hexed: support PicoDrive savestate loading (only VDP+VRAM for now)
[megadrive.git] / hexed / transfer.S
1 ###############################################################################
2 #
3 # Copyright (c) 2011, GraÅžvydas Ignotas
4 # All rights reserved.
5 #
6 # Redistribution and use in source and binary forms, with or without
7 # modification, are permitted provided that the following conditions are met:
8 #     * Redistributions of source code must retain the above copyright
9 #       notice, this list of conditions and the following disclaimer.
10 #     * Redistributions in binary form must reproduce the above copyright
11 #       notice, this list of conditions and the following disclaimer in the
12 #       documentation and/or other materials provided with the distribution.
13 #     * Neither the name of the organization nor the
14 #       names of its contributors may be used to endorse or promote products
15 #       derived from this software without specific prior written permission.
16 #
17 # THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND ANY
18 # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 # DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY
21 # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 #
28 # Assemble with gas
29 #   --register-prefix-optional --bitwise-or
30 #
31
32 #include "transfer.h"
33
34 .text
35 .globl do_transfer
36
37
38 # receive 1 byte to d0
39 #  in: a1 - data port
40 #  trash: d1
41 .macro recv_one_byte is_last=0
42         move.b          #0,(a1)         /* clear TH */
43
44 0: /*L_wait_tl_low*/
45         move.b          (a1),d1
46         btst.b          #4,d1
47         bne             0b /*L_wait_tl_low*/
48
49         move.b          #0x40,(a1)      /* set TH */
50         and.b           #0x0f,d1
51
52 0: /*L_wait_tl_hi*/
53         move.b          (a1),d0
54         btst.b          #4,d0
55         beq             0b /*L_wait_tl_hi*/
56
57 .if !\is_last
58         move.b          #0,(a1)         /* clear TH - ready for next */
59 .endif
60         lsl.b           #4,d0
61         or.b            d1,d0
62 .endm
63
64 # send 1 byte in d0
65 #  in: a1 - data port
66 #  trash: d1,d2
67 .macro send_one_byte
68         move.b          d0,d2
69         and.b           #0x0f,d2
70
71 0: /*Lwait_tl_low:*/
72         move.b          (a1),d1
73         btst.b          #4,d1
74         bne             0b /*Lwait_tl_low*/
75
76         move.b          d2,(a1)         /* clears TH and writes data */
77
78         move.b          d0,d2
79         lsr.b           #4,d2
80         bset.b          #6,d2           /* prepare TH */
81
82 0: /*wait_tl_hi*/
83         move.b          (a1),d1
84         btst.b          #4,d1
85         beq             0b /*wait_tl_hi1*/
86
87         move.b          d2,(a1)
88 .endm
89
90 recv_byte:
91         moveq.l         #0,d0
92         recv_one_byte 1
93         rts
94
95 # receive 1 16bit word to d0
96 #  in: a1 - data port
97 #  trash: d1,d2
98 recv_word:
99         recv_one_byte
100         move.b          d0,d2
101         recv_one_byte
102         lsl.w           #8,d2
103         move.b          d0,d2
104         move.w          d2,d0
105         rts
106
107 # receive address/size to d0 (3 bytes BE)
108 #  in: a1 - data port
109 #  trash: d1,d2
110 recv_ad:
111         moveq.l         #0,d2
112         bsr             recv_byte
113         move.b          d0,d2
114         bsr             recv_byte
115         lsl.l           #8,d2
116         move.b          d0,d2
117         bsr             recv_byte
118         lsl.l           #8,d2
119         move.b          d0,d2
120         move.l          d2,d0
121         rts
122
123 send_byte:
124         send_one_byte
125         rts
126
127 .equ sat_maxsize, (80*8+0x200) /* sprites+max_align */
128
129 # make sure cache is invalidated
130 # note: VRAM copy doesn't seem to help here
131 # note2: cache is updated as data is written
132 #  in: d0 - vdp reg5, a0 = 0xc00000
133 #  trash: d1,d2,a2
134 invalidate_sprite_cache:
135         move.w          #0x8f02,4(a0)           /* auto increment 2 */
136         lsl.b           #1,d0                   /* upper byte of sat address */
137         move.b          d0,d1
138         lsr.b           #6,d1                   /* 15:14 dst addr */
139         and.b           #0x3f,d0                /* assemble cmd */
140         lsl.w           #8,d0
141         swap            d0
142         move.b          d1,d0
143         move.l          d0,4(a0)
144
145         move.l          #0xffe000,a2
146         move.l          #sat_maxsize/2-1,d2
147 0:
148         move.w          (a0),(a2)+
149         dbra            d2,0b
150
151         bset            #30,d0                  /* VRAM write */
152         move.l          d0,4(a0)
153
154         move.l          #0xffe000,a2
155         move.l          #sat_maxsize/2-1,d2
156 0:
157         move.w          (a2)+,(a0)
158         dbra            d2,0b
159         rts
160
161
162
163 do_transfer:
164         lea             0xa10005,a1
165         move.b          #0x40,(0xa1000b).l      /* ctrl - all inputs except TH */
166         move.b          #0x00,(a1)
167
168         bsr             recv_byte
169         cmp.b           #CMD_PREFIX,d0
170         bne             return
171
172         bsr             recv_byte
173         cmp.b           #CMD_FIRST,d0
174         bcs             return
175         cmp.b           #CMD_LAST+1,d0
176         bcc             return
177         sub.b           #CMD_FIRST,d0
178
179         lsl.w           #2,d0
180         lea             (jumptab,pc,d0),a0
181         jmp             (a0)
182 jumptab:
183         bra             pcc_transfer_recv       /* sent to us */
184         bra             pcc_transfer_send       /* recv from us */
185         bra             pcc_jump
186         bra             pcc_io
187         bra             pcc_loadstate
188         bra             pcc_test_code
189
190
191 /* receive data from PC */
192 pcc_transfer_recv:
193         bsr             recv_ad
194         move.l          d0,a0
195         bsr             recv_ad
196         move.l          d0,d3
197
198 tr_recv_loop:
199         recv_one_byte
200         move.b          d0,(a0)+
201         subq.l          #1,d3
202         bgt             tr_recv_loop
203         bra             return
204
205
206 /* send data to PC */
207 pcc_transfer_send:
208         bsr             recv_ad
209         move.l          d0,a0
210         bsr             recv_ad
211         move.l          d0,d3
212
213 0: /*Lwait_tl_low: it should switch to rx mode before lowering tl */
214         move.b          (a1),d0
215         btst.b          #4,d0
216         bne             0b /*Lwait_tl_low*/
217
218         move.b          #0x4f,(0xa1000b).l
219         move.b          #0x40,(a1)
220
221 tr_send_loop:
222         move.b          (a0)+,d0
223         send_one_byte
224         subq.l          #1,d3
225         bgt             tr_send_loop
226         bra             return
227
228
229 /* call specified location */
230 pcc_jump:
231         bsr             recv_ad
232         move.l          d0,a0
233         jsr             (a0)
234         bra             return
235
236
237 /* do simple i/o commands */
238 pcc_io:
239         moveq.l         #0,d4
240         bsr             recv_byte
241         move.b          d0,d4
242         bsr             recv_byte
243         lsl.l           #8,d4
244         move.b          d0,d4
245
246 pcc_io_loop:
247         move.b          #0x40,(0xa1000b).l      /* input mode */
248
249         sub.w           #1,d4
250         bmi             return
251
252         bsr             recv_byte
253         move.b          d0,d3                   /* cmd */
254
255         bsr             recv_ad
256         move.l          d0,a2                   /* addr */
257
258         cmp.b           #IOSEQ_W32, d3
259         beq             pcc_io_w32
260         cmp.b           #IOSEQ_W16, d3
261         beq             pcc_io_w16
262         cmp.b           #IOSEQ_W8, d3
263         bne             pcc_io_rx
264
265 pcc_io_w8:
266         bsr             recv_byte
267         move.b          d0,(a2)
268         bra             pcc_io_loop
269
270 pcc_io_w16:
271         bsr             recv_byte
272         move.b          d0,d3
273         bsr             recv_byte
274         lsl.w           #8,d3
275         move.b          d0,d3
276         move.w          d3,(a2)
277         bra             pcc_io_loop
278
279 pcc_io_w32:
280         bsr             recv_byte
281         move.b          d0,d3
282         bsr             recv_byte
283         lsl.w           #8,d3
284         move.b          d0,d3
285         bsr             recv_byte
286         lsl.l           #8,d3
287         move.b          d0,d3
288         bsr             recv_byte
289         lsl.l           #8,d3
290         move.b          d0,d3
291         move.l          d3,(a2)
292         bra             pcc_io_loop
293
294 pcc_io_rx:
295 0: /*Lwait_tl_low:*/
296         move.b          (a1),d0
297         btst.b          #4,d0
298         bne             0b /*Lwait_tl_low*/
299
300         move.b          #0x4f,(0xa1000b).l
301         move.b          #0x40,(a1)
302
303         cmp.b           #IOSEQ_R32, d3
304         beq             pcc_io_r32
305         cmp.b           #IOSEQ_R16, d3
306         beq             pcc_io_r16
307         cmp.b           #IOSEQ_R8, d3
308         bne             return
309
310 pcc_io_r8:
311         move.b          (a2),d0
312         bsr             send_byte
313         bra             pcc_io_loop
314
315 pcc_io_r16:
316         move.w          (a2),d3
317         move.w          d3,d0
318         lsr.w           #8,d0
319         bsr             send_byte
320         move.b          d3,d0
321         bsr             send_byte
322         bra             pcc_io_loop
323
324 pcc_io_r32:
325         move.l          (a2),d3
326         move.l          d3,d0
327         swap            d0
328         lsr.l           #8,d0
329         bsr             send_byte
330         move.l          d3,d0
331         swap            d0
332         bsr             send_byte
333         move.w          d3,d0
334         lsr.w           #8,d0
335         bsr             send_byte
336         move.b          d3,d0
337         bsr             send_byte
338         bra             pcc_io_loop
339
340
341 /* PicoDrive savestate load */
342 pcc_loadstate:
343         /* write VRAM */
344         move.l          #0xc00000,a0
345         move.w          #0x8f02,4(a0)           /* auto increment 2 */
346
347         move.l          #0x40000000,4(a0)
348         move.l          #0x10000/2-1,d3
349 tr_do_vram_loop:
350         bsr             recv_word
351         move.w          d0,(a0)
352         dbra            d3, tr_do_vram_loop
353
354         /* write cram */
355         move.l          #0xc0000000,4(a0)
356         move.l          #0x80/2-1,d3
357 tr_do_cram_loop:
358         bsr             recv_word
359         move.w          d0,(a0)
360         dbra            d3, tr_do_cram_loop
361
362         /* write vsram */
363         move.l          #0x40000010,4(a0)
364         move.l          #0x80/2-1,d3
365 tr_do_vsram_loop:
366         bsr             recv_word
367         move.w          d0,(a0)
368         dbra            d3, tr_do_vsram_loop
369
370         /* recv and write regs */
371         lea             0xffe000,a3
372         move.l          a3,a2
373         moveq.l         #0x20-1,d3
374 tr_do_vdpreg_recv_loop:
375         bsr             recv_byte
376         move.b          d0,(a2)+
377         dbra            d3, tr_do_vdpreg_recv_loop
378
379         move.l          a3,a2
380         moveq.l         #0,d3
381 tr_do_vdpreg_loop:
382         move.b          d3,d1
383         or.b            #0x80,d1
384         lsl.w           #8,d1
385         move.b          (d3,a2),d1
386         move.w          d1,4(a0)
387         addq.l          #1,d3
388         cmp.b           #0x17,d3        /* FIXME: r23 might cause DMA or.. */
389         bne             0f              /* ..something and hang VDP.. */
390         add.b           #1,d3           /* ..so we skip it */
391 0:
392         cmp.b           #0x20,d3
393         blt             tr_do_vdpreg_loop
394
395         moveq.l         #0,d0
396         move.b          5(a3),d0
397         bsr             invalidate_sprite_cache
398
399
400 0:      bra             0b
401
402         bra             return
403
404
405
406
407 /* some random code */
408 pcc_test_code:
409         bra             return
410
411
412
413 return:
414         move.b          #0,(0xa1000b).l /* all inputs */
415         move.l          #0xffe000,a1
416         move.l          d0,(a1)+        /* last state for debug */
417         move.l          d1,(a1)+
418         move.l          d2,(a1)+
419         move.l          d3,(a1)+
420         move.l          a0,(a1)+
421         bra             return_to_main
422
423
424 # vim:filetype=asmM68k