Search code examples
assemblymotorola68000

Motorola 68000 Storage in Assembly


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.


Solution

  • 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: