1 ###############################################################################
3 # Copyright (c) 2009, 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 ''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 <copyright holder> 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
41 ##################################################
43 # Register and bitmask definitions #
45 ##################################################
47 .equ GFXDATA, 0xc00000
48 .equ GFXCNTL, 0xc00004
51 .equ VDP0_E_DISPLAY, 0x02
52 .equ VDP0_PLTT_FULL, 0x04
54 .equ VDP1_SMS_MODE, 0x80
55 .equ VDP1_E_DISPLAY, 0x40
63 .equ VDP12_SCREEN_V224, 0x00
64 .equ VDP12_SCREEN_V448, 0x04
65 .equ VDP12_PROGRESSIVE, 0x00
66 .equ VDP12_INTERLACED, 0x02
67 .equ VDP12_SCREEN_H256, 0x00
68 .equ VDP12_SCREEN_H320, 0x81
70 .equ VDP16_MAP_V32, 0x00
71 .equ VDP16_MAP_V64, 0x10
72 .equ VDP16_MAP_V128, 0x30
73 .equ VDP16_MAP_H32, 0x00
74 .equ VDP16_MAP_H64, 0x01
75 .equ VDP16_MAP_H128, 0x03
78 .equ MMODE_VAL_INPUT, 1
79 .equ MMODE_EDIT_VAL, 2
81 .equ MMODE_START_MENU, 4
82 .equ MMODE_GOTO_PREDEF, 5
83 .equ MMODE_JMP_ADDR, 6
86 .equ predef_addr_cnt, ((predef_addrs_end-predef_addrs)/4)
88 ##################################################
92 ##################################################
95 # Write val to VDP register reg
96 .macro write_vdp_r_dst reg val dst
97 move.w #((\reg << 8) + 0x8000 + \val),\dst
100 # Write val to VDP register reg, vdp addr in a3
101 .macro write_vdp_reg reg val
102 write_vdp_r_dst \reg, \val, (a3)
105 # Set up address in VDP, control port in dst
106 .macro VRAM_ADDR adr dst
107 move.l #(0x40000000 | ((\adr & 0x3fff) << 16) | (\adr >> 14)),\dst
110 .macro VSRAM_ADDR adr dst
111 move.l #(0x40000010 | ((\adr & 0x3fff) << 16) | (\adr >> 14)),\dst
115 # make VDP word from address adr and store in d0
116 .macro XRAM_ADDR_var adr
126 .macro VRAM_ADDR_var adr
132 .macro CRAM_ADDR_var adr
138 # convert tile coords in d0, d1 to nametable addr to a0
147 # check if some d-pad button (and modifier) is pressed
148 .macro do_dpad bit op val
156 # convert a6 to normal addr
158 .macro mk_a6_addr reg
166 .macro change_mode mode_new mode_back
168 or.w #(\mode_back<<11)|(\mode_new<<8),d7
172 .macro menu_text str x y pal
176 move.l #0x8000|(\pal<<13),d2
180 #################################################
184 #################################################
187 dc.w 0x0000,0x0eee,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000
188 dc.w 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000
189 dc.w 0x0000,0x02e2,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000
190 dc.w 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000
191 dc.w 0x0000,0x0e44,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000
192 dc.w 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000
193 dc.w 0x0000,0x044e,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000
194 dc.w 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000
199 /* Y size link attr X */
200 dc.w 0; dc.b 0x05; dc.b 0; dc.w 0x6002; dc.w 0
204 dc.l 0x000000, 0x200000, 0x400000, 0xa00000, 0xa10000
205 dc.l 0xa11100, 0xa12000, 0xa13000, 0xa14000, 0xc00000
209 dc.l 0x000000, 0x7fffff
210 dc.l 0xe00000, 0xffffff
211 dc.l 0xa00000, 0xa100ff
212 dc.l 0xa11000, 0xa113ff
213 dc.l 0xa12000, 0xa120ff
214 dc.l 0xa13000, 0xa130ff
218 dc.l 0x000000 /* 1 for recv */
231 .ascii "Go to address\0"
233 .ascii "Go to (predef)\0"
235 .ascii "Jump to address\0"
239 .ascii "DTACK safety\0"
241 .ascii "Ready to send\0"
243 .ascii "Ready to recv\0"
245 .ascii "Working.. \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 /* mask irqs during init */
272 /* copy to expansion device if magic number is set */
278 move.w #0x2000/8-1,d0
287 /* we could be relocated by 32x or something else, adjust start addr */
293 /* copy, assume 8K size */
295 move.w #0x2000/8-1,d0
302 lea (test_code,pc),a0
304 move.w #(test_code_end - test_code)/2-1,d0
315 /* patch test code */
317 add.w #(test_code_ret_op-test_code+2),a1
329 move.b #0x40,(0xa10009).l
330 move.b #0x40,(0xa10003).l
335 /* Clear h/v scroll */
337 VRAM_ADDR 0x8000,(GFXCNTL)
339 VSRAM_ADDR 0,(GFXCNTL)
342 /* Load color data */
345 moveq.l #(colors_end-colors)/2,d0
348 /* load font patterns */
351 VRAM_ADDR 0,(GFXCNTL)
363 rol.l #1,d1 /* fixup */
367 /* generate A layer map */
375 0: move.l #0x00000000,(a0)
381 /* generate B layer map */
386 0: move.l #0x00000000,(a0)
389 /* upload sprite data */
392 lea (sprite_data,pc),a1
394 move.l #(sprite_data_end-sprite_data)/2-1,d3
399 /* wait for vsync before unmask */
402 /* wait a bit to avoid nested vint */
405 dbra d0,0b /* 10 cycles to go back */
407 /* enable and unmask vint */
408 write_vdp_r_dst 1,(VDP1_E_VBI | VDP1_E_DISPLAY | VDP1_MODE5),(GFXCNTL)
412 ##################################################
425 /* let's hope VRAM is already set up.. */
433 ##################################################
437 # movem.l d0-d4/a0-a5,-(a7)
443 lea (jumptab,pc,d0),a0
448 bra mode_edit_val /* edit val in editor */
455 ##################### main #######################
458 /* assume we will hang */
459 lea (txt_dtack_err,pc),a0
469 move.l d0,a1 /* current addr */
472 add.b #27-1,d1 /* line where the cursor sits */
476 move.l #27-1,d5 /* line counter for dbra */
499 # unsafe or partially safe
502 swap d4 /* mask in upper word */
504 bne draw_row_hsafe_words_pre
506 draw_row_hsafe_bytes_pre:
511 draw_row_hsafe_bytes:
517 move.l #'?'|('?'<<16),(a0)
519 move.l #'?'|('?'<<16),(a0)
529 dbra d4,draw_row_hsafe_bytes
536 beq draw_cursor_unsafe_byte
537 bra draw_chars_hsafe_pre
539 draw_row_hsafe_words_pre:
544 draw_row_hsafe_words:
550 move.l #'?'|('?'<<16),(a0)
551 move.l #'?'|('?'<<16),(a0)
558 dbra d4,draw_row_hsafe_words
560 move.l #(' '<<16)|' ',(a0)
565 beq draw_cursor_unsafe_word
567 draw_chars_hsafe_pre:
577 move.l #'?'|('?'<<16),(a0)
578 bra draw_chars_hsafe_next
580 btst.l #15,d7 /* must perform correct read type */
581 bne 0f /* doing byte reads on security reg hangs */
608 draw_chars_hsafe_next:
610 dbra d4,draw_chars_hsafe
612 move.l #(' '<<16)|' ',(a0)
651 move.l #(' '<<16)|' ',(a0)
673 move.l #(' '<<16)|' ',(a0)
695 move.l #' '|(' '<<16),(a0)
696 move.l #' '|(' '<<16),(a0)
701 jsr get_input /* x0cbrldu x1sa00du */
703 btst.l #16+4,d0 /* A - scroll modifier */
706 do_dpad 16+0, sub, #0x0800
707 do_dpad 16+1, add, #0x0800
708 do_dpad 16+10, sub, #0xd800
709 do_dpad 16+11, add, #0xd800
716 do_dpad 0, subq, #0x0008
717 do_dpad 1, addq, #0x0008
738 btst.l #12,d0 /* B - switch byte/word mode */
741 add.w #0x4000,d7 /* changes between 01 10 */
744 sub.l d1,a6 /* make even, just in case */
747 btst.l #13,d0 /* C - edit selected byte */
750 change_mode MMODE_EDIT_VAL, MMODE_MAIN
751 write_vdp_r_dst 12,(VDP12_SCREEN_V224 | VDP12_SCREEN_H320 | VDP12_STE),(GFXCNTL)
754 btst.l #5,d0 /* Start - menu */
758 change_mode MMODE_START_MENU, MMODE_MAIN
759 write_vdp_r_dst 12,(VDP12_SCREEN_V224 | VDP12_SCREEN_H320 | VDP12_STE),(GFXCNTL)
763 # movem.l (a7)+,d0-d4/a0-a5
771 draw_cursor_unsafe_byte:
773 and.l #7,d0 /* byte offs */
776 add.b d1,d0 /* d0 *= 3 (chars) */
780 move.l #(0x2000|'?'|((0x2000|'?')<<16)),(a0)
784 jsr load_prepare /* restore a0 */
785 bra draw_chars_hsafe_pre
787 draw_cursor_unsafe_word:
789 and.l #7,d0 /* byte offs */
791 lsr.b #1,d1 /* which word */
794 add.b d2,d1 /* num of chars to skip */
799 move.l #(0x2000|'?'|((0x2000|'?')<<16)),d0
805 jsr load_prepare /* restore a0 */
806 bra draw_chars_hsafe_pre
811 and.l #7,d0 /* byte offs */
817 add.b d1,d0 /* d0 *= 3 (chars) */
825 jsr load_prepare /* restore a0 */
831 and.l #7,d0 /* byte offs */
833 lsr.b #1,d1 /* which word */
836 add.b d2,d1 /* num of chars to skip */
847 jsr load_prepare /* restore a0 */
852 #################### hedit #######################
856 bne mode_hedit_finish
858 /* read val to edit */
874 change_mode MMODE_VAL_INPUT, MMODE_EDIT_VAL
893 ##################### goto #######################
904 or.b #3,d5 /* 3 bytes */
906 change_mode MMODE_VAL_INPUT, MMODE_GOTO
926 ################### val edit #####################
930 movea.l #0xe000+14*2+11*64*2,a1
950 lea (txt_a_confirm,pc),a0
961 and.b #3,d3 /* edit field bytes */
979 lsr.b #1,d1 /* length in bytes */
983 and.b #7,d1 /* nibble to edit */
987 sub.b #1,d3 /* chars to shift out */
998 jsr get_input /* x0cbrldu x1sa00du */
1005 add.b d1,d1 /* nibble count */
1006 sub.b #1,d1 /* max n.t.e. val */
1009 and.b #7,d2 /* nibble to edit */
1021 lsl.l d1,d3 /* mask */
1022 lsl.l d1,d4 /* what to add/sub */
1033 eor.l #0xffffffff,d3
1067 btst.l #4,d0 /* A - confirm */
1070 move.w d7,d1 /* back to prev mode */
1080 ################### start menu ###################
1087 menu_text txt_about, 13, 9, 1
1088 menu_text txt_goto, 13, 11, 0
1089 menu_text txt_goto_predef, 13, 12, 0
1090 menu_text txt_jmp_addr, 13, 13, 0
1091 menu_text txt_dump, 13, 14, 0
1092 menu_text txt_dtack, 13, 15, 0
1093 menu_text txt_a_confirm, 13, 17, 2
1095 /* dtack safety on/off */
1096 movea.l #0xe000+26*2+15*64*2,a0
1098 move.w #0x8000|'O',(a0)
1101 move.w #0x8000|'N',(a0)
1104 move.w #0x8000|'F',(a0)
1105 move.w #0x8000|'F',(a0)
1109 movea.l #0xe000+11*2+11*64*2,a0
1119 jsr get_input /* x0cbrldu x1sa00du */
1128 or.b #1,d2 /* up -1, down 1 */
1143 btst.l #4,d0 /* A - confirm */
1148 change_mode MMODE_GOTO, MMODE_MAIN
1155 change_mode MMODE_GOTO_PREDEF, MMODE_MAIN
1161 change_mode MMODE_JMP_ADDR, MMODE_MAIN
1167 change_mode MMODE_DUMP, MMODE_MAIN
1187 movea.l #0xe000+10*2+8*64*2,a1
1201 ################### goto predef ##################
1205 movea.l #0xe000+14*2+8*64*2,a1
1206 move.l #predef_addr_cnt+2-1,d1
1218 /* draw addresses */
1219 movea.l #0xe000+17*2+9*64*2,a1
1220 lea (predef_addrs,pc),a2
1221 move.w #predef_addr_cnt-1,d4
1227 jsr print_hex_preped
1232 movea.l #0xe000+15*2+9*64*2,a0
1241 jsr get_input /* x0cbrldu x1sa00du */
1248 or.b #1,d2 /* up -1, down 1 */
1252 move.b #predef_addr_cnt-1,d5
1254 cmp.b #predef_addr_cnt-1,d5
1261 btst.l #4,d0 /* A - confirm */
1266 lea (predef_addrs,pc),a0
1269 bra mode_goto_finish
1280 ##################### jmp ########################
1287 or.b #3,d5 /* 3 bytes */
1289 change_mode MMODE_VAL_INPUT, MMODE_JMP_ADDR
1294 write_vdp_r_dst 1,(VDP1_E_DISPLAY | VDP1_MODE5),(GFXCNTL) /* disable vint */
1298 ################### transfer #####################
1301 move.b #0x40,(0xa1000b).l
1302 move.b #0x40,(0xa10005).l
1304 move.l (transfer_mode,pc),d0
1307 lea (txt_ready_send,pc),a0
1310 lea (txt_ready_recv,pc),a0
1318 move.b (0xa10005),d0
1322 menu_text txt_working, 13, 13, 0
1325 move.l (transfer_addr,pc),a0
1326 move.l (transfer_len,pc),d2
1328 move.l (transfer_mode,pc),d0
1333 move.b #0x4f,(0xa1000b).l
1344 move.b d1,(a1) /* clears TH and writes data */
1348 bset.b #6,d1 /* prepare TH */
1359 move.b #0,(0xa1000b).l
1363 move.b #0,(a1) /* clear TH */
1371 move.b #0x40,(a1) /* set TH */
1380 move.b #0,(a1) /* clear TH */
1388 move.b #0,(0xa1000b).l
1392 # go back to main mode
1394 bclr.l #7,d6 /* not edited */
1395 change_mode MMODE_MAIN, MMODE_MAIN
1396 write_vdp_r_dst 12,(VDP12_SCREEN_V224 | VDP12_SCREEN_H320),(GFXCNTL)
1400 #################################################
1402 # Initialize VDP registers #
1404 #################################################
1408 write_vdp_reg 0,(VDP0_E_DISPLAY | VDP0_PLTT_FULL)
1409 write_vdp_reg 1,(VDP1_E_DISPLAY | VDP1_MODE5)
1410 write_vdp_reg 2,(0xe000 >> 10) /* Screen map a adress */
1411 write_vdp_reg 3,(0xe000 >> 10) /* Window address */
1412 write_vdp_reg 4,(0xc000 >> 13) /* Screen map b address */
1413 write_vdp_reg 5,(0xfc00 >> 9) /* Sprite address */
1415 write_vdp_reg 7,0 /* Backdrop color */
1416 write_vdp_reg 0x0a,1 /* Lines per hblank interrupt */
1417 write_vdp_reg 0x0b,0 /* 2-cell vertical scrolling */
1418 write_vdp_reg 0x0c,(VDP12_SCREEN_V224 | VDP12_SCREEN_H320)
1419 write_vdp_reg 0x0d,(0x8000 >> 10) /* Horizontal scroll address */
1420 write_vdp_reg 0x0e,0
1421 write_vdp_reg 0x0f,2
1422 write_vdp_reg 0x10,(VDP16_MAP_V32 | VDP16_MAP_H64) /* layer size */
1423 write_vdp_reg 0x11,0
1424 write_vdp_reg 0x12,0
1428 # get mask of bits representing safe words
1429 # a1 - address to check
1430 # destroys d0-d2, strips upper bits from a1
1435 lea (safe_addrs,pc),a1
1436 move.w #(safe_addrs_end - safe_addrs)/8-1,d2
1458 /* check for VDP address */
1463 bne addr_unsafe /* not vdp */
1472 blt addr_hsafe_3 /* data port */
1474 blt addr_safe /* below PSG */
1476 bge addr_safe /* above PSG */
1479 moveq.l #0,d0 /* skip line */
1483 moveq.l #3,d0 /* skip 2 words */
1493 # read single phase from controller
1498 move.b #0x40,(0xa10003)
1502 move.b (0xa10003),d0
1503 move.b #0x00,(0xa10003)
1506 move.b (0xa10003),d0
1511 eor.w d0,d1 /* changed btns */
1512 move.w d0,d7 /* old val */
1514 and.w d0,d1 /* what changed now */
1519 and.b #0x0f,d2 /* do autorepeat */
1530 # Prepare to write to VDP RAM @a0
1531 # sets a0 to VDP data port for convenience
1537 move.l d0,(GFXCNTL).l
1542 # Load color data from ROM
1544 # a1: color list address
1545 # d0: number of colors to load
1551 move.l d0,(GFXCNTL).l
1566 # d2 - tile_bits[15:11]
1591 # d3 - tile_bits[15:11]|digit_cnt[7:0]
1592 # destroys a0, preserves d3
1603 ror.l d0,d2 /* prep value */
1604 subq.l #1,d1 /* count */
1606 and.w #0xf800,d0 /* keep upper bits in d0 */
1619 dbra d1,_print_hex_loop
1624 # wait vertical sync interrupt
1635 # wait vsync start (polling)
1659 jmp 0x123456 /* will be patched */
1662 #################################################
1666 #################################################
1674 # vim:filetype=asmM68k