; LAST UPDATE: 03.12.2022 savelij
; ((out&0ffff)==37f7)&&((val&0ff)==1)
; ((out&0ffff)==77f7)&&((val&0ff)==1)
; ((out&0ffff)==0b7f7)&&((val&0ff)==1)
; ((out&0ffff)==0f7f7)&&((val&0ff)==1)
; ((M(5CF4)==2)&&(M(5CF5)==1B))
; (((M(5CF4)==2)&&(M(5CF5)==1B))&&(SP<4000))
; ((OUT&0FFFF)==1F)|((OUT&0FFFF)==3F)|((OUT&0FFFF)==7F)
include ../../macros.a80
include ../../global_vars.a80
include ../../define.a80
include ../../evodos_vars.a80
STACK EQU 0x0DFF
OLD_IF EQU STACK-WORD*2
OLD_AF EQU STACK-WORD
; команда выхода и переход на обработчик
JP_EMU MACRO ADDRESS
DUPL ADDRESS-$,0
OUT (EXIT_PORT),A
JP ADR_ADDRESS
ENDM
; генерация адресов для таблицы
LABEL_GEN MACRO ADDRESS
_ADDRESS EQU ($ - TABLE_VIRT) / 4
DW ADDRESS,ADR_ADDRESS.WORK
ENDM
; переход на обработчик с кодом адреса
EMU_JUMP MACRO ADDRESS
ADR_ADDRESS EQU $
LD (OLD_AF + 1),A
LD A,_ADDRESS
JP WORKER
.WORK EQU $
ENDM
ORG 0
DUPL 0x0038 - $,0
EI
RET
DUPL 0x006F - $,0
JP (HL)
JP_EMU 0x02BE ; OUT (0xFF), A
DUPL 0x0801 - $,0
;таблица адресов перехвата и вызыватора обработчиков
TABLE_VIRT
LABEL_GEN 0x02BE ; OUT (0xFF), A
LABEL_GEN 0x1E3A ; OUT (0x3F), A
LABEL_GEN 0x1FDD ; IN A, (0x1F)
LABEL_GEN 0x1FF3 ; OUT (0xFF), A
LABEL_GEN 0x2000 ; OUT (0x1F), A
LABEL_GEN 0x2076 ; IN A, (0x1F)
LABEL_GEN 0x2085 ; OUT (0x3F), A
LABEL_GEN 0x208D ; OUT (0x5F), A
LABEL_GEN 0x2093 ; OUT (0x1F), A
LABEL_GEN 0x2099 ; IN A, (0x1F)
LABEL_GEN 0x20B1 ; IN A, (0xFF)
LABEL_GEN 0x20B8 ; OUT (C), D
LABEL_GEN 0x2740 ; IN A, (0x1F)
LABEL_GEN 0x2748 ; OUT (0x7F), A
LABEL_GEN 0x2A53 ; OUT (C), A
LABEL_GEN 0x2A71 ; OUT (0xFF), A MAGIC
LABEL_GEN 0x2A77 ; IN A, (0x1F) MAGIC
LABEL_GEN 0x2AD9 ; OUT (OxFF), A MAGIC
LABEL_GEN 0x2B25 ; IN A, (0x5F) MAGIC
LABEL_GEN 0x2C07 ; IN A, (0x5F) MAGIC
LABEL_GEN 0x2CD8 ; IN A, (0x5F) MAGIC
LABEL_GEN 0x2D75 ; OUT (0x5F), A MAGIC
LABEL_GEN 0x2D80 ; OUT (0x1F), A MAGIC
LABEL_GEN 0x2D87 ; IN A, (0x1F) MAGIC
LABEL_GEN 0x2F0C ; OUT (0xFF), A MAGIC
LABEL_GEN 0x2F1D ; OUT (0x5F), A MAGIC
LABEL_GEN 0x2F28 ; OUT (0x1F), A MAGIC
LABEL_GEN 0x2F2F ; IN A, (0x1F) MAGIC
LABEL_GEN 0x2F3C ; OUT (0xFF), A MAGIC
LABEL_GEN 0x2F4D ; OUT (0xFF), A MAGIC
LABEL_GEN 0x2F50 ; OUT (0x7F), A MAGIC
LABEL_GEN 0x2F57 ; OUT (0x1F), A MAGIC
LABEL_GEN 0x2F59 ; IN A, (0xFF)
LABEL_GEN 0x2FB1 ; OUT (0xFF), A
LABEL_GEN 0x2FC3 ; OUT (0x1F), A
LABEL_GEN 0x3C30 ; IN A, (0x1F)
LABEL_GEN 0x3D4D ; OUT (0xFF), A
LABEL_GEN 0x3D9A ; OUT (0x1F), A
LABEL_GEN 0x3DA6 ; IN A, (0xFF)
LABEL_GEN 0x3DB5 ; IN A, (0x1F)
LABEL_GEN 0x3DBA ; IN A, (0x1F)
LABEL_GEN 0x3DD5 ; OUT (0xFF), A
LABEL_GEN 0x3E30 ; IN A, (0x1F)
LABEL_GEN 0x3E3A ; IN A, (0x1F)
LABEL_GEN 0x3E44 ; OUT (0x7F), A
LABEL_GEN 0x3E4C ; OUT (0x7F), A
LABEL_GEN 0x3E50 ; IN A, (0x3F)
LABEL_GEN 0x3E78 ; IN A, (0x3F)
LABEL_GEN 0x3E7E ; OUT (0x3F), A
LABEL_GEN 0x3E87 ; IN A, (0x3F)
LABEL_GEN 0x3E95 ; OUT (0x3F), A
LABEL_GEN 0x3EB5 ; IN A, (0x1F)
LABEL_GEN 0x3EBC ; IN A, (0x3F)
LABEL_GEN 0x3EC9 ; OUT (0x1F), A
LABEL_GEN 0x3ECE ; IN A, (0xFF)
LABEL_GEN 0x3EDF ; OUT (0x1F), A
LABEL_GEN 0x3EF3 ; IN H, (C)
LABEL_GEN 0x3EF5 ; IN A, (0xFF)
LABEL_GEN 0x3EFE ; IN A, (0x7F)
LABEL_GEN 0x3F1B ; OUT (0x5F), A
LABEL_GEN 0x3F25 ; OUT (0x1F), A
LABEL_GEN 0x3F33 ; IN A, (0x1F)
LABEL_GEN 0x3F4D ; OUT (0x1F), A
LABEL_GEN 0x3F55 ; IN A, (0x3F)
LABEL_GEN 0x3F5A ; Ix A, (0x5F)
LABEL_GEN 0x3F69 ; IN A, (0x3F)
LABEL_GEN 0x3F72 ; IN A, (0x5F)
LABEL_GEN 0x3FBC ; IN A, (0xFF)
LABEL_GEN 0x3FCA ; IN A, (0xFF)
LABEL_GEN 0x3FD1 ; OUTI
LABEL_GEN 0x3FD7 ; IN A, (0xFF)
LABEL_GEN 0x3FE5 ; IN A, (0xFF)
LABEL_GEN 0x3FEC ; INI
LABEL_GEN 0x3FF0 ; OUT (C), A
LABEL_GEN 0x3FF3 ; IN A, (C)
; вызываторы перехвата
EMU_JUMP 0x02BE ; OUT (0xFF),A
JP OUT_FF
EMU_JUMP 0x1E3A ; OUT (0x3F),A
JP OUT_3F
EMU_JUMP 0x1FDD ; IN A,(0x1F)
JP IN_1F
EMU_JUMP 0x1FF3 ; OUT (0xFF),A
JP OUT_FF
EMU_JUMP 0x2000 ; OUT (0x1F),A
JP OUT_1F
EMU_JUMP 0x2076 ; IN A,(0x1F)
JP IN_1F
EMU_JUMP 0x2085 ; OUT (0x3F),A
JP OUT_3F
EMU_JUMP 0x208D ; OUT (0x5F),A
JP OUT_5F
EMU_JUMP 0x2093 ; OUT (0x1F),A
JP OUT_1F
EMU_JUMP 0x2099 ; IN A,(0x1F)
JP IN_1F
EMU_JUMP 0x20B1 ; IN A,(0xFF)
JP IN_FF
EMU_JUMP 0x20B8 ; OUT (C),D
JP OUT_C_D
EMU_JUMP 0x2740 ; IN A,(0x1F)
JP IN_1F
EMU_JUMP 0x2748 ; OUT (0x7F),A
JP OUT_7F
EMU_JUMP 0x2A53 ; OUT (C),A
JP OUT_C_A
EMU_JUMP 0x2A71 ; OUT (0xFF),A
JP OUT_FF
EMU_JUMP 0x2A77 ; IN A,(0x1F)
JP IN_1F
EMU_JUMP 0x2AD9 ; OUT (0xFF),A
JP OUT_FF
EMU_JUMP 0x2B25 ; IN A,(0x5F)
JP IN_5F
DUPL 0x09FF - $,0
DW 0xFFFF
EMU_JUMP 0x2C07 ;IN A,(0x5F)
JP IN_5F
EMU_JUMP 0x2CD8 ; IN A,(0x5F)
JP IN_5F
EMU_JUMP 0x2D75 ; OUT (0x5F),A
JP OUT_5F
EMU_JUMP 0x2D80 ; OUT (0x1F),A
JP OUT_1F
EMU_JUMP 0x2D87 ; IN A,(0x1F)
JP IN_1F
EMU_JUMP 0x2F0C ; OUT (0xFF),A
JP OUT_FF
EMU_JUMP 0x2F1D ; OUT (0x5F),A
JP OUT_5F
EMU_JUMP 0x2F28 ; OUT (0x1F),A
JP OUT_1F
EMU_JUMP 0x2F2F ; IN A,(0x1F)
JP IN_1F
EMU_JUMP 0x2F3C ; OUT (0xFF),A
JP OUT_FF
EMU_JUMP 0x2F4D ; OUT (0xFF),A
JP OUT_FF
EMU_JUMP 0x2F50 ; OUT (0x7F),A
JP OUT_7F
EMU_JUMP 0x2F57 ; OUT (0x1F),A
JP OUT_1F
EMU_JUMP 0x2F59 ; IN A,(0xFF)
CALL IN_FF
LD HL,EXIT_0x2F59
LD (ADR_EXIT),HL
JP UPDATE_AF
EMU_JUMP 0x2FB1 ; OUT (0xFF),A
JP OUT_FF
EMU_JUMP 0x2FC3 ; OUT (0x1F),A
JP OUT_1F
EMU_JUMP 0x3C30 ; IN A,(0x1F)
JP IN_1F
EMU_JUMP 0x3D4D ; OUT (0xFF),A
JP OUT_FF
EMU_JUMP 0x3D9A ; OUT (0x1F),A
JP OUT_1F
EMU_JUMP 0x3DA6 ; IN A,(0xFF)
JP IN_FF
EMU_JUMP 0x3DB5 ; IN A,(0x1F)
JP IN_1F
EMU_JUMP 0x3DBA ; IN A,(0x1F)
JP IN_1F
EMU_JUMP 0x3DD5 ; OUT (0xFF),A
JP OUT_FF
EMU_JUMP 0x3E30 ; IN A,(0x1F)
JP IN_1F
EMU_JUMP 0x3E3A ; IN A,(0x1F)
JP IN_1F
EMU_JUMP 0x3E44 ; OUT (0x7F),A
JP OUT_7F
EMU_JUMP 0x3E4C ; OUT (0x7F),A
JP OUT_7F
EMU_JUMP 0x3E50 ; IN A,(0x3F)
JP IN_3F
EMU_JUMP 0x3E78 ; IN A,(0x3F)
JP IN_3F
EMU_JUMP 0x3E7E ; OUT (0x3F),A
JP OUT_3F
EMU_JUMP 0x3E87 ; IN A,(0x3F)
JP IN_3F
EMU_JUMP 0x3E95 ; OUT (0x3F),A
JP OUT_3F
EMU_JUMP 0x3EB5 ; IN A,(0x1F)
JP IN_1F
EMU_JUMP 0x3EBC ; IN A,(0x3F)
JP IN_3F
EMU_JUMP 0x3EC9 ; OUT (0x1F),A
JP OUT_1F
EMU_JUMP 0x3ECE ; IN A,(0xFF)
JP IN_FF
EMU_JUMP 0x3EDF ; OUT (0x1F),A
JP OUT_1F
EMU_JUMP 0x3EF3 ; IN H,(C)
JP IN_H_C
EMU_JUMP 0x3EF5 ; IN A,(0xFF)
CALL IN_FF
LD HL,EXIT_0x3EF5
LD (ADR_EXIT),HL
UPDATE_AF LD A,(OLD_AF + 1)
AND 0xC0
PUSH AF
POP HL
LD (OLD_AF),HL
RET
EMU_JUMP 0x3EFE ; IN A,(0x7F)
CALL OUT_1F.INFF_BIT6
JP IN_7F
EMU_JUMP 0x3F1B ; OUT (0x5F),A
JP OUT_5F
EMU_JUMP 0x3F25 ; OUT (0x1F),A
JP OUT_1F
EMU_JUMP 0x3F33 ; IN A,(0x1F)
JP IN_1F
EMU_JUMP 0x3F4D ; OUT (0x1F),A
JP OUT_1F
EMU_JUMP 0x3F55 ; IN A,(0x3F)
JP IN_3F
EMU_JUMP 0x3F5A ; IN A,(0x5F)
JP IN_5F
EMU_JUMP 0x3F69 ; IN A,(0x3F)
JP IN_3F
EMU_JUMP 0x3F72 ; IN A,(0x5F)
JP IN_5F
EMU_JUMP 0x3FBC ; IN A,(0xFF) ; запись сектора
JP WRITE_SECTOR
EMU_JUMP 0x3FCA ; IN A,(0xFF) ; запись сектора
JP WRITE_SECTOR
EMU_JUMP 0x3FD1 ; OUTI ; запись сектора
JP WRITE_SECTOR
EMU_JUMP 0x3FD7 ; IN A,(0xFF) ; чтение сектора
JP READ_SECTOR
; EMU_JUMP 0x3FD7 ; ожидание готовности чтения
; JP WAIT_READ
EMU_JUMP 0x3FE5 ; IN A,(0xFF) ; чтение сектора
JP READ_SECTOR
EMU_JUMP 0x3FEC ; INI ; чтение сектора
JP IN_INI
EMU_JUMP 0x3FF0 ; OUT (C),A
LD BC,(OLD_BC)
LD A,(OLD_AF+1)
LD D,A
JP WR_C_D
EMU_JUMP 0x3FF3 ; IN A,(C)
LD BC,(OLD_BC)
IN A,(C)
PUSH AF
POP HL
LD (OLD_AF),HL
RET
; стек и обработчики
DUPL STACK - $,0
DW INT_BREAK
DUPL STACK + 0x41 - $,0
INT_BREAK PUSH AF
PUSH HL
PUSH DE
LD A,(FLAG_RW_BREAK)
AND A
JR NZ,IB1
LD HL,(OLD_IF)
LD L,0xFF
LD E,(HL)
INC HL
LD D,(HL)
LD HL,(OLD_SP)
DEC HL
LD (HL),D
DEC HL
LD (HL),E
LD (OLD_SP),HL
POP DE
POP HL
POP AF
EI
RET
IB1 PUSH BC
LD (INT_SP),SP
CALL READ_TMP_CPU12
CALL WRITE_CPU12
LD A,(OLD_PORT_BF)
OUT (PEVO_CONF),A
LD A,(OLD_IF + 1)
LD I,A
LD HL,(OLD_AF)
PUSH HL
POP AF
LD HL,(OLD_SP)
LD DE,0x2A71 ; адрес возврата из обработчика прерывания внешней проги через OUT (0xFF),A
DEC HL
LD (HL),D
DEC HL
LD (HL),E
DEC HL
EX DE,HL
LD HL,OLD_IF + 1
LD H,(HL)
LD L,0xFF
LD C,(HL)
INC HL
LD B,(HL)
EX DE,HL
LD (HL),B
DEC HL
LD (HL),C
LD SP,HL
LD HL,(OLD_HL)
LD DE,(OLD_DE)
LD BC,(OLD_BC)
LD A,(WR_FF) ; байтик для возврата через команду OUT (0xFF),A
EI
JP 0x2A53
INT_RET LD SP,0
INT_SP EQU $-2
IN A,(PEVO_CONF)
LD (OLD_PORT_BF),A
OR 1
OUT (PEVO_CONF),A
LD A,HIGH (STACK)
LD I,A
CALL WRITE_TMP_CPU12
POP BC
POP DE
POP HL
POP AF
RET
; выход из обработчика
EXIT_PAGE_FE LD A,(OLD_PORT_BF)
OUT (PEVO_CONF),A ; восстановление порта 0xBF
LD A,(OLD_IF + 1)
LD I,A
LD HL,(OLD_AF)
PUSH HL
POP AF
LD HL,0 ; восстановление HL
OLD_HL EQU $-2
LD DE,0 ; восстановление DE
OLD_DE EQU $-2
LD BC,0 ; восстановление BC
OLD_BC EQU $-2
LD SP,0 ; восстановление SP
OLD_SP EQU $-2
JP 0
ADR_EXIT EQU $-2
DUPL STACK + 0x101 - $,0
; вход в обработчик
WORKER LD (NUM_ADR),A
LD (OLD_SP),SP
LD SP,STACK-WORD
PUSH AF
EX (SP),HL
LD A,L
LD (OLD_AF),A
POP HL
LD A,I
JP PE,WORKER1
LD A,I
WORKER1 PUSH AF ; IF
IN A,(PEVO_CONF)
LD (OLD_PORT_BF),A ; порт BF
OR 1
OUT (PEVO_CONF),A
LD A,HIGH (STACK)
LD I,A
LD (OLD_HL),HL
LD (OLD_DE),DE
LD (OLD_BC),BC
LD HL,0
NUM_ADR EQU $-2
ADD HL,HL
ADD HL,HL
LD DE,TABLE_VIRT
ADD HL,DE
LD E,(HL)
INC HL
LD D,(HL) ; DE-адрес возврата из обработчика
INC HL
LD (ADR_EXIT),DE
LD E,(HL)
INC HL
LD D,(HL) ; DE-адрес обработчика
PUSH DE
LD HL,EXIT_PAGE_FE ; код выхода из обработчика
EX (SP),HL
JP (HL)
; чтение/запись примонтированного диска
MOUNT_RW DI
LD A,(RDWR_MODE)
AND 0x80
LD L,A
LD A,(WR_FF)
AND 3
OR L
BIT 7,A
PUSH AF
LD HL,0x2A77
PUSH HL
LD HL,MNT_RW
PUSH HL
JR Z,.L1
; копируем сектор который будем записывать на смонтированный образ
LD HL,(OLD_HL)
LD DE,MNT_SECTOR
CALL COPY_BLOCK
LD (OLD_HL),HL
; переключаем паги для работы с маунтом
.L1 PUSH AF
LD BC,WIN_A1
LD A,0x40
OUT (C),A
LD B,HIGH (WIN_P1)
LD A,RAM_EVODOS
OUT (C),A
POP AF
; переставляем стек
LD HL,0x4000
ADD HL,SP
LD SP,HL
JP 0x2A53
PHASE $ + 0x4000
MNT_RW LD L,A
LD A,(PORT_3F + 0x4000) ; взяли номер трека
ADD A,A ; сторон 2
LD D,A
LD A,(WR_FF + 0x4000)
AND 0x10 ; проверка какая сторона диска
JR NZ,WRRDSECM1
INC D ; для стороны 1
WRRDSECM1 LD A,(PORT_5F + 0x4000) ; взяли номер сектора
LD E,A ; D-трек, E-сектор
LD A,L
LD HL,MNT_SECTOR + 0x4000
RST8 _MOUNTER,_RDWR_MOUNT
JP 0x3D2F
DEPHASE
RET_MNT_RW
LD HL,-0x4000
ADD HL,SP
LD SP,HL
CALL WRITE_CPU12
LD HL,(OLD_IF)
PUSH HL
POP AF
JP PO,.DI_MODE ; прерывания разрешены?
CP 0x3F
JR Z,.DI_MODE
EI
.DI_MODE POP AF
RET NZ
LD HL,MNT_SECTOR
LD DE,(OLD_HL)
CALL COPY_BLOCK
LD (OLD_HL),DE
RET
; инфа для создания 9 сектора нового диска
DSKINFO DB 0 ; + 0xE1 - номер первого свободного сектора
DB 1 ; + 0xE2 - номер первого свободного трека
DB 0x16 ; + 0xE3 - тип дискеты
DB 0 ; + 0xE4 - количество файлов на дискете
SECFREE DW 2544 ; + 0xE5 - количество свободных секторов
DB 0x10 ; + 0xE7 - идентификационный код TRDOS
DW 0 ; + 0xE8 - 2 байта 0
DUPL 9," " ; + 0xEA - 9 байт 0x20
DB 0 ; + 0xF3 - 1 байт 0
DB 0 ; + 0xF4 - количество удаленных файлов
DB "RAMDISKO" ; + 0xF5 - имя дискеты
DSK_END
DUPL LOW (-$),0
MNT_SECTOR
; адреса перехвата
JP_EMU 0x1E3A ; OUT (0x3F), A
JP_EMU 0x1FDD ; IN A, (0x1F)
JP_EMU 0x1FF3 ; OUT (0xFF), A
JP_EMU 0x2000 ; OUT (0x1F), A
JP_EMU 0x2076 ; IN A, (0x1F)
JP_EMU 0x2085 ; OUT (0x3F), A
JP_EMU 0x208D ; OUT (0x5F), A
JP_EMU 0x2093 ; OUT (0x1F), A
JP_EMU 0x2099 ; IN A, (0x1F)
JP_EMU 0x20B1 ; IN A, (0xFF)
JP_EMU 0x20B8 ; OUT (C), D
JP_EMU 0x2740 ; IN A, (0x1F)
JP_EMU 0x2748 ; OUT (0x7F), A
JP_EMU 0x2A53 ; OUT (C), A
; первая команда в обработчике MAGIC для возврата в пагу FE
; JP_EMU 0x2A71 ; OUT (0xFF), A
DUPL 0x2A71 - $,0
OUT (EXIT_PORT),A
JP INT_RET ; возвращение из обработчика INT
; JP_EMU 0x2A77 ; IN A, (0x1F)
DUPL 0x2A77 - $,0
OUT (EXIT_PORT),A
JP RET_MNT_RW ; возвращение после вызова RST 8
JP_EMU 0x2AD9 ; OUT (0xFF), A
JP_EMU 0x2B25 ; IN A, (0x5F)
JP_EMU 0x2C07 ; IN A, (0x5F)
JP_EMU 0x2CD8 ; IN A, (0x5F)
JP_EMU 0x2D75 ; OUT (0x5F), A
JP_EMU 0x2D80 ; OUT (0x1F), A
JP_EMU 0x2D87 ; IN A, (0x1F)
JP_EMU 0x2F0C ; OUT (0xFF), A
JP_EMU 0x2F1D ; OUT (0x5F), A
DUPL 0x2F24 - $,0 ; для адреса 0x2F4D
JP ADR_0x2F4D
JP_EMU 0x2F28 ; OUT (0x1F), A
JP_EMU 0x2F2F ; IN A, (0x1F)
JP_EMU 0x2F3C ; OUT (0xFF), A
DUPL 0x2F4D - $,0 ; OUT (0xFF), A
OUT (EXIT_PORT),A
DB 0x18 ; JR 0x2F24
JP_EMU 0x2F50 ; OUT (0x7F), A
DUPL 0x2F57 - $,0 ; OUT (0x1F), A
OUT (EXIT_PORT),A
JR JUMP_0x2F57
JR JUMP_0x2F59 ; IN A, (0xFF)
EXIT_0x2F59 OUT (EXIT_PORT),A
JUMP_0x2F59 JP ADR_0x2F59
JUMP_0x2F57 JP ADR_0x2F57
JP_EMU 0x2FB1 ; OUT (0xFF), A
JP_EMU 0x2FC3 ; OUT (0x1F), A
DUPL 0x32A2 - $,0
; обработчики чтения/записи портов
; запись "A" в порт 0x1F
OUT_1F LD A,(OLD_AF + 1)
LD (WR_1F),A
AND %11110000
RRCA
RRCA
RRCA
ADD A,LOW (.TABL_CMD)
LD L,A
ADC A,HIGH (.TABL_CMD)
SUB L
LD H,A
LD A,(HL)
INC HL
LD H,(HL)
LD L,A
JP (HL)
.TABL_CMD DW .CMD_00
DW .CMD_10
DW .CMD_20
DW .CMD_30
DW .CMD_40
DW .CMD_50
DW .CMD_60
DW .CMD_70
DW .CMD_80
DW .CMD_90
DW .CMD_A0
DW .CMD_B0
DW .CMD_C0
DW .CMD_D0
DW .CMD_E0
DW .CMD_F0
; 00-0F команда восстановления
.CMD_00 XOR A
LD (PORT_3F),A
JR .INFF_BIT6
; 10-1F команда поиска
.CMD_10 LD A,(PORT_7F)
LD (PORT_3F),A
CALL DISK_NONE
LD A,0x80
JR C,.INFF_BIT6_1
.INFF_BIT6 XOR A
.INFF_BIT6_1 LD (RD_1F),A
LD A,0xBF
LD (RD_FF),A
RET
; 20-3F команда шаг в предыдущем направлении
.CMD_20
.CMD_30 LD A,(PORT_3F)
.NAPRAVL INC A
LD (PORT_3F),A
JR .INFF_BIT6
; 40-5F команда шаг вперед
.CMD_40
.CMD_50 LD A,(PORT_3F)
INC A
LD (PORT_3F),A
LD A,0x3C ; INC A
LD (.NAPRAVL),A
JR .INFF_BIT6
; 60-7F команда шаг назад
.CMD_60
.CMD_70 LD A,(PORT_3F)
DEC A
LD (PORT_3F),A
LD A,0x3D ; DEC A
LD (.NAPRAVL),A
; 80-9F команда чтение сектора
.CMD_80
.CMD_90
; A0-BF команда запись сектора
.CMD_A0
.CMD_B0
; C0-CF чтение адреса
.CMD_C0 JR .INFF_BIT6
; D0-DF принудительное прерывание
.CMD_D0 LD A,0xBF
LD (RD_FF),A
RET
; E0-EF чтение дорожки
.CMD_E0
.CMD_F0 JR .INFF_BIT6
; запись "A" в порт 0x3F
OUT_3F LD A,(OLD_AF + 1)
LD (PORT_3F),A
RET
; запись "A" в порт 0x5F
OUT_5F LD A,(OLD_AF + 1)
LD (PORT_5F),A
RET
; запись "A" в порт 0x7F
OUT_7F LD A,(OLD_AF + 1)
LD (PORT_7F),A
RET
; запись "A" в порт 0xFF
OUT_FF LD A,(OLD_AF + 1)
LD (WR_FF),A
LD D,A
LD BC,0x00FF
JR WR_C_D
; запись "A" в порт (C)
OUT_C_A LD A,(OLD_AF + 1)
WRCA1 LD D,A
LD BC,(OLD_BC) ; если порт не TR-DOS
LD A,C
; определение в какой порт запись
CP 0x1F
JP Z,OUT_1F
CP 0x3F
JR Z,OUT_3F
CP 0x5F
JR Z,OUT_5F
CP 0x7F
JR Z,OUT_7F
CP 0xFF
JR Z,OUT_FF
CP LOW (WIN_A0)
JR Z,WRCA3
WR_C_D PUSH BC
LD BC,FDD_EMU_PORT
IN E,(C)
XOR A
OUT (C),A
POP BC
OUT (C),D
LD BC,FDD_EMU_PORT
OUT (C),E
RET
; запись в порты ATM/PENTEVO
WRCA3 LD A,B
LD HL,BB_CPU1
CP HIGH (WIN_A1)
JR Z,WRCA2
CP HIGH (WIN_P2)
JR Z,WRCA2
LD HL,BB_CPU2
CP HIGH (WIN_A2)
JR Z,WRCA2
CP HIGH (WIN_P2)
JR NZ,WR_C_D
WRCA2 LD E,B
PUSH DE
PUSH HL
CALL READ_CPU12
POP HL
POP DE
LD (HL),D
INC HL
LD (HL),E
JP WRITE_CPU12
; запись "D" в порт (C)
OUT_C_D LD A,(OLD_DE + 1)
JR WRCA1
; передача байта, команда OUTI
OUT_OUTI LD HL,(BUFF_SECT)
EXX
LD A,(HL)
INC HL
EXX
LD (HL),A
INC HL
LD (BUFF_SECT),HL
RET
; чтение порта 0x1F
IN_1F LD A,(WR_1F)
AND %11110000
CP 0x10
JR C,.L1
CP 0x20
JR C,.L3
CP 0x80
JR C,.L5
CP 0xD0
JR Z,.L7
XOR A
JR .L2
.L7 LD A,0x80
JR .L2
.L5 LD A,(PORT_3F)
AND A
JR NZ,.L1
LD A,%00100100
JR .L6
.L3 LD A,(.INDEX)
XOR %00000100
JR .L4
.L1 LD A,%00100100
.INDEX EQU $-1
.L4 XOR %00000010
.L6 LD (.INDEX),A
.L2 LD (RD_1F),A
LD (OLD_AF + 1),A
RET
; чтение порта 0x3F
IN_3F LD A,(PORT_3F)
LD (OLD_AF + 1),A
RET
; чтение порта 0x5F
IN_5F LD A,(PORT_5F)
LD (OLD_AF + 1),A
RET
; чтение порта 0x7F
IN_7F LD A,(PORT_7F)
LD (OLD_AF + 1),A
RET
; чтение порта 0xFF
IN_FF LD A,(RD_FF)
LD (OLD_AF + 1),A
RET
; чтение в "H" из (С)
IN_H_C LD A,(OLD_BC)
; определение из какого порта чтение
CP 0x1F
JR NZ,.L2
LD A,(RD_1F)
LD (OLD_HL + 1),A
RET
.L2 CP 0x3F
JR NZ,.L3
LD A,(PORT_3F)
LD (OLD_HL + 1),A
RET
.L3 CP 0x5F
JR NZ,.L4
LD A,(PORT_5F)
LD (OLD_HL + 1),A
RET
.L4 CP 0x7F
JR NZ,.L5
LD A,(PORT_7F)
LD (OLD_HL+1),A
RET
.L5 CP 0xFF
JR NZ,.L6
LD A,(RD_FF)
LD (OLD_HL + 1),A
RET
.L6 LD BC,(OLD_BC)
IN A,(C)
LD (OLD_HL + 1),A
RET
; чтение INI
IN_INI LD HL,(OLD_HL)
LD A,H
CP 0x40
JR C,.L1
DEC HL
LD A,(RD_1F)
LD (HL),A
; временно, для анрыла
; LD A,0xD3
; LD (0x3FD7),A
; временно, для анрыла
.L1 LD HL,0x2A53
LD (ADR_EXIT),HL
JP OUT_1F.INFF_BIT6
WAIT_READ LD A,(WR_1F)
AND 0xF0
CP 0x80
JP C,OUT_1F.INFF_BIT6
CP 0xC0
JR NC,READ_SECTOR.L1
CALL READ_CPU12 ; сохранение текущей конфигурации окон проецирования 1,2
CALL FIND_SECTOR ; проверяем наличие сектора
PUSH AF
CALL WRITE_CPU12 ; восстановление конфигурации окон проецирования 1,2
POP AF
JR NC,READ_SECTOR_1
; сектора нет, не дождетесь
LD A,0x3C
JP OUT_1F.INFF_BIT6_1
; чтение сектора или портов
READ_SECTOR LD A,(WR_1F)
AND 0xF0
CP 0x80
JP C,OUT_1F.INFF_BIT6
CP 0xC0
JR C,READ_SECTOR_1
.L1 CALL READ_CPU12 ; чтение текущей конфы
LD BC,WIN_A1
LD A,0x40
OUT (C),A
LD B,HIGH (WIN_P1)
LD A,RAM_RAMDISK
OUT (C),A ; страница заголовков рамдиска
LD A,(PORT_3F) ; взяли номер трека
ADD A,A ; сторон 2
LD C,A
LD A,(WR_FF)
AND 0x10 ; проверка какая сторона диска
JR NZ,.L2
INC C ; для стороны 1
.L2 LD B,HIGH (CPU1) + 2 ; адрес начала инфы о секторах на дорожке
LD A,0 ; текущий номер сектора
.CURR_SEC EQU $-1
INC A
AND %00001111
LD (.CURR_SEC),A
ADD A,A
ADD A,HIGH (CPU1) + 2
LD B,A
LD A,(PORT_3F) ; номер дорожки
LD C,A
LD A,(BC) ; проичтали номер сектора
PUSH AF
CALL WRITE_CPU12 ; восстановление конфы
LD A,(PORT_3F)
LD HL,(OLD_HL)
LD (HL),A ; номер дорожки
INC HL
LD (HL),0 ; номер стороны
INC HL
POP AF
LD (HL),A ; номер сектора
INC HL
LD (HL),0 ; размер сектора
INC HL
LD (HL),0 ; байт CRC
INC HL
LD (HL),0 ; байт CRC
INC HL
LD (OLD_HL),HL
LD HL,OLD_BC + 1
LD A,(HL)
SUB 6 ; REG B - 6
LD (HL),A
LD HL,0x2A53
LD (ADR_EXIT),HL
JP OUT_1F.INFF_BIT6
; чтение сектора
READ_SECTOR_1 XOR A
JR WRITE_SECTOR_1
; запись сектора
WRITE_SECTOR LD A,0xFF
WRITE_SECTOR_1 LD (RDWR_MODE),A
LD A,1
LD (FLAG_RW_BREAK),A
LD HL,(OLD_IF)
PUSH HL
POP AF
JP PO,.DI_MODE ; прерывания разрешены?
CP 0x3F
JR Z,.DI_MODE
HALT ; разрешены, ждем обработчик прерывания
.DI_MODE CALL READ_CPU12 ; сохранение текущей конфигурации окон проецирования 1,2
CALL W_WR_RD_SECT
XOR A
LD (FLAG_RW_BREAK),A
LD HL,0x8090
LD (OLD_AF),HL ; эмуляция флага успешного чтения/записи сектора
LD HL,0x2A53
LD (ADR_EXIT),HL
JP WRITE_CPU12 ; восстановление конфигурации окон проецирования 1,2
; поиск сектора в таблице
FIND_SECTOR LD BC,WIN_A1
LD A,0x40
OUT (C),A
LD B,HIGH (WIN_P1)
LD A,RAM_RAMDISK
OUT (C),A ; страница заголовков рамдиска
LD A,(PORT_3F) ; взяли номер трека
ADD A,A ; сторон 2
LD C,A
LD A,(WR_FF)
AND 0x10 ; проверка какая сторона диска
JR NZ,.L2
INC C ; для стороны 1
.L2 LD B,HIGH (CPU1) + 2 ; адрес начала инфы о секторах на дорожке
LD HL,(PORT_5F) ; взяли номер сектора
LD H,0
.L1 LD A,(BC)
LD D,A ; взяли номер сектора
INC B
LD A,(BC)
LD E,A ; взяли размер сектора
INC B
LD A,D
AND A
SCF
RET Z ; ошибка, сектор не найден
LD A,L
CP D
RET Z ; сектор найден
LD A,E
ADD A,H
LD H,A
JR .L1
; чтение или запись сектора рамдиска
W_WR_RD_SECT LD A,(WR_FF)
AND 3
INC A
LD B,A
LD A,%10000000
.L1 RLCA
DJNZ .L1
LD B,A
LD A,(COPY_VIRT_BITS)
AND B
JP NZ,MOUNT_RW ; работа с примонтированным образом
CALL FIND_SECTOR
JR NC,.L2
; сектор не найден, на выход
LD A,0x10
JP IN_1F.L2
; сектор найден, читаем/пишем
.L2 LD A,E
RRCA
LD (SECTOR_SIZE),A ; размер найденного сектора
LD L,0
LD E,L
SRL H
RR L ; HL = смещение в блоках до найденного сектора
LD B,HIGH (CPU1)
LD A,(BC)
LD D,A
ADD HL,DE ; HL = смещение от начала страницы в блоках
INC B
LD A,(BC)
LD C,A ; смещение в страницах от начала рамдиска
LD A,H
CP HIGH (CPU1)
JR C,.L5
SUB 0x40
LD H,A
INC C
; HL = смещение в странице до начала сектора
.L5 LD A,C ; смещение до номера страницы, где указанный сектор начинается
ADD A,RAM_DATARAMD ; прибавили номер начала рамдиск и +1. в 0 странице рамдиска описатели секторов
LD (RDWR_PAGE),A ; сохранили номер вычисленной страницы
LD DE,(OLD_HL)
LD BC,(BB_CPU1)
LD A,C
LD C,LOW (WIN_A0)
OUT (C),A ; вернули стандартную 5 страницу
.S9 LD A,D ; проверка границы откуда/куда копировать
CP HIGH (CPU2)
PUSH DE
LD DE,CPU1 + HIGH (WIN_P1)
LD BC,WIN_A1 ; если верхние 32кб озу, то нужно включить в 1 окне проецирования
JR NC,.S1
LD DE,CPU2 + HIGH (WIN_P2)
LD B,HIGH (WIN_A2) ; если нижние 32кб озу, то нужно включить во 2 окне проецирования
.S1 LD A,0x40
OUT (C),A
LD B,E
LD A,(RDWR_PAGE) ; номер вычисленной страницы озу
OUT (C),A ; включили вычисленную страницу
LD B,D ; старший байт адреса начала включенной страницы
POP DE
LD A,B
ADD A,H
LD H,A
LD A,(RDWR_MODE)
AND A
JR NZ,.I1
LD A,D
INC A
JR NZ,.I1
LD A,E
AND A
JR Z,.I1
NEG
LD C,A
LD B,0
LDIR
NEG
LD C,A
.I2 EX DE,HL
ADD HL,BC
EX DE,HL
ADD HL,BC
LD A,(SECTOR_SIZE)
JP .S8_
.I1 LD A,D
CP HIGH (CPU1)
JR NC,.I3
LD A,(SECTOR_SIZE)
AND A
LD BC,0x80
JR Z,.I2
LD BC,0x100
JR .I2
.I3 CP HIGH (CPU2) ; проверка перехода границы страниц
JP NC,.S3 ; если выше то сразу копируем
CP HIGH (CPU2) - 1
JP C,.S3 ; если ниже так же сразу копируем
LD A,E
AND A ; если сектор полностью укладывется до границы, то сразу копируем
JR Z,.S3 ; иначе принудительно копируем в два приема
LD A,(RDWR_MODE) ; чтение или запись?
AND A
LD A,E ; младший байт адрес в блоке
JR Z,.S4
EX DE,HL ; для записи меняем направление
.S4 NEG
LD C,A ; копируем остаток до конца блока
LD B,0
LDIR
NEG
PUSH AF ; спрятали сколько осталось копировать из начала следующего блока
LD BC,(BB_CPU2)
LD A,C
LD C,LOW (WIN_A0)
OUT (C),A
LD B,HIGH (WIN_A1)
LD A,0x40
OUT (C),A
LD B,HIGH (WIN_P1)
LD A,(RDWR_PAGE)
OUT (C),A ; вычисленную страницу включаем в 1 окне проецирования
LD A,(RDWR_MODE) ; чтение или запись
AND A
JR Z,.S5
LD A,D ; для записи
SUB 0x40 ; изменили адрес куда копировать на другое окно проецирования
LD D,A
JR .S6
.S5 LD A,H ; для чтения
SUB 0x40 ; изменили адрес куда копировать на другое окно проецирования
LD H,A
.S6 POP AF
LD C,A ; сколько осталось скопировать байт
LD B,0
LDIR
LD A,(SECTOR_SIZE)
JR .S8_
.S3 LD A,(RDWR_MODE) ; чтение или запись
AND A
JR Z,.S7
EX DE,HL ; для записи меняем направление
.S7 LD A,(SECTOR_SIZE)
AND A
JR NZ,.S8
CALL COPYHBLOCK ; для сектора размером 128 байт копируем половину и выходим
.ECOPY_BLOCK LD A,(RDWR_MODE)
AND A
JR Z,.ECOPY_BLOCK1
EX DE,HL
.ECOPY_BLOCK1 LD (OLD_HL),DE
RET
.S8 CALL COPY_BLOCK ; для сектора 256 байт копируем весь и выходим
.S8_ DEC A
JR Z,.ECOPY_BLOCK
LD (SECTOR_SIZE),A
LD A,(RDWR_MODE)
AND A
JR Z,.S0
EX DE,HL
.S0 LD A,0x3F
AND H
LD H,A
JP .S9
COPY_BLOCK
REPT 128
LDI
ENDM
COPYHBLOCK
REPT 128
LDI
ENDM
RET
; проверка наличия маркера рамдиска
CMP_RAM_DISK CALL READ_CPU12
LD BC,WIN_P1
LD A,RAM_RAMDISK
OUT (C),A
LD HL,CPU1 + 0x3FFF
LD D,(HL)
DEC H
LD E,(HL) ; взяли байты для проверки маркера
CALL WRITE_CPU12
LD HL,"RD"
AND A
SBC HL,DE
RET Z ; если маркер на месте, то рамдиска не создаем
; создание чистого рамдиска
CREATE_TRDTABL LD BC,WIN_P1
LD A,RAM_RAMDISK ; нужна страница начала рамдиска, где будет таблица описателей
OUT (C),A
LD HL,CPU1
PUSH HL
LD DE,CPU1 + 1
LD BC,0x3FFF
LD (HL),L
LDIR ; очистили страницу
POP DE ; адрес начала страницы
LD HL,0 ; смещение в блоках и страницах
LD A,0xA0
ELT2 PUSH AF
LD BC,0x1000 ; счетчик номеров секторов и их номера
LD A,L
RRCA
RRCA
LD (DE),A ; смещение в блоках дорожки в странице
INC D
LD A,H
LD (DE),A ; смещение в страницах до дорожки
INC D
ELT1 INC C
LD A,C
LD (DE),A ; номер сектора
INC D
LD A,2
LD (DE),A ; размер сектора
INC D
DJNZ ELT1 ; вносим в таблицу все номера секторов с размерами
LD D,HIGH (CPU1) ; вернули указатель в начало
INC E ; для следующей дорожки
LD BC,0x40
ADD HL,BC ; переход к следующей дорожке
POP AF
DEC A
JR NZ,ELT2 ; повторяем для всех дорожек
LD HL,CPU1 + 0x3FFF
LD (HL),"R" ; вносим маркер рамдиска
DEC H
LD (HL),"D"
LD BC,WIN_P1
LD A,RAM_DATARAMD
OUT (C),A
LD HL,CPU1
LD DE,CPU1 + 1
LD BC,0x0FFF
LD (HL),L
LDIR
LD HL,DSKINFO
LD DE,CPU1 + 0x08E1
LD BC,DSK_END - DSKINFO
LDIR
; восстановление конфигурации окон проецирования 1,2
WRITE_CPU12 LD BC,(BB_CPU1)
LD A,C
LD C,LOW (WIN_A0)
OUT (C),A
LD BC,(BB_CPU2)
LD A,C
LD C,LOW (WIN_A0)
OUT (C),A
RET
; чтение текущего конфига страниц проецирования 1,2
READ_TMP_CPU12 LD HL,(BB_CPU1)
PUSH HL
LD HL,(BB_CPU2)
PUSH HL
CALL READ_CPU12
LD HL,(BB_CPU1)
LD (TMP_BB_CPU1),HL
LD HL,(BB_CPU2)
LD (TMP_BB_CPU2),HL
POP HL
LD (BB_CPU2),HL
POP HL
LD (BB_CPU1),HL
JR WRITE_CPU12
; восстановление текущей конфигурации страниц проецирования 1,2
WRITE_TMP_CPU12 LD BC,0
TMP_BB_CPU1 EQU $-2
LD A,C
LD C,LOW (WIN_A0)
OUT (C),A
LD BC,0
TMP_BB_CPU2 EQU $-2
LD A,C
LD C,LOW (WIN_A0)
OUT (C),A
RET
; чтение конфигурации окон проецирования 1,2
READ_CPU12 LD BC,RD_RAMNROM
IN L,(C) ; биты RAM & ROM
INC B
IN H,(C) ; биты DOS & 7FFD
ADD HL,HL
LD B,HIGH (RD_1WINA1)
IN A,(C)
CP 0xC0
JR NC,.L1
LD E,A
LD D,HIGH (WIN_P1)
JR .L2
.L1 RLCA
RLCA
SLA L
RRA
SLA H
RRA
LD E,A
LD D,HIGH (WIN_A1)
.L2 LD (BB_CPU1),DE
INC B
IN A,(C)
CP 0xC0
JR NC,.L3
LD E,A
LD D,HIGH (WIN_P2)
JR .L4
.L3 RLCA
RLCA
SLA L
RRA
SLA H
RRA
LD E,A
LD D,HIGH (WIN_A2)
.L4 LD (BB_CPU2),DE
RET
; проверка наличия виртуального диска
DISK_NONE PUSH HL
PUSH BC
CALL READ_CPU12
LD BC,WIN_A1
LD A,0x40
OUT (C),A
LD B,HIGH (WIN_P1)
LD A,RAM_RAMDISK
OUT (C),A
LD HL,CPU1 + 0x3FFF
LD A,(HL)
DEC H
CP "R"
SCF
JR NZ,DISK_NONE1
LD A,(HL)
CP "D"
SCF
JR NZ,DISK_NONE1
XOR A
DISK_NONE1 PUSH AF
CALL WRITE_CPU12
POP AF
POP BC
POP HL
RET
; на входе: H-адрес ячейки
; L-прочитанное значение
READCMOS PUSH BC
LD BC,CMOSD_SET_ADR
OUT (C),H
LD B,HIGH (CMOSD_RD_WR)
IN L,(C)
POP BC
LD A,L
AND A
RET
JP_EMU 0x3C30 ; IN A, (0x1F)
DUPL 0x3D2F - $,0
NOP
RET
JP_EMU 0x3D4D ; OUT (0xFF), A
JP_EMU 0x3D9A ; OUT (0x1F), A
JP_EMU 0x3DA6 ; IN A, (0xFF)
JP_EMU 0x3DB5 ; IN A, (0x1F)
JP_EMU 0x3DBA ; IN A, (0x1F)
JP_EMU 0x3DD5 ; OUT (0xFF), A
JP_EMU 0x3E30 ; IN A, (0x1F)
JP_EMU 0x3E3A ; IN A, (0x1F)
JP_EMU 0x3E44 ; OUT (0x7F), A
DUPL 0x3E49 - $,0
JP ADR_0x3E4C ; для адреса 0x3E4C
; JP_EMU 0x3E4C ; OUT (0x7F), A
DUPL 0x3E4C - $,0
OUT (EXIT_PORT),A
JR 0x3E49
JP_EMU 0x3E50 ; IN A, (0x3F)
JP_EMU 0x3E78 ; IN A, (0x3F)
JP_EMU 0x3E7E ; OUT (0x3F), A
JP_EMU 0x3E87 ; IN A, (0x3F)
JP_EMU 0x3E95 ; OUT (0x3F), A
JP_EMU 0x3EB5 ; IN A, (0x1F)
JP_EMU 0x3EBC ; IN A, (0x3F)
JP_EMU 0x3EC9 ; OUT (0x1F), A
JP_EMU 0x3ECE ; IN A, (0xFF)
JP_EMU 0x3EDF ; OUT (0x1F), A
DUPL 0x3EF3 - $,0 ; IN H, (C)
OUT (EXIT_PORT),A
JR JUMP_0x3EF3
JR JUMP_0x3EF5 ; IN A, (0xFF)
EXIT_0x3EF5 OUT (EXIT_PORT),A
JUMP_0x3EF5 JP ADR_0x3EF5
; JP_EMU 0x3EF5 ; IN A, (0xFF)
JP_EMU 0x3EFE ; IN A, (0x7F)
JUMP_0x3EF3 JP ADR_0x3EF3
JP_EMU 0x3F1B ; OUT (0x5F), A
JP_EMU 0x3F25 ; OUT (0x1F), A
JP_EMU 0x3F33 ; IN A, (0x1F)
DUPL 0x3F40 - $,0 ; для адреса 0x3EF3
JP ADR_0x3EF3
JP_EMU 0x3F4D ; OUT (0x1F), A
JP_EMU 0x3F55 ; IN A, (0x3F)
JP_EMU 0x3F5A ; IN A, (0x5F)
JP_EMU 0x3F69 ; IN A, (0x3F)
JP_EMU 0x3F72 ; IN A, (0x5F)
JP_EMU 0x3FBC ; IN A, (0xFF) ;запись сектора
DUPL 0x3FC7 - $,0
JUMP_0x3FF0 JP ADR_0x3FF0
JP_EMU 0x3FCA ; IN A, (0xFF) ;запись сектора
JP_EMU 0x3FD1 ; OUTI ;запись сектора
JP_EMU 0x3FD7 ; IN A, (0xFF) ;чтение сектора
JUMP_0x3FEC JP ADR_0x3FEC
JUMP_0x3FF3 JP ADR_0x3FF3
JP_EMU 0x3FE5 ; IN A, (0xFF) ;чтение сектора
; JP_EMU 0x3FEC ; INI ;чтение сектора
DUPL 0x3FEC - $,0
OUT (EXIT_PORT),A
JR JUMP_0x3FEC
; DUPL 0x3FF0 - $,0 ; OUT (C), A
OUT (EXIT_PORT),A
DB 0x18 ; JR 0x3FC7
; DUPL 0x3FF5 - $,0 ; IN A, (C)
OUT (EXIT_PORT),A
JP JUMP_0x3FF3
DUPL 0x3FF8 - $,0
DB "EVOSFE"
DW DATA_VERS