BBC ASSEMBLY LANGUAGE - SIMPLIFIED EXPLANATION Revised Version May 1993 Daniel Shimmin, The Queen's College, OXFORD. Memory & Storage ================ A BIT is a single section of the computer's memory. It can be either on or off. If it is on it represents the value one, if it is off it represents the value zero. To store larger numbers eight bits are grouped together into a BYTE. A byte can store any whole number between 0 and 255. The computer's memory contains 65536 bytes, numbered between 0 and 65535 in decimal or between &0000 and &FFFF in hexadecimal. (HEXADECIMAL is a numbering system that uses the letters A to F as well as the numbers 0 to 9. The details of hexadecimal mathematics are fairly dull and mostly irrelevant, but do not confuse hexadecimal and decimal numbers; the hex ones have the & symbol before them.) The location of an individual byte in memory is an ADDRESS. It will be a number between &0000 and &FFFF, since hex is nearly always used for addresses. The contents of a byte in memory can be printed on the screen from BASIC by PRINT ?&addr or PRINT CHR$(?&addr) where addr is the hex address of the byte, or loaded into the accumulator in assembly language by LDA &addr If we want to store an address in memory we must use TWO bytes. This is because one byte can only hold up to 255, and an address could be up to 65535 (&FFFF) as explained above. Addresses are therefore called SIXTEEN-BIT ADDRESSES since to store them you need two bytes of eight bits each. The 6502 Registers ================== The registers in the 6502 are like variables, but there are a lot less of them. They are: The accumulator (A) The X register (X) The Y register (Y) The status register All of these registers contain eight bits and so can store any whole number between zero and 255. Remember that a byte in memory can also only store a number up to 255. All programming in assembly language involves using at least one of the registers to store numbers. The status register cannot normally be used. The Assembler ============= Most of the BBC series of computers contain an assembler that works in BASIC. This allows you to write assembly language in a BASIC listing. The best syntax is as follows: 10 FOR I%=1 TO 2 20 P%=&900 30 [ OPT I% 40 .. -assembly language here- 270 280 ] 290 NEXT To execute the machine code created by this program from BASIC, you would type,"CALL &900". How the assembler works ======================= Every assembly language instruction (e.g. LDA or JMP) has a hex value that represents it (e.g. A9 or 4C). It is NOT necessary to learn these values since the assembler will assemble them in for you. What the assembler does is to take each instruction in your assembly language program and place it in memory, starting at the address that you have chosen (P%). When the assembler comes to a variable that you have put into the program, e.g. 510 .loop it will simply set up a BASIC variable called "loop" with the value of the address that it is currently assembling at. For example if, when the computer gets to line 510, it is assembling in at &907, it will set up loop as the decimal equivalent of &907. This means that if later you want to put in a JMP command that will make the program jump back to the point where "loop" is in the assembly language, you do not need to type in JMP &907 but you can just type JMP loop and the computer will fill in the address (&907) for you. Note that if the assembler comes to a variable (e.g. JMP loop) that has not been set up yet (by .loop) it will simply ignore it. When it goes through the assembly language the second time (since you are using a FOR...NEXT loop it will go through it twice) it will fill it in then. For example, if your assembly language program started like this: .loop LDA _37 JMP loop the assembler would assemble this at these addresses (all in hex): addr value assembly language ------------------------------------ 0900 A9 LDA _ 0901 25 37 0902 4C JMP 0903 00 ) Address of loop, i.e. 0904 09 ) &900 When the BASIC assembler assembles code into memory it also produces a listing of the code being compiled in to make things simpler. It often helps to study this listing carefully so that you know what is going on. Comments (cf. BASIC REM statements) can be added to assembly language programs by inserting a backslash (\), then the comment after it. Subroutines =========== The BBC contains a number of subroutines which can be used to perform certain functions. To execute these subroutines you can use either CALL &addr from BASIC where addr is the sixteen-bit address of the routine, or JSR &addr in assembly language. Most of these routines require you to supply them with certain parameters (numbers) to work with, and this is done by loading the accumulator and/or the X and Y registers with the necessary eight-bit number. Similarly some of the routines will return certain values in some of the registers. --------------- JSR &FFE0 will wait for a key to be pressed and will then return the ASCII value of the key pressed in the accumulator. JSR &FFEE will print on the screen the ASCII value held in the accumulator. JSR &FFE3 does the same as &FFEE but will do a carriage return (i.e. RETURN on the keyboard) if the ASCII value is 13. JSR &FFF4 performs *FX calls. On calling the subroutine A should hold the first FX value, X the second and Y the third. JSR &FFF7 does operating system ("*") commands. This routine requires a string of characters ending in 13 somewhere in memory. This string will be the command that the routine will carry out. The high byte of the address of the string (addresses need two bytes, remember?) should be loaded into X and the low byte into Y. This is most easily done by LDX _addr MOD 256 LDY _addr DIV 256 JSR &FFF7 .addr EQUS"CAT" : EQUB 13