Machine Code Article(s) PART I By Andrew Black This series of articles are only meant to deal with the basics of Machine Code and are NOT written by a expert! The first few parts of the series will be more techincal information that you need to understand and refer to before starting programming. At about Part III I will begin the real programming stuff. --------------------------------------------------------------------- This section is aimed to give a basic intoduction and explantion to Machine Code programming. --------------------------------------------------------------------- The 6502 Proccessor ------------------- The BBC range of microcomputers uses the 6502 microprocessor, which has a comprehensive set of instructions. Fortunately the BBC has a built-in assembler so that we can write our programs in mnemonics rather than pure machine code. The assembler may be used directly from within BASIC programs. This means that machine code may be assembled and called from a BASIC program while it is running, or the machine code may be saved and loaded into memory without a BASIC program. 6502 Registers -------------- The register structure of the 6502 is the ACCUMULATOR, PROGRAM COUNTER, X and Y INDEX REGISTERS, STATUS REGISTER and STACK POINTER. The diagram below illustrates this and shows that all the registers are 8 bits wide, apart from the program counter which is 16 bits wide. This allows 65,536 locations to be addressed (8 bits would give only 256 locations). Diagram of 6502 registers ------------------------- 7 0 (bits) -------- : A : Accumulator -------- -------- : X : -------- Index registers : Y : -------- -------- : P : Status register -------- -------- : S : Stack pointer -------- 15 0 (bits) ------------------ : PCH : PCL : Program Counter ------------------ The Accumulator --------------- The Accumulator can be reguarded as the main working area of the proccessor. It is used to carry out all the arithmetic and logical functions of the processor. The table below gives the list of all the instructions that act on the Accumulator. We will be using only a few of these to begin with. ADC - Add with carry AND - Logical AND ASL - Arithmetic shift left BIT - Compare memory bits CMP - Compare with accumulator EOR - Logical EOR LDA - Load the accumulator LSR - Logical shift right ORA - Logical OR PHA - Push accumulator PLA - Pull accumulator ROL - Rotate left ROR - Rotate right SBC - Subtract with complement of carry STA - Store the accumulator TAX - Transfer the accumulator to X register TAY - Transfer the accumulator to Y register TXA - Transfer the X register contents to the accumulator TYA - Transfer the Y register contents to the accumulator The Index registers ------------------- The Index Registers are referred to as the X and Y registers, and are often used to provide the 'offset' or index from a base address. They can be incremented and decremented directly, unlike the accumulator, which is why they are often used as counters. No arithmetic or logical operations may be carried out on the contents of these registers, but their contents can easily be transfered to the accumulator. The following table gives the instructions that act upon the Index Registers. CPX - Compare the X register CPY - Compare the Y register DEX - Decrement the X register DEY - Decrement the Y register INX - Increment the X register INY - Increment the Y register LDX - Load the X register LDY - Load the Y register STX - Store the X register STY - Store the Y register TAX - Transfer the accumulator to X register TAY - Transfer the accumulator to Y register TXA - Transfer the X register contents to the accumulator TYA - Transfer the Y register contents to the accumulator The Program Counter ------------------- The Program Counter contains the addresses of the next instructin to be executed. It consists of two 8 bit registers making up the 16 bit address. These two registers are referred to as Program Counter High and Program Counter Low. The Status register ------------------- This is an 8 bit register which consists of the status flags and will be looked at another time. The Stack pointer ----------------- The Stack Pointer is an important register when branchs need to be executed. The Stack Pointer keeps track of where to find the next free location in the stack. The stack is a special area of memory which will also be looked at another time. ---------------------------------------------------------------------- The Assembler ------------- In order to learn how to use the assembler from within a BASIC program we will look at an example program. Example 1.0 (File: ASS1) ------------------------- 10 REM * Example 1.0 * 20 SCREEN = &7C27 30 CLS 40 P% = &900 50 [ 60 .START 70 LDA #65 80 STA SCREEN 90 RTS 100 ] 110 CALL START * * This program will not work on any machine that uses shadow screen * * memory as it addresses MODE 7 screen memory directly ie. the * * Master. To make it work replace Line 80 with JSR &FFEE. Load the file ASS1 and run it. This program places the letter A at the top right hand corner of the screen. The function of each line is as follows ... Line 20 - Set the variable SCREEN to the address of the top right of the screen (&7C27). Line 40 - Assemble the machine code generated by the program at location &900 onwards. Line 50 - Indicate beginning of assembly langauge. Line 60 - Use a label to mark the start of the assembly langauge. Line 70 - Place the ASCII code for "A" in the accumulator register. Line 80 - Store the contents of the accumulator at location SCREEN. Line 90 - Return to BASIC. Line 100 - Indicate end of assembly langauge. Line 110 - Execute machine code. As well as executing the program, the assembler outputs a listing of the assembled machine code. This listing can be divided into five fields: Location Opcode Operand Operand Mnemonic 0900 0900 .START 0900 A9 41 LDA #65 0902 8D 27 7C STA SCREEN 0905 60 RTS Note that the address of the screen location has been listed 'back to front' with the low byte first. This is a result of the way in which the 6502 works. It requires addresses to be given in low byte first and the assembler has taken care of this for us. Memory Usage (Where to place your program) ------------------------------------------ The variable P% is used to set the program counter and thus determines where in memory the machine code is to be assembled. If the machine code is going to be long then careful consideration must be given to its location. I have used &900 in the first program and this is a fairly safe area for about two pages of memory (512 bytes). Longer machine code programs can be placed above the memory used by BASIC. The Memory Map -------------- Location Use &00- &8F Current language use. &90- &9F Econet use. &A0- &A7 Current NMI owner use. &A8- &AF OS command whilst executing &B0- &BF Filing system scratch space &C0- &CF Current FS use. &D0- &E1 VDU driver use. &E2 CFS status byte. &E3 CFS *OPT byte. &E4- &E6 General OS workspace. &E7 Keyboard auto-repeat timer. &E8- &E9 OSWORD input buffer pointer &EA 6850 use / timer counter. &EB CFS use. &EC- &ED Two key rollover use. &EE RAM copy of 1MHz bus reg. &EF Acc. value for last OSBYTE/ OSWORD call. &F0 X reg. " " " " &F1 Y reg. " " " " &F2- &F3 GSINIT/GSREAD text pointer. &F4 RAM copy of ROMSEL (&FE30). &F5 Speech/ROM FS use. &F6- &F7 Pointer for paged ROM read. &F8- &F9 NOT USED BY OS 1.2. &FA- &FC OS workspace. &FD- &FE Point to byte aftr last BRK &FF Escape flag. (Bit 7 set) &100- &1FF 6502 Stack. &200- &235 OS Call vectors (QV) &236- &28F Main system variables. (Accessed by FX166 - FX255) &290 *TV vertical adjust. &291 *TV interlace flag. &292- &29B System clock use. &29C- &2A0 Event countdown timer. &2A1- &2B0 Paged ROM type table. &2B1- &2CE Various OS use. &2CF- &2E9 Buffer flags + indices. &2EA- &2ED CFS use. &2EE- &2FF Space for OSFILE ctrl block &300- &37F VDU workspace. &380- &3DF CFS use. &39F-&3A6 NOT USED BY OS1.2 &3E0- &3FF Keyboard input buffer. &400- &7FF Current language use. &800- &83F Sound workspace. &840- &84F Sound channel 0 buffer. &850- &85F Sound channel 1 buffer. &860- &86F Sound channel 2 buffer. &870- &87F Sound channel 3 buffer. &880- &8BF Printer buffer. &8C0- &8FF ENVELOPES 1 - 4. &900- &9BF ENVELOPES 5 - 16 or RS423 output buffer or Cassette output buffer. &9C0- &9FF Speech buffer or Cassette output buffer. &A00- &AFF Cassette input buffer or RS423 input buffer. &B00- &CFF Econet workspace (previously soft key expansion buffer + char. definitions.) &D00- &D9E NMI routines. &D9F- &DEF Expanded vector set. &DF0- &DFF Paged ROM workspc pointers &E00-&7FFF User/screen RAM. - Some of this may be taken for paged ROM workspace (eg DFS takes to &1900). - Screen memory :- &3000-&7FFF MODEs 0,1,2 &4000-&7FFF MODE 3 &5800-&7FFF MODEs 4,5 &6000-&7FFF MODE 6 &7C00-&7FFF MODE 7 &3000-&7FFF Shadow screen RAM &8000-&BFFF Paged ROMs/RAMs. The above memory map is very comprehensive and you really only to look at it for occasional reference. Areas &900 to &AFF can be used as a machine code area Area &B00 to &BFF can be used with the loss of function keys Area &C00 to &D00 can be used with the loss of charcter definitions If you have a disc system your computer could use the area &D00 to &1900 for disc workspace. If your computer does use this area DO NOT place machine code programs in (the computer might crash). When writing machine code programs using the assembler do NOT set the P% to &1900 or anywhere that has the BASIC program, variables stored. It will crash. IF you want to place machine code above the areas set aside by the operating system then you have to manipulate the values of PAGE, LOMEM, HIMEM and TOP. These are pesudo-variables used by BASIC to determine where in memory BASIC programs can store variables etc. These techniques for small programs are really unnecessary. You can use the DIM function to reserve memory space within the program for the machine code. This is how you would use it: 10 DIM AREA 9 (area in bytes) 20 P% = AREA 40 [ . . Machine code . 100 ] 110 CALL AREA Numbers ------- The assembler accepts numbers in decimal or hexadecimal. Any number preceded by an an amperstand (&) is considered a hex number, else it is reguarded as decimal. eg. 65 - Decimal &41 - Hexadecimal Labels ------ When using a label to indicate a position within the program they must begin with a full stop followed by a letter(s). A label name can have up to 255 characters and must not have any spaces between the letters. Labels are very useful since it is much easier to use CALL START than CALL &D00. This is even more important when calling subroutines whose locations would have to be calculated. eg ... .hello_there or .abcdefghijklmnopqrstuvwxyz Comments -------- In BASIC REM statements are used to clarify pograms (wanna bet!), and comments can also be inserted into assembly language programs. Instead of writing REM the backslash (\) symbol is used. In MODE 7 this looks like a half symbol. 70 LDA #67 \ Place ASCII value of 'C' in accumulator Notes ----- Machine Code mnemonics unlike BASIC commands can have mixed upper or lower case letters eg. LDA or lda or LdA or lDa or lDA or LDa are all perfectly valid. However for clarity it is best just to use Upper case letters. ---------------------------------------------------------------------- This may seem like a lot learn but it is neccessary if you want to program in machine code. Experiment with the the assembler, maybe write a program to print your name in MODE 7. By about Part III of this series we will start programming properly as I will have gone over most of the assembler and proccessor commands. The next part of this series will look at more functions of the 6502 and addition - subtraction in machine code. ---------------------------------------------------------------------- Any suggestions concerning machine programming or particular aspects, write in and tell me and I will try to feature it.