Subversion Repositories ngs

Rev

Rev 115 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1.  
  2. ; LAST UPDATE: 11.12.2024 savelij
  3.  
  4.                 include ../macros.a80
  5.                 include ../ports_ngs.a80
  6.                 include ../sdcomand.a80
  7.  
  8. ; адрес загрузки найденной прошивки
  9. ADRLOAD         EQU 0x8000
  10.  
  11. RAMCOD          EQU 0x4080                      ; адрес работы основного кода
  12. RAM8KB          EQU 0x6000                      ; адрес буфера для переброски кода
  13. STRPAG          EQU 0x8000                      ; адрес куда загрузки
  14.  
  15. FREQUENCY       EQU C_20MHZ                     ; текущая частота для основной прошивки
  16.  
  17.                 ORG 0
  18.                 DI
  19.                 LD SP,RAMCOD
  20.                 XOR A
  21.                 OUT (VOL1),A
  22.                 OUT (VOL2),A
  23.                 OUT (VOL3),A
  24.                 OUT (VOL4),A
  25.                 OUT (VOL5),A
  26.                 OUT (VOL6),A
  27.                 OUT (VOL7),A
  28.                 OUT (VOL8),A                    ; заглушили мод порты для использования буфера
  29.  
  30. ;               JP RDBYT_DBG                    ; отладочная фигня
  31.  
  32. ; ожидание загрузки прошивки со спека
  33.                 LD B,0                          ; читаем 256 порт статуса
  34. .L1             IN A,(ZXSTAT)                   ; на предмет изменения состояния
  35.                 RRA
  36.                 JR C,RDBYT01
  37.                 DJNZ .L1
  38.                 DEC B                           ; счетчик обнулился, состояние порта не изменилось
  39.                 JR RDBYT03                      ; грузим стандартную прошивку
  40.  
  41. RDBYT01         IN A,(ZXCMD)                    ; читем пришедший байт из порта команд
  42.                 LD C,A                          ; сохранили для проверки
  43.                 IN A,(ZXDATRD)                  ; читем байт из порта данных
  44.                 OUT (CLRCBIT),A                 ; сбросили команд бит
  45.                 CP C                            ; сравниваем пришедшие байты
  46.                 JR NZ,RDBYT03                   ; не совпали, грузим стандартную прошивку
  47.                 CP 0x55                         ; пришел байт 0x55?
  48.                 JR NZ,RDBYT03                   ; если нет, грузим стандартную прошивку
  49.                 LD B,0                          ; читаем 256 раз изменение порта команд
  50.                 IN A,(ZXSTAT)
  51.                 RRA
  52.                 JR C,RDBYT02
  53.                 DJNZ $-5
  54.                 DEC B
  55.                 JR RDBYT03                      ; не дождались, грузим стандартную прошивку
  56.  
  57. RDBYT02         IN A,(ZXCMD)                    ; забрали байт из порта команд
  58.                 LD C,A                          ; сохранили для проверки
  59.                 IN A,(ZXDATRD)                  ; забрали байт из порта данных
  60.                 CP C                            ; сравнили
  61.                 JR NZ,RDBYT03                   ; если не совпадают, грузим стандартную прошивку
  62. RDBYT_DBG       CP 0xAA                         ; это 0xAA?
  63. RDBYT03         EX AF,AF'                       ; временно спрятали флаги процессора
  64.                 LD HL,GRUZILA
  65.                 LD DE,RAMCOD
  66.                 LD BC,RAMCEND-VERLOAD
  67.                 LDIR                            ; перенесли основной код в адрес работы
  68.                 OUT (CLRCBIT),A                 ; сбросили команд бит
  69.                 EX AF,AF'                       ; вернули спрятанные флаги
  70.                 JP Z,GRUZIM2                    ; если все условия совпали, запускаем загрузчик
  71.                 JP GRUZIM0                      ; иначе грузим стандартную прошивку из пзу
  72.  
  73. GRUZILA
  74.                 PHASE RAMCOD
  75.  
  76. VERLOAD         DB "Loader"
  77.                 DW DATA_VERS
  78.  
  79. ; путь до файла прошивки GS
  80. F_PATH          DB "NEOGS.ROM",0
  81.  
  82. UPDATENAME      DB "NGS_ROM.UPD",0
  83.  
  84. TXT1            DB "not found",0
  85. TXT1E
  86. TXT2            DB "beta",0
  87. TXT2E
  88. TXT3            DB 0;"stable",0
  89. TXT3E
  90.  
  91. GRUZIM0         CALL RROMSD                     ; загружаем и запускаем прошивку с SD карты, если она там есть
  92.                 JP GS105                        ; иначе загружаем прошивку из пзу и запускаем
  93.  
  94. GRUZIM2         LD A,0x11                       ; конфигурим НГС
  95.                 LD (NGS_MODES),A
  96.                 OUT (GSCFG0),A                  ; отрубаем пзу и врубаем частоту 12МГЦ
  97.                 XOR A
  98.                 OUT (MPAG),A                    ; включаем страницу 0
  99. GRUZIM          IN A,(ZXSTAT)                   ; постоянно ждем команд от спека
  100.                 RRA
  101.                 JR NC,GRUZIM
  102.                 IN A,(ZXCMD)                    ; поймали команду
  103.                 CP 0x1D                         ; это команда проверки?
  104.                 JR NZ,GRUZIM1
  105.                 LD A,0x76
  106.                 OUT (ZXDATWR),A                 ; отдаем байт идентификации загрузчика
  107.                 OUT (CLRCBIT),A
  108.                 JR GRUZIM                       ; и продолжаем ждать команд
  109.  
  110. GRUZIM1         CP 0xF3
  111.                 JP Z,GS105                      ; при поступлении команд 0xF3 и
  112.                 CP 0xF4
  113.                 JP Z,GS105                      ; 0xF4 загружаем и запускаем прошивку из пзу
  114.                 CP LOW (FLOADE-FLOADER)/2+1
  115.                 JP NC,GS105                     ; аналогично не команда загрузчика переходим на основное пзу
  116.                 ADD A,A
  117.                 LD L,A
  118.                 LD H,0
  119.                 LD DE,GRUZIM2
  120.                 PUSH DE                         ; на стеке адрес возврата после исполнения команды
  121.                 LD DE,FLOADER
  122.                 ADD HL,DE
  123.                 LD E,(HL)
  124.                 INC HL
  125.                 LD D,(HL)                       ; забрали адрес исполнения команды
  126.                 EX DE,HL
  127.                 JP (HL)                         ; поехали на исполнение
  128.  
  129. FLOADER         DW LOADROM                      ; 00 загрузка rom со спека вместо скопированной из ROM
  130.                 DW JPLDROM                      ; 01 запуск загруженной прошивки
  131.                 DW GS105                        ; 02 копирование из ROM и запуск
  132.                 DW RROMSD                       ; 03 загрузка и запуск ROM с SD карты
  133.                 DW LOADCOD                      ; 04 загрузка кода со спека
  134.                 DW LDINSD                       ; 05 загрузка файла с SD карты
  135.                 DW RUNCOD                       ; 06 запуск кода с любого адреса и в любой странице
  136.                 DW STATSD                       ; 07 статус загруженного файла
  137.                 DW VERPAGE                      ; 08 версия в текстовом виде для указанной страницы
  138.                 DW GET_CRC                      ; 09 получить CRC16
  139.                 DW LOADUPDATE                   ; 0A загрузка файла с обновлением
  140.                 DW SET_FREQ                     ; 0B установка частоты процессора
  141. FLOADE
  142.  
  143. SET_FREQ        IN A,(ZXDATRD)                  ; приняли номер частоты
  144.                 BIT 7,A
  145.                 JR NZ,SET_FREQ2
  146.                 OUT (CLRCBIT),A                 ; сбросили команд бит
  147.                 AND 3
  148.                 LD L,C_10MHZ                    ; установка частоты 10 МГЦ
  149.                 JR Z,SET_FREQ1
  150.                 DEC A
  151.                 LD L,C_12MHZ                    ; установка частоты 12 МГЦ
  152.                 JR Z,SET_FREQ1
  153.                 DEC A
  154.                 LD L,C_20MHZ                    ; установка частоты 20 МГЦ
  155.                 JR Z,SET_FREQ1
  156.                 LD L,C_24MHZ                    ; установка частоты 24 МГЦ
  157. SET_FREQ1       LD A,(NGS_MODES)
  158.                 AND %11001111
  159.                 OR L
  160.                 LD (NGS_MODES),A
  161.                 OUT (GSCFG0),A
  162.                 RET
  163.  
  164. SET_FREQ2       LD A,(NGS_MODES)
  165.                 AND 0x30
  166.                 RRCA
  167.                 RRCA
  168.                 RRCA
  169.                 RRCA
  170.                 OUT (CLRCBIT),A
  171.                 OUT (ZXDATWR),A
  172.                 JP WDN
  173.  
  174. ; передача на спек версии в текстовом виде
  175. VERPAGE         IN A,(ZXDATRD)                  ; забрали байт номера запрошенной страницы пзу
  176.                 AND 7                           ; старшие 5 бит в игноре
  177.                 EX AF,AF'                       ; временно спрятали флаги проца
  178.                 LD A,0x30
  179.                 OUT (GSCFG0),A                  ; включили 10 МГЦ и вернули пзу
  180.                 EX AF,AF'                       ; вернули флаги
  181.                 ADD A,A                         ; нам нужна вторые 32К страницы пзу
  182. ;               AND A                           ; выбрана страница 0?
  183. ;               JR NZ,VERPAG1                   ; если нет, то идем на извлечение последних 8 байт
  184. ;               LD HL,VERLOAD                   ; для загрузчика берем из другого адреса
  185. ;               LD DE,RAMCEND
  186. ;               LD BC,8
  187. ;               PUSH DE
  188. ;               LDIR
  189. ;               POP DE
  190. ;               JR VERPAG2                      ; пошли на переводчик в текстовый вид
  191.  
  192. VERPAG1         INC A
  193.                 OUT (MPAG),A                    ; включили последние 16К выбранной страницы пзу
  194.                 LD HL,0xFFF8
  195.                 LD BC,8
  196.                 LD DE,RAMCEND
  197.                 PUSH DE
  198.                 LDIR                            ; перенесли 8 байт из хвоста пзу
  199.                 POP DE
  200. VERPAG2         LD A,0x11
  201.                 OUT (GSCFG0),A                  ; отрубили пзу и вернули 12МГЦ
  202.                 XOR A
  203.                 OUT (MPAG),A                    ; вернули страницу 0 озу
  204.                 LD B,8                          ; проверям перенесенные 8 байт, а не 0xFF ли там?
  205.                 LD A,(DE)
  206.                 INC DE
  207.                 INC A
  208.                 JR NZ,VFPGA1                    ; не 0xFF, продолжаем
  209.                 DJNZ $-5
  210.                 DEC SP                          ; таки все 8 байт 0xFF, версии у пзу страницы нету
  211.                 DEC SP
  212.                 POP DE
  213.                 LD HL,TXT1
  214.                 LD BC,TXT1E-TXT1
  215.                 LDIR                            ; отдать текст об этом
  216.                 JR VFPGA0
  217.  
  218. VFPGA1          DEC SP
  219.                 DEC SP
  220.                 POP DE
  221.                 CALL UNVERS                     ; распаковка полученных 8 байт в текст
  222. VFPGA0          OUT (CLRCBIT),A                 ; сбросили команд бит
  223.                 LD HL,RAMCEND
  224.                 LD BC,ZXDATWR
  225. VFPGA2          LD A,(HL)
  226.                 OUTI
  227.                 EX AF,AF'
  228.                 CALL WDN
  229.                 EX AF,AF'
  230.                 AND A
  231.                 JR NZ,VFPGA2                    ; отдаем текст версии пока не встретится байт 0, который тоже отдаем
  232.                 RET
  233.  
  234. ; распаковщик даты
  235. UNVERS          LD HL,6
  236.                 ADD HL,DE                       ; пропустили 6 байт текста версии
  237.                 LD C,(HL)                       ; забрали младший байт версии
  238.                 LD (HL)," "                     ; на его место пробел
  239.                 INC HL
  240.                 LD B,(HL)                       ; забрали старший байт
  241.                 LD A,C                          ; взяли младший байт версии
  242.                 AND 0x1F                        ; нас интересуют младшие 5 бит (день месяца)
  243.                 JR NZ,.L1
  244.                 RES 7,B                         ; если получился 0, возможно это бета версия
  245. .L1             CP 32
  246.                 JR C,.L2                        ; в месяце не может быть более 31 дня
  247.                 RES 7,B                         ; иначе это бета версия
  248. .L2             CALL A2TXT                      ; переводим полученное число в текст
  249.                 SRL B                           ; сдинули версию на 1 бит влево чтобы номер месяца
  250.                 RR C                            ; оказался в одном байте
  251.                 LD A,C                          ; забрали этот байт
  252.                 RRCA
  253.                 RRCA
  254.                 RRCA
  255.                 RRCA                            ; сдвинули нужные биты в младшие разрады байта
  256.                 AND 0x0F                        ; оставили нужные 4 бита (номер месяца)
  257.                 JR NZ,.L3                       ; номер месяца неможет быть 0
  258.                 RES 6,B                         ; иначе это бета версия
  259. .L3             CP 13                           ; и номер месяца не может быть больше 12
  260.                 JR C,.L4
  261.                 RES 6,B                         ; иначе бета версия
  262. .L4             LD (HL),"."                     ; отделили номер дня месяца точкой
  263.                 INC HL
  264.                 CALL A2TXT                      ; конвертировали номер месяца
  265.                 LD (HL),"."                     ; так же отделили точкой
  266.                 INC HL
  267.                 LD A,B                          ; взяли оставшиеся биты
  268.                 AND 0x3F                        ; нам нужны 6 бит номера года
  269.                 CALL A2TXT                      ; конвертнули в текст
  270.                 BIT 6,B                         ; бета или стабл версия?
  271.                 JR NZ,.L5
  272.                 LD DE,TXT2                      ; все-таки бета, о чем и добавляем текст к версии
  273.                 LD BC,TXT2E-TXT2
  274.                 JR .L6
  275.  
  276. .L5             LD DE,TXT3                      ; версия стабл
  277.                 LD BC,TXT3E-TXT3
  278. .L6             LD (HL)," "                     ; перед текстом (бета или стабл) вставляем пробел
  279.                 INC HL
  280.                 EX DE,HL
  281.                 LDIR                            ; перетащили текст
  282.                 EX DE,HL
  283.                 LD (HL),0                       ; завершили строку нулем
  284.                 RET
  285.  
  286. ; перевод "A" в десятичный вид и в текст. для чисел от 0 до 99
  287. A2TXT           PUSH HL                         ; сохранили адрес куда ложить сконверченное
  288.                 LD L,A
  289.                 LD H,0
  290.                 LD DE,10
  291.                 XOR A
  292.                 DEC A
  293. .L1             INC A
  294.                 SBC HL,DE
  295.                 JR NC,.L1                       ; считаем количество десятков в числе
  296.                 ADD HL,DE                       ; вернули перебор вычитания
  297.                 ADD A,"0"                       ; перевели в тесктовый вид полученное число
  298.                 LD D,A                          ; пока сохранили
  299.                 LD A,L                          ; взяли оставшиеся единицы числа
  300.                 ADD A,"0"                       ; конвертули в текст
  301.                 POP HL                          ; вернули адрес куда ложить
  302.                 LD (HL),D                       ; положили десятки заданного числа
  303.                 INC HL
  304.                 LD (HL),A                       ; положили единицы того же числа
  305.                 INC HL
  306.                 RET
  307.  
  308. ; загрузка с SD карты по указанному пути
  309. ; первый байт-номер страницы озу куда начинать грузить
  310. ; далее байты текстовой строка пути и имени файла
  311. ; конец строки байт 0, он же стоп байт
  312. LDINSD          LD BC,ZXDATRD                   ; адрес порта данных
  313.                 LD HL,RAMCEND                   ; адрес куда строку пути складировать
  314.                 PUSH HL
  315.                 IN A,(C)                        ; приняли номер страницы откуда начинать загрузку
  316.                 OUT (CLRCBIT),A                 ; сбросили команд бит
  317.                 EX AF,AF'
  318. LDINSD1         CALL WDY
  319.                 IN A,(C)
  320.                 LD (HL),A
  321.                 INC HL
  322.                 AND A
  323.                 JR NZ,LDINSD1                   ; принимаем строку пока не встретится байт 0
  324.                 EX AF,AF'
  325.                 POP HL
  326.                 JP LOAD_SD                      ; далее запускаем загрузку с SD карты
  327.  
  328. ; загрузка файла с обновлениями
  329. LOADUPDATE      LD HL,UPDATENAME                ; имя файла обновления
  330.                 LD A,2                          ; грузить начиная со 2 страницы
  331.                 OUT (CLRCBIT),A
  332.                 JP LOAD_SD
  333.  
  334. ; статус загрузки файла с SD карты
  335. STATSD          LD A,(STATUS)
  336.                 OUT (ZXDATWR),A
  337.                 OUT (CLRCBIT),A
  338.                 RET
  339.  
  340. ; загрузка и запуск прошивки с SD карты
  341. ; имя, путь и адрес фиксирован
  342. RROMSD          LD HL,F_PATH                    ; адрес строки фиксированного пути для загрузки
  343.                 XOR A
  344.                 CALL LOAD_SD                    ; загружаем
  345.                 AND A
  346.                 RET NZ                          ; если ошибка, то грузим из пзу
  347.                 JP JPLDROM
  348.  
  349. ; запуск кода в любой странице
  350. ; 0 - номер страницы озу
  351. ; 1 - младший байт адреса запуска
  352. ; 2 - старший байт адреса запуска
  353. RUNCOD          LD BC,ZXDATRD                   ; адрес порта данных
  354.                 IN A,(C)                        ; приняли номер страницы озу
  355.                 OUT (CLRCBIT),A                 ; сбросили команд бит
  356.                 OUT (MPAG),A
  357.                 CALL WDY
  358.                 IN L,(C)                        ; приняли младший байт адреса запуска
  359.                 CALL WDY
  360.                 IN H,(C)                        ; приняли старший байт адреса запуска
  361.                 JP (HL)                         ; запускаем
  362.  
  363. ; 0 - номер страницы озу
  364. ; 1 - младший байт длины загрузки
  365. ; 2 - старший байт длины загрузки
  366. ; загрузка не более 32КБ
  367. LOADCOD         LD BC,ZXDATRD                   ; адрес порта данных
  368.                 LD HL,0x8000                    ; адрес начала зaгрузки
  369.                 IN A,(C)                        ; приняли номер страницы озу
  370.                 OUT (CLRCBIT),A                 ; сбросили команд бит
  371.                 OUT (MPAG),A                    ; включили заданную страницу озу
  372.                 CALL WDY
  373.                 IN E,(C)                        ; приняли младший байт длины загрузки
  374.                 CALL WDY
  375.                 IN D,(C)                        ; приняли старший байт длины загрузки
  376. LOADCO1         CALL WDY
  377.                 INI
  378.                 LD A,H
  379.                 AND A
  380.                 RET Z                           ; если озу кончилось, выходим
  381.                 DEC DE
  382.                 LD A,D
  383.                 OR E
  384.                 JR NZ,LOADCO1                   ; грузим скока указано
  385.                 RET
  386.  
  387. ; загрузка прошивки 32КБ со спека
  388. LOADROM         XOR A
  389.                 OUT (MPAG),A                    ; включаем страницу
  390.                 LD HL,0x8000                    ; адрес загрузки
  391.                 OUT (CLRCBIT),A                 ; сброс команд бита
  392.                 LD BC,ZXDATRD                   ; адрес порта данных
  393. LOADROM1        CALL WDY
  394.                 INI
  395.                 LD A,H
  396.                 AND A
  397.                 JR NZ,LOADROM1                  ; грузим пока память не кончится
  398.                 RET
  399.  
  400. ; грузилка стандартной прошивки из ROM
  401. GS105           LD HL,STRPAG                    ; адрес куда переносить
  402.                 LD A,4                          ; переносить 4 куска по 8 килобайт
  403. MOV1            EX AF,AF'                       ; прячем счетчик
  404.                 LD A,0x30
  405.                 OUT (GSCFG0),A                  ; включили пзу
  406.                 LD A,2
  407.                 OUT (MPAG),A                    ; страницу 2 со стандартной прошивкой
  408.                 PUSH HL
  409.                 LD DE,RAM8KB
  410.                 LD BC,0x2000
  411.                 LDIR                            ; перенесли в буфер 8 килобайт
  412.                 LD A,0x31
  413.                 OUT (GSCFG0),A                  ; переключили пзу
  414.                 XOR A
  415.                 OUT (MPAG),A                    ; включили страницу 0 озу
  416.                 POP DE
  417.                 LD HL,RAM8KB
  418.                 LD BC,0x2000
  419.                 LDIR                            ; перенесли из буфера 8 килобайт
  420.                 EX DE,HL
  421.                 EX AF,AF'
  422.                 DEC A
  423.                 JR NZ,MOV1                      ; и так 4 раза
  424.  
  425. ; запуск загруженной прошивки
  426. JPLDROM         XOR A
  427.                 OUT (MPAG),A                    ; включили страницу 0 озу
  428. ;               LD A,0x13                       ; включили частоту 12МГЦ, отключили пзу и защитили озу от записи
  429. ;               LD A,0x23                       ; включили частоту 20МГЦ, отключили пзу и защитили озу от записи
  430.                 LD A,3+FREQUENCY                ; включили указанную частоту, отключили пзу и защитили озу от записи
  431.                 OUT (GSCFG0),A
  432.                 JP 0                            ; стартуем стандартную прошивку
  433.  
  434. ; ждем пока спек даст байт
  435. WDY             IN A,(ZXSTAT)
  436.                 RLA
  437.                 JR NC,WDY
  438.                 RET
  439.  
  440. ; ждем пока спек заберет байт из порта
  441. WDN             IN A,(ZXSTAT)
  442.                 RLA
  443.                 JR C,WDN
  444.                 RET
  445.  
  446. ; подсчет CRC16
  447. GET_CRC         LD A,2
  448.                 OUT (MPAG),A
  449.                 DEC A
  450.                 OUT (GSCFG0),A
  451.                 LD HL,(0x8000)
  452.                 SRL H
  453.                 RR L
  454.                 SRL H
  455.                 RR L
  456.                 SRL H
  457.                 RR L
  458.                 SRL H
  459.                 RR L
  460.                 LD A,L
  461.                 LD IYH,A
  462. ;               LD IX,0x8000
  463. ;               LD C,(IX+0)
  464. ;               LD B,(IX+1)
  465. ;               CALL CRC16
  466. ;               LD C,(IX+0)
  467. ;               LD B,(IX+1)
  468. ;               LD A,0x81
  469. ;               AND A
  470. ;               SBC HL,BC
  471. ;               JR NZ,OUT_ERR                   ; CRC16 заголовка ERROR
  472.                 LD IX,0x8000+8-0x10
  473. SCHET           LD DE,0x10
  474.                 ADD IX,DE                       ; в IX адрес выбранного блока
  475.                 LD C,(IX+4)
  476.                 LD B,(IX+5)                     ; в BC длина блока
  477.                 LD E,(IX+1)
  478.                 LD L,(IX+2)
  479.                 LD H,(IX+3)
  480.                 LD A,L
  481.                 AND 0x7F
  482.                 LD D,A                          ; в DE смещение в странице
  483.                 ADD HL,HL
  484.                 LD A,2
  485.                 ADD A,H
  486.                 LD IYL,A
  487.                 OUT (MPAG),A                    ; номер страницы
  488.                 PUSH IX
  489.                 LD IX,0x8000
  490.                 ADD IX,DE                       ; в IX адрес начала блока
  491.                 CALL CRC16
  492.                 POP IX
  493.                 LD C,(IX+6)
  494.                 LD B,(IX+7)
  495.                 LD A,0x82
  496.                 AND A
  497.                 SBC HL,BC
  498.                 JR NZ,OUT_ERR
  499.                 DEC IYH
  500.                 JR NZ,SCHET
  501. ERR_OK          LD A,0x80
  502.  
  503. ; CRC16 ERROR
  504. ; 0x80 - CRC16 блока ok
  505. ; 0x81 - CRC16 заголовка error
  506. ; 0x82 - CRC16 блока ERROR
  507. OUT_ERR         OUT (CLRCBIT),A
  508.                 OUT (ZXDATWR),A
  509.                 CALL WDN
  510.                 LD A,L
  511.                 OUT (ZXDATWR),A
  512.                 CALL WDN
  513.                 LD A,H
  514.                 OUT (ZXDATWR),A
  515.                 RET
  516.  
  517. CRC16           LD HL,0xFFFF
  518.                 LD DE,0x1021
  519. CRC_0           LD A,(IX)
  520.                 INC IX
  521.                 EX AF,AF'
  522.                 LD A,IXL
  523.                 OR IXH
  524.                 JR NZ,CRC_3
  525.                 INC IYL
  526.                 LD A,IYL
  527.                 OUT (MPAG),A
  528.                 LD IX,0x8000
  529. CRC_3           EX AF,AF'
  530.                 XOR H
  531.                 LD H,A
  532.                 LD A,8
  533. CRC_1           ADD HL,HL
  534.                 JR NC,CRC_2
  535.                 EX AF,AF'
  536.                 LD A,L
  537.                 XOR E
  538.                 LD L,A
  539.                 LD A,H
  540.                 XOR D
  541.                 LD H,A
  542.                 EX AF,AF'
  543. CRC_2           DEC A
  544.                 JR NZ,CRC_1
  545.                 DEC BC
  546.                 LD A,B
  547.                 OR C
  548.                 JR NZ,CRC_0
  549.                 LD A,2
  550.                 OUT (MPAG),A
  551.                 RET
  552.  
  553. ;---------------------------------
  554. ; грузилка файла по указанному пути
  555.  
  556.  INIT_VAR 0x5000
  557.  SETVAR BUF_512,        0x200           ; буфер сектора
  558.  SETVAR TDIRCLS,        0x400           ; буфер кластеров ROOT директории
  559.  SETVAR CAL_FAT,        BYTE            ; калибр FAT
  560.  SETVAR BYTSSEC,        BYTE            ; количество секторов в кластере
  561.  SETVAR ROOTCLS,        DWORD           ; кластер начала ROOT директории
  562.  SETVAR ROOTSEC,        WORD            ; размер в секторах ROOT директории
  563.  SETVAR SEC_FAT,        DWORD           ; количество секторов одной FAT
  564.  SETVAR RSVDSEC,        WORD            ; размер резервной области
  565.  SETVAR STARTRZ,        DWORD           ; начало диска/раздела
  566.  SETVAR FRSTDAT,        DWORD           ; адрес первого сектора данных от BPB
  567.  SETVAR SEC_DSC,        DWORD           ; количество секторов на диске/разделе
  568.  SETVAR CLS_DSC,        DWORD           ; количество кластеров на диске/разделе
  569.  SETVAR FATSTR,         DWORD           ; начало первой FAT таблицы
  570.  SETVAR ADRPATH,        WORD            ; адрес текста пути файла
  571.  SETVAR STATUS,         BYTE            ; статус после вызова LOAD_SD
  572.  SETVAR OLD_SP,         WORD            ; стек для выхода
  573.  SETVAR FB_EXT,         0x0B            ; буфер 8.3 для поиска имени
  574.  SETVAR LVL_DIR,        BYTE            ; номер уровня директории
  575.  SETVAR LSTLOAD,        DWORD           ; номер сектора загруженного в буфер
  576.  SETVAR NGS_MODES,      BYTE            ; текущий установленный режим
  577.  
  578. ; SD карта не найдена
  579. ZAW003          LD A,0xEE
  580. WR_STAT         LD SP,(OLD_SP)
  581.                 LD (STATUS),A
  582.                 RET
  583.  
  584. ; загрузка файла
  585. ; на входе: A - страница начала загрузки
  586. ; HL - адрес текстовой строки
  587. ; пути к файлу вместе с именем и расширением файла. путь полностью от ROOT
  588. ; загружается файл по размеру дополненому до полных секторов (сектор 512 байт)
  589. ; пример: размер файла =0x80-после дополнения будет загружен 1 сектор
  590. ; =0x401 - будет загружено 3 сектора
  591. ; на выходе: A =
  592.                 ; 0x00 - файл загружен
  593.                 ; 0xAA - файл не найден
  594.                 ; 0xDD - FAT не обнаружен
  595.                 ; 0xEE - SD карта не обнаружена
  596. LOAD_SD         LD IYL,A                        ; сохранили номер страницы куда грузить
  597.                 LD (ADRPATH),HL                 ; сохранили адрес строки пути
  598.                 LD (OLD_SP),SP                  ; сохранили стек
  599.                 LD A,0xFF
  600.                 LD (LSTLOAD+3),A                ; принудительная загрузка сектора без проверки
  601.                 LD A,1
  602.                 OUT (GSCFG0),A                  ; отключили пзу, все страница озу
  603.                 LD A,M_SDNCS+M_SNCLR;%10011011
  604.                 OUT (SCTRL),A                   ; сконфигурили нгс с CS=1 для SD карты         
  605.                 LD B,0x10
  606. .L1             LD A,0xFF
  607.                 OUT (SD_SEND),A                 ; пишем 0x80 байт 0xFF в порт карточки
  608.                 DJNZ .L1
  609.                 XOR A                           ; 256 попыток найти SD карту
  610.                 EX AF,AF'
  611.                 LD A,M_SDNCS
  612.                 OUT (SCTRL),A                   ; выбрали SD карту CS=0
  613. .L2             LD HL,CMD00
  614.                 CALL OUTCOM                     ; переводим карточку в режим SPI командой 0
  615.                 CALL IN_OOUT                    ; ждем ответа
  616.                 EX AF,AF'
  617.                 DEC A
  618.                 JR Z,ZAW003                     ; ждем по счептчику 256 раз
  619.                 EX AF,AF'
  620.                 DEC A
  621.                 JR NZ,.L2                       ; ждем пока карта ответит байтом 1
  622.                 LD BC,SD_RSTR
  623.                 LD HL,CMD08
  624.                 CALL OUTCOM                     ; определяем спецификацию карты
  625.                 CALL IN_OOUT                    ; в "A" ответ карты R1
  626.                 IN H,(C)
  627.                 NOP
  628.                 IN H,(C)       
  629.                 NOP
  630.                 IN H,(C)
  631.                 NOP
  632.                 IN H,(C)                        ; прочитали остальные байты в никуда
  633.                 BIT 2,A                         ; если ошибка, то
  634.                 LD HL,0                         ; карта спецификации 1.0
  635.                 JR NZ,.L3                       ; иначе
  636.                 LD H,0x40                       ; карта спецификации 2.0
  637. .L3             LD A,CMD_55
  638.                 CALL OUT_COM                    ; запускаем внутреннюю инициализацию карты
  639.                 CALL IN_OOUT
  640.                 in (c) ;in f,(c)
  641.                 in (c) ;in f,(c)
  642.                 LD BC,SD_SEND
  643.                 LD A,ACMD_41
  644.                 OUT (C),A
  645.                 LD A,H
  646.                 OUT (C),A
  647.                 XOR A
  648.                 OUT (C),A
  649.                 NOP
  650.                 OUT (C),A
  651.                 NOP
  652.                 OUT (C),A
  653.                 DEC A
  654.                 OUT (C),A
  655.                 CALL IN_OOUT
  656.                 AND A
  657.                 JR NZ,.L3                       ; ждем пока карты перейдет в режим готовности
  658. .L4             LD A,CMD_59
  659.                 CALL OUT_COM                    ; принудительно отключаем CRC16
  660.                 CALL IN_OOUT
  661.                 AND A
  662.                 JR NZ,.L4
  663. .L5             LD HL,CMD16
  664.                 CALL OUTCOM                     ; принудительный размер сектора 512 байт
  665.                 CALL IN_OOUT
  666.                 AND A
  667.                 JR NZ,.L5
  668.  
  669. ; инициализация переменных FAT
  670. WC_FAT          LD DE,0
  671.                 LD B,D
  672.                 LD C,E
  673.                 CALL LOADLST                    ; читаем сектор 0 карточки
  674.                 PUSH HL
  675.                 POP IX
  676.                 LD DE,0x01BE
  677.                 ADD HL,DE                       ; переходим на смещение для проверок
  678.                 LD A,(HL)                       ; проверям чтобы был 0, карточки не могут быть загрузочными
  679.                 AND A
  680.                 JR NZ,.L2                       ; если не 0, проверить другое
  681.                 LD DE,4
  682.                 ADD HL,DE                       ; переходим к проверке типа раздела
  683.                 LD A,(HL)
  684.                 LD B,0
  685.                 CP 1                            ; FAT12?
  686.                 JR Z,.L1
  687.                 LD B,2
  688.                 CP 0x0B                         ; FAT32?
  689.                 JR Z,.L1
  690.                 CP 0x0C                         ; FAT32?
  691.                 JR Z,.L1
  692.                 LD B,1
  693.                 CP 6                            ; FAT16?
  694.                 JR Z,.L1
  695.                 CP 4                            ; FAT16?
  696.                 JR Z,.L1
  697.                 CP 0x0E                         ; FAT16?
  698.                 JR NZ,.L2              
  699. .L1             LD A,B                          ; берем из "B" тип раздела
  700.                 LD (CAL_FAT),A                  ; сохранили
  701.                 ADD HL,DE
  702.                 CALL LOADZP                     ; берем номер сектора начала основного раздела
  703.                 JR .R1                          ; переходим к инициализации переменных для работы с фатом
  704.  
  705. ; MBR не обнаружен, проверяем сектор 0 карты как описатель
  706. .L2             LD C,(IX+0x0D)                  ; C = количество секторов в кластере
  707.                 XOR A
  708.                 LD E,A
  709.                 LD B,8
  710. .L3             RR C
  711.                 ADC A,0
  712.                 DJNZ .L3                        ; количество секторов в кластере должно быть степенью 2
  713.                 DEC A
  714.                 JR NZ,.L4                       ; проверили количество бит
  715.                 INC E                           ; +1, есть такое
  716. .L4             LD A,(IX+0x0E)
  717.                 OR (IX+0x0F)
  718.                 JR Z,.L5                        ; количество зарезервированных секторов должно быть >0
  719.                 INC E                           ; +1, есть такое
  720. .L5             LD A,(IX+0x13)
  721.                 OR (IX+0x14)
  722.                 JR NZ,.L6                       ; количество секторов на разделе для ФАТ16?
  723.                 INC E
  724. .L6             LD A,(IX+0x20)
  725.                 OR (IX+0x21)
  726.                 OR (IX+0x22)
  727.                 OR (IX+0x23)
  728.                 JR NZ,.L7                       ; количество секторов на разделе для ФАТ32?
  729.                 INC E                           ; од но из них должно быть =0, другое >0
  730. .L7             LD A,(IX+0x15)
  731.                 AND 0xF0
  732.                 CP 0xF0
  733.                 JR NZ,.L8                       ; старшие биты должны быть в 1
  734.                 INC E
  735. .L8             LD A,E
  736.                 CP 4                            ; условия совпали?
  737.                 LD A,0xDD                       ; FAT не найден
  738.                 JP NZ,WR_STAT
  739.                 LD A,0xFF
  740.                 LD (CAL_FAT),A                  ; тип фат пока не определен
  741.                 LD DE,0
  742.                 LD B,D
  743.                 LD C,E
  744.  
  745. .R1             LD (STARTRZ),DE
  746.                 LD (STARTRZ+2),BC               ; положили номер стартового сектора раздела
  747.                 CALL LOADLST                    ; загрузили его
  748.                 LD HL,0
  749.                 LD DE,(BUF_512+0x16)            ; BPB_FATSZ16
  750.                 LD A,D
  751.                 OR E
  752.                 JR NZ,.R2                       ; если не FAT12/16 (BPB_FATSZ16=0)
  753.                 LD DE,(BUF_512+0x24)
  754.                 LD HL,(BUF_512+0x26)            ; BPB_FATSZ32
  755.                                                 ; то берем из смещения +36
  756. .R2             LD (SEC_FAT+2),HL
  757.                 LD (SEC_FAT),DE                 ; число секторов на FAT-таблицу
  758.                 LD HL,0
  759.                 LD DE,(BUF_512+0x13)            ; BPB_TOTSEC16
  760.                 LD A,D
  761.                 OR E
  762.                 JR NZ,.R3                       ; если не FAT12/16 (BPB_TOTSEC16=0)
  763.                 LD DE,(BUF_512+0x20)
  764.                 LD HL,(BUF_512+0x22)            ; BPB_TOTSEC32
  765.                                                 ; то берем из смещения +32
  766. .R3             LD (SEC_DSC+2),HL
  767.                 LD (SEC_DSC),DE                 ; к-во секторов на диске/разделе
  768.  
  769. ; вычисляем ROOTDIRSECTORS
  770.                 LD BC,(BUF_512+0x0B)            ; BPB_BYTSPERSEC
  771.                 LD DE,(BUF_512+0x11)            ; BPB_ROOTENTCNT
  772.                 LD HL,0
  773.                 LD A,D
  774.                 OR E
  775.                 JR Z,.R4
  776.                 LD B,H
  777.                 LD C,L
  778.                 LD A,0x10
  779.                 CALL BCDE_A
  780.                 EX DE,HL
  781.  
  782. ; это реализована формула
  783. ; ROOTDIRSECTORS = ((BPB_ROOTENTCNT*32) + (BPB_BYTSPERSEC-1)) / BPB_BYTSPERSEC
  784. ; В HL=ROOTDIRSECTORS. если FAT32, то HL=0 всегда
  785.  
  786. .R4             PUSH HL                         ; ROOTDIRSECTORS
  787.                 LD (ROOTSEC),HL
  788.                 LD A,(BUF_512+0x10)
  789.                 LD DE,(SEC_FAT)
  790.                 LD HL,(SEC_FAT+2)
  791.                 DEC A
  792. .R5             EX DE,HL
  793.                 ADD HL,HL
  794.                 EX DE,HL
  795.                 ADC HL,HL
  796.                 DEC A
  797.                 JR NZ,.R5
  798.                 POP BC                          ; полный размер FAT-области в секторах
  799.                 CALL HLDEPBC                    ; прибавили ROOTDIRSECTORS
  800.                 LD BC,(BUF_512+0x0E)            ; BPB_RSVDSECCNT
  801.                 LD (RSVDSEC),BC
  802.                 CALL HLDEPBC                    ; прибавили BPB_RESVDSECCNT
  803.                 LD (FRSTDAT),DE
  804.                 LD (FRSTDAT+2),HL               ; положили номер первого сектора данных
  805.                 LD B,H
  806.                 LD C,L
  807.                 LD HL,SEC_DSC                   ; BCDE + 32-ое число по адресу HL
  808.                 CALL BCDEHLM                    ; вычли из полного к-ва секторов раздела
  809.                 LD A,(BUF_512+0x0D)
  810.                 LD (BYTSSEC),A
  811.                 CALL BCDE_A                     ; разделили на к-во секторов в кластере
  812.                 LD (CLS_DSC),DE
  813.                 LD (CLS_DSC+2),BC               ; положили кол-во кластеров на разделе
  814.  
  815.                 LD A,(CAL_FAT)
  816.                 CP 0xFF
  817.                 JR NZ,.R6
  818. ; определение типа FAT при отсуствии MBR
  819.                 LD DE,(SEC_FAT-1)
  820.                 LD BC,(SEC_FAT+1)
  821.                 LD E,0                          ; BCDE = количество секторов *0x100
  822.                 PUSH BC
  823.                 PUSH DE                         ; сохранили
  824.                 SRL B
  825.                 RR C
  826.                 RR D
  827.                 RR E                            ; BCDE = количество секторов *0x80
  828.                 LD HL,CLS_DSC                   ; количество кластеров на FAT
  829.                 PUSH HL                         ; сохранили
  830.                 CALL HLBCDEM                    ; количество кластеров-(количество секторов*0x80)
  831.                 LD A,E
  832.                 AND 0x80                        ; количество менее 128 кластеров в секторе для FAT32
  833.                 OR D
  834.                 OR C
  835.                 OR B
  836.                 LD A,2
  837.                 POP HL
  838.                 POP DE
  839.                 POP BC
  840.                 JR Z,.R6                        ; FAT32 если флаг Z=0
  841.                 CALL HLBCDEM                    ; количество кластеров-(количество секторов*0x100)
  842.                 LD A,D
  843.                 OR C
  844.                 OR B
  845.                 LD A,1
  846.                 JR Z,.R6                        ; FAT16 если флаг Z=0
  847.                 XOR A                           ; иначе FAT12
  848.  
  849. ; для FAT12/16 вычисляем адрес первого сектора директории
  850. ; для FAT32 берем по смещемию +44, на выходе BCDE - сектор ROOTDIR
  851. .R6             LD (CAL_FAT),A                  ; уточнили тип фата
  852.                 EX AF,AF'
  853.                 LD DE,(RSVDSEC)
  854.                 LD BC,0
  855.                 LD HL,STARTRZ
  856.                 CALL BCDEHLP
  857.                 LD (FATSTR),DE
  858.                 LD (FATSTR+2),BC                ; вычислили и положили номер сектора начала FAT-таблиц
  859.                 EX AF,AF'
  860.                 AND A
  861.                 LD DE,0
  862.                 LD B,D
  863.                 LD C,E
  864.                 JR Z,.F1                        ; FAT12 - none
  865.                 DEC A
  866.                 JR Z,.F1                        ; FAT16
  867.                 LD DE,(BUF_512+0x2C)
  868.                 LD BC,(BUF_512+0x2E)            ; FAT32
  869. .F1             LD (ROOTCLS),DE
  870.                 LD (ROOTCLS+2),BC               ; положили номер кластер ROOT директории
  871.  
  872.                 XOR A
  873.                 LD (LVL_DIR),A                  ; начинаем с ROOT директории
  874.                 LD HL,(ADRPATH)                 ; вернули адрес строки пути до файла
  875. .F6             PUSH BC
  876.                 PUSH DE                         ; сохранили номер кластера
  877.                 CALL FNDBUF                     ; распаковка части текстовой строки для создания маски поиска
  878.                 POP DE
  879.                 POP BC                          ; восстановили номер кластера
  880.                 PUSH HL                         ; сохранили текущий адрес текстовой строки
  881.  
  882.                 LD HL,TDIRCLS                   ; адрес таблицы кластеров текущей директории
  883.                 LD A,D
  884.                 OR E
  885.                 OR B
  886.                 OR C
  887.                 CALL SAVEZP                     ; сохранили в таблицу номер текущего кластера
  888.                 JR Z,.F3                        ; если номер кластера 0, то это ROOT дира (для ФАТ12/16)
  889. .F2             PUSH HL
  890.                 CALL RDFATZP                    ; читаем следущий номер кластера из цепочки директории
  891.                 CALL LST_CLS                    ; проверяем на конец цепочки
  892.                 POP HL
  893.                 JR C,.F3
  894.                 CALL SAVEZP                     ; если непоследний сохраняем в таблицу
  895.                 JR .F2                          ; следующий номер кластера
  896.  
  897. .F3             LD BC,0xFFFF
  898.                 CALL SAVEZP                     ; кладем маркер конца цепочки
  899.                 EXX
  900.                 LD HL,LVL_DIR
  901.                 LD A,(HL)                       ; текущий уровень директории
  902.                 INC (HL)                        ; следующий уровень директории
  903.                 AND A
  904.                 LD BC,0                         ; количество записей ROOT директории
  905.                 JR NZ,.F4
  906.                 LD A,(CAL_FAT)
  907.                 CP 2
  908.                 JR NC,.F4
  909.                 LD HL,(ROOTSEC)                 ; уже не ROOT директория
  910.                 ADD HL,HL
  911.                 ADD HL,HL
  912.                 ADD HL,HL
  913.                 ADD HL,HL
  914.                 ADD HL,HL
  915.                 LD B,H
  916.                 LD C,L
  917. .F4             EXX
  918.  
  919. .F5             INC BC                          ; ищем по заданной маске начиная с 0
  920.                 CALL RDDIRSC                    ; грузим по номеру описателя сектор директории
  921.                 LD A,C
  922.                 AND 0x0F                        ; в секторе максимум 16 описателей
  923.                 LD E,A
  924.                 LD D,0
  925.                 EX DE,HL
  926.                 ADD HL,HL
  927.                 ADD HL,HL
  928.                 ADD HL,HL
  929.                 ADD HL,HL
  930.                 ADD HL,HL
  931.                 ADD HL,DE                       ; получили адрес нужного описателя
  932.                 EXX
  933.                 DEC BC
  934.                 LD A,B
  935.                 OR C
  936.                 EXX
  937.                 LD A,0xAA
  938.                 JP Z,WR_STAT
  939.                 LD A,(HL)                       ; проверяем первый байт имени описателя
  940.                 AND A
  941.                 LD A,0xAA                       ; если байт =0, то
  942.                 JP Z,WR_STAT                    ; переход по ошибке = файл не найден
  943.                 PUSH HL
  944.                 PUSH BC
  945.                 CALL COMPARE                    ; сравниваем с заданной маской
  946.                 POP BC
  947.                 POP DE
  948.                 PUSH DE
  949.                 POP IX                          ; содержимое IX = адрес описателя
  950.                 JR NZ,.F5                       ; не совпадает, переходим к следующему описателю
  951.                 CALL RD_CLAS                    ; забираем номер кластера из найденного описателя
  952.                 EX (SP),HL                      ; восстановили текущий адрес в строке пути до файла
  953.                 INC SP
  954.                 INC SP                          ; маскировка на стеке адреса размера в байтах текущего файла
  955.                 LD A,(HL)
  956.                 AND A                           ; текстовая строка кончилась?
  957.                 JR NZ,.F6                       ; если нет, то ищем дальше
  958.                 LD A,(IX+0x0B)                  ; проверяем это дира или файл?
  959.                 AND 0x10
  960.                 LD A,0xAA                       ; если дира, то ошибка
  961.                 JP NZ,WR_STAT                   ; текстовая строка должна указывать на файл
  962.                 DEC SP
  963.                 DEC SP
  964.                 POP HL                          ; восстановили в HL адрес откуда взять размер файла в байтах
  965.                 PUSH BC
  966.                 PUSH DE
  967.                 CALL LOADZP                     ; забираем размер файла (в байтах)
  968.                 LD A,E
  969.                 AND A
  970.                 JR Z,.F8                        ; младший байт размера файла =0?
  971.                 INC D                           ; увеличиваем размер на 256 байт без учета младшего байта
  972. .F8             BIT 0,D                         ; проверяем чет/нечет
  973.                 JR Z,.F9                        ; если нечет, то
  974.                 INC D                           ; увеличиваем размер еще на 256 байт
  975. .F9             CALL BCDE200                    ; делим на 512 (на размер сектор)
  976.                 PUSH DE
  977.                 EXX
  978.                 POP HL
  979.                 EXX
  980.                 LD A,(BYTSSEC)                  ; взяли размер кластера в секторах
  981.                 LD IXH,A                        ; сохранили
  982.                 POP DE
  983.                 POP BC
  984.                 LD HL,0x8000                    ; адрес загрузки
  985.  
  986. ; HX - размер кластера
  987. ; HL' - кол-во секторов файла
  988. ; BCDE - номер стартового кластера
  989. ; LY - стартовая страница загрузки
  990.  
  991.                 LD A,IYL                        ; восстановили страницу загрузки
  992.                 AND A
  993.                 JR NZ,CP_PAGE                   ; проверка для загрузки в страницу 0
  994.                 OUT (MPAG),A                    ; включаем страницу 0
  995.                 EXX
  996.                 LD A,L
  997.                 LD DE,0x41
  998.                 SBC HL,DE
  999.                 JR C,.F7                        ; если файл 0x41 и более секторов
  1000.                 LD A,0x40                       ; то грузим только 0x40 первых секторов
  1001. .F7             EXX
  1002.                 JP LDMINI                       ; переходим на загрузку
  1003.  
  1004. ; загрузка в страницу 1 запрещена
  1005. CP_PAGE         DEC A
  1006.                 LD A,0xAA
  1007.                 JP Z,WR_STAT
  1008.                 LD A,IYL
  1009.  
  1010. ; включаем страницу загрузки
  1011. LDFILE0         OUT (MPAG),A                    ; включаем заданную страницу для загрузки
  1012.  
  1013. ; загрузка в страницы 02...7F
  1014. LD_FILE         EXX
  1015.                 LD E,IXH
  1016.                 LD D,0                          ; DE = размер кластера в секторах
  1017.                 AND A
  1018.                 SBC HL,DE                       ; сверяем с количеством секторов для загрузки
  1019.                 LD IXL,IXH                      ; LX = количество секторов для загрузки
  1020.                 EXX
  1021.                 JR NC,.L1
  1022.                 EXX                             ; секторов для загрузки меньше размера кластера
  1023.                 ADD HL,DE      
  1024.                 LD A,L
  1025.                 LD IXL,A                        ; LX = количество секторов для загрузки
  1026.                 EXX
  1027.  
  1028. .L1             PUSH BC
  1029.                 PUSH DE
  1030.                 PUSH HL
  1031.                 CALL REALSEC                    ; перевели номер кластера в номер реального сектора
  1032.                 LD A,IXL
  1033.                 CP 0x41                         ; количество секторов для загрузки больше 0x40?
  1034.                 JR C,.L2
  1035.                 LD A,0x40                       ; будем грузить 0x40 секторов
  1036. .L2             POP HL
  1037.                 LD IYH,A
  1038.                 CALL RDMULTI                    ; загружаем сектора
  1039.                 LD A,IXH
  1040.                 AND 0x80
  1041.                 JR Z,.L5
  1042.                 LD A,IXL
  1043.                 SUB IYH
  1044.                 JR Z,.L3
  1045.                 JR C,.L3
  1046.                 LD HL,0x40
  1047.                 ADD HL,DE
  1048.                 EX DE,HL
  1049.                 LD HL,0
  1050.                 ADC HL,BC
  1051.                 LD B,H
  1052.                 LD C,L
  1053.                 LD L,A
  1054.                 INC IYL
  1055.                 LD A,IYL
  1056.                 CP 0x40
  1057.                 JR C,.L4
  1058. .L3             INC SP
  1059.                 INC SP
  1060.                 INC SP
  1061.                 INC SP
  1062.                 JR LDEFILE
  1063.  
  1064. .L4             OUT (MPAG),A                    ; следующая страница
  1065.                 LD A,L
  1066.                 LD HL,0x8000
  1067.                 CALL RDMULTI
  1068. .L5             POP DE
  1069.                 POP BC
  1070.                 PUSH HL
  1071.                 CALL RDFATZP
  1072.                 CALL LST_CLS
  1073.                 POP HL
  1074.                 JR C,LDEFILE
  1075.                 LD A,IXL
  1076.                 CP IXH
  1077.                 JR C,LDEFILE
  1078.                 LD A,H
  1079.                 AND A
  1080.                 JR NZ,LD_FILE
  1081.                 LD HL,0x8000
  1082.                 INC IYL
  1083.                 LD A,IYL
  1084.                 CP 0x40
  1085.                 JR C,LDFILE0
  1086. LDEFILE         XOR A
  1087.                 JP WR_STAT
  1088.  
  1089. LDMINI          EXX
  1090.                 LD L,A
  1091.                 LD A,IXH
  1092.                 LD H,A
  1093.                 CP L
  1094.                 JR C,$+3
  1095.                 LD A,L
  1096.                 EXX
  1097.                 PUSH BC
  1098.                 PUSH DE
  1099.                 PUSH AF
  1100.                 PUSH HL
  1101.                 CALL REALSEC
  1102.                 POP HL
  1103.                 POP AF
  1104.                 CALL RDMULTI
  1105.                 POP DE
  1106.                 POP BC
  1107.                 LD A,H
  1108.                 AND A
  1109.                 RET Z
  1110.                 PUSH HL
  1111.                 CALL RDFATZP
  1112.                 CALL LST_CLS
  1113.                 POP HL
  1114.                 JR C,LDEFILE
  1115.                 EXX
  1116.                 LD A,L
  1117.                 SUB H
  1118.                 EXX
  1119.                 JR NC,LDMINI
  1120.                 JR LDEFILE
  1121.  
  1122. SAVEZP          LD (HL),E
  1123.                 INC HL
  1124.                 LD (HL),D
  1125.                 INC HL
  1126.                 LD (HL),C
  1127.                 INC HL
  1128.                 LD (HL),B
  1129.                 INC HL
  1130.                 RET
  1131.  
  1132. LOADZP          LD E,(HL)
  1133.                 INC HL
  1134.                 LD D,(HL)
  1135.                 INC HL
  1136.                 LD C,(HL)
  1137.                 INC HL
  1138.                 LD B,(HL)
  1139.                 INC HL
  1140.                 RET
  1141.  
  1142. ; чтение сектора DIR по номеру BC
  1143. RDDIRSC         PUSH BC
  1144.                 LD D,B
  1145.                 LD E,C
  1146.                 LD BC,0
  1147.                 LD A,0x10
  1148.                 CALL BCDE_A
  1149.                 LD A,E
  1150.                 PUSH AF
  1151.                 LD A,(BYTSSEC)
  1152.                 PUSH AF
  1153.                 CALL BCDE_A
  1154.                 LD HL,TDIRCLS
  1155.                 EX DE,HL
  1156.                 ADD HL,HL
  1157.                 ADD HL,HL
  1158.                 ADD HL,DE
  1159.                 CALL LOADZP
  1160.                 CALL REALSEC
  1161.                 POP AF
  1162.                 DEC A
  1163.                 LD L,A
  1164.                 POP AF
  1165.                 AND L
  1166.                 LD L,A
  1167.                 LD H,0
  1168.                 ADD HL,DE
  1169.                 EX DE,HL
  1170.                 LD HL,0
  1171.                 ADC HL,BC
  1172.                 LD B,H
  1173.                 LD C,L
  1174.                 CALL LOADLST
  1175.                 POP BC
  1176.                 RET
  1177.  
  1178. ; проверка на последний кластер в цепочке
  1179. LST_CLS         LD A,(CAL_FAT)                  ; зависит от разрядности фата
  1180.                 AND A
  1181.                 JR NZ,LST_CL1
  1182.                 LD HL,0x0FF7                    ; проверка для ФАТ12
  1183.                 SBC HL,DE
  1184.                 RET
  1185.  
  1186. LST_CL1         DEC A
  1187.                 JR NZ,LST_CL2
  1188. LST_CL3         LD HL,0xFFF7                    ; проверкам для ФАТ16 и младших бит ФАТ32
  1189.                 SBC HL,DE
  1190.                 RET
  1191.  
  1192. LST_CL2         LD HL,0x0FFF                    ; проверка для старших бит ФАТ32
  1193.                 SBC HL,BC
  1194.                 RET NZ
  1195.                 JR LST_CL3
  1196.  
  1197. ; чтение следующего номера кластера в цепочке
  1198. RDFATZP         LD A,(CAL_FAT)                  ; чтение зависит от разрадности фата
  1199.                 AND A
  1200.                 JR Z,RDFATS0                    ; переход вперед для ФАТ12
  1201.                 DEC A
  1202.                 JR Z,RDFATS1                    ; переход вперед для ФАТ16
  1203.                 EX DE,HL                        ; здесь чтение для ФАТ32
  1204.                 ADD HL,HL
  1205.                 EX DE,HL
  1206.                 LD HL,0
  1207.                 ADC HL,BC
  1208.                 ADC HL,BC                       ; умножили номер кластера на 2
  1209.                 LD A,E
  1210.                 LD E,D
  1211.                 LD D,L
  1212.                 LD C,H
  1213.                 LD B,0                          ; разделили номер кластера на 256
  1214.                 CALL RDFATS2                    ; читаем младшие 16 бит используя чтение для ФАТ16
  1215.                 INC HL
  1216.                 LD C,(HL)
  1217.                 INC HL
  1218.                 LD B,(HL)                       ; прочитали последующие старшие 16 бит
  1219.                 RET
  1220.  
  1221. ; чтение 16 битного номера кластера из цепочки для ФАТ16
  1222. RDFATS1         LD BC,0
  1223.                 LD A,E
  1224.                 LD E,D
  1225.                 LD D,C                          ; разделили номер кластера на 256, старшие 16 бит =0
  1226. RDFATS2         PUSH AF                         ; общее чтение 16 битного номера кластера для ФАТ16/32
  1227.                 PUSH BC
  1228.                 LD HL,FATSTR
  1229.                 CALL BCDEHLP                    ; прибавили смещение от начала фат таблицы
  1230.                 CALL LOADLST                    ; загрузили вычисленный номер сектора
  1231.                 POP BC
  1232.                 POP AF
  1233.                 LD E,A
  1234.                 LD D,0
  1235.                 ADD HL,DE
  1236.                 ADD HL,DE                       ; вычислили смещение до нужного номера в загруженном секторе
  1237.                 LD E,(HL)
  1238.                 INC HL
  1239.                 LD D,(HL)                       ; получили 16 бит номера кластера
  1240.                 RET
  1241.  
  1242. ; чтение 12 битного номера кластера из цепочки для ФАТ12
  1243. RDFATS0         LD H,D
  1244.                 LD L,E
  1245.                 ADD HL,HL
  1246.                 ADD HL,DE                       ; HL = HL * 3
  1247.                 SRL H
  1248.                 RR L                            ; HL = HL / 2 - в итоге умножили номер кластера на 1,5
  1249.                 LD A,E                          ; A - нам интересен только бит номер старого номера кластера
  1250.                 LD E,H
  1251.                 LD D,0
  1252.                 LD B,D
  1253.                 LD C,D                          ; разделили номер кластера на 256
  1254.                 SRL E
  1255.                 PUSH AF
  1256.                 PUSH HL
  1257.                 LD HL,FATSTR
  1258.                 CALL BCDEHLP                    ; прибавили смещение от начала фат таблицы
  1259.                 CALL LOADLST                    ; загрузили вывчисленный сектор
  1260.                 POP BC
  1261.                 LD A,B
  1262.                 AND 1
  1263.                 LD B,A                          ; BC = смещение в загруженном секторе
  1264.                 ADD HL,BC                       ; HL = адрес откуда читать байты номера кластера
  1265.                 LD B,(HL)                       ; прочитали младшую часть номера кластера
  1266.                 INC HL                          ; адрес следующего байта
  1267.                 LD A,H
  1268.                 CP HIGH (BUF_512)+2             ; проверка на переход границы загруженного сектора
  1269.                 JR NZ,RDFATS4
  1270.                 PUSH BC                         ; выход за пределы текущего загруженного сектора
  1271.                 LD BC,0
  1272.                 INC DE
  1273.                 CALL LOADLST                    ; загружаем следующий сектор фат таблицы
  1274.                 POP BC
  1275. RDFATS4         POP AF
  1276.                 LD D,(HL)                       ; читаем старшие биты номера кластера
  1277.                 LD E,B                          ; теперь DE = номер следующего кластера в цепочке
  1278.                 LD BC,0
  1279.                 RRA                             ; проверяем бит 0 старого номера кластера
  1280.                 JR NC,RDFATS3
  1281.                 SRL D                           ; сдвигаем номер прочитанного номера кластера в младшие 12 бит
  1282.                 RR E
  1283.                 SRL D
  1284.                 RR E
  1285.                 SRL D
  1286.                 RR E
  1287.                 SRL D
  1288.                 RR E
  1289. RDFATS3         LD A,D
  1290.                 AND 0x0F
  1291.                 LD D,A                          ; сбросили незначащие старшие 4 бита у полученного номера кластера
  1292.                 RET
  1293.  
  1294. ; вычисление реального сектора
  1295. ; на входе BCDE = номер кластера FAT
  1296. ; на выходе BCDE = номер реального сектора
  1297. REALSEC         LD A,B
  1298.                 OR C
  1299.                 OR D
  1300.                 OR E
  1301.                 JR NZ,REALSE1                   ; BCDE = 0?
  1302.                 LD HL,SEC_FAT                   ; это root директория у ФАТ12/16
  1303.                 LD DE,(FATSTR)                  ; местоположение ROOT диры сразу после фат таблицы
  1304.                 LD BC,(FATSTR+2)
  1305.                 PUSH HL
  1306.                 CALL BCDEHLP                    ; прибавили к началу фат таблицы ее размер
  1307.                 POP HL
  1308.                 JP BCDEHLP                      ; прибавили еще раз и получили номер сектора начала ROOT диры
  1309.  
  1310. REALSE1         LD HL,0xFFFE
  1311.                 EX DE,HL
  1312.                 ADD HL,DE
  1313.                 EX DE,HL
  1314.                 INC HL
  1315.                 ADC HL,BC                       ; HLDE = номер кластера - 2
  1316.                 LD A,(BYTSSEC)                  ; нужно умножить на размер кластера
  1317.                 JR REALSE2
  1318.  
  1319. REALSE3         SLA E
  1320.                 RL D
  1321.                 RL L
  1322.                 RL H
  1323. REALSE2         RRCA
  1324.                 JR NC,REALSE3                   ; умножили на размер кластера
  1325.                 LD B,H
  1326.                 LD C,L
  1327.                 LD HL,STARTRZ
  1328.                 CALL BCDEHLP                    ; прибавили смещение от начала диска
  1329.                 LD HL,FRSTDAT
  1330.                 JP BCDEHLP                      ; прибавили смещение от начала раздела
  1331.  
  1332. ; BCDE = BCDE / 512
  1333. BCDE200         LD E,D
  1334.                 LD D,C
  1335.                 LD C,B
  1336.                 LD B,0
  1337.                 LD A,2
  1338.                 JR BCDE_A
  1339.  
  1340. ; BCDE = BCDE >> A
  1341. BCDE_A1         SRL B
  1342.                 RR C
  1343.                 RR D
  1344.                 RR E
  1345. BCDE_A          RRCA
  1346.                 JR NC,BCDE_A1
  1347.                 RET
  1348.  
  1349. ; BCDE = (ADR) - BCDE
  1350. BCDEHLM         LD A,(HL)
  1351.                 INC HL
  1352.                 SUB E
  1353.                 LD E,A
  1354.                 LD A,(HL)
  1355.                 INC HL
  1356.                 SBC A,D
  1357.                 LD D,A
  1358.                 LD A,(HL)
  1359.                 INC HL
  1360.                 SBC A,C
  1361.                 LD C,A
  1362.                 LD A,(HL)
  1363.                 SBC A,B
  1364.                 LD B,A
  1365.                 RET
  1366.  
  1367. ; BCDE = (ADR) + BCDE
  1368. BCDEHLP         LD A,(HL)
  1369.                 INC HL
  1370.                 ADD A,E
  1371.                 LD E,A
  1372.                 LD A,(HL)
  1373.                 INC HL
  1374.                 ADC A,D
  1375.                 LD D,A
  1376.                 LD A,(HL)
  1377.                 INC HL
  1378.                 ADC A,C
  1379.                 LD C,A
  1380.                 LD A,(HL)
  1381.                 ADC A,B
  1382.                 LD B,A
  1383.                 RET
  1384.  
  1385. ; HLDE = HLDE + BC
  1386. HLDEPBC         EX DE,HL
  1387.                 ADD HL,BC
  1388.                 EX DE,HL
  1389.                 LD BC,0
  1390.                 ADC HL,BC
  1391.                 RET
  1392.  
  1393. ; BCDE = BCDE - (ADR)
  1394. HLBCDEM         LD A,E
  1395.                 SUB (HL)
  1396.                 INC HL
  1397.                 LD E,A
  1398.                 LD A,D
  1399.                 SBC A,(HL)
  1400.                 INC HL
  1401.                 LD D,A
  1402.                 LD A,C
  1403.                 SBC A,(HL)
  1404.                 INC HL
  1405.                 LD C,A
  1406.                 LD A,B
  1407.                 SBC A,(HL)
  1408.                 LD B,A
  1409.                 RET
  1410.  
  1411. ; грузилка одного сектора
  1412. LOADLST         CALL CPNUMSC
  1413.                 JR NZ,LOADLST1
  1414.                 LD HL,BUF_512
  1415.                 RET
  1416.  
  1417. LOADLST1        LD HL,BUF_512                   ; адрес буфера сектора
  1418.                 LD A,1                          ; грузить 1 сектор
  1419.                 PUSH HL
  1420.                 CALL RDMULTI                    ; загрузили сектор
  1421.                 POP HL                          ; на выходе HL=адрес начала буфера загруженного сектора
  1422.                 RET
  1423.  
  1424. ; проверка на уже загруженный сектор
  1425. CPNUMSC         LD HL,LSTLOAD
  1426.                 LD A,(HL)
  1427.                 INC HL
  1428.                 CP E
  1429.                 RET NZ
  1430.                 LD A,(HL)
  1431.                 INC HL
  1432.                 CP D
  1433.                 RET NZ
  1434.                 LD A,(HL)
  1435.                 INC HL
  1436.                 CP C
  1437.                 RET NZ
  1438.                 LD A,(HL)
  1439.                 CP B
  1440.                 RET
  1441.  
  1442. ; подача команды в SD карту без параметров
  1443. OUTCOM          PUSH BC
  1444.                 LD BC,0x0600+SD_SEND            ; выдать в порт 6 байт
  1445.                 OTIR
  1446.                 POP BC
  1447.                 RET
  1448.  
  1449. ; выдача в порт SD карты команды с параметром 0
  1450. OUT_COM         PUSH BC
  1451.                 LD BC,SD_SEND
  1452.                 in (c) ;in f,(c)
  1453.                 in (c) ;in f,(c)
  1454.                 OUT (C),A                       ; отправили код команды
  1455.                 XOR A
  1456.                 OUT (C),A                       ; биты 31-24 параметра
  1457.                 NOP
  1458.                 OUT (C),A                       ; биты 23-16 параметра
  1459.                 NOP
  1460.                 OUT (C),A                       ; биты 15-8 параметра
  1461.                 NOP
  1462.                 OUT (C),A                       ; биты 7-0 параметра
  1463.                 DEC A
  1464.                 OUT (C),A                       ; без CRC16
  1465.                 POP BC
  1466.                 RET
  1467.  
  1468. SECM200         PUSH HL
  1469.                 PUSH BC
  1470.                 LD A,CMD_58
  1471.                 LD BC,SD_RSTR
  1472.                 CALL OUT_COM
  1473.                 CALL IN_OOUT
  1474.                 IN H,(C)
  1475.                 NOP
  1476.                 IN A,(C)
  1477.                 NOP
  1478.                 IN A,(C)
  1479.                 NOP
  1480.                 IN A,(C)
  1481.                 BIT 6,H
  1482.                 POP HL
  1483.                 JR NZ,.L1
  1484.                 EX DE,HL
  1485.                 ADD HL,HL
  1486.                 EX DE,HL
  1487.                 ADC HL,HL
  1488.                 LD H,L
  1489.                 LD L,D
  1490.                 LD D,E
  1491.                 LD E,0
  1492. .L1             LD A,CMD_18
  1493.                 LD C,SD_SEND
  1494.                 in (c) ;in f,(c)
  1495.                 in (c) ;in f,(c)
  1496.                 OUT (C),A
  1497.                 NOP
  1498.                 OUT (C),H
  1499.                 NOP
  1500.                 OUT (C),L
  1501.                 NOP
  1502.                 OUT (C),D
  1503.                 NOP
  1504.                 OUT (C),E
  1505.                 LD A,0xFF
  1506.                 OUT (C),A
  1507.                 POP HL
  1508.                 RET
  1509.  
  1510. IN_OOUT         EXX
  1511.                 LD DE,0x30FF
  1512. .L1             IN A,(SD_RSTR)
  1513.                 CP E
  1514.                 JR NZ,.L2
  1515.                 DEC D
  1516.                 JR NZ,.L1
  1517. .L2             EXX
  1518.                 RET
  1519.  
  1520. CMD00           DB 0x40,0x00,0x00,0x00,0x00,0x95;GO_IDLE_STATE
  1521. CMD08           DB 0x48,0x00,0x00,0x01,0xAA,0x87;SEND_IF_COND
  1522. CMD16           DB 0x50,0x00,0x00,0x02,0x00,0xFF;SET_BLOCKEN
  1523.  
  1524. ; много секторное чтение с SD карты
  1525. RDMULTI         EX AF,AF'
  1526.                 CALL SECM200
  1527.                 EX AF,AF'
  1528.                 LD BC,SD_RSTR
  1529. .L1             EX AF,AF'
  1530. .L2             CALL IN_OOUT
  1531.                 CP 0xFE
  1532.                 JR NZ,.L2
  1533.                 INIR
  1534.                 NOP
  1535.                 INIR
  1536.                 NOP
  1537.                 IN A,(C)
  1538.                 NOP
  1539.                 IN A,(C)
  1540.                 EX AF,AF'
  1541.                 DEC A
  1542.                 JR NZ,.L1
  1543.                 LD A,CMD_12
  1544.                 CALL OUT_COM
  1545. .L3             CALL IN_OOUT
  1546.                 INC A
  1547.                 JR NZ,.L3
  1548.                 RET
  1549.  
  1550. ; выборка номера кластера из файлового описателя
  1551. RD_CLAS         EX DE,HL
  1552.                 LD DE,0x14                      ; старшие 16 бит читаем из смещения +20
  1553.                 ADD HL,DE
  1554.                 LD C,(HL)
  1555.                 INC HL
  1556.                 LD B,(HL)
  1557.                 LD E,5                          ; младшие 16 бит читаем из смещения +26
  1558.                 ADD HL,DE
  1559.                 LD E,(HL)
  1560.                 INC HL
  1561.                 LD D,(HL)
  1562.                 INC HL
  1563.                 RET
  1564.  
  1565. ; проверка по маске
  1566. COMPARE         LD DE,FB_EXT
  1567.                 LD B,0x0B
  1568.                 LD A,(DE)
  1569.                 CP (HL)
  1570.                 RET NZ
  1571.                 INC HL
  1572.                 INC DE
  1573.                 DJNZ $-5
  1574.                 RET
  1575.  
  1576. ; распаковщик пути к файлу
  1577. FNDBUF          LD BC,0x0802
  1578.                 LD DE,FB_EXT
  1579. FNDBUF4         LD A,(HL)
  1580.                 INC HL
  1581.                 CP "."
  1582.                 JR Z,FNDBUF2
  1583.                 CP "/"
  1584.                 JR Z,FNDBUF5
  1585.                 LD (DE),A
  1586.                 INC DE
  1587.                 DJNZ FNDBUF4
  1588.                 LD A,(HL)
  1589.                 AND A
  1590.                 RET Z
  1591.                 INC HL
  1592.                 JR FNDBUF3
  1593.  
  1594. FNDBUF5         LD A,C
  1595.                 AND A
  1596.                 RET Z
  1597. FNDBUF2         LD A,B
  1598.                 AND A
  1599.                 JR Z,FNDBUF3
  1600.                 LD A," "
  1601.                 LD (DE),A
  1602.                 INC DE
  1603.                 DJNZ $-2
  1604. FNDBUF3         LD B,3
  1605.                 DEC C
  1606.                 DEC HL
  1607.                 LD A,(HL)
  1608.                 CP "/"
  1609.                 JR Z,FNDBUF4
  1610.                 INC HL
  1611.                 JR FNDBUF4
  1612. RAMCEND
  1613.                 DEPHASE
  1614.