Sorry that this is later than I had hoped to get it out, but here it is -- Expect another one soon in a month or two depending on submissions... Praise, Comments, (It sucks, I loved it, etc) are welcome -> duck@pembvax1.pembroke.edu. Many thanks to Craig Bruce for his article on line drawing / dot plotting with the 80 column screen on the C=128. =============================================================================== Hacking / This Magazine by Craig Taylor duck@pembvax1.pembroke.edu Def: Hacker - Noun - A talented amateur user of computers. Source - Webster's New World Dictionary Correction: Hacker - Noun - A talented user of computers. There, now that we got that out of the way, let's see how some people interpret the word hacker. In the 1980's newspapers, magazines, movies - everywhere ya looked people were using the term "Hacker" to denote a person who maliciously tried to destroy / bore ill intent towards another computer system. This was the result of the misunderstanding of the actual definition of "Hacker" (under my correction above). This magazine will not tell people how to "phreak", how to hack voice mailboxes and other illegal activities. However, it will attempt to reveal some of the "mystique" behind some of the new techniques and abilities found in the Commodore 64 and Commodore 128 that are just now being revealed. In the event that an article is submitted and there is a question about it's ability to be applied towards illegal activites, the article will be carried with a warning that the intent is not towards that activity. Hopefully, these will never come along. :-) The Commodore 64 came out in late 1982 (I believe) and was known to only support 16 colors, 320 x 200 resolution graphics of 2 colors, 160x200 resolution graphics of 4 colors. Since then people have pushed the Commodore 64 to its limits with apparent resolution of 320 x 200 with a resolution of 4 colors and even higher... more than 8 sprites on the screen... fast high-quality digitized sounds.... The Commodore 128 came out as an "upgrade" from the Commodore 64 and with it's unique memory management scheme and the Z80a chip still on there people are still finding out unique and interesting ways to explore the C=128. One of the most interesting has been that of the seperate video display chip which makes it possible to dispaly 640x200 resolution graphics quickly and easily. **ATTENTION** This magazine is going to be a sourcebook of many people - If you know anything about something, please feel free to submit it. Just mail the article to the following : duck@pembvax1.pembroke.edu and a subject of "ARTICLE - " and then the article name. The source code for all programs mentioned within articles will be provided as well as any executables uuencoded sent out seprately. [Ed. Note - In this issue, the source is not sent seperately due to only one article with files] In addition, the magazine will go out when there are enough articles collected. Also, I'm currently in college - so - it will also be dependant on few tests etc being around the release period. In this issue: Title Author(s) ------------------------------------------------------------------------------ Hacking - Definition Of duck@pembvax1.pembroke.edu Learning ML - Part 1 duck@pembvax1.pembroke.edu 6502 Known/Unknown Opcodes compilation of several Dot Plotting & Bitmapping csbruce@ccnga.uwaterloo.ca the 8563 Screen. ** All articles and files (C) 1992 by their respective authors. ============================================================================= Beginning ML - Part One (C) 1992 by Craig Taylor The best way to learn machine language is to actually code routines that you don't think will work, hope that they work, and then figure out why they don't work. (If they do work, you try to figure out why you didn't think they'd work). Ie: THE BEST WAY TO LEARN ANY PROGRAMMING LANGUAGE IS TO PROGRAM IN THAT LANGUAGE. And Machine Language is a programming language. Now, let's get a few terms and definitions out of the way: Machine Language - Instructions that the computer understands at a primitive level and executes accordingly. Assembly Language - Instructions more understandable to humans than pure Machine Language that makes life easier. Assembly: Machine: Example: lda #$00 $A9 $00 Huh? you might be saying at the moment. Turns out that LDA stands for, or is a mnemonic (computer people always come up with these big long words -- you'll see mnemonic's often when dealing with machine language) for the following: "LOAD register A with the following value" ^ ^ ^ Cool 'eh? Yeah, but there's somebody grumbling now about why not make it LOADA etc.. Hey, that's life. (GRIN). Oh, more definitions: Register - A location inside the CPU that can be manipulated directly without having to access memory. The "A" register is often called the accumalator which indicates its function: all math and logical manipulations are done to the "A" register (from hereon out it will be referred to as .A). There are two other registers inside the 6502 processor, specifically .X and .Y. These registers help act as counters and indexes into memory (sorta like mem[x] in pascal but not quite...). Now, let's add 3 and 5 and leave the result in the accumalator (.A). lda #3 ; Here .A = 3 (anything w/ a ; is a ; comment and will be ignored by the assembler... clc ; hu? - This clears the carry. The 6502 ; does addition *everytime* with the carry ... so if we clear it it won't ; affect the result. adc #5 ; Now, .A = .A + 5 and we're done. If the CLC confused you then consider that if you're adding a column of #'s: 12 <--\__The 2 + 9 = 11, but we put the 1 down and set the carry to 1. + 89 <---/ -- 101 Then we say 1 + 8 + carry , which in this case happens to = 1 and we get 10 and again we set the carry and write down 0. Then it's just the carry and we write that down. If we didn't clear the carry we may have ended up with the value of 9 instead 8 if the carry had happened to be set. Aaagh, Math - Let's continue - The CLC mnemonic stands for "CLEAR CARRY" and the ADC stands for "ADD with CARRY". On many processors there is a ADD (without a carry) but unfortunately the 6502 processor inside the C=64 doesn't have it. So we've got: load reg A with the value 5 lda #5 clear the carry clc add reg a and value 3 adc #3 In Basic it's just: A = 5+3 One statement... In Machine Language you've got to break everything down into smaller and smaller steps and quite often the ML listing will be far longer than the BASIC or PASCAL or C equivlent. Definitions: Assembler - Program takes source code in basic form or from a file and writes to memory or a file the resulting executable. Allows higher flexibility than a monitor (see below) due to use of labels etc and not having to keep track of each address within the program. Monitor - A program, resident in memory, invoked by a sys call from basic or by hitting the restore key that will let you disassemble, assemble and examine areas of memory and execute programs directly from the monitor. Useful for debugging programs and for writing short programs. Let's enter the following into a monitor (if you don't have one then contact duck@pembvax1.pembroke.edu and I'll send ya one): 128: c64: >a 1300 lda #$93 >a c000 lda #$93 >a 1302 jsr $ffd2 >a c003 jsr $ffd2 >a 1305 rts >a c005 rts (exit monitor) (exit monitor) bank15:sys4864 sys 49152 Wow! It cleared the screen. Neat 'eh? But see how much ya gotta break problems down? The first statement loads in $93 hex into the accumalator ($93 hex just happens to equal 147 which is also the Commodorscii code for clear screen. For a whole list just look in the back of the book that came with the computer). Then we jump to a system routine which Commodore so graciously supplied us with that prints the value of the character in .A to the screen. (jsr $ffd2) then we do a RTS (ReTurn from Subroutine) so that we will go back to basic and the Ready prompt when we are finished with the sys call. You C= 128 people may be wondering why you had to do a bank 15 and assemble the stuff at a different memory location. Turns out that the C128 memory map of where routines etc are at is much more complex than the C=64 and thus you have to tell basic which bank you wish to have all sys, peek, and poke calls to take place in. Also, $c000 as used on the C=64 is not an area that is free to use on the C128 in this manner. Assignment: Take a look @ the different commands as listed in 6502 Opcodes and try to understand what they do. Experiment with the jsr $ffd2 routine by using different values etc. Next Time: Printing out strings, and understanding 'Indexing'. =========================================================================== 6502 Opcodes and Quasi-Opcodes. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The following table lists all of the available opcodes on the 65xx line of micro-processors (such as the 6510 on the C=64 and the 8502 on the C=128) ----------------------------------------------------------------------------- Std Mnemonic Hex Value Description Addressing Mode Bytes/Time * BRK $00 Stack <- PC, PC <- ($fffe) (Immediate) 1/7 * ORA $01 A <- (A) V M (Ind,X) 6/2 JAM $02 [locks up machine] (Implied) 1/- SLO $03 M <- (M >> 1) + A + C (Ind,X) 2/8 NOP $04 [no operation] (Z-Page) 2/3 * ORA $05 A <- (A) V M (Z-Page) 2/3 * ASL $06 C <- A7, A <- (A) << 1 (Z-Page) 2/5 SLO $07 M <- (M >> 1) + A + C (Z-Page) 2/5 * PHP $08 Stack <- (P) (Implied) 1/3 * ORA $09 A <- (A) V M (Immediate) 2/2 * ASL $0A C <- A7, A <- (A) << 1 (Accumalator) 1/2 ANC $0B A <- A /\ M, C=~A7 (Immediate) 1/2 NOP $0C [no operation] (Absolute) 3/4 * ORA $0D A <- (A) V M (Absolute) 3/4 * ASL $0E C <- A7, A <- (A) << 1 (Absolute) 3/6 SLO $0F M <- (M >> 1) + A + C (Absolute) 3/6 * BPL $10 if N=0, PC = PC + offset (Relative) 2/2'2 * ORA $11 A <- (A) V M ((Ind),Y) 2/5'1 JAM $12 [locks up machine] (Implied) 1/- SLO $13 M <- (M >. 1) + A + C ((Ind),Y) 2/8'5 NOP $14 [no operation] (Z-Page,X) 2/4 * ORA $15 A <- (A) V M (Z-Page,X) 2/4 * ASL $16 C <- A7, A <- (A) << 1 (Z-Page,X) 2/6 SLO $17 M <- (M >> 1) + A + C (Z-Page,X) 2/6 * CLC $18 C <- 0 (Implied) 1/2 * ORA $19 A <- (A) V M (Absolute,Y) 3/4'1 NOP $1A [no operation] (Implied) 1/2 SLO $1B M <- (M >> 1) + A + C (Absolute,Y) 3/7 NOP $1C [no operation] (Absolute,X) 2/4'1 * ORA $1D A <- (A) V M (Absolute,X) 3/4'1 * ASL $1E C <- A7, A <- (A) << 1 (Absolute,X) 3/7 SLO $1F M <- (M >> 1) + A + C (Absolute,X) 3/7 * JSR $20 Stack <- PC, PC <- Address (Absolute) 3/6 * AND $21 A <- (A) /\ M (Ind,X) 2/6 JAM $22 [locks up machine] (Implied) 1/- RLA $23 M <- (M << 1) /\ (A) (Ind,X) 2/8 * BIT $24 Z <- ~(A /\ M) N<-M7 V<-M6 (Z-Page) 2/3 * AND $25 A <- (A) /\ M (Z-Page) 2/3 * ROL $26 C <- A7 & A <- A << 1 + C (Z-Page) 2/5 RLA $27 M <- (M << 1) /\ (A) (Z-Page) 2/5'5 * PLP $28 A <- (Stack) (Implied) 1/4 * AND $29 A <- (A) /\ M (Immediate) 2/2 * ROL $2A C <- A7 & A <- A << 1 + C (Accumalator) 1/2 ANC $2B A <- A /\ M, C <- ~A7 (Immediate9 1/2 * BIT $2C Z <- ~(A /\ M) N<-M7 V<-M6 (Absolute) 3/4 * AND $2D A <- (A) /\ M (Absolute) 3/4 * ROL $2E C <- A7 & A <- A << 1 + C (Absolute) 3/6 RLA $2F M <- (M << 1) /\ (A) (Absolute) 3/6'5 * BMI $30 if N=1, PC = PC + offset (Relative) 2/2'2 * AND $31 A <- (A) /\ M ((Ind),Y) 2/5'1 JAM $32 [locks up machine] (Implied) 1/- RLA $33 M <- (M << 1) /\ (A) ((Ind),Y) 2/8'5 NOP $34 [no operation] (Z-Page,X) 2/4 * AND $35 A <- (A) /\ M (Z-Page,X) 2/4 * ROL $36 C <- A7 & A <- A << 1 + C (Z-Page,X) 2/6 RLA $37 M <- (M << 1) /\ (A) (Z-Page,X) 2/6'5 * SEC $38 C <- 1 (Implied) 1/2 * AND $39 A <- (A) /\ M (Absolute,Y) 3/4'1 NOP $3A [no operation] (Implied) 1/2 RLA $3B M <- (M << 1) /\ (A) (Absolute,Y) 3/7'5 NOP $3C [no operation] (Absolute,X) 3/4'1 * AND $3D A <- (A) /\ M (Absolute,X) 3/4'1 * ROL $3E C <- A7 & A <- A << 1 + C (Absolute,X) 3/7 RLA $3F M <- (M << 1) /\ (A) (Absolute,X) 3/7'5 * RTI $40 P <- (Stack), PC <-(Stack) (Implied) 1/6 * EOR $41 A <- (A) \-/ M (Ind,X) 2/6 JAM $42 [locks up machine] (Implied) 1/- SRE $43 M <- (M >> 1) \-/ A (Ind,X) 2/8 NOP $44 [no operation] (Z-Page) 2/3 * EOR $45 A <- (A) \-/ M (Z-Page) 2/3 * LSR $46 C <- A0, A <- (A) >> 1 (Absolute,X) 3/7 SRE $47 M <- (M >> 1) \-/ A (Z-Page) 2/5 * PHA $48 Stack <- (A) (Implied) 1/3 * EOR $49 A <- (A) \-/ M (Immediate) 2/2 * LSR $4A C <- A0, A <- (A) >> 1 (Accumalator) 1/2 ASR $4B A <- [(A /\ M) >> 1] (Immediate) 1/2 * JMP $4C PC <- Address (Absolute) 3/3 * EOR $4D A <- (A) \-/ M (Absolute) 3/4 * LSR $4E C <- A0, A <- (A) >> 1 (Absolute) 3/6 SRE $4F M <- (M >> 1) \-/ A (Absolute) 3/6 * BVC $50 if V=0, PC = PC + offset (Relative) 2/2'2 * EOR $51 A <- (A) \-/ M ((Ind),Y) 2/5'1 JAM $52 [locks up machine] (Implied) 1/- SRE $53 M <- (M >> 1) \-/ A ((Ind),Y) 2/8 NOP $54 [no operation] (Z-Page,X) 2/4 * EOR $55 A <- (A) \-/ M (Z-Page,X) 2/4 * LSR $56 C <- A0, A <- (A) >> 1 (Z-Page,X) 2/6 SRE $57 M <- (M >> 1) \-/ A (Z-Page,X) 2/6 * CLI $58 I <- 0 (Implied) 1/2 * EOR $59 A <- (A) \-/ M (Absolute,Y) 3/4'1 NOP $5A [no operation] (Implied) 1/2 SRE $5B M <- (M >> 1) \-/ A (Absolute,Y) 3/7 NOP $5C [no operation] (Absolute,X) 3/4'1 * EOR $5D A <- (A) \-/ M (Absolute,X) 3/4'1 SRE $5F M <- (M >> 1) \-/ A (Absolute,X) 3/7 * RTS $60 PC <- (Stack) (Implied) 1/6 * ADC $61 A <- (A) + M + C (Ind,X) 2/6 JAM $62 [locks up machine] (Implied) 1/- RRA $63 M <- (M >> 1) + (A) + C (Ind,X) 2/8'5 NOP $64 [no operation] (Z-Page) 2/3 * ADC $65 A <- (A) + M + C (Z-Page) 2/3 * ROR $66 C<-A0 & A<- (A7=C + A>>1) (Z-Page) 2/5 RRA $67 M <- (M >> 1) + (A) + C (Z-Page) 2/5'5 * PLA $68 A <- (Stack) (Implied) 1/4 * ADC $69 A <- (A) + M + C (Immediate) 2/2 * ROR $6A C<-A0 & A<- (A7=C + A>>1) (Accumalator) 1/2 ARR $6B A <- [(A /\ M) >> 1] (Immediate) 1/2'5 * JMP $6C PC <- Address (Indirect) 3/5 * ADC $6D A <- (A) + M + C (Absolute) 3/4 * ROR $6E C<-A0 & A<- (A7=C + A>>1) (Absolute) 3/6 RRA $6F M <- (M >> 1) + (A) + C (Absolute) 3/6'5 * BVS $70 if V=1, PC = PC + offset (Relative) 2/2'2 * ADC $71 A <- (A) + M + C ((Ind),Y) 2/5'1 JAM $72 [locks up machine] (Implied) 1/- RRA $73 M <- (M >> 1) + (A) + C ((Ind),Y) 2/8'5 NOP $74 [no operation] (Z-Page,X) 2/4 * ADC $75 A <- (A) + M + C (Z-Page,X) 2/4 * ROR $76 C<-A0 & A<- (A7=C + A>>1) (Z-Page,X) 2/6 RRA $77 M <- (M >> 1) + (A) + C (Z-Page,X) 2/6'5 * SEI $78 I <- 1 (Implied) 1/2 * ADC $79 A <- (A) + M + C (Absolute,Y) 3/4'1 NOP $7A [no operation] (Implied) 1/2 RRA $7B M <- (M >> 1) + (A) + C (Absolute,Y) 3/7'5 NOP $7C [no operation] (Absolute,X) 3/4'1 * ADC $7D A <- (A) + M + C (Absolute,X) 3/4'1 * ROR $7E C<-A0 & A<- (A7=C + A>>1) (Absolute,X) 3/7 RRA $7F M <- (M >> 1) + (A) + C (Absolute,X) 3/7'5 NOP $80 [no operation] (Immediate) 2/2 * STA $81 M <- (A) (Ind,X) 2/6 NOP $82 [no operation] (Immediate) 2/2 SAX $83 M <- (A) /\ (X) (Ind,X) 2/6 * STY $84 M <- (Y) (Z-Page) 2/3 * STA $85 M <- (A) (Z-Page) 2/3 * STX $86 M <- (X) (Z-Page) 2/3 SAX $87 M <- (A) /\ (X) (Z-Page) 2/3 * DEY $88 Y <- (Y) - 1 (Implied) 1/2 NOP $89 [no operation] (Immediate) 2/2 * TXA $8A A <- (X) (Implied) 1/2 ANE $8B M <-[(A)\/$EE] /\ (X)/\(M) (Immediate) 2/2^4 * STY $8C M <- (Y) (Absolute) 3/4 * STA $8D M <- (A) (Absolute) 3/4 * STX $8E M <- (X) (Absolute) 3/4 SAX $8F M <- (A) /\ (X) (Absolute) 3/4 * BCC $90 if C=0, PC = PC + offset (Relative) 2/2'2 * STA $91 M <- (A) ((Ind),Y) 2/6 JAM $92 [locks up machine] (Implied) 1/- SHA $93 M <- (A) /\ (X) /\ (PCH+1) (Absolute,X) 3/6'3 * STY $94 M <- (Y) (Z-Page,X) 2/4 * STA $95 M <- (A) (Z-Page,X) 2/4 SAX $97 M <- (A) /\ (X) (Z-Page,Y) 2/4 * STX $96 M <- (X) (Z-Page,Y) 2/4 * TYA $98 A <- (Y) (Implied) 1/2 * STA $99 M <- (A) (Absolute,Y) 3/5 * TXS $9A S <- (X) (Implied) 1/2 SHS $9B X <- (A) /\ (X), S <- (X) (Absolute,Y) 3/5 M <- (X) /\ (PCH+1) SHY $9C M <- (Y) /\ (PCH+1) (Absolute,Y) 3/5'3 * STA $9D M <- (A) (Absolute,X) 3/5 SHX $9E M <- (X) /\ (PCH+1) (Absolute,X) 3/5'3 SHA $9F M <- (A) /\ (X) /\ (PCH+1) (Absolute,Y) 3/5'3 * LDY $A0 Y <- M (Immediate) 2/2 * LDA $A1 A <- M (Ind,X) 2/6 * LDX $A2 X <- M (Immediate) 2/2 LAX $A3 A <- M, X <- M (Ind,X) 2/6 * LDY $A4 Y <- M (Z-Page) 2/3 * LDA $A5 A <- M (Z-Page) 2/3 * LDX $A6 X <- M (Z-Page) 2/3 LAX $A7 A <- M, X <- M (Z-Page) 2/3 * TAY $A8 Y <- (A) (Implied) 1/2 * LDA $A9 A <- M (Immediate) 2/2 * TAX $AA X <- (A) (Implied) 1/2 LXA $AB X04 <- (X04) /\ M04 (Immediate) 1/2 A04 <- (A04) /\ M04 * LDY $AC Y <- M (Absolute) 3/4 * LDA $AD A <- M (Absolute) 3/4 * LDX $AE X <- M (Absolute) 3/4 LAX $AF A <- M, X <- M (Absolute) 3/4 * BCS $B0 if C=1, PC = PC + offset (Relative) 2/2'2 * LDA $B1 A <- M ((Ind),Y) 2/5'1 JAM $B2 [locks up machine] (Implied) 1/- LAX $B3 A <- M, X <- M ((Ind),Y) 2/5'1 * LDY $B4 Y <- M (Z-Page,X) 2/4 * LDA $B5 A <- M (Z-Page,X) 2/4 * LDX $B6 X <- M (Z-Page,Y) 2/4 LAX $B7 A <- M, X <- M (Z-Page,Y) 2/4 * CLV $B8 V <- 0 (Implied) 1/2 * LDA $B9 A <- M (Absolute,Y) 3/4'1 * TSX $BA X <- (S) (Implied) 1/2 LAE $BB X,S,A <- (S /\ M) (Absolute,Y) 3/4'1 * LDY $BC Y <- M (Absolute,X) 3/4'1 * LDA $BD A <- M (Absolute,X) 3/4'1 * LDX $BE X <- M (Absolute,Y) 3/4'1 LAX $BF A <- M, X <- M (Absolute,Y) 3/4'1 * CPY $C0 (Y - M) -> NZC (Immediate) 2/2 * CMP $C1 (A - M) -> NZC (Ind,X) 2/6 NOP $C2 [no operation] (Immediate) 2/2 DCP $C3 M <- (M)-1, (A-M) -> NZC (Ind,X) 2/8 * CPY $C4 (Y - M) -> NZC (Z-Page) 2/3 * CMP $C5 (A - M) -> NZC (Z-Page) 2/3 * DEC $C6 M <- (M) - 1 (Z-Page) 2/5 DCP $C7 M <- (M)-1, (A-M) -> NZC (Z-Page) 2/5 * INY $C8 Y <- (Y) + 1 (Implied) 1/2 * CMP $C9 (A - M) -> NZC (Immediate) 2/2 * DEX $CA X <- (X) - 1 (Implied) 1/2 SBX $CB X <- (X)/\(A) - M (Immediate) 2/2 * CPY $CC (Y - M) -> NZC (Absolute) 3/4 * CMP $CD (A - M) -> NZC (Absolute) 3/4 * DEC $CE M <- (M) - 1 (Absolute) 3/6 DCP $CF M <- (M)-1, (A-M) -> NZC (Absolute) 3/6 * BNE $D0 if Z=0, PC = PC + offset (Relative) 2/2'2 * CMP $D1 (A - M) -> NZC ((Ind),Y) 2/5'1 JAM $D2 [locks up machine] (Implied) 1/- DCP $D3 M <- (M)-1, (A-M) -> NZC ((Ind),Y) 2/8 NOP $D4 [no operation] (Z-Page,X) 2/4 * CMP $D5 (A - M) -> NZC (Z-Page,X) 2/4 * DEC $D6 M <- (M) - 1 (Z-Page,X) 2/6 DCP $D7 M <- (M)-1, (A-M) -> NZC (Z-Page,X) 2/6 * CLD $D8 D <- 0 (Implied) 1/2 * CMP $D9 (A - M) -> NZC (Absolute,Y) 3/4'1 NOP $DA [no operation] (Implied) 1/2 DCP $DB M <- (M)-1, (A-M) -> NZC (Absolute,Y) 3/7 NOP $DC [no operation] (Absolute,X) 3/4'1 * CMP $DD (A - M) -> NZC (Absolute,X) 3/4'1 * DEC $DE M <- (M) - 1 (Absolute,X) 3/7 DCP $DF M <- (M)-1, (A-M) -> NZC (Absolute,X) 3/7 * CPX $E0 (X - M) -> NZC (Immediate) 2/2 * SBC $E1 A <- (A) - M - ~C (Ind,X) 2/6 NOP $E2 [no operation] (Immediate) 2/2 ISB $E3 M <- (M) - 1,A <- (A)-M-~C (Ind,X) 3/8'1 * CPX $E4 (X - M) -> NZC (Z-Page) 2/3 * SBC $E5 A <- (A) - M - ~C (Z-Page) 2/3 * INC $E6 M <- (M) + 1 (Z-Page) 2/5 ISB $E7 M <- (M) - 1,A <- (A)-M-~C (Z-Page) 2/5 * INX $E8 X <- (X) +1 (Implied) 1/2 * SBC $E9 A <- (A) - M - ~C (Immediate) 2/2 * NOP $EA [no operation] (Implied) 1/2 SBC $EB A <- (A) - M - ~C (Immediate) 1/2 * SBC $ED A <- (A) - M - ~C (Absolute) 3/4 * CPX $EC (X - M) -> NZC (Absolute) 3/4 * INC $EE M <- (M) + 1 (Absolute) 3/6 ISB $EF M <- (M) - 1,A <- (A)-M-~C (Absolute) 3/6 * BEQ $F0 if Z=1, PC = PC + offset (Relative) 2/2'2 * SBC $F1 A <- (A) - M - ~C ((Ind),Y) 2/5'1 JAM $F2 [locks up machine] (Implied) 1/- ISB $F3 M <- (M) - 1,A <- (A)-M-~C ((Ind),Y) 2/8 NOP $F4 [no operation] (Z-Page,X) 2/4 * SBC $F5 A <- (A) - M - ~C (Z-Page,X) 2/4 * INC $F6 M <- (M) + 1 (Z-Page,X) 2/6 ISB $F7 M <- (M) - 1,A <- (A)-M-~C (Z-Page,X) 2/6 * SED $F8 D <- 1 (Implied) 1/2 * SBC $F9 A <- (A) - M - ~C (Absolute,Y) 3/4'1 NOP $FA [no operation] (Implied) 1/2 ISB $FB M <- (M) - 1,A <- (A)-M-~C (Absolute,Y) 3/7 NOP $FC [no operation] (Absolute,X) 3/4'1 * SBC $FD A <- (A) - M - ~C (Absolute,X) 3/4'1 * INC $FE M <- (M) + 1 (Absolute,X) 3/7 ISB $FF M <- (M) - 1,A <- (A)-M-~C (Absolute,X) 3/7 '1 - Add one if address crosses a page boundry. '2 - Add 1 if branch succeeds, or 2 if into another page. '3 - If page boundry crossed then PCH+1 is just PCH '4 - Sources disputed on exact operation, or sometimes does not work. '5 - Full eight bit rotation (with carry) Sources: Programming the 6502, Rodney Zaks, (c) 1983 Sybex Paul Ojala, Post to Comp.Sys.Cbm (po87553@cs.tut.fi / albert@cc.tut.fi) D John Mckenna, Post to Comp.Sys.Cbm (gudjm@uniwa.uwa.oz.au) Compiled by Craig Taylor (duck@pembvax1.pembroke.edu) ============================================================================== Simple Hires Line Drawing Package for the C-128 80-Column Screen Copyright (c) 1992 Craig Bruce 1. GRAPHICS PACKAGE OVERVIEW The graphics package this article explains is BLOADed into memory at address $1300 on bank 15 and has three entry points: $1300 = move the pixel cursor or draw a line: .AX=x, .Y=y, .C=cmd $1303 = activate graphics mode and clear the screen $1306 = exit graphics mode and reload the character set To move the pixel cursor to the start point of a line, load the .AX registers with the X coordinate (0-639), load the .Y register with the Y coordinate (0-199), clear the carry flag, and call $1300. (Make sure that Bank 15 is in context). This can be done in BASIC as follows: SYS 4864, X AND 255, X/256, Y, 0 To draw a line from the pixel cursor location to a given point, load the .AX and .Y registers like before, set the carry flag, and call $1300. The pixel cursor will then be set to the end point of the line just drawn, so you do not have to set it again if you are drawing a continuous object (like a square). SYS 4864, X AND 255, X/256, Y, 1 The activate and exit routines are called without any parameters and work very simply. You should be sure to call exit before returning to the program editing mode or you will not be able to see what you are typing. A BASIC demonstration program is also included in the UU section for this package. It starts by putting the pixel cursor at the center of the screen and then picks a random point to draw to, and repeats until you press a key to stop it. For an interesting effect, put a call to $1303 immediately before the call to draw the line. The point plotting speed is about 4,100 pixels per second and the line drawing speed is a bit slower than this because of all of the calculations that have to be done to draw a line. There are faster pixel plotting and line drawing algorithms than the ones implemented here, but that is material for a future article. 2. INTRODUCTION TO THE VDC Programming the 8563 Video Display Controller is quite straight forward. You access it a bit indirectly, but it can still be done at relatively high speeds using machine language. The VDC contains 37 control registers and from 16K to 64K of dedicated display memory that is separate from the main processor. The memory must be accessed through the VDC registers. The important VDC registers for this exercise are: REG BITS DESC --- ---- ---- $12 7-0 VDC RAM address high byte $13 7-0 VDC RAM address low byte $18 7 Block copy / block fill mode select $19 7 Bitmap / Character mode select $19 6 Color / Monochrome mode select $1a 7-4 Foreground color $1a 3-0 Background color $1e 7-0 Copy / fill repetition count $1f 7-0 VDC RAM data read / write You access the VDC chip registers though addresses $D600 and $D601 on bank 15. Location $D600 selects the VDC register to use on write and returns the VDC status on read. The only important status information is bit 7 (value $80) which is the "ready" flag. The following two subroutines read or write the value in .A to VDC register number .X: VdcRead: stx $d600 VdcWrite: stx $d600 WaitLoop: bit $d600 WaitLoop: bit $d600 bpl WaitLoop bpl WaitLoop lda $d601 sta $d601 rts rts Once the current VDC register is selected at $d600, it remains selected. You may read or write it though $d601 as many times as you like as long as you wait for the VDC to be "ready" between accesses. In order to access the VDC RAM, you must first put the high and low bytes of the VDC RAM address into registers $12 and $13 (high byte first) and then read or write through register $1f to read or write the data in the VDC RAM. After each access to register $1f, the VDC RAM address is incremented by one. So, if you repeatedly read or write to register $1f you can read or write a chunk of VDC memory very quickly. 3. ENTERING GRAPHICS MODE Activating the graphics mode of the VDC is very simple - you just have to set bit 7 of VDC register $19 and poof! You should also clear bit 6 of that register to disable the character color mode. This graphics package supports only monochrome graphics since the standard 16K VDC does not have enough space to hold both the bitmap and the 8*8 pixel cell attributes. The 640*200 pixel display takes 128,000 bits or 16,000 bytes. This leaves 384 bytes of VDC RAM that is not needed by the bitmap but it is not large enough to do anything with, so it is wasted. When you disable the character color mode, the VDC takes its foreground and background color values from register $1a. The foreground color is what color the "1" bits in the bitmap will be displayed in and the background color, the "0" bits. Now that the bitmap mode is set up, we must clear the VDC memory locations 0 to 15999 (decimal) to clear the bitmap screen. This can be done very quickly using the VDC fill mode. If you poke a value into VDC register number $1e, the VDC will fill its memory from the location currently in the VDC RAM address registers for the number of bytes you just poked into register $1e with the value that you last poked into the VDC RAM data register. (This is assuming that "fill" mode is selected in register $18). If you poke a 0 into the repeat register it means to fill 256 bytes. So, to clear the bitmap, poke a zero into both of the VDC RAM address registers since the bitmap starts at location 0. Then poke a value of 0 into VDC RAM data register. This sets the fill value to 0 and pokes the first VDC RAM location. Then, go into a loop and put a zero into the VDC repeat register 63 times. This will fill 63 contiguous chunks of 256 bytes each. We end up filling 16,129 bytes, but that is not a problem since we have 384 "safety" bytes at the end of the bitmap. Internally, the VDC will fill its memory at a rate of about 1 Megabyte per second (if I remember my test results correctly), so clearing the screen is a PDFQ operation. 4. EXITING GRAPHICS MODE To exit from graphics mode we have to reload the character set from the ROM on bank 14 and we have to go back into character mode and clear the text screen. The kernel provides its own character reload routine so I used that. The only problem with it is that it is a lot slower than it has to be. It takes about 0.45 seconds whereas the same job can be done in about 0.09 seconds. The kernel is so slow because it uses the kernel INDFETCH nonsense. Then you just set the bitmap mode bit to zero and the character color mode to one. This gets you back to normal character mode. You also have to clear the text screen since it will be filled with garbage from the graphing. 5. POINT PLOTTING The pixels on the screen accessed by their X and Y coordinates, 0 <= X <= 639, 0 <= Y <= 199. The formula to calculate the byte address in the VDC RAM given the X and Y coordinates is made simple by the mapping of bytes to the pixels on the screen. The bytes of VDC memory go across the screen rather than in 8*8 cells like the VIC screen. Each pixel row is defined by 80 consecutive bytes of VDC RAM. The formula for the byte address of a pixel is: AD=Y*80+INT(X/8), and the formula for the bit number is simply BI=X AND 7. The bit number can be used as an index into a table of bit values: [$80,$40,$20,$10,$08,$04,$02,$01], such that index 0 contains $80, since the highest bit is the leftmost bit. Calculating the bit number and looking up the bit value is very easy to do in machine language, but the byte address calculation requires a little more work. First we have to multiply the Y value by 80, using a 16-bit word for storage. This is done by shifting the Y value left twice, adding the original Y value, and shifting left four more times. Then we have to shift the X value right by three using a 16-bit word for storage to get INT(X/8), and we add the two results together and we have the byte address. To plot the point, we have to peek into the VDC RAM at the byte address to see what is "behind" the pixel we want to plot. Then OR the new bit value on to the "background" value and poke the result back into VDC RAM at the byte address. Unfortunately, since the VDC RAM address register auto-increments after each reference, we will have to set it twice - once for the read and once for the write. That means that the VDC registers have to be accessed six times for each pixel. Fortunately, the VDC operates at its highest speed in monochrome bitmap mode (it has less work to do than in color character mode, so it is able to pay mor