; ; ; !TODO ; ; [ ] - ключ для загрузки образа в новый рам-диск "/i имя_файла" ; [ ] - ключ для загрузки образа в существующий рам-диск "/i имя_файла /d буква диска" ; [ ] - ключ для сохранения рам-диска в образ "/s буква диска" ; [ ] - ключ для закрытия рам-диска "/с буква диска" ; ; ; Compilation parameters ;-------------[] ;DEVICE SPRINTER ;MMU 2 e, 0 ; нулевая страница в банку 2 и проверка на границы ;OUTPUT './Build/new.bin' ;-------------[] ; Defines section ;-------------[] define NEED_LOADER 0 DEFINE App_EXE_Version 1 ; define NeedSafePort_Y 0 ;-------------[] ; Included LUA section ;-------------[] includelua ;-------------[] ; Included constants section ;-------------[] include 'Shared_Includes/constants/sp2000.inc' include 'Shared_Includes/constants/dss_equ.inc' include 'Shared_Includes/constants/BIOS_equ.inc' ;-------------[] ; Included macroses section ;-------------[] include 'Shared_Includes/macroses/macros.z80' include 'Shared_Includes/macroses/accelerator.z80' ;-------------[] ; Standart EQU section ;-------------[] org_addr EQU #8000 + CLP_Buffer code_addr EQU BEGIN stack_point EQU #C000 stack_buffer EQU 64 program_start EQU BEGIN Loader_length EQU 0 ;-------------[] ; Program EQU section ;-------------[] ; IMG_File: ; .Sectors EQU 2880 ; .RamPages EQU 90 ; STRUCT MEM_BUFFER_BLOCK ; FileID BYTE ; BlockID BYTE ; SavePage BYTE ; PagesBuffer BLOCK IMG_File.RamPages+1 ; ENDS ;-------------[] ; Code start section ;[]-------------------------------------------------------------------[] include 'Shared_Includes/constants/EXE_Header.z80' ORG org_addr BEGIN: LD (dss_line),IX ; Сохраняем указатель на строку запуска. LD HL,EXIT.messages.start LD C,Dss.PChars RST ToDSS LD C,Dss.CurDisk RST ToDSS LD A,'A' ADD A,C LD (EXIT.messages.ramDrive),A LD A,(IX) ; тут DSS кладёт длину параметров ком.строки AND A ; проверяем на отсутствие параметров JP Z,EXIT.help ; запуска в ком.строке. Если их нет - выход с инструкцией CALL Set_keys JP C,EXIT.error.UNDEFINED ; проверка ключей на несовместимость)) LD HL,key_buff LD A,(HL) INC HL XOR (HL) JR NZ,.not_saveRMD INC HL OR (HL) JP Z,EXIT.error.WrongKeys CALL RMD_SAVE JP EXIT.good .not_saveRMD: AND (HL) JR NZ,RMD_MOUNT RMD_UNMOUNT: ;LD A,(key_buff.DRVsave) ;INC A ;CALL NZ,RMD_SAVE ;!TODO check error? LD A,(key_buff.DRV) LD C,BIOS.FreeMemRMD RST ToBIOS ;!TODO check error? LD C,Dss.RescanDrives RST ToDSS JP EXIT.good ;!TODO ;-------------[] ;-------------[] ;Сохранение образа рамдиска в файл RMD_SAVE: XOR A ;LD A,FileAttrib.Normal LD HL,SaveName LD C,Dss.Create RST ToDSS JP C,EXIT.error.writeFile LD (key_buff.FM),A ; сохраняем файловый манипулятор IN A,(SLOT3) LD (.SavePage),A LD A,(key_buff.DRVsave) LD C,BIOS.GET_RAMD_ST RST ToBIOS LD HL,PagesBuffer LD C,BIOS.GetMemBlkPages RST ToBIOS LD C,Dss.Write .loop: PUSH BC PUSH HL LD A,(HL) OUT (SLOT3),A LD A,(key_buff.FM) LD HL,#C000 LD DE,#4000 ;LD C,Dss.Write RST ToDSS ; A - файловый манипулятор ; HL - адрес в памяти ; DE - количество читаемых байт POP HL POP BC ;!TODO удалять файл если ошибка записи JP C,EXIT.error.writeFile INC HL DJNZ .loop .SavePage+*: LD A,0 OUT (SLOT3),A LD C,Dss.RescanDrives RST ToDSS LD A,(key_buff.FM) LD C,Dss.Close JP ToDSS ;-------------[] ;-------------[] RMD_MOUNT: LD A,(key_buff.FM) LD HL,0 LD IX,0 LD BC,Dss.Move_FP.FrEnd RST ToDSS ; узнаём размер файла ; A - файловый манипулятор ; HL:IX - смещение указателя в файле ; B - способ перемещения: ; 0 - от начала файла ; 1 - от текущего значения указателя ; 2 - от конца файла XOR A OR H JP NZ,EXIT.error.noRAM LD A,L CP #39 JP NC,EXIT.error.noRAM PUSH IX POP HL DUP 2 ; превращаем размер файла в байтах в страницы SLA L RL H RLA EDUP LD B,A LD A,H OR L JR Z,.skipINK INC B ; необходимое число страниц ;-------------[] .skipINK: LD A,B LD (.RamPagesNum),A LD C,BIOS.GetMem RST ToBIOS ;LD B,num_pages ; запрашиваемое число страниц ОЗУ ;LD C,0C2h ; номер функции ;CALL 3D13h ; NC -> А - идентификатор блока ; CF -> A=1 - нет памяти JP C,EXIT.error.noRAM LD (.BlockID),A ;-------------[] ;-------------[] LD HL,PagesBuffer LD C,BIOS.GetMemBlkPages RST ToBIOS ; LD A,id_blk ; идентификатор блока ; LD HL,bufer ; буфер длиной 256 байт для размещения списка ; ; буфер должен быть длиной на единицу больше числа ; ; страниц в блоке ; LD C,0C5h ; номер функции ; RST ToBIOS ; NC -> HL - тот же буфер, B - число страниц в блоке ; ; данные по адресу HL - список физических страниц по ; ; порядку. Список заканчивается байтом FF ; ; CF -> неверный идентификатор блока. Старая ; ; информация в буфере может быть затерта JP C,EXIT.error.wrongMEMblkID ;-------------[] ;-------------[] XOR A .loop: PUSH AF LD C,BIOS.GET_RAMD_ST RST ToBIOS ; получение идентификатора блока, назначенного на RAM-Disk AND A JR Z,.loopExit POP AF INC A CP 16 JP NZ,.loop JP EXIT.error.noFreeRAMdsk .loopExit: POP AF ;-------------[.] ; . ; . ;-------------[.] ; A = ram_disk number from BIOS.GET_RAMD_ST .BlockID+*: LD HL,0 LD B,L LD C,BIOS.BLK_TO_RAMD RST ToBIOS ; ; любой блок памяти может содержать данные ; ; RAM-Disk-а в формате TR-DOS для подключения этих ; ; данных в качестве диска и служит эта функция ; LD A,ram_disk ; номер RAM-Disk-а 0..15 - соответствует ; ; RAM-Disk-ам от e: до t: ; LD B,id_blk ; идентификатор блока ; LD C,0C9h ; номер функции ; RST ToBIOS ; NC -> нормальное завершение ; ; CF -> ошибка: неверный номер RAM-Disk-а или ; ; RAM-Disk занят JP C,EXIT.error.wrongRAMdrv ;-------------[] ;Чтение образа в память рамдиска ;-------------[] LD A,(key_buff.FM) LD HL,0 LD IX,0 LD BC,Dss.Move_FP.FrStart RST ToDSS IN A,(SLOT3) LD (.SavePage),A .RamPagesNum+*: LD B,0 LD HL,PagesBuffer LD C,Dss.Read ;;;;!TODO сделать общей процедурой .LOOP: PUSH BC PUSH HL LD A,(HL) OUT (SLOT3),A LD A,(key_buff.FM) LD HL,#C000 LD DE,#4000 ;LD C,Dss.Read RST ToDSS ; A - файловый манипулятор ; HL - адрес в памяти ; DE - количество читаемых байт POP HL POP BC JR C,EXIT.error.readFile INC HL DJNZ .LOOP ;;;; .SavePage+*: LD A,0 OUT (SLOT3),A LD C,Dss.RescanDrives RST ToDSS LD A,(key_buff.FM) LD C,Dss.Close RST ToDSS ;!TODO check error? JR EXIT.mounted ;-------------[] ;-------------[] MODULE EXIT good: LD HL,messages.good LD B,DSS_Error.sys.NO_ERROR printANDexit: PUSH BC LD C,Dss.PChars RST ToDSS POP BC .loop: LD C,Dss.Exit RST ToDSS JR .loop help: LD HL,messages.help LD B,DSS_Error.sys.NO_ERROR JR printANDexit mounted: LD HL,OpenName LD C,Dss.PChars RST ToDSS LD HL,messages.mounted LD B,DSS_Error.sys.NO_ERROR JR printANDexit error: .writeFile: LD B,DSS_Error.sys.WRITE_ERROR LD HL,messages.writeFile JR printANDexit .WrongKeys: LD B,DSS_Error.sys.COMMON_ERROR LD HL,messages.WrongKeys JR printANDexit .UNDEFINED: LD B,DSS_Error.sys.COMMON_ERROR LD HL,messages.UNDEFINED JR printANDexit .noRAM: LD B,DSS_Error.sys.NOT_ENOUGH_MEMORY LD HL,messages.noRAM JR printANDexit .wrongMEMblkID: LD B,DSS_Error.sys.INVALID_MEMORY_HND LD HL,messages.wrongMEMblkID JR printANDexit .wrongRAMdrv: LD B,DSS_Error.sys.INVALID_DRIVE LD HL,messages.wrongRAMdrv JR printANDexit .readFile: LD B,DSS_Error.sys.READ_ERROR LD HL,messages.readFile JR printANDexit .noFreeRAMdsk: LD B,DSS_Error.sys.COMMON_ERROR LD HL,messages.noFreeRAMdsk JR printANDexit ; ; messages: .start: DB "\r\nMountima v" .verNum: DB "0.25 beta. (c) Tolik_Trek@SprinterTeam, " .year: DZ "2026.\r\n" ; .mounted: DB " mounted to RAM drive " .ramDrive: DZ "Z:\r\n" ; .good: DZ "Done.\r\n" .noRAM: DZ "ERROR! No enough memory.\r\n" .wrongMEMblkID: DZ "ERROR! Invalid Memory block ID.\r\n" .wrongRAMdrv: DZ "ERROR! Invalid RAM disk ID or RAM disk busy.\r\n" .readFile: DZ "ERROR! Unable to read disk image file.\r\n" .writeFile: DZ "ERROR! Unable to write disk image to file.\r\n" .noFreeRAMdsk: DZ "ERROR! The number of RAM disks in use has reached its maximum.\r\n" .WrongKeys: DZ "ERROR! Wrong key combination.\r\n" .help: DB "Mountima Help:\r\n" DB " /M - Mounts IMG file to RAM drive.\r\n" DB " /U - Unmounts RAM drive.\r\n" DB " /S - Saves RAM drive to IMG file.\r\n" DB "Examples:\r\n" DB ' mountima.exe /M c:\images\image.img', "\r\n" DB ' mountima.exe /U e:', "\r\n" DZ ' mountima.exe /S c:\images\image.img e:',"\r\n" .UNDEFINED: DZ "Undefined error: SET_KEYS\r\n" ;!TODO ENDMODULE ;-------------[] dss_line: DW 0 ;******************************************************* ; ____ _ _ ; / ___| ___| |_ | | _____ _ _ ___ ; \___ \ / _ \ __| | |/ / _ \ | | / __| ; ___) | __/ |_ | < __/ |_| \__ \ ; |____/ \___|\__| |_|\_\___|\__, |___/ ; |___/ ; Получаем ключи запуска, распихиваем их по углам, ; настраиваем начальные условия работы. ;-----------------; key_buff: .U: DB 0 ; unmount .M: DB 0 ; mount .S: DB 0 ; save ramdisk .FM: DB 0 ; File Manipulator .DRV: DB #FF ; номер рамдиска для unmount .DRVsave: DB #FF ; номер рамдиска для SAVE ;-----------------; Set_keys: LD HL,(dss_line) INC HL LD (.NextParam),HL .CheckChar: CALL .GetParam ;JR NC,.next CCF RET NC ; Разбор окончен. .next: LD A,(Buffer+2) ; В основном цикле CheckChar мы ждём только два ADD #FF ; символа в ключе. Поэтому если их больше, RET C ; то выходим с ошибкой. LD A,(Buffer) SUB '/' SCF RET NZ ; Проверка/установка ключа LD HL,key_buff ; начало хранения ключей LD E,L ; для проверки на ключ U LD A,(Buffer+1) AND %11011111 ; делаем маленький символ большим))) CP 'U' ; проверяем параметр mount image JR Z,.set_key INC HL ; следующий ключ CP 'M' ; проверяем параметр unmount image JR Z,.set_key INC HL ; следующий ключ CP 'S' ; проверяем параметр save image JR Z,.set_key SCF ; ошибка в параметре RET ; выход с ошибкой ;-----------------; ;-----------------; .set_key: LD A,(HL) ; проверяем не установлен ли ключ. ADD #FF ; если есть, значит ключ введён 2 раза RET C ; ошибка - повтор ключа. выход INC (HL) ; Признак установки ключа - не ноль. Установили ключ. LD A,L SUB E ; для проверки на ключ U LD (.save_a),A CALL .GetParam ; получаем следующий параметр строки DOS к найденому ключу RET C ; выход, если ошибка XOR A .save_a+1: OR 0 JR NZ,.file_key CALL .GetDRVnum RET C LD (key_buff.DRV),A ; сохраняем номер рамдиска для BIOS.FreeMemRMD JP .CheckChar ; погнали на следующий виток разбора ключей /* .save_a+*: LD A,0 XOR 2 JR Z,.key_save XOR 2 JR NZ,.file_key ;unmount key CALL .GetDRVnum ;!TODO error number RET C LD (key_buff.DRV),A ; сохраняем номер рамдиска для BIOS.FreeMemRMD ;-------------------- JP .CheckChar ; погнали на следующий виток разбора ключей .key_save: CALL .GetDRVnum RET C LD (key_buff.DRVsave),A ; сохраняем номер рамдиска для BIOS.FreeMemRMD */ .file_key: LD A,(key_buff.M) AND A JR Z,.noRD LD HL,Buffer CALL .OpenRDfile ; Открытие файла (или проверка наличия) по имени из буфера RET C ; выход, если ошибка JP .CheckChar ; погнали на следующий виток разбора ключей .noRD: LD HL,(.NextParam) ; проверка, что есть следующий параметр LD A,H OR L SCF RET Z ; LD HL,Buffer LD BC,256 XOR A CPIR JP PE,.yes_filename SCF RET ; .yes_filename: LD DE,Buffer SBC HL,DE SCF RET Z ; LD B,H LD C,L EX DE,HL LD DE,SaveName LDIR LD HL,(.NextParam) INC HL LD A,(HL) CP ':' SCF RET NZ CALL .GetParam CCF RET NC CALL .GetDRVnum RET C LD (key_buff.DRVsave),A ; сохраняем номер рамдиска для save ram drive RET ;-----------------; ;-----------------; .GetParam: .NextParam+1: LD HL,0 LD DE,Buffer ; буфер для операций со строками LD C,Dss.GSwitch ; тут выделяем параметр запуска RST ToDSS ; получаем в буфере следующий параметр LD (.NextParam),HL LD A,(Buffer) AND A RET NZ ; Нормальный возврат C = 0 LD HL,0 ; Маркер конца разбора LD (.NextParam),HL SCF RET ; Возврат с ошибкой C = 1 ;-----------------; ;-----------------; .OpenRDfile: LD BC,Dss.EX_Path.GET_ALL ; проверяем буфер на корректность имени файла RST ToDSS RET C ; ошибка в строке AND %00000011 ; проверяем, что есть имя и XOR %00000011 ; расширение файла (0 и 1 биты) SCF RET NZ ; ошибка файла - выход LD A,Dss.Open.R LD HL,Buffer LD C,Dss.Open RST ToDSS ; открытие файла LD (key_buff.FM),A ; сохраняем файловый манипулятор RET C ; LD HL,Buffer LD DE,OpenName ; буфер (13 байт) LD BC,Dss.EX_Path.GET_NAME ; B=3, C=#45 RST ToDSS ; CF=0: A - результат, буфер - "FILE.EXT",0 RET ;-----------------; .GetDRVnum: LD HL,Buffer+2 LD (HL),'\' INC HL LD (HL),0 EX DE,HL LD HL,Buffer LD BC,Dss.EX_Path.GET_DRIVE ; тут определяем имя диска ли в буфере RST ToDSS ; получаем в А логический номер диска RET C LD BC,0*256 + 8 LD DE,#55AA RST ToDSS.DRV ; из логического в физический номер диска EX AF,AF' LD C,A AND #F0 XOR #60 SCF RET NZ LD A,C AND #0F RET ;-----------------; ;******************************************************* ;Loader_length EQU $-BEGIN ;!FIXIT PagesBuffer EQU $ Buffer EQU PagesBuffer+256 SaveName EQU Buffer+256 OpenName EQU SaveName+256 ;----------------------------------------------[End Code section] STACK_CHECK_MACRO stack_point, (stack_buffer+256) ;----------------------------------------------[Data after Loader] /* ;-----------------------------------------------------------------------; Test: LD (dss_line),IX ; Сохраняем указатель на строку запуска. LD A,(IX) ; тут DSS кладёт длину параметров ком.строки AND A ; проверяем на отсутствие параметров JP NZ,1F ; запуска в ком.строке. Если их нет, LD HL,Help_Msg ; то печатаем инструкцию и выходим CALL PrintStr ; из программы с нормальным кодом LD B,0 ; завершения. JP Exit ; ;-----------------------------------------------------------------------; ;-----------------------------------------------------------------------; GetParam: LD HL,(NextParameter) ; LD C,43h ; тут выделяем параметр запуска LD DE,Buffer ; буфер для операций со строками RST ToDSS ; получаем в буфере следующий параметр ld (NextParameter),hl ; CCF ; LD A,(Buffer) ; AND A ; RET NZ ; Нормальный возврат C = 0 SCF ; RET ; Возврат с ошибкой C = 1 ;-----------------------------------------------------------------------; LD HL,COMLINE ;HL указывает на командную строку .loop: LD DE,BUFFER ;DE указывает на буфер для параметров LD C,43h ;Функция выделения параметра RST ToDSS ;Выполнение функции PUSH AF PUSH HL POP HL POP AF JP NC,.loop LD A,(BUFFER) AND A JR NZ,NEXTP */