....|....|....|....|....|....|...|....|....|....|....|....|....|..... Alphanso's Assembler Assylum Assembly Language for the Beginner .;SHARON...THIS IS A NEW SERIES. THE 1ST LINE OF TITLE SHOULD BE BIG .; AND THE SECOND LINE AS A SORT OF 'SUB TITLE'... OK? by Dave Heyliger - AMUS Staff So me and the 'Fonz' decided that there is a desparate need to have everyone completely destroying their monitor and operating system through the use of the destructive tool called assembly language. Yes, beleive it or not AMUS fans, this is yet another one of those 'how-to' type series dedicated to the end-user out there who is ready to explore the internal guts of their machine. This series will introduce you to assembly language programming on the Motorola 68000 microprocessor (you know.. the one inside your Alpha). I am determined to give you step-by-step, byte-by-byte explainations that will take most of the mystery out of assembly programming. Get psyched, get pumped, (and get everyone off the machine!) cuz it's gonna get ugly! (We assembly language programmers use 'Rambo' type lingo when we get excited). Charge!!! Hardware before Software An assembly language program 'talks' directly to the hardware. You have the power to change almost anything with incredible speed and power. In fact, you actually have to know the hardware of the machine before any coding or programming can occur, so let's take a quick look at the Motorola 68000 (simplified): Motorola 68000 +----------------------------------+ | ################################ | D0 | ################################ | D1 | ################################ | D2 Data | ################################ | D3 Registers | ################################ | D4 | ################################ | D5 | ################################ | D6 | ################################ | D7 | | | ################################ | A0 | ################################ | A1 | ################################ | A2 Address | ################################ | A3 Registers ---|-################################ | A4 | | ################################ | A5 | | ################################ | A6 | | | | | ################################ | A7 | | ################ | SR | +----------------------------------+ | V 32 bit magnified picture of register A4 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 31 15 7 0 |---- byte ----| |----------- word ----------| |------------------------- long word -------------------------| Basically, the Motorola 68000 contains DATA registers and ADDRESS registers (D and A registers). There are 8 data registers and 8 address registers, and although they may look the same, the machine will handle these registers differently. Obviously, addresses will be stored in the A registers, and 'data' will be stored in the D registers. Each register consists of 32 bits that may be either ON or OFF. This is how the computer stores all types of information (see Heyliger's Highlights, Nov. '85). There are different ways to 'talk' to the registers: you may tell the register that you are only interested in a byte (8 bits), a word (16 bits) or a long word (32 bits). The default for most commands to the registers are long words (the example program below talks to the registers in bytes). Before I discuss the address registers, it might be helpful to understand how the computer stores information in MEMORY. Basically, your computer contains a series of tiny electronic storage cells. You could think of these cells being contained in an ARRAY. Each element in the array is a memory cell that can hold a byte of data. To access the individual memory cells, you could simulate an access just as in BASIC with an index (or pointer) to the array. Let's look at it graphically: individual byte \ MEMORY [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ]....(array) 0 1 2 3 4 5 6 7 8 9 ....(index) If you knew that memory location 5 had a value of 'sum' stored in it, then sum := memory[5]. Think of the '5' as the memory ADDRESS. Since your computer has quite a bit of storage (perhaps a few megabytes), the array index value can be quite large (0..1,000,000+). Fortunately, the 68000 has address registers that can contain such large values so that they can still hold the 'pointer' to the location in memory. Also, if the value of 'sum' takes more than one byte to store the entire value, the byte(s) following location number 5 will contain the rest of the data. When the computer is asked to retrieve this data (and the computer realizes that it is more that one byte long), it will retrieve the correct number of bytes starting at location 5 and continue up to the last byte of 'sum'. The way in which addresses are stored (i.e., what NUMBER is in any A register at any one time) is not too important. We'll see that the machine will place addresses into the A registers with the 'correct' NUMBER. More important is to understand how we TELL the computer to 'go get an address'. The example programs will go into this detail further. Nine times out of ten, the NUMBER in an A register that represents a valid address of one of your memory locations inside your computer will be POINTING to that memory location (the actual physical byte). Again, the examples in this series will repeatively demonstrate pointing etc. The D registers are the exact opposite. We WANT to know what NUMBER is in them, and we can also directly tell the computer to put any number we want into any of the D registers. D means DATA or numbers, whether these numbers represent characters, values, RAD50, or whatever. Sample programming will further enlighten you. A few extra notes on the 16 registers. Notice that I set the A7 register off from the rest of the address registers. This register is used to POINT to a STACK if the user has so defined one. A STACK is very useful when developing subroutines etc. If you don't know what a stack is, you will learn in the months ahead. Also, there is one more register that has not been covered, and this register is the Status Register. When you do addition, subtraction, or move data between registers, certain bits inside the Status Register will be turned on or off depending on if the move involved a zero, if the subtraction was a negitive result, etc. This will allow you to do GOTO's just like in BASIC just by checking these bits (usually called FLAGS). AMOS/L Makes Life Easier The people who designed the 68000 came up with certain 'commands' that the processor would understand. These commands are usually refered to as the 'instruction set'. Every 68000, whether it is in an Alpha Micro, a MacIntosh, or any other machine, will support the standard instruction set. So far so good. AMOS/L has supplied the assembly programmer with a very large set of MONITOR calls, which act just like an instruction from the instruction set, but are UNIQUE to the Alpha Micro and have their own unique name. These puppies are a real life saver. You can read about these calls in the AMOS/L MONITOR CALLS Software Manual (you will NEED this manual, along with AlphaFIX Manual, and the Assembly Language Programmers Manual, and, the 100/L Instruction Set Software Manual... get 'em from AMUS). Learning from Examples Now before I go on, I must tell you that I am no pro at this stuff. The way I have been learning is by READING other peoples programs. I recommend this approach strongly. In fact, what I suggest you do is to look at all of the .M68 programs from your AMUS tape that are in the [100,51] and [100,52] P,PN's. Most of these have comments (brief as they may be) so you can go through them step-by-step (using your manuals). You can learn very fast by reading other programs. With that in mind, let's disect a really simple program that simply prints the ASCII characters (ABC...xyz) to your screen. Note: all *.LIT files on you computer were 'created' by writing SOURCE code (VUEing a .M68 file), and then ASSEMBLING the source code file, and so that is what we will do below. Here is your first example program, ASCII.M68: ;***************************************************** ;* ASCII.M68 - Prints the ASCII letters to the screen ;* ;* Produces: ASCII.LIT ;* ;* Useage: ASCII [cr] ;* ;* by Dave Heyliger - AMUS Staff ;***************************************************** OBJNAM ASCII.LIT ;Final name will be this SEARCH SYS ;Here is where all of the SEARCH SYSSYM ;MONITOR calls unique to SEARCH TRM ;AMOS live, so get them. TOP: PHDR -1,0,PH$REE!PH$REU ;Re-entrant and re-useable. MOVB #65.,D1 ;MOVe to reg. D1 a decimal 65 LOOP: TTY ;MON. call to 'print' D1 out ADDB #1.,D1 ;ADD (byte) a decimal 1 to D1 CMPB D1,#123. ;See if D1 = decimal 123 BNE LOOP ;If D1 <> 123, branch to LOOP CRLF ;D1 = 123.. simulate a return EXIT ;and jump back to AMOS END ;End of assembly code. Line-by-Line, Byte-by-Byte The top of this program contains comments that tell the reader of the file what the program name is, how one is to use it, and any other information the creator feels necessary. Notice the ";" at the start of each comment line. Also notice that comment lines may occur anywhere in the file. OBJNAM OBJect File NAMe. This one-liner will allow the programmer to specify what the output file will be called. If you know it will be a '.LIT' file, then you may omit this line due to the default of {filename.M68} --> {filename.LIT}. If you were creating a subroutine for basic, you would have OBJNAM {file}.SBR, for example. SEARCH SYS,SYSSYM,TRM SEARCH (in DSK0: 7,7) SYS.UNV, SYSSYM.UNV, and TRM.UNV. It is in these files that all of the 'gizmo' monitor calls are defined, and so you will ALWAYS want to search these three files, even if you DON'T use them (a good 'just in case' practice). Therefore, every program you read will probably have these three SEARCH lines. TOP: PHDR -1,0,PH$REE!PH$REU First item to notice is the useage of TOP: as a LABEL. You may use any name you like for a label, with the following restrictions: 1) it must end with a colon : 2) 6 characters maximum in length, and 3) start your label in the first column. Labels are important in that the computer will 'mark' all program lines that have labels and remember where they are in the program. PHDR - this stands for Program HeaDeR. It is not a mandatory line, but this line will define certain characteristics of the program and will be checked if the program was to be loaded into system memory or user memory. Since all of the programs we will generate will be RE-ENTRANT and RE-USEABLE, we will always include this information in the program header line. The (-1) means you must be logged-on the computer, the (0) means zero privilege (don't worry about it), and PH$REE = re-entrant, PH$REU = re-useable. Re-entrant and re-useable (in basic terms) means that the program can be run anywhere in any one user's memory partition and still work, i.e., it is NOT memory dependent. The "!" will set BOTH of these 'flags' ON in the Header Status word (more of this in later articles). MOVB #65.,D1 Our first real instruction! When reading instructions, most 'flow' from left to right. MOVB means MOVe Byte (so 8 full bits will be moved). The #65. tell the computer 'this is the value of the Byte I am going to MOVe'. The "#" means 'number', and the "." means decimal. If we had left off the ".", an octal 65 (decimal 53) would be the byte in question. Finally, we are MOVing the Byte to data register D1. To read the entire line as the computer would understand it: 'move a byte whose value is 65 decimal into the D1 register'. Why are we moving a 65 into D1? Well, recall that the decimal ASCII value of 'A' is 65. 65 is our 'starting point' of our ASCII characters. The D1 register will hold this number for us (think of the register D1 as a variable starting out at a value of 65). LOOP: TTY Another label and our first MONITOR call! Remember, a monitor call is a pre-defined Alpha Micro command that will perform something for us. TTY simply means 'take the character in the D1 register and blast it to the screen, and then continue with the next instruction'. But you say "there isn't a character in D1, there is a number". You would be right. However, all characters are represented as numbers, and since the computer knows it is looking at a 'character', bingo! See how simple these monitor calls make our life?!! ADDB #1.,D1 This is an easy one. It looks like an ADD, but with a twist. It is an ADD Byte (so we really are only looking at the rightmost 8 bits in the data register when we ADD the number to follow). The Byte to ADD is a decimal 1, and the register we are ADDing it to is the D1 register. We are ADDing one to D1 because 'B' is decimal value 66, 'C' is a 67, etc. CMPB D1,#123. Another instruction, CoMPare Byte. This means that we will be comparing two Bytes of information. Whenever a CoMPare is performed, the Status FLAGS are effected (keep on reading...). So, in this line of the program, the computer reads this as 'CoMPare Bytes... one of the bytes is in D1, and the other byte is a decimal 123'. Nothing in any of the registers is affected, i.e. D1 still will have a 66 on the first time around ('z' is ASCII 123). BNE LOOP Branch if Not Equal. Branch if what is not equal?? OK, here's the poop: on any CoMPare line, the Status FLAGS are effected. Internally inside the processor, a CoMPare will subtract whatever we are comparing and then set the FLAGS accordingly, while at the same time, it will throw away the results AND leave the stuff we are comparing alone (WOW! Maybe you should read that again!). SO... the computer will 'subtract' the value 123 from D1, and if it is a ZERO (meaning the two values were indeed equal), the ZERO FLAG (one of the bits in the Status register) will be SET (turned 'on'). Let's make life easy and not worry too much about what other FLAGS the Status Register has, OK? For now, just remember that there is a ZERO flag, and it will be SET to ON if a CoMPare produces an 'invisible' result of zero (puff-pant). The Branch on Not Equal will look directly at the ZERO FLAG, and if it is NOT set (meaning the subtraction was not equal to zero), then Branch back to the line marked by LOOP. "OH!", you say, "a GOTO". How right you are! CRLF Another monitor call. This baby will simulate a Carriage Return Line Feed. When will this occur? Well, the statement directly before this is the Branch if Not Equal. If the ZERO flag IS set, then the branch will NOT happen, and the program 'falls through' to this monitor call. EXIT Another simple one. EXIT this silly program and return to AMOS. END This marks the end of the source for ASCII.M68 Getting your Program to Run I strongly suggest that you type this short program in using VUE, (VUE ASCII.M68) and then ASSEMBLE the program. Assemble is very similar to COMPIL for a BASIC program. To assemble the program, type a 'G' from the '>' in VUE, or type at the dot "M68 ASCII". The assembler (a program on the Alpha) will then take your .M68 file and create your .LIT file. Notice that you will see 'SEARCHING...' appear, since we told the computer to SEARCH for our monitor calls. Also notice how the assembler will report to you any errors, and the final size (in bytes) of your program. Again, type in this program so that you may see how the assembler works! When you have typed it in and assembled the program, type in ASCII at the dot and watch the program do its stuff. Enough for One Day Well, that will just about do it for the first of this series. If you DON'T have those manuals I mentioned, you WILL need them! Next time, we will do some work with the Address registers, and define in more detail the re-entrant and re-useable programming structure. There is a ton of small topics to be covered, so be patient with me. If after reading this action-packed article you are just dying for more information, I suggest the book "68000 ASSEMBLY LANGUAGE PROGRAMMING" by Kane, Hawkins, and Leventhal (Osborne/McGraw-Hill). This book discusses the general use of the 'instruction set', but has no information on the monitor calls that AMOS provides. Well, the Fonz and I are ready to cruse the Boulder Mall for chicks and chips (the chips are the Fonz' idea), so I'll see you machine crazed junkies next month. And remember, send chocolate covered peanuts (Sharon won't buy them for me anymore)!