6502 проблема подпрограммы randy hyde "JSR INCRTN"

Я слежу за A totorial в книге, использующей язык ассемблера 6502 от Randy Hyde, есть часть в главе 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

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 байта - но самый первый из трех мне кажется ошибочным.) ADR код операции на 6502, поэтому я должен предположить, что это псевдо-код операции ассемблера, который формирует 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 дважды.

Эта подпрограмма 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 каждый сохраненный байт и цикл выполнения улучшают производительность.

Другие вопросы по тегам