-
Notifications
You must be signed in to change notification settings - Fork 1
/
hw_md.s
433 lines (391 loc) · 14.5 KB
/
hw_md.s
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
| SEGA MegaDrive support code
| by Chilly Willy
.text
.align 2
| Initialize the hardware & load font tiles
.global init_hardware
init_hardware:
movem.l d2-d7/a2-a6,-(sp)
| init joyports
lea 0xA10000,a5
move.b #0x40,0x09(a5)
move.b #0x40,0x0B(a5)
move.b #0x40,0x03(a5)
move.b #0x40,0x05(a5)
lea 0xC00000,a3 /* VDP data reg */
lea 0xC00004,a4 /* VDP cmd/sts reg */
| wait on VDP DMA (in case we reset in the middle of DMA)
move.w #0x8114,(a4) /* display off, dma enabled */
0:
move.w (a4),d0 /* read VDP status */
btst #1,d0 /* DMA busy? */
bne.b 0b /* yes */
moveq #0,d0
move.w #0x8000,d5 /* set VDP register 0 */
move.w #0x0100,d7
| Set VDP registers
lea InitVDPRegs(pc),a5
moveq #18,d1
1:
move.b (a5)+,d5 /* lower byte = register data */
move.w d5,(a4) /* set VDP register */
add.w d7,d5 /* + 0x0100 = next register */
dbra d1,1b
| clear VRAM
move.w #0x8F02,(a4) /* set INC to 2 */
move.l #0x40000000,(a4) /* write VRAM address 0 */
move.w #0x7FFF,d1 /* 32K - 1 words */
2:
move.w d0,(a3) /* clear VRAM */
dbra d1,2b
| The VDP state at this point is: Display disabled, ints disabled, Name Tbl A at 0xC000,
| Name Tbl B at 0xE000, Name Tbl W at 0xB000, Sprite Attr Tbl at 0xA800, HScroll Tbl at 0xAC00,
| H40 V28 mode, and Scroll size is 64x32.
| Clear CRAM
lea InitVDPRAM(pc),a5
move.l (a5)+,(a4) /* set reg 1 and reg 15 */
move.l (a5)+,(a4) /* write CRAM address 0 */
moveq #31,d3
3:
move.l d0,(a3)
dbra d3,3b
| Clear VSRAM
move.l (a5)+,(a4) /* write VSRAM address 0 */
moveq #19,d4
4:
move.l d0,(a3)
dbra d4,4b
| halt Z80 and init FM chip
/* Allow the 68k to access the FM chip */
move.w #0x100,0xA11100
move.w #0x100,0xA11200
| reset YM2612
lea FMReset(pc),a5
lea 0xA00000,a0
move.w #0x4000,d1
moveq #26,d2
5:
move.b (a5)+,d1 /* FM reg */
move.b (a5)+,0(a0,d1.w) /* FM data */
nop
nop
dbra d2,5b
moveq #0x30,d0
moveq #0x5F,d2
6:
move.b d0,0x4000(a0) /* FM reg */
nop
nop
move.b #0xFF,0x4001(a0) /* FM data */
nop
nop
move.b d0,0x4002(a0) /* FM reg */
nop
nop
move.b #0xFF,0x4003(a0) /* FM data */
nop
nop
addq.b #1,d0
dbra d2,6b
| reset PSG
lea PSGReset(pc),a5
lea 0xC00000,a0
move.b (a5)+,0x0011(a0)
move.b (a5)+,0x0011(a0)
move.b (a5)+,0x0011(a0)
move.b (a5),0x0011(a0)
| load font tile data
move.w #0x8F02,(a4) /* INC = 2 */
move.l #0x40000000,(a4) /* write VRAM address 0 */
lea font_data,a0
move.w #0x6B*8-1,d2
7:
move.l (a0)+,d0 /* font fg mask */
move.l d0,d1
not.l d1 /* font bg mask */
andi.l #0x11111111,d0 /* set font fg color */
andi.l #0x00000000,d1 /* set font bg color */
or.l d1,d0
move.l d0,(a3) /* set tile line */
dbra d2,7b
| set the default palette for text
move.l #0xC0000000,(a4) /* write CRAM address 0 */
move.l #0x00000CCC,(a3) /* entry 0 (black) and 1 (lt gray) BGR */
move.l #0xC0200000,(a4) /* write CRAM address 32 */
move.l #0x000000A0,(a3) /* entry 16 (black) BGR and 17 (green) */
move.l #0xC0400000,(a4) /* write CRAM address 64 */
move.l #0x0000000A,(a3) /* entry 32 (black) BGR and 33 (red) */
move.w #0x8174,(a4) /* display on, vblank enabled */
move #0x2000,sr /* enable interrupts */
movem.l (sp)+,d2-d7/a2-a6
rts
| VDP register initialization values
InitVDPRegs:
.byte 0x04 /* 8004 => write reg 0 = /IE1 (no HBL INT), /M3 (enable read H/V cnt) */
.byte 0x14 /* 8114 => write reg 1 = /DISP (display off), /IE0 (no VBL INT), M1 (DMA enabled), /M2 (V28 mode) */
.byte 0x30 /* 8230 => write reg 2 = Name Tbl A = 0xC000 */
.byte 0x2C /* 832C => write reg 3 = Name Tbl W = 0xB000 */
.byte 0x07 /* 8407 => write reg 4 = Name Tbl B = 0xE000 */
.byte 0x54 /* 8554 => write reg 5 = Sprite Attr Tbl = 0xA800 */
.byte 0x00 /* 8600 => write reg 6 = always 0 */
.byte 0x00 /* 8700 => write reg 7 = BG color */
.byte 0x00 /* 8800 => write reg 8 = always 0 */
.byte 0x00 /* 8900 => write reg 9 = always 0 */
.byte 0x00 /* 8A00 => write reg 10 = HINT = 0 */
.byte 0x00 /* 8B00 => write reg 11 = /IE2 (no EXT INT), full scroll */
.byte 0x81 /* 8C81 => write reg 12 = H40 mode, no lace, no shadow/hilite */
.byte 0x2B /* 8D2B => write reg 13 = HScroll Tbl = 0xAC00 */
.byte 0x00 /* 8E00 => write reg 14 = always 0 */
.byte 0x01 /* 8F01 => write reg 15 = data INC = 1 */
.byte 0x01 /* 9001 => write reg 16 = Scroll Size = 64x32 */
.byte 0x00 /* 9100 => write reg 17 = W Pos H = left */
.byte 0x00 /* 9200 => write reg 18 = W Pos V = top */
.align 2
| VDP Commands
InitVDPRAM:
.word 0x8104, 0x8F01 /* set registers 1 (display off) and 15 (INC = 1) */
.word 0xC000, 0x0000 /* write CRAM address 0 */
.word 0x4000, 0x0010 /* write VSRAM address 0 */
FMReset:
/* disable LFO */
.byte 0,0x22
.byte 1,0x00
/* disable timer & set channel 6 to normal mode */
.byte 0,0x27
.byte 1,0x00
/* all KEY_OFF */
.byte 0,0x28
.byte 1,0x00
.byte 1,0x04
.byte 1,0x01
.byte 1,0x05
.byte 1,0x02
.byte 1,0x06
/* disable DAC */
.byte 0,0x2A
.byte 1,0x80
.byte 0,0x2B
.byte 1,0x00
/* turn off channels */
.byte 0,0xB4
.byte 1,0x00
.byte 0,0xB5
.byte 1,0x00
.byte 0,0xB6
.byte 1,0x00
.byte 2,0xB4
.byte 3,0x00
.byte 2,0xB5
.byte 3,0x00
.byte 2,0xB6
.byte 3,0x00
| PSG register initialization values
PSGReset:
.byte 0x9f /* set ch0 attenuation to max */
.byte 0xbf /* set ch1 attenuation to max */
.byte 0xdf /* set ch2 attenuation to max */
.byte 0xff /* set ch3 attenuation to max */
.align 2
| short set_sr(short new_sr);
| set SR, return previous SR
| entry: arg = SR value
| exit: d0 = previous SR value
.global set_sr
set_sr:
moveq #0,d0
move.w sr,d0
move.l 4(sp),d1
move.w d1,sr
rts
| short get_pad(short pad);
| return buttons for selected pad
| entry: arg = pad index (0 or 1)
| exit: d0 = pad value (0 0 0 1 M X Y Z S A C B R L D U) or (0 0 0 0 0 0 0 0 S A C B R L D U)
.global get_pad
get_pad:
move.l d2,-(sp)
move.l 8(sp),d0 /* first arg is pad number */
cmpi.w #1,d0
bhi no_pad
add.w d0,d0
addi.l #0xA10003,d0 /* pad control register */
movea.l d0,a0
bsr.b get_input /* - 0 s a 0 0 d u - 1 c b r l d u */
move.w d0,d1
andi.w #0x0C00,d0
bne.b no_pad
bsr.b get_input /* - 0 s a 0 0 d u - 1 c b r l d u */
bsr.b get_input /* - 0 s a 0 0 0 0 - 1 c b m x y z */
move.w d0,d2
bsr.b get_input /* - 0 s a 1 1 1 1 - 1 c b r l d u */
andi.w #0x0F00,d0 /* 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 */
cmpi.w #0x0F00,d0
beq.b common /* six button pad */
move.w #0x010F,d2 /* three button pad */
common:
lsl.b #4,d2 /* - 0 s a 0 0 0 0 m x y z 0 0 0 0 */
lsl.w #4,d2 /* 0 0 0 0 m x y z 0 0 0 0 0 0 0 0 */
andi.w #0x303F,d1 /* 0 0 s a 0 0 0 0 0 0 c b r l d u */
move.b d1,d2 /* 0 0 0 0 m x y z 0 0 c b r l d u */
lsr.w #6,d1 /* 0 0 0 0 0 0 0 0 s a 0 0 0 0 0 0 */
or.w d1,d2 /* 0 0 0 0 m x y z s a c b r l d u */
eori.w #0x1FFF,d2 /* 0 0 0 1 M X Y Z S A C B R L D U */
move.w d2,d0
move.l (sp)+,d2
rts
| 3-button/6-button pad not found
no_pad:
.ifdef HAS_SMS_PAD
move.b (a0),d0 /* - 1 c b r l d u */
andi.w #0x003F,d0 /* 0 0 0 0 0 0 0 0 0 0 c b r l d u */
eori.w #0x003F,d0 /* 0 0 0 0 0 0 0 0 0 0 C B R L D U */
.else
move.w #0xF000,d0 /* SEGA_CTRL_NONE */
.endif
move.l (sp)+,d2
rts
| read single phase from controller
get_input:
move.b #0x00,(a0)
nop
nop
move.b (a0),d0
move.b #0x40,(a0)
lsl.w #8,d0
move.b (a0),d0
rts
| void clear_screen(void);
| clear the name table for plane B
.global clear_screen
clear_screen:
moveq #0,d0
lea 0xC00000,a0
move.w #0x8F02,4(a0) /* set INC to 2 */
move.l #0x60000003,d1 /* VDP write VRAM at 0xE000 (scroll plane B) */
move.l d1,4(a0) /* write VRAM at plane B start */
move.w #64*32-1,d1
1:
move.w d0,(a0) /* clear name pattern */
dbra d1,1b
rts
| void put_str(char *str, int color, int x, int y);
| put string characters to the screen
| entry: first arg = string address
| second arg = 0 for normal color font, N * 0x0200 for alternate color font (use CP bits for different colors)
| third arg = column at which to start printing
| fourth arg = row at which to start printing
.global put_str
put_str:
movea.l 4(sp),a0 /* string pointer */
move.l 8(sp),d0 /* color palette */
lea 0xC00000,a1
move.w #0x8F02,4(a1) /* set INC to 2 */
move.l 16(sp),d1 /* y coord */
lsl.l #6,d1
or.l 12(sp),d1 /* cursor y<<6 | x */
add.w d1,d1 /* pattern names are words */
swap d1
ori.l #0x60000003,d1 /* OR cursor with VDP write VRAM at 0xE000 (scroll plane B) */
move.l d1,4(a1) /* write VRAM at location of cursor in plane B */
1:
move.b (a0)+,d0
subi.b #0x20,d0 /* font starts at space */
move.w d0,(a1) /* set pattern name for character */
tst.b (a0)
bne.b 1b
rts
| void put_chr(char chr, int color, int x, int y);
| put a character to the screen
| entry: first arg = character
| second arg = 0 for normal color font, N * 0x0200 for alternate color font (use CP bits for different colors)
| third arg = column at which to start printing
| fourth arg = row at which to start printing
.global put_chr
put_chr:
movea.l 4(sp),a0 /* character */
move.l 8(sp),d0 /* color palette */
lea 0xC00000,a1
move.w #0x8F02,4(a1) /* set INC to 2 */
move.l 16(sp),d1 /* y coord */
lsl.l #6,d1
or.l 12(sp),d1 /* cursor y<<6 | x */
add.w d1,d1 /* pattern names are words */
swap d1
ori.l #0x60000003,d1 /* OR cursor with VDP write VRAM at 0xE000 (scroll plane B) */
move.l d1,4(a1) /* write VRAM at location of cursor in plane B */
move.l a0,d1
move.b d1,d0
subi.b #0x20,d0 /* font starts at space */
move.w d0,(a1) /* set pattern name for character */
rts
| void delay(int count);
| wait count number of vertical blank periods - relies on vblank running
| entry: arg = count
.global delay
delay:
move.l 4(sp),d0 /* count */
add.l gTicks,d0 /* add current vblank count */
0:
cmp.l gTicks,d0
bgt.b 0b
rts
| void set_palette(short *pal, int start, int count)
| copy count entries pointed to by pal into the palette starting at the index start
| entry: pal = pointer to an array of words holding the colors
| start = index of the first color in the palette to set
| count = number of colors to copy
.global set_palette
set_palette:
movea.l 4(sp),a0 /* pal */
move.l 8(sp),d0 /* start */
move.l 12(sp),d1 /* count */
add.w d0,d0 /* start*2 */
swap d0 /* high word holds address */
ori.l #0xC0000000,d0 /* write CRAM address (0 + index*2) */
subq.w #1,d1 /* for dbra */
lea 0xC00000,a1
move.w #0x8F02,4(a1) /* set INC to 2 */
move.l d0,4(a1) /* write CRAM */
0:
move.w (a0)+,(a1) /* copy color to palette */
dbra d1,0b
rts
| void write_byte(void *dst, unsigned char val)
.global write_byte
write_byte:
movea.l 4(sp),a0
move.l 8(sp),d0
move.b d0,(a0)
rts
| void write_word(void *dst, unsigned short val)
.global write_word
write_word:
movea.l 4(sp),a0
move.l 8(sp),d0
move.w d0,(a0)
rts
| void write_long(void *dst, unsigned int val)
.global write_long
write_long:
movea.l 4(sp),a0
move.l 8(sp),d0
move.l d0,(a0)
rts
| unsigned char read_byte(void *src)
.global read_byte
read_byte:
movea.l 4(sp),a0
move.b (a0),d0
rts
| unsigned short read_word(void *src)
.global read_word
read_word:
movea.l 4(sp),a0
move.w (a0),d0
rts
| unsigned int read_long(void *src)
.global read_long
read_long:
movea.l 4(sp),a0
move.l (a0),d0
rts