Гляжу в _VARS.A и там
Code: Select all
\ BASE TO BC
_V_B2B: PUSH_H
LHLD _L_BASE
MOV_B,H
MOV_C,L
POP_H
RET
используется в __RULES, но вызов этой подпрограммы можно выкинуть совсем, вставив в __RULES вместо неё LXI_B, @BASE (что суть тоже самое)
Code: Select all
\ REGS TO BC
_V_R2B: PUSH_H
LHLD _L_REGS
MOV_B,H
MOV_C,L
POP_H
RET
нигде не используется
Code: Select all
\ SET VAR
\ BC - BASE
\ HL - VAR
\ DE - DATA
_V_SET: PUSH_H
DAD_B
POP_B
DAD_B
MOV_M,E
INX_H
MOV_M,D
RET
пока нигде не используется, но может понадобиться в будущем (см. ниже)
Code: Select all
\ GET VAR
\ BC - BASE
\ HL - VAR
\ --------
\ HL - DATA
_V_GET: PUSH_H
DAD_B
POP_B
DAD_B
MOV_E,M
INX_H
MOV_D,M
XCHG
RET
используется только в _VARS.A
Code: Select all
\ GET VAR FROM BASE
\ HL - VAR
\ --------
\ HL - DATA
_B_GET: XCHG
LHLD _L_BASE
DAD_D
DAD_D
MOV_E,M
INX_H
MOV_D,M
XCHG
RET
используется в __RULES, но вызов этой подпрограммы можно заменить на LXI_B, @BASE и CALL _V_GET
Code: Select all
\ SET VAR FROM BASE
\ HL - VAR
\ DE - DATA
_B_SET: PUSH_H
LHLD _L_BASE
POP_B
DAD_B
DAD_B
MOV_M,E
INX_H
MOV_M,D
RET
используется в __RULES (см.ниже)
Code: Select all
\ GET REG
\ L - REGISTER
\ --------
\ HL - DATA
_R_GET: MVI_H, 0
XCHG
LHLD _L_REGS
DAD_D
DAD_D
MOV_E,M
INX_H
MOV_D,M
XCHG
RET
используется в _VARS.A и __RULES, но вызов этой подпрограммы можно заменить на LXI_B, @REGS и CALL _V_GET с предварительным обнулением регистра H
Code: Select all
\ SET REG
\ L - REGISTER
\ DE - DATA
\ --------
_R_SET: PUSH_D
MVI_H, 0
XCHG
LHLD _L_REGS
DAD_D
DAD_D
POP_D
MOV_M,E
INX_H
MOV_M,D
RET
используется в __RULES (см.ниже)
Code: Select all
\ GET ARR
\ BC - BASE
\ DE - ARRAY
\ HL - VAR
\ --------
\ HL - DATA
_A_GET: PUSH_B
PUSH_D
CALL _V_GET
XCHG
POP_B
POP_H
DAD_B
DAD_B
DAD_D
DAD_D
MOV_E,M
INX_H
MOV_D,M
XCHG
RET
используется в __RULES
Code: Select all
\ GET ARR REG
\ BC - BASE
\ DE - ARRAY
\ HL - REGISTER
\ --------
\ HL - DATA
_ARGET: PUSH_B
PUSH_D
CALL _R_GET
XCHG
POP_B
POP_H
DAD_B
DAD_B
DAD_D
DAD_D
MOV_E,M
INX_H
MOV_D,M
XCHG
RET
используется в __RULES
Code: Select all
\ ADR ARR
\ BC - BASE
\ DE - ARRAY
\ HL - VAR
\ --------
\ HL - ADDRESS
_A_ADR: PUSH_B
PUSH_D
CALL _V_GET
XCHG
POP_B
POP_H
DAD_B
DAD_B
DAD_D
DAD_D
RET
используется в __RULES
Code: Select all
\ ADR ARR REG
\ BC - BASE
\ DE - ARRAY
\ HL - REGISTER
\ --------
\ HL - ADDRESS
_ARADR: PUSH_B
PUSH_D
CALL _R_GET
XCHG
POP_B
POP_H
DAD_B
DAD_B
DAD_D
DAD_D
RET
используется в __RULES
Причём самый часто используемый в сгенерённом коде кусок из __RULES выглядит вот так:
Code: Select all
// 0xF3 // LOAD A -> mem[A]
*EXPR 0xF3
#addsub _VARS
#genlab %l1
#genlab %l2
MVI_A, #FF
CMP_H
JNZ %l1
\ REGISTER
CALL _R_GET
JMP %l2
%l1
\ VARIABLE
CALL _B_GET
%l2
*
Это дело надо упростить, чтобы было как-то так:
Code: Select all
// 0xF3 // LOAD A -> mem[A]
*EXPR 0xF3
#addsub _VARS
CALL _X_GET
*
Соответственно в _VARS.A надо будет добавить "вумную" подпрограмму _X_GET, которая сама будет определять чего от неё хотят - регистр (HL==#FFxx), переменную (HL>=0) или слово из буфера обмена с системой ввода-вывода (#8000...#FEFF) - последнего пока нету, но будет (буфер будет виртуальный - вместо обращения к памяти в данном случае будет вызываться подпрограмма из SYSTEM_.A которая будет возвращать слово по специфическому для системы алгоритму).
Аналогичное надо будет проделать вот с этим:
Code: Select all
// 0xF4 // SAVE A,B -> . (mem[A]=B)
*EXPR 0xF4
#addsub _VARS
#genlab %l1
#genlab %l2
POP_D
XCHG
MVI_A, #FF
CMP_H
JNZ %l1
\ REGISTER
CALL _R_SET
JMP %l2
%l1
\ VARIABLE
CALL _B_SET
%l2
POP_H
*
Добавив "вумную" подпрограмму _X_SET (устанавливающую регистр или память в зависимости от адреса), а подпрограммы _R_SET и _B_SET выкинуть за ненадобностью. Либо надо написать код прямо по месту т.к. SAVE это редкая операция, которая происходит один раз на выражение, и обращений к буферу файловой подсистемы на запись у нас не предвидится поэтому можно обойтись только вызовом _V_SET с разной базой для регистров и переменных:
Code: Select all
// 0xF4 // SAVE A,B -> . (mem[A]=B)
*EXPR 0xF4
#addsub _VARS
#genlab %l1
POP_D
XCHG
LXI_B, @BASE
MVI_A, #FF
SUB_H
JNZ %l1
MOV_H,A
LXI_B, @REGS
%l1
CALL _V_SET
POP_H
*
Единственное тут нету никакой проверки на выход за пределы области переменных (или регистров, коих у нас не более 32), но если компилятор ROBBYC работает корректно, то все смещения должны быть в нужных пределах (ну разве что бинарник будет попорчен при передаче или чтении с диска, тогда конечно да)...
P.S. Инициализация регистров Robby (а именно A,B,C и L) у меня сейчас компилируется в относительно компактный код целевой платформы, как и копирование из памяти переменных в регистр и из регистра в память переменных - вот думаю, а не сделать ли в случае платформы 2 (RW1P2) все регистры read/write? И накидать ещё регистров до 32-х, как планировал ранее - тогда простые подпрограммы можно будет писать только на регистрах (для пользователя они будут выглядеть просто как однобуквенные переменные) и они будут работать заметно быстрее...