|
Секреты TR-DOS - Полная адаптация программ к диску без использования системных переменных TR-DOS.
|
СЕКРЕТЫ TR-DOS
Полная адаптация программ к диску без использования системных переменных TR-DOS
(На примере игры DUNDARACH фирмы GARGOYLE GAMES)
© Станислав Шилов, г. Пермь, 1995.
В последнее время на дисках появилось множество адвентюрных программ с одним недостатком - у них нет выгрузки на диск. На диск программу перевести не так уж сложно, а вот сделать приличную процедуру загрузки/выгрузки положения игры с диска, куда сложнее. Зачастую стандартными приемами TR-DOS здесь не обойдешься, т.к. большинство игр с выгрузками расположены сразу после системных переменных Бейсика или вообще занимают всю память, так что для системных переменных TR-DOS, тем более для буфера TR-DOS совершенно нет места. Как же поступают в таком случае? Самое простое, что можно сделать - это сделать программу записывающей выгрузки саму в себя. Все кодовые блоки такой программы, обычно соединяют вместе в один бейсик-блок и оставляют несколько секторов после всех кодовых блоков для выгрузки. Для записи и загрузки положения можно воспользоваться двумя подпрограммами в ПЗУ TR-DOS: #2D73 -запись сектора, #2F1B - чтение сектора. Для чтения/записи блока секторов придётся писать собственную программку (уже готовая есть в SPECTROFON^ № 3). Но у этого способа адаптации есть несколько недостатков. Перечислю их. Во-первых, если попытаться записать положение игры на защищенный от записи диск, то на экране появится сообщение "READ ONLY...", после чего можете спокойно сбрасывать игру и перезагружать снова. Аналогичная ситуация возникает при сбойном секторе, только возникнет сообщение "DISK ERROR.". Например, если в дисковод поставить IS-DOS диск и попробовать загрузить положение игры, то на экране возникнет вышеупомянутое сообщение. Во-вторых, очень сильно пользователя ограничивает только одна выгрузка в игре, тем более сложной.
Как же избежать этих недостатков? В приведенных в этой статье программах устранены все перечисленные ошибки, но есть один недостаток, т.к. в DUNDARACH совершенно не было места для процедур чтения/записи, поэтому можно поступить следующим образом. Подгружать все программы чтения/записи файлов с диска, а в памяти оставить только программу чтения секторов с диска. Программу, которая загружает сектора, и постоянно находится в памяти, будет в дальнейшем назваться - "считывающей", а программа, которая загружается в память с диска - "основной".
"Основная" программа подгружается в экранную область с диска с помощью "считывающей" программы, которая находится в памяти вместо кассетных подпрограмм. После чего запускается " основная" программа и выполняет запись или загрузку файла с выгрузкой. Сначала рассмотрим, так называемую "считывающую" программу. При вызове опции 2 (SAVE GAME) или 3 (RESTORE GAME) меню OPTIONS, программа переходит соответственно на метки JRSAVE и JRLOAD. Затем очищается экран (строка 170), после чего инициализируется дисковод методом прямого обращения к ВГ-93 (об этом методе я расскажу позже). Затем читаем несколько секторов в экранную область с адреса #4B00 (переменная DATPLC) с "основной" программой (строки 240-660, 810-940). После этого проверяем считанную информацию, если первые два байта равны #A7, #1F, то значит, в дисководе стоит нужный диск, иначе программа просто выйдет в меню OPTIONS. После этого запускается "основная" программа. Теперь объясняю, как всё работает в "основной" программе. Сначала запрашиваем версионную букву выгрузки (подпрограмма ENTNAM), затем считываем каталог диска (подпрограмма RDCAT) с адреса #5000 (пер. CAT). После чего проверяется длина каждого файла, если длина файла соответствует длине выгрузке, то данные этого файла переносятся на адрес #5000, затем #5010 и т.д. Затем сравнивается каждое имя прошедшего проверку файла с данными нужного нам имени с адреса #AF2C-FNAME (подпрограмма FINDAF), если файл соответствует нужной выгрузке, то процедура LOAD загружает данные файла сначала в буфер с адреса #4000, а затем перекидывает нужное количество байтов в память программы командой LDIR. Если процедура SAVE находит файл, соответствующий выгрузке, то сразу переходит на процедуру записи данных, т. е. попросту перезаписывает его, иначе создает новый файл в каталоге диска (подпрограмма NEWF). При создании нового файла с адреса #4F00-CATDAT загружаются данные диска, вносятся требуемые изменения, после чего они записываются на диск. Затем загружается сектор с последним файлом и в этот сектор заносится имя нового файла, после чего подпрограмма SVE записывает данные в файл. Ну, вот в принципе и вся работа "основной" программы.
Перечислю ошибки, которые могут возникнуть при работе с диском. Ошибки, на которые не выдается сообщения:
1. Попытка записи на защищенный диск;
2. Попытка записи на не отформатированный диск;
3. Попытка чтения выгрузки с диска со сбойными секторами или с не TR-DOS диска.
В случае этих ошибок программа будет ждать пока Вы не вставите другой диск или не нажмете клавишу SPACE для выхода в меню OPTIONS. Если в дисководе нет диска, то программа будет ждать до тех пор, пока Вы его не вставите. Ошибки, которые сопровождаются сообщением:
1. Нет выгрузок на диске (NO FILE(S) ON DISK);
2. Файл не найден (FILE ABSENT);
3. Нет места на диске (NO SPACE ON DISK).
Вот и все возможные ошибки, которые могут возникнуть у Вас при работе с диском.
Третьей отдельной программой, которая входит в дисковый DUNDARACH - это программа START. Компилируется она вместе со "считывающей" программой, т.к. вносит изменения именно в эту программу. Она настраивает программу на текущий дисковод (A...D), на тип дисковода (односторонний, двухсторонний) и дает "считывающей" программе координаты "основной" программы (дорожка, сектор). Ну, вот я и объяснил все что мог, остальное ищите в комментариях к программам.
Теперь объясню метод обращения напрямую к ВГ-93. Приведенные в этой статье программы пользуются только тремя подпрограммами TR-DOS.
Занесение в регистры ВГ-93 команд.
#20B8 OUT (C),D ;В регистре C номер порта, в регистр D - число
#2 0B8 OUT |
(C) ,D |
;В регистре C номер порта, в регистр D - число |
DJNZ |
#2 0B1 |
;В регистре B обязательно должна быть 1. |
RET |
|
;Выход. |
Жалко, что разработчики TR-DOS не догадались написать аналогичную подпрограммку для |
чтения портов. Если бы она была, то можно было читать регистр состояния ВГ-93. |
Запись данных на диск. |
|
#3FCA IN |
A, (#FF) |
;Регистр состояния ВГ-93. |
AND |
#C0 |
;Ожидание |
JR |
Z,# 3 FCA |
;готовности ВГ-93. |
RET |
M |
,'Выход, если ВГ-93 окончил запись. |
OUT I |
|
;Вывод байта на диск. |
JR |
#3FCA |
'Переход на запись следующего байта. |
Чтение данных с диска. |
|
#3FE5 IN |
A, (#FF) |
'Регистр состояния ВГ-93. |
AND |
#C0 |
; Ожидание |
JR |
Z,#3FE5 |
'готовности ВГ-93. |
RET |
M |
;Выход, если ВГ-93 окончил загрузку. |
INI |
|
;Ввод байта с диска. |
JR |
#3FE5 |
'Переход на загрузку следующего байта. |
Все остальное, относящееся к ВГ-93 Вы можете прочитать в ZX-РЕВЮ № 4, 1994, стр. 10 и в ZX-РЕВЮ № 5, 1994, стр. 19. Для читателей, которые хотят применять "основную" программу для собственных, даю подпрограмму PRINT, без которой ничего работать не будет отдельно от игры.
PRINT |
POP |
HL |
' адрес возврата из подпрограммы в регистре HL |
|
CALL |
PRN |
'Вызываем подпрограмму печати. |
|
JP |
(HL) |
'Выходим на следующий после текста оператор. |
PRN |
LD |
A,(HL) |
'В регистре A символ. |
|
INC |
HL |
'HL=HL+1 |
|
CP |
П a П "%" |
' Конец текста? |
|
RET |
Z |
'Если да, то выход. |
|
PUSH |
HL |
|
|
RST |
#10 |
'Печатаем символ. |
|
POP |
HL |
|
|
JR |
PRN |
'Переход на следующий символ. |
FNAME |
DEFM |
"dun |
H |
;имя файла (8 байтов). |
LETTER |
DEFB |
II и |
|
;Версионная буква. |
|
DEFB |
#20, |
#20 |
|
|
DEFB |
#20, |
#20 |
|
TYPE |
DEFB |
"С" |
|
;тип файла "С" - CODE. |
LSTR |
DEFB |
00 |
|
; стартовый адрес файла |
HSTR |
DEFB |
00 |
|
|
LLEN |
DEFB |
AC |
|
;длина файла. |
HLEN |
DEFB |
0A |
|
|
SLEN |
DEFB |
0B |
|
;длина в секторах. |
SSECT |
DEFB |
00 |
|
;Начальный сектор. |
STRK |
DEFB |
00 |
|
;Начальная дорожка. |
Если Вы используете другие данные в описании файла, то не забудьте в "основной" программе исправить строки 1440, 1470, 1490.
Считывающая программа.
;Переход на следующий символ. Ещё хочу сказать, что с адреса на которую указывает переменная FNAME, должны быть все данные о файле. Т.е. если Вы хотите использовать программу в своих целях, то вместо команды FNAME EQU #AF2C вставьте:
10 |
ORG |
#AFE5 'Адрес компиляции программы. |
2 0 SAVE |
EQU |
#4C9B 'Адрес подпрограммы записи. |
3 0 LOAD |
EQU |
#4C14 'Адрес подпрограммы загрузки. |
4 0 DATPLC |
EQU |
#4B00 'Адрес загрузки основных подпрограмм. |
5 0 PRINT |
EQU |
#AD1A 'Адрес подпрограммы печати. |
60 RDCAT |
EQU |
#4B96 'Адрес подпрограммы чтения каталога. |
7 0 MENU |
EQU |
#AF3C 'Адрес выхода в меню. |
8 0 BLKLNG |
EQU |
#0300 'Длина в секторах загрузочного блока. |
90 CLS |
LD |
HL,#5800 'Подпрограмма очистки экрана. |
100 |
LD |
DE,#5801 ' |
110 |
LD |
BC,#02 FF ' |
120 |
LD |
(HL),L ' |
130 |
LDIR |
' |
140 |
RET |
' |
15 0 JRSAVE |
LD |
HL,SAVE 'Сюда осуществляется переход |
160 |
JR |
LOADAT ' из опции 2 (SAVE GAME), |
170 JRLOAD |
LD |
HL,LOAD ' из опции 3 (RESTORE GAME) |
180 LOADAT |
LD |
(COMAND+1),HL 'Установка перехода. |
190 |
CALL |
CLS 'Очищаем экран. |
200 |
|
CALL |
BG93 |
Инициализируем дисковод. |
210 |
|
DEFB |
#1F |
|
220 |
RES |
DEFB |
#0C |
|
230 |
|
CALL |
RESET |
Очистка ВГ-93. |
240 |
|
CALL |
BG93 |
Устанавливаем головку дисковода на |
250 |
|
DEFB |
#7 F |
нужную дорожку в регистр данных. |
260 |
TRACK |
DEFB |
#00 |
Номер дорожки. |
270 |
|
CALL |
BG93 |
Устанавливаем системный регистр |
280 |
|
DEFB |
#FF |
(#3^сторона 1, #2^сторона |
290 |
SIDE1 |
DEFB |
#3C |
0 для дисковода A). |
300 |
|
CALL |
BG93 |
Команда ВГ-93 поиска |
310 |
|
DEFB |
#1F |
дорожки и стороны. |
320 |
|
DEFB |
#1C |
#1C=000111000b. |
330 |
|
CALL |
RESET |
Очистка ВГ-93. |
340 |
|
LD |
HL,DATPLC |
Адрес загрузки в памяти. |
350 |
SECTOR |
LD |
BC,BLKLNG |
Регистр B-длина, регистр C-сектор. |
360 |
LOOP |
PUSH |
BC |
Сохранение BC. |
370 |
|
PUSH |
HL |
Сохр. адр. начала загрузки. |
380 |
|
LD |
A, C |
Устанавливаем |
390 |
|
LD |
(SECTPL),A |
сектор из |
400 |
|
CALL |
BG93 |
регистра С |
410 |
|
DEFB |
#5 F |
в порт #5F |
420 |
SECTPL |
DEFB |
#01 |
TR-DOS. |
430 |
|
CALL |
BG93 |
Команда ВГ-93 - |
440 |
|
DEFB |
#1F |
- чтение сектора. |
450 |
|
DEFB |
#80 |
#80=10000000b. |
460 |
|
POP |
HL |
В HL - адрес |
470 |
|
PUSH |
HL |
начала загрузки. |
480 |
|
CALL |
R_LOAD |
Вызов подпрограмма чтения сектора. |
490 |
|
POP |
DE |
Проверка |
500 |
|
PUSH |
DE |
на ошибку |
510 |
|
INC |
D |
чтения, |
520 |
|
AND |
A |
если HL |
530 |
|
SBC |
HL, DE |
не |
540 |
|
POP |
HL |
равен 0, |
550 |
|
POP |
BC |
то |
560 |
|
JR |
NZ,EXIT |
выход в меню. |
570 |
|
LD |
A, #7 F |
Если нажата |
580 |
|
IN |
A, (#FE) |
клавиша |
590 |
|
AND |
#01 |
SPACE, то |
600 |
|
JR |
Z,EXIT |
выход в меню. |
610 |
|
INC |
H |
Адрес=адрес+#0100. |
620 |
|
INC |
C |
Увеличение номера сектора. |
630 |
|
LD |
A, C |
Если номер=#11 (конец дорожки), |
640 |
|
CP |
#11 |
то переход на следующую |
650 |
|
JR |
Z,NEXTRK |
дорожку или сторону. |
660 |
DJN |
DJNZ |
LOOP |
Чтение следующего сектора. |
670 |
|
LD |
HL,DATPLC |
Если первые |
680 |
|
LD |
A, #A7 |
два байта |
690 |
|
CP |
(HL) |
прочитанного |
700 |
|
JR |
NZ,EXIT |
блока |
710 |
|
LD |
A, #1F |
не равны #A7,#1F, |
720 |
|
INC |
HL |
то |
730 |
|
CP |
(HL) |
выход |
740 |
|
JR |
NZ,EXIT |
в меню. |
750 |
|
CALL |
NAST |
Настройка номера дисковода. |
760 |
|
EI |
|
|
770 |
|
CALL |
RDCAT |
Чтение каталога. |
780 |
COMAND |
CALL |
#0000 |
вызов подпрограмм SAVE или LOAD. |
790 |
EXIT |
EI |
|
Выход |
800 |
|
JP |
MENU |
в меню OPTIONS. |
810 |
NEXTRK |
|
|
Подпрограмма перехода |
820 |
|
PUSH |
BC |
на следующую дорожку. |
830 |
|
PUSH |
HL |
|
840 |
NOFORW |
CALL |
BG93 |
Команда сдвига головки |
850 |
|
DEFB |
#1F |
дисковода на 1 шаг, если |
860 |
FORWRD |
DEFB |
#5C |
сектор находится между 0 и |
870 |
|
CALL |
RESET |
1 дорожками, то с метки NOFORW |
880 |
JMP |
CALL |
BG93 |
при старте программы будет |
890 |
|
DEFB |
#FF |
поставлена команда JR JMP. |
900 |
SIDE0 |
DEFB |
#2C |
Установка стороны 1 или 0. |
910 |
|
POP |
HL |
|
920 |
|
POP |
BC |
|
930 |
|
LD |
C, 1 |
Установка номера сектора=1. |
940 |
|
JR |
DJN |
Переход на чтение следующий сектор |
950 |
BG93 |
EX |
(SP),HL |
Берем после CALL |
960 |
|
LD |
C, (HL) |
в регистр C - порт TR-DOS, |
970 |
|
INC |
HL |
а в регистр D - число, |
980 |
|
LD |
D, (HL) |
посылаемое в этот порт. |
990 |
|
INC |
HL |
|
1000 |
|
EX |
(SP),HL |
На стеке - адрес возврата+2. |
1010 |
|
PUSH |
HL |
Посылаем HL на стек. |
1020 |
|
LD |
HL, #20B8 |
В HL - адрес в ПЗУ TR-DOS |
1030 |
|
LD |
B, #01 |
подпрограмма записи числа |
1040 |
|
JR |
TRDOS |
в порт TR-DOS. |
1050 |
RESET |
LD |
HL,#00 00 |
Подпрограмма очистки ВГ-93. |
1060 |
R_LOAD |
LD |
DE,#00 00 |
Подпрограмма чтения сектора, в HL - |
1070 |
|
LD |
C, #7 F |
адрес начала загрузки. |
1080 |
|
PUSH |
HL |
Сохраняем HL. |
1090 |
|
LD |
HL,#3FE5 |
В HL-адрес подпрограммы чтения сектора |
1100 |
TRDOS |
DI |
|
|
1110 |
|
EX |
(SP),HL |
Меняем содержимое стека и HL. |
1120 |
|
JP |
#3D2 F |
Переход в ПЗУ TR-DOS. |
1130 |
NAST |
LD |
A,(SIDE1) |
Настройка |
1140 |
|
OR |
#10 |
загруженной |
1150 |
|
LD |
(#4906),A |
подпрограммы |
1160 |
|
AND |
#EF |
на номер |
1170 |
|
LD |
(#4 90A) ,A |
дисковода (0...3). |
1180 |
|
RET |
|
|
1185 |
|
|
|
|
;----- |
|
|
|
1190 |
START |
|
|
Подпрограмма запуска. |
1200 |
|
LD |
A, (#5CF4) |
В регистр A - текущий сектор. |
1210 |
|
INC |
A |
увеличиваем на 1. |
1220 |
|
LD |
(SECTOR+1),A |
сохраняем в программе. |
1230 |
|
LD |
A, (#5CF6) |
В регистре A - номер дисковода. |
1240 |
|
LD |
E, A |
Сохраняем в регистре E. |
1250 |
|
ADD |
A, #C8 |
В регистре |
1260 |
|
LD |
L, A |
HL - адрес кода, определяющего |
1270 |
|
LD |
H, #5C |
режим работы дисковода. |
1280 |
|
LD |
A, #3C |
В регистре A - код системного
9 |
1290 |
ADD |
A, E |
|
|
регистра ВГ-93, для стороны 1. |
1300 |
LD |
E, A |
|
|
|
1310 |
LD |
D, A |
|
|
|
1320 SIDE1 |
BIT |
1,(HL) |
|
|
Проверка типа дисковода. |
1330 SSIDE |
LD |
A,(#5CF5 |
) |
|
В A - номер текущего трека. |
1340 |
JR |
Z, SSIDE |
|
|
Если односторонний, то переход. |
1350 |
AND |
A |
|
|
Проверка |
1360 |
RRA |
|
|
|
текущей стороны, |
1370 |
JR |
C, SIDE1 |
|
|
если флаг C, то сторона 0. |
1380 |
RES |
4, D |
|
|
В D системного регистра для стороны 0. |
1390 |
LD |
HL,#0618 |
|
|
Установка перехода в подпрограмму |
1400 |
LD |
(NOFORW) |
, HL |
|
сдвига головки. |
1410 |
JR |
SSIDE |
|
|
|
1420 |
RES |
4, E |
|
|
|
1430 |
LD |
(TRACK) , |
A |
|
Установка дорожки. |
1440 |
LD |
A, D |
|
|
|
1450 |
LD |
(SIDE0), |
A |
|
Установка текущей стороны. |
1460 |
LD |
A, E |
|
|
|
1470 |
LD |
(SIDE1), |
A |
|
Установка следующей стороны. Старт программы. |
|
|
|
|
Основная программа. |
10 |
ORG |
#4B00 |
|
;Адрес компиляции программы. |
2 0 WYGR |
EQU |
#B0D6 |
|
;WYGR - начало выгрузки. |
3 0CATDAT |
EQU |
#4 F0 0 |
|
;CATDAT-адрес, с которого будут загружены ;данные диска (дорожка 0,сектор 9). |
4 0 BUFFER |
EQU |
#4000 |
|
;Начало буфера выгрузки. |
5 0 LENGHT |
EQU |
#0AAD |
|
;Длина выгрузки в DUN DARACH. |
60 CAT |
EQU |
#5000 |
|
;Адрес загрузки каталога. |
7 0 FNAME |
EQU |
#AF2C |
|
;Начало имени файла выгрузки. |
8 0 PRINT |
EQU |
#AD1A |
|
;Адрес процедуры печати. |
90 CLS |
EQU |
#AFE5 |
|
;Адрес процедуры очистки экрана. |
100 RDSECT |
EQU |
#0B00 |
|
; |
110 RDS1 |
EQU |
#000B |
|
; Количество секторов в выгрузке. |
120 RDS2 |
EQU |
#0B |
|
;/ |
130 LETTER |
EQU |
#AF2F |
|
;Буква в имени файла выгрузки. |
140 GO TR |
AND |
A |
|
;GO TR-Подпрограмма поиска дорожки. |
;В регистре |
A должна |
быть |
установлена искомая дорожка. |
150 SDRIVE |
RRA |
|
|
;Проверка стороны. |
160 |
LD |
(TRACK) , |
A |
^охранение дорожки деленной на 2. |
170 |
LD |
A, #3C |
|
;#3C-код 1 стороны для диска A. |
180 |
JR |
NC,SIDE1 |
|
;Если флаг NC, то переход, |
190 |
LD |
A, #2C |
|
; иначе установка стороны 0. |
200 SIDE1 |
LD |
(SYSREG) |
,A |
;Сохранение определенной стороны. |
210 |
CALL |
BG93 |
|
;Установка стороны диска |
220 |
DEFB |
#FF |
|
;в порту ВГ-93. |
230 SYSREG |
DEFB |
#3C |
|
;Сторона дисковода. |
240 |
CALL |
BG93 |
|
;Установка регистра дорожки. |
250 |
DEFB |
#7 F |
|
;Адрес порта дорожки-#7F. |
2 60 TRACK |
DEFB |
#00 |
|
;Номер дорожки. |
270 |
CALL |
BG93 |
|
; |
280 |
DEFB |
#1F |
|
;Порт команд-состояния ВГ93. |
290 |
DEFB |
#18 |
|
;#18=00011000-поиск дорожки. |
300 |
CALL |
RESET |
|
;Очиска ВГ-93. |
310 |
RET |
|
|
; |
320 CATSAV LD HL,CATDAT ;ONDISK-Процедура записи сектора на диск.
/Параметры: HL-начало записываемого блока в памяти, после CALL должен ;стоять номер сектора.
330 |
ONDISK |
LD |
A,#A4 |
Подпрограмма записи данных каталога. |
|
|
|
|
#A4=10100100b-запись сектора. |
340 |
|
LD |
(S OR L),A |
Установка переменных записи. |
350 |
|
LD |
DE,R SAVE |
В DE адрес подпрограммы вывода на диск |
360 |
|
JR |
JMP1 |
|
370 |
LOAD C |
LD |
HL,CATDAT |
Подпрограммы загрузки каталога. |
380 |
FROM D |
LD |
A,#8 0 |
#80-команда чтения сектора. |
390 |
|
LD |
(S OR L),A |
Установка переменных загрузки. |
400 |
|
LD |
DE,R LOAD |
В DE - адрес подпрограммы чтения. |
410 |
JMP1 |
LD |
(ROUTIN+1),DE |
Установка перехода. |
420 |
|
EX |
(SP),HL |
Обмен содержимым стека с НL. |
430 |
|
LD |
A, (HL) |
В регистр A номер сектора. |
440 |
|
INC |
HL |
увеличить адрес возврата на 1. |
450 |
|
EX |
(SP),HL |
Обратный обмен HL и стека. |
460 |
|
LD |
(SECTOR) ,A |
Установка сектора. |
470 |
LOOP1 |
PUSH |
HL |
Сохранение HL. |
480 |
|
CALL |
BG93 |
Номер сектора - в регистр. |
490 |
|
DEFB |
#5 F |
#5F-регистр сектора. |
500 |
SECTOR |
DEFB |
#01 |
Номер сектора. |
510 |
|
CALL |
BG93 |
Команда записи или загрузки, |
520 |
|
DEFB |
#1F |
в зависимости от установленных |
530 |
SORL |
DEFB |
#80 |
раннее переменных. |
540 |
|
POP |
HL |
Восстановление первоначаль |
550 |
|
PUSH |
HL |
ного значения HL. |
560 |
ROUTIN |
CALL |
R LOAD |
Исполнение SAVE или LOAD. |
570 |
|
LD |
A, #7 F |
Проверка нажатия клавиши |
580 |
|
IN |
A, (#FE) |
SPACE, если клавиша нажата, |
590 |
|
AND |
#01 |
то выход из подпрограммы. |
600 |
|
JR |
Z,BREAK |
|
610 |
|
LD |
DE,#0100 |
Проверка считанного или записанного |
620 |
|
AND |
A |
сектора, если он |
630 |
|
SBC |
HL, DE |
не равняется 256 байтам, то |
640 |
|
POP |
DE |
повтор записи или считывания |
650 |
|
PUSH |
DE |
|
660 |
|
SBC |
HL, DE |
|
670 |
BREAK |
POP |
HL |
|
680 |
|
JR |
NZ,LOOP1 |
Повтор чтения/записи при ошибке. |
690 |
|
RET |
|
|
700 |
BG93 |
EX |
(SP),HL |
Берем после CALL BG93 |
710 |
|
LD |
C, (HL) |
в регистр C-порт TR-DOS, |
720 |
|
INC |
HL |
в регистр D-число, которое |
730 |
|
LD |
D, (HL) |
нужно занести в этот порт. |
740 |
|
INC |
HL |
|
750 |
|
EX |
(SP),HL |
Восстановить адрес возврата+2. |
760 |
|
PUSH |
HL |
|
770 |
|
LD |
HL, #20B8 |
В HL-адрес подпрограммы записи |
780 |
|
LD |
B, 01 |
в порты TR-DOS. |
790 |
|
JR |
TRDOS |
|
800 |
RESET |
|
|
|
810 |
|
LD |
HL,#0000 |
Очистка ВГ-93. |
820 |
R LOAD |
LD |
DE,#00 00 |
Подпрограмма чтения сектора. |
830 |
|
LD |
C, #7 F |
|
840 |
|
PUSH |
HL |
|
850 |
|
LD |
HL,#3FE5 |
|
860 |
TRDOS |
DI |
|
|
870 |
|
EX |
(SP),HL |
Меняем регистры HL со стеком. |
880 |
|
JP |
#3D2 F |
Вход в ПЗУ TR-DOS. |
890 |
R SAVE |
LD |
DE,#00 00 |
Подпрограмма вывода на диск. |
900 |
|
LD |
C, #7 F |
|
910 |
|
PUSH |
HL |
|
920 |
|
LD |
HL,#3FCA |
|
930 |
|
EX |
(SP),HL |
|
940 |
|
JP |
#3D2 F |
Вход в ПЗУ TRDOS. |
950 |
RDCAT |
CALL |
ENTNAM |
RDCAT-Подпрограмма чтения каталога |
;и сортировки имен. Установка буквы в имени файла.
960 |
|
CALL |
CLS |
Очистка экрана. |
970 |
|
XOR |
A |
Установка головки на |
980 |
|
CALL |
GO TR |
нулевую дорожку. |
990 |
|
CALL |
LOAD C |
Загрузка каталога в память. |
1000 |
|
DEFB |
#09 |
Сектор 09, дорожка 0. |
1010 |
|
LD |
A,(CATDAT+#E3) |
Проверка количества секторов на |
1020 |
|
BIT |
3,A |
одной дорожке, если 8, то |
1030 |
|
JR |
Z,DDRIVE |
происходит смена |
1040 |
|
XOR |
A |
переменных для |
1050 |
|
LD |
(SDRIVE),A |
одностороннего |
1060 |
|
LD |
A, #08 |
дисковода. |
1070 |
|
LD |
(SSECT+1),A |
|
1080 |
DDRIVE |
LD |
HL,CAT |
Считывание имен файлов с |
1090 |
|
LD |
C, #08 |
диска в память с адреса #5000. |
1100 |
LOOP2 |
PUSH |
BC |
Счетчик на чтение первых |
1110 |
|
LD |
A, #09 |
8 секторов каталога. |
1120 |
|
SUB |
C |
A=A-C |
1130 |
|
LD |
( SECT1) ,A |
установка текущего сектора. |
1140 |
|
CALL |
FROM D |
считывание сектора. |
1150 |
SECT1 |
DEFB |
#09 |
|
1160 |
|
POP |
BC |
Восстановление BC. |
1170 |
|
LD |
DE,#0010 |
Проверка имен файлов. |
1180 |
|
LD |
B, E |
Установка счётчика на 16 имён. |
1190 |
LOOP3 |
LD |
A,(HL) |
Проверка первой буквы |
1200 |
|
AND |
A |
имени, если она |
1210 |
|
JR |
Z,C FILE |
равна 0, то выход, |
1220 |
|
ADD |
HL, DE |
иначе проверка |
1230 |
|
DJNZ |
LOOP3 |
следующего имени файла. |
1240 |
|
DEC |
C |
Переход на считывание |
1250 |
|
JR |
NZ,LOOP2 |
следующего сектора. |
1260 |
C FILE |
|
|
Отбор файлов по длине. |
1270 |
|
LD |
DE,CAT |
DE - на начало каталога. |
1280 |
|
PUSH |
DE |
|
1290 |
|
POP |
HL |
HL=DE |
1300 |
|
XOR |
A |
Обнуление счетчика файлов. |
1310 |
|
LD |
(NFILES),A |
Сохранение. |
1320 |
LOOP4 |
LD |
BC,#0010 |
Кол-во байт в заголовке. |
1330 |
|
LD |
A, (HL) |
В A - первый байт имени файла, |
1340 |
|
AND |
A |
если он равен 0 (конец |
1350 |
|
JR |
Z, ENDCAT |
каталога), то выход из подпрограммы |
1360 |
|
CP |
#01 |
Если=1 (стертый файл), |
1370 |
|
JR |
Z,A TYPE |
то проверка следующего файла. |
1380 |
|
PUSH |
HL ' |
1390 |
|
POP |
IX 'IX=HL |
1400 |
|
LD |
A, (IX+8) 'Тип файла: BASIC, CODE или |
1410 |
|
TYPE |
NOP 'другой тип. Здесь можно |
1420 |
|
NOP |
'вставить XOR [ASCII CODE]. |
1430 |
|
LD |
A,(IX+11) 'Младший байт длины. После |
1440 |
LLEN |
XOR |
#AC ' его проверки можно отсеять |
1450 |
|
JR |
NZ,A TYPE 'остальные файлы. |
1460 |
|
LD |
A,(IX+12) 'Проверка младшего байта. |
1470 |
HLEN |
XOR |
#0A 'Проверка старшего |
1480 |
|
JR |
NZ,A TYPE 'байта длины. |
1490 |
SLEN |
LD |
A,RDS2 'Проверка на количество секторов. |
1500 |
|
SUB |
(IX+13) 'Если не равно переменной |
1510 |
|
JR |
NZ,A TYPE 'RDS2, то это не выгрузка. |
1520 |
|
LDIR |
'Перенос проверенного имени. |
1530 |
|
LD |
A, (NFILES) 'Увеличение счетчика |
1540 |
|
INC |
A 'отобранных файлов. |
1550 |
|
LD |
(NFILES),A 'Сохранение счётчика. |
1560 |
A TYPE |
ADD |
HL,BC 'Проверка следующего файла. |
1570 |
|
JR |
LOOP4 ' |
1580 |
ENDCAT |
XOR |
A 'Занесение после последнего |
1590 |
|
LD |
(DE),A 'отобранного файла 0. |
1600 |
|
RET |
'Выход из подпрограммы. |
1610 |
NFILES |
DEFB |
#00 'Количество отобранных файлов. |
1620 |
LOAD |
|
'Подпрограмма загрузки положения игры. |
1630 |
|
LD |
A,(NFILES) 'Проверка количества выгрузок, |
1640 |
|
CP |
#00 'если ни одной, то выход с |
1650 |
|
JP |
Z,ERR1 'сообщением об их отсутствии. |
1660 |
|
CALL |
FINDAF 'Поиск имени файла, если файла |
1670 |
|
JP |
C,ERR2 'нет то выход с ошибкой. |
1680 |
|
LD |
HL,FROM D 'Настройка переменных чтения. |
1690 |
|
LD |
(CDLORS+1),HL ' |
1700 |
|
CALL |
SORL 'Вызов подпрограммы загрузки. |
1710 |
|
JR |
Z,ENDLD 'Выход из подпрограммы при ошибке. |
1720 |
|
LD |
HL,BUFFER 'Перенос выгрузки из буфера |
1730 |
|
LD |
DE,WYGR 'в программу. |
1740 |
|
LD |
BC,LENGHT ' |
1750 |
|
LDIR |
' |
1760 |
ENDLD |
RET |
' |
1770 SORL
'буфер
1780 |
LD а, в LD |
A,(IX+15) зависимости от пер (FINDTR+1),A |
Подпрограмма чтения или записи из )еменных. IX-данные файла. Поиск начальной дорожки. |
1790 |
CALL |
FINDTR |
|
1800 |
LD |
A,(IX+14) |
В A - начальный сектор. |
1810 |
LD |
HL,BUFFER |
В HL начало буфера. |
1820 |
LD |
BC,RDSECT |
BC количество секторов в буфере. |
1830 LOOP5 |
PUSH |
BC |
Сохранение BC. |
1840 |
INC |
A |
Увеличение номера сектора. |
1850 |
PUSH |
HL |
|
1860 |
PUSH |
AF |
|
1870 |
LD |
(SECT2),A |
Установка сектора. |
1880 |
CDLORS |
CALL |
FROM D |
Чтение/запись сектора. |
1890 |
SECT2 |
DEFB |
#00 |
|
1900 |
|
POP |
AF |
|
1910 |
|
POP |
HL |
|
1920 |
|
INC |
H |
Увеличение адреса на 256. |
1930 |
|
CP |
#10 |
проверка сектора, если не |
1940 |
|
JR |
NZ,LAB |
16, то переход на дальнейшее |
1950 |
|
PUSH |
HL |
чтение/запись, иначе |
1960 |
|
LD |
A, (FINDTR+1) |
сдвиг головки |
1970 |
|
INC |
A |
вперед на 1 трек. |
1980 |
|
LD |
(FINDTR+1),A |
|
1990 |
|
CALL |
GO TR |
|
2000 |
|
POP |
HL |
|
2010 |
|
XOR |
A |
Обнуление сектора. |
2020 |
LAB |
|
|
|
2030 |
|
POP |
BC |
Восстановление BC. |
2040 |
|
DJNZ |
LOOP5 |
Дальнейшее чтение. |
2050 |
|
RET |
|
|
2060 |
FINDTR |
LD |
A,01 |
Поиск дорожки. |
2070 |
|
CALL |
GO TR |
|
2080 |
|
RET |
|
|
2090 |
FINDAF |
LD |
HL,CAT ;Подпрограмма поиска имени файла среди |
|
; отобр |
анных |
по длине. HL-начало имени первого файла. |
2100 |
L1 |
LD |
A,(HL) |
Проверка конца каталога. |
2110 |
|
AND |
A |
Если первый байт имени |
2120 |
|
JR |
Z, END |
файла=0, то выход. |
2130 |
|
PUSH |
HL |
|
2140 |
|
LD |
DE,FNAME |
В DE - имя искомого файла. |
2150 |
|
LD |
BC,#0800 |
Количество байт в имени 8. |
2160 |
L2 |
LD |
A,(DE) |
Провер.первого байта имени. |
2170 |
|
INC |
DE |
DE=DE+1 |
2180 |
|
AND |
A |
проверка A на ноль.Если да, |
2190 |
|
JR |
Z, L3 |
то проверка следующего имени. |
2200 |
|
CP |
(HL) |
сравнение байтов имен. |
2210 |
|
INC |
HL |
увеличение адреса следующей |
2220 |
|
JR |
NZ, L3 |
буквы. Если не равны, то |
|
|
|
|
проверка следующего имени. |
2230 |
|
DJNZ |
L2 |
иначе проверка следующей буквы. |
2240 |
|
POP |
IX |
IX-адрес найденного имени. |
2250 |
|
SCF |
|
выключение флага переноса. |
2260 |
|
CCF |
|
|
2270 |
|
RET |
|
|
2280 |
L3 |
POP |
HL |
|
2290 |
|
LD |
DE,#0010 |
Адрес следующего имени: |
2300 |
|
ADD |
HL, DE |
равен HL=HL+16 |
2310 |
|
JR |
L1 |
Проверка, если файл |
2320 |
END |
SCF |
|
не найден, то включение |
2330 |
|
RET |
|
флага переноса и выход. |
2340 |
SAVE |
|
|
Подпрограмма записи положения игры. |
2350 |
|
LD |
HL,WYGR |
Перенос выгрузки из |
2360 |
|
LD |
DE,BUFFER |
программы в буфер. |
2370 |
|
LD |
BC,LENGHT |
|
2380 |
|
LDIR |
|
|
2390 |
|
CALL |
FINDAF |
Поиск имени. |
2400 |
|
JP |
C, NEWF |
Если файл не найден, создание нового файла. |
2410 |
SVE |
LD |
HL,ONDISK |
Иначе перезапись старого. |
2420 |
|
LD |
(CDLORS+1),HL |
Настройка переменных. |
2430 |
|
LD |
A,(IX+15) |
Дорожка начала файла. |
2440 |
|
LD |
(FINDTR+1),A |
|
2450 |
|
CALL |
FINDTR |
Поиск дорожки. |
2460 |
|
LD |
A,(IX+14) |
Сектор начала файла. |
2470 |
|
LD |
HL,BUFFER |
В HL - начало буфера. |
2480 |
|
LD |
BC,RDSECT |
В BC - количество секторов. |
2490 |
|
CALL |
SORL |
Запись блока секторов. |
2500 |
|
RET |
|
|
2510 |
NEWF |
CALL |
BG93 |
Создание нового файла. |
2520 |
|
DEFB |
#1F |
Команда восстановления. |
2530 |
|
DEFB |
#0C |
#^-регистр команд.
#0C=00 00110 0-восстановление. |
2540 |
|
CALL |
RESET |
RESET ВГ93. |
2550 |
|
CALL |
LOAD C |
Загрузка данных каталога. |
2560 |
|
DEFB |
#09 |
|
2570 |
|
LD |
HL,(CATDAT+#E5) |
проверка оставшихся сект. |
2580 |
|
LD |
DE,RDS1 |
на диске, если меньше RDS1, |
2590 |
|
SBC |
HL, DE |
то выход с сообщением об |
2600 |
|
JP |
C, ERR3 |
ошибке (no space on disk!). |
2610 |
|
LD |
(CATDAT+#E5) , HL |
|
2620 |
|
LD |
HL,CATDAT+#E4 |
Проверка количества файлов на |
2630 |
|
INC |
(HL) |
диске, если 128, то выход с |
2640 |
|
BIT |
7, (HL) |
сообщением об ошибке. |
2650 |
|
JP |
NZ, ERR3 |
|
2660 |
|
LD |
HL,(CATDAT+#E1) |
Изменение данных последнего |
2670 |
|
LD |
E, L |
трека/сектора. |
2680 |
|
LD |
D, H |
|
2690 |
|
PUSH |
DE |
|
2700 |
|
LD |
A,RDS2 |
В А количество секторов. |
2710 |
SSECT |
LD |
B,#10 |
В - количество секторов в треке. |
2720 |
|
ADD |
A, E |
|
2730 |
L5 |
CCF |
|
|
2740 |
|
SUB |
B |
|
2750 |
|
JR |
C, L6 |
|
2760 |
|
INC |
D |
|
2770 |
|
JR |
L5 |
|
2780 |
L6 |
ADD |
A,B |
|
2790 |
|
LD |
E, A |
|
2800 |
|
EX |
DE, HL |
|
2810 |
|
LD |
(CATDAT+#E1) , HL |
Сохранение последнего трека/сектора. |
2820 |
|
CALL |
CATSAV |
Запись измененных данных. |
2830 |
|
DEFB |
#09 |
|
2840 |
|
LD |
A,(CATDAT+#E4) |
A - количество файлов на диске. |
2850 |
|
DEC |
A |
Первоначальное количество файлов. |
2860 |
|
RRCA |
|
В результате этих манипуляций |
2870 |
|
RRCA |
|
получаем в А номер сектора |
2880 |
|
RRCA |
|
(от 1 до 8), в котором |
2890 |
|
RRCA |
|
находится имя последнего |
2900 |
|
PUSH |
AF |
файла на диске. На стеке |
2910 |
|
AND |
#07 |
имеем номер файла в |
2920 |
|
INC |
A |
секторе (1-16). |
2930 |
|
LD |
(SECT3),A |
Ввод переменных в программу. |
2940 |
|
LD |
(SECT4),A |
|
2950 |
|
CALL |
LOAD C |
Читаем сектор. |
2960 |
SECT3 |
DEFB |
#00 |
|
2970 |
|
POP |
AF |
|
2980 |
|
AND |
#F0 |
Создаём в памяти имя файла. |
2990 |
|
LD |
E, A |
|
3000 |
|
LD |
D, #00 |
|
3010 |
|
ADD |
HL, DE |
|
3020 |
|
PUSH |
HL |
|
3030 |
|
POP |
IX |
|
3040 |
|
EX |
DE, HL |
Копируем имя. |
3050 |
|
LD |
HL,FNAME |
|
3060 |
|
LD |
BC,#000E |
|
3070 |
|
LDIR |
|
|
3080 |
|
EX |
DE, HL |
|
3090 |
|
POP |
DE |
Вводим начальный |
3100 |
|
LD |
(HL),E |
сектор |
3110 |
|
INC |
HL |
и |
3120 |
|
LD |
(HL),D |
трек. |
3130 |
|
CALL |
CATSAV |
Записываем на диск |
3140 |
SECT4 |
DEFB |
#00 |
измененный сектор. |
3150 |
|
JP |
SVE |
На запись данных файла. |
3160 |
ERR1 |
CALL |
PRINT |
Ошибка 1. |
3170 |
|
DEFB |
#16 |
Если на диске нет |
3180 |
|
DEFB |
#10 |
выгрузок игры, |
3190 |
|
DEFB |
#03 |
то выдается |
3200 |
|
DEFB |
#10 |
это сообщение. |
3210 |
|
DEFB |
#07 |
|
3220 |
|
DEFB |
#11 |
|
3230 |
|
DEFB |
#00 |
|
3240 |
|
DEFM |
"no file(s) of restore game!%" |
3250 |
|
CALL |
ANYKEY |
|
3260 |
|
JP |
PAUSE |
|
3270 |
ERR2 |
CALL |
PRINT |
Ошибка 2. |
3280 |
|
DEFB |
#16 |
Файл не найден. |
3290 |
|
DEFB |
#10 |
|
3300 |
|
DEFB |
#09 |
|
3310 |
|
DEFB |
#10 |
|
3320 |
|
DEFB |
#07 |
|
3330 |
|
DEFB |
#11 |
|
3340 |
|
DEFB |
#00 |
|
3350 |
|
DEFM |
"file absent!%" |
|
3360 |
|
CALL |
ANYKEY |
|
3370 |
|
JP |
PAUSE |
|
3380 |
ERR3 |
CALL |
PRINT |
Ошибка 3. |
3390 |
|
DEFB |
#16 |
Нет места на диске. |
3400 |
|
DEFB |
#10 |
|
3410 |
|
DEFB |
#07 |
|
3420 |
|
DEFB |
#10 |
|
3430 |
|
DEFB |
#07 |
|
3440 |
|
DEFB |
#11 |
|
3450 |
|
DEFB |
#00 |
|
3460 |
|
DEFM |
"no space on disk!%" |
3470 |
|
CALL |
ANYKEY ; |
3480 |
|
JP |
PAUSE ; |
3490 |
ANYKEY |
|
|
3500 |
|
CALL |
PRINT |
|
3510 |
|
DEFB |
#16 |
|
3520 |
|
DEFB |
#12 |
|
3530 |
|
DEFB |
#09 |
|
3540 |
|
DEFB |
#10 |
|
3550 |
|
DEFB |
#07 |
|
3560 |
|
DEFB |
#11 |
|
3570 |
|
DEFB |
#00 |
|
3580 |
|
DEFB |
#13 |
|
3590 |
|
DEFB |
#01 |
|
3600 |
|
DEFM |
"press any key%" |
3610 |
|
RET |
; |
3620 |
PAUSE |
|
|
3630 |
NEXTP |
XOR |
A |
Подпрограмма ожидания нажатия |
3640 |
|
IN |
A, (#FE) |
любой клавиши. |
3650 |
|
CPL |
|
|
3660 |
|
AND |
#1F |
|
3670 |
|
JR |
Z,NEXTP |
|
3680 |
|
RET |
|
|
3690 |
ENTNAM |
CALL |
PRINT |
Подпрограмма ввода версии выгрузки. |
3700 |
|
DEFB |
#16 |
|
3710 |
|
DEFB |
#10 |
|
3720 |
|
DEFB |
#05 |
|
3730 |
|
DEFB |
#10 |
|
3540 |
|
DEFB |
#06 |
|
3750 |
|
DEFB |
#11 |
|
3760 |
|
DEFB |
#00 |
|
3770 |
|
DEFM |
"enter version letter%" |
3780 |
|
XOR |
A |
|
3790 |
|
LD |
(#5C08),A |
|
3800 |
LL |
LD |
A,(#5C08) |
|
3810 |
|
AND |
#DF |
|
3820 |
|
CP |
#41 |
|
3830 |
|
JR |
C, LL |
|
3840 |
|
CP |
#5B |
|
3850 |
|
JR |
NC, LL |
|
3860 |
|
LD |
(LETTER) ,A |
|
3870 |
|
RET |
|
|
|
|