6809 ASSEMBLY LANGUAGE PROGRAMMING CLEARING THE LOWRES SCREEN I commend your patience; after last month, I was worried you might not come back! As I promised last month, I will provide a programming problem this month and I will also explain how to assemble a simple program. We shall be working on a simple problem this month. Hmmm. Clearing the screen seems pretty simple--I know BASIC's CLS command does this for us but let us assume for now that BASIC did not come with such a handy command. To answer the question you are probably asking: we shall be working with the low resolution text screen; it is the simplest to program. The following is a BASIC program to clear the screen (I Know! the topic is not BASIC. Bear with me, please): 10 FOR X = &H400 TO &H5FF 20 POKE X,&H60 30 NEXT X This is a simple routine which puts a space into each individual location on the screen. The "&H" stands for hexadecimal. The lowres text screen starts at $400 and ends at $5FF. The internal code for a space on the lores text screen is $60. We will use basically the same technique in assembly language. First, we must decide what registers to use. Since we will be using an address which needs incrementing each time through the loop, why don't we use the X index register to hold the current address. We also need to store a value somewhere where it is easily accessable. This is what the accumulators are for. Let's use accumulator A. (A voice from the back row asks, "Why not B?" No reason, we just have to choose one.) The next problem is planning the logic of the program. Some people can just sling code at the computer and make it work, but most of us have to do some sort of ground work. This is one way to do it (it's a sort of basic flowchart): load beginning of screen to X ` \ / get value of a space ` \ / --> store a space at X ` ` ` \ / ` increase X ` ` ---(no) are we done? (yes) ` \ / return to calling routine The first statement indicates that we are loading an address into X. This would indicate a load instruction, in this case, LDX. We have an instruction which can use different addressing modes: immediate, direct page, extended direct, and indexed. Since we know the address is not going to change, we can use immediate: immediate addressing is usually used to store a constant in an instruction. We also remember that the screen starts at $400 so we use this as the immediate data: LDX #$400. The next instruction we need is also a load instruction which also is loading a constant. We decided above that we would use accumulator A to hold this value, which we can recall as $60. This would give us the instruction: LDA #$60. The next instruction is a store instruction with accumulator A since that is where the space code is stored. We will be storing it at the current location on the screen which is stored in X. This implies indexed addressing since the address is likely to change. We know the instruction will be STA in an indexed form, but which one? The next instruction, increase X, signals that we will want auto-incrementing. The chart last month states that we use the form ,R+ for one byte increments. Since we are using X we can substitute X for R. This gives us the instruction: STA ,X+. Next, we want to compare X to the end of the text screen. This would be a CMPX instruction. Again, the end of the screen is constant to this would imply that we should use immediate addressing: CMPX #$5FF -- recall that $5FF is the end of the screen. Now that we have compared X to the end of the screen, how do we branch as the flow chart says we must if we are not finished? This involves branching instructions; they cause a branch if a condition or set of conditions is met. Since if X is equal to $5FF or if it is less, we still must store spaces to the screen, we will be needing a "branch if lower or same" instruction. This is BLS according to last month's chart. One more problem with this instruction; where are we going with the branch? The line points to the store instruction so we must find some way of labelling this instruction. Assembly language allows us the use of symbols which we use at points we wish to reference from the program, so we could put a symbol like LOOP at the store instruction and then branch to LOOP. This would make that instruction BLS LOOP. If we do not branch, we must exit the routine in a controlled manner. This involves a "return from subroutine" instruction: RTS. We do not need an argument for this instruction; it does only one thing: it returns control to the calling program. Our finished code would appear as follows: 00010 CLRSCN LDX #$400 00020 LDA #$60 00030 LOOP STA ,X+ 00040 CMPX #$5FF 00050 BLS LOOP 00060 RTS Note that the CLRSCN label is used to reference the routine from other programs and when naming it in a document. The line numbers are a convention in an assembly language listing. They serve no purpose except in referencing a part of the code quickly. The next step is to enter the code into aneditor/ assembler such as EDTASM+ and assemble it. If you do not have EDTASM+ or a similar package, don't fret; there is a way to assemble the program without one. This process is described for CLRSCN below. This is where all those tables from last month come in. Hand assembly is not always an easy process, but it is not impossible. First you look up all the operation codes for instructions and make a note of them. For example: 8E 00010 CLRSCN LDX #$400 86 00020 LDA #$60 A7 00030 LOOP STA ,X+ 8C 00040 CMPX #$5FF 23 00050 BLS LOOP 39 00060 RTS The immediate addressing only requires that the operand be converted to the appropriate number of bytes of hexadecimal numbers and added to the code. The indexing operation is a different story: The table last month states that the operand byte for the ,R+ operation is 1RR00000 in which RR=00 for X. We must convert this to hexadecimal. We take the first four bits (1s or 0s) and look them up for their equivalent and repeat this for the last four and put these together to get $80. Plug this into the code. The following is a binary to hexadecimal conversion chart: 0000 -> 0 1000 -> 8 0001 -> 1 1001 -> 9 0010 -> 2 1010 -> A 0011 -> 3 1011 -> B 0100 -> 4 1100 -> C 0101 -> 5 1101 -> D 0110 -> 6 1110 -> E 0111 -> 7 1111 -> F Finally the BLS instruction is the most difficult to assemble. This uses an 8-bit offset in which if the first bit is a 1, the value is negative. This offset is from the address immediately following the offset byte(s). To find this, we must know how many bytes we must skip over and in which direction. We know we must go backwards so this is negative. Now we count the number of bytes to the begining of the destination instruction (including our branch instruction if negative): I counted 7. Now we must find out the value of -7 in hexadecimal. We do this by counting back from 0 staring at $FF as -1. Here goes nothing: $FF...$FE...$FD...$FC...$FA...$FB...$FA...$F9. $F9 is our offset! We plug this into the code and it is complete! Now to throw a monkey wrench at you: we must put this code somewhere in memory so that it can be executed. We set the location of assembly by using the ORG instruction followed by the address of our choosing. For example we could put our program at $7F00 with an ORG $7F00. This means to start with the first instruction at $7F00. It is very important that you choose a location before assembling a program if it uses direct addressing in its jumps (JMP, JSR). Now our program looks like this: 7F00 00010 ORG $7F00 7F00 8E 0400 00020 CLRSCN LDX #$400 7F03 86 60 00030 LDA #$60 7F05 A7 80 00040 LOOP STA ,X+ 7F07 8C 05FF 00050 CMPX #$5FF 7F0A 23 F9 00060 BLS LOOP 7F0C 39 00070 RTS 7F00 00080 END CLRSCN The end instruction signals the end of assembly. Its argument signals the entrance address (indicated in machine code as a value without an address). You must use the /AO switch if using EDTASM+ to assemble this program (or any program with an ORG) Now we can use a simple BASIC program to get this to memory and execute it: 10 CLEAR 200,&H7EFF clear memory above $7EFF for code 20 FOR X=&H7F00 to &H7F0C get code to memory at $7F00 30 READ A$:POKE X,VAL("&H"+A$) get values from data to mem 40 NEXT X 50 DATA 8E,04,00,86,60,A7,80 machine code data from 60 DATA 8C,05,FF,23,F9,39 assembly listing above The values in the data statements are the codes we were building earlier in this column. You can call this routine through an EXEC &H7F00 after the above program is run. You can execute any machine language routine (assembled program) with an EXEC if it ends with an RTS. Compare this routine with the BASIC one presented above and notice how much faster assembly language is than BASIC!