АВТОРСКАЯ РАЗРАБОТКА
© С. Веремеенко, г. Екатеринбург.
ПРОСТОЙ ТРАНСЛИРУЮЩИЙ ДРАЙВЕР ВИДЕОПРОЦЕССОРА.
Вашему вниманию предлагался простой драйвер видеопроцессора, описание которого приведено в ZX РЕВЮ 1995/6. Основная цель этой статьи - познакомить читателей с методикой создания драйверов и на конкретном примере показать некоторые приёмы программирования на Ассемблере 6502. Поэтому программа написана нарочито "дубово", время для изысков пока не пришло.
Практически этот драйвер может использоваться для встраивания в прикладные программы, написанные на Ассемблере, не требующие анализа коллизии спрайтов. С применением этого драйвера написана программа "VIDEOART", представляющая собой редактор пейзажей. Драйвер DRIVT имеет и некоторые другие ограничения. Не поддерживаются многофазные спрайты, нет абсолютной адресации экранов, не реализована очередь команд, нет команд блочного ввода информации и т.д.
Однако он обладает неоспоримым достоинством, которое в данном случае явилось решающим. Его минимальный объём позволяет опубликовать листинг с подробными комментариями.
Для тех, кто по какой либо причине не сможет его ассемблировать, приведён шестнадцатеричный дамп.
Драйвер DRIVT имеет всего 15 команд. 14 из них двухбайтные и в особых комментариях не нуждаются. Они вызываются из ассемблера последовательностью команд:
LD A,COM ; команда (#00-#0D)
OUT (#7F) , A
LD A,ARG ; аргумент
OUT (#7F) , A
Эту последовательность удобно оформить в виде макроса COMV MAC
LD А,=0
OUT (#7F) , A
LD A, =1
OUT (#7F) , A
ENDM
Команда
LD A,#FF
OUT (#7F) , A
является однобайтной и называется "выполнение спрайта". Дело в том, что все команды меняющие координаты спрайта на экране или его атрибуты, запоминаются видеопроцессором, но не выполняются, пока не подана эта команда. Если бы команды управления спрайтами выполнялись сразу, то возникал бы эффект "дробления" спрайта, состоящего из нескольких элементов, при его движении. Такой подход не является оптимальным, но он позволяет простым способом достичь достаточно качественного управления спрайтами.
Особой является команда DREG1 (код #01). Как известно, при записи в регистр 2001h кода #00 появляется возможность ускорить процесс записи информации в видеоОЗУ в несколько сотен раз, но экран при этом гаснет. В DRIVT эта возможность реализована. Вы можете, не гася экран (команда DREG1, #1E), вводить информацию со скоростью 400 Бод, или, погасив его (команда DREGl, #00), увеличить эту скорость до 80-200 тысяч Бод. Поскольку процесс ввода синхронизирован сигналом WAIT, никаких искусственных задержек в программу вводить не нужно. Видеопроцессор сам примет ровно столько информации, сколько способен в текущем режима
Достоинство обоих режимов можно совместить, если реализовать очередь команд, но для такого простого драйвера это нецелесообразно.
001е******************************************************** 0 02;* * 003;* (С) С. Веремеенко *
004;* Драйвер видеопроцессора DRIVT *
005;* *
006е********************************************************
007 |
|
|
|
|
008 |
REG0 |
EQU |
00h |
; копия регистра 2000h |
009 |
REG1 |
EQU |
01h |
; копия регистра 2001h |
010 |
RG5L |
EQU |
02h |
; горизонтальный скроллинг |
011 |
RG5H |
EQU |
03h |
; вертикальный скроллинг |
012 |
RG6L |
EQU |
04h |
; текущий адрес VRAL, мл. байт |
013 |
RG6H |
EQU |
05h |
; текущий адрес VRAM, ст. байт |
014 |
COM |
EQU |
0 6h |
; буфер команды |
015 |
DATA |
EQU |
07h |
; буфер данных |
016 |
NUMSP |
EQU |
0 8h |
; номер элемента спрайта |
017 |
REG11 |
EQU |
0 9h |
; временная копия REG1 |
018 |
FCOM |
EQU |
10h |
; семафор команды |
019 |
FUSE |
EQU |
11h |
; семафор исполнения |
020 |
FWRV |
EQU |
12h |
; семафор записи |
021 |
ADRL |
EQU |
2 0h |
; адрес записи VRAM, L-байт |
022 |
ADRH |
EQU |
21h |
; адрес записи VRAM, Н-байт |
023 |
|
|
|
|
024 |
|
|
|
|
025 |
|
|
|
|
026 |
|
ORG |
0F800h |
|
027 |
|
|
|
|
028 |
BEGIN |
SEI |
|
; запрет маскируемых прерываний |
029 |
|
CLD |
|
; двоичный режим |
030 |
|
LDA |
|
; #00h |
031 |
|
STA |
6000h |
; снятие WAIT ZX-SPECTRUM |
032 |
|
STA |
2 0 0 0h |
; запрет немаскируемых прерываний |
033 |
|
STA |
2 0 01h |
; гашение экрана |
034 |
L0 |
LDA |
2 0 02h |
; пауза 2 0 mS для установки |
035 |
|
BPL |
L0 |
; начального состояния |
036 |
L1 |
LDA |
2 0 02h |
; видеопроцессора, эмуляция |
037 |
|
BMI |
LI |
; сигнала "RESET" |
038 |
|
|
|
|
039 |
|
LDA |
#3Fh |
|
040 |
|
STA, |
2 0 0 6h |
|
041 |
|
LDA |
#0F0h |
|
042 |
|
STA |
2006H |
; адрес ВидеоОЗУ 03FF0h |
043 |
|
LDA |
#0Dh |
|
044 |
|
STA |
2007h |
; чёрный фон |
045 |
|
|
|
|
046 |
|
LDX |
#0FFh |
|
047 |
|
TXS |
|
; указатель стека 01FFh |
048 |
|
|
|
|
049 |
|
LDA |
#2 0h |
|
050 |
|
STA |
2 0 0 6h |
|
051 |
|
LDA |
#00h |
; 2 000h - адрес |
052 |
|
STA |
2006 |
; нулевого экрана |
L4
Все экраны очищены
2006h 2006h
TYA
L2 STA 0,Y
I NY BNE L2
; Нулевая страница ОЗУ (0000h-00FFh) обнулена
0200h,Y ; запись 00h по адресу 0200h+Y
STA I NY
BNE L3
; Вторая страница ОЗУ (0200h-02FFh), в которой размещён ; буфер спрайтов, обнулена
LDA #8 0h ; разрешение немаскируемых
STA 2 000h ; прерываний
LOOP CLI ; разрешение маскируемых
JMP LOOP ; прерываний и "теневая"
; задача - пустой цикл. Приём команды идёт по маскируемому ; прерыванию, выполнение в необходимых случаях ; по немаскируемому.
053
054
055
056
057
058
059
060 061 062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080 081 082
083
084
085
086
087
088
089
090
#10h #00h #00h 2007h
L4
L4
16 страниц по 256 байт
это объём 4 экранов
заполняющий байт
запись 00h в видеоОЗУ
инкремент младшего байта счётчика
LDX LDY LDA STA I NY BNE DEX BNE
; декремент счетчика страниц заполнены 0 0h
; X и Y равны нулю, поэтому ; адрес видеоОЗУ - 0000h
; А=Y=0 0h
; запись 0 0h по адресу 0 0h+Y ; инкремент указателя
команда 0FFh - выполнение спрайта,
091 |
USSPT LDA |
#0FFh |
; семафор FUSE устанавливаем |
092 |
STA |
FUSE |
; в 0FFh |
093 |
LDA |
REG0 |
; текущее значение per. 2 000h |
094 |
ORA |
#8 0h |
; 7 бит устанавливаем в 1 |
095 |
STA |
2 0 0 0h |
; временно разрешаем |
096 |
; немаскируемые прерывания, если они были запрещены. |
097 |
USS LDA |
FUSE |
; ожидаем пока семафор не |
098 |
BNE |
USS |
; будет сброшен в процедуре |
099 |
|
|
; немаскируемого прерывания, |
100 |
LDA |
REG0 |
; восстановление режима |
101 |
STA |
2 0 0 0h |
; регистра 2000h |
102 |
STA |
6000h |
; сброс WAIT ZX-SPEGTRUM |
103 |
RTI |
|
; возврат в цикл LOOP |
104 |
|
|
|
FCOM ARGL 6000h USSPT #0Fh
СОМ #FFh FCOM 6000h - приём команды от ZX-SPECTRUM семафор команды. Если он не равен 00h - аргумент команда от ZX-SPECTRUM если D7=1, то исполнение ограничение количества команд до 16 сохранение команды ожидаем аргумент
105
106
107
108
109
110 111 112
113
114
115
116
117
118
119
120 121 122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
LDX BNE LDA BMI AND
STA LDA STA STA RTI
Её код в ячейке СОМ ARGL LDA #00h ; восстановление семафора
FCOM ; команды
СОМ ; код команды в аккумуляторе
А ; удваиваем его
; и заносим в Y TABL,Y ; младший байт адреса из TABL JM+1 ; модификация адреса в
; команде перехода. Некрасиво ; но экономно. TABL+1,Y ; старший байт адреса из TABL JM+2 ;еще одна модификация
60 0 0h ; аргумент в аккумуляторе
; дублируем его в X JM JMP 0 ; адрес перехода берется из
;TABL и заносится в аргумент ; команды JMP до того как она выполнится.
LDA STA LDA ASL TAY LDA STA
сброс WAIT
возврат из прерывания
14 0 TABL |
DEFW |
DREGO |
; 00h, |
установка регистра 2000h |
141 |
DEFW |
DREG1 |
; 01h, |
установка регистра 2001h |
142 |
DEFW |
DRGX |
; 02h, |
горизонтальный скроллинг |
143 |
DEFW |
DRGY |
; 03h, |
вертикальный |
скроллинг |
144 |
DEFW |
DRG6L |
; 04h, |
младший байт |
регистра 2006h |
145 |
DEFW |
DRG6H |
; 05h, |
старший байт |
регистра 2006h |
146 |
DEFW |
ADRLV |
; 0 6h, |
младший байт |
адреса видео |
147 |
DEFW |
ADRHV |
; 07h, |
старший байт |
адреса видео |
148 |
DEFW |
DATAV |
; 08h, |
данные видео |
|
149 |
DEFW |
XSPRT |
; 0 9h, |
Х-координата |
блока спрайта |
150 |
DEFW |
YSPRT |
; 0Ah, |
Y-координата |
блока спрайта |
151 |
DEFW |
ZSPRT |
; 0Bh, |
код блока спрайта |
152 |
DEFW |
ASPRT |
; 0Ch, |
атрибут блока |
спрайта |
153 |
DEFW |
NSPRT |
; 0Dh, |
номер элемента спрайта |
154 |
DEFW |
REZ |
; 0Eh, |
резерв |
|
155 |
DEFW |
REZ |
; 0Fh, |
резерв |
|
156
157 |
REZ |
STA |
6000h |
; |
сброс WAIT без выполнения |
158 |
|
RTI |
|
; |
команды |
159 |
|
|
|
|
|
160 |
DREGO |
STA |
REGO |
; |
копия 2 000h |
161 |
|
STA |
2 0 0 0h |
; |
непосредственное выполнение |
162 |
|
STA |
6000h |
|
|
163 |
|
RTI |
|
|
|
164 |
|
|
|
|
|
165 |
DREG1 |
STA |
REG1 |
|
аргумент в REG1 |
166 |
LDRG |
CMP |
REG11 |
|
ждем, пока REG 1 и REG11 |
167 |
|
BNE |
LDRG |
|
не сравняются |
168 |
|
CMP |
#00h |
|
если регистр 2001h |
169 |
|
BEQ |
DR11 |
|
установлен в 00h, то ... |
170 |
|
LDA |
REGO |
|
иначе восстановление |
171 |
|
STA |
2 0 0 0h |
; |
регистра 2000h |
172 |
|
STA |
6000h |
|
|
173 |
|
RTI |
|
|
|
174 |
|
|
|
|
|
175 |
DR11 |
LDA |
#00h |
; |
... запрет немаскируемого |
176 |
|
STA |
2 0 0 0h |
; |
прерывания |
177 |
|
STA |
6000h |
|
|
178 |
|
RTI |
|
|
|
179 |
|
|
|
|
|
180 |
DRGX |
STA |
RG5L |
; |
загрузка регистра горизонтального |
181 |
|
STA |
6000h |
; |
скроллинга. Исполнение в |
182 |
|
RTI |
|
; |
немаскируемом прерывании |
183 |
|
|
|
|
|
184 |
DRGY |
STA |
RG5H |
; |
вертикальный скроллинг организован |
185 |
|
STA |
6000h |
; |
аналогично горизонтальному |
186 |
|
RTI |
|
|
|
187 |
|
|
|
|
|
188 |
DRG6L |
STA |
RG6L |
; |
установка текущего состояния |
189 |
|
STA |
6000h |
; |
регистра 2006h |
190 |
|
RTI |
|
; |
младший байт |
191 |
|
|
|
|
|
192 |
DRG6H |
STA |
RG6H |
; |
то же, старший байт |
193 |
|
STA |
6000h |
|
|
194 |
|
RTI |
|
|
|
195 |
|
|
|
|
|
196 |
ADRHV |
STA |
ADRH |
; |
адрес видеоОЗУ |
197 |
|
STA |
6000h |
; |
старший байт |
198 |
|
RTI |
|
|
|
199 |
|
|
|
|
|
200 |
ADRLV |
STA |
ADRL |
; |
адрес видеоОЗУ |
201 |
|
STA |
6000h |
; |
младший байт |
202 |
|
RTI |
|
|
|
203 |
|
|
|
|
|
204 |
DATAV |
LDA |
REG1 |
; |
если регистр 2001h установлен |
205 |
|
BEQ |
PTV1 |
; |
в 00h, непосредственное выполнение |
206 |
|
LDA |
REG0 |
; |
иначе временное разрешение |
207 |
|
ORA |
#8 0h |
; |
немаскируемых прерываний |
208 |
|
STA |
2 0 0 0h |
|
|
209 |
|
STX |
DATA |
|
загружаемые данные |
210 |
|
LDA |
0FFh |
|
установка семафора |
211 |
|
STA |
FWRV |
|
|
212 |
DTV |
LDA |
FWRV |
|
ожидание сброса семафора |
213 |
|
BNE |
DTV |
|
|
214 |
|
LDA |
REGO |
|
восстановление |
215 |
|
STA |
2 0 0 0h |
|
регистра 2000h |
216 |
|
STA |
6000h |
|
|
217 |
|
RTI |
|
|
|
218 |
|
|
|
|
|
219 |
DTV1 |
LDA |
ADRH |
|
установка адреса |
220 |
|
STA |
2 00 6b |
|
видеоОЗУ |
221 |
|
LDA |
ADRL |
|
|
222 |
|
STA |
2 0 0 6h |
|
|
223 |
|
STX |
2007h |
|
загрузка данных |
224 |
|
LDA |
RG6H |
|
постановление текущего |
225 |
|
STA |
2 0 0 6h |
|
адреса видеоОЗУ |
226 |
|
LDA |
RG6L |
|
|
227 |
|
STA |
2 0 0 6h |
|
|
228 |
|
STA |
6000h |
|
|
229 |
|
RTI |
|
|
|
230 |
|
|
|
|
|
231 |
|
232 |
* |
команды |
управления |
спрайтами * |
233 |
|
234 |
|
|
|
|
|
235 |
NSPRT |
AND |
#3Fh |
|
ограничение номера спрайта |
236 |
|
STA |
NUMSP |
|
от 0 до 63 |
237 |
|
STA |
6000h |
|
|
238 |
|
RTI |
|
|
|
239 |
|
|
|
|
|
240 |
XSPRT |
LDA |
NUMSP |
|
номер спрайта |
241 |
|
ASL |
A |
|
умножаем |
242 |
|
ASL |
A |
|
на четыре |
243 |
|
TAY |
|
|
и загружаем в Y |
244 |
|
TXA |
|
|
аргумент в аккумуляторе |
245 |
|
STA |
02 03h,Y |
|
загружаем его в 0203h+Y |
246 |
|
STA |
6000h |
|
|
247 |
|
RTI |
|
|
|
248 |
|
|
|
|
|
249 |
YSPRT |
LDA |
NUMSP |
|
аналогично XSPRT |
250 |
|
ASL |
A |
|
|
251 |
|
ASL |
A |
|
|
252 |
|
TAY |
|
|
|
253 |
|
TXA |
|
|
|
254 |
|
STA |
02 0 0h,Y |
|
|
255 |
|
STA |
6000h |
|
|
256 |
|
RTI |
|
|
|
257 |
|
|
|
|
|
258 |
ZSPRT |
LDA |
NUMSP |
|
аналогично XSPRT |
259 |
|
ASL |
A |
|
|
260 |
|
ASL |
A |
|
|
261 |
|
TAY |
|
|
262 |
|
TXA |
|
|
263 |
|
STA |
02 01h,Y |
|
264 |
|
STA |
6000h |
|
265 |
|
RTI |
|
|
266 |
|
|
|
|
267 |
ASPRT |
LDA |
NUMSP ; аналогично XSPRT |
|
268 |
|
ASL |
A |
|
269 |
|
ASL |
A |
|
270 |
|
TAY |
|
|
271 |
|
TXA |
|
|
272 |
|
STA |
02 02h,Y |
|
273 |
|
STA |
6000h |
|
274 |
|
RTI |
|
|
275 |
|
|
|
|
276 |
; |
** |
277 |
*
; |
немаскируемое прерывание, выполнение команды |
* |
278 |
; |
** |
279 |
|
|
|
|
280 |
NINT |
SEI |
; запрет маскируемого, прерывания |
281 |
|
PHA |
; аккумулятор в стек |
|
282 |
|
TXA |
|
|
283 |
|
PHA |
; X в стек |
|
284 |
|
TYA |
|
|
285 |
|
PHA |
; Y в стек |
|
286 |
|
|
|
|
287 |
|
LDA |
FWRV ; проверка семафора FWRV |
|
288 |
|
BNE |
WRVID ; запись в видеоОЗУ |
|
289 |
|
LDA |
FUSE ; проверка семафора FUSE |
|
290 |
|
BEQ |
EXIN ; если нет, то конец |
|
291 |
|
|
|
|
292 |
|
LDA |
#00h ; установка параметров |
|
293 |
|
STA |
2 0 03h ; контроллер ПДП |
|
294 |
|
LDA |
#02h ; и его |
|
295 |
|
STA |
4 014h ; запуск |
|
296 |
|
LDA |
#60h ; сброс семафора |
|
297 |
|
STA |
FUSE |
|
298 |
|
JMP |
EXIN ; и выход |
|
299 |
|
|
|
|
300 |
WRVID |
LDA |
ADRH ; установка адреса записи |
|
301 |
|
STA |
2 0 0 6h ; в видеоОЗУ |
|
302 |
|
LDA |
ADRL |
|
303 |
|
STA |
2 0 0 6h |
|
304 |
|
LDA |
DATA ; запись в видеоОЗУ |
|
305 |
|
STA |
2007h |
|
306 |
|
LDA |
#0 0h ; сброс семафора FWRV |
|
307 |
|
STA |
FWRV |
|
308 |
|
|
|
|
309 |
EXIN |
LDA |
RG5H ; выполнение скроллинга |
|
310 |
|
STA |
2005h |
|
311 |
|
LDA |
RG5L |
|
312 |
|
STA |
2005h |
|
313 |
LDA |
RG6H |
; восстановление текущего |
314 |
STA |
2 0 0 6h |
; адреса видеоОЗУ |
315 |
LDA |
RG6L |
|
316 |
STA |
2 0 0 6h |
|
317 |
LDA |
REG1 |
; копирование REG1 |
318 |
STA |
REG11 |
; в REG11 |
319 |
STA |
200 1h |
; и запись в регистр 2001h |
320 |
PLA |
|
|
321 |
TYA |
|
; Y из стека |
322 |
PLA |
|
|
323 |
TXA |
|
; X из стека |
324 |
PLA |
|
; аккумулятор из стека |
325 |
CLI |
|
; разрешение маскируемого прерывания |
326 |
RTI |
|
; выход из процедуры |
327 |
|
|
|
328 |
DEFS |
0FFFAh-$ |
|
32 9 ; эта команда обеспечивает правильную установку системных
33 0 ; векторов при произвольном (в разумных пределах) ORG
331
332 NMI DEFW NINT
333 START DEFW BEGIN
334 IRQ DEFW INTER
Исправьте неточности!
В схеме видеопроцессора (ZX РЕВЮ 95/6, стр. 7).
1. Ламели разъема X1.1 и XL2 должны быть пронумерованы сверху вниз от 1 до 30.
2. У дешифраторов 1533ИД4 номера выводов 1 и 2 нужно поменять местами. Знак инверсии стоит правильно.
3. В разрыв шины 82 (идет от D6 к D2) нужно поставить инвертор.
4. Выводы 2 и 4 микросхемы D5 надо соединить с "землей" через конденсаторы n16. _5. На шину питания поставить блокировочные конденсаторы 47М и 4 шт. 68n._