Код:
prompt equ 0F86Ch
puta equ 0F815h
puts equ 0F818h
THE_PSW EQU 07FFEH
THE_HL EQU 07FFCH
JRNZ EQU 0C7H
JRZ EQU 0CFH
JRNC EQU 0D7H
JRC EQU 0DFH
org 0
; Эта крошечная утилита с оригинальным трюком
; использования RST-команд.
; Возможность выбора точки старта программы посредством
; директивы <G0>..<G38>-МОНИТОРа.
; Возможность вызова нужной подпрограммы при помощи
; функции <USR(0..56)>-БЕЙСИКа.
; Вызов дополнительного API из любой части остального
; приложения посредством <RST 0>..<RST 7>
ORG 00000H
DB 0FFH,0FFH,0FFH,0FFH,0FFH,0FFH,0FFH,0FFH
DB 0FFH,0FFH,0FFH,0FFH,0FFH,0FFH,0FFH,0FFH
DB 0FFH,0FFH,0FFH,0FFH,0FFH,0FFH,0FFH,0FFH
DB 0FFH,0FFH,0FFH,0FFH,0FFH,0FFH,0FFH,0FFH
DB 0FFH,0FFH,0FFH,0FFH,0FFH,0FFH,0FFH,0FFH
DB 0FFH,0FFH,0FFH,0FFH,0FFH,0FFH,0FFH,0FFH
DB 0FFH,0FFH,0FFH,0FFH,0FFH,0FFH,0FFH,0FFH
; Здесь располагается обработчик программных прерываний и системных вызовов.
; Через "МОНИТОР" из-вне имеется 57 точек входа директивой G0-G38 для запуска
; программы в различных режимах.
; Внутри программы эти вызовы дублируют API "МОНИТОРа" и дополняют его.
ORG 00038H
SHLD THE_HL ; Сохраняем HL-пару
PUSH PSW ; Затем, посредством
POP H ; регистровой пары HL
SHLD THE_PSW ; сохраняем и PSW
LXI H,08A00H; Проверяем указатель стека:
DAD SP ; Предустановил ли его МОНИТОР?
POP H
JC START ; Значит это "холодный старт"
MOV A,H
ADD A ; Проверим, прикладной ли вызов?
JNZ THE_APP ; Приложение вызывает наш API
JC MON_RST ; Значит один из FF МОНИТОРа
MVI A,TAPIS ; Table of APIs
ADD L ; Иначе - это USR-вызов
MOV A,M
INX H
MOV H,M
XTHL
LHLD THE_PSW
PUSH H
POP PSW
LHLD THE_HL
RET
THE_APP:MOV A,M ; Вызов из приложения
XRI 080H ; Если укладывается в KOI-7
JM PRINT ; Просто печатаем сообщение
INX H
PUSH H ; Сейчас проверим следующий байт
SUI 012H ; Одна из стандартных 18 точек
JC THE_MON ; МОНИТОРа?
ADD A
MVI H,THE_API >> 8
MOV L,A
MOV A,M
INX H
MOV H,M
MOV L,A
XTHL
RET
THE_MON:CMA
MOV L,A
ADD A
ADD L
MOV L,A
MVI H,0F8H
THE_RET:PUSH H
LHLD THE_PSW
PUSH H
POP PSW
LHLD THE_HL
RET
PRINT: PUSH H
PUSH B
CALL PUTS
POP B
INX H
JMP THE_RET
TAPIS: DW PROMPT
DW 0,0,0,0,0,0,0
DW 0,0,0,0,0,0,0,0
DW 0,0,0,0,0,0,0,0
DW 0,0,0,0,0,0,0,0
DW 0,0,0,0,0,0,0,0
DW 0,0,0,0,0,0,0,0
DW 0,0,0,0,0,0,0
START: LXI SP,075FFH
MOV C,L
DB 0FFH,1FH,'START:',0
MOV A,C
DB 0FFH,08AH
DB 0FFH,092H
Фокус в том, что при запуске через «G0…G38» указатель стека SP установлен в служебную область МОНИТОРа и программно легко это определить.
А вот при «CALL 00000h…00038h» указатель стека уже в области пользователя и получается, что и «RST 0» тоже работает как особая подпрограмма.
На ZX-Spectrum этот трюк не сработает, так как при СБРОСе SP никак не изменяется.
Но вот кодом «FF» я заполнял все 256 ячеек (исключения - 00038h и 00098h, где нужно вставить «JR»), а сам код начинался с 00100h.