A92: newbies.txt


[Prev][Next][Index][Thread]

A92: newbies.txt



here is the new version of the old e mails i send to list fargo: i would like
people to 
tell me if they feel something is missing or if they find errors before i
release it.
Mathieu, <hm lacage@aol.com>
****************************************************************************
*                           68k ASM for newbies                            *
****************************************************************************


I will try to make U understand the basic knwoledge for asm: less than a
month ago, i knew nothing on asm... Thus, i feel i am well placed to
explain what i did not understood... I hope you will excuse spelling errors
, and will find this usefull ( for french readers, i recommend "assembleur
facile" in the " les best-sellers de l' informatique" by philippe mercier
chez les editions "Marabout": ~70 FF: ecrit pour PC mais tres, tres bien
fait  !)

I ) PRESENTATION

 1 ) generalities

First, as assembly is a langage Xtremly similar to the structure of the
machine, there are a few things U ought to know...
The 92' s alphabet is limited to "0" and "1" which correspond to material
states: " electrons not passing" and " electrons flowing through the
arteries of the calc".A letter in this alphabet is called a BIT.
8 bits form a BYTE , 16 bits a WORD and 32bits a DOUBLE WORD or LONGWORD.
These 4 structures are the structures with which you will be working ( it
happens to be the ones with which the processor of the 92 is working ).
the "lower byte" of a word is the right 8 bits of the word ( the right byte )
the "higher byte" of a word is the left 8 bits of the word.. 
Same for longwords: lower word and upper word...

Please: never forget : whatever the numbers you will be using, these numbers
are just a representation of a serie of bits stored in the memory of the 92
(under the form of micro interrupters swithed on or off ).
So: the computer is working with binary data ( these little bits got 2
states: "bi"  of bin ) . But data isn' t enough: to build a program, you
need data and instructions. Instructions will thus be simply coded using
binary data: to each instruction, corresponds an instruction which the
processor can understand.
Here, a problem arises which you guys have surely seen: there is no way
for the calculator to do a difference between data and instructions, and
more generaly, between 2 form of data. You have to know the difference
between  your datas as a programmer.

 2 ) binary 

As you know, all programs can be restricted to the manipulations of numbers:
a program is a traduction of an algorythm, a pseudo code.
So: how do we use numbers: all we got is 0 and 1 ? ? Take it easy: Can
you remember when you learned to count ? Then, that' s it. Basicaly, numbers
are representing objects: 10 is a representation of  " I I I I I I I I I I ".
exemple: what is the diffrence between 27, 270, 2700. They are multiplied
by 10 which is the number of letters we are using : they can decomposed in :
27=2*10+7, 270=2*100+7*10+0, 2700=2*1000+7*100+0*10+0.
let' s use the same principle with 2 letters: we' ll try to decompose a
numbers into its 2 powers:
exemple: 1=1*2^0                                             :    1
              2= 1*2^1+0*2^0                                 :   10 
              3= 1*2^1 +1*2^0                                :   11
              8= 1*2^3 +0                                    : 1000
              9= 1*2^3+0+0+1*2^0                             : 1001
that' s it ! we got numbers !  
then with the structures we mentioned sooner, we can represent 255=2^8-1 as
a maximum number with a byte...

To those of you who are reading this and saying: he thinks we are dumb!! All
he did is a base change... Yeah but i thnk that even if you got a calc which
does these conversions between decimal and binary much faster than we will
ever do these ( my casio does this quite well... ) , we should try to work
in binary, with these numbers, as they are at the heart of the machine.

Oh: i was about to forget: how do we represent negative numbers: we adopt a
convention: the bit the most to the left of a data is the sign bit; if set,
the data is negative... with a byte, you got then, as a maximum number and
minimum number: +127 and, -127. we' ll see later how they are precisely coded...

Ok: now, you know what is inside the calc : you understand the headaches of
the first programmers who had to program in binary: it is awfull...
So, to represent the content of memory, we use hexadecimal.
 
 3 ) hexadecimal

As i said sooner, hexadecimalis just a representation of the state  of the
memory.We will now have 16 letters: 0-9 and A-F : this has been chosen
because it gets much easier to represent a word with this notation: to a
group of 4 bits, we associate a "letter" as 4 bits allow 2^4=16 states.
thus, you see well in the definition of hexadecimal how it is simple...
 
 ex: 1100 1010 1000 1101 is CA8D ( i think ... )

an adress is a number which indicates the place of some info in mem... the
unit of an adress is the byte ( 8 bits )... adresses are often given in hex.
It is more convenient. Adresses are often called pointers: they point at
data.


 4 ) the calculator
 
Your calc is made of 2 parts:
      *** The memory: where the data is stored under a binary form. "Data"
          means the instructions with their parameters which are to be
          executed by the processor. This mem is the RAM ( 128 kb on most
          calcs ) and the ROM ( 1 Mb on all 92 ) 


      *** The processor, the heart of the calc: 2parts

       a) a small part of memory in the processor where parameters for the
       near to come instructions are stored: the registers...
       b) the processor itself, where instructions are executed...

The registers are some small micro switches which can be set to anything we
want: we use to store the data we want to process in these regs. We may put
there numbers to add or adresses to data ... ANYTHING !
Registers are a small memory which is physically in the processor. This very
small memory is VERY IMPORTANT: it is used to store vital info on the state
of the processor and some info you need

These registers have been created because acessing to the memory is slow:
if the data is very near to where it is to be processed , the speed is
greatly increased. Registers are very usefull because they allow a very
flexible programming...
There are five sorts of regs:

a) Dataregisters: numbered from 0 to 7 ( there are 8 ) : D0/D7  : 32 bits
b) adressregisters: A0/A6  : 32 bits
These are for you: you may store in these registers all data you wish.
you may store in these registers 32 bit data

c) A7 : stack register ( it is phisicaly similar to A0/A6 but it is used in
a totaly different manner and you should not meddle with it ... )  :32 bits

d) Status register:  16 bits
composed of 2 bytes: the lower byte, the flag register is widely used:its
bits are set depending on the result of some operations executed by the
processor.
the flag register is: 0 0 0 X N Z V C
The five flags to the left are described in the arithmetics section.
The upper byte or the system byte is a group of bits used by the system:
you can use them too but it requires to know what you are doing. The use
of these bits and of exceptions is described in the "vectors.txt" file.

e) program counter: 24 bits 
the program counter is a register in which the adress in memory to the next
instuction to be executed is stored : you cannot modify its content !


5 ) The 92: Fargo.

the aim of this part is to make u understand how fargo works. 

when you switch on the calc, the processor goes to see at adress $0000000 in
the memory: the 64 bits which are stored there are called the initialisation
vector. They are the adress of the memory where the first program to be
executed is stored... Then, after this vector, at adress $0000008, the
exception vector table begin... There, are stored adresses to routines
triggered when an error, a trap or an interrupt occur.
u should look at traps.txt ( file with fargo ) for more info on these. 
when fargo is not installed, the ti os is triggered and we cannot have
access directly to the processor: it is impossible to execute asm (
impossible... perhaps someone will find a way one day ... )
When you send the calc a fargo backup, you send a backup slightly bigger
than the calc' s memory: at one point or another, the adress the backup
writes to will be bigger than $20000 ( 128 kb ). higher adresses go back at
the begening of the memory:  the initialisation vector is $000000 and
$020000... thus, the backup will be writing in the exception vector table and
on routines used to send or receive data... and the fargo program will be
trigered... If looking for more info on this, look at "vectors.txt".
great isn' t it ? I think that when u will have finished reading that file,
u should go through all fargo doc... It IS VERY USEFULL !!!!!!!!!!!!!
 

 II) First instructions: move/arithmetics

 1) Move

one of the most important action you need to do when programming is handling
data. I mean that you need to know how to move data to or fro memory.
The corresponding insturction is: "Move" ( as "mov" for th 8086 processor
family ) 
ex: move     D2, D4 will move ( copy ) data from D2 to D4. More generaly, in
all instructions you 'll use, the first parameter is the source and the
second the destination.
Then, you need to precise the data form you will use : BYTE, WORD or
LONGWORD: you can move the lower byte of D2, its lower WORD or its whole
content. Here is how to do this: 

move.B   D2,D4     : byte
move.W   D2,D4     : word
move.L   D2,D4     : longword

this syntax is used for all instructions too. ( the .x extension where
x=b,w,l is an extension valid for all inst ) Important: when programming,
never forget to precise the lenght of the data you use: this is CAPITAL !
Even when it is trivial, you should precise the lenght... ( i don' t do
always this myself but i am no exemple and i have spend days debugging such
errors... I wouldn' t have if i had done this... ) 

warning: when you move a byte in a 32 bit reg, the upper word and byte in
not reseted or affected...
Move may be used to put certain values in some places: you wish to put
"1270" ( in decimal ) in the D4 register.
just type : move.w   #1270,D4
the "#" stands for immediate value: you will thus store the number 1270 or
"10011110110" in the D4 register .
if the number you got is hex, just type: move.w  #$4F6,D4
"$" stands for hexadecimal.
if the number you got in bin, just type: move.w  #%00000001,D4
"%" stands for binary.
 
still, if you want to move data from a certain place in the memory ( not
the processor's one ): you know the adress of the data you need: $4F6.
type : move.w    $4F6,D4
the processor will take the word stored at the adress 4F6 and copy it to D4.
rq: when going through a programmers code, you will notice some use:
move.w   ($4F6),D4 : they add parentheses... this is for a purpose of clarity
Similarly, if you have stored in an adress register the adress of the data
you want, you may type: "move  (A0),D1"
the parentheses ( necessary: not for purposes of clarity ) mean that it is
indirect adressing: the data we will copy to D1 is the data which A0 points
to.

Here it is ! You have seen the principals operatins you can do with move. 
However, before going on, i think you should try to take a look a jimmy
mardel' s guide: he describes all ways of using the move command: all ways
of adressing memory. This may seem not very exciting but it is usefull to
know waht you can do before trying to program.

So: we know how to change things in memory: but what operations can we do on
these datas ? 

2) Flags

C is the carry flag: it is used in various operations and its general use is:
The Carry generated by a mathematic operation ( addition, substraction,
multiplication... ) is stored there. See the arithmetic part to understand
more closely its use.
V is the overflow flag: it is set if an arythmetic operation resulted in an
overflow.
Z is the zero flag: it is set if the result of an arithmetic operation is
zero.
N is the negative flag: it is set if the highest bit of the result of the
last arithmetic operation is set: in fact, if set, it means that the result
was negative if you were working with negative numbers.
X is a copy of C but it isn' t affected by all arithmetic operations.

3)   arithmetics

I will present here simple arithmetics: addition, substractions and negative
numbers.
let' s imagine you want to calculate 100+25
you would do: move.w  #100,D0
              move.w  #25,D1
              add.w   D0,D1

this piece of code will do: D0+D1->D1
you' ll have 125 in D1 at the end of this code. But of course in binary.
now, for 100 - 25 , 

move.w    #100,D0
move.w    #25,D1
sub.w     D1,D0

in which case, you do: D0 - D1 ->D0
let ' s imagine we had done : 
sub.w      D0,D1
then, there would be - 75 in D0, a negative number ! 
So: we know that to recognize a neg number, we look at its highest bit ( if
set, negative ) 

let' s imagine it was that simple:
we wish to add 4 and -1. we should get +3
        4       0100
    +  -1       1001
     ________________
       +3       1101= - 5     

this doesn' t work. So, we use a slightly different way to represent negative
numbers.

we have +4 : 0100
we want -4 : we take the complement to one ( we are inverting all bits of
the number ) and we add 1
then - 4 is : 1100.

            11   -------------> these are the carry bits
we get:   1011
       +  0001
     __________
          1100   ( don' t forget carry bits ) 

in our exemple of:   4+  -1

 11      -----------------> u see : there is a carry bit which is "forgotten"
  0100
  1111
  ____
  0011 = + 3
so: this is the way neg numbers are handled: don' t forget that a negative
 number is just in your mind: the processor don' t know the difference
between 11111111 ( -1 in a byte ) and  11111111 ( 255 in a byte ) . so: the
content of the registers depends on what you want them to be.
There is something you need not to forget: always precise the lenght of the
data used:  here, i did the addition between +4 and -1 on a half byte:
the result is valid on a half byte. we have +3 on a half byte. But if we had
taken into account the highest carry bit ( which seems to be lost: it is
stored in the flag register ), the result would have been: 10011
The difference between these two interpretations of the operation ( which
seem to contradict one each other ) is signed vs unsigned. If you are 
working with signed numbers, you know you don' t have to bother about the
carry bit but if not working with signed numbers, you should better test the
carry bit... otherwise, you will get 0011...  

 In the processor, everything happens the same way: it calculates your
addition on the data specified and stores the carry bit elsewhere. ( it
stores it in the carry bit of the status register : see jimmy guide for
precisions on the structure of the status register )
There, you may see the use of the "ext" statement.
let' s imagine we got a table in which all entries are bytes and in which
numbers may as well positive as negative...
the first number stored is -1 : $FF ( it is a byte ! )
now, we want to add this to a number which is stored in D0 but this number
is a word...
if we did:
move.b   (A0),D1
add.w    D1,D0
this would be completely false: we would not add -1 to D0 but +128 to D0.
yes: if the upper byte of the D1 reg was cleared, then we have: $00FF in the
lower word of D1. Thus, if we add D1 and D0, we add 128=$00FF to D0
we need to add -1 on a word to D0: -1 is $FFFF: ext will transform a negative
number on a byte to a negative number on a word.
type "ext.w    D1": this will put $FFFF in D1
you can use "ext.l D1" to extend the sign  to a longword...
Basicaly, what the "ext" statement has done is copying the last bit of the
lower byte through the upper byte of D1.
Thus, if D1 was a positive number and something was written in the upper byte,
doing "ext.w  D1" would clear the upper byte of anything which may be left.
Some porgrammers use this instruction to clear the upper word of a reg:
"ext.l D1" will clear the upper word if D1 is lower than +32768=$8000...


Ok: you know how to do additions, substractions... What about multiplications
and divisions ? 
the corresponding instructions are :  mulu ( unsigned ) , muls ( signed ) ,
divu ( unsigned ) and divs ( signed ) . if working with signed numbers, then
use muls and divs. 
muls  D2,D4  will multiply the lower words of D2 and D4, and store the 32 bit
result in D4.
divs D2,D4 will calculate D4/D2 ( D4 is 32 bits and D2 is 16 bits )and store
the quotient in the lower word of D4 and the rest in the upper word of D4.


4 ) integers vs reals

you have been working till then with integers... what about reals ?
well: the 68k processor has no build in instructions to handle floating point
arithmetic ( ie: reals )! We will need some ideas to handle this problem...
In base ten, the natural idea is :  if you want a 10^-3 precision in your
numbers, you multiply them by 1000 ( natural idea when we know how to count
in decimal... ) and you cut them at the point. Then, you make all operations..
We will see later how to do this efficiently in asm. ( but the basic idea is
the same ) 

III ) The stack / the compiler / first program 

1) The stack

the stack is a 8 kilobyte ( i think ) area of memory stored in the system
memory. ( you don' t need to know where exactly )  . You have access to this
memory by the stack pointer ( A7 ) : the adress to the stack is stored in A7.

The stack is mainly used to: 
     1) save variables before working with them 
     2) transmit parameters to a subroutine
 
I have never myself used the second one : storing params in the registers is
much more easy and much faster ( that is the way of most of the libraries i
know ) . Why using the stack in this way ? Because we ( the users of fargo )
are using routines implemented in the ti os: these routines use the stack to
store parameters. ( ex: the put_text or put_hex routines of the romlib
library ) .
Then it is often usefull to use the stack to save all registers and restore
them after: this is something most libs do . refer to jimmy' s guide to
know how to do: check the "movem" instruction .

now , you know what the stack is used for: how can you use it ? 
 
easy: imagine you want to call the put_text subroutine ( in romlib ) 
You need to store 4 parameters in the stack. 
first:   move.w   #"1stparam", ( A7 )
 
now, you have to move the adress ( longword ) of the string to disp to the
stack. but, if you just add:  move.l   "adress",(A7)     you will just crunch thedata you had pushed before.
you may have written: sub   #4, A7
then , move.l  "adress",(A7) thus you would have now:
 
1st param       <---------------   adress A7 pointed to 
"adress"        <---------------   adress A7 points to 

i have sub the size of the adress ( 4 bytes ) before sending the adress to
the stack. 
why haven' t we added the size of " adress"  ? because the rom needs us to
push the parameters in reverse order. that' s all ! 
However, there is another way to do this, more efficient: 
move.w   "1st param", - (A7)
move.l    "adress", - (A7)

all this does is before moving data, removing the size of the data from the
stack pointer ( A7 ) . here, some of you may understand why the first move
has a minus now: just before, we had crunched the data which was stored
 before our first move. It could have been a big problem if we had been in a
subroutine with bsr ... 
 So, now, you know that A7 points at the adress of the last data which has
 been moved in  ( or pushed: when moving to the stack, you push, we moving
from the stack , you pop )

2) the compiler
 
now, you know basic instructions : you know how to write some assembly code. 
when working with fargo, you use A68k as a compiler ( a great freeware
compiler from W. Gibbs ) . i think you need to do a difference betwwen the
compiler's directives and the instructions of assembly: 

here is the general laying of a program: 

  @program  prog_code,prog_name                 ; make sure you don' t forget
a space
                                                                    ; before
the "program" statement 
         
prog_code: 
 
; here, your program 

rts        ; the instruction which ends a prog 
 
prog_name: dc.b  " my_prog",0

; here, your variables 
; ex:   
my_var: dc.w  0
 
 reloc_open:         ; don' t forget here  too the space before this block  
 add_library flib
 ; other libraries 
 reloc_close:
 end               
    
; over
 
you have seen here the use of a very precise syntax: respect it or you will
never be able to compile anything ... We have used here a compiler directive:
dc."data lenght"  where "datalenght" is b, w or l .this directive difines
the label which precedes as a var: here, my_var is a word with 0 inside.
you may access to it in the program with: 
"move.w  my_var,D0" or "move.w   D0,my_var"
easy, no ? 
For precisions, go and see jimmy' s guide ( yeah, always refering to it but
i am just presenting basic things  )
other directives: dcb.x y y1,y2,y3...
                   ds.x y
ds.w 100 : it reserves a place of memory of 100 words=200 bytes: this mem is
empty.

3) 1st program: hello world ! 

ok: we want to disp sth on the screen.
here is the prog_code section: we' ll need to use the put_text routine in
romlib: 
 puttext(int x, int y, char *string, int color)  
we need to push the parameters in reverse order: 

prog_code:
    
    move.w   #4,-(A7)                ; moving the first param to the stack 
    lea      string(pc),A0           ; moving adress of string to the stack
    move.l   A0,-(A7)
    move.w   #0,-(A7)                ;   pushing position
    move.w   #0,-(A7)                ;     pushing position
    jsr      romlib[put_text]        ; calling subroutine
    add.l    #10,(A7)                ; restoring the stack
pointer
    rts
       

now: let' s see what we did: lea ? what' s this ? 
lea  srting,D0 :  moves the relative adress of string to D0 ( the relative
adress is number of bytes you need to add to the absolute adress of the
instruction "lea" to get the adress of string ) 
we wrote: lea   string(pc),D0
this adds the absolute adress of the "lea" inst to the relative adress of
string and stores the result in D0 ( or, to the adress specified by A7)
 thus, you get the absolute adress of "string"

we could have written: pea    string(pc) ( push effective adress ) 
then we call the subroutine: a jsr which has the same effect than bsr on the
stack (however slightly different ) 
lastly, after having dsiplayed our string, we restore the stack: instead of
erasing the data in the stack, we restore the pointer to its initial value:
10=2+4+2+2: we add the sum of the size of the data we pushed to the stack
pointer
or, more simply:  lea  10(A7),A7

ok: you got this txt file written with all the syntax stuff ( don' t forget
to add the romlib library) . Save this file with the extension : "asm" and
run "fargo <name of the file without the asm extension> "
you get your <name of the file>.92p file: send it to the calc, lauch it...
Nothing happens ! 
why ? well: the calc disps your message but goes too fast for you to see it. 
all you have to do is to add a waiting loop ...
exercise: try to find in the libs with fargo a subroutine which does this and
write the corrected prog...


IV ) Branches

1 ) labels
   
in an ASM prog , you may define labels: if you have done some programming on
a casio calc or on some old basic, there was the goto function... 
"goto  <label>" meant that when executing the goto statement, the computer
had to go at the label pointed by goto. ( it could be combined with a if
 statement ) 
we got the same in ASM.

to define a lable, you write: 
name_of_label:
that' s all ! the ":" is important: it is him which helps the compiler to
recognize the label...
 
2) comparisons, status register... 

to compare 2 operands, you execute a cmp statement... 

cmp  D0,D1

this does: D1 - D0 and affects the bits of the status register depending on
the result of this substraction. important: the result is not stored in
memory or anywhere: it is virtual... 
now: the status reg: i have no time to go through it: look at jimmy' s guide
to know how the flags ( the bits ) of this reg are affected...
You have to know that the result of a standard arithmetic operation usualy
affects the status reg in the same way: you may thus remove some cmp from
your programs... 

3 ) conditionnal branch...

the statement is: Bxx  where xx is one the 14 ( or more: no courage to check
) extensions ( check jimmy' s guide: it is explained in the inst section ) 

ex: Bcc, Bhi... 

here is a way to work with them: 

let' s imagine that you write: 
cmp    B , A

then bxx will branch to the label if: 

when working with unsigned integers: 
 
A >  B            Bhi
A >= B            Bcc
A <= B            Bls
A <  B            Bcs
A =  B            beq
A <> B            bne

with signed integers

A >  B            bgt
A >= B            bge
A <= B            ble
A <  B            blt
A =  B            beq
A <> B            bne

and, to test the V and N flags: 
bvc if V is not set and bvs if not set 
bpl  if N is not set and bmi if not set

thus, we have now a way to build conditionnal branches... Now, i would
like to explain how the Bxx statement works...
Basicaly, when conditions are fullfilled, the bxx statement just adds to
the PC the relative adress form the actual instruction to the label: this
relative adress is calculated by the compiler and stored in the program.


4 ) other conditionnal DEBranches

i am afraid but i don' t know how to use the dbxx inst... 
this one seems to be powerfull.. you should have a look at it

5 ) non conditionnal branch.

There are 2 unconditionnal branches:
BSR ( branch to subroutine ) and JSR ( jump to subroutine )
Jsr and Bsr do nearly the same work but one is used to call a subprogram
( a library: JSR ) and the other to call a subroutine in the calling program.
when writing "BSR  <name of sub>", you oblige the processor to do this:
he stores in the stack the adress written in the PC ( program counter ) ( in
fact , he saves the position of the execution of the program before calling
the subroutine ) then, he puts in the PC the adress of the first instruction
of the subroutine. at the end of the subroutine , when you write RTS, the
processor restores the PC with the value stored in the stack and exutes the
instruction the PC points to . This isn' t that simple but, basicaly, it is
what happens.

there is other similar stuff about the link and unlnk instructions but i
have never used these, so... ( if some want more details, then again , jimmy
guide or email me : i got some ref book and will try to figure this out )

V )  Structured programming in ASM

More than any other langage, ASM is extremly complex: listings get longer and
longer, most of the time unreaddable, no one but you can understand the
program... It becomes very quickly impossible ... 
There are some solutions... 


1 )  pseudo code

before writing anything in ASM, you MUST know what you will do.. 
I remember my programming some things in pascal or basic some time ago... I
began to write things on the screen without even knowing how i would do what
i had in mind. If this was possible  for very simple progs, it is no more
possible for an ASM prog ( because of its complexity and lenght ) 
So: you need fist to write a pseudo code: it is a text ( preferably in your
own language at the begening ) which describes the general structure of the
program... 
for exemple, if you are writing a doom like engine.. ( my case ) 
for ray from 0 to 150 

launch ray. 

calculate dist to the first object. 

render the slight portion of picture based on the distance to the first
object encountered.

end_launch

easy, not ? 
this is the first version: slowly by slowly, you try to go deeper, you
explain with more detail what will be done in the "launch ray " section... 
While writing the pseudo code, you build a " table descriptor": there, you
keep track of each variable, its use, its type, the different values it will
take, its range, its initialisation... 

then at last, you got a doc which can be understood by anyone... ( taking
time of course )  

2 )  The program 

on this basic structure, you can write your program.... 
it is very imp that you keep in mind that structures as "if then else endif"
are very easy to code...
for exemple: 

if_1:
   cmp D0,D1
   bcc   else_1
then_1:
; your code
   bra end_if_1
else_1:

end_if_1:


or the "while, do, end_while" structure: 
while_1:
   cmp   D0,D1
   bcc   end_while_1
do:
; your code

end_while_1

or the "iter, end_iter" statement:

iter_1:
; your code
exit_if_1:
   cmp  D0,D1
   bcc  exit
   bra  iter_1
end_iter_1

VI ) Debugging

Well: you have written now your first program, perhaps have you tried to
write another one... If so, wellcome to the great world of asm debugging...
There, you will spend more than 60 percent of your time while programming
in asm ! :) !
hopefully, there are a few tools available to minimize that wasted time...

when you compile a program using the " fargo" statement, the compiler
creates a file called "list.txt". This file is VERY usefull !
There, you will find your code and at the begening of each line, the
hexadecimal coding of your work: these hex numbers are the exact copy
of what you would find if you scanned the memory of your 92 where your
program is stored.
This is usefull with the 92 debuggers: RAVEN and RECLIB.
I have been using reclib some time before changing to raven... There lacks
one feature to raven: the ability to look at the screen to see what has been
drawed when the debugger is called...
These debuggers are execption handlers: they stay some sort of "resident" in
the memory and redirect all calls to exception routines and error traps.
RAVEN will allow you to look at the content of memory, of registers when an
error occurs then to exit from the program. It will recover from most errors.
As a user, you may even "break" the program by hitting the "on" key and to
get back to the program by "enter".
when you are in the raven screen, you can see the content of a part of the
memory the PC points to: these are the codes of the near to come instructions.
You may compare these to the hex codes in the list.txt file: thus, you will
be able to know exactly where the program has been broke...
Similarly, you can add user breakpoints: you can add "illegal" in your code,
just like any other istruction: it will provoque an "illegal instruction"
when executing the program and will allow you top sneak in th memory...
but this is not very efficient as you cannot allow the program to go on after
this.
You may add this code at the place you want the breakpoint to be:

   move.b  D0,-(A7)
   clr.b   D0
breakpoint:
   tst.b   D0
   beq     breakpoint
   move.b  (A7)+,D0
  

this piece of code will create an endless loop as it will test the lower
byte of D0 ( cleared ) if it equal to 0 and will test it till it is not zero.
if you are using raven, just hit the on key when this loop is launched, then
modify the content of D0 ( write anything in the lowre byte of D0 ) and go in
trace mode ( trace mode is when you hit "t" : each instruction is executed
after "t" is hit and the porgram gets back to the debugger ) : after a few
instructions, you will be back to the program, you will be able to see all
regs and to trace the program...






*****************************************************************************                              The END                                     ****************************************************************************
*                          ver 1.00, 26 july 1997                           *
*****************************************************************************
well: i hope this file will be usefull to some people who know no assembly
at all and that it will increase the fargo programmer community.

thanks:

    * david ellsworth for the great FARGO !!!!!!!!!!! ( why fargo, david ? )
    * all those who helped me to learn asm...
    * special thanks to bryanr2 on IRC for his modesty and his beeing polite

If u want to reach me, email at : 

mathieu: <hm lacage@aol.com>

on ex-list fargo: A92 ( available at calc-ti.org ) 

on IRC: on #calc-ti, my nick is fly_craze and i am there usually between 22h
and 23 h 30 ( paris time ) .

my adress:
Mr LACAGE Mathieu
2 Rue de la Lavande
34430, Saint Jean de Vedas
FRANCE