Полная адаптация программ к диску без использования системных переменных 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, без которой ничего работать не будет отдельно от игры.
|
|
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 |
|
Ошибка 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 |
|
Ошибка 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 |
|
Ошибка 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 |
| ||
|
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 |
|
Подпрограмма ввода версии выгрузки. |
|
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 | |||