6502 проблема подпрограммы Рэнди Хайда JSR INCRTN

Я следую учебнику A в книге с использованием языка ассемблера 6502 Рэнди Хайда, в главе 14, разделе 7 есть часть, где он пишет «jsr incrtn», проблема в том, что он не создал подпрограмму, называемую incrtn, вот полный код ,


    PRTSTR:
     STA ASAVE
     STY YSAVE
     PLA ;GET RETURN ADDRESS FROM
     STA RTNADR ;THE 6502 STACK
     PLA
     STA RTNADR+$1
     ;
     JSR INCRTN ;INCREMEOT THE RETURN ADDRESS
     LDY #$0
     LDA (RTNADR),Y ;GET L.O. ADDRESS OF STRING
     STA ZPAGE
     INY
     LDA (RTNADR),Y ;GET H.O.ADDRESS OF STRING
     STA ZPAGE+$1
     ;
     JSR INCRTN ;MOVE RTNADR PAST THE ADDRESS
     JSR INCRTN ;BYTES
     ;
     ;
     ; AT THIS POINT, ZPAGE POINTS TO THE STRING WHICH
     ; IS SUPPOSED TO BE OUTPUT
     ;
     DEY ;RESET Y REG TO ZERO
     LDA (ZPAGE),Y ;GET THE LENGTH OF THE STRING
     STA LENGTH ;AND STORE IT IN "LENGTH"
     PRTS1 INY ;MOVE TO THE NEXT CHARACTER
     CPY LENGTH ;ARE WE THROUGH YET?
     BEQ PRTS2
     ;
     LDA (ZPAGE),Y ;GET THIS CHARACTER
     JSR COUT ;AND OUTPUT
     JMP PRTS1 ;MOVE TO NEXT CHAR AND REPEAT
     ;
     PRTS2 LDA ASAVE ;RESTORE THE REGISTERS
     LDY YSAVE
     JMP (RTNADR) ;SIMULATE AN RTS
     ;
     ;
     ;
     ASAVE EPZ $0 ;ZERO PAGE WORKSPACE
     YSAVE EPZ ASAVE+$1
     ZPAGE EPZ YSAVE+$1
     RTNADR EPZ ZPAGE+$2
     COUT EQU $FDED ;COUT ROUTINE
     END

Может кто-нибудь помочь мне?

Обновление, если кто-то хочет знать, как печатать текст короче, вот некоторый рабочий код.


           LDX #$0
  LOOP     INX 
           LDA STRING,X 
           JSR $FDF0 
           CPX STRING 
           BLT LOOP 
           RTS  
  STRING   STR "hello world"
         END

person Xander Weiss-Lemieux    schedule 13.12.2019    source источник
comment
Похоже, это должно быть RTNADR += 1, конечно, вы можете это запрограммировать?   -  person Jester    schedule 13.12.2019
comment
Так должен ли я заменить jsr incrtn на rtnadr +=1?   -  person Xander Weiss-Lemieux    schedule 13.12.2019
comment
Нет, вы должны написать подпрограмму, которая увеличивает RTNADR на 1.   -  person Jester    schedule 13.12.2019


Ответы (2)


До того, как у процессоров появился стек или достаточное количество регистров, параметры часто передавались через «встроенную» передачу параметров, то есть параметры передаются после инструкции JSR или типа вызова, путем помещения значений или указателей непосредственно после инструкции вызова, с требованием, чтобы вызываемый абонент пропускает их при возврате, чтобы возобновить вызов вызывающего абонента.

Как вы знаете, инструкция вызова захватывает адрес возврата (каким-то образом, где-то: может быть, в стеке или, может быть, в памяти кода подпрограммы!), и этот адрес возврата можно использовать для выборки параметров, которые помещаются после инструкции вызова. Адрес возврата увеличивается для получения последовательных параметров, и когда это сделано, его необходимо увеличить (на 1 или 2) еще раз, чтобы вернуться к фактическому коду вызывающей стороны, а не к встроенным параметрам, которые, конечно же, являются данными. , а не код.

Стиль, который Хайд использует для этого PRTSTR, представляет собой встроенный механизм параметров.

Вот использование этого PRTSTR:

    ...
STRING STR "HELLO THERE"
    ...
START
    JSR PRTSTR    # call to print string
    ADR STRING    # pointer parameter passed "inline" within code, 
                  # this is data, to be used and then skipped over by print string
    ...           # actual return location to resume code in START

Учитывая, что в 6502 были как стек вызовов, так и регистры, использование встроенного механизма для вызовов является своего рода возвратом, но, безусловно, это было сделано. (Встроенный механизм передачи параметров предшествует стекам вызовов и большому количеству регистров, которые мы имеем в современных процессорах.)

Со стеком, но с небольшим количеством регистров, некоторые вызовы с многочисленными параметрами выполнялись бы путем помещения параметров в стек, в то время как другие выполнялись бы путем передачи доступных регистров.

В коде на чистом ассемблере вы можете создать собственное соглашение о вызовах для каждой функции. Только появление C и других языков высокого уровня создает потребность в канонических, регулярных и предсказуемых соглашениях о вызовах, которые могут быть кодифицированы в компиляторе.


Я должен признать, что не понимаю первую из трех инструкций JSR INCRTN. (Последние два я понимаю — они пропускают указатель на строку (инлайн-параметр после JSR), а так как указатели двухбайтовые, то и адрес нужно увеличивать на 2 байта — но самый первый из трех мне кажется ошибочным. ) На 6502 нет кода операции ADR, поэтому я должен предположить, что это псевдокод операции ассемблера, который формирует 2-байтовый указатель на метку.

Мое предположение несколько подтверждает Хайд в 14-6, где говорится:

    JSR SASIGN ;STRING ASSIGNMENT
    ADR DEST ;DEST = SOURCE
    ADR SOURCE

что приведенное выше представляет собой последовательность из 7 байтов (т.е. 1 для кода операции JSR, 2 для SASIGN (операнд JSR) и по 2 для ADR DEST и ADR SOURCE).


Таким образом, 16-битная переменная в RTNADR и RTNADR + 1 должна быть увеличена на единицу, когда код выполняет JSR INCRTN.


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

Кроме того, поскольку я не могу понять первый JSR INCRTN, а второй вызывается дважды, он может просто увеличиться на 2 вместо 1 дважды.

person Erik Eidt    schedule 13.12.2019
comment
JSR помещает адрес - 1 следующей операции в стек. Отсюда первый звонок. - person Nick Westgate; 15.12.2019

Эта подпрограмма INCRTN должна выглядеть примерно так:

INCRTN:
    INC RTNADR      ; Add 1 to RTNADR
    BNE INCRTNEX
    INC RTNADR+$01  ; If the pointer passes a page boundary,
INCRTNEX:           ; advance to the next page.
    RTS

Это выполняет 16-битное приращение к объекту RTNADR.

Альтернативная версия, которая потребует ввода значения в A, но будет более гибкой, заключается в использовании следующего:

ADD2RTN:
    CLC
    ADC RTNADR
    STA RTNADR
    BCC ADD2RTNX
    INC RTNADR+$01
ADD2RTNX:
    RTS

Это добавляет 8-битное значение (предусмотренное в A) к 16-битному объекту RTNADR.

Первый сегмент кода, который я предоставил, делает именно то, что сделал бы образец, который вы дали, в то время как второй обеспечивает гораздо более высокую производительность, поскольку необходимо добавить более двух байтов.

В приведенном вами коде вы можете заменить код, который загружает адрес строки и продвигает адрес возврата следующим образом:

LDY #$01
LDA (RTNADR),Y
STA ZPAGE
INY
LDA (RTNADR),Y
STA ZPAGE+$1
LDA #03
JSR ADD2RTN
;
LDY #0        ; Manually reset Y to 0 instead of using DEY twice to save time

Это выполняется на несколько циклов быстрее, чем исходный код (для JSR и RTS требуется по 6 циклов, а INC использует 5, поскольку RTNADR находится на нулевой странице) и не добавляет никакого кода. При работе с 6502 каждый сохраненный байт и цикл выполнения повышают производительность.

person G David    schedule 26.01.2020