Motorola 68000 Storage в сборе

Эта программа написана так, чтобы принимать пользовательский ввод с разделителями-пробелами с четырьмя токенами, складывать токены вместе, если они все являются числами, и выводить результат на терминал. Прямо сейчас он работает для таких чисел, как «1 1 1 1» и «123 123 123 123», но когда я пытаюсь сложить 4 числа длиной семь цифр (7 цифр, потому что это крайний случай), он только добавляет до 23068. Похоже, это проблема с размером одной из моих этикеток или что-то в этом роде, но я не уверен.

Вот код:

*
        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

Изменить 1

Похоже, это связано с тем, что я конвертирую представление ascii в фактическое число. Я добавляю .l к метке результата. Метка достаточно велика для хранения символов, но я не перемещаю на нее достаточно большой фрагмент.

Когда я ввожу «9999999 9999999 9999999 9999999» и устанавливаю точку останова для просмотра, память будет правильно отображать шестнадцатеричное значение 26259FC, поэтому возникает проблема, когда я конвертирую его обратно с помощью предоставленного макроса.

Я не ожидаю, что у кого-то есть решение для этого, но, возможно, у кого-то есть.

Edit2: этот код был пересмотрен под руководством Sep Rowland (большое спасибо). Я думаю, что получил все, что он рассказал, и исправленный код был отправлен в качестве ответа.


person Jeremy H.    schedule 17.11.2017    source источник


Ответы (2)


Ошибка (которую вы уже нашли) была ext.l D0. Учитывая, что знак этой инструкции расширяет младшее слово в D0, неудивительно, что результаты были неверными.


У меня редко выпадает возможность углубиться в хороший код 68K, поэтому здесь я добавлю несколько комментариев, которые могут улучшить вашу программу.

addi.l  #1,D1
adda.l  #1,A1

Вы можете написать эти небольшие дополнения, которые добавляют от #1 до #8, более оптимально, если вы используете инструкцию addq:

addq.l  #1,D1
addq.l  #1,A1

Чтобы отобразить сообщение об ошибке, когда определенный ввод не является числом, можно написать намного проще, если вы преобразуете число в D1 (1-4) в символ ("1"-"4") и напишите это в одиночной ошибке сообщение:

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

Этот выходной буфер недостаточно длинный для того, что вы делаете!
У вас всего 12 байт, но вы сначала копируете 10-символьное сообщение sum, добавляете пробел, добавьте результат длиной в несколько символов, добавьте точку и добавьте ноль. Явно переполнение буфера.
Теперь вы можете сделать этот буфер длиннее или разумно перестать копировать все вокруг и просто поместить буфер result рядом с сообщением sum (с с добавлением пробела и без завершающего нуля). Затем отобразите объединенные тексты sum и result за один раз. Гораздо более простое решение.

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:

Здесь вы можете сделать ярлык в коде, тем самым ускорив программу.
Не нужно BRA до самого верха, где вы будете делать 3 теста без необходимости.

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:

Всегда старайтесь не писать лишние инструкции.

topEx:
    move.l  A1,A2       *Duplicating address to use for strlen
top:    

    ...

    BRA     topEx
rest:
person Sep Roland    schedule 19.11.2017
comment
Серьезно, спасибо, что так подробно рассказали об этом. Я собираюсь просмотреть это вместе с моим кодом, чтобы внести улучшения. Несмотря на то, что это сборка, возможность оптимизации на таком низком уровне по-прежнему чрезвычайно ценна для меня. Пока(1) {Спасибо} - person Jeremy H.; 23.11.2017
comment
Пересмотрел ответ, который я предоставил в соответствии с вашим руководством. Думаю, я все получил. Я рад, что мне удалось вернуться и внести исправления, которые, по моему мнению, должны были быть там с самого начала, но этот опыт я перенесу в следующую написанную программу. Спасибо еще раз! - person Jeremy H.; 29.11.2017

Первоначальная проблема: инструкция ext.l. Это объясняется Сепом Роулендом в одном из других предоставленных ответов.

Другие изменения: под руководством Сепа я оптимизировал код в нескольких областях.

+1 для просмотра памяти и точек останова.

* Problem statement: Read input and determine if 4 numbers are provided. Add numbers.
* Input: ### ### ### ###
* Output: "The sum is ###"
* Error conditions tested: Correct number of data provided. Number vs Char
*  Also handles leading white spaces/multiple spaces between tokens
* Included files: None
* Method and/or pseudocode: 
* References: 
*----------------------------------------------------------------------
*
        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    


    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
    clr.l   D1          *D1 is input counter and starts at 0
    clr.l   D2          *D2 used as workspace
    move.l  #0,result   *Clearing garbage out of memory address
    move.l  A1,A2       *A2 used 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 checktoprange   *This means byte *might* be an ascii number

    cmpi.b  #32,(A1)
    BNE notnumber

whitespace:             *This will eat whitespace anywhere in buffer
    addq.l  #1,A1       *If we are here, we know current location is space
    cmpi.b  #32,(A1)    *So increment pointer and check for additional spaces
    BEQ whitespace
    move.l  A1,A2       *If we are here, we encountered a token
    BRA top             *Shift our pointer for token start location


checktoprange:  
    cmpi.b  #57,(A1)    *Is byte value higher than ascii numbers range?
    BGT notnumber       *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.

    addq.l  #1,A1       *Else increment the address pointer and loop.
    BRA top

endoftoken: 
    addq.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.
    addq.l  #1,D1       *Increment token counter
    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
    cvt2a   result,#8
    stripp  result,#8
    lea result,A0
    adda.l  D0,A0
    move.b  #46,(A0)+
    clr.b   (A0)
    lineout sum
    BRA end


incnums:
    lineout incno       *If here, there were not the correct number of tokens.
    BRA end


notnumber:
    lea bn,A1
    addi.b  #49,D1       *From number to character
    move.b  D1,5(A1)     *Replaces the dot in the error message
    lineout bn

end:    

        break                   * Terminate execution
*
*----------------------------------------------------------------------
*       Storage declarations

header: dc.b    'This is a header',0
prompt: dc.b    'Enter the four space separated numbers:',0
incno:  dc.b    'There are not four inputs.',0
buffer: ds.b    80
bn:     dc.b    'The #. input is not a number',0
sum:    dc.b    'The sum is '
result: ds.l    1


        end
person Jeremy H.    schedule 17.11.2017
comment
Я вижу, что вы удачно разместили result как последний элемент в области хранения. Для основного цикла вашей программы нормально, если он ссылается только на dword, но для преобразования в текстовое представление вам потребуется больше (около 10 байтов или около того) . Всегда лучше явно указать память, которую будет использовать ваша программа, и не лезть в какую-либо память, которая оказывается свободной за пределами вашей программы. - person Sep Roland; 17.12.2017
comment
Я собираюсь продолжать наблюдать за памятью во время работы программы, чтобы понять дополнительные случаи и сколько памяти ей потребуется. Спасибо! - person Jeremy H.; 18.12.2017