forked from sonicretro/skdisasm
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsonic3k.macros.asm
366 lines (319 loc) · 10.5 KB
/
sonic3k.macros.asm
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
; simplifying macros and functions
; nameless temporary symbols should NOT be used inside macros because they can interfere with the surrounding code
; normal labels should be used instead (which automatically become local to the macro)
; sign-extends a 32-bit integer to 64-bit
; all RAM addresses are run through this function to allow them to work in both 16-bit and 32-bit addressing modes
ramaddr function x,(-(x&$80000000)<<1)|x
; makes a VDP command
vdpComm function addr,type,rwd,(((type&rwd)&3)<<30)|((addr&$3FFF)<<16)|(((type&rwd)&$FC)<<2)|((addr&$C000)>>14)
; values for the type argument
VRAM = $21
CRAM = $2B
VSRAM = $25
; values for the rwd argument
READ = $C
WRITE = $7
DMA = $27
; tells the VDP to copy a region of 68k memory to VRAM or CRAM or VSRAM
dma68kToVDP macro source,dest,length,type
lea (VDP_control_port).l,a5
move.l #(($9400|((((length)>>1)&$FF00)>>8))<<16)|($9300|(((length)>>1)&$FF)),(a5)
move.l #(($9600|((((source)>>1)&$FF00)>>8))<<16)|($9500|(((source)>>1)&$FF)),(a5)
move.w #$9700|(((((source)>>1)&$FF0000)>>16)&$7F),(a5)
move.w #((vdpComm(dest,type,DMA)>>16)&$FFFF),(a5)
move.w #(vdpComm(dest,type,DMA)&$FFFF),(DMA_trigger_word).w
move.w (DMA_trigger_word).w,(a5)
; From ' § 7 DMA TRANSFER' of https://emu-docs.org/Genesis/sega2f.htm:
;
; "In the case of ROM to VRAM transfers,
; a hardware feature causes occasional failure of DMA unless the
; following two conditions are observed:
;
; --The destination address write (to address $C00004) must be a word
; write.
;
; --The final write must use the work RAM.
; There are two ways to accomplish this, by copying the DMA program
; into RAM or by doing a final "move.w ram address $C00004""
endm
; tells the VDP to fill a region of VRAM with a certain byte
dmaFillVRAM macro byte,addr,length
lea (VDP_control_port).l,a5
move.w #$8F01,(a5) ; VRAM pointer increment: $0001
move.l #(($9400|((((length)-1)&$FF00)>>8))<<16)|($9300|(((length)-1)&$FF)),(a5) ; DMA length ...
move.w #$9780,(a5) ; VRAM fill
move.l #$40000080|(((addr)&$3FFF)<<16)|(((addr)&$C000)>>14),(a5) ; Start at ...
move.w #(byte)<<8,(VDP_data_port).l ; Fill with byte
.loop: move.w (a5),d1
btst #1,d1
bne.s .loop ; busy loop until the VDP is finished filling...
move.w #$8F02,(a5) ; VRAM pointer increment: $0002
endm
; calculates initial loop counter value for a dbf loop
; that writes n bytes total at 4 bytes per iteration
bytesToLcnt function n,n>>2-1
; calculates initial loop counter value for a dbf loop
; that writes n bytes total at 2 bytes per iteration
bytesToWcnt function n,n>>1-1
; calculates initial loop counter value for a dbf loop
; that writes n bytes total at x bytes per iteration
bytesToXcnt function n,x,n/x-1
; fills a region of 68k RAM with 0
clearRAM macro addr,length
if ((addr)&$8000)==0
lea (addr).l,a1
else
lea (addr).w,a1
endif
moveq #0,d0
if ((addr)&1)
move.b d0,(a1)+
endif
move.w #bytesToLcnt(length - ((addr)&1)),d1
.loop: move.l d0,(a1)+
dbf d1,.loop
if ((length - ((addr)&1))&2)
move.w d0,(a1)+
endif
if ((length - ((addr)&1))&1)
move.b d0,(a1)+
endif
endm
; tells the Z80 to stop, and waits for it to finish stopping (acquire bus)
stopZ80 macro
move.w #$100,(Z80_bus_request).l ; stop the Z80
.loop: btst #0,(Z80_bus_request).l
bne.s .loop ; loop until it says it's stopped
endm
; tells the Z80 to start again
startZ80 macro
move.w #0,(Z80_bus_request).l ; start the Z80
endm
; function to make a little-endian 16-bit pointer for the Z80 sound driver
z80_ptr function x,(x)<<8&$FF00|(x)>>8&$7F|$80
; macro to declare a little-endian 16-bit pointer for the Z80 sound driver
rom_ptr_z80 macro addr
dc.w z80_ptr(addr)
endm
; macro for generating water palette transition tables
watertransheader macro {INTLABEL}
__LABEL__ label *
; Number of entries in list minus one
dc.w (((__LABEL___End - __LABEL__ - 2) / 2) - 1)
endm
; macro for generating level select strings
levselstr macro str
save
codepage LEVELSELECT
dc.b strlen(str)-1, str
restore
endm
; codepage for level select
save
codepage LEVELSELECT
charset '0','9', 16
charset 'A','Z', 30
charset 'a','z', 30
charset '*', 26
charset $A9, 27 ; '?'
charset ':', 28
charset '.', 29
charset ' ', 0
restore
; macro to declare an offset table
offsetTable macro {INTLABEL}
current_offset_table := __LABEL__
__LABEL__ label *
endm
; macro to declare an entry in an offset table
offsetTableEntry macro ptr
dc.ATTRIBUTE ptr-current_offset_table
endm
; macro to declare a zone-ordered table
; entryLen is the length of each table entry, and zoneEntries is the number of entries per zone
zoneOrderedTable macro entryLen,zoneEntries,{INTLABEL}
__LABEL__ label *
; set some global variables
zone_table_name := "__LABEL__"
zone_table_addr := *
zone_entry_len := entryLen
zone_entries := zoneEntries
zone_entries_left := 0
cur_zone_id := 0
cur_zone_str := "0"
endm
zoneOrderedOffsetTable macro entryLen,zoneEntries,{INTLABEL}
current_offset_table := __LABEL__
__LABEL__ zoneOrderedTable entryLen,zoneEntries
endm
; macro to declare one or more entries in a zone-ordered table
zoneTableEntry macro value
if "value"<>""
if zone_entries_left
dc.ATTRIBUTE value
zone_entries_left := zone_entries_left-1
else
!org zone_table_addr+zone_id_{cur_zone_str}*zone_entry_len*zone_entries
dc.ATTRIBUTE value
zone_entries_left := zone_entries-1
cur_zone_id := cur_zone_id+1
cur_zone_str := "\{cur_zone_id}"
endif
shift
zoneTableEntry.ATTRIBUTE ALLARGS
endif
endm
; macro to declare one or more BINCLUDE entries in a zone-ordered table
zoneTableBinEntry macro numEntries,path
if zone_entries_left
BINCLUDE path
zone_entries_left := zone_entries_left-numEntries
else
!org zone_table_addr+zone_id_{cur_zone_str}*zone_entry_len*zone_entries
BINCLUDE path
zone_entries_left := zone_entries-numEntries
cur_zone_id := cur_zone_id+1
cur_zone_str := "\{cur_zone_id}"
endif
endm
; macro to declare one entry in a zone-ordered offset table
zoneOffsetTableEntry macro value
zoneTableEntry.ATTRIBUTE value-current_offset_table
endm
; macro which sets the PC to the correct value at the end of a zone offset table and checks if the correct
; number of entries were declared
zoneTableEnd macro
if (cur_zone_id<>no_of_zones)&&(MOMPASS=1)
message "Warning: Table \{zone_table_name} has \{cur_zone_id/1.0} entries, but it should have \{(no_of_zones)/1.0} entries"
endif
!org zone_table_addr+cur_zone_id*zone_entry_len*zone_entries
endm
; macros for defining animated PLC script lists
zoneanimstart macro {INTLABEL}
__LABEL__ label *
zoneanimcount := 0
zoneanimcur := "__LABEL__"
dc.w zoneanimcount___LABEL__ ; Number of scripts for a zone (-1)
endm
zoneanimend macro
zoneanimcount_{"\{zoneanimcur}"} = zoneanimcount-1
endm
zoneanimdeclanonid := 0
zoneanimdecl macro duration,artaddr,vramaddr,numentries,numvramtiles
zoneanimdeclanonid := zoneanimdeclanonid + 1
start:
dc.l (duration&$FF)<<24|artaddr
dc.w tiles_to_bytes(vramaddr)
dc.b numentries, numvramtiles
zoneanimcount := zoneanimcount + 1
endm
; macros to convert from tile index to art tiles, block mapping or VRAM address.
make_art_tile function addr,pal,pri,((pri&1)<<15)|((pal&3)<<13)|(addr&tile_mask)
tiles_to_bytes function addr,((addr&$7FF)<<5)
; function to calculate the location of a tile in plane mappings with a width of 40 cells
planeLocH28 function col,line,(($50 * line) + (2 * col))
; macro for declaring a "main level load block" (MLLB)
levartptrs macro plc1,plc2,palette,art1,art2,map16x161,map16x162,map128x1281,map128x1282
dc.l (plc1<<24)|art1
dc.l (plc2<<24)|art2
dc.l (palette<<24)|map16x161
dc.l (palette<<24)|map16x162
dc.l map128x1281
dc.l map128x1282
endm
; macro for a pattern load request list header
; must be on the same line as a label that has a corresponding _End label later
plrlistheader macro {INTLABEL}
__LABEL__ label *
dc.w (((__LABEL___End - __LABEL__Plc) / 6) - 1)
__LABEL__Plc:
endm
; macro for a pattern load request
plreq macro toVRAMaddr,fromROMaddr
dc.l fromROMaddr
dc.w tiles_to_bytes(toVRAMaddr)
endm
; macro for a debug object list header
; must be on the same line as a label that has a corresponding _End label later
dbglistheader macro {INTLABEL}
__LABEL__ label *
dc.w ((__LABEL___End - __LABEL__ - 2) / $A)
endm
; macro to define debug list object data
dbglistobj macro obj, mapaddr, subtype, frame, vram
dc.l frame<<24|obj
dc.l subtype<<24|mapaddr
dc.w vram
endm
tribyte macro val
if "val"<>""
dc.b (val >> 16)&$FF,(val>>8)&$FF,val&$FF
shift
tribyte ALLARGS
endif
endm
; macro to define a palette script pointer
palscriptptr macro header, data
dc.w data-header, 0
dc.l header
._headpos := header
endm
; macro to define a palette script header
palscripthdr macro palette, entries, value
dc.w (palette)&$FFFF
dc.b entries-1, value
endm
; macro to define a palette script data
palscriptdata macro frames, data
.framec := frames-1
shift
dc.w ALLARGS
dc.w .framec
endm
; macro to define a palette script data from an external file
palscriptfile macro frames, data
.framec := frames-1
shift
binclude ALLARGS
dc.w .framec
endm
; macro to repeat script from start
palscriptrept macro header
dc.w -4
endm
; macro to define loop from start for x number of times, then initialize with new header
palscriptloop macro header
dc.w -8, header-._headpos
._headpos := header
endm
; macro to run the custom script routine
palscriptrun macro header
dc.w -$C
endm
; ---------------------------------------------------------------------------
; Set a VRAM address via the VDP control port.
; input: 16-bit VRAM address, control port (default is ($C00004).l)
; ---------------------------------------------------------------------------
locVRAM: macro loc,controlport
if ("controlport"=="")
move.l #($40000000+((loc&$3FFF)<<16)+((loc&$C000)>>14)),(VDP_control_port).l
else
move.l #($40000000+((loc&$3FFF)<<16)+((loc&$C000)>>14)),controlport
endif
endm
; ---------------------------------------------------------------------------
; disable interrupts
; ---------------------------------------------------------------------------
disable_ints: macro
move #$2700,sr
endm
; ---------------------------------------------------------------------------
; enable interrupts
; ---------------------------------------------------------------------------
enable_ints: macro
move #$2300,sr
endm
; ---------------------------------------------------------------------------
ResetDMAQueue macro
move.w #DMA_Queue,(DMA_Queue_Slot).w
endm