|
Секреты 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 |
|
|
|
|