This program is written to take space delimited user input with four tokens, add the tokens together if they are all numbers, and print the result to the terminal. Right now it works for numbers such as "1 1 1 1" and "123 123 123 123," but when I attempt to add 4 numbers that are seven digits long (7 digits, because that is the extreme case), it only adds up to 23068. This sounds like it would be a sizing issue with one of my labels or something, but I am not certain.
Here is the code:
*
ORG $0
DC.L $3000 * Stack pointer value after a reset
DC.L start * Program counter value after a reset
ORG $3000 * Start at location 3000 Hex
*
*----------------------------------------------------------------------
*
#minclude /home/cs/faculty/cs237/bsvc/macros/iomacs.s
#minclude /home/cs/faculty/cs237/bsvc/macros/evtmacs.s
*
*----------------------------------------------------------------------
*
* Register use
*
*----------------------------------------------------------------------
*
start: initIO * Initialize (required for I/O)
setEVT * Error handling routines
* initF * For floating point macros only
* Your code goes HERE
*Output info:
lineout header *Display header info
lineout prompt *Display prompt
linein buffer *Read input to buffer
lea buffer,A1 *
adda.l D0,A1 *Add null terminator
clr.b (A1) *
lea buffer,A1 *Reload the beginning of buffer address
move.l #1,D1 *D1 is input counter and starts at 1
clr.l D2 *
clr.l D3 *Prepping registers for calculations
move.l #0,result *
move.l A1,A2 *Duplicating address to use for strlen
top:
tst.b (A1) *Check for end of string
BEQ rest *If end, go to rest
cmpi.b #47,(A1) *Check current byte against low end of ascii numbers
BGT toprange *This means byte *might* be an ascii number
cmpi.b #32,(A1) *Byte is below range for numbers. Is it a space?
BNE notno *If this triggers, it's not a space and not a number. Exit.
cmpi.b #32,1(A1) *Is the character after this a space? If yes, loop to top.
BNE addit *If not, it's either another valid byte or null terminator.
adda.l #1,A1 *Increment token counter and loop to top.
BRA top
toprange:
cmpi.b #57,(A1) *Is byte value higher than ascii numbers range?
BGT notno *If yes, it's not an ascii number. Exit.
cmpi.b #32,1(A1) *Is the byte after this a space?
BEQ endoftoken *If yes, that means this is the end of the token.
tst.b 1(A1) *If not, is this byte a null terminator?
BEQ endoftoken *If yes, this is the last token. Add it.
adda.l #1,A1 *Else increment the address pointer and loop.
BRA top
endoftoken:
adda.l #1,A1 *Increment pointer
move.l A1,D2 *
sub.l A2,D2 *Find length of token
cvta2 (A2),D2 *Convert current token segment to number
add.l D0,result *Add converted number to result address.
BRA top *Loop to top.
addit:
tst.b 1(A1) *Test for null
BEQ endoftoken *If null, go endof token to add it to running total
addi.l #1,D1 *If next byte isn't null, there might be more tokens. Incr & cont.
adda.l #1,A1
move.l A1,A2 *Shift token starting point pointer forward
BRA top
rest:
cmpi.l #4,D1 *Check to make sure we have 4 tokens
BNE incnums *If not, exit on error
move.l result,D0 *Convert numbers back to text representations
ext.l D0
cvt2a result,#8
stripp result,#8
lea result,A0
adda.l D0,A0
clr.b (A0)
lea sum,A1 *Point to first bit of text for strcat
lea output,A2 *Point to destination during copying
strcat1:
tst.b (A1) *Null?
BEQ strcat2 *Go to next segment of code
move.b (A1)+,(A2)+ *If not null, copy from A1 to A2. Post increment
BRA strcat1
strcat2:
move.b #32,(A2)+ *Append space. Post increment
lea result,A1 *Point to calculated result
strcat3:
tst.b (A1) *Is this byte null?
BEQ printr *If yes, go to print response.
move.b (A1)+,(A2)+ *If not, copy byte to output string.
BRA strcat3
printr:
move.b #46,(A2)+ *Append period to output string.
clr.b (A2) *Null terminate the string.
lineout output *Print built string to terminal.
BRA end
incnums:
lineout incno *If here, there were not the correct number of tokens.
BRA end
notno:
cmpi.b #1,D1 *This checks the token counter to determine which token was not a #
BNE ch2
lineout bn1
BRA end
ch2:
cmpi.b #2,D1
BNE ch3
lineout bn2
BRA end
ch3:
cmpi.b #3,D1
BNE ch4
lineout bn3
BRA end
ch4:
lineout bn4
end:
*Output result
break * Terminate execution
*
*----------------------------------------------------------------------
* Storage declarations
prompt: dc.b 'Enter the four space separated numbers:',0
sum: dc.b 'The sum is',0
incno: dc.b 'There are not four inputs.',0
buffer: ds.b 80
result: ds.l 3
output: ds.l 3
bn1: dc.b 'The #1 input is not a number',0
bn2: dc.b 'The #2 input is not a number',0
bn3: dc.b 'The #3 input is not a number',0
bn4: dc.b 'The #4 input is not a number',0
end
Edit 1
It looks like it has to do with when I convert the ascii representation to an actual number. I add.l to the result label. The label is big enough to store the characters, but I am not moving a large enough chunk to it.
When I enter "9999999 9999999 9999999 9999999" and set a break point to watch it, the memory will correctly display the hex value of 26259FC, so it's a problem when I convert it back using the provided macro.
I don't expect anyone to have a solution for that, but maybe someone does.
Edit2: This code has been revised under the guidance of Sep Rowland (many thanks). I think I got everything he covered, and the revised code has been submitted as an answer.
The error (that you found already) was ext.l D0
. Given that this instruction sign-extends the low word in D0
it was not surprising that results were off.
I seldom get an opportunity to delve into some good 68K code, so here I go with some comments that can improve your program.
addi.l #1,D1 adda.l #1,A1
You can write these small additions that add from #1 to #8, more optimal if you use the addq
instruction:
addq.l #1,D1
addq.l #1,A1
To display the error message when a certain input is not a number, can be written much simpler if you convert the number in D1
(1-4) into a character ("1"-"4") and write that in the single error message:
lea bn,A1
addi.b #48,D1 *From number to character
move.b D1,5(A1) *Replaces the dot in the error message
lineout bn
...
bn: dc.b 'The #. input is not a number',0
output: ds.l 3
This output buffer is not long enough for what you're doing!
You've only 12 bytes, yet you first copy the 10 character long sum message, add a space, add the several characters long result, add a period and add a zero. Clearly a buffer overrun.
Now you could make this buffer longer or else intelligently stop copying everything around and just place the result buffer adjacent to the sum message (with a space appended and without a terminating zero). Then display the combined sum and result texts in one go. A much simpler solution.
move.l result,D0 *Convert numbers back to text representations
cvt2a result,#8
stripp result,#8
lea result,A2
adda.l D0,A2
move.b #46,(A2)+ *Append period to output string.
clr.b (A2) *Null terminate the string.
lineout sum *Print built string to terminal.
BRA end
...
sum: dc.b 'The sum is '
result: ds.l 3
cmpi.b #32,1(A1) *Is the character after this a space? If yes, loop to top. BNE addit *If not, it's either another valid byte or null terminator. adda.l #1,A1 *Increment token counter and loop to top. BRA top toprange:
Here you can make a shortcut in the code, thus speeding up the program.
No need to BRA
all the way to the top, where you will be doing 3 tests needlessly.
SkipWhitespace:
cmpi.b #32,1(A1)
BNE addit
addq.l #1,A1
BRA SkipWhitespace
toprange:
move.l A1,A2 *Duplicating address to use for strlen top: ... move.l A1,A2 *Shift token starting point pointer forward BRA top rest:
Always try to not write redundant instructions.
topEx:
move.l A1,A2 *Duplicating address to use for strlen
top:
...
BRA topEx
rest: