; LAST UPDATE: 10.02.2024 savelij
include macros.a80
include define.a80
include global_vars.a80
include ports_ngs.a80
include sdcomand.a80
include ports_ide.a80
include nums_devices.a80
include fat_dir.a80
INIT_VAR DRV_VAR
SETVAR BUF_512_, 0x200 ; буфер сектора
include ../../fat_vars.a80
SETVAR_ALIGN
SUBVAR (WORD + WORD + BYTE + BYTE)
SETVAR LENGHT, WORD ; длина файла в байтах
SETVAR LOADSCS1, WORD ; адрес вызываемого драйвера
SETVAR MAS_SLA, BYTE ; маска для MASTER/SLAVE
SETVAR NUM_DEVICE, BYTE ; номер устройства для запуска кода
ORG INITVAR
; на входе: A - номер выбранного устройства
; BCDE - номер кластера запускаемого файла
DI
LD A,(NUM_DEVICE)
CP _SD_SDZ
LD HL,READ_ZSD ; драйвер SD ZC карты
JR Z,SETLOADER
CP _SD_SDG
LD HL,READ_NEOGS ; драйвер SD NGS карты
JR Z,SETLOADER
CP _HDD_NEMO_MASTER
LD HL,RD_HDD_NEMO ; драйвер HDD NEMO
IFDEF ALL_DRVS
JR Z,SETLOADER
CP _HDD_SMUC_MASTER
LD HL,RD_HDD_SMUC ; драйвер HDD SMUC
JR Z,SETLOADER
CP _HDD_DIVIDE_MASTER
LD HL,RD_HDD_DIVIDE ; драйвер HDD DIVIDE
JR Z,SETLOADER
LD HL,RD_HDD_PROFI ; драйвер HDD PROFI
ENDIF
SETLOADER LD (LOADSCS1),HL ; установили адрес читалки секторов
LD A,(MAS_SLA)
AND A
LD A,0xE0
JR Z,SETMASL
LD A,0xF0
SETMASL LD (MAS_SLA),A
LD BC,(FILE_SRC + _DIR_FstClusHI)
LD (AFILCLS+2),BC
LD DE,(FILE_SRC + _DIR_FstClusLO)
LD (AFILCLS),DE
LD A,(FILE_SRC + _DIR_Ext + 1)
CP "P"
JP Z,RUNSPG2 ; переход на запуск SPG файла
CP "N"
JP Z,RUNSNA ; переход на запуск SNA файла
CALL REALSEC ; преобразовали в номер сектора
CALL LOADLST ; загрузили в буфер
EXX
LD HL,(BUF_512_ + _DIR_Ext + 1)
LD (0x5D45),HL ; адрес старта кода
LD HL,(BUF_512_ + _DIR_Attr)
LD (LENGHT),HL ; установка длины файла в байтах
LD DE,0x11
ADD HL,DE ; пропуск HOBETA заголовка
LD A,L
AND A
JR Z,READ01 ; если младший байт не 0
INC H ; старший +1
READ01 LD A,H
SRL A ; делим на 2 ибо на FAT сектор 512 байт
ADC A,0 ; учитываем чет/нечет
DEC A ; первый сектор загружен, грузить на 1 меньше
EXX
JP Z,LDIRBUF ; если сектор 1 перенос и запуск
DEC A
LD IXL,A ; запомнили количество секторов - 1
JP Z,READ08 ; если файл влез в 2 сектора
EXX
CALL LD_ONES ; перенос остатков первого сектора
PUSH DE ; адрес куда далее грузить
EXX
LD HL,1 ; один сектор уже загружен
ADD HL,DE ; далее грузить со следующего сектора
EX DE,HL
JR NC,READ04
INC BC ; BCDE = BCDE + 1
READ04 POP HL ; в HL адрес для продолжения загрузки
LD IY,(SecPerClus) ; LY = количество секторов в кластере
LD A,IXL
CP IYL ; секторов осталось меньше чем в кластере
JR C,READ02 ; переход на дозагрузку остатка секторов
INC IXL
LD A,IYL
CP 2
JR C,READ07
DEC A
JR READ05
READ07 PUSH HL
LD DE,(AFILCLS)
LD BC,(AFILCLS + 2)
CALL RD_NEXT_CLUSTER ; получить номер следующего кластера
LD (AFILCLS),DE
LD (AFILCLS + 2),BC
CALL CHECK_LAST_CLUSTER ; проверка на окончание FAT цепочки
POP HL
JR C,RUNLOAD ; если кластера закончились, то запуск загруженного
PUSH HL
CALL REALSEC ; преобразование номера кластера в номер сектора
POP HL
LD A,IXL ; сколько секторов осталось загрузить
CP IYL ; сравниваем с размером кластера
JR C,READ02 ; если осталось загрузить секторов меньше чем в кластере, то дозагружаем остаток
LD A,IYL ; сколько секторов загружать
READ05 CALL LOADSCS ; загрузка секторов
LD A,IXL ; сколько секторов всего загружать
SUB IYL ; минус сколько секторов только что загрузили
JR Z,RUNLOAD ; сектора кончились, переходим на запуск
LD IXL,A ; сколько секторов осталось загрузить
JR READ07 ; продолжаем загрузку
; размер кода в Hobeta менее 2 секторов
; копируем хвост первого сектора и догружаем из второго с переносом
READ08 EXX
CALL LD_ONES
PUSH DE
EXX
POP HL
LD IXL,1
JR READ03
; загрузка количества секторов, если осталось менее размера кластера
READ02 AND A
JR Z,READ03
CALL LOADSCS
READ03 PUSH HL
LD A,IXL
LD L,A
LD H,0
ADD HL,DE
EX DE,HL
JR NC,READ06
INC BC
READ06 CALL LOADLST
LD BC,(LENGHT)
EX DE,HL
LD HL,0x11
ADD HL,BC
LD B,H
LD C,L
EX DE,HL
POP DE
LD A,B
AND 1
LD B,A
OR C
JR Z,RUNLOAD
LDIR
; запуск загруженного
RUNLOAD LD HL,0x2758
EXX
LD IY,0x5C3A
EI
JP 0x1B7D ; запуск перенесенной бейсик проги
LDIRBUF LD HL,0x200 - 0x11
LD DE,(BUF_512_ + 0x0B)
AND A
SBC HL,DE
JR NC,LDIRBUF1
CALL LD_ONES
JP RUNLOAD
LDIRBUF1 LD HL,BUF_512_ + 0x11
LD DE,(BUF_512_ + 9)
LD BC,(BUF_512_ + 0x0B)
LDIR
JP RUNLOAD
; перенос куска из уже загруженного сектора, если файл = 501 байт и менее
LD_ONES LD HL,BUF_512_ + 0x11
LD DE,(BUF_512_ + 9)
LD BC,0x200-0x11
LDIR
RET
; загрузить сектора с выбранного устройства
LOADSCS PUSH HL
LD HL,(LOADSCS1)
EX (SP),HL
RET
; чтение файла
; BCDE - номер кластера откуда грузить
; IXL - размер кластера
; IXH - временные переменные
; IYL - количество секторов для загрузки
; IYH - смещение в кластере
LOAD_FILE PUSH BC ; старшие 16 бит номера кластера
PUSH DE ; младшие 16 бит номера кластера
PUSH HL ; сохранили адрес загрузки
CALL REALSEC ; перевели номер кластера в номер сектора
LD IX,(SecPerClus)
LD A,IYH ; смещение в кластере
LD L,A
LD H,0
ADD HL,DE
EX DE,HL
JR NC,.L1
INC BC ; BCDE = номер сектора откуда грузить
.L1 LD A,IYL ; количество секторов для загрузки
CP IXL ; размер кластера
JP C,.L2
LD A,IXL ; размер кластера
.L2 ADD A,IYH ; смещение в кластере
CP IXL ; размер кластера
LD A,IYL ; количество секторов для загрузки
JP C,.L5
LD A,IXL ; размер кластера
SUB IYH ; смещение в кластере
.L5 LD IXH,A ; TEMP VAR, сколько секторов сейчас грузим
POP HL ; восстановили адрес загрузки
CALL LOADSCS ; загрузили сектора
POP DE
POP BC ; восстановили номер кластера
LD A,IYH ; смещение в кластере
ADD A,IXH ; TEMP VAR
CP IXL ; размер кластера
JP C,.L3
SUB IXL ; размер кластера
.L3 LD IYH,A ; смещение в кластере
JP C,.L4
PUSH HL ; сохранили адрес загрузки
CALL RD_NEXT_CLUSTER ; прочитали номер следующего кластера
CALL CHECK_LAST_CLUSTER ; проверили, а может это последний кластер?
POP HL ; восстановили адрес загрузки
RET C ; если последний, выходим
.L4 LD A,IYL ; количество секторов для загрузки
SUB IXH ; TEMP VAR
RET Z
LD IYL,A ; количество секторов для загрузки
JP NZ,LOAD_FILE
RET
; проверка номера кластера
CHECK_LAST_CLUSTER
LD A,(FATType)
AND A
JR NZ,.L1
LD HL,0x0FF7
SBC HL,DE
RET
.L1 DEC A
JR NZ,.L2
LD HL,0xFFF7
SBC HL,DE
RET
.L2 LD HL,0x0FFF
SBC HL,BC
RET NZ
LD HL,0xFFF7
SBC HL,DE
RET
; чтение следующего кластера
RD_NEXT_CLUSTER LD A,(FATType)
AND A
JR Z,.L1
DEC A
JR Z,.L2
EX DE,HL
ADD HL,HL
EX DE,HL
LD HL,0
ADC HL,BC
ADD HL,BC ; HLDE = BCDE * 2
LD A,E
LD E,D
LD D,L
LD C,H
LD B,0
CALL .L3
INC HL
LD C,(HL)
INC HL
LD B,(HL)
RET
.L2 LD BC,0
LD A,E
LD E,D
LD D,C
.L3 PUSH AF
PUSH BC
LD HL,NumSecFAT1
CALL BCDEHLP
CALL LOADLST
POP BC
POP AF
LD E,A
LD D,0
ADD HL,DE
ADD HL,DE
LD E,(HL)
INC HL
LD D,(HL)
RET
.L1 LD H,D
LD L,E
ADD HL,HL
ADD HL,DE
SRL H
RR L
LD A,E
LD E,H
LD D,0
LD B,D
LD C,D
SRL E
PUSH AF
PUSH HL
LD DE,(NumSecFAT1)
LD BC,(NumSecFAT1 + 2)
CALL LOADLST
POP BC
LD A,B
AND 1
LD B,A
ADD HL,BC
LD B,(HL)
INC HL
LD A,H
CP HIGH (BUF_512) + 2
JR NZ,.L4
PUSH BC
LD BC,0
INC DE
CALL LOADLST
POP BC
.L4 POP AF
LD D,(HL)
LD E,B
LD BC,0
RRA
JR NC,.L5
REPT 4
SRL D
RR E
ENDM
.L5 LD A,D
AND 0x0F
LD D,A
RET
; преобразование номера кластера
; вычисление реального сектора
; на входе: BCDE = номер кластера
; на выходе: BCDE = номер сектора
REALSEC LD A,B
OR C
OR D
OR E
JR NZ,REALSE1
LD DE,(NumSecRootDir)
LD BC,(NumSecRootDir + 2)
RET
REALSE1 LD HL,0xFFFE
EX DE,HL
ADD HL,DE
EX DE,HL
INC HL
ADC HL,BC ; номер кластера - 2
LD A,(SecPerClus)
JR REALSE2
REALSE3 SLA E
RL D
RL L
RL H
REALSE2 RRCA
JR NC,REALSE3 ; умножили на размер кластера
LD B,H
LD C,L
LD HL,FirstSecData
JP BCDEHLP ; прибавили смещение от начала раздела
; BCDE / 512
BCDE200 LD E,D
LD D,C
LD C,B
LD B,0
LD A,2
JR BCDE_A
; BCDE >> A = BCDE
BCDE_A1 SRL B
RR C
RR D
RR E
BCDE_A RRCA
JR NC,BCDE_A1
RET
; (ADR) - BCDE = BCDE
BCDEHLM LD A,(HL)
INC HL
SUB E
LD E,A
LD A,(HL)
INC HL
SBC A,D
LD D,A
LD A,(HL)
INC HL
SBC A,C
LD C,A
LD A,(HL)
SBC A,B
LD B,A
RET
; (ADR) + BCDE = BCDE
BCDEHLP LD A,(HL)
INC HL
ADD A,E
LD E,A
LD A,(HL)
INC HL
ADC A,D
LD D,A
LD A,(HL)
INC HL
ADC A,C
LD C,A
LD A,(HL)
ADC A,B
LD B,A
RET
; HLDE + BC = HLDE
HLDEPBC EX DE,HL
ADD HL,BC
EX DE,HL
LD BC,0
ADC HL,BC
RET
; загрузка сектора в буфер
LOADLST LD HL,BUF_512_
PUSH HL
LD A,1
CALL LOADSCS
POP HL
RET
include drivers/drv_zc.a80
include drivers/drv_neogs.a80
include drivers/drv_nemo.a80
IFDEF ALL_DRVS
include drivers/drv_smuc.a80
include drivers/drv_divide.a80
include drivers/drv_profi.a80
ENDIF
include spg2_run.a80
include sna_run.a80