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, 0xc00000
210 dc.l 0x000000, 0x7fffff
211 dc.l 0xe00000, 0xffffff
212 dc.l 0xa00000, 0xa100ff
213 dc.l 0xa11000, 0xa113ff
214 dc.l 0xa12000, 0xa120ff
215 dc.l 0xa13000, 0xa130ff
228 .ascii "Go to address\0"
230 .ascii "Go to (predef)\0"
232 .ascii "Jump to address\0"
234 .ascii "PC Transfer\0"
236 .ascii "DTACK safety\0"
238 .ascii "Transfer Ready\0"
242 .ascii "DTACK err?\0"
244 .ascii "Exception \0"
246 ##################################################
250 ##################################################
253 # a6 = page_start[31:8]|cursor_offs[7:0]
254 # d7 = old_inputs[31:16]|edit_bytes[15:14]|g_mode_old[13:11]|g_mode[10:8]|irq_cnt[7:0]
255 # d6 = edit_word_save[31:15]|edit_done[7]|no_dtack_detect[4]|autorep_cnt[3:0]
257 # edit: edit_word[31:8]|edit_pos[4:2]|byte_cnt[1:0]
263 /* make sure io port 2 is doing inputs */
264 move.b #0,(0xa1000b).l
265 /* mask irqs during init */
269 /* copy to expansion device if magic number is set */
275 move.l (sizeof_bin,pc),d0
285 /* we could be relocated by 32x or something else, adjust start addr */
291 /* copy, assume 8K size */
293 move.l (sizeof_bin,pc),d0
301 lea (test_code,pc),a0
303 move.w #(test_code_end - test_code)/2-1,d0
314 /* patch test code */
316 add.w #(test_code_ret_op-test_code+2),a1
328 move.b #0x40,(0xa10009).l
329 move.b #0x40,(0xa10003).l
334 /* Clear h/v scroll */
336 VRAM_ADDR 0x8000,(GFXCNTL)
338 VSRAM_ADDR 0,(GFXCNTL)
341 /* Load color data */
344 moveq.l #(colors_end-colors)/2,d0
347 /* load font patterns */
350 VRAM_ADDR 0,(GFXCNTL)
362 rol.l #1,d1 /* fixup */
366 /* generate A layer map */
374 0: move.l #0x00000000,(a0)
380 /* generate B layer map */
385 0: move.l #0x00000000,(a0)
388 /* upload sprite data */
391 lea (sprite_data,pc),a1
393 move.l #(sprite_data_end-sprite_data)/2-1,d3
398 /* wait for vsync before unmask */
401 /* wait a bit to avoid nested vint */
404 dbra d0,0b /* 10 cycles to go back */
406 /* enable and unmask vint */
407 write_vdp_r_dst 1,(VDP1_E_VBI | VDP1_E_DISPLAY | VDP1_MODE5),(GFXCNTL)
411 ##################################################
424 /* let's hope VRAM is already set up.. */
432 ##################################################
436 # movem.l d0-d4/a0-a5,-(a7)
438 btst.b #5,(0xa10005).l
440 change_mode MMODE_PC, MMODE_MAIN
441 write_vdp_r_dst 12,(VDP12_SCREEN_V224 | VDP12_SCREEN_H320 | VDP12_STE),(GFXCNTL)
448 lea (jumptab,pc,d0),a0
451 /* branch insns here because we want to be position independent */
454 bra mode_edit_val /* edit val in editor */
461 ##################### main #######################
464 /* assume we will hang */
465 lea (txt_dtack_err,pc),a0
475 move.l d0,a1 /* current addr */
478 add.b #27-1,d1 /* line where the cursor sits */
482 move.l #27-1,d5 /* line counter for dbra */
505 # unsafe or partially safe
508 swap d4 /* mask in upper word */
510 bne draw_row_hsafe_words_pre
512 draw_row_hsafe_bytes_pre:
517 draw_row_hsafe_bytes:
523 move.l #'?'|('?'<<16),(a0)
525 move.l #'?'|('?'<<16),(a0)
535 dbra d4,draw_row_hsafe_bytes
542 beq draw_cursor_unsafe_byte
543 bra draw_chars_hsafe_pre
545 draw_row_hsafe_words_pre:
550 draw_row_hsafe_words:
556 move.l #'?'|('?'<<16),(a0)
557 move.l #'?'|('?'<<16),(a0)
564 dbra d4,draw_row_hsafe_words
566 move.l #(' '<<16)|' ',(a0)
571 beq draw_cursor_unsafe_word
573 draw_chars_hsafe_pre:
583 move.l #'?'|('?'<<16),(a0)
584 bra draw_chars_hsafe_next
586 btst.l #15,d7 /* must perform correct read type */
587 bne 0f /* doing byte reads on security reg hangs */
614 draw_chars_hsafe_next:
616 dbra d4,draw_chars_hsafe
618 move.l #(' '<<16)|' ',(a0)
657 move.l #(' '<<16)|' ',(a0)
679 move.l #(' '<<16)|' ',(a0)
701 move.l #' '|(' '<<16),(a0)
702 move.l #' '|(' '<<16),(a0)
707 jsr get_input /* x0cbrldu x1sa00du */
709 btst.l #16+4,d0 /* A - scroll modifier */
712 do_dpad 16+0, sub, #0x0800
713 do_dpad 16+1, add, #0x0800
714 do_dpad 16+10, sub, #0xd800
715 do_dpad 16+11, add, #0xd800
722 do_dpad 0, subq, #0x0008
723 do_dpad 1, addq, #0x0008
744 btst.l #12,d0 /* B - switch byte/word mode */
747 add.w #0x4000,d7 /* changes between 01 10 */
750 sub.l d1,a6 /* make even, just in case */
753 btst.l #13,d0 /* C - edit selected byte */
756 change_mode MMODE_EDIT_VAL, MMODE_MAIN
757 write_vdp_r_dst 12,(VDP12_SCREEN_V224 | VDP12_SCREEN_H320 | VDP12_STE),(GFXCNTL)
760 btst.l #5,d0 /* Start - menu */
764 change_mode MMODE_START_MENU, MMODE_MAIN
765 write_vdp_r_dst 12,(VDP12_SCREEN_V224 | VDP12_SCREEN_H320 | VDP12_STE),(GFXCNTL)
769 # movem.l (a7)+,d0-d4/a0-a5
777 draw_cursor_unsafe_byte:
779 and.l #7,d0 /* byte offs */
782 add.b d1,d0 /* d0 *= 3 (chars) */
786 move.l #(0x2000|'?'|((0x2000|'?')<<16)),(a0)
790 jsr load_prepare /* restore a0 */
791 bra draw_chars_hsafe_pre
793 draw_cursor_unsafe_word:
795 and.l #7,d0 /* byte offs */
797 lsr.b #1,d1 /* which word */
800 add.b d2,d1 /* num of chars to skip */
805 move.l #(0x2000|'?'|((0x2000|'?')<<16)),d0
811 jsr load_prepare /* restore a0 */
812 bra draw_chars_hsafe_pre
817 and.l #7,d0 /* byte offs */
823 add.b d1,d0 /* d0 *= 3 (chars) */
831 jsr load_prepare /* restore a0 */
837 and.l #7,d0 /* byte offs */
839 lsr.b #1,d1 /* which word */
842 add.b d2,d1 /* num of chars to skip */
853 jsr load_prepare /* restore a0 */
858 #################### hedit #######################
862 bne mode_hedit_finish
864 /* read val to edit */
880 change_mode MMODE_VAL_INPUT, MMODE_EDIT_VAL
899 ##################### goto #######################
910 or.b #3,d5 /* 3 bytes */
912 change_mode MMODE_VAL_INPUT, MMODE_GOTO
932 ################### val edit #####################
936 movea.l #0xe000+14*2+11*64*2,a1
956 lea (txt_a_confirm,pc),a0
967 and.b #3,d3 /* edit field bytes */
985 lsr.b #1,d1 /* length in bytes */
989 and.b #7,d1 /* nibble to edit */
993 sub.b #1,d3 /* chars to shift out */
1004 jsr get_input /* x0cbrldu x1sa00du */
1011 add.b d1,d1 /* nibble count */
1012 sub.b #1,d1 /* max n.t.e. val */
1015 and.b #7,d2 /* nibble to edit */
1027 lsl.l d1,d3 /* mask */
1028 lsl.l d1,d4 /* what to add/sub */
1039 eor.l #0xffffffff,d3
1073 btst.l #4,d0 /* A - confirm */
1076 move.w d7,d1 /* back to prev mode */
1086 ################### start menu ###################
1093 menu_text txt_about, 13, 9, 1
1094 menu_text txt_goto, 13, 11, 0
1095 menu_text txt_goto_predef, 13, 12, 0
1096 menu_text txt_jmp_addr, 13, 13, 0
1097 menu_text txt_dump, 13, 14, 0
1098 menu_text txt_dtack, 13, 15, 0
1099 menu_text txt_a_confirm, 13, 17, 2
1101 /* dtack safety on/off */
1102 movea.l #0xe000+26*2+15*64*2,a0
1104 move.w #0x8000|'O',(a0)
1107 move.w #0x8000|'N',(a0)
1110 move.w #0x8000|'F',(a0)
1111 move.w #0x8000|'F',(a0)
1115 movea.l #0xe000+11*2+11*64*2,a0
1125 jsr get_input /* x0cbrldu x1sa00du */
1134 or.b #1,d2 /* up -1, down 1 */
1149 btst.l #4,d0 /* A - confirm */
1154 change_mode MMODE_GOTO, MMODE_MAIN
1161 change_mode MMODE_GOTO_PREDEF, MMODE_MAIN
1167 change_mode MMODE_JMP_ADDR, MMODE_MAIN
1173 change_mode MMODE_PC, MMODE_MAIN
1193 movea.l #0xe000+10*2+8*64*2,a1
1207 ################### goto predef ##################
1211 movea.l #0xe000+14*2+8*64*2,a1
1212 move.l #predef_addr_cnt+2-1,d1
1224 /* draw addresses */
1225 movea.l #0xe000+17*2+9*64*2,a1
1226 lea (predef_addrs,pc),a2
1227 move.w #predef_addr_cnt-1,d4
1233 jsr print_hex_preped
1238 movea.l #0xe000+15*2+9*64*2,a0
1247 jsr get_input /* x0cbrldu x1sa00du */
1254 or.b #1,d2 /* up -1, down 1 */
1258 move.b #predef_addr_cnt-1,d5
1260 cmp.b #predef_addr_cnt-1,d5
1267 btst.l #4,d0 /* A - confirm */
1272 lea (predef_addrs,pc),a0
1275 bra mode_goto_finish
1286 ##################### jmp ########################
1293 or.b #3,d5 /* 3 bytes */
1295 change_mode MMODE_VAL_INPUT, MMODE_JMP_ADDR
1300 write_vdp_r_dst 1,(VDP1_E_DISPLAY | VDP1_MODE5),(GFXCNTL) /* disable vint */
1305 move.b #0x40,(0xa1000b).l /* port 2 ctrl */
1306 move.b #0x00,(0xa10005).l /* port 2 data - start with TH low */
1308 lea (txt_transfer_ready,pc),a0
1315 move.b (0xa10005),d0
1319 menu_text txt_working, 13, 13, 0
1322 # go back to main mode
1324 bclr.l #7,d6 /* not edited */
1325 change_mode MMODE_MAIN, MMODE_MAIN
1326 write_vdp_r_dst 12,(VDP12_SCREEN_V224 | VDP12_SCREEN_H320),(GFXCNTL)
1330 #################################################
1332 # Initialize VDP registers #
1334 #################################################
1338 write_vdp_reg 0,(VDP0_E_DISPLAY | VDP0_PLTT_FULL)
1339 write_vdp_reg 1,(VDP1_E_DISPLAY | VDP1_MODE5)
1340 write_vdp_reg 2,(0xe000 >> 10) /* Screen map a adress */
1341 write_vdp_reg 3,(0xe000 >> 10) /* Window address */
1342 write_vdp_reg 4,(0xc000 >> 13) /* Screen map b address */
1343 write_vdp_reg 5,(0xfc00 >> 9) /* Sprite address */
1345 write_vdp_reg 7,0 /* Backdrop color */
1346 write_vdp_reg 0x0a,1 /* Lines per hblank interrupt */
1347 write_vdp_reg 0x0b,0 /* 2-cell vertical scrolling */
1348 write_vdp_reg 0x0c,(VDP12_SCREEN_V224 | VDP12_SCREEN_H320)
1349 write_vdp_reg 0x0d,(0x8000 >> 10) /* Horizontal scroll address */
1350 write_vdp_reg 0x0e,0
1351 write_vdp_reg 0x0f,2
1352 write_vdp_reg 0x10,(VDP16_MAP_V32 | VDP16_MAP_H64) /* layer size */
1353 write_vdp_reg 0x11,0
1354 write_vdp_reg 0x12,0
1358 # get mask of bits representing safe words
1359 # a1 - address to check
1360 # destroys d0-d2, strips upper bits from a1
1365 lea (safe_addrs,pc),a1
1366 move.w #(safe_addrs_end - safe_addrs)/8-1,d2
1388 /* check for VDP address */
1393 bne addr_unsafe /* not vdp */
1402 blt addr_hsafe_3 /* data port */
1404 blt addr_safe /* below PSG */
1406 bge addr_safe /* above PSG */
1409 moveq.l #0,d0 /* skip line */
1413 moveq.l #3,d0 /* skip 2 words */
1423 # read single phase from controller
1428 move.b #0x40,(0xa10003)
1432 move.b (0xa10003),d0
1433 move.b #0x00,(0xa10003)
1436 move.b (0xa10003),d0
1441 eor.w d0,d1 /* changed btns */
1442 move.w d0,d7 /* old val */
1444 and.w d0,d1 /* what changed now */
1449 and.b #0x0f,d2 /* do autorepeat */
1460 # Prepare to write to VDP RAM @a0
1461 # sets a0 to VDP data port for convenience
1467 move.l d0,(GFXCNTL).l
1472 # Load color data from ROM
1474 # a1: color list address
1475 # d0: number of colors to load
1481 move.l d0,(GFXCNTL).l
1496 # d2 - tile_bits[15:11]
1521 # d3 - tile_bits[15:11]|digit_cnt[7:0]
1522 # destroys a0, preserves d3
1533 ror.l d0,d2 /* prep value */
1534 subq.l #1,d1 /* count */
1536 and.w #0xf800,d0 /* keep upper bits in d0 */
1549 dbra d1,_print_hex_loop
1554 # wait vertical sync interrupt
1565 # wait vsync start (polling)
1589 jmp 0x123456 /* will be patched */
1592 #################################################
1596 #################################################
1604 # vim:filetype=asmM68k