_Bonkers_ Level #03 (c) Curtis White FREEWARE: NO SALE OF THIS MAGAZINE IS ALLOWED WITHOUT PRIOR WRITTEN PERMISSION. This time we have a ton of stuff that we will be covering! We will make the leap from the monitor to the assembler, start building our library of routines, and maybe learn a few more instructions. No time to waste; let's venture on! The Bonker's Staff Editor: Coolhand < Send your opinions, thanks, Technical Dude: Dokken < and gripes to these clowns! Author: Light < Support Web Site: http://soho.ios.com/~coolhnd/bonkers/planet.htm Stage #01 Info Highway equals one way street and 23,000 cars going in both directions. First, we have been coding in the machine language monitor which, as we know, is used primarily for viewing and changing memory locations. Now, we will be coding in an assembler, which will allow us to edit and understand our code better by using labels, directives, comments, and symbols. There are several good assemblers for the c64/128. It is not the purpose of this magazine to determine which is the best for you. But all of our source code will be Turbo Assembler compatible; we will list some common Turbo Assembler commands below, followed by common assembly terms. +----------------------------------------------------------------------+ | Turbo Assembler Commands | +----------------------------------------------------------------------+ LEFT ARROW 2 - Comment line. LEFT ARROW 3 - Assemble to memory. LEFT ARROW 5 - Assemble to disk. LEFT ARROW 1 - Return to basic. LEFT ARROW S - Save source to disk in program format. LEFT ARROW W - Save source to disk in sequential format. LEFT ARROW L - Load source from disk in program format. LEFT ARROW E - Load source from disk in sequential format. LEFT ARROW INST DEL - Delete line of code +-----------------------------------------------------------------------+ | Common Assembly Terms | +-----------------------------------------------------------------------+ Assembler: Program that takes source code and produces object code. Note each instruction in the source code becomes the same object code instruction after it's assembled. Constants: As we have already learned, the prefix that determines the number base used, like $ for hex and % for binary. Directives: These are used to communicate with the assembler. They are powerful and they are used frequently. Expressions: A string of operators (+, /, -, *), NOTE that these are performed during assembly and not during run time. Label: Name for a line of code in the assembler. This is used to replace actual addresses that are used in the monitor. Object Code: The code that the assembler makes and the computer runs. Also the code that can be viewed in a monitor. Opcode: Machine/Assembly language instruction. Example LDA, STA, BEQ, RTS. Operand: Data which the opcode or instruction uses, not all instructions have operands. Source Code: The code that you edit in the assembler, includes comments. Let's get started on our first assembly language program. We will cover every detail of this short program. *= 8192 ; Start address of object code chrout = $ffd2 printa lda #"a" ; get letter a jsr chrout ; print letter to screen rts ; return to basic Note: to run this program either type 'SYS 8192' from BASIC or hit LEFT ARROW 3 from Turbo Assembler. First the * is a directive which is used to change the program counter. The PC (Program Counter) as we know dictates what code is currently running and going to be executed or run. SYS 49152 sets the program counter to address 49152. The *= just assigns where our object code will be placed in memory and usually it is also the start address of our code. The = is also a directive which has a variety of uses. In the example chrout = $ffd2, we assign the address $ffd2 to the label chrout. Printa is a label which can used just as an address or location is used in the monitor. The ; declares that comments are to follow and they are to be ignored when assembling, hence we can now type the comments in along with the actual code. The ; (semi-colon) is almost identical to the Basic command REM. A Task... (Yeah right, who is going to ever use this?) The task is to create a simple word processor which will allow us to leave memos on the computer and then highlight those memos. To use the program simply SYS 8192 or LEFT ARROW 3 (FOR TASM ONLY) and type your message (no cursor will be displayed). This sounds like fun so let's do it! *= 8192 ; start address chrout = $ffd2 ; KERNAL ROUTINE TO OUTPUT A CHAR getin = $ffe4 ; KERNAL ROUTINE TO INPUT A CHAR ;//////////////////Setup Screen lda #$93 ;Clear screen char jsr chrout ;Clear it lda #$00 ;Color Black sta $d020 ;53280 DECIMAL BORDER COLOR sta $d021 ;53281 DECIMAL BACKGROUND COLOR ;//////////////////Main Loop main jsr wordproc ;INPUT/OUTPUT jsr memodisplay ;HIGHLIGHT BORDER jmp main ;BACK TO MAIN ;//////////////////Word Processor wordproc jsr getin ;KERNAL ROUTINE TO GET CHAR jsr chrout ;Now output char that getin copied rts ;Return to main loop ;//////////////////Highlight Memo memodisplay ldx #$00 ;Set Index Register X To Value 0 coloop lda colors,x ;Get data colors, indexed to X. sta $d020 ;Store those colors 2 border inx ;Increase our index cpx #9 ;Compare X TO 9 (9 colors) bne coloop ;Branch coloop until 9 cols rts ;End Subroutine colors .byte 6,14,3,7,1,7,3,14,6 Now, it is time to dissect the more interesting parts of the above code. First, notice the $d020/$d021 (53280/53281). These are memory locations that will change the entire border or background color of the screen. Sixteen unique colors are available for us to use (numbers 0 through 15), and it just so happens that zero is the color black. Also, notice the JSR GETIN. We use this kernal subroutine to get a character from the keyboard into the A Register. Since the kernal subroutine CHROUT outputs the character that is stored in the A register to the screen, we can use these together to copy letters from the keyboard to the screen. Notice the JMP (JUMP Instruction). This instruction is similar to the JSR (Jump Saving Return Address), except that the JMP instruction does not save the return address. For those who already know BASIC, you can compare it to the GOTO rather then the GOSUB, as with JSR. Now, as a quick reminder that we are using an assembler, below is what the same code looks like in the MONITOR. <<----------------------- BEGIN MACHINE LANGUAGE CODE . 8192 LDA #147 . 8194 jsr 65490 . 8197 lda #0 . 8199 sta 53280 . 8202 sta 53281 . 8205 jsr 8214 . 8208 jsr 8221 . 8211 jmp 8205 . 8214 jsr 65508 . 8217 jsr 65490 . 8220 rts . 8221 ldx #0 . 8223 lda 8235,x . 8226 sta 53280 . 8229 inx . 8230 cpx #9 . 8232 bne -11 (223) . 8234 rts . 8235 b 6 14 3 7 1 . 8240 b 7 3 14 6 3 <<---------------------- END MACHINE LANGUAGE CODE Preparing to code a beast.. First, as with programming any computer, the systems architecture will be of utmost importance when deciding how to achieve the results that we want. We will not ignore the unique properties of the c64/128; but our goal is to explain machine language to the beginner. Inside your c64/128 is a chip called the VIC II. It is responsible for everything you see on the screen. When we changed the background ($d021) and border ($d020) colors, we were changing the registers of the VIC II chip. It has several modes of operation, including high resolution, medium resolution, character set graphics, extended background color mode, multicolor mode, and many more features. We will cover those areas that are important to us, but we will not indulge on these topics. It is in your interest to learn more about these graphics features, as they can make some cool effects possible Anyhow.. there is a mode called EXTENDED BACKGROUND COLOR mode. We can enable that mode with a basic statement of POKE53265,PEEK(53265)OR64. Now, if you have it enabled, type the following: lower case a, shifted a, reversed lower case a, shifted reverse a. As you can see, instead of getting the normal characters, you can have several background colors. In fact, we are limited to 64 characters, but we have a total of FOUR background colors. These are determined by the registers $d021 (NORMAL), $d022(SHIFTED), $d023 (REVERSED), and $d024 (REVERSE SHIFTED). So normal characters get their background color from $d021 as usual, shifted characters get their background color from $d022, and so on. What if we could get reversed characters with these additional background colors? Then, cycle the colors in that background color register, and it would look as if the letters were changing colors. If you type some reversed text and change the background colors, you see that the background color shows through the letters. If you fill the screen with the character color and then cycle the background color, it looks as if the color of the letters is changing. But, in the normal text mode we only have two colors (foreground and background), so all the words would be cycling colors. This is no good if we want to draw attention to one word or a few words. Now, with extended background color we can cycle three of the background registers with different sets of colors and leave one the same. But, it is not that simple, since we are limited to the first 64 characters. These are the normal characters and are not reversed. The character color would not change, and it would look as if the background colors were changing. This could be used to draw attention to words or letters. But I'd rather have the colors cycling inside the letters, wouldn't you? So are we at a dead end? No! We can use what is called a custom character set. The characters are stored in ROM. The first 64 characters just happen to be the normal characters (not reversed like we need). The ROM character set is located at 53248 to 56832. Notice that these locations are the same as the VIC II chip's registers. The VIC II can swap memory in and out without much trouble; how the heck we don't care! But, if we swap out the VIC II and copy those locations to RAM and tell the VIC II to look in ram and not ROM for the characters, we can get our custom character set which equals reversed characters with the extended background color mode! So, being the all powerful coder that I am. I know that 54272 through 54272+512 contain the sixty four reversed characters that we need. You can arrive at the 512 by multiplying 8 bytes of memory for each character times 64 characters. Really though, I never bother typing in numbers or code or anything - the tech dude does all the work. Below is what this looked like before the tech dude changed it. (DIAG A1) So *insert arrogant words here*. I know that *tech word* through *tech word* will *explanation*. *Humble reader* *tech word*. Really though, I never bother *action* in numbers or *whatever* the tech dude does all the work. *REF DIAG A1* is what this looked like *REF DIAG A1* the tech dude *action*. That is the way the entire magazine is drafted, no joke! -- Note from technical dude: Not! -- Okay.. anyhow back to our awesome program. We need to set extended background color mode, copy the reversed characters to ram, and then tell the VIC II to look in RAM not ROM for the characters. Sounds like a mission briefing.. but maybe it will not be that hard. HAHAH A Task..(The Best Note Maker Ever Published) -catchy! Here is this awesome note maker.. with explanations throughout. This is not the final program, but we will make a full fledged operational note maker, perhaps even in this Level. To change colors you can SHIFT what you type, REVERSE on, and even SHIFT reverse. (Below is the documented program. I will repeat it without added comments) ; Bonkers Note Maker v1 *= 8192 chrout = $ffd2 getin = $ffe4 lda #0 sta 646 Location 646 sets the foreground color which will actually be the background color sense our characters will be reversed! On newer VIC chips, when #$96 is JSR'd to chrout, the value that is in 646 is used to initialize color memory. lda #$93 jsr chrout Here we clear the screen. lda #$00 sta $d020 We set the border color register to black lda #$01 sta $d021 Do not be fooled.. ehhe, we are setting the background color register to white, but our characters are reversed so this is actually the foreground color. sei This turns off the interrupts, it is a new opcode which you may use quite a bit or you may not use much at all. SEI (Set Enable Interrupt), turn em off! We do this because we are switching out ROM. If an interrupt occured when ROM is switched out, the KERNAL calls during this time would crash our program! This, by the way, would be bad. copychar lda 1 and #251 sta 1 What we do here is switch out the VIC chip's memory in our to access the ROM behind the chip. The AND is also a new opcode, it can be used to turn bits off. Do not worry about it, we will devote a lot of time to it in the future. ldx #$00 Getchl lda 54272,x sta 12288,x lda 54272+256,x sta 12288+256,x inx cpx #255 bne getchl Here is a loop to get our 64 characters. Notice that we use two sets of LDA/STA to access more then 256 locations, since the X register can hold only values 0 through 255. lda 1 ora #4 sta 1 Here we switch the VIC II back into memory. Notice that the ORA is a new opcode, it can be used to turn bits on. Again, we will devote several pages to these new bit operations. cli Now that we have switched ROM back in, we allow the VIC II chip to interrupt so it can do its own maintenence things like processing keyboard inputs. lda 53272 and #240 ora #12 sta 53272 These 4 instructions, which do the same as the BASIC statement: poke 53272, (peek(53272) and 240) or 12, tells the VIC II chip to use the charset located at 12288 in RAM. From now on, we use the reversed charset that we copied from ROM. lda 53265 ora #64 sta 53265 Here we set the VIC II chip to EXTENDED BACKGROUND COLOR mode, giving us access to four background colors. main jsr wordproc jsr memodisplay jmp main The powerhouse is this loop. The processor will jsr wordproc, and when it gets to the rts, it will return to jsr memodisplay. The next instruction will be jmp main, and it will start all over again. wordproc jsr getin jsr chrout rts This subroutine calls two kernal subroutines which get a keyboard character and output a keyboard character. memodisplay ldx #$00 memloop lda col1,x sta 53282 lda col2,x sta 53283 lda col3,x sta 53284 inx cpx #9 bne memloop rts This code puts 9 colors in each of the 3 registers for a smooth cycling effect. col1 .byte 6,14,3,7,1,7,3,14,6 col2 .byte 11,12,15,7,1,7,15,12,11 col3 .byte 9,4,8,7,1,7,4,8,9 Here is our color data. First we have a smooth blue blend, then a gray blend, and finally an orange blend. Here is the code without the comments. Note you can add your own comments with the ";" and make notes and reminders to yourself. It is always a good idea to comment programs. ; Bonkers Note Maker v1 *= 8192 chrout = $ffd2 getin = $ffe4 lda #0 sta 646 lda #$93 jsr chrout lda #$00 sta $d020 lda #$01 sta $d021 sei copychar lda 1 and #251 sta 1 ldx #$00 getchl lda 54722,x sta 12288,x lda 54272+256,x sta 12288+256,x inx cpx #255 bne getchl lda 1 ora #4 sta 1 cli lda 53272 and #240 ora #12 sta 53272 lda 53265 ora #64 sta 53265 main jsr wordproc jsr memodisplay jmp main wordproc jsr getin jsr chrout rts memodsiplay ldx #$00 memloop lda col1,x sta 53282 lda col2,x sta 53283 lda col3,x sta 53284 inx cpx #9 bne memloop rts col1 .byte 6,14,3,7,1,7,3,14,6 col2 .byte 11,12,15,7,1,7,15,12,11 col3 .byte 9,4,8,7,1,7,4,8,9 Did you have fun playing with the note maker? I did, but it wasn't easy hitting shift, reverse on, and reverse off. And since this isn't UNIX, we can actually make it easy to use, so we will! What we will do is assign the function key F3 as a reverse on, reverse off switch. So that one tap and you get your colors, tap again and it will turn off reverse mode. And you get the other colors if you shift with it on or off. It would be even better to assign each color a function key, but that will have to wait.. below is the code you should change.. wordproc jsr getin cmp #134 ;Check for F3 beq rvsmode ;If so then go set rvsmode jsr chrout rts rvsmode lda flip1 ;On/Off variable cmp #0 ;If it is off then turn it on bne rvsoff rvson lda #18 ;It is off, turn rvs mode on jsr chrout ;output rvs on lda #1 ;Set our variable to on sta flip1 ;mode rts rvsoff lda #146 ;It is on, turn rvs mode off jsr chrout ;output rvs off lda #0 ;set our variable to off mode sta flip1 ;be sure to save it rts flip1 .byte 0 Check out the BEQ this means (Branch If Equal) it is the opposite of BNE (Branch If Not Equal). The above code runs off of the simple concept: if flip1 is on turn it off, if flip1 is off turn it on. It will always be equal to one or zero. Sometimes, these little things can get confusing, but a little trial and error will always help! ___ Power-up Time ____ Questions //\\//\\// 1. Tell what the instructions SEI, CLI, BNE, BEQ, AND, and ORA do. (Note we did not truly go into detail on AND/OR, so a general idea will do) 2. What is a monitor? What is an assembler? Compare and contrast. 3. Can we address more then 256 locations with indexing? Explain how. 4. Replace the existing .byte statements with different numbers. (Check a chart to get the specific colors that you want) 5. Change the number of colors that the memloop uses. Hint: change the cpx #9 and col1, col2, and col3. 6. Change the F3 RVS/RVS OFF key to F5 RVS/RVS OFF. Hint: F5 has a value of 135. ___Stage Boss___ Add some text telling how to use the program. Like a simple text introduction. If you're really brave, add a pop-up help feature. This could be quite a challenge. You will have to save the contents of the screen memory, which starts at location $0400, and restore it. Stage #01 Completed. ______Things You've Learned_____ Well.. you learned how to code in an assembler. You modified a useful note program. You learned the most common assembly terms. You increased your programming skills, and you have a general idea of how the new instructions work. _____Level #03 Completed_____ Sorry to end it up so soon, but we do have deadlines. You can look forward to the next issue though; we will continue to develop our note program (the final version will have save, music, edit, and multiple pages!). We will also look into common assembly problems, and we, of course, will have a follow up on some of those new mysterious instructions and much more! In addition we may have some special issues coming up soon. Well no more delays.. so enjoy and grab another! The Bonkers Staff