
For the next stage of our project we are going to learn how to increase the score for each team. For now we are going to use a key press to emulate a goal, one key for each side.
You will notice that the code has had some refactoring, it is particularly important with assembler to keep your code space as readable as possible, even more so than high level languages in which it normally takes one line of code to output to the console. With assembler it can take a least three and that’s not including the initial setup code!
Lets take a look at our listing:
ExecBase = 4
OpenLib = -552
OpenLibVersion = 34
CloseLib = -414
PutString = -948
Nothing has changed here, this is the usual byte offsets for the jump table and minimum library versions.
init:
MOVE.L #OpenLibVersion,D0
LEA DosName,A1
MOVE.L ExecBase,A6
JSR OpenLib(A6)
TST.L D0
BEQ.B no_lib_error
MOVE.L D0,A6
The next part has changed slightly in that it has been placed under a label ‘init’. This is just to keep the code base easier to understand. The code loads the dos.library and stores it into the address register A6 so we can use it throughout our program.
title_page_init:
MOVE.L #TitleString,D1
JSR PutString(A6)
MOVE.L #InstructionString,D1
JSR PutString(A6)
Again the title initialisation of the title screen has been sectioned off. This section of code prints the title “Dazza’s World of Soccer” and a piece of instruction text “Press ‘s’ to Start or ‘Esc’ to quit.”.
title_page:
BSR check_for_keypress
CMP.B #$45,d0 ;check for 'esc' key and quit
BEQ quit
CMP.B #$21,d0 ;check for 's' key and start game loop
BEQ game_init
BNE title_page
This section handles the title screen itself checking for either the ‘S’ key for starting the game or the ‘esc’ key for, you guessed it, exiting the game. We have also sectioned of the key press check to its own routine as we are using the same piece of code multiple times.
Again nothing really new except for some tidying up.
game_init:
MOVE.B #0,SideOneScoreValue ;init side one score
MOVE.B #0,SideTwoScoreValue ;init side two score
Now we are getting into the new code. Very simple to start with. Two variables have been initialised at the end of the full listing and this code stores the decimal value 0 within.
game_loop:
BSR scoring
BSR scoreboard ;get scoreboard text
BTST #6,$bfe001 ;loop until left mouse button press
BNE game_loop
This section is our original game loop with the scoreboard part sectioned out into it’s own subroutine. We also have a new routines added to allow for detecting the keys to increment the scores for the two sides, more on that later. The game loop is simple at the moment. We check to see if keys are pressed to increment the score, followed by the routine to draw the score board. Finally we check to see if the mouse button has been pressed to exit the game loop.
quit:
MOVE.L #QuitString,D1
JSR PutString(A6)
MOVE.L A6,A1
MOVE.L ExecBase,A6
JSR CloseLib(A6)
This code hasn’t changed. This is basically the code to close down the libraries and print a message to the screen saying ‘quit’.
no_lib_error:
CLR.L D0
RTS
And this routine is called to exit the code if the libraries failed to close.
Now onto where sufficient changes have been made:
scoreboard:
BSR check_for_keypress
MOVE.L #ScoreboardString,D1
JSR PutString(A6) ;output text
LEA buffer,a0 ;pointer to the buffer
MOVE.B SideOneScoreValue,D1 ;number to convert
JSR deci_4 ;test subroutine
MOVE.L #buffer,D1
JSR PutString(A6)
MOVE.L #newline,D1
JSR PutString(A6)
This section is for the score keeping and display for side 1. We first jump to the subroutine that handles the checks for key presses were within another jump is made to the code the deals with the score keeping (explained shortly).
Next we output the following text to the screen, “Scoreboard: Side 1” along with a line break. We can now get into explaining how we output the score. As it’s value is stored in memory as a decimal it has to be converted to ascii before it can be displayed on screen. This is handled by the deci_4 subroutine which places the result into the variable named buffer, again explained when we come to the code. The result will reside in a data register to be used to output to screen. We then add a newline which is define as a constant (hex value 10).
MOVE.L #ScoreboardStringThree,D1
JSR PutString(A6)
LEA buffer,a0 ;pointer to the buffer
MOVE.B SideTwoScoreValue,D1 ;number to convert
JSR deci_4 ;test subroutine
MOVE.L #buffer,D1
JSR PutString(A6)
MOVE.L #newline,D1
JSR PutString(A6)
MOVE.L #newline,D1
JSR PutString(A6)
MOVE.L #newline,D1
JSR PutString(A6)
RTS
These instructions are almost a copy of the previous listing but for the score for side two. We end with exiting the scoreboard routine and returning back to the main game loop.
Lets take a look at our new subroutines:
scoring:
BSR check_for_keypress
CMP.B #$01,d0 ;check for '1' key to increase side 1 score
BEQ increase_side_one_score
CMP.B #$02,d0 ;check for '2' key to increase side 2 acore
BEQ increase_side_two_score
RTS
This subroutine is our score emulation code. We again use the ‘check_for_keypress’ routine to place the raw key code result of what key (if any has been pressed) in to the data register D0. We then compare known key codes with the data register. if the data register contains the key code for key ‘1’ ($01) then we jump to the subroutine that deals with increasing the score of side 1, if not then we check for a key ‘2’ press to increase the score for side 2.
increase_side_one_score:
MOVE.B SideOneScoreValue,D1
ADD.B #1,D1
MOVE.B D1,SideOneScoreValue
RTS
To increase the score we simply move the current score into the data register, add a decimal 1 to its value and then move it back into memory storage referenced via our variable. We do exactly the same with the score for side 2.
increase_side_two_score
MOVE.B SideTwoScoreValue,D1
ADD.B #1,D1
MOVE.B D1,SideTwoScoreValue
RTS
The next couple of routines is where things get slightly more complicated:
check_for_keypress:
MOVE.B $bfec01,d0 ;move key press (if any) to d0
NOT.B d0
ROR.B #1,d0
RTS
This is our routine to, well, as is says on the tin to check for a key press. The hardware register where a key press is register is located at $bfec01. This is the CIAA serial data register that is connected to keyboard. We first move its contents to a data register as we need to manipulate the data within to get to the data we need.
The first part of the manipulation is a bitwise NOT. This flips the bits in the location i.e. 10010000 becomes 01101111. I am still on the search for the reasons why this is needed.
The second rotates the bits right by one place. After some research I found out the reason why. The following is taken from ADCD 2.1.
“All codes transmitted to the computer are rotated one bit before
transmission. The transmitted order is therefore 6-5-4-3-2-1-0-7. The
reason for this is to transmit the up/down flag last, in order to cause
a key-up code to be transmitted in case the keyboard is forced to restore
lost sync”
As you can see by the example the bits are rotated to the left by 1 bit so the code is needed to rotate them back.A fter these instructions we now have our raw key code in the data register 0.
The last piece of code is from
http://wiki.amigaspirit.hu/index.php/Amiga_Machine_Language_(Chapter_4) and has been documented within. This deals with converting decimal numbers to ascii which we use to output our score for each side.
deci_4: ;subroutine-four digit numbers
divu #1000,D1 ;divide by 1000
bsr digit ;evaluate result-move remainder
divu #100,D1 ;divide by 100
bsr digit ;evaluate result and move
divu #10,D1 ;divide by 10
bsr digit ;evaluate result-move remainder
;evaluate the remainder directly
digit:
add #$30,D1 ;convert result into ASCII
move.b D1,(a0)+ ;move it into buffer
clr D1 ;erase lower word
swap D1 ;move the remainder down
rts ;return
We end with our constant and variables
buffer: BLK.B 5,0 ;reserve bytes for result
ScoreboardString: DC.B 'Scoreboard: Side 1 ',10,0
newline: DC.B 10+'',0
ScoreboardStringThree: DC.B 'Side 2 ',10,0
SideOneScoreValue: DS.B 1
SideTwoScoreValue: DS.B 1
DosName: DC.B "dos.library",0
TitleString: DC.B "Dazza's World of Soccer",10,0
InstructionString: DC.B "Press 's' to Start or 'Esc' to quit.",10,0
QuitString: DC.B "Quit",10,0 ;Newline character (ASCII 10)
;has been also added to force
;a new line in the console.
The full listing is a follows
ExecBase = 4
OpenLib = -552
OpenLibVersion = 34
CloseLib = -414
PutString = -948
init:
MOVE.L #OpenLibVersion,D0
LEA DosName,A1
MOVE.L ExecBase,A6
JSR OpenLib(A6)
TST.L D0
BEQ.B no_lib_error
MOVE.L D0,A6
title_page_init:
MOVE.L #TitleString,D1
JSR PutString(A6)
MOVE.L #InstructionString,D1
JSR PutString(A6)
title_page:
BSR check_for_keypress
CMP.B #$45,d0 ;check for 'esc' key and quit
BEQ quit
CMP.B #$21,d0 ;check for 's' key and start game loop
BEQ game_init
BNE title_page
game_init:
MOVE.B #0,SideOneScoreValue ;init side one score
MOVE.B #0,SideTwoScoreValue ;init side two score
game_loop:
BSR scoring
BSR scoreboard ;get scoreboard text
BTST #6,$bfe001 ;loop until left mouse button press
BNE game_loop
quit:
MOVE.L #QuitString,D1
JSR PutString(A6)
MOVE.L A6,A1
MOVE.L ExecBase,A6
JSR CloseLib(A6)
no_lib_error:
CLR.L D0
RTS
scoreboard:
BSR check_for_keypress
MOVE.L #ScoreboardString,D1
JSR PutString(A6) ;output text
LEA buffer,a0 ;pointer to the buffer
MOVE.B SideOneScoreValue,D1 ;number to convert
JSR deci_4
MOVE.L #buffer,D1
JSR PutString(A6)
MOVE.L #newline,D1
JSR PutString(A6)
MOVE.L #ScoreboardStringThree,D1
JSR PutString(A6)
LEA buffer,a0 ;pointer to the buffer
MOVE.B SideTwoScoreValue,D1 ;number to convert
JSR deci_4
MOVE.L #buffer,D1
JSR PutString(A6)
MOVE.L #newline,D1
JSR PutString(A6)
MOVE.L #newline,D1
JSR PutString(A6)
MOVE.L #newline,D1
JSR PutString(A6)
RTS
scoring:
BSR check_for_keypress
CMP.B #$01,d0 ;check for '1' key to increase side 1 score
BEQ increase_side_one_score
CMP.B #$02,d0 ;check for '2' key to increase side 2 acore
BEQ increase_side_two_score
RTS
increase_side_one_score:
lea buffer,a0
MOVE.B SideOneScoreValue,D1
ADD.B #1,D1
MOVE.B D1,SideOneScoreValue
RTS
increase_side_two_score
MOVE.B SideTwoScoreValue,D1
ADD.B #1,D1
MOVE.B D1,SideTwoScoreValue
RTS
check_for_keypress:
MOVE.B $bfec01,d0 ;move key press (if any) to d0
NOT.B d0
ROR.B #1,d0
RTS
deci_4: ;subroutine-four digit numbers
divu #1000,D1 ;divide by 1000
bsr digit ;evaluate result-move remainder
divu #100,D1 ;divide by 100
bsr digit ;evaluate result and move
divu #10,D1 ;divide by 10
bsr digit ;evaluate result-move remainder
;evaluate the remainder directly
digit:
add #$30,D1 ;convert result into ASCII
move.b D1,(a0)+ ;move it into buffer
clr D1 ;erase lower word
swap D1 ;move the remainder down
rts ;return
buffer: BLK.B 5,0 ;reserve bytes for result ScoreboardString: DC.B 'Scoreboard: Side 1 ',10,0
newline: DC.B 10+'',0
ScoreboardStringThree: DC.B 'Side 2 ',10,0
SideOneScoreValue: DS.B 1
SideTwoScoreValue: DS.B 1
DosName: DC.B "dos.library",0
TitleString: DC.B "Dazza's World of Soccer",10,0
InstructionString: DC.B "Press 's' to Start or 'Esc' to quit.",10,0
QuitString: DC.B "Quit",10,0 ;Newline character (ASCII 10) has
;been also added to force a new
;line in the console.
Leave a Reply