»SML:»CL9:-------------------------------------- »SML:»CL8: »BIG:Coder's Course »SML: »BIG:Part 1 »SML:»CL9:-------------------------------------- »CL4: By Cytron/Depth »CL0:OK, all you dear »CL1:"I've seen a lot of demos and want to code"»-sceners, I'm offering you a nice little assemblercourse for free. I guess that there are loads of those already, but as I learned coding pretty easy myself, I thought that my approach might be a good one. The approach is simply »CL1:getting into all the good sides of Amiga right away» - let the assembler do the understanding for you in the beginning, and just code something. And don't worry about copper, blitter, c2p, etc.. Just learn to control simple methods right away, and make a few small things that demomnstrate that 'I can do it', and makes you want to go further into it! ANYWAY, that was my appoach 6 months ago, and I've coded 3 demos already. Besides, I'm working on a 4k. So, this is what YOU can do in 3 months from now! Anyway, let's get started with... »CL8:The simple mathematical stuff, that ALL sceners should know!: »SML:»CL1:Hexadeciaml representation:»CL0: When writing $FE it simply means 254, namely 16*$F+$E = 16*15+14=254. »CL1:Signed/Unsigned:» When viewing at a number as signed, The most significant bit determines the sign.. If set, the number is negative and the number is all the other bits inverted plus 1. This is easier to see than to explain: eg., signed words: »CL1: $FE65 = -$019B = - 411 $3444 = $3444 = 13380 $FF56 = -$00AA = - 170 $8645 = -$79BB = - 31163 $5634 = $5634 = 22068 $0064 = $0064 = 100 $C000 = -$4000 = - 16384 $FFFF = -$0001 = - 1 » »CL8: »BIG:The registers: »SML:»CL9:-------------------------------------- »CL0:The MC68xxx contains »CL1:16 registers, 8 data- and 8 address-registers (d0-d7 and a0-a7)». The difference between the two types of registers will be explained later in this chapter. From now on, aX will mean an addressregister and dX will mean a dataregister. The registers are 32-bit, simply meaning that a register contains 32 bits of data, that is up to $FFFFFFFF. When using commands that refer to registers, one has to specify which part of the register is being used. Let's look at the three ways of 'looking at' a register, »CL1:eg. if d0 = $FE673C41, then d0 as longword is $FE673C41 d0 as word is $3C41 d0 as byte is $41 »It's as simple as that! When using this principle in an assembler, one simply writes »CL1:d0.l», »CL1:d0.w», or »CL1:d0.b» (Omitting this will usually make the assembler »CL8:The basic instructions for this part: »BIG: move, add, sub, muls/mulu »SML:»CL9:-------------------------------------------------------------------------------- »CL0:All of these instructions have the following usage: »CL1: command a,b »CL0: means do the command from a to b. eg.»CL4: move.w d1,d2 »CL5: ; move the contents in d1 as word to d2 as word. »CL4: add.b d7,d0 » ; add d7.b to d0.b. Please note that only the byte in ; d0 is affected, no matter what the result of the add is. »CL4: sub.w d0,a0 » ; subtract d0 from a0. (Remeber to check the note ; about addressregisters later) »CL4: mulu.w d0,d0 » ; multiply d0.w Unsigned with itself and put it in d0.l ; (this one is special, since we're multiplying) »CL4: muls.w d3,d2 » ; multiply d3.w with d2.w both viewed upon as SIGNED, ; and store the result in d2.l signed. »CL0:interpretate it as d0.w, but »CL1:PLEASE» get used to »CL1:ALWAYS» writing the extensions. The code get's easier to grasp that way!) »CL8: »BIG:Regarding address/dataregisters:»SML: »CL9: ----------------------------------------------- »CL0:Addressregisters are mainly used to The simplest addressing modes: point onto some memory, not to perform When wanting to read/write from/to arithmetic instruction upon. memory, the smartest approach is to Therefore, only add, sub and move store the source/destination-address works with addressregisters.. And it's in an address-register, and then a little more complex than that. So, writing to the memory from there. To for now, just leave the demonstrate this, I'll make a little adressregisters when doing example that will also show you the arithmetical instructions. IMMEDIATE priciple: »CL4:Start: move.l #30,d0 »CL5:; Moves 30 into d0. d0 = $0000001E »CL4: lea Space,a0 »; Let a0 point at Space »CL4: move.b d0,(a0) »; move d0 as byte into Space. Space = $1E000000 »CL4: move.w d0,(a0) »; move d0 as word into Space. Space = $001E0000 »CL4: move.l d0,(a0) »; hehe... Space = $0000001E »CL4: rts »; Return to assembler »CL4:Space: dc.l 0 »; When this is assembled, Space = $00000000 »CL0:As you see, using »CL1:(aX)» means »CL1:AT» the address stored in aX. You might also mark that I've used an immidiate move. I've moved the number 30 into d0. »CL1:(You might wonder why I've moved as longword. The reason is that I clear the entire register, so that I know for sure that d0.l = $0000001E)» »CL8:»BIG:Let's start up our assembler: »CL9:»SML:-------------------------------------- »CL0:It's time for you to experiment a little bit yourselves. Being in an assembler and watching what happens is the fastest way to learn anything. I will strongly recommend you to use »CL1:AsmOne 1.29», as this assembler is very straightforward and has a brilliant singlestepdebug feature (What a great word!). These examples apply for AsmOne 1.29. They might work in other assembler as well, but I wouldn't know! Type the little program, I've made, in your assembler (Escape of course toggles between editing the source and controlling the whole thing). Now try this: »CL2:a» The thing should now assemble your code in hopefully report No Errors. When this is done, try typing »CL2:h Space» Now a lot of numbers should pop up at your screen. Like this: »CL7:0822450C 00 00 00 00 12 34 56 78 01 01 00 00 00 08 00 00 ".....4Vx........" 0822451C 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 "................" 0822452C 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 "................" »CL0:^^^^^^^^ ^^ ^^^^^^^^^^^^^^^^ Address Data as Hex. Each line contains 16 bytes of data. Data as AscII (Escape let's you out again) What we've just seen is the data at the label Space. If we change the line »CL4:Space: dc.l 0 »to »CL4:Space: dc.l $CAFEBABE », our memory will (after assembling again) look like this: »CL7:08224514 »CL6:CA FE BA BE» 12 34 56 78 01 01 00 00 00 08 00 00 "Êþº¾.4Vx........" 08224524 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 "................" 08224534 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 "................" » »CL0:As you can see, The memory has now been changed. Now let's try writing: »CL2:h Start »CL7:08224500 20 3C 00 00 00 1E 41 F9 08 22 45 14 10 80 30 80 " <....Aù."E..`0`" 08224510 20 80 4E 75 CA FE BA BE 12 34 56 78 01 01 00 00 " `NuÊþº¾.4Vx...." 08224520 00 08 00 00 00 00 00 00 00 00 00 00 00 00 00 00 "................" »CL0:Now, we're at another location in memory close to the other one (you can see CAFEBABE someplace!) While we're in this HEX-viewer, try pressing »CL1:RAMIGA+d» (Disassemble). Now we get: »CL7:08224500 203C0000001E MOVE.L #$0000001E,D0 08224506 41F908224514 LEA $08224514,A0 0822450C 1080 MOVE.B D0,(A0) 0822450E 3080 MOVE.W D0,(A0) 08224510 2080 MOVE.L D0,(A0) 08224512 4E75 RTS 08224514 CAFE DC $CAFE 08224516 BABE DC $BABE» ^^^^^^^^ ^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^ Address Instruction as Code Instruction In other words, this is what the computer gets out of our little program. You should note that the »CL7:LEA $08224514,A0» moves exactly the address we wanted (The label Space) into a0. Now let the real fun begin.. (Escape). Let's singlestepdebug our little program! Type: »CL2:ad» , which means assemble/debug. »CL1:Whoaa...» You're in the 'editor', and a black line is on the first line in the program. The contents of all registers are to the right. Now try pressing arrow down. And see, that d0 contains 0000001E. Do this until you've reached the »CL4:move.w d0,(a0)» , then press escape. Now examine what's on »CL1:Space» (h Space for the slow ones of you!!). It should definately not be CAFEBABE anymore! Great! Finally, try just pressing »CL2:a j» And the entire program runs to the end »CL1:(until rts is encountered)». Now again examine »CL1:Space». This isn't very hard, I know! So know let's try generating a little table. For this we need to learn a little bit about »CL1:branching». Let's introduce... »CL8: »BIG:The bxx command(s): »CL9:»SML: ----------------------------------------- »CL0:The »CL1:bxx» is not ONE command, it's loads of commands. Let's make little example: »CL4:Start: move.b #$80,d1 move.b #$80,d0 sub.b d0,d1 beq Stop move.l #$DEADBEEF,d0 Stop: rts » Before you run this program, let me ask you? Does d0 contain $DEADBEEF after this program has been run? :-) OK... As you might hvae guessed, the »CL1:beq» command means »CL1:branch to the label Stop if the result was zero.» What actually happens is that the computer has got a »CL1:FLAGREGISTER», containing information about the result of the last arithmetic operation. The flags are: »CL1: Z (Zero) N (Negative) C (Carry) V (oVerflow)» Explaining the use of this would bore you to death, I think. The only intersting things to say are perhaps that - the carry flag is set if an addition or multiplication hs a result bigger than can be in the register. - the V-flag is used on signed values. What is much more important is that the flags can be seen »CL1:BENEATH» the registers when »CL1:singlestepping». Try singlestepping the little program and watch the flags, as you move numbers into registers »CL1:(Note: $80.b = -$80),» and as you subtract. The many types of branching depend on the flags as this: »CL4:beq »CL5:(EQual): » Z-flag set. bne »CL5:(Not Equal): » Z-flag not set. bmi »CL5:(MInus): » N-flag set. bpl »CL5:(PLus): » N-flag not set. bcs »CL5:(Carry Set): » C-flag set. bcc »CL5:(Carry Clear): » C-flag not set. bvs »CL5:(oVerflow Set): » V-flag set. bvc »CL5:(oVerflow Clear): » V-flag not set. blt »CL5:(Less Than): » V-flag the same as N-flag AND Z-flag not set. ble »CL5:(Less or Equal): » V-flag the same as N-flag. bge »CL5:(Greater Than): » V-flag not the same as N-flag AND Z-flag not set. bgt »CL5:(Greater or Equal):» V-flag not the same as N-flag blo »CL5:(LOwer): » C-flag set. bls »CL5:(Lower or Same): » C-flag set OR Z-flag set bhs »CL5:(Higher or Same): » C-flag not set. bhi »CL5:(HIgher): » C-flag not set OR Z-flag set »CL0:As you see, this can get rather complicated. Some of these commands are supposed to be used after the »CL1:cmp»-command (compare). But for now, let's just stick to »CL1:beq» and »CL1:bne». These two can take us a long way! »CL1:They can make us do loops!» Before we begin, let me introduce you to a quite handy adressing mode: »CL4: move.X something,(aX)+ move.X something,-(aX) »This is extremely neat, »CL1:as it will add/subtract either 1,2, or 4 to/from aX every time some data has been written to it.» eg:»CL4: add.w d0,(a0)+»CL5: ; add d0.w to the location of a0 and then add 2 to a0 »CL4: sub.b d1,-(a1)» ; subtract 1 from a1 and then ; subtract d1.b from the location of a1. »CL4: move.l #0,(a2)+ »; move $00000000 to the location of a2 and then ; add 4 to a2. »CL0:Our first decent program will make a square table (word-size) of the numbers 0-255. This isn't hardcoded, as I might confuse you a bit by smart optimizing! »BIG:»CL8:Let's do it!: »SML:»CL9:------------------------------------------------------------------------------- »CL4:Squares: move.w #0,d0 »CL5: ; The number, we're at »CL4: lea SquareTable,a0 »; Find our table. »CL4:Loop: move.w d0,d1 mulu.w d1,d1 » ; The square. Unsigned! »CL4: move.w d1,(a0)+ » ; Move the square into the table, ; then add 2 to a0 »CL4: add.w #1,d0 » ; The next number »CL4: cmp.w #256,d0 » ; Are we finished? »CL4: bne Loop » ; If not, then loop. »CL4: rts SquareTable: dcb.w 256,0 » ; Declare 256 words as 0 »CL0:You should try to test if the program has done what it should by simply checking if the SquareTable consists the 256 squares after jumping. (a, j, h SquareTable). And by all means, try singlestepdebugging it and watch what happens in the registers! This concludes the first lesson of coding. I hope that some of you are inspired to make something out of coding now. Or at least to stay tuned here. Coding isn't as hard as it seems. Stay tuned for the next lesson, where we will go further into adressing and perhaps take a brief look at some optimizingmethods plus some more assembler-specific tricks.