Amiga Asm: Character Replacement in a String

In high level language, string concatenation (the joining of two or more strings) is a very simple process. Well, except if you spend a lot of time in a world where concatenating strings is done by using a plus sign and then you swap horses mid stream and enter the world of PHP! When will you finally realise that you use a period sign to concatenate? Before or after spending what seems a life time trying to figure why you are getting garbled or no text on your screen! Anyway rant over and back to the subject in hand. Concatenation with Assembler is a little bit more tricky.

The normal way do string concatenation is by iterate through every character and placing them one by one to a new register. If we are dealing with replacements a few characters in length then we can load a base string as a template into memory and inject data into certain position. Lets take a look at an example

quoteFromFilm:    dc.b    
'Hello, my initials are'
forename: dc.b '# '
furname: dc.b '#.'
' You killed my father, prepare to die!',10,0

Certain readers will be grinning from ear to ear when they read the quote which is based on a famous line from the film ‘The Princess Bride’ but with some alterations. As we can see from the template that there is a ‘#’ replacing the initial of the forename and the same for the surname. This # character (it can be any) will be replaced with the desired initial. It is also worth noting that the template is made up of a number of labels. The first label being called ‘QuoteFromFilm’ and the last ‘Surname’ which is ended with a line termination (0). Assembler will hit the first label and work through until it hits the line termination. This allows the ability to output all three labels one after each other. Lets have a look at the code to achieve this.

SetQuote:
lea forename(pc),a2
move.b #replace_forename,(a2)
lea surname(pc),a2
move.b #replace_surname,1(a2)
rts
quoteFromFilm: dc.b
'Hello, my initials are'
forename: dc.b '#'
surname: dc.b ' #.'
' You killed my father, prepare to die!',10,0
replace_forename: dc.b 'Inigo',0
replace_surname: dc.b 'Montoya',0

How it works

So how does this work? You will notice we use a instruction called ‘LEA’. This instruction Loads an Effective Address into an address register. It has the following syntax:

lea effective address,An

Where “An” is any of the eight address registers (a0-a7). In the code example you can see that we have the line:

forename(pc),a2

This means that the a2 register becomes a pointer to forename. “PC” is the Program Counter. After this instruction we have:

move.b #replace_forename,(a2)  

This replaces the content of the memory from where the register points to with the content of the memory labelled ‘#replace_forename’. If we specified a value in front of the bracketed register as per the surname replacement line:

move.b    #replace_surname,1(a2)

then the replacement will happen one byte from the starting position. Remember ASCII characters are 8 bits long (a byte) and our surname contains the content ‘ #.’ (notice the space before the hash symbol!) the replacement will mean that the space at the front of the string will be kept and the surname initial will overwrite the ‘#’.

The program will finally finished when it meets the null termination. A common mistake is to forget the null termination and all of the sudden you have Incorporated sub sequential labels into your string.

Incorporating Into Game Code

So now we have our example lets incorporate this into our code. Below you will see that I have added the code to output the scoreboard. I had to do some rearranging of the code first so we now have a defined title and game loop routines.

ExecBase = 4                 
OpenLib = -552
OpenLibVersion = 34
CloseLib = -414
PutString = -948

MOVE.L #OpenLibVersion,D0
LEA DosName,A1
MOVE.L ExecBase,A6
JSR OpenLib(A6)
TST.L D0
BEQ.B NoLibError
MOVE.L D0,A6
MOVE.L #TitleString,D1
JSR PutString(A6)
MOVE.L #InstructionString,D1
JSR PutString(A6)

title_page:
MOVE.B $bfec01,d0 ;move key press (if any) to d0
NOT.b d0
ROR.b #1,d0
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_loop
BNE title_page
game_loop:
bsr scoreboard ;get scoreboard text
MOVE.L #ScoreboardString,D1
JSR PutString(A6) ;output 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)
NoLibError: CLR.L D0
RTS
scoreboard:
LEA SideOneScore(PC),A2
MOVE.B SideOneScoreValue,15(A2)
LEA SideTwoScore(PC),A2
MOVE.B SideTwoScoreValue(PC),15(A2)
RTS
ScoreboardString:
DC.B 'Scoreboard:'
SideOneScore: DC.B ' Side 1 Score: #'; replace at 15 bytes
SideTwoScore: DC.B ' Side 2 Score: #',10,0 ; replace at 15 bytes
SideOneScoreValue: DC.B '3',0
SideTwoScoreValue: DC.B '2',0

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

Compile and run via the command to see the output.

vasmm68k_mot -kick1hunks -Fhunkexe -o  "C:\Users\Public\Documents\Amiga Files\WinUAE\Harddrives\Programs\simplegameloop2" -nosym SimpleGameLoop2.asm 

Be the first to comment

Leave a Reply

Your email address will not be published.


*