
 Fourth Steps
 ============

 Contents
 ========


 More Loops
 ==========

 So far we have looked only at the Bcc instruction, more specificaly the BNE
version.  Lets look at an instruction that will allow us full use of Bcc.

 CMP
 ===

 Syntax : CMP.s  <ea>,Dn

          .s is either .l .w or .b

 The compare instruction. This instruction allows us to compare a value to the
value held in the data register, Dn. The comparison takes the form of a
subtraction, so all internal flags are set accordingly, but neither the source
or destination are effected. The result of the subtraction is not remembered.
This instruction is usually followed by an appropriate Bcc instruction.

 Here are a few examples:

1/ The following example compares d1 to d2 ( ie d2-d1 ). The following branch
instructions test the state of the internal flags and act accordingly. Note
that the third test could be omitted, since if d2 is not greate, or less than
d1 then it must be equal to d1. This was done to demonstrate the use of the Bcc
instruction.

		move.l	#10,d1
		cmp.l	d1,d2
		bgt	greater_than_ten	branches if d2>d1
		blt	less_than_ten		branches if d2<d1
		beq	is_ten			branches if d2=d1

2/ The following example shows how to isolate lower case characters in a list
and convert them to lower case. It is assumed that next_char holds the ( ASCII
 ) code of the character to be tested. Obviously if char < `a` and char > `z`
then the char is not lower case alphabetic and will not need to be converted. 
Note that subtracting $20 from the code of a lower case ASCII character will
convert that character to upper case ( code A = $41 and code a = $61 ).

		move.b	next_char,d0
		cmp.b	#`a`,d0
		blt	not_lower_case		branches if d0 < ascii `a`
		cmp.b	#`z`,d0
		bgt	not_lower_case		branches if d0 > ASCII `z`
		subi.b	#20,d0			convert to upper case
not_lower_case	rts				all done so return

3/ This final example can be found on the disc as eg_22.s. This routine 
will calculate the length of a string of bytes terminated by a carriage
return ( $0a ). Each byte is examined and a counter is increased inside the
loop. When a carriage return is found the loop is left and the counter is
decreased by one to account for the carriage return.


main		move.l	#char_string,a0		a0 holds addr of text string
		moveq.l	#0,d1			clear counter
len_loop	move.b	(a0)+,d0		d0 holds next char
		addi.b	#1,d1			bump counter
		cmp.b	#$0a,d0			is char a carriage return ?
		bne	len_loop		if not branch back
		subi.b	#1,d1			correct counter
		move.l	d1,string_len		save strings length
		display_d1			print strings length
		rts
		
char_string	dc.b	'How long is this text ? ',$0a
		even
string_len	dc.l	0


 As you can see the combination of CMP and Bcc can be used to test for just
about any situation. As always, there are other forms of this command that
allow comparison to be made with more than just a data register. These are:

 CMPA
 ====
 
 Syntax :  cmpa.s  <ea> , An
 
           where .s can be .l or .w
           
 Compare addresses. As you may have guessed, this instruction allows the 
source data to be compared with the contents of an address register.
As an example, eg_23.s shows how to use this to determine when the end of
a string has been reached. The example counts the number of spaces in a 
string.


main		move.l	#char_string,a0		a0 holds addr of text string
		moveq.l	#0,d1			clear counter
loop 		move.b	(a0)+,d0		get next char
		cmp.b	#" ",d0		is char a space ?
		bne	not_a_space		branch if not a space
		addi.w	#1,d1			bump counter
not_a_space	cmpa.l	#str_end,a0		end of string ?
		bne.s	loop			if not loop back
		display_d1			print number of spaces
		rts				and return
		
char_string	dc.b	'How long is this text ? ',$0a
str_end		even

 CMPI
 ====
 
 Syntax : cmpi.s  #data , <ea>
 
 	  where .s can be .l .w or .b
 
 Compare immediate data. This instruction will compare the value found at <ea> 
with the immediate value #data. Some examples should illustrate:

		cmpi.w	#55,d0
		
		cmpi.l	#end_of_table,a0
		
		cmpi.b	#` `,(a0)
		
		cmpi.b	#$0a,last_key_code
		
 CMPM
 ====
 
 Syntax :  cmpm.s  (An)+ , (An)+
 
           where .s can be .l .w or .b
           
 Compare memory. This command will compare the value stored in memory pointed 
to by the second address register to the value stored in memory pointed to by
the first address register. The address registers are then bumped to point to 
the next values. This can be used, for example, to compare to strings as in 
the following example. If the strings are the same d0 is set to 1, else d0 is
set to 0. This is example eg_24.s

main		move.l	#str1,a0	a0--> 1st string
		move.l	#str2,a1	a1--> 2nd string
		moveq.l	#0,d0		reset flag
loop		cmpm.b	(a0)+,(a1)+	compare next chars
		bne	not_same	branch if not equal
		cmpi.b	#$0,(a0)	end of string ?
		bne	loop		if not go back
		moveq.l	#1,d0		strings the same so set flag
not_same	display_d0
		rts
		
str1		dc.b	`these strings are the same`,0
		even
str2		dc.b	`these strings are the same`,0
		even
		
 To verify that this works, change the second string and assemble it again.
When you run it, d0 should return 0.

 It is worth knowing that Devpac can decide which form of cmp you are trying
to use, for example: cmp.l #string,a1 is not strictly a 68000 instruction. The
correct instruction would be  cmpa.l #string,a1. Devpac will not produce an
error in this case, it will substitute cmpa for you. This is also true for 
other instructions such as ADD ( ADDA, ADDM, ADDI etc ).

 If you just want to test a value for its sign ( +ve, -ve or 0 ) there is an
instruction to do just this.

 TST
 ===
 
 Syntax : tst.s  <ea>
 
 	  where .s can be .l .w or .b
 
 Test an operand. This instruction tests the value in question and then sets
the zero and negative bits accordingly. You can then use a Bcc instruction to 
act on the outcome of the test. Here are some examples:

1/ This fragment will branch if the word valu in d0 is negative.

		tst.w	d0
		bmi	negative_num
		
2/ This fragment will branch if the byte pointed to by a0 is 0.

		tst.b	(a0)
		beq	zero_byte
		
3/ This fragment will branch if the word number in memory at val is posotive.

		tst.w	val
		bpl	posotive_num
		
 
 The last instruction I am going to look at this month is DBcc. 
 
 DBcc
 ====
 
 Syntax  :  DBcc  Dn,label
 
 Test, decrement and branch. What a mouthful. This instruction does a number
of jobs all in one go. First it tests the internal flags to see if the 
specified condition code is satisfied, if it is then execution passes on to
the next instruction. If the condition code is not satisfied then Dn is
decremented ( ie Dn = Dn - 1 ). If the new value of Dn is -1 then again
execution passes on to the next instruction. If however d1 is not -1 then
execution continues at the address label ( strictly speaking, label should be
a 16 bit displacement value which is added to the pc and execution then 
continues at the address formed. Luckily Devpac converts the label into the
correct 16 bit displacement ).

 Putting this into plain English, Dn is used as a loop counter. The loop in
question will be the code between the label specified and the DBcc instruction
itself. The loop will be executed either Dn+1 times or until the specified
condition code is satisfied.

 Lets look at the most simple example first, when the condition code is F ( ie
false, or never satisfied ). When this is the case the loop will always be 
executed Dn + 1 times. This is example eg_25.s

main		moveq.l	#2,d0		set loop counter for 3 iterations
loop		display_d0		display loop counter
		dbf	d0,loop		branch back until loop counter = -1
		rts

 Frequently programmers use dbra instead of dbf, dbra is not strictly a 68000
instruction, but Devpac will again know what you mean.

 Here is another example that will calculate the factorial ( no recursion ) 
of a small number. The factorial of a number is found by multiplying the 
number by all numbers before it down to 1. For example 5 factorial ( written
as 5! ) = 5x4x3x2x1, 6! = 6 * 5! = 6x5x4x3x2x1. This is eg_26.s

main		move.w	num,d1	get the number
		subq.w	#1,d1	adjust for dbra
		moveq.l	#1,d0	start at 1 and work up to the number
		move.l	d0,d2	initialise factorial
loop		mulu.w	d0,d2	multiply by next integer
		addq.w	#1,d0	bump to next integer
		dbra	d1,loop	loop until all done
		display_d2	print the factorial
		rts		return
		
num		dc.w	5

 This routine uses d1 as a loop counter, d2 to hold the factorial and d1 as
a counter that starts at 1 and is incremented during each iteration. Note 
that the second line subtracts 1 from the number to adjust it for the DBcc
instruction. This is necessary since DBcc finishes when the value in the data
register is decremented to -1 and not 0.

 Lets work through this example step by step, firstly then there is the data
initialisation:

 d1 = 4     	( number -1 )
 d0 = 1
 d2 = 1
 
First pass through loop :

 d1 = 4
 d2 = d2 x d0 = 1 x 1 = 1
 d0 = d0 + 1  = 1 + 1 = 2
 
Second pass through loop ( d1 decremented by the DBRA instruction ) :

 d1 = 3
 d2 = d2 x d0 = 1 x 2 = 2
 d0 = d0 + 1  = 2 + 1 = 3
 
Third pass through loop :

 d1 = 2
 d2 = d2 x d0 = 2 x 3 = 6
 d0 = d0 + 1  = 3 + 1 = 4
 
Fourth pass through loop :

 d1 = 1
 d2 = d2 x d0 = 6 x 4 = 24
 d0 = d0 + 1  = 4 + 1 = 5
 
Fith pass through loop :

 d1 = 0
 d2 = d2 x d0 = 24 x 5 = 120
 d0 = d0 + 1  = 5  + 1 = 6
 
 When the DBRA instruction is executed this time d1 changes from 0 to -1.
This ends the loop and execution continues at the display_d2 instruction. As
you can see d2 now holds the factorial of 5, the original number.

 Lets move on to another use of DBcc. Suppose we wish to find the length of a
0 terminated string. The maximum string length is 15 chars, any string longer
than this is assumed to be 15 chars ( this way the loop can terminate when a
carriage return is encounterd or after the first 15 chars have been scanned ).
 To do this we are going to use a CMP instruction followed by a DBEQ. The CMP
instruction will be used to test for a carriage return, if the current char is
not a carriage return then the EQ condition code will be false and the DBEQ
will branch to the label we specify. If the character is a carriage return
then EQ will be true and execution will continue at the instruction following
the DBEQ. By setting a data register to 14 ( 1 less than the maximum length of
a string ) the loop can also be terminated if no carriage return is found:

main		movea.l	#string,a0	a0-->start of string
		moveq.l	#$0a,d0		d0 = code of carriage return
		moveq.l	#15-1,d1	d1 = max string length - 1
		move.l	d1,d2		copy max length
loop		cmp.b	(a0)+,d0	check if next char is a CR
		dbeq	d1,loop		if not CR and d1 > -1 branch to loop
		sub.w	d1,d2		calculate string length
		display_d2		print string length
		rts			finished so return
		
string		dc.b	'Some string',$0a
		even
		
 Note how the length is calculated. The maximum length is copied from d1 to 
d2. When the loop terminates the value in d1 ( max length - chars scanned )
is subtracted from d2. This is eg_27.s on this disc.

 ie if the 4th character was a CR ( $0a ), then:
 
 d1 = 11
 d2 = 14
 
 string length = 14 - 11 = 3 chars.
 
 Remember that if the condition code is satisfied then the data register is
NOT decremented, execution passes straight on to the instruction following
the DBcc instruction.

 Sometimes you will need to know what caused the loop to terminate. Was it the
data register or was it the condition code. This can be achieved by following 
the DBcc instruction with a Bcc instruction that will test for the same 
condition code ( which is unaffected by the DBcc instruction ). If it was the
condition code that caused the loop to terminate then a branch will occur at
the Bcc instruction, otherwise execution will continue at the instruction
following Bcc. In the previous example if no CR was encounterd we may want to
deal with the string in a diffirent way. Here is how to achieve this :

; Same initialisation code

		|	|
		|	|
		cmp.b	(a0)+,d0
		dbeq	loop
		beq	CR_found
		bra	no_CR
		
 The BEQ command following the DBEQ will only cause a branch if the loop ended
because a carriage return was found.

 This is by no means the end of loops, they will be cropping up all the time.
Now though I would like to move on to subroutines.

 Subroutines
 ===========
 
 When you are writting a program you will often come across sections of code
that are repeated numerous times throught the code. Obviously it would make
more sense to write the section of code just once and then have the main
program call this section when required. This would shorten the size of the
program and also make it easier to read. These sections of code are called
subroutines. 

 Another advantage of using subroutines is that they can usualy be written
and tested by themselves before adding them to the main program. So when
things go wrong ( as they usualy do ) you know that the subroutines at least
are bug free. If you document your subroutines well, they can be saved on
disc and are there should you ever need them again in another program.

 There are three commands available to you for dealing with subroutines, these
are:

 BSR - Branch to SubRoutine
 JSR - Jump to SubRoutine
 RTS - ReTurn from Subroutine
 
 Why two calling commands ? Well BSR can only be used to call subroutines that
are within a 16 bit displacement from the point they were called from. Until
you start writting massive programs, this will usualy be the case. JSR can call
a subroutine no matter how far away it is. For the purpose of this tutorial I
will only use BSR, although JSR could be substituted.

 All subroutines should end with an RTS instruction ( recognise this ? ).
 
 Here is a discription of each of these instructions :
 
 BSR
 ===
 
 Syntax : bsr  < label >
 
 This instruction branches to the subroutine indicated by a displacement value. 
The displacement is calculated by the assembler from the label specified. When
executed the CPU pushes the address of the next instruction onto the stack (
this is the return address ). The displacement is then added to the program
counter ( this gives the address indicated by label ) and execution continues
from this point. The displacement can be posotive or negative, so the 
subroutine can be before or after the BSR instruction. This instruction is
faster than JSR.

 eg.  bsr	find_len
 
 calls the subroutine begining at label find_len
 
 JSR
 ===
 
 Syntax :  jsr  < ea >
 
 This instruction first pushes the address of the next instruction onto the
stack ( this is the return address ). The effective address is then loaded
into the program counter and execution continues from this point.

 eg.  jsr	find_len
 
 eg1. move.l	#find_len,a0
      jsr	a0
      
 eg2. move.l	#sub,a0
      jsr	(a0)
           """
           """
           """
 sub  dc.l      find_len
 
 
 All the above examples call the subroutine starting at find_len
 
 RTS
 ===
 
 Syntax :  rts
 
 This instruction pulls an address off of the stack ( the return address saved
earlier ) and loads this value into the program counter, execution then 
continues from this point.


 Lets write a subroutine that will calculate the length of a 0 terminated 
string. The subroutine will need to know where to find the string, so the
address should be in a0 prior to call. The length of the string will be
returned in d0. As I said earlier, make lots of comments :

; This subroutine calculates the length of a 0 terminated string of characters.

; Entry :  a0 must hold the address of the string

; Exit  :  d0 holds the length of the string
;          a0 holds address of 0 byte + 1

str_len		moveq.l	#-1,d0		initialise counter
loop		addq.l	#1,d0		bump counter
		tst.b	(a0)+		end of string ?
		bne	loop		if not loop back
		rts			all done so return
		
 Note that d0 is initalised to -1. This saves having to subtract 1 after the
loop to account for the 0 byte at the end.
      
 Now a short program to test out this subroutine:

main		movea.l	#string,a0
		bsr	str_len
		display_d0
		rts
		
string		dc.b	'this is a short string.',0
		even
		
 This subroutine is on the disc and is called str_len.sub ( original hey ! ).
The test program is also on the disc, and is eg_28.s

 Before moving on to a more useful subroutine, lets use our string length
subroutine again, this is eg_29.s :

main		movea.l	#string1,a0
		bsr	str_len
		display_d0
		movea.l	#string2,a0
		bsr	str_len
		display_d0
		movea.l	#string3,a0
		bsr	str_len
		display_d0
		rts
		
string1		dc.b	'My name is :',0
		even
string2		dc.b	'Mark ',0
		even
string3		dc.b	'Meany.',0
		even
		
 As you probably guessed, this program calculates the length of three strings.
 
 I have not coverd enough material to explain how the following subroutine
works, but this does not stop you from using it. This subroutine requires:

 1/  The DOS library is open ( if you use start.s on the disc it will be ).
 
 2/  The address of a 0 terminated text string.
 
 The subroutine will display the text string on the screen for you. This
subroutine is on the disc, called print.sub. I have already added it to the
available subroutines for you, so if you use start.s on this disc there is
no need to type it in again, just use bsr	print as in eg_30.s

 Now that a text string can be displayed, we can write subroutines that will
alter the text and see the result. Example 22 for example tested a character
to see if it was lower case, we could expand on this and write a subroutine
that scans a string converting all lower case characters to upper case as it
goes. By printing the string before and then after, we can verify that the 
subroutine works. Here is the subroutine, compare this to example 22 to see
the modifications made.

; This subroutine will convert all lower case letters in a 0 terminated text 
;string to upper case.

; Entry  :  a0 must hold the address of the text

; Exit   :  a0 holds address of byte following 0 terminator
;           d0.b holds 0

ucase		move.b		(a0),d0		d0 = next character
		cmpi.b		#'a',d0		is char < 'a'
		blt		not_lower_case	if so dont convert it
		cmpi.b		#'z',d0		is char > 'z'
		bgt		not_lower_case	if so dont convert it
		subi.b		#$20,d0		convert to upper case
not_lower_case	move.b		d0,(a0)+	replace character
		tst.b		d0		are we at end of string
		bne		ucase		if not check next character
		rts				otherwise return

 This subroutine is also saved on the disc as ucase.sub for you to use as you
wish.

 Here is a program that tests that the above subroutine works by printing a 
string before and after processing. This is eg_31.s

main		movea.l		#string,a0	a0 holds address of string
		bsr		print		print the string
		bsr		ucase		convert string to upper case
		movea.l		#string,a0	get address of string in a0
		bsr		print		print the converted string
		mouse_press			wait for left button
		rts				all done so return
		
string		dc.b		'convert THIS to UppEr CaSe .',$0a,$0a,0


 Well thats it for this month. 
 
 If you have been working through these tutorials please let me know !
 
 Last month I forgot to mention that the MSB is the left most bit in a byte,
word or long word whichever is relevant. The LSB is the right most bit:

 BYTE :  x x x x x x x x
         |             |
        MSB           LSB
        
 WORD :  x x x x x x x x x x x x x x x x
         |                             |
        MSB                           LSB
        
 LONG
 WORD :  x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x 
         |                                                             |
        MSB                                                           LSB
        
  x is one bit  ( 1 or 0 )
  
  LSB is Least Signifigant Bit
  
  MSB is Most Signifigant Bit



