1 ###############################################################################
3 # Copyright (c) 2009,2011 GraÅžvydas Ignotas
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.
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.
29 # --register-prefix-optional --bitwise-or
34 .equ RELOCATE_TO_RAM, 0xff0100 /* addr or 0 to disable */
35 .equ COPY_TEST_CODE, 0 /* addr or 0 to disable, copy only */
44 ##################################################
46 # Register and bitmask definitions #
48 ##################################################
50 .equ GFXDATA, 0xc00000
51 .equ GFXCNTL, 0xc00004
54 .equ VDP0_E_DISPLAY, 0x02
55 .equ VDP0_PLTT_FULL, 0x04
57 .equ VDP1_SMS_MODE, 0x80
58 .equ VDP1_E_DISPLAY, 0x40
66 .equ VDP12_SCREEN_V224, 0x00
67 .equ VDP12_SCREEN_V448, 0x04
68 .equ VDP12_PROGRESSIVE, 0x00
69 .equ VDP12_INTERLACED, 0x02
70 .equ VDP12_SCREEN_H256, 0x00
71 .equ VDP12_SCREEN_H320, 0x81
73 .equ VDP16_MAP_V32, 0x00
74 .equ VDP16_MAP_V64, 0x10
75 .equ VDP16_MAP_V128, 0x30
76 .equ VDP16_MAP_H32, 0x00
77 .equ VDP16_MAP_H64, 0x01
78 .equ VDP16_MAP_H128, 0x03
81 .equ MMODE_VAL_INPUT, 1
82 .equ MMODE_EDIT_VAL, 2
84 .equ MMODE_START_MENU, 4
85 .equ MMODE_GOTO_PREDEF, 5
86 .equ MMODE_JMP_ADDR, 6
89 .equ predef_addr_cnt, ((predef_addrs_end-predef_addrs)/4)
91 ##################################################
95 ##################################################
98 # Write val to VDP register reg
99 .macro write_vdp_r_dst reg val dst
100 move.w #((\reg << 8) + 0x8000 + \val),\dst
103 # Write val to VDP register reg, vdp addr in a3
104 .macro write_vdp_reg reg val
105 write_vdp_r_dst \reg, \val, (a3)
108 # Set up address in VDP, control port in dst
109 .macro VRAM_ADDR adr dst
110 move.l #(0x40000000 | ((\adr & 0x3fff) << 16) | (\adr >> 14)),\dst
113 .macro VSRAM_ADDR adr dst
114 move.l #(0x40000010 | ((\adr & 0x3fff) << 16) | (\adr >> 14)),\dst
118 # make VDP word from address adr and store in d0
119 .macro XRAM_ADDR_var adr
129 .macro VRAM_ADDR_var adr
135 .macro CRAM_ADDR_var adr
141 # convert tile coords in d0, d1 to nametable addr to a0
150 # check if some d-pad button (and modifier) is pressed
151 .macro do_dpad bit op val
159 # convert a6 to normal addr
161 .macro mk_a6_addr reg
169 .macro change_mode mode_new mode_back
171 or.w #(\mode_back<<11)|(\mode_new<<8),d7
175 .macro menu_text str x y pal
179 move.l #0x8000|(\pal<<13),d2
183 #################################################
187 #################################################
190 dc.w 0x0000,0x0eee,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000
191 dc.w 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000
192 dc.w 0x0000,0x02e2,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000
193 dc.w 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000
194 dc.w 0x0000,0x0e44,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000
195 dc.w 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000
196 dc.w 0x0000,0x044e,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000
197 dc.w 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000
202 /* Y size link attr X */
203 dc.w 0; dc.b 0x05; dc.b 0; dc.w 0x6002; dc.w 0
207 dc.l 0x000000, 0x200000, 0x400000, 0xa00000, 0xa10000
208 dc.l 0xa11100, 0xa12000, 0xa13000, 0xa14000, 0xa15100
213 dc.l 0x000000, 0x7fffff
214 dc.l 0xe00000, 0xffffff
215 dc.l 0xa00000, 0xa100ff
216 dc.l 0xa11000, 0xa113ff
217 dc.l 0xa12000, 0xa120ff
218 dc.l 0xa13000, 0xa130ff
220 dc.l 0xa15100, 0xa1513f
222 dc.l 0xa15180, 0xa153ff
223 safe_addrs_end_32x_vdp:
235 .ascii "Go to address\0"
237 .ascii "Go to (predef)\0"
239 .ascii "Jump to address\0"
241 .ascii "PC Transfer\0"
243 .ascii "DTACK safety\0"
245 .ascii "Transfer Ready\0"
249 .ascii "DTACK err?\0"
251 .ascii "Exception \0"
253 ##################################################
257 ##################################################
260 # a6 = page_start[31:8]|cursor_offs[7:0]
261 # d7 = old_inputs[31:16]|edit_bytes[15:14]|g_mode_old[13:11]|g_mode[10:8]|irq_cnt[7:0]
262 # d6 = edit_word_save[31:15]|edit_done[7]|no_dtack_detect[4]|autorep_cnt[3:0]
264 # edit: edit_word[31:8]|edit_pos[4:2]|byte_cnt[1:0]
270 /* make sure io port 2 is doing inputs */
271 move.b #0,(0xa1000b).l
272 /* make sure irqs are masked */
274 /* take care of TMSS */
275 move.b (0xa10000).l,d0
278 move.l #0x53454741,(0xa14000).l
279 /* want cart, not OS rom if cart pops in */
280 move.w #1,(0xa14100).l
281 /* touch VDP after TMSS setup? */
286 /* want to do early PC transfer (with RAM/VRAM intact and such)?
287 * also give time PC to see start condition */
293 bne no_early_transfer
294 move.b #0x40,(0xa1000b).l /* port 2 ctrl */
295 move.b #0x00,(a0) /* port 2 data - start with TH low */
299 beq do_early_transfer
302 move.b #0,(0xa1000b).l
303 bra no_early_transfer /* timeout */
312 /* copy to expansion device if magic number is set */
318 move.l (sizeof_bin,pc),d0
328 /* we could be relocated by 32x or something else, adjust start addr */
334 /* copy, assume 8K size */
335 move.l #RELOCATE_TO_RAM,a2
336 move.l (sizeof_bin,pc),d0
352 lea (test_code,pc),a0
353 move.l #COPY_TEST_CODE,a1
354 move.w #(test_code_end - test_code)/2-1,d0
359 /* patch test code */
360 move.l #COPY_TEST_CODE,a1
361 add.w #(test_code_ret_op-test_code+2),a1
375 move.b #0x40,(0xa10009).l
376 move.b #0x40,(0xa10003).l
381 /* Clear h/v scroll */
383 VRAM_ADDR 0x8000,(GFXCNTL)
385 VSRAM_ADDR 0,(GFXCNTL)
388 /* Load color data */
391 moveq.l #(colors_end-colors)/2,d0
394 /* load font patterns */
397 VRAM_ADDR 0,(GFXCNTL)
409 rol.l #1,d1 /* fixup */
413 /* generate A layer map */
421 0: move.l #0x00000000,(a0)
427 /* generate B layer map */
432 0: move.l #0x00000000,(a0)
435 /* upload sprite data */
438 lea (sprite_data,pc),a1
440 move.l #(sprite_data_end-sprite_data)/2-1,d3
445 /* wait for vsync before unmask */
448 /* wait a bit to avoid nested vint */
451 dbra d0,0b /* 10 cycles to go back */
453 /* enable and unmask vint */
454 write_vdp_r_dst 1,(VDP1_E_VBI | VDP1_E_DISPLAY | VDP1_MODE5),(GFXCNTL)
458 ##################################################
471 /* let's hope VRAM is already set up.. */
479 ##################################################
483 # movem.l d0-d4/a0-a5,-(a7)
485 btst.b #5,(0xa10005).l
487 change_mode MMODE_PC, MMODE_MAIN
488 write_vdp_r_dst 12,(VDP12_SCREEN_V224 | VDP12_SCREEN_H320 | VDP12_STE),(GFXCNTL)
495 lea (jumptab,pc,d0),a0
498 /* branch insns here because we want to be position independent */
501 bra mode_edit_val /* edit val in editor */
508 ##################### main #######################
511 /* assume we will hang */
512 lea (txt_dtack_err,pc),a0
522 move.l d0,a1 /* current addr */
525 add.b #27-1,d1 /* line where the cursor sits */
529 move.l #27-1,d5 /* line counter for dbra */
552 # unsafe or partially safe
555 swap d4 /* mask in upper word */
557 bne draw_row_hsafe_words_pre
559 draw_row_hsafe_bytes_pre:
564 draw_row_hsafe_bytes:
570 move.l #'?'|('?'<<16),(a0)
572 move.l #'?'|('?'<<16),(a0)
582 dbra d4,draw_row_hsafe_bytes
589 beq draw_cursor_unsafe_byte
590 bra draw_chars_hsafe_pre
592 draw_row_hsafe_words_pre:
597 draw_row_hsafe_words:
603 move.l #'?'|('?'<<16),(a0)
604 move.l #'?'|('?'<<16),(a0)
611 dbra d4,draw_row_hsafe_words
613 move.l #(' '<<16)|' ',(a0)
618 beq draw_cursor_unsafe_word
620 draw_chars_hsafe_pre:
630 move.l #'?'|('?'<<16),(a0)
631 bra draw_chars_hsafe_next
633 btst.l #15,d7 /* must perform correct read type */
634 bne 0f /* doing byte reads on security reg hangs */
661 draw_chars_hsafe_next:
663 dbra d4,draw_chars_hsafe
665 move.l #(' '<<16)|' ',(a0)
704 move.l #(' '<<16)|' ',(a0)
726 move.l #(' '<<16)|' ',(a0)
748 move.l #' '|(' '<<16),(a0)
749 move.l #' '|(' '<<16),(a0)
754 jsr get_input /* x0cbrldu x1sa00du */
756 btst.l #16+4,d0 /* A - scroll modifier */
759 do_dpad 16+0, sub.l, #0x0800
760 do_dpad 16+1, add.l, #0x0800
761 do_dpad 16+10, sub.l, #0xd800
762 do_dpad 16+11, add.l, #0xd800
769 do_dpad 0, subq.l, #0x0008
770 do_dpad 1, addq.l, #0x0008
771 do_dpad 10, sub.l, d1
772 do_dpad 11, add.l, d1
791 btst.l #12,d0 /* B - switch byte/word mode */
794 add.w #0x4000,d7 /* changes between 01 10 */
797 sub.l d1,a6 /* make even, just in case */
800 btst.l #13,d0 /* C - edit selected byte */
803 change_mode MMODE_EDIT_VAL, MMODE_MAIN
804 write_vdp_r_dst 12,(VDP12_SCREEN_V224 | VDP12_SCREEN_H320 | VDP12_STE),(GFXCNTL)
807 btst.l #5,d0 /* Start - menu */
811 change_mode MMODE_START_MENU, MMODE_MAIN
812 write_vdp_r_dst 12,(VDP12_SCREEN_V224 | VDP12_SCREEN_H320 | VDP12_STE),(GFXCNTL)
816 # movem.l (a7)+,d0-d4/a0-a5
824 draw_cursor_unsafe_byte:
826 and.l #7,d0 /* byte offs */
829 add.b d1,d0 /* d0 *= 3 (chars) */
833 move.l #(0x2000|'?'|((0x2000|'?')<<16)),(a0)
837 jsr load_prepare /* restore a0 */
838 bra draw_chars_hsafe_pre
840 draw_cursor_unsafe_word:
842 and.l #7,d0 /* byte offs */
844 lsr.b #1,d1 /* which word */
847 add.b d2,d1 /* num of chars to skip */
852 move.l #(0x2000|'?'|((0x2000|'?')<<16)),d0
858 jsr load_prepare /* restore a0 */
859 bra draw_chars_hsafe_pre
864 and.l #7,d0 /* byte offs */
870 add.b d1,d0 /* d0 *= 3 (chars) */
878 jsr load_prepare /* restore a0 */
884 and.l #7,d0 /* byte offs */
886 lsr.b #1,d1 /* which word */
889 add.b d2,d1 /* num of chars to skip */
900 jsr load_prepare /* restore a0 */
905 #################### hedit #######################
909 bne mode_hedit_finish
911 /* read val to edit */
927 change_mode MMODE_VAL_INPUT, MMODE_EDIT_VAL
946 ##################### goto #######################
957 or.b #3,d5 /* 3 bytes */
959 change_mode MMODE_VAL_INPUT, MMODE_GOTO
979 ################### val edit #####################
983 movea.l #0xe000+14*2+11*64*2,a1
1003 lea (txt_a_confirm,pc),a0
1014 and.b #3,d3 /* edit field bytes */
1032 lsr.b #1,d1 /* length in bytes */
1036 and.b #7,d1 /* nibble to edit */
1040 sub.b #1,d3 /* chars to shift out */
1051 jsr get_input /* x0cbrldu x1sa00du */
1058 add.b d1,d1 /* nibble count */
1059 sub.b #1,d1 /* max n.t.e. val */
1062 and.b #7,d2 /* nibble to edit */
1074 lsl.l d1,d3 /* mask */
1075 lsl.l d1,d4 /* what to add/sub */
1086 eor.l #0xffffffff,d3
1120 btst.l #4,d0 /* A - confirm */
1123 move.w d7,d1 /* back to prev mode */
1133 ################### start menu ###################
1140 menu_text txt_about, 13, 9, 1
1141 menu_text txt_goto, 13, 11, 0
1142 menu_text txt_goto_predef, 13, 12, 0
1143 menu_text txt_jmp_addr, 13, 13, 0
1144 menu_text txt_dump, 13, 14, 0
1145 menu_text txt_dtack, 13, 15, 0
1146 menu_text txt_a_confirm, 13, 17, 2
1148 /* dtack safety on/off */
1149 movea.l #0xe000+26*2+15*64*2,a0
1151 move.w #0x8000|'O',(a0)
1154 move.w #0x8000|'N',(a0)
1157 move.w #0x8000|'F',(a0)
1158 move.w #0x8000|'F',(a0)
1162 movea.l #0xe000+11*2+11*64*2,a0
1172 jsr get_input /* x0cbrldu x1sa00du */
1181 or.b #1,d2 /* up -1, down 1 */
1196 btst.l #4,d0 /* A - confirm */
1201 change_mode MMODE_GOTO, MMODE_MAIN
1208 change_mode MMODE_GOTO_PREDEF, MMODE_MAIN
1214 change_mode MMODE_JMP_ADDR, MMODE_MAIN
1220 change_mode MMODE_PC, MMODE_MAIN
1240 movea.l #0xe000+10*2+8*64*2,a1
1254 ################### goto predef ##################
1258 movea.l #0xe000+14*2+8*64*2,a1
1259 move.l #predef_addr_cnt+2-1,d1
1271 /* draw addresses */
1272 movea.l #0xe000+17*2+9*64*2,a1
1273 lea (predef_addrs,pc),a2
1274 move.w #predef_addr_cnt-1,d4
1280 jsr print_hex_preped
1285 movea.l #0xe000+15*2+9*64*2,a0
1294 jsr get_input /* x0cbrldu x1sa00du */
1301 or.b #1,d2 /* up -1, down 1 */
1305 move.b #predef_addr_cnt-1,d5
1307 cmp.b #predef_addr_cnt-1,d5
1314 btst.l #4,d0 /* A - confirm */
1319 lea (predef_addrs,pc),a0
1322 bra mode_goto_finish
1333 ##################### jmp ########################
1340 or.b #3,d5 /* 3 bytes */
1342 change_mode MMODE_VAL_INPUT, MMODE_JMP_ADDR
1347 write_vdp_r_dst 1,(VDP1_E_DISPLAY | VDP1_MODE5),(GFXCNTL) /* disable vint */
1353 move.b #0x40,(0xa1000b).l /* port 2 ctrl */
1354 move.b #0x00,(0xa10005).l /* port 2 data - start with TH low */
1356 lea (txt_transfer_ready,pc),a0
1363 move.b (0xa10005),d0
1367 menu_text txt_working, 13, 13, 0
1372 # go back to main mode
1374 bclr.l #7,d6 /* not edited */
1375 change_mode MMODE_MAIN, MMODE_MAIN
1376 write_vdp_r_dst 12,(VDP12_SCREEN_V224 | VDP12_SCREEN_H320),(GFXCNTL)
1380 #################################################
1382 # Initialize VDP registers #
1384 #################################################
1388 write_vdp_reg 0,(VDP0_E_DISPLAY | VDP0_PLTT_FULL)
1389 write_vdp_reg 1,(VDP1_E_DISPLAY | VDP1_MODE5)
1390 write_vdp_reg 2,(0xe000 >> 10) /* Screen map a adress */
1391 write_vdp_reg 3,(0xe000 >> 10) /* Window address */
1392 write_vdp_reg 4,(0xc000 >> 13) /* Screen map b address */
1393 write_vdp_reg 5,(0xfc00 >> 9) /* Sprite address */
1395 write_vdp_reg 7,0 /* Backdrop color */
1396 write_vdp_reg 0x0a,1 /* Lines per hblank interrupt */
1397 write_vdp_reg 0x0b,0 /* 2-cell vertical scrolling */
1398 write_vdp_reg 0x0c,(VDP12_SCREEN_V224 | VDP12_SCREEN_H320)
1399 write_vdp_reg 0x0d,(0x8000 >> 10) /* Horizontal scroll address */
1400 write_vdp_reg 0x0e,0
1401 write_vdp_reg 0x0f,2
1402 write_vdp_reg 0x10,(VDP16_MAP_V32 | VDP16_MAP_H64) /* layer size */
1403 write_vdp_reg 0x11,0
1404 write_vdp_reg 0x12,0
1408 # get mask of bits representing safe words
1409 # a1 - address to check
1410 # destroys d0-d2, strips upper bits from a1
1415 lea (safe_addrs,pc),a1
1416 move.w #(safe_addrs_end - safe_addrs)/8-1,d2
1417 cmp.l #0x4D415253,(0xa130ec) /* 'MARS' */
1419 move.w #(safe_addrs_end_32x - safe_addrs)/8-1,d2
1420 move.w (0xa15100),d0
1422 cmp.w #3,d0 /* ADEN and nRES */
1424 btst.b #7,d0 /* FM */
1426 move.w #(safe_addrs_end_32x_vdp - safe_addrs)/8-1,d2
1451 /* check for VDP address */
1456 bne addr_unsafe /* not vdp */
1465 blt addr_hsafe_3 /* data port */
1467 blt addr_safe /* below PSG */
1469 bge addr_safe /* above PSG */
1472 moveq.l #0,d0 /* skip line */
1476 moveq.l #3,d0 /* skip 2 words */
1486 # read single phase from controller
1491 move.b #0x40,(0xa10003)
1495 move.b (0xa10003),d0
1496 move.b #0x00,(0xa10003)
1499 move.b (0xa10003),d0
1504 eor.w d0,d1 /* changed btns */
1505 move.w d0,d7 /* old val */
1507 and.w d0,d1 /* what changed now */
1512 and.b #0x0f,d2 /* do autorepeat */
1523 # Prepare to write to VDP RAM @a0
1524 # sets a0 to VDP data port for convenience
1530 move.l d0,(GFXCNTL).l
1535 # Load color data from ROM
1537 # a1: color list address
1538 # d0: number of colors to load
1544 move.l d0,(GFXCNTL).l
1559 # d2 - tile_bits[15:11]
1584 # d3 - tile_bits[15:11]|digit_cnt[7:0]
1585 # destroys a0, preserves d3
1596 ror.l d0,d2 /* prep value */
1597 subq.l #1,d1 /* count */
1599 and.w #0xf800,d0 /* keep upper bits in d0 */
1612 dbra d1,_print_hex_loop
1617 # wait vertical sync interrupt
1628 # wait vsync start (polling)
1653 jmp 0x123456 /* will be patched */
1657 #################################################
1661 #################################################
1669 # vim:filetype=asmM68k