;===================[ Функции распределения памяти ]===================; ; ;----------------------------------------------------------------------; ; Определение объема памяти. ; Выход: BC - FREE MEM в блоках по 16k, HL - FULL MEM EMM.GetMemSize: IN A,(SLOT2) LD B,A LD A,SYS_PAGE OUT (SLOT2),A LD HL,SYS_PAGE.RAMD_FAT-#4000 LD C,0 .loop: LD A,(HL) INC L JR Z,.exit AND A JR NZ,.loop INC C JR .loop .exit: LD HL,#100 LD A,B LD B,0 OUT (SLOT2),A RET ;----------------------------------------------------------------------; ; ; ;----------------------------------------------------------------------; ; Инициализация распределения памяти. EMM.InitMem: PUSH BC PUSH HL PUSH DE IN A,(SLOT2) LD C,A LD A,SYS_PAGE OUT (SLOT2),A LD HL,SYS_PAGE.RAMD_FAT-#4000 ; Адрес FAT ОЗУ. ; обнуляем таблицу .loopFree: LD (HL),0 INC L JR NZ,.loopFree ; резервируем спец.страницы и страницы ZX LD B,RESERVED_PAGES.Blocks LD DE,RESERVED_PAGES ; таблица занятых системных страниц .loop: LD A,(DE) CP #FF JR Z,.exitLoop .loopBlk: INC DE LD L,A LD A,(DE) LD (HL),A CP #FF JR NZ,.loopBlk .exitLoop: INC DE DJNZ .loop LD L,A LD (HL),A ; Инициализация ключей RAM-Disks LD HL,SYS_PAGE.RAMD_KEYS-#4000 LD B,SYS_PAGE.RAMD_KEYS.NUM .loop2: LD (HL),0 INC L DJNZ .loop2 LD A,C OUT (SLOT2),A POP DE POP HL POP BC RET ;---------------------------------------------------------------------[] RESERVED_PAGES: ;; Block #1 - можно освободить по ID 1 DB 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 ; for Spectrum ; эмулятор ПЗУ ;!FIXIT ROM-Emulator сделать динамические страницы DB #42,#43,#44,#45,#46,47;,#48,#49,#4A,#4B ; For (BASIC128, BASIC48, TRDOS, SCORP_ROM)*2, vBIOS, vEXTENSION DB #FF ; End of the block ; ; ;; Block #2 - нельзя освобождать DB 0 ; for Spectrum DB DCP_PAGE ; Ports map DB Spec_Page ; Page for Spectrum mode ; Screen pages DB #50,#51,#52,#53,#54,#55,#56,#57 DB #58,#59,#5A,#5B,#5C,#5D,#5E,#5F ; ;DB MODE_PAGE ; ????? DB CBL.BUFFER_PAGE ; Page for CBL audio DB SYS_PAGE ; Page for system (BIOS) variables DB #FF ; End of the block ; .Blocks EQU 2 ;----------------------------------------------------------------------; ; ; ;----------------------------------------------------------------------; ; Получить блок памяти N bytes, ; Вход: B - число необходимых блоков ; Выход: L,A - КЛЮЧ RAM-Disk/код ошибки ; CF - признак ошибки ;EMM_FN2M: EMM.GetMem: ;PUSH DE PUSH BC IN A,(SLOT2) EX AF,AF' LD A,SYS_PAGE OUT (SLOT2),A LD C,B ; сохранить число нужных блоков LD HL,SYS_PAGE.RAMD_FAT-#4000 ; Цикл проверки наличия нужных блоков. .loop: DEC L JR Z,.noRAM LD A,(HL) AND A JR NZ,.loop DJNZ .loop ; Место есть ! LD B,C ; Восстановить нужный объем диска LD C,#FF ; МЕТКА КОНЦА RAM-Disk LD HL,SYS_PAGE.RAMD_FAT-#4000 ; Заполнить RAMD_FAT .loop2: DEC L LD A,(HL) AND A JR NZ,.loop2 LD (HL),C LD C,L DJNZ .loop2 ; L - указатель цепочки. EX AF,AF' OUT (SLOT2),A LD A,L AND A POP BC ;POP DE RET .noRAM: LD L,1 ; НЕТ ПАМЯТИ EX AF,AF' OUT (SLOT2),A LD A,L SCF POP BC ;POP DE RET ;----------------------------------------------------------------------; ; ; ;----------------------------------------------------------------------; ; Получить блок памяти N bytes, для RAM-Disk A ; Вход: B - число необходимых блоков, A - RAM-Disk ; Выход: L,A - КЛЮЧ RAM-Disk/код ошибки ; CF - признак ошибки ;EMM.GetMem: EMM.GetMemRMD: PUSH AF CALL EMM.GetMem JR C,.error1 LD B,A POP AF CALL BLK_TO_RAMD RET NC .error2: LD L,2 ; RAM-Disk занят ;!TODO перечислить все варианты ошибок и их номера как для ДСС RET .error1: POP AF ; нет памяти LD L,1 SCF RET ;----------------------------------------------------------------------; ; ;----------------------------------------------------------------------; ; Освободить блок памяти ключа K ; Вход: A - КЛЮЧ RAM-Disk EMM.FreeMemRMD: CALL GET_RAMD_ST RET C SCF RET Z LD C,A IN A,(SLOT2) LD B,A LD A,SYS_PAGE OUT (SLOT2),A LD (HL),0 LD A,B OUT (SLOT2),A LD A,C ;JR EMM.FreeMem ;------[ ; Освободить блок памяти ; Вход: A - НАЧАЛО ЦЕПОЧКИ ;EMM_FN3M: EMM.FreeMem: AND A SCF RET Z LD L,A IN A,(SLOT2) EX AF,AF' LD A,SYS_PAGE OUT (SLOT2),A LD H,high (SYS_PAGE.RAMD_FAT - #4000) LD A,L EMM_F3M_L1: LD L,A LD A,(HL) ; следующий блок AND A JR Z,EMM_FN3M_ERR LD (HL),0 ; Освободить CP #FF ; Если не конец JR NZ,EMM_F3M_L1 ; продолжать EX AF,AF' OUT (SLOT2),A LD A,0 ;!FIXIT недокументировано AND A RET EMM_FN3M_ERR: EX AF,AF' OUT (SLOT2),A LD A,2 ;!FIXIT недокументировано SCF RET ;----------------------------------------------------------------------; ; ; WARNING!!! не трогать DE ;----------------------------------------------------------------------; ; Получить страницу N ключа K ; Вход: A - КЛЮЧ RAM-Disk, B - номер страницы ; Выход: A - страница EMM.GetMemPageRMD: CALL GET_RAMD_ST RET C SCF RET Z ;JR EMM.GetMemPage ;------[ ; Получить страницу N блока K ; Вход: A - блок, B - номер страницы ; Выход: A - страница, IF CF - A=0 - нет блока, A=FF - END ;EMM_FN4M: EMM.GetMemPage: LD L,A IN A,(SLOT2) EX AF,AF' LD A,SYS_PAGE OUT (SLOT2),A INC B LD H,high (SYS_PAGE.RAMD_FAT - #4000) EMM_F4M_L1: LD A,(HL) AND A JR Z,EMM_F4M_ERR DEC B JR Z,EMM_F4M_END LD L,A CP #FF JR NZ,EMM_F4M_L1 EMM_F4M_ERR: LD L,A EX AF,AF' OUT (SLOT2),A LD A,L SCF RET EMM_F4M_END: EX AF,AF' OUT (SLOT2),A LD A,L AND A RET ;----------------------------------------------------------------------; ; ; ;----------------------------------------------------------------------; ; Получить следующую страницу по FAT ; Вход: A - страница ОЗУ ; Выход: A - следующая страница ОЗУ ;EMM_FN5: EMM.GetMemPageNext: LD L,A AND A SCF RET Z IN A,(SLOT2) LD H,A LD A,SYS_PAGE OUT (SLOT2),A LD A,H LD H,high (SYS_PAGE.RAMD_FAT - #4000) LD L,(HL) OUT (SLOT2),A LD A,L AND A SCF RET Z AND A RET ;----------------------------------------------------------------------; ; ; ;----------------------------------------------------------------------; ; Получить список страниц блока в HL ; Вход: A - блок, HL - адрес буфера - 256 байт. ; Выход: HL - адрес блока, B - длина блока в страницах ОЗУ ;EMM_FN5M: EMM.GetMemBlkPages: PUSH DE PUSH HL EX DE,HL LD B,0 LD L,A .loop: LD A,L LD (DE),A INC DE AND A JR Z,.error CP #FF JR Z,.end IN A,(SLOT2) LD C,A LD A,SYS_PAGE OUT (SLOT2),A LD H,high (SYS_PAGE.RAMD_FAT - #4000) LD L,(HL) LD A,C OUT (SLOT2),A INC B JR NZ,.loop .error: SCF POP HL POP DE RET .end: POP HL POP DE AND A RET ;----------------------------------------------------------------------; ; ; ;----------------------------------------------------------------------; ;RAMD_R_W: ; ╔════════════════════════════════════════════════╗ ; ║ RD/WR SECTOR ║\ ; ║ HL - BUFER ║\ ; ║ DE - ABS sector в 256b блоках ║\ ; ║ B - число данных в 256b блоках ║\ ; ║ A - block RAM ║\ ; ║ A' - команда чтение/запись/чтение ROM Disk ║\ ; ║ 0 - read, 255 - write, 70 - read ROM DISK ║\ ; ║ ** NOT USED TR-DOS VARS ** ║\ ; ╚════════════════════════════════════════════════╝\ ; \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ BLK_RD_WR: AND A SCF RET Z ; ; сохраняем состояние прерываний LD C,A LD A,R PUSH AF LD A,C DI CALL .start ; восстанавливаем состояние прерываний EX AF,AF' POP AF JP PO,.noInterrupts EI .noInterrupts: EX AF,AF' RET ; .start: EX AF,AF' AND A ; 0 - read JR Z,.reset_Z CP #FF ; write JR Z,.keep_Z CP 5 ; old read JR Z,.reset_Z CP 6 ; old write JR Z,.keep_Z CP #46 JP Z,ROM_DISK EX AF,AF' SCF RET .reset_Z: INC A ; set Z for WRITE .keep_Z: EX AF,AF' ; PUSH HL PUSH BC LD C,SLOT2 IN B,(C) ld h,a LD A,SYS_PAGE OUT (SLOT2),A ld a,h LD H,high (SYS_PAGE.RAMD_FAT - #4000) LD L,A INC D RAMD_LOOP_D: DEC D JR Z,NOT_FOUR_BLK LD L,(HL) LD L,(HL) LD L,(HL) LD L,(HL) JR RAMD_LOOP_D NOT_FOUR_BLK: LD A,E .loop: SUB #40 JR C,NOT_ONE_BLK LD L,(HL) JR .loop NOT_ONE_BLK: AND #3F LD D,A ; DE - ADRESS in RAM-Disk LD E,0 LD A,L ; L - текущий банк RAM-Disk OUT (C),B ; восстановить страницу POP BC ; длина данных POP HL ; адрес буфера BIT 7,H JR NZ,BLK_PAGE1 ; !!!!! JR NZ,BLK_PAGE1 ? BLK_PAGE3: ; !TODO переделать на SLOT ????? LD C,SLOT3 IN C,(C) OUT (SLOT3),A SET 7,D SET 6,D JR BLK_CONT1 BLK_PAGE1: LD C,SLOT1 IN C,(C) OUT (SLOT1),A RES 7,D SET 6,D BLK_CONT1: ; DE - RamDisk, HL - data EX AF,AF' JR Z,NO_EX_RW1 ; WRITE EX DE,HL ; for READ NO_EX_RW1: EX AF,AF' LD A,16 BLK_LL1: DUP 16 LDI EDUP DEC A JR NZ,BLK_LL1 EX AF,AF' JR Z,NO_EX_RW2 ; WRITE EX DE,HL ; for READ NO_EX_RW2: EX AF,AF' ; DEC C прокрутился 256 раз и вернулся INC B ; B уже уменьшился на 1, DEC B JP Z,BLK_EXIT_1 BIT 6,D JP NZ,BLK_CONT1 BIT 7,D JR Z,BLK_PAGE3_X IN A,(SLOT1) LD E,A LD D,#42 LD A,SYS_PAGE OUT (SLOT1),A LD A,(DE) OUT (SLOT1),A LD DE,#4000 JP BLK_CONT1 BLK_PAGE3_X: IN A,(SLOT3) LD E,A LD D,#C2 LD A,SYS_PAGE OUT (SLOT3),A LD A,(DE) OUT (SLOT3),A LD DE,#C000 BIT 7,H JP Z,BLK_CONT1 LD E,A LD A,C OUT (SLOT3),A IN A,(SLOT1) LD C,A LD A,E OUT (SLOT1),A LD DE,#4000 JP BLK_CONT1 BLK_EXIT_1: LD A,D DEC A RLCA LD A,C JR C,BLK_EXIT_2 OUT (SLOT1),A RET BLK_EXIT_2: OUT (SLOT3),A AND A RET ;----------------------------------------------------------------------; ; ; ;----------------------------------------------------------------------; ;**************************************** ;!!!!! READ_ROM_PAGE_X чтение последних ; 256 байтов ПЗУ в служебную страницу зачем-то ; READ_ROM_PAGE_X: ; LD DE,0 ; LD BC,#100 ; один сектор ; PUSH DE ; PUSH BC ; LD HL,#3F00 ; LD DE,#FF00 ; LD A,#1F ; last page ROM ; JR ROM_DISK.loopRead ;**************************************** ; Чтение с ROM-Disk ; HL - адрес, куда читать ; DE - номер сектора (считать по 256b сектор) ; B - число секторов ; A' - размер сектора (1 - 256b, 2 - 512 b) ROM_DISK: ; сохраняем состояние прерываний ;LD A,R EX AF,AF' LD C,0 ; счетчик DEC A JR Z,.loop ;JR Z,.start DEC A SCF RET NZ EX DE,HL ADD HL,HL EX DE,HL LD A,B ADD A,A LD B,A ;!!!!! RET C DI CALL .loop ; ; восстанавливаем состояние прерываний ; EX AF,AF' ; JP PO,.noInterrupts ; EI ; .noInterrupts: ; EX AF,AF' ; ; RET C AND A RR D RR E XOR A RET ; .start: ; DI ; CALL .loop ; ; восстанавливаем состояние прерываний ; EX AF,AF' ; JP PO,.noInterrupts2 ; EI ; .noInterrupts2: ; EX AF,AF' ; ; ; RET .loop: PUSH DE ; номер сектора PUSH BC LD A,E AND 63 ; ADRESS in ROM-Page PUSH AF ; сохранить адрес EX DE,HL ; DE - адрес буфера ADD HL,HL ADD HL,HL ; H - номер банки LD A,(ROM_DISK.Pages.Number) INC H CP H LD L,H LD H, high ROM_DISK.Pages.Number ; ROM-Disk pages! LD A,(HL) ; PAGE-ROM POP HL ; восстановить адрес в ROM-Page LD L,0 ; если далеко захотели - выход с ошибкой JR C,.errorExit ; ROM-Disk-end ; DE - буфер ; HL - адрес в ROM ; B - число секторов ; A - ROM-Page .loopRead: PUSH HL ; откуда PUSH DE ; куда LD HL,-.stackDepth - .readProcedure.size ; memory stack use! ADD HL,SP ; stack PUSH HL ; адрес программы .readProcedure LD DE,.readProcedure ; перенести программу на стек EX DE,HL LD BC,.readProcedure.size LDIR ; программа на стеке LD BC,#100 ; длина сектора RET ; исполнить программу .readProcedure, на стеке адреса буфера и ROM ; DE - next address ; HL - ROM address .readNext: POP BC ; число секторов INC C ; счетчик считанных секторов DEC B ; сектора кончились? JR Z,.normExit BIT 6,H ; чтение не закончено PUSH BC ; сохранить счетчики JR Z,.loopRead ; читать дальше POP BC POP HL ; номер сектора LD A,B LD B,0 ADD HL,BC LD B,A ; вычислить след.сектор EX DE,HL ; теперь HL - адрес, DE сектор, B - сколько еще читать JP .loop ; начать все снова! ; чтение закончено .normExit: POP HL ; сектор, откуда велось чтение ADD HL,BC ; по возврату: HL - след.адрес EX DE,HL ; DE - след.сектор AND A RET ; ошибка .errorExit: ; !TODO сделать, чтоб на выходе показывалось количество прочитанных секторов POP BC POP DE SCF RET ; процедура, переносимая на стек для чтения из ROM-Disk ; осторожнее с PUSH, если надо много, то увеличивай .stackDepth .readProcedure: POP DE ; куда POP HL ; откуда OUT (ROM.SLOT0),A ; ROM_PAGE LDIR ; здесь читается из ROM-Disk LD B,A XOR A OUT (ROM.SLOT0),A OUT (SYS_PORT.ROM),A LD A,B JP .readNext .stackDepth EQU 8 ; расстояние от конца процедуры до вершины стека. .readProcedure.size EQU $-.readProcedure ;----------------------------------------------------------------------; ; ; ;----------------------------------------------------------------------; ; вход: DE - ram_disk trk_sec, A - RAM-Disk ; выход: HL - адрес, A - page RAMD_CALC_PAGE: CP 16 CCF RET C ; НЕТ ТАКОГО RAM-Disk PUSH AF LD H,D LD L,E ADD HL,HL ADD HL,HL LD B,H LD A,E OR #C0 LD C,A ; C - часть адреса, B - страница POP AF CALL EMM.GetMemPageRMD ; ПОЛУЧИТЬ СТРАНИЦУ LD L,0 LD H,C RET ;----------------------------------------------------------------------; ; ; ;----------------------------------------------------------------------; ; Вход: ; A - RAM Disk ID ; Выход: ; A - Number (0..15) GET_RAMD_NUM: EX AF,AF' IN A,(SLOT2) EX AF,AF' LD BC,SYS_PAGE * 256 + SLOT2 OUT (C),B LD HL,SYS_PAGE.RAMD_KEYS-#4000 LD BC,SYS_PAGE.RAMD_KEYS.NUM CPIR EX AF,AF' OUT (SLOT2),A EX AF,AF' SCF RET PE DEC L LD A,L SUB low SYS_PAGE.RAMD_KEYS RET ;----------------------------------------------------------------------; ; ; ;----------------------------------------------------------------------; ; на выходе при А = 0 должен быть установлен флаг Z ; DSS надеется, что эта функция не грохает DE GET_RAMD_ST: CP SYS_PAGE.RAMD_KEYS.NUM CCF RET C PUSH BC LD HL,SYS_PAGE.RAMD_KEYS-#4000 ADD A,L LD L,A IN A,(SLOT2) LD B,A LD A,SYS_PAGE OUT (SLOT2),A LD C,(HL) LD A,B OUT (SLOT2),A LD A,C POP BC AND A RET ;----------------------------------------------------------------------; ; ; ;----------------------------------------------------------------------; ; RAM-Disk A, BLK - B BLK_TO_RAMD: CP SYS_PAGE.RAMD_KEYS.NUM CCF RET C PUSH HL LD L,A IN A,(SLOT2) LD C,A LD A,SYS_PAGE OUT (SLOT2),A LD A,L LD HL,SYS_PAGE.RAMD_KEYS-#4000 ADD A,L LD L,A LD A,(HL) ; ключ блока AND A JR NZ,BLK_BUSY ; RAM-Disk занят - ошибка LD (HL),B LD A,C OUT (SLOT2),A LD A,B AND A POP HL RET BLK_BUSY: LD A,C OUT (SLOT2),A SCF POP HL RET ;----------------------------------------------------------------------; ; ; ;----------------------------------------------------------------------; ; RAM-Disk A RAMD_CLEAR: CP SYS_PAGE.RAMD_KEYS.NUM CCF RET C PUSH HL LD L,A IN A,(SLOT2) LD C,A LD A,SYS_PAGE OUT (SLOT2),A LD A,L LD HL,SYS_PAGE.RAMD_KEYS-#4000 ; RAM-Disk свободен ADD A,L LD L,A LD B,A ; запомнить удаляемый рамдиск LD A,(HL) AND A JR Z,BLK_BUSY ; возврат с ошибкой LD (HL),0 LD A,C OUT (SLOT2),A AND A POP HL RET ;----------------------------------------------------------------------; ; ; ;----------------------------------------------------------------------; ; разделить блок памяти на два блока ; A - блок, B - длина первого блока после разделения ; выход: A - блок 1, B - блок 2 EMM.DivMemBlocks: INC B DEC B SCF RET Z DEC B LD E,A CALL EMM.GetMemPage ; получить номер страницы блока RET C LD D,A IN A,(SLOT2) EX AF,AF' LD A,SYS_PAGE OUT (SLOT2),A LD H,high (SYS_PAGE.RAMD_FAT - #4000) LD L,D LD A,(HL) LD (HL),0FFH LD B,A EX AF,AF' OUT (SLOT2),A LD A,E AND A RET ;----------------------------------------------------------------------; ; ; ;----------------------------------------------------------------------; ; слить два блока памяти в один ; А - блок 1, B - блок 2 ; выход: А - блок EMM.MergeMemBlocks: LD E,A IN A,(SLOT2) EX AF,AF' LD A,SYS_PAGE OUT (SLOT2),A LD H,high (SYS_PAGE.RAMD_FAT - #4000) LD L,E LD C,B LD B,0 EMM_ADD_L: LD A,(HL) AND A JR Z,EMM_ADD_ERR CP 0FFH JR Z,EMM_ADD_NEXT LD L,A DJNZ EMM_ADD_L EMM_ADD_ERR: EX AF,AF' OUT (SLOT2),A SCF RET EMM_ADD_NEXT: LD A,C AND A JR Z,EMM_ADD_ERR LD (HL),A EX AF,AF' OUT (SLOT2),A AND A LD A,E RET ;----------------------------------------------------------------------; ;