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, 1
42 ##################################################
44 # Register and bitmask definitions #
46 ##################################################
48 .equ GFXDATA, 0xc00000
49 .equ GFXCNTL, 0xc00004
52 .equ VDP0_E_DISPLAY, 0x02
53 .equ VDP0_PLTT_FULL, 0x04
55 .equ VDP1_SMS_MODE, 0x80
56 .equ VDP1_E_DISPLAY, 0x40
64 .equ VDP12_SCREEN_V224, 0x00
65 .equ VDP12_SCREEN_V448, 0x04
66 .equ VDP12_PROGRESSIVE, 0x00
67 .equ VDP12_INTERLACED, 0x02
68 .equ VDP12_SCREEN_H256, 0x00
69 .equ VDP12_SCREEN_H320, 0x81
71 .equ VDP16_MAP_V32, 0x00
72 .equ VDP16_MAP_V64, 0x10
73 .equ VDP16_MAP_V128, 0x30
74 .equ VDP16_MAP_H32, 0x00
75 .equ VDP16_MAP_H64, 0x01
76 .equ VDP16_MAP_H128, 0x03
79 .equ MMODE_VAL_INPUT, 1
80 .equ MMODE_EDIT_VAL, 2
82 .equ MMODE_START_MENU, 4
83 .equ MMODE_GOTO_PREDEF, 5
84 .equ MMODE_JMP_ADDR, 6
87 .equ predef_addr_cnt, ((predef_addrs_end-predef_addrs)/4)
89 ##################################################
93 ##################################################
96 # Write val to VDP register reg
97 .macro write_vdp_r_dst reg val dst
98 move.w #((\reg << 8) + 0x8000 + \val),\dst
101 # Write val to VDP register reg, vdp addr in a3
102 .macro write_vdp_reg reg val
103 write_vdp_r_dst \reg, \val, (a3)
106 # Set up address in VDP, control port in dst
107 .macro VRAM_ADDR adr dst
108 move.l #(0x40000000 | ((\adr & 0x3fff) << 16) | (\adr >> 14)),\dst
111 .macro VSRAM_ADDR adr dst
112 move.l #(0x40000010 | ((\adr & 0x3fff) << 16) | (\adr >> 14)),\dst
116 # make VDP word from address adr and store in d0
117 .macro XRAM_ADDR_var adr
127 .macro VRAM_ADDR_var adr
133 .macro CRAM_ADDR_var adr
139 # convert tile coords in d0, d1 to nametable addr to a0
148 # check if some d-pad button (and modifier) is pressed
149 .macro do_dpad bit op val
157 # convert a6 to normal addr
159 .macro mk_a6_addr reg
167 .macro change_mode mode_new mode_back
169 or.w #(\mode_back<<11)|(\mode_new<<8),d7
173 .macro menu_text str x y pal
177 move.l #0x8000|(\pal<<13),d2
181 #################################################
185 #################################################
188 dc.w 0x0000,0x0eee,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000
189 dc.w 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000
190 dc.w 0x0000,0x02e2,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000
191 dc.w 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000
192 dc.w 0x0000,0x0e44,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000
193 dc.w 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000
194 dc.w 0x0000,0x044e,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000
195 dc.w 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000
200 /* Y size link attr X */
201 dc.w 0; dc.b 0x05; dc.b 0; dc.w 0x6002; dc.w 0
205 dc.l 0x000000, 0x200000, 0x400000, 0xa00000, 0xa10000
206 dc.l 0xa11100, 0xa12000, 0xa13000, 0xa14000, 0xa15100
211 dc.l 0x000000, 0x7fffff
212 dc.l 0xe00000, 0xffffff
213 dc.l 0xa00000, 0xa100ff
214 dc.l 0xa11000, 0xa113ff
215 dc.l 0xa12000, 0xa120ff
216 dc.l 0xa13000, 0xa130ff
218 dc.l 0xa15100, 0xa1513f
220 dc.l 0xa15180, 0xa153ff
221 safe_addrs_end_32x_vdp:
233 .ascii "Go to address\0"
235 .ascii "Go to (predef)\0"
237 .ascii "Jump to address\0"
239 .ascii "PC Transfer\0"
241 .ascii "DTACK safety\0"
243 .ascii "Transfer Ready\0"
247 .ascii "DTACK err?\0"
249 .ascii "Exception \0"
251 ##################################################
255 ##################################################
258 # a6 = page_start[31:8]|cursor_offs[7:0]
259 # d7 = old_inputs[31:16]|edit_bytes[15:14]|g_mode_old[13:11]|g_mode[10:8]|irq_cnt[7:0]
260 # d6 = edit_word_save[31:15]|edit_done[7]|no_dtack_detect[4]|autorep_cnt[3:0]
262 # edit: edit_word[31:8]|edit_pos[4:2]|byte_cnt[1:0]
268 /* make sure io port 2 is doing inputs */
269 move.b #0,(0xa1000b).l
270 /* make sure irqs are masked */
272 /* take care of TMSS */
273 move.b (0xa10000).l,d0
276 move.l #0x53454741,(0xa14000).l
277 /* want cart, not OS rom if cart pops in */
278 move.w #1,(0xa14100).l
279 /* touch VDP after TMSS setup? */
283 /* want to do early PC transfer (with RAM/VRAM intact and such)?
284 * also give time PC to see start condition */
290 bne no_early_transfer
292 move.b #0x40,(0xa1000b).l /* port 2 ctrl */
293 move.b #0x00,(a0) /* port 2 data - start with TH low */
297 beq do_early_transfer
301 move.b #0,(0xa1000b).l
302 bra no_early_transfer /* timeout */
311 /* copy to expansion device if magic number is set */
317 move.l (sizeof_bin,pc),d0
327 /* we could be relocated by 32x or something else, adjust start addr */
333 /* copy, assume 8K size */
335 move.l (sizeof_bin,pc),d0
343 lea (test_code,pc),a0
345 move.w #(test_code_end - test_code)/2-1,d0
356 /* patch test code */
358 add.w #(test_code_ret_op-test_code+2),a1
370 move.b #0x40,(0xa10009).l
371 move.b #0x40,(0xa10003).l
376 /* Clear h/v scroll */
378 VRAM_ADDR 0x8000,(GFXCNTL)
380 VSRAM_ADDR 0,(GFXCNTL)
383 /* Load color data */
386 moveq.l #(colors_end-colors)/2,d0
389 /* load font patterns */
392 VRAM_ADDR 0,(GFXCNTL)
404 rol.l #1,d1 /* fixup */
408 /* generate A layer map */
416 0: move.l #0x00000000,(a0)
422 /* generate B layer map */
427 0: move.l #0x00000000,(a0)
430 /* upload sprite data */
433 lea (sprite_data,pc),a1
435 move.l #(sprite_data_end-sprite_data)/2-1,d3
440 /* wait for vsync before unmask */
443 /* wait a bit to avoid nested vint */
446 dbra d0,0b /* 10 cycles to go back */
448 /* enable and unmask vint */
449 write_vdp_r_dst 1,(VDP1_E_VBI | VDP1_E_DISPLAY | VDP1_MODE5),(GFXCNTL)
453 ##################################################
466 /* let's hope VRAM is already set up.. */
474 ##################################################
478 # movem.l d0-d4/a0-a5,-(a7)
480 btst.b #5,(0xa10005).l
482 change_mode MMODE_PC, MMODE_MAIN
483 write_vdp_r_dst 12,(VDP12_SCREEN_V224 | VDP12_SCREEN_H320 | VDP12_STE),(GFXCNTL)
490 lea (jumptab,pc,d0),a0
493 /* branch insns here because we want to be position independent */
496 bra mode_edit_val /* edit val in editor */
503 ##################### main #######################
506 /* assume we will hang */
507 lea (txt_dtack_err,pc),a0
517 move.l d0,a1 /* current addr */
520 add.b #27-1,d1 /* line where the cursor sits */
524 move.l #27-1,d5 /* line counter for dbra */
547 # unsafe or partially safe
550 swap d4 /* mask in upper word */
552 bne draw_row_hsafe_words_pre
554 draw_row_hsafe_bytes_pre:
559 draw_row_hsafe_bytes:
565 move.l #'?'|('?'<<16),(a0)
567 move.l #'?'|('?'<<16),(a0)
577 dbra d4,draw_row_hsafe_bytes
584 beq draw_cursor_unsafe_byte
585 bra draw_chars_hsafe_pre
587 draw_row_hsafe_words_pre:
592 draw_row_hsafe_words:
598 move.l #'?'|('?'<<16),(a0)
599 move.l #'?'|('?'<<16),(a0)
606 dbra d4,draw_row_hsafe_words
608 move.l #(' '<<16)|' ',(a0)
613 beq draw_cursor_unsafe_word
615 draw_chars_hsafe_pre:
625 move.l #'?'|('?'<<16),(a0)
626 bra draw_chars_hsafe_next
628 btst.l #15,d7 /* must perform correct read type */
629 bne 0f /* doing byte reads on security reg hangs */
656 draw_chars_hsafe_next:
658 dbra d4,draw_chars_hsafe
660 move.l #(' '<<16)|' ',(a0)
699 move.l #(' '<<16)|' ',(a0)
721 move.l #(' '<<16)|' ',(a0)
743 move.l #' '|(' '<<16),(a0)
744 move.l #' '|(' '<<16),(a0)
749 jsr get_input /* x0cbrldu x1sa00du */
751 btst.l #16+4,d0 /* A - scroll modifier */
754 do_dpad 16+0, sub.l, #0x0800
755 do_dpad 16+1, add.l, #0x0800
756 do_dpad 16+10, sub.l, #0xd800
757 do_dpad 16+11, add.l, #0xd800
764 do_dpad 0, subq.l, #0x0008
765 do_dpad 1, addq.l, #0x0008
766 do_dpad 10, sub.l, d1
767 do_dpad 11, add.l, d1
786 btst.l #12,d0 /* B - switch byte/word mode */
789 add.w #0x4000,d7 /* changes between 01 10 */
792 sub.l d1,a6 /* make even, just in case */
795 btst.l #13,d0 /* C - edit selected byte */
798 change_mode MMODE_EDIT_VAL, MMODE_MAIN
799 write_vdp_r_dst 12,(VDP12_SCREEN_V224 | VDP12_SCREEN_H320 | VDP12_STE),(GFXCNTL)
802 btst.l #5,d0 /* Start - menu */
806 change_mode MMODE_START_MENU, MMODE_MAIN
807 write_vdp_r_dst 12,(VDP12_SCREEN_V224 | VDP12_SCREEN_H320 | VDP12_STE),(GFXCNTL)
811 # movem.l (a7)+,d0-d4/a0-a5
819 draw_cursor_unsafe_byte:
821 and.l #7,d0 /* byte offs */
824 add.b d1,d0 /* d0 *= 3 (chars) */
828 move.l #(0x2000|'?'|((0x2000|'?')<<16)),(a0)
832 jsr load_prepare /* restore a0 */
833 bra draw_chars_hsafe_pre
835 draw_cursor_unsafe_word:
837 and.l #7,d0 /* byte offs */
839 lsr.b #1,d1 /* which word */
842 add.b d2,d1 /* num of chars to skip */
847 move.l #(0x2000|'?'|((0x2000|'?')<<16)),d0
853 jsr load_prepare /* restore a0 */
854 bra draw_chars_hsafe_pre
859 and.l #7,d0 /* byte offs */
865 add.b d1,d0 /* d0 *= 3 (chars) */
873 jsr load_prepare /* restore a0 */
879 and.l #7,d0 /* byte offs */
881 lsr.b #1,d1 /* which word */
884 add.b d2,d1 /* num of chars to skip */
895 jsr load_prepare /* restore a0 */
900 #################### hedit #######################
904 bne mode_hedit_finish
906 /* read val to edit */
922 change_mode MMODE_VAL_INPUT, MMODE_EDIT_VAL
941 ##################### goto #######################
952 or.b #3,d5 /* 3 bytes */
954 change_mode MMODE_VAL_INPUT, MMODE_GOTO
974 ################### val edit #####################
978 movea.l #0xe000+14*2+11*64*2,a1
998 lea (txt_a_confirm,pc),a0
1009 and.b #3,d3 /* edit field bytes */
1027 lsr.b #1,d1 /* length in bytes */
1031 and.b #7,d1 /* nibble to edit */
1035 sub.b #1,d3 /* chars to shift out */
1046 jsr get_input /* x0cbrldu x1sa00du */
1053 add.b d1,d1 /* nibble count */
1054 sub.b #1,d1 /* max n.t.e. val */
1057 and.b #7,d2 /* nibble to edit */
1069 lsl.l d1,d3 /* mask */
1070 lsl.l d1,d4 /* what to add/sub */
1081 eor.l #0xffffffff,d3
1115 btst.l #4,d0 /* A - confirm */
1118 move.w d7,d1 /* back to prev mode */
1128 ################### start menu ###################
1135 menu_text txt_about, 13, 9, 1
1136 menu_text txt_goto, 13, 11, 0
1137 menu_text txt_goto_predef, 13, 12, 0
1138 menu_text txt_jmp_addr, 13, 13, 0
1139 menu_text txt_dump, 13, 14, 0
1140 menu_text txt_dtack, 13, 15, 0
1141 menu_text txt_a_confirm, 13, 17, 2
1143 /* dtack safety on/off */
1144 movea.l #0xe000+26*2+15*64*2,a0
1146 move.w #0x8000|'O',(a0)
1149 move.w #0x8000|'N',(a0)
1152 move.w #0x8000|'F',(a0)
1153 move.w #0x8000|'F',(a0)
1157 movea.l #0xe000+11*2+11*64*2,a0
1167 jsr get_input /* x0cbrldu x1sa00du */
1176 or.b #1,d2 /* up -1, down 1 */
1191 btst.l #4,d0 /* A - confirm */
1196 change_mode MMODE_GOTO, MMODE_MAIN
1203 change_mode MMODE_GOTO_PREDEF, MMODE_MAIN
1209 change_mode MMODE_JMP_ADDR, MMODE_MAIN
1215 change_mode MMODE_PC, MMODE_MAIN
1235 movea.l #0xe000+10*2+8*64*2,a1
1249 ################### goto predef ##################
1253 movea.l #0xe000+14*2+8*64*2,a1
1254 move.l #predef_addr_cnt+2-1,d1
1266 /* draw addresses */
1267 movea.l #0xe000+17*2+9*64*2,a1
1268 lea (predef_addrs,pc),a2
1269 move.w #predef_addr_cnt-1,d4
1275 jsr print_hex_preped
1280 movea.l #0xe000+15*2+9*64*2,a0
1289 jsr get_input /* x0cbrldu x1sa00du */
1296 or.b #1,d2 /* up -1, down 1 */
1300 move.b #predef_addr_cnt-1,d5
1302 cmp.b #predef_addr_cnt-1,d5
1309 btst.l #4,d0 /* A - confirm */
1314 lea (predef_addrs,pc),a0
1317 bra mode_goto_finish
1328 ##################### jmp ########################
1335 or.b #3,d5 /* 3 bytes */
1337 change_mode MMODE_VAL_INPUT, MMODE_JMP_ADDR
1342 write_vdp_r_dst 1,(VDP1_E_DISPLAY | VDP1_MODE5),(GFXCNTL) /* disable vint */
1347 move.b #0x40,(0xa1000b).l /* port 2 ctrl */
1348 move.b #0x00,(0xa10005).l /* port 2 data - start with TH low */
1350 lea (txt_transfer_ready,pc),a0
1357 move.b (0xa10005),d0
1361 menu_text txt_working, 13, 13, 0
1365 # go back to main mode
1367 bclr.l #7,d6 /* not edited */
1368 change_mode MMODE_MAIN, MMODE_MAIN
1369 write_vdp_r_dst 12,(VDP12_SCREEN_V224 | VDP12_SCREEN_H320),(GFXCNTL)
1373 #################################################
1375 # Initialize VDP registers #
1377 #################################################
1381 write_vdp_reg 0,(VDP0_E_DISPLAY | VDP0_PLTT_FULL)
1382 write_vdp_reg 1,(VDP1_E_DISPLAY | VDP1_MODE5)
1383 write_vdp_reg 2,(0xe000 >> 10) /* Screen map a adress */
1384 write_vdp_reg 3,(0xe000 >> 10) /* Window address */
1385 write_vdp_reg 4,(0xc000 >> 13) /* Screen map b address */
1386 write_vdp_reg 5,(0xfc00 >> 9) /* Sprite address */
1388 write_vdp_reg 7,0 /* Backdrop color */
1389 write_vdp_reg 0x0a,1 /* Lines per hblank interrupt */
1390 write_vdp_reg 0x0b,0 /* 2-cell vertical scrolling */
1391 write_vdp_reg 0x0c,(VDP12_SCREEN_V224 | VDP12_SCREEN_H320)
1392 write_vdp_reg 0x0d,(0x8000 >> 10) /* Horizontal scroll address */
1393 write_vdp_reg 0x0e,0
1394 write_vdp_reg 0x0f,2
1395 write_vdp_reg 0x10,(VDP16_MAP_V32 | VDP16_MAP_H64) /* layer size */
1396 write_vdp_reg 0x11,0
1397 write_vdp_reg 0x12,0
1401 # get mask of bits representing safe words
1402 # a1 - address to check
1403 # destroys d0-d2, strips upper bits from a1
1408 lea (safe_addrs,pc),a1
1409 move.w #(safe_addrs_end - safe_addrs)/8-1,d2
1410 cmp.l #0x4D415253,(0xa130ec) /* 'MARS' */
1412 move.w #(safe_addrs_end_32x - safe_addrs)/8-1,d2
1413 move.w (0xa15100),d0
1415 cmp.w #3,d0 /* ADEN and nRES */
1417 btst.b #7,d0 /* FM */
1419 move.w #(safe_addrs_end_32x_vdp - safe_addrs)/8-1,d2
1444 /* check for VDP address */
1449 bne addr_unsafe /* not vdp */
1458 blt addr_hsafe_3 /* data port */
1460 blt addr_safe /* below PSG */
1462 bge addr_safe /* above PSG */
1465 moveq.l #0,d0 /* skip line */
1469 moveq.l #3,d0 /* skip 2 words */
1479 # read single phase from controller
1484 move.b #0x40,(0xa10003)
1488 move.b (0xa10003),d0
1489 move.b #0x00,(0xa10003)
1492 move.b (0xa10003),d0
1497 eor.w d0,d1 /* changed btns */
1498 move.w d0,d7 /* old val */
1500 and.w d0,d1 /* what changed now */
1505 and.b #0x0f,d2 /* do autorepeat */
1516 # Prepare to write to VDP RAM @a0
1517 # sets a0 to VDP data port for convenience
1523 move.l d0,(GFXCNTL).l
1528 # Load color data from ROM
1530 # a1: color list address
1531 # d0: number of colors to load
1537 move.l d0,(GFXCNTL).l
1552 # d2 - tile_bits[15:11]
1577 # d3 - tile_bits[15:11]|digit_cnt[7:0]
1578 # destroys a0, preserves d3
1589 ror.l d0,d2 /* prep value */
1590 subq.l #1,d1 /* count */
1592 and.w #0xf800,d0 /* keep upper bits in d0 */
1605 dbra d1,_print_hex_loop
1610 # wait vertical sync interrupt
1621 # wait vsync start (polling)
1645 jmp 0x123456 /* will be patched */
1648 #################################################
1652 #################################################
1660 # vim:filetype=asmM68k