forked from sonicretro/skdisasm
-
Notifications
You must be signed in to change notification settings - Fork 5
/
sonic3k.macros.asm
252 lines (217 loc) · 7.02 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
; 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 = %100001
CRAM = %101011
VSRAM = %100101
; values for the rwd argument
READ = %001100
WRITE = %000111
DMA = %100111
; 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
; 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 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
; 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
; 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 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