From: notaz Date: Mon, 7 Dec 2015 23:54:13 +0000 (+0200) Subject: Add 'teensytp/' from commit 'be48e888050f18a31e788269c8f47358036a8e3b' X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?p=megadrive.git;a=commitdiff_plain;h=37f24627a5efd05d8b52bc3a3e1253d077926c2e;hp=be48e888050f18a31e788269c8f47358036a8e3b Add 'teensytp/' from commit 'be48e888050f18a31e788269c8f47358036a8e3b' git-subtree-dir: teensytp git-subtree-mainline: 8d788f3de66aeda55c2518b5e511111face3a82a git-subtree-split: be48e888050f18a31e788269c8f47358036a8e3b --- diff --git a/.gitignore b/.gitignore index 850d10a..5457b76 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,2 @@ *.o -*.elf -*.hex -.*.swp -cscope.out -tags +*.gen diff --git a/hexed/Makefile b/hexed/Makefile new file mode 100644 index 0000000..55a0e05 --- /dev/null +++ b/hexed/Makefile @@ -0,0 +1,48 @@ +CROSS = m68k-elf- +CC = $(CROSS)gcc +AS = $(CROSS)as +LD = $(CROSS)ld +OBJCOPY = $(CROSS)objcopy + +ASFLAGS += -m68000 --register-prefix-optional --bitwise-or -pic +CPPFLAGS += -Wa,-m68000 -Wa,--register-prefix-optional -Wa,--bitwise-or -Wa,-pic + +TARGET = hexed.bin +OBJS = sega_gcc.o hexed.o transfer.o font.o + +all: $(TARGET) + +$(TARGET): a.out + $(OBJCOPY) -I elf32-m68k -O binary $^ $@ + +a.out: $(OBJS) + $(LD) -Tmd.ld -Map $(TARGET).map $^ + +clean: + $(RM) $(TARGET) $(OBJS) $(TARGET).map a.out pc_transfer + + +pc_transfer: pc_transfer.c + gcc -Wall -O2 -ggdb -o $@ $^ -lz + +%.o: %.S + $(CC) -c -o $@ $^ $(CPPFLAGS) + +%.bin: %.o + $(OBJCOPY) -I elf32-m68k -O binary $^ $@ + + +# ----------- release ----------- +ifneq ($(findstring rel,$(MAKECMDGOALS)),) +ifeq ($(VER),) +$(error need VER) +endif +endif + +rel: hexed.bin readme.txt src + zip -9 -r hexed_r$(VER).zip $^ + rm -rf src + +src: hexed.s font.s sega_gcc.s md.ld Makefile + mkdir src + cp $^ src/ diff --git a/hexed/font.s b/hexed/font.s new file mode 100644 index 0000000..6b3be24 --- /dev/null +++ b/hexed/font.s @@ -0,0 +1,69 @@ +.text +.globl font + +font: + dc.b 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 + dc.b 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 + dc.b 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 + dc.b 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 + dc.b 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 + dc.b 0x3C,0x42,0x99,0xBD,0xBD,0x99,0x42,0x3C,0x3C,0x42,0x81,0x81,0x81,0x81,0x42,0x3C + dc.b 0xFE,0x82,0x8A,0xD2,0xA2,0x82,0xFE,0x00,0xFE,0x82,0x82,0x82,0x82,0x82,0xFE,0x00 + dc.b 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x64,0x74,0x7C,0x38,0x00,0x00 + dc.b 0x80,0xC0,0xF0,0xFC,0xF0,0xC0,0x80,0x00,0x01,0x03,0x0F,0x3F,0x0F,0x03,0x01,0x00 + dc.b 0x18,0x3C,0x7E,0x18,0x7E,0x3C,0x18,0x00,0xEE,0xEE,0xEE,0xCC,0x00,0xCC,0xCC,0x00 + dc.b 0x00,0x00,0x30,0x68,0x78,0x30,0x00,0x00,0x00,0x38,0x64,0x74,0x7C,0x38,0x00,0x00 + dc.b 0x3C,0x66,0x7A,0x7A,0x7E,0x7E,0x3C,0x00,0x0E,0x3E,0x3A,0x22,0x26,0x6E,0xE4,0x40 + dc.b 0x18,0x3C,0x7E,0x3C,0x3C,0x3C,0x3C,0x00,0x3C,0x3C,0x3C,0x3C,0x7E,0x3C,0x18,0x00 + dc.b 0x08,0x7C,0x7E,0x7E,0x7C,0x08,0x00,0x00,0x10,0x3E,0x7E,0x7E,0x3E,0x10,0x00,0x00 + dc.b 0x58,0x2A,0xDC,0xC8,0xDC,0x2A,0x58,0x00,0x24,0x66,0xFF,0xFF,0x66,0x24,0x00,0x00 + dc.b 0x00,0x10,0x10,0x38,0x38,0x7C,0xFE,0x00,0xFE,0x7C,0x38,0x38,0x10,0x10,0x00,0x00 + dc.b 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1C,0x1C,0x1C,0x18,0x00,0x18,0x18,0x00 + dc.b 0x6C,0x6C,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x7C,0x28,0x7C,0x28,0x00,0x00 + dc.b 0x10,0x38,0x60,0x38,0x0C,0x78,0x10,0x00,0x40,0xA4,0x48,0x10,0x24,0x4A,0x04,0x00 + dc.b 0x18,0x34,0x18,0x3A,0x6C,0x66,0x3A,0x00,0x18,0x18,0x20,0x00,0x00,0x00,0x00,0x00 + dc.b 0x30,0x60,0x60,0x60,0x60,0x60,0x30,0x00,0x0C,0x06,0x06,0x06,0x06,0x06,0x0C,0x00 + dc.b 0x10,0x54,0x38,0x7C,0x38,0x54,0x10,0x00,0x00,0x18,0x18,0x7E,0x18,0x18,0x00,0x00 + dc.b 0x00,0x00,0x00,0x00,0x18,0x18,0x30,0x00,0x00,0x00,0x00,0x00,0x3E,0x00,0x00,0x00 + dc.b 0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x04,0x08,0x10,0x20,0x40,0x00,0x00 + dc.b 0x38,0x4C,0xC6,0xC6,0xC6,0x64,0x38,0x00,0x18,0x38,0x18,0x18,0x18,0x18,0x7E,0x00 + dc.b 0x7C,0xC6,0x0E,0x3C,0x78,0xE0,0xFE,0x00,0x7E,0x0C,0x18,0x3C,0x06,0xC6,0x7C,0x00 + dc.b 0x1C,0x3C,0x6C,0xCC,0xFE,0x0C,0x0C,0x00,0xFC,0xC0,0xFC,0x06,0x06,0xC6,0x7C,0x00 + dc.b 0x3C,0x60,0xC0,0xFC,0xC6,0xC6,0x7C,0x00,0xFE,0xC6,0x0C,0x18,0x30,0x30,0x30,0x00 + dc.b 0x78,0xC4,0xE4,0x78,0x86,0x86,0x7C,0x00,0x7C,0xC6,0xC6,0x7E,0x06,0x0C,0x78,0x00 + dc.b 0x00,0x00,0x18,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x18,0x18,0x30 + dc.b 0x1C,0x38,0x70,0xE0,0x70,0x38,0x1C,0x00,0x00,0x7C,0x00,0x00,0x7C,0x00,0x00,0x00 + dc.b 0x70,0x38,0x1C,0x0E,0x1C,0x38,0x70,0x00,0x7C,0xC6,0xC6,0x1C,0x18,0x00,0x18,0x00 + dc.b 0x3C,0x42,0x99,0xA1,0xA5,0x99,0x42,0x3C,0x38,0x6C,0xC6,0xC6,0xFE,0xC6,0xC6,0x00 + dc.b 0xFC,0xC6,0xC6,0xFC,0xC6,0xC6,0xFC,0x00,0x3C,0x66,0xC0,0xC0,0xC0,0x66,0x3C,0x00 + dc.b 0xF8,0xCC,0xC6,0xC6,0xC6,0xCC,0xF8,0x00,0xFE,0xC0,0xC0,0xFC,0xC0,0xC0,0xFE,0x00 + dc.b 0xFE,0xC0,0xC0,0xFC,0xC0,0xC0,0xC0,0x00,0x3E,0x60,0xC0,0xCE,0xC6,0x66,0x3E,0x00 + dc.b 0xC6,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0x00,0x7E,0x18,0x18,0x18,0x18,0x18,0x7E,0x00 + dc.b 0x06,0x06,0x06,0x06,0xC6,0xC6,0x7C,0x00,0xC6,0xCC,0xD8,0xF0,0xF8,0xDC,0xCE,0x00 + dc.b 0x60,0x60,0x60,0x60,0x60,0x60,0x7E,0x00,0xC6,0xEE,0xFE,0xFE,0xD6,0xC6,0xC6,0x00 + dc.b 0xC6,0xE6,0xF6,0xFE,0xDE,0xCE,0xC6,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00 + dc.b 0xFC,0xC6,0xC6,0xC6,0xFC,0xC0,0xC0,0x00,0x7C,0xC6,0xC6,0xC6,0xDE,0xCC,0x7A,0x00 + dc.b 0xFC,0xC6,0xC6,0xCE,0xF8,0xDC,0xCE,0x00,0x78,0xCC,0xC0,0x7C,0x06,0xC6,0x7C,0x00 + dc.b 0x7E,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00 + dc.b 0xC6,0xC6,0xC6,0xEE,0x7C,0x38,0x10,0x00,0xC6,0xC6,0xD6,0xFE,0xFE,0xEE,0xC6,0x00 + dc.b 0xC6,0xEE,0x3C,0x38,0x7C,0xEE,0xC6,0x00,0x66,0x66,0x66,0x3C,0x18,0x18,0x18,0x00 + dc.b 0xFE,0x0E,0x1C,0x38,0x70,0xE0,0xFE,0x00,0x3C,0x30,0x30,0x30,0x30,0x30,0x3C,0x00 + dc.b 0x60,0x60,0x30,0x18,0x0C,0x06,0x06,0x00,0x3C,0x0C,0x0C,0x0C,0x0C,0x0C,0x3C,0x00 + dc.b 0x18,0x3C,0x66,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF + dc.b 0x30,0x30,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x3C,0x06,0x3E,0x66,0x66,0x3C,0x00 + dc.b 0x60,0x7C,0x66,0x66,0x66,0x66,0x7C,0x00,0x00,0x3C,0x66,0x60,0x60,0x66,0x3C,0x00 + dc.b 0x06,0x3E,0x66,0x66,0x66,0x66,0x3E,0x00,0x00,0x3C,0x66,0x66,0x7E,0x60,0x3C,0x00 + dc.b 0x1C,0x30,0x78,0x30,0x30,0x30,0x30,0x00,0x00,0x3E,0x66,0x66,0x66,0x3E,0x06,0x3C + dc.b 0x60,0x7C,0x76,0x66,0x66,0x66,0x66,0x00,0x18,0x00,0x38,0x18,0x18,0x18,0x18,0x00 + dc.b 0x0C,0x00,0x1C,0x0C,0x0C,0x0C,0x0C,0x38,0x60,0x60,0x66,0x6C,0x78,0x6C,0x66,0x00 + dc.b 0x38,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0xEC,0xFE,0xFE,0xFE,0xD6,0xC6,0x00 + dc.b 0x00,0x7C,0x76,0x66,0x66,0x66,0x66,0x00,0x00,0x3C,0x66,0x66,0x66,0x66,0x3C,0x00 + dc.b 0x00,0x7C,0x66,0x66,0x66,0x7C,0x60,0x60,0x00,0x3E,0x66,0x66,0x66,0x3E,0x06,0x06 + dc.b 0x00,0x7E,0x70,0x60,0x60,0x60,0x60,0x00,0x00,0x3C,0x60,0x3C,0x06,0x66,0x3C,0x00 + dc.b 0x30,0x78,0x30,0x30,0x30,0x30,0x1C,0x00,0x00,0x66,0x66,0x66,0x66,0x6E,0x3E,0x00 + dc.b 0x00,0x66,0x66,0x66,0x66,0x3C,0x18,0x00,0x00,0xC6,0xD6,0xFE,0xFE,0x7C,0x6C,0x00 + dc.b 0x00,0x66,0x3C,0x18,0x3C,0x66,0x66,0x00,0x00,0x66,0x66,0x66,0x66,0x3E,0x06,0x3C + dc.b 0x00,0x7E,0x0C,0x18,0x30,0x60,0x7E,0x00,0x0E,0x18,0x0C,0x38,0x0C,0x18,0x0E,0x00 + dc.b 0x18,0x18,0x18,0x00,0x18,0x18,0x18,0x00,0x70,0x18,0x30,0x1C,0x30,0x18,0x70,0x00 + dc.b 0x00,0x00,0x76,0xDC,0x00,0x00,0x00,0x00,0x10,0x28,0x10,0x54,0xAA,0x44,0x00,0x00 + diff --git a/hexed/hexed.s b/hexed/hexed.s new file mode 100644 index 0000000..ae77a3e --- /dev/null +++ b/hexed/hexed.s @@ -0,0 +1,1660 @@ +############################################################################### +# +# Copyright (c) 2009,2011 Gražvydas Ignotas +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of the organization nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND ANY +# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Assemble with gas +# --register-prefix-optional --bitwise-or +# + +.equ USE_VINT, 0 +.equ COPY_TO_EXP, 1 +.equ RELOCATE_TO_RAM, 1 + +.text +.globl main +.globl INT +.globl VBL +.globl return_to_main + +################################################## +# # +# Register and bitmask definitions # +# # +################################################## + +.equ GFXDATA, 0xc00000 +.equ GFXCNTL, 0xc00004 + +.equ VDP0_E_HBI, 0x10 +.equ VDP0_E_DISPLAY, 0x02 +.equ VDP0_PLTT_FULL, 0x04 + +.equ VDP1_SMS_MODE, 0x80 +.equ VDP1_E_DISPLAY, 0x40 +.equ VDP1_E_VBI, 0x20 +.equ VDP1_E_DMA, 0x10 +.equ VDP1_NTSC, 0x00 +.equ VDP1_PAL, 0x08 +.equ VDP1_MODE5, 0x04 + +.equ VDP12_STE, 0x08 +.equ VDP12_SCREEN_V224, 0x00 +.equ VDP12_SCREEN_V448, 0x04 +.equ VDP12_PROGRESSIVE, 0x00 +.equ VDP12_INTERLACED, 0x02 +.equ VDP12_SCREEN_H256, 0x00 +.equ VDP12_SCREEN_H320, 0x81 + +.equ VDP16_MAP_V32, 0x00 +.equ VDP16_MAP_V64, 0x10 +.equ VDP16_MAP_V128, 0x30 +.equ VDP16_MAP_H32, 0x00 +.equ VDP16_MAP_H64, 0x01 +.equ VDP16_MAP_H128, 0x03 + +.equ MMODE_MAIN, 0 +.equ MMODE_VAL_INPUT, 1 +.equ MMODE_EDIT_VAL, 2 +.equ MMODE_GOTO, 3 +.equ MMODE_START_MENU, 4 +.equ MMODE_GOTO_PREDEF, 5 +.equ MMODE_JMP_ADDR, 6 +.equ MMODE_PC, 7 + +.equ predef_addr_cnt, ((predef_addrs_end-predef_addrs)/4) + +################################################## +# # +# MACROS # +# # +################################################## + + +# Write val to VDP register reg +.macro write_vdp_r_dst reg val dst + move.w #((\reg << 8) + 0x8000 + \val),\dst +.endm + +# Write val to VDP register reg, vdp addr in a3 +.macro write_vdp_reg reg val + write_vdp_r_dst \reg, \val, (a3) +.endm + +# Set up address in VDP, control port in dst +.macro VRAM_ADDR adr dst + move.l #(0x40000000 | ((\adr & 0x3fff) << 16) | (\adr >> 14)),\dst +.endm + +.macro VSRAM_ADDR adr dst + move.l #(0x40000010 | ((\adr & 0x3fff) << 16) | (\adr >> 14)),\dst +.endm + + +# make VDP word from address adr and store in d0 +.macro XRAM_ADDR_var adr + move.l \adr,d0 + lsl.l #8,d0 + lsl.l #8,d0 + rol.l #2,d0 + lsl.b #2,d0 + lsr.l #2,d0 +.endm + + +.macro VRAM_ADDR_var adr + XRAM_ADDR_var \adr + or.l #0x40000000,d0 +.endm + + +.macro CRAM_ADDR_var adr + XRAM_ADDR_var \adr + or.l #0xc0000000,d0 +.endm + + +# convert tile coords in d0, d1 to nametable addr to a0 +.macro XY2NT + lsl.w #6,d1 + add.w d1,d0 + lsl.w #1,d0 + movea.l #0xe000,a0 + add.w d0,a0 +.endm + +# check if some d-pad button (and modifier) is pressed +.macro do_dpad bit op val + btst.l #\bit,d0 + beq 0f + \op \val,a6 + bra dpad_end +0: +.endm + +# convert a6 to normal addr +# destroys d0 +.macro mk_a6_addr reg + move.l a6,\reg + moveq.l #0,d0 + move.b \reg,d0 + lsr.l #8,\reg + add.l d0,\reg +.endm + +.macro change_mode mode_new mode_back + and.w #0xc0ff,d7 + or.w #(\mode_back<<11)|(\mode_new<<8),d7 +.endm + +# destroys a0,d0-d2 +.macro menu_text str x y pal + lea (\str,pc),a0 + move.l #\x,d0 + move.l #\y,d1 + move.l #0x8000|(\pal<<13),d2 + jsr print +.endm + +################################################# +# # +# DATA # +# # +################################################# + +colors: + dc.w 0x0000,0x0eee,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 + dc.w 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 + dc.w 0x0000,0x02e2,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 + dc.w 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 + dc.w 0x0000,0x0e44,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 + dc.w 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 + dc.w 0x0000,0x044e,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 + dc.w 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 +colors_end: + + +sprite_data: + /* Y size link attr X */ + dc.w 0; dc.b 0x05; dc.b 0; dc.w 0x6002; dc.w 0 +sprite_data_end: + +predef_addrs: + dc.l 0x000000, 0x200000, 0x400000, 0xa00000, 0xa10000 + dc.l 0xa11100, 0xa12000, 0xa13000, 0xa14000, 0xa15100 + dc.l 0xc00000 +predef_addrs_end: + +safe_addrs: + dc.l 0x000000, 0x7fffff + dc.l 0xe00000, 0xffffff + dc.l 0xa00000, 0xa100ff + dc.l 0xa11000, 0xa113ff + dc.l 0xa12000, 0xa120ff + dc.l 0xa13000, 0xa130ff +safe_addrs_end: + dc.l 0xa15100, 0xa1513f +safe_addrs_end_32x: + dc.l 0xa15180, 0xa153ff +safe_addrs_end_32x_vdp: + +sizeof_bin: + dc.l _edata + +txt_edit: + .ascii "- edit -\0" +txt_a_confirm: + .ascii "A-confirm\0" +txt_about: + .ascii "hexed r2\0" +txt_goto: + .ascii "Go to address\0" +txt_goto_predef: + .ascii "Go to (predef)\0" +txt_jmp_addr: + .ascii "Jump to address\0" +txt_dump: + .ascii "PC Transfer\0" +txt_dtack: + .ascii "DTACK safety\0" +txt_transfer_ready: + .ascii "Transfer Ready\0" +txt_working: + .ascii "PC mode \0" +txt_dtack_err: + .ascii "DTACK err?\0" +txt_exc: + .ascii "Exception \0" + +################################################## +# # +# MAIN PROGRAM # +# # +################################################## + +# global regs: +# a6 = page_start[31:8]|cursor_offs[7:0] +# d7 = old_inputs[31:16]|edit_bytes[15:14]|g_mode_old[13:11]|g_mode[10:8]|irq_cnt[7:0] +# d6 = edit_word_save[31:15]|edit_done[7]|no_dtack_detect[4]|autorep_cnt[3:0] +# d5 = main: tmp +# edit: edit_word[31:8]|edit_pos[4:2]|byte_cnt[1:0] +# menu: sel + +.align 2 + +main: + /* make sure io port 2 is doing inputs */ + move.b #0,(0xa1000b).l + /* make sure irqs are masked */ + move.w #0x2700,sr + /* take care of TMSS */ + move.b (0xa10000).l,d0 + andi.b #0x0f,d0 + beq no_tmss + move.l #0x53454741,(0xa14000).l + /* want cart, not OS rom if cart pops in */ + move.w #1,(0xa14100).l + /* touch VDP after TMSS setup? */ + tst.w (0xc00004).l +no_tmss: + + /* want to do early PC transfer (with RAM/VRAM intact and such)? + * also give time PC to see start condition */ + move.l #0x2000,d0 +0: dbra d0,0b + + move.l #0xa10005,a0 + btst.b #5,(a0) + bne no_early_transfer +move.b #1,(0) + move.b #0x40,(0xa1000b).l /* port 2 ctrl */ + move.b #0x00,(a0) /* port 2 data - start with TH low */ + move.l #0x2000,d0 +0: + btst.b #4,(a0) + beq do_early_transfer + dbra d0,0b + +move.b #2,(0) + move.b #0,(0xa1000b).l + bra no_early_transfer /* timeout */ + +do_early_transfer: +move.b #9,(0) + bsr do_transfer + +no_early_transfer: + +.if COPY_TO_EXP + /* copy to expansion device if magic number is set */ + move.l #0x400000,a1 + cmp.w #0x1234,(a1) + bne 0f + + move.l #0,a0 + move.l (sizeof_bin,pc),d0 + lsr.l #3,d0 +1: + move.l (a0)+,(a1)+ + move.l (a0)+,(a1)+ + dbra d0,1b +0: +.endif + +.if RELOCATE_TO_RAM + /* we could be relocated by 32x or something else, adjust start addr */ + lea (pc),a0 + move.l a0,d0 + and.l #0xff0000,d0 + move.l d0,a0 + + /* copy, assume 8K size */ + move.l #0xFF0100,a1 + move.l (sizeof_bin,pc),d0 + lsr.l #3,d0 +1: + move.l (a0)+,(a1)+ + move.l (a0)+,(a1)+ + dbra d0,1b + + /* copy test code */ + lea (test_code,pc),a0 + move.l #0xffc000,a1 + move.w #(test_code_end - test_code)/2-1,d0 +1: + move.w (a0)+,(a1)+ + dbra d0,1b + + lea (0f,pc),a0 + move.l a0,d0 + and.l #0x00ffff,d0 + add.l #0xFF0100,d0 + move.l d0,a0 + + /* patch test code */ + move.l #0xffc000,a1 + add.w #(test_code_ret_op-test_code+2),a1 + move.l a0,(a1) + + jmp (a0) +0: +.endif + + movea.l #0,a6 + move.l #0x8000,d7 + moveq.l #0,d6 + + /* Init pads */ + move.b #0x40,(0xa10009).l + move.b #0x40,(0xa10003).l + + /* Initialize VDP */ + jsr init_gfx + + /* Clear h/v scroll */ + movea.l #GFXDATA,a0 + VRAM_ADDR 0x8000,(GFXCNTL) + move.l #0,(a0) + VSRAM_ADDR 0,(GFXCNTL) + move.l #0,(a0) + + /* Load color data */ + movea.l #0,a0 + lea (colors,pc),a1 + moveq.l #(colors_end-colors)/2,d0 + jsr load_colors + + /* load font patterns */ + movea.l #GFXDATA,a0 + lea (font,pc),a1 + VRAM_ADDR 0,(GFXCNTL) + move.w #128*8,d3 +font_loop: + moveq.l #8-1,d2 + moveq.l #0,d1 + move.b (a1)+,d0 +0: + lsr.b #1,d0 + roxl.l #1,d1 + ror.l #5,d1 + dbra d2,0b + + rol.l #1,d1 /* fixup */ + move.l d1,(a0) + dbra d3,font_loop + + /* generate A layer map */ + movea.l #0xe000,a1 + move.l #28-1,d4 +lmaploop0: + movea.l a1,a0 + jsr load_prepare + + move.l #64/2-1,d3 +0: move.l #0x00000000,(a0) + dbra d3,0b + + add.l #64*2,a1 + dbra d4,lmaploop0 + + /* generate B layer map */ + movea.l #0xc000,a0 + jsr load_prepare + + move.l #64*28/2-1,d3 +0: move.l #0x00000000,(a0) + dbra d3,0b + + /* upload sprite data */ + movea.l #0xfc00,a0 + jsr load_prepare + lea (sprite_data,pc),a1 + + move.l #(sprite_data_end-sprite_data)/2-1,d3 +0: move.l (a1)+,(a0) + dbra d3,0b + +.if USE_VINT + /* wait for vsync before unmask */ + jsr wait_vsync_poll + + /* wait a bit to avoid nested vint */ + move.w #20,d0 +0: + dbra d0,0b /* 10 cycles to go back */ + + /* enable and unmask vint */ + write_vdp_r_dst 1,(VDP1_E_VBI | VDP1_E_DISPLAY | VDP1_MODE5),(GFXCNTL) + move.w #0x2000,sr +.endif + +################################################## + +forever: +.if USE_VINT + jsr wait_vsync +.else + jsr wait_vsync_poll + jsr VBL +.endif + bra forever + + +INT: + /* let's hope VRAM is already set up.. */ + lea (txt_exc,pc),a0 + move.l #9,d0 + move.l #27,d1 + move.l #0xe000,d2 + jsr print + bra forever + +################################################## + +VBL: + addq.b #1,d7 +# movem.l d0-d4/a0-a5,-(a7) + + btst.b #5,(0xa10005).l + bne no_auto_transfer + change_mode MMODE_PC, MMODE_MAIN + write_vdp_r_dst 12,(VDP12_SCREEN_V224 | VDP12_SCREEN_H320 | VDP12_STE),(GFXCNTL) + +no_auto_transfer: + moveq.l #0,d0 + move.w d7,d0 + lsr.w #6,d0 + and.w #0x1c,d0 + lea (jumptab,pc,d0),a0 + jmp (a0) +jumptab: + /* branch insns here because we want to be position independent */ + bra mode_main + bra mode_val_input + bra mode_edit_val /* edit val in editor */ + bra mode_goto + bra mode_start_menu + bra mode_goto_predef + bra mode_jmp_addr + bra mode_transfer + +##################### main ####################### + +mode_main: + /* assume we will hang */ + lea (txt_dtack_err,pc),a0 + move.l #9,d0 + move.l #27,d1 + move.l #0xe000,d2 + jsr print + + moveq.l #0,d1 + move.l a6,d0 + move.b d0,d1 + lsr.l #8,d0 + move.l d0,a1 /* current addr */ + lsr.b #3,d1 + neg.b d1 + add.b #27-1,d1 /* line where the cursor sits */ + swap d1 + + movea.l #0xe002,a2 + move.l #27-1,d5 /* line counter for dbra */ + or.l d1,d5 + +draw_row: + move.l a2,a0 + jsr load_prepare + + btst.l #15,d7 + beq 0f + move.w #' ',(a0) +0: + /* addr */ + move.l a1,d2 + moveq.l #6,d3 + jsr print_hex_preped + + btst.l #4,d6 + bne draw_row_safe + + bsr get_safety_mask + cmp.b #0xf,d0 + beq draw_row_safe + +# unsafe or partially safe +draw_row_hsafe: + move.l d0,d4 + swap d4 /* mask in upper word */ + btst.l #15,d7 + bne draw_row_hsafe_words_pre + +draw_row_hsafe_bytes_pre: + /* 8 bytes */ + moveq.l #2,d3 + move.w #3,d4 + +draw_row_hsafe_bytes: + move.w #' ',(a0) + move.b d4,d0 + add.b #16,d0 + btst.l d0,d4 + bne 0f + move.l #'?'|('?'<<16),(a0) + move.w #' ',(a0) + move.l #'?'|('?'<<16),(a0) + bra 1f +0: + move.b (0,a1),d2 + jsr print_hex_preped + move.w #' ',(a0) + move.b (1,a1),d2 + jsr print_hex_preped +1: + addq.l #2,a1 + dbra d4,draw_row_hsafe_bytes + + move.w #' ',(a0) + + move.l d5,d0 + swap d0 + cmp.w d5,d0 + beq draw_cursor_unsafe_byte + bra draw_chars_hsafe_pre + +draw_row_hsafe_words_pre: + /* 4 shorts */ + moveq.l #4,d3 + move.w #3,d4 + +draw_row_hsafe_words: + move.w #' ',(a0) + move.b d4,d0 + add.b #16,d0 + btst.l d0,d4 + bne 0f + move.l #'?'|('?'<<16),(a0) + move.l #'?'|('?'<<16),(a0) + bra 1f +0: + move.w (a1),d2 + jsr print_hex_preped +1: + addq.l #2,a1 + dbra d4,draw_row_hsafe_words + + move.l #(' '<<16)|' ',(a0) + + move.l d5,d0 + swap d0 + cmp.w d5,d0 + beq draw_cursor_unsafe_word + +draw_chars_hsafe_pre: + subq.l #8,a1 + move.w #3,d4 + moveq.l #0,d0 + +draw_chars_hsafe: + move.b d4,d0 + add.b #16,d0 + btst.l d0,d4 + bne 0f + move.l #'?'|('?'<<16),(a0) + bra draw_chars_hsafe_next +0: + btst.l #15,d7 /* must perform correct read type */ + bne 0f /* doing byte reads on security reg hangs */ + move.b (0,a1),d0 + lsl.l #8,d0 + move.b (1,a1),d0 + bra 1f +0: + move.w (a1),d0 +1: + ror.l #8,d0 + move.b d0,d1 + sub.b #0x20,d1 + cmp.b #0x60,d1 + blo 0f + move.b #'.',d0 +0: + move.w d0,(a0) + + move.b #0,d0 + rol.l #8,d0 + move.b d0,d1 + sub.b #0x20,d1 + cmp.b #0x60,d1 + blo 0f + move.b #'.',d0 +0: + move.w d0,(a0) + +draw_chars_hsafe_next: + addq.l #2,a1 + dbra d4,draw_chars_hsafe + + move.l #(' '<<16)|' ',(a0) + add.w #0x80,a2 + dbra d5,draw_row + bra draw_status_bar + + +# normal draw +draw_row_safe: + btst.l #15,d7 + bne draw_row_words + +draw_row_bytes: + /* 8 bytes */ + moveq.l #2,d3 + moveq.l #8-1,d4 +draw_bytes: + move.w #' ',(a0) + move.b (a1)+,d2 + jsr print_hex_preped + dbra d4,draw_bytes + + move.w #' ',(a0) + + move.l d5,d0 + swap d0 + cmp.w d5,d0 + beq draw_cursor_byte + bra draw_chars_pre + +draw_row_words: + /* 4 shorts */ + moveq.l #4,d3 + moveq.l #4-1,d4 +draw_words: + move.w #' ',(a0) + move.w (a1)+,d2 + jsr print_hex_preped + dbra d4,draw_words + + move.l #(' '<<16)|' ',(a0) + + move.l d5,d0 + swap d0 + cmp.w d5,d0 + beq draw_cursor_word + +draw_chars_pre: + /* 8 chars */ + subq.l #8,a1 + moveq.l #8-1,d4 +draw_chars: + move.b (a1)+,d0 + move.b d0,d1 + sub.b #0x20,d1 + cmp.b #0x60,d1 + blo 0f + move.w #'.',d0 +0: + move.w d0,(a0) + dbra d4,draw_chars + + move.l #(' '<<16)|' ',(a0) + + add.w #0x80,a2 + dbra d5,draw_row + + +draw_status_bar: + /* status bar */ + move.l a2,a0 + jsr load_prepare + + btst.l #15,d7 + beq 0f + move.w #' ',(a0) +0: + mk_a6_addr d2 + move.l #0x4006,d3 + jsr print_hex_preped + + /* clear error */ + moveq.l #5-1,d0 +0: + move.l #' '|(' '<<16),(a0) + move.l #' '|(' '<<16),(a0) + dbra d0,0b + + + /* handle input */ + jsr get_input /* x0cbrldu x1sa00du */ + + btst.l #16+4,d0 /* A - scroll modifier */ + beq input_noa + + do_dpad 16+0, sub.l, #0x0800 + do_dpad 16+1, add.l, #0x0800 + do_dpad 16+10, sub.l, #0xd800 + do_dpad 16+11, add.l, #0xd800 +input_noa: + moveq.l #0,d1 + move.w d7,d1 + lsr.w #7,d1 + lsr.w #7,d1 + + do_dpad 0, subq.l, #0x0008 + do_dpad 1, addq.l, #0x0008 + do_dpad 10, sub.l, d1 + do_dpad 11, add.l, d1 + +dpad_end: + /* update addr */ + move.l a6,d1 + cmp.b #0xf0,d1 + blo 0f + sub.l #0xd800,a6 + add.w #0x00d8,a6 + bra 1f +0: + cmp.b #0xd8,d1 + blo 1f + add.l #0xd800,a6 + sub.w #0x00d8,a6 +1: + + /* other btns */ + moveq.l #0,d1 + btst.l #12,d0 /* B - switch byte/word mode */ + beq input_nob + bclr.l #15,d7 + add.w #0x4000,d7 /* changes between 01 10 */ + move.l a6,d1 + and.l #1,d1 + sub.l d1,a6 /* make even, just in case */ + +input_nob: + btst.l #13,d0 /* C - edit selected byte */ + beq input_noc + + change_mode MMODE_EDIT_VAL, MMODE_MAIN + write_vdp_r_dst 12,(VDP12_SCREEN_V224 | VDP12_SCREEN_H320 | VDP12_STE),(GFXCNTL) + +input_noc: + btst.l #5,d0 /* Start - menu */ + beq input_nos + + moveq.l #0,d5 + change_mode MMODE_START_MENU, MMODE_MAIN + write_vdp_r_dst 12,(VDP12_SCREEN_V224 | VDP12_SCREEN_H320 | VDP12_STE),(GFXCNTL) + +input_nos: +vbl_end: +# movem.l (a7)+,d0-d4/a0-a5 +.if USE_VINT + rte +.else + rts +.endif + + +draw_cursor_unsafe_byte: + move.l a6,d0 + and.l #7,d0 /* byte offs */ + move.b d0,d1 + add.b d0,d0 + add.b d1,d0 /* d0 *= 3 (chars) */ + add.b d0,d0 + lea (7*2,a2,d0),a0 + jsr load_prepare + move.l #(0x2000|'?'|((0x2000|'?')<<16)),(a0) + + move.l a2,a0 + add.w #31*2,a0 + jsr load_prepare /* restore a0 */ + bra draw_chars_hsafe_pre + +draw_cursor_unsafe_word: + move.l a6,d0 + and.l #7,d0 /* byte offs */ + move.l d0,d1 + lsr.b #1,d1 /* which word */ + move.b d1,d2 + lsl.b #2,d2 + add.b d2,d1 /* num of chars to skip */ + add.b d1,d1 + + lea (8*2,a2,d1),a0 + jsr load_prepare + move.l #(0x2000|'?'|((0x2000|'?')<<16)),d0 + move.l d0,(a0) + move.l d0,(a0) + + move.l a2,a0 + add.w #29*2,a0 + jsr load_prepare /* restore a0 */ + bra draw_chars_hsafe_pre + + +draw_cursor_byte: + move.l a6,d0 + and.l #7,d0 /* byte offs */ + move.w #0x2002,d3 + + move.b (-8,a1,d0),d2 + move.b d0,d1 + add.b d0,d0 + add.b d1,d0 /* d0 *= 3 (chars) */ + add.b d0,d0 + lea (7*2,a2,d0),a0 + jsr load_prepare + jsr print_hex_preped + + move.l a2,a0 + add.w #31*2,a0 + jsr load_prepare /* restore a0 */ + + bra draw_chars_pre + +draw_cursor_word: + move.l a6,d0 + and.l #7,d0 /* byte offs */ + move.l d0,d1 + lsr.b #1,d1 /* which word */ + move.b d1,d2 + lsl.b #2,d2 + add.b d2,d1 /* num of chars to skip */ + add.b d1,d1 + move.w #0x2004,d3 + + move.w (-8,a1,d0),d2 + lea (8*2,a2,d1),a0 + jsr load_prepare + jsr print_hex_preped + + move.l a2,a0 + add.w #29*2,a0 + jsr load_prepare /* restore a0 */ + + bra draw_chars_pre + + +#################### hedit ####################### + +mode_edit_val: + btst.l #7,d6 + bne mode_hedit_finish + + /* read val to edit */ + moveq.l #0,d5 + mk_a6_addr d1 + move.l d1,a0 + btst.l #15,d7 + bne 0f + move.b (a0),d5 + lsl.l #8,d5 + or.b #1,d5 + bra 1f +0: + move.w (a0),d5 + lsl.l #8,d5 + or.b #2,d5 +1: + + change_mode MMODE_VAL_INPUT, MMODE_EDIT_VAL + bra vbl_end + +mode_hedit_finish: + /* write the val */ + mk_a6_addr d1 + move.l d1,a0 + lsr.l #8,d5 + + btst.l #15,d7 + bne 0f + move.b d5,(a0) + bra 1f +0: + move.w d5,(a0) +1: + + bra return_to_main + +##################### goto ####################### + +mode_goto: + btst.l #7,d6 + bne mode_goto_finish + + moveq.l #0,d5 + swap d6 + move.w d6,d5 + swap d6 + swap d5 + or.b #3,d5 /* 3 bytes */ + bclr.l #7,d6 + change_mode MMODE_VAL_INPUT, MMODE_GOTO + bra vbl_end + +mode_goto_finish: + lsr.l #8,d5 + move.l d5,d0 + move.l d0,d1 + and.l #7,d1 + and.b #0xf8,d0 + lsl.l #8,d0 + or.l d1,d0 + move.l d0,a6 + + lsr.l #8,d5 + swap d6 + move.w d5,d6 + swap d6 + + bra return_to_main + +################### val edit ##################### + +mode_val_input: + /* frame */ + movea.l #0xe000+14*2+11*64*2,a1 + moveq.l #6-1,d1 +0: + move.w a1,a0 + jsr load_prepare + moveq.l #11-1,d0 +1: + move.w #0,(a0) + dbra d0,1b + + add.w #64*2,a1 + dbra d1,0b + + /* text */ + lea (txt_edit,pc),a0 + move.l #15,d0 + move.l #11,d1 + move.l #0xc000,d2 + jsr print + + lea (txt_a_confirm,pc),a0 + move.l #15,d0 + move.l #15,d1 + move.l #0xc000,d2 + jsr print + + /* edit field */ + moveq.l #0,d0 + moveq.l #0,d1 + moveq.l #0,d3 + move.b d5,d3 + and.b #3,d3 /* edit field bytes */ + + move.b #19,d0 + sub.b d3,d0 + move.b #13,d1 + move.l d5,d2 + lsr.l #8,d2 + add.b d3,d3 + or.w #0x8000,d3 + jsr print_hex + + /* current char */ + moveq.l #0,d0 + moveq.l #0,d1 + + and.w #6,d3 + move.b #19,d0 + move.b d3,d1 + lsr.b #1,d1 /* length in bytes */ + sub.b d1,d0 + move.b d5,d1 + lsr.b #2,d1 + and.b #7,d1 /* nibble to edit */ + add.b d1,d0 + + sub.b d1,d3 + sub.b #1,d3 /* chars to shift out */ + lsl.b #2,d3 + add.b #8,d3 + move.l d5,d2 + lsr.l d3,d2 + + move.b #13,d1 + move.w #0xa001,d3 + jsr print_hex + + /* handle input */ + jsr get_input /* x0cbrldu x1sa00du */ + + move.w d0,d1 + and.w #0x0f00,d1 + beq ai_no_dpad + move.b d5,d1 + and.b #3,d1 + add.b d1,d1 /* nibble count */ + sub.b #1,d1 /* max n.t.e. val */ + move.b d5,d2 + lsr.b #2,d2 + and.b #7,d2 /* nibble to edit */ + + move.b d0,d3 + and.b #3,d3 + beq ai_no_ud + moveq.l #0,d3 + moveq.l #0,d4 + move.b #0xf,d3 + move.b #0x1,d4 + sub.b d2,d1 + lsl.b #2,d1 + add.b #8,d1 + lsl.l d1,d3 /* mask */ + lsl.l d1,d4 /* what to add/sub */ + move.l d5,d1 + and.l d3,d1 + btst.l #8,d0 + beq 0f + add.l d4,d1 + bra 1f +0: + sub.l d4,d1 +1: + and.l d3,d1 + eor.l #0xffffffff,d3 + and.l d3,d5 + or.l d1,d5 + bra vbl_end + +ai_no_ud: + btst.l #10,d0 + bne 0f + add.b #1,d2 + bra 1f +0: + sub.b #1,d2 +1: + cmp.b #0,d2 + bge 0f + move.b d1,d2 +0: + cmp.b d1,d2 + ble 0f + move.b #0,d2 +0: + and.b #0xe3,d5 + lsl.b #2,d2 + or.b d2,d5 + bra vbl_end + +ai_no_dpad: + move.w d0,d1 + and.w #0x1020,d1 + beq ai_no_sb + + bra return_to_main + +ai_no_sb: + btst.l #4,d0 /* A - confirm */ + beq ai_no_input + bset.l #7,d6 + move.w d7,d1 /* back to prev mode */ + and.w #0x3800,d1 + lsr.w #3,d1 + and.w #0xc0ff,d7 + or.w d1,d7 + +ai_no_input: + bra vbl_end + + +################### start menu ################### + +mode_start_menu: + /* frame */ + bsr start_menu_box + + /* text */ + menu_text txt_about, 13, 9, 1 + menu_text txt_goto, 13, 11, 0 + menu_text txt_goto_predef, 13, 12, 0 + menu_text txt_jmp_addr, 13, 13, 0 + menu_text txt_dump, 13, 14, 0 + menu_text txt_dtack, 13, 15, 0 + menu_text txt_a_confirm, 13, 17, 2 + + /* dtack safety on/off */ + movea.l #0xe000+26*2+15*64*2,a0 + jsr load_prepare + move.w #0x8000|'O',(a0) + btst.l #4,d6 + bne 0f + move.w #0x8000|'N',(a0) + bra 1f +0: + move.w #0x8000|'F',(a0) + move.w #0x8000|'F',(a0) +1: + + /* cursor */ + movea.l #0xe000+11*2+11*64*2,a0 + moveq.l #0,d0 + move.b d5,d0 + and.b #7,d0 + lsl.w #7,d0 + add.w d0,a0 + jsr load_prepare + move.w #'>',(a0) + + /* input */ + jsr get_input /* x0cbrldu x1sa00du */ + + move.w d0,d1 + and.w #3,d1 + beq msm_no_ud + move.b d5,d1 + and.b #7,d1 + btst.l #0,d0 + sne d2 + or.b #1,d2 /* up -1, down 1 */ + add.b d2,d1 + cmp.b #0,d1 + bge 0f + move.b #4,d1 +0: + cmp.b #4,d1 + ble 0f + move.b #0,d1 +0: + and.b #0xf8,d5 + or.b d1,d5 + bra vbl_end + +msm_no_ud: + btst.l #4,d0 /* A - confirm */ + beq msm_no_a + move.b d5,d1 + and.b #7,d1 + bne 0f + change_mode MMODE_GOTO, MMODE_MAIN + bsr start_menu_box + bra vbl_end +0: + cmp.b #1,d1 + bne 0f + moveq.l #0,d5 + change_mode MMODE_GOTO_PREDEF, MMODE_MAIN + bsr start_menu_box + bra vbl_end +0: + cmp.b #2,d1 + bne 0f + change_mode MMODE_JMP_ADDR, MMODE_MAIN + bsr start_menu_box + bra vbl_end +0: + cmp.b #3,d1 + bne 0f + change_mode MMODE_PC, MMODE_MAIN + bsr start_menu_box + bra vbl_end +0: + cmp.b #4,d1 + bne 0f + bchg.l #4,d6 + bra vbl_end +0: + +msm_no_a: + move.w d0,d1 + and.w #0x3000,d1 + beq msm_no_bc + bra return_to_main + +msm_no_bc: + bra vbl_end + +start_menu_box: + movea.l #0xe000+10*2+8*64*2,a1 + move.w #11-1,d1 +0: + move.w a1,a0 + jsr load_prepare + move.w #20-1,d0 +1: + move.w #0,(a0) + dbra d0,1b + + add.w #64*2,a1 + dbra d1,0b + rts + +################### goto predef ################## + +mode_goto_predef: + /* frame */ + movea.l #0xe000+14*2+8*64*2,a1 + move.l #predef_addr_cnt+2-1,d1 +0: + move.w a1,a0 + jsr load_prepare + moveq.l #10-1,d0 +1: + move.w #0,(a0) + dbra d0,1b + + add.w #64*2,a1 + dbra d1,0b + + /* draw addresses */ + movea.l #0xe000+17*2+9*64*2,a1 + lea (predef_addrs,pc),a2 + move.w #predef_addr_cnt-1,d4 + move.l #0x8006,d3 +mgp_da_loop: + move.w a1,a0 + jsr load_prepare + move.l (a2)+,d2 + jsr print_hex_preped + add.w #64*2,a1 + dbra d4,mgp_da_loop + + /* cursor */ + movea.l #0xe000+15*2+9*64*2,a0 + moveq.l #0,d0 + move.b d5,d0 + lsl.w #7,d0 + add.w d0,a0 + jsr load_prepare + move.w #'>',(a0) + + /* input */ + jsr get_input /* x0cbrldu x1sa00du */ + + move.w d0,d1 + and.w #3,d1 + beq mgp_no_ud + btst.l #0,d0 + sne d2 + or.b #1,d2 /* up -1, down 1 */ + add.b d2,d5 + cmp.b #0,d5 + bge 0f + move.b #predef_addr_cnt-1,d5 +0: + cmp.b #predef_addr_cnt-1,d5 + ble 0f + move.b #0,d5 +0: + bra vbl_end + +mgp_no_ud: + btst.l #4,d0 /* A - confirm */ + beq mgp_no_a + moveq.l #0,d0 + move.b d5,d0 + lsl.w #2,d0 + lea (predef_addrs,pc),a0 + move.l (a0,d0),d5 + lsl.l #8,d5 + bra mode_goto_finish + +mgp_no_a: + move.w d0,d1 + and.w #0x3000,d1 + beq mgp_no_bc + bra return_to_main + +mgp_no_bc: + bra vbl_end + +##################### jmp ######################## + +mode_jmp_addr: + btst.l #7,d6 + bne mode_jmp_finish + + moveq.l #0,d5 + or.b #3,d5 /* 3 bytes */ + bclr.l #7,d6 + change_mode MMODE_VAL_INPUT, MMODE_JMP_ADDR + bra vbl_end + +mode_jmp_finish: + lsr.l #8,d5 + write_vdp_r_dst 1,(VDP1_E_DISPLAY | VDP1_MODE5),(GFXCNTL) /* disable vint */ + move.l d5,a0 + jmp (a0) + +mode_transfer: + move.b #0x40,(0xa1000b).l /* port 2 ctrl */ + move.b #0x00,(0xa10005).l /* port 2 data - start with TH low */ + + lea (txt_transfer_ready,pc),a0 + move.l #13,d0 + move.l #13,d1 + move.l #0x8000,d2 + jsr print + +wait_tl_low0: + move.b (0xa10005),d0 + btst.b #4,d0 + bne wait_tl_low0 + + menu_text txt_working, 13, 13, 0 + bsr do_transfer + bra return_to_main + +# go back to main mode +return_to_main: + bclr.l #7,d6 /* not edited */ + change_mode MMODE_MAIN, MMODE_MAIN + write_vdp_r_dst 12,(VDP12_SCREEN_V224 | VDP12_SCREEN_H320),(GFXCNTL) + bra vbl_end + + +################################################# +# # +# Initialize VDP registers # +# # +################################################# + +init_gfx: + move.l #GFXCNTL,a3 + write_vdp_reg 0,(VDP0_E_DISPLAY | VDP0_PLTT_FULL) + write_vdp_reg 1,(VDP1_E_DISPLAY | VDP1_MODE5) + write_vdp_reg 2,(0xe000 >> 10) /* Screen map a adress */ + write_vdp_reg 3,(0xe000 >> 10) /* Window address */ + write_vdp_reg 4,(0xc000 >> 13) /* Screen map b address */ + write_vdp_reg 5,(0xfc00 >> 9) /* Sprite address */ + write_vdp_reg 6,0 + write_vdp_reg 7,0 /* Backdrop color */ + write_vdp_reg 0x0a,1 /* Lines per hblank interrupt */ + write_vdp_reg 0x0b,0 /* 2-cell vertical scrolling */ + write_vdp_reg 0x0c,(VDP12_SCREEN_V224 | VDP12_SCREEN_H320) + write_vdp_reg 0x0d,(0x8000 >> 10) /* Horizontal scroll address */ + write_vdp_reg 0x0e,0 + write_vdp_reg 0x0f,2 + write_vdp_reg 0x10,(VDP16_MAP_V32 | VDP16_MAP_H64) /* layer size */ + write_vdp_reg 0x11,0 + write_vdp_reg 0x12,0 + rts + + +# get mask of bits representing safe words +# a1 - address to check +# destroys d0-d2, strips upper bits from a1 +get_safety_mask: + move.l a1,d1 + lsl.l #8,d1 + lsr.l #8,d1 + lea (safe_addrs,pc),a1 + move.w #(safe_addrs_end - safe_addrs)/8-1,d2 + cmp.l #0x4D415253,(0xa130ec) /* 'MARS' */ + bne no_32x + move.w #(safe_addrs_end_32x - safe_addrs)/8-1,d2 + move.w (0xa15100),d0 + and.w #3,d0 + cmp.w #3,d0 /* ADEN and nRES */ + bne no_32x_vdp + btst.b #7,d0 /* FM */ + bne no_32x_vdp + move.w #(safe_addrs_end_32x_vdp - safe_addrs)/8-1,d2 +no_32x_vdp: +no_32x: + +0: + move.l (a1)+,d0 + cmp.l d0,d1 + blt 1f + move.l (a1),d0 + cmp.l d0,d1 + ble addr_safe +1: + addq.l #4,a1 + dbra d2,0b + + move.l d1,a1 + + moveq.l #0x0c,d0 + cmp.l #0xa14000,d1 + beq gsm_rts + + moveq.l #0x08,d0 + cmp.l #0xa14100,d1 + beq gsm_rts + + /* check for VDP address */ + move.l d1,d0 + swap d0 + and.b #0xe0,d0 + cmp.b #0xc0,d0 + bne addr_unsafe /* not vdp */ + + move.l d1,d0 + and.l #0x0700e0,d0 + bne addr_unsafe + + move.l d1,d0 + and.b #0x1f,d0 + cmp.b #0x04,d0 + blt addr_hsafe_3 /* data port */ + cmp.b #0x10,d0 + blt addr_safe /* below PSG */ + cmp.b #0x18,d0 + bge addr_safe /* above PSG */ + +addr_unsafe: + moveq.l #0,d0 /* skip line */ + rts + +addr_hsafe_3: + moveq.l #3,d0 /* skip 2 words */ + rts + +addr_safe: + move.l d1,a1 + moveq.l #0xf,d0 +gsm_rts: + rts + + +# read single phase from controller +# #a0 - addr +# d0 - result +# destroys d1,d2 +get_input: + move.b #0x40,(0xa10003) + nop + nop + nop + move.b (0xa10003),d0 + move.b #0x00,(0xa10003) + lsl.w #8,d0 + nop + move.b (0xa10003),d0 + eor.w #0xffff,d0 + + swap d7 + move.w d7,d1 + eor.w d0,d1 /* changed btns */ + move.w d0,d7 /* old val */ + swap d7 + and.w d0,d1 /* what changed now */ + bne 0f + + addq.b #1,d6 + move.b d6,d2 + and.b #0x0f,d2 /* do autorepeat */ + cmp.b #9,d2 + bne 1f + move.w d0,d1 +0: + and.b #0xf0,d6 +1: + swap d0 + move.w d1,d0 + rts + +# Prepare to write to VDP RAM @a0 +# sets a0 to VDP data port for convenience +# a0: VRAM base +# destroys d0 + +load_prepare: + VRAM_ADDR_var a0 + move.l d0,(GFXCNTL).l + move.l #GFXDATA,a0 + rts + + +# Load color data from ROM +# a0: CRAM base +# a1: color list address +# d0: number of colors to load +# destroys d1 + +load_colors: + move.l d0,d1 + CRAM_ADDR_var a0 + move.l d0,(GFXCNTL).l + + move.l #GFXDATA,a0 + subq.w #1,d1 +0: + move.w (a1)+,(a0) + dbra d1,0b + + rts + + +# print +# a0 - string +# d0 - x +# d1 - y +# d2 - tile_bits[15:11] +# destroys a1 + +print: + move.l a0,a1 + XY2NT + jsr load_prepare + move.l d2,d0 + and.w #0xf800,d0 + +_print_loop: + move.b (a1)+,d0 + beq _print_end + + move.w d0,(a0) + bra _print_loop + +_print_end: + rts + + +# print_hex +# d0 - x +# d1 - y +# d2 - value +# d3 - tile_bits[15:11]|digit_cnt[7:0] +# destroys a0, preserves d3 + +print_hex: + XY2NT + jsr load_prepare + +print_hex_preped: + moveq.l #0,d0 + move.b d3,d0 + move.l d0,d1 + lsl.b #2,d0 + ror.l d0,d2 /* prep value */ + subq.l #1,d1 /* count */ + move.w d3,d0 + and.w #0xf800,d0 /* keep upper bits in d0 */ + +_print_hex_loop: + rol.l #4,d2 + move.b d2,d0 + and.b #0xf,d0 + + add.b #'0',d0 + cmp.b #'9',d0 + ble 0f + addq.b #7,d0 +0: + move.w d0,(a0) + dbra d1,_print_hex_loop + + rts + + +# wait vertical sync interrupt + +wait_vsync: + move.b d7,d0 +_wait_change: + stop #0x2000 + cmp.b d7,d0 + beq _wait_change + rts + + +# wait vsync start (polling) +# destroys a0,d0 + +wait_vsync_poll: + move.l #GFXCNTL,a0 +0: + move.w (a0),d0 + and.b #8,d0 + nop + nop + bne 0b +0: + move.w (a0),d0 + and.b #8,d0 + nop + nop + beq 0b + rts + + +test_code: + nop + +test_code_ret_op: + jmp 0x123456 /* will be patched */ +test_code_end: + +################################################# +# # +# RAM DATA # +# # +################################################# + +.bss + +# nothing :) + +.end + +# vim:filetype=asmM68k diff --git a/hexed/md.ld b/hexed/md.ld new file mode 100644 index 0000000..208bfa7 --- /dev/null +++ b/hexed/md.ld @@ -0,0 +1,122 @@ +OUTPUT_ARCH(m68k) +SEARCH_DIR(.) +/*GROUP(-lbcc -lc -lgcc)*/ +__DYNAMIC = 0; + +/* + * Setup the memory map of the SEGA Genesis. + * stack grows down from high memory. + * + * The memory map look like this: + * +--------------------+ <- low memory + * | .text | + * | _etext | + * | ctor list | the ctor and dtor lists are for + * | dtor list | C++ support + * +--------------------+ + * | .data | initialized data goes here + * | _edata | + * +--------------------+ + * | .bss | + * | __bss_start | start of bss, cleared by crt0 + * | _end | start of heap, used by sbrk() + * +--------------------+ + * . . + * . . + * . . + * | __stack | top of stack + * +--------------------+ + */ +/* +MEMORY +{ + rom : ORIGIN = 0x00000000, LENGTH = 0x00400000 + ram : ORIGIN = 0xffff0000, LENGTH = 0x00010000 +} +*/ + +MEMORY { + ram : ORIGIN = 0x0, LENGTH = 0xfffffff +} + +/* + * allocate the stack to be at the top of memory, since the stack + * grows down + */ + +PROVIDE (__stack = 0x00fffff0); + +PROVIDE (ram = 0xffff0000); +/* + * Initalize some symbols to be zero so we can reference them in the + * crt0 without core dumping. These functions are all optional, but + * we do this so we can have our crt0 always use them if they exist. + * This is so BSPs work better when using the crt0 installed with gcc. + * We have to initalize them twice, so we cover a.out (which prepends + * an underscore) and coff object file formats. + */ +PROVIDE (hardware_init_hook = 0); +PROVIDE (_hardware_init_hook = 0); +PROVIDE (software_init_hook = 0); +PROVIDE (_software_init_hook = 0); + +SECTIONS +{ + .text 0x00000000: + { + *(.text) + . = ALIGN(0x4); + __CTOR_LIST__ = .; + LONG((__CTOR_END__ - __CTOR_LIST__) / 4 - 2) + *(.ctors) + LONG(0) + __CTOR_END__ = .; + __DTOR_LIST__ = .; + LONG((__DTOR_END__ - __DTOR_LIST__) / 4 - 2) + *(.dtors) + LONG(0) + __DTOR_END__ = .; + *(.rodata) + *(.gcc_except_table) + + __INIT_SECTION__ = . ; + *(.init) + SHORT (0x4e75) /* rts */ + + __FINI_SECTION__ = . ; + *(.fini) + SHORT (0x4e75) /* rts */ + + _etext = .; + *(.lit) + } > ram + + .data BLOCK (0x4) : + { + *(.shdata) + *(.data) + _edata = .; + } > ram + + .bss 0xff0000 : + { + __bss_start = . ; + *(.shbss) + *(.bss) + *(COMMON) + *(.eh_fram) + *(.eh_frame) + _end = ALIGN (0x8); + __end = _end; + } > ram + + .stab 0 (NOLOAD) : + { + *(.stab) + } + + .stabstr 0 (NOLOAD) : + { + *(.stabstr) + } +} diff --git a/hexed/pc_transfer.c b/hexed/pc_transfer.c new file mode 100644 index 0000000..bcfb652 --- /dev/null +++ b/hexed/pc_transfer.c @@ -0,0 +1,605 @@ +/* + * Copyright (c) 2011, Gražvydas Ignotas + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the organization nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "transfer.h" + +/* + * PC: + * BASE+0 ~ data + * BASE+1 ~ status: BAOSEI?? + * /BUSY, ACK, PE, SLCT, ERROR, IRQ + * BASE+2 ~ control: ??MISIAS + * bidirrectMODE, IRQ_EN, /SLCT_IN, INIT, /AUTO_FD_XT, /STROBE + * + * SEGA + * ?HRL3210 + * TH, TR, TL, D3, D2, D1, D0 + * + * SEGA PC + * 1 D0 <-> 2 D0 + * 2 D1 <-> 3 D1 + * 3 D2 <-> 4 D2 + * 4 D3 <-> 5 D3 + * 5 +5V + * 6 TL <-- 14 /AUTO_FD_XT + * 7 TH --> 10 ACK + * 8 GND --- 21 GND + * 9 TR <-- 17 /SLCT_IN + * + * start: TH low/high, TL high + * + * TH low - lower nibble: MD ready to recv | MD sent to PC + * TL low - lower niblle: sent to MD | ready to recv from MD + * TH high - upper nibble: MD ready to recv | MD sent to PC + * TL high - upper nibble: sent | ready to recv from MD + */ + +#define ACK_TIMEOUT 2000000 + +#define PORT_DATA 888 +#define PORT_STATUS 889 +#define PORT_CONTROL 890 + +#define timediff(now, start) \ + ((now.tv_sec - start.tv_sec) * 1000000 + now.tv_usec - start.tv_usec) + +#define PBE2(p) ((*(p) << 8) | *(p+1)) +#define PBE3(p) ((*(p) << 16) | (*(p + 1) << 8) | *(p + 2)) +#define PBE4(p) ((*(p) << 24) | (*(p + 1) << 16) | (*(p + 2) << 8) | *(p + 3)) + +static void do_exit(const char *msg, const char *where) +{ + /* switch TL back to high */ + outb(0xe0, PORT_CONTROL); + + if (where) + fprintf(stderr, "%s: ", where); + if (msg) + fprintf(stderr, "%s", msg); + exit(1); +} + +static void inthandler(int u) +{ + do_exit("\n", NULL); +} + +static void wait_th_low(const char *where) +{ + struct timeval start, now; + + gettimeofday(&start, NULL); + + while (inb(PORT_STATUS) & 0x40) { + gettimeofday(&now, NULL); + if (timediff(now, start) > ACK_TIMEOUT) + do_exit("timeout waiting TH low\n", where); + } +} + +static void wait_th_high(const char *where) +{ + struct timeval start, now; + + gettimeofday(&start, NULL); + + while (!(inb(PORT_STATUS) & 0x40)) { + gettimeofday(&now, NULL); + if (timediff(now, start) > ACK_TIMEOUT) + do_exit("timeout waiting TH high\n", where); + } +} + +static void output_to_input(void) +{ + /* TL high, recv mode; also give time + * MD to see TL before we lower it in recv_byte */ + outb(0xe0, PORT_CONTROL); + usleep(4*10); /* must be at least 12+8+8 M68k cycles, 28/7.67M */ +} + +static void input_to_output(void) +{ + wait_th_low("input_to_output"); + outb(0xc0, PORT_CONTROL); /* TL high, out mode */ +} + +static unsigned int recv_byte(void) +{ + unsigned int byte; + + outb(0xe2, PORT_CONTROL); /* TL low */ + + wait_th_low("recv_byte"); + + byte = inb(PORT_DATA) & 0x0f; + + outb(0xe0, PORT_CONTROL); /* TL high */ + + wait_th_high("recv_byte"); + + byte |= inb(PORT_DATA) << 4; + + return byte; +} + +static void recv_bytes(unsigned char *b, size_t count) +{ + while (count-- > 0) + *b++ = recv_byte(); +} + +static void send_byte(unsigned int byte) +{ + wait_th_low("recv_bytes"); + + outb(byte & 0x0f, PORT_DATA); + outb(0xc2, PORT_CONTROL); /* TL low */ + + wait_th_high("recv_bytes"); + + outb((byte >> 4) & 0x0f, PORT_DATA); + outb(0xc0, PORT_CONTROL); /* TL high */ +} + +static void send_bytes(unsigned char *b, size_t count) +{ + while (count-- > 0) + send_byte(*b++); +} + +static void send_cmd(unsigned int cmd) +{ + send_byte(CMD_PREFIX); + send_byte(cmd); +} + +static void usage(const char *argv0) +{ + fprintf(stderr, "usage:\n%s [args]\n" + "\tsend [size]\n" + "\trecv \n" + "\tjump \n" + "\tio {r{8,16,32} ,w{8,16,32} }*\n" + "\tloadstate \n" + "\trecvvram \n", argv0); + exit(1); +} + +static unsigned int atoi_or_die(const char *a) +{ + char *p = NULL; + unsigned int i; + + i = strtoul(a, &p, 0); + if (p == NULL || *p != 0) { + fprintf(stderr, "atoi: can't convert: %s\n", a); + exit(1); + } + + return i; +} + +static void checked_gzread(gzFile f, void *data, size_t size) +{ + unsigned int ret; + ret = gzread(f, data, size); + if (ret != size) { + fprintf(stderr, "gzread returned %d/%zu\n", ret, size); + exit(1); + } +} + +int main(int argc, char *argv[]) +{ + unsigned int addr = 0, size = 0; + unsigned int count = 0, i = 0; + int ret; + unsigned char *data; + FILE *file = NULL; + + if (argc < 2) + usage(argv[0]); + + data = malloc(0x1000000); + if (data == NULL) { + fprintf(stderr, "can't alloc %d bytes\n", 0x1000000); + return 1; + } + + /* parse args, read files.. */ + if (strcmp(argv[1], "send") == 0) + { + if (argc != 4 && argc != 5) + usage(argv[0]); + + file = fopen(argv[2], "rb"); + if (file == NULL) { + fprintf(stderr, "can't open file: %s\n", argv[2]); + return 1; + } + + addr = atoi_or_die(argv[3]); + if (argv[4] == NULL) { + fseek(file, 0, SEEK_END); + size = ftell(file); + fseek(file, 0, SEEK_SET); + } + else + size = atoi_or_die(argv[4]); + + ret = fread(data, 1, size, file); + if (ret != size) { + fprintf(stderr, "fread returned %d/%d\n", ret, size); + perror(NULL); + return 1; + } + } + else if (strcmp(argv[1], "recv") == 0) + { + if (argc != 5) + usage(argv[0]); + + file = fopen(argv[2], "wb"); + if (file == NULL) { + fprintf(stderr, "can't open file: %s\n", argv[2]); + return 1; + } + + addr = atoi_or_die(argv[3]); + size = atoi_or_die(argv[4]); + + memset(data, 0, size); + } + else if (strcmp(argv[1], "jump") == 0) + { + if (argc != 3) + usage(argv[0]); + + addr = atoi_or_die(argv[2]); + } + else if (strcmp(argv[1], "io") == 0) + { + unsigned int cmd = 0, value, iosize; + unsigned char *p = data; + + for (i = 2; i < argc; ) { + if (argv[i][0] == 'r') + cmd = IOSEQ_R8; + else if (argv[i][0] == 'w') + cmd = IOSEQ_W8; + else + usage(argv[0]); + + iosize = atoi_or_die(&argv[i][1]); + if (iosize == 32) + cmd += 2; + else if (iosize == 16) + cmd += 1; + else if (iosize != 8) + usage(argv[0]); + *p++ = cmd; + i++; + + addr = atoi_or_die(argv[i]); + *p++ = addr >> 16; + *p++ = addr >> 8; + *p++ = addr >> 0; + i++; + + if (cmd == IOSEQ_W8 || cmd == IOSEQ_W16 || cmd == IOSEQ_W32) { + value = atoi_or_die(argv[i]); + switch (iosize) { + case 32: + *p++ = value >> 24; + *p++ = value >> 16; + case 16: + *p++ = value >> 8; + case 8: + *p++ = value >> 0; + } + i++; + } + + count++; + } + } + else if (strcmp(argv[1], "loadstate") == 0) + { + unsigned char chunk; + char header[12]; + gzFile f; + int len; + + if (argc != 3) + usage(argv[0]); + + f = gzopen(argv[2], "rb"); + if (f == NULL) { + perror("gzopen"); + return 1; + } + + checked_gzread(f, header, sizeof(header)); + if (strncmp(header, "PicoSEXT", 8) != 0) { + fprintf(stderr, "bad header\n"); + return 1; + } + + while (!gzeof(file)) + { + ret = gzread(f, &chunk, 1); + if (ret == 0) + break; + checked_gzread(f, &len, 4); + //printf("%2d %x\n", chunk, len); + switch (chunk) { + case 3: // VRAM + checked_gzread(f, data, len); + size += len; + break; + case 5: // CRAM + checked_gzread(f, data + 0x10000, len); + size += len; + break; + case 6: // VSRAM + checked_gzread(f, data + 0x10080, len); + size += len; + break; + case 8: // video + checked_gzread(f, data + 0x10100, len); + data[size+0] &= ~1; // no display disable + data[size+1] |= 0x40; // no blanking + size += 0x20; + break; + default: + if (chunk > 64+8) { + fprintf(stderr, "bad chunk: %d\n", chunk); + return 1; + } + gzseek(f, len, SEEK_CUR); + break; + } + } + gzclose(f); + if (size != 0x10120) { + fprintf(stderr, "bad final size: %x\n", size); + return 1; + } + // unbyteswap *RAMs (stored byteswapped) + for (i = 0; i < 0x10100; i += 2) { + int tmp = data[i]; + data[i] = data[i + 1]; + data[i + 1] = tmp; + } + } + else if (strcmp(argv[1], "recvvram") == 0) + { + if (argc != 3) + usage(argv[0]); + + file = fopen(argv[2], "wb"); + if (file == NULL) { + fprintf(stderr, "can't open file: %s\n", argv[2]); + return 1; + } + + size = 0x10000; + memset(data, 0, size); + } + else + usage(argv[0]); + + ret = ioperm(PORT_DATA, 3, 1); + if (ret != 0) { + perror("ioperm"); + return 1; + } + + signal(SIGINT, inthandler); + + printf("regs: %02x %02x %02x\n", + inb(PORT_DATA), inb(PORT_STATUS), inb(PORT_CONTROL)); + + /* wait for start condition */ + if (!(inb(PORT_STATUS) & 0x40)) + printf("waiting for TH high..\n"); + while (!(inb(PORT_STATUS) & 0x40)) + usleep(10000); + + outb(0xe8, PORT_CONTROL); /* TR low - request for transfer */ + + /* wait for request ack */ + if (inb(PORT_STATUS) & 0x40) + printf("waiting for TH low..\n"); + for (i = 10000; inb(PORT_STATUS) & 0x40; i += 100) { + if (i > 100000) + i = 100000; + usleep(i); + } + + outb(0xe0, PORT_CONTROL); + + if (strcmp(argv[1], "send") == 0) + { + send_cmd(CMD_PC_SEND); + send_byte((addr >> 16) & 0xff); + send_byte((addr >> 8) & 0xff); + send_byte((addr >> 0) & 0xff); + send_byte((size >> 16) & 0xff); + send_byte((size >> 8) & 0xff); + send_byte((size >> 0) & 0xff); + + for (i = 0; i < size; i++) + { + if ((i & 0xff) == 0) { + printf("\b\b\b\b\b\b\b\b\b\b\b\b\b"); + printf("%06x/%06x", i, size); + fflush(stdout); + } + + send_byte(data[i]); + } + } + else if (strcmp(argv[1], "recv") == 0) + { + send_cmd(CMD_PC_RECV); + send_byte((addr >> 16) & 0xff); + send_byte((addr >> 8) & 0xff); + send_byte((addr >> 0) & 0xff); + send_byte((size >> 16) & 0xff); + send_byte((size >> 8) & 0xff); + send_byte((size >> 0) & 0xff); + output_to_input(); + + for (i = 0; i < size; i++) + { + if ((i & 0xff) == 0) { + printf("\b\b\b\b\b\b\b\b\b\b\b\b\b"); + printf("%06x/%06x", i, size); + fflush(stdout); + } + + data[i] = recv_byte(); + } + + fwrite(data, 1, size, file); + } + else if (strcmp(argv[1], "jump") == 0) + { + send_cmd(CMD_JUMP); + send_byte((addr >> 16) & 0xff); + send_byte((addr >> 8) & 0xff); + send_byte((addr >> 0) & 0xff); + } + else if (strcmp(argv[1], "io") == 0) + { + unsigned char *p = data; + unsigned char rdata[4]; + send_cmd(CMD_IOSEQ); + send_byte((count >> 8) & 0xff); + send_byte((count >> 0) & 0xff); + + for (; count > 0; count--) { + input_to_output(); + send_bytes(p, 4); /* cmd + addr */ + + switch (p[0]) { + case IOSEQ_R8: + output_to_input(); + recv_bytes(rdata, 1); + printf("r8 %06x %02x\n", PBE3(p + 1), rdata[0]); + p += 4; + break; + case IOSEQ_R16: + output_to_input(); + recv_bytes(rdata, 2); + printf("r16 %06x %04x\n", PBE3(p + 1), PBE2(rdata)); + p += 4; + break; + case IOSEQ_R32: + output_to_input(); + recv_bytes(rdata, 4); + printf("r32 %06x %08x\n", PBE3(p + 1), PBE4(rdata)); + p += 4; + break; + case IOSEQ_W8: + send_bytes(&p[4], 1); + printf("w8 %06x %02x\n", PBE3(p + 1), p[4]); + p += 5; + break; + case IOSEQ_W16: + send_bytes(&p[4], 2); + printf("w16 %06x %04x\n", PBE3(p + 1), PBE2(p + 4)); + p += 6; + break; + case IOSEQ_W32: + send_bytes(&p[4], 4); + printf("w32 %06x %08x\n", PBE3(p + 1), PBE4(p + 4)); + p += 8; + break; + default: + do_exit("error in ioseq data\n", NULL); + break; + } + } + } + else if (strcmp(argv[1], "loadstate") == 0) + { + send_cmd(CMD_LOADSTATE); + + for (i = 0; i < size; i++) + { + if ((i & 0x1f) == 0) { + printf("\b\b\b\b\b\b\b\b\b\b\b\b\b"); + printf("%06x/%06x", i, size); + fflush(stdout); + } + + send_byte(data[i]); + } + } + else if (strcmp(argv[1], "recvvram") == 0) + { + send_cmd(CMD_VRAM_RECV); + output_to_input(); + + for (i = 0; i < size; i++) + { + if ((i & 0xff) == 0) { + printf("\b\b\b\b\b\b\b\b\b\b\b\b\b"); + printf("%06x/%06x", i, size); + fflush(stdout); + } + + data[i] = recv_byte(); + } + + fwrite(data, 1, size, file); + } + + if (size != 0) { + printf("\b\b\b\b\b\b\b\b\b\b\b\b\b"); + printf("%06x/%06x\n", i, size); + } + if (file != NULL) + fclose(file); + + /* switch TL back to high, disable outputs */ + outb(0xe0, PORT_CONTROL); + + return 0; +} + diff --git a/hexed/readme.txt b/hexed/readme.txt new file mode 100644 index 0000000..cac50e0 --- /dev/null +++ b/hexed/readme.txt @@ -0,0 +1,19 @@ +------------------------------------------------------------------------------- +hexed - realtime memory viewer for Genesis/Megadrive + written by Gražvydas "notaz" Ignotas +------------------------------------------------------------------------------- + +This is rather simple address space viewer for Genesis/Megadrive. It is capable +of displaying 216 bytes of memory simultaneously in a manner similar to some +hex editors for the PC, with refresh of 50/60Hz. It was created for hardware +research purposes. + +Here are the key bindings: + A + up, A + down - scroll one line up/down. + A + left, A + right - scroll one page up/down. + B - toggle between byte/word display/edit mode. + C - edit highlighted value. + Start - enter menu. + + +hexed is released under the BSD license (see included source code for details). diff --git a/hexed/sega_gcc.s b/hexed/sega_gcc.s new file mode 100644 index 0000000..07a3494 --- /dev/null +++ b/hexed/sega_gcc.s @@ -0,0 +1,106 @@ + dc.l 0x0,0x200 + dc.l INT,INT,INT,INT,INT,INT,INT + dc.l INT,INT,INT,INT,INT,INT,INT,INT + dc.l INT,INT,INT,INT,INT,INT,INT,INT + dc.l INT,INT,INT,HBL,INT,VBL,INT,INT + dc.l INT,INT,INT,INT,INT,INT,INT,INT + dc.l INT,INT,INT,INT,INT,INT,INT,INT + dc.l INT,INT,INT,INT,INT,INT,INT,INT + dc.l INT,INT,INT,INT,INT,INT,INT + .ascii "SEGA GENESIS " + .ascii "hexed (c) notaz, 2009-2011 " + .ascii "HEXED (C) NOTAZ, 2009-2011 " + .ascii "GM 00000000-00" + .byte 0x00,0x00 + .ascii "JD " + .byte 0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00 + .byte 0x00,0xff,0x00,0x00,0xff,0xff,0xff,0xff + .ascii " " + .ascii " " + .ascii " " + .ascii "JUE " + + moveq #0,%d0 + movea.l %d0,%a7 + move %a7,%usp + bra main + +* INT: +* rte + +HBL: + rte + +* VBL: +* addq.l #1,(vtimer).l +* rte + +* Standard 32X startup code for MD side at 0x3F0 + .org 0x3F0 + + .word 0x287C,0xFFFF,0xFFC0,0x23FC,0x0000,0x0000,0x00A1,0x5128 + .word 0x46FC,0x2700,0x4BF9,0x00A1,0x0000,0x7001,0x0CAD,0x4D41 + .word 0x5253,0x30EC,0x6600,0x03E6,0x082D,0x0007,0x5101,0x67F8 + .word 0x4AAD,0x0008,0x6710,0x4A6D,0x000C,0x670A,0x082D,0x0000 + .word 0x5101,0x6600,0x03B8,0x102D,0x0001,0x0200,0x000F,0x6706 + .word 0x2B78,0x055A,0x4000,0x7200,0x2C41,0x4E66,0x41F9,0x0000 + .word 0x04D4,0x6100,0x0152,0x6100,0x0176,0x47F9,0x0000,0x04E8 + .word 0x43F9,0x00A0,0x0000,0x45F9,0x00C0,0x0011,0x3E3C,0x0100 + .word 0x7000,0x3B47,0x1100,0x3B47,0x1200,0x012D,0x1100,0x66FA + .word 0x7425,0x12DB,0x51CA,0xFFFC,0x3B40,0x1200,0x3B40,0x1100 + .word 0x3B47,0x1200,0x149B,0x149B,0x149B,0x149B,0x41F9,0x0000 + .word 0x04C0,0x43F9,0x00FF,0x0000,0x22D8,0x22D8,0x22D8,0x22D8 + .word 0x22D8,0x22D8,0x22D8,0x22D8,0x41F9,0x00FF,0x0000,0x4ED0 + .word 0x1B7C,0x0001,0x5101,0x41F9,0x0000,0x06BC,0xD1FC,0x0088 + .word 0x0000,0x4ED0,0x0404,0x303C,0x076C,0x0000,0x0000,0xFF00 + .word 0x8137,0x0002,0x0100,0x0000,0xAF01,0xD91F,0x1127,0x0021 + .word 0x2600,0xF977,0xEDB0,0xDDE1,0xFDE1,0xED47,0xED4F,0xD1E1 + .word 0xF108,0xD9C1,0xD1E1,0xF1F9,0xF3ED,0x5636,0xE9E9,0x9FBF + .word 0xDFFF,0x4D41,0x5253,0x2049,0x6E69,0x7469,0x616C,0x2026 + .word 0x2053,0x6563,0x7572,0x6974,0x7920,0x5072,0x6F67,0x7261 + .word 0x6D20,0x2020,0x2020,0x2020,0x2020,0x2043,0x6172,0x7472 + .word 0x6964,0x6765,0x2056,0x6572,0x7369,0x6F6E,0x2020,0x2020 + .word 0x436F,0x7079,0x7269,0x6768,0x7420,0x5345,0x4741,0x2045 + .word 0x4E54,0x4552,0x5052,0x4953,0x4553,0x2C4C,0x5444,0x2E20 + .word 0x3139,0x3934,0x2020,0x2020,0x2020,0x2020,0x2020,0x2020 + .word 0x2020,0x2020,0x2020,0x2020,0x2020,0x2020,0x2020,0x2020 + .word 0x2020,0x2020,0x2020,0x524F,0x4D20,0x5665,0x7273,0x696F + .word 0x6E20,0x312E,0x3000,0x48E7,0xC040,0x43F9,0x00C0,0x0004 + .word 0x3011,0x303C,0x8000,0x323C,0x0100,0x3E3C,0x0012,0x1018 + .word 0x3280,0xD041,0x51CF,0xFFF8,0x4CDF,0x0203,0x4E75,0x48E7 + .word 0x81C0,0x41F9,0x0000,0x063E,0x43F9,0x00C0,0x0004,0x3298 + .word 0x3298,0x3298,0x3298,0x3298,0x3298,0x3298,0x2298,0x3341 + .word 0xFFFC,0x3011,0x0800,0x0001,0x66F8,0x3298,0x3298,0x7000 + .word 0x22BC,0xC000,0x0000,0x7E0F,0x3340,0xFFFC,0x3340,0xFFFC + .word 0x3340,0xFFFC,0x3340,0xFFFC,0x51CF,0xFFEE,0x22BC,0x4000 + .word 0x0010,0x7E09,0x3340,0xFFFC,0x3340,0xFFFC,0x3340,0xFFFC + .word 0x3340,0xFFFC,0x51CF,0xFFEE,0x4CDF,0x0381,0x4E75,0x8114 + .word 0x8F01,0x93FF,0x94FF,0x9500,0x9600,0x9780,0x4000,0x0080 + .word 0x8104,0x8F02,0x48E7,0xC140,0x43F9,0x00A1,0x5180,0x08A9 + .word 0x0007,0xFF80,0x66F8,0x3E3C,0x00FF,0x7000,0x7200,0x337C + .word 0x00FF,0x0004,0x3341,0x0006,0x3340,0x0008,0x4E71,0x0829 + .word 0x0001,0x000B,0x66F8,0x0641,0x0100,0x51CF,0xFFE8,0x4CDF + .word 0x0283,0x4E75,0x48E7,0x8180,0x41F9,0x00A1,0x5200,0x08A8 + .word 0x0007,0xFF00,0x66F8,0x3E3C,0x001F,0x20C0,0x20C0,0x20C0 + .word 0x20C0,0x51CF,0xFFF6,0x4CDF,0x0181,0x4E75,0x41F9,0x00FF + .word 0x0000,0x3E3C,0x07FF,0x7000,0x20C0,0x20C0,0x20C0,0x20C0 + .word 0x20C0,0x20C0,0x20C0,0x20C0,0x51CF,0xFFEE,0x3B7C,0x0000 + .word 0x1200,0x7E0A,0x51CF,0xFFFE,0x43F9,0x00A1,0x5100,0x7000 + .word 0x2340,0x0020,0x2340,0x0024,0x1B7C,0x0003,0x5101,0x2E79 + .word 0x0088,0x0000,0x0891,0x0007,0x66FA,0x7000,0x3340,0x0002 + .word 0x3340,0x0004,0x3340,0x0006,0x2340,0x0008,0x2340,0x000C + .word 0x3340,0x0010,0x3340,0x0030,0x3340,0x0032,0x3340,0x0038 + .word 0x3340,0x0080,0x3340,0x0082,0x08A9,0x0000,0x008B,0x66F8 + .word 0x6100,0xFF12,0x08E9,0x0000,0x008B,0x67F8,0x6100,0xFF06 + .word 0x08A9,0x0000,0x008B,0x6100,0xFF3C,0x303C,0x0040,0x2229 + .word 0x0020,0x0C81,0x5351,0x4552,0x6700,0x0092,0x303C,0x0080 + .word 0x2229,0x0020,0x0C81,0x5344,0x4552,0x6700,0x0080,0x21FC + .word 0x0088,0x02A2,0x0070,0x303C,0x0002,0x7200,0x122D,0x0001 + .word 0x1429,0x0080,0xE14A,0x8242,0x0801,0x000F,0x660A,0x0801 + .word 0x0006,0x6700,0x0058,0x6008,0x0801,0x0006,0x6600,0x004E + .word 0x7020,0x41F9,0x0088,0x0000,0x3C28,0x018E,0x4A46,0x6700 + .word 0x0010,0x3429,0x0028,0x0C42,0x0000,0x67F6,0xB446,0x662C + .word 0x7000,0x2340,0x0028,0x2340,0x002C,0x3E14,0x2C7C,0xFFFF + .word 0xFFC0,0x4CD6,0x7FF9,0x44FC,0x0000,0x6014,0x43F9,0x00A1 + .word 0x5100,0x3340,0x0006,0x303C,0x8000,0x6004,0x44FC,0x0001 + diff --git a/hexed/transfer.S b/hexed/transfer.S new file mode 100644 index 0000000..ef5bf5d --- /dev/null +++ b/hexed/transfer.S @@ -0,0 +1,447 @@ +############################################################################### +# +# Copyright (c) 2011, Gražvydas Ignotas +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of the organization nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND ANY +# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Assemble with gas +# --register-prefix-optional --bitwise-or +# + +#include "transfer.h" + +.text +.globl do_transfer + + +# receive 1 byte to d0 +# in: a1 - data port +# trash: d1 +.macro recv_one_byte is_last=0 + move.b #0,(a1) /* clear TH */ + +0: /*L_wait_tl_low*/ + move.b (a1),d1 + btst.b #4,d1 + bne 0b /*L_wait_tl_low*/ + + move.b #0x40,(a1) /* set TH */ + and.b #0x0f,d1 + +0: /*L_wait_tl_hi*/ + move.b (a1),d0 + btst.b #4,d0 + beq 0b /*L_wait_tl_hi*/ + +.if !\is_last + move.b #0,(a1) /* clear TH - ready for next */ +.endif + lsl.b #4,d0 + or.b d1,d0 +.endm + +# send 1 byte in d0 +# in: a1 - data port +# trash: d1,d2 +.macro send_one_byte + move.b d0,d2 + and.b #0x0f,d2 + +0: /*Lwait_tl_low:*/ + move.b (a1),d1 + btst.b #4,d1 + bne 0b /*Lwait_tl_low*/ + + move.b d2,(a1) /* clears TH and writes data */ + + move.b d0,d2 + lsr.b #4,d2 + bset.b #6,d2 /* prepare TH */ + +0: /*wait_tl_hi*/ + move.b (a1),d1 + btst.b #4,d1 + beq 0b /*wait_tl_hi1*/ + + move.b d2,(a1) +.endm + +recv_byte: + moveq.l #0,d0 + recv_one_byte 1 + rts + +# receive 1 16bit word to d0 +# in: a1 - data port +# trash: d1,d2 +recv_word: + recv_one_byte + move.b d0,d2 + recv_one_byte + lsl.w #8,d2 + move.b d0,d2 + move.w d2,d0 + rts + +# receive address/size to d0 (3 bytes BE) +# in: a1 - data port +# trash: d1,d2 +recv_ad: + moveq.l #0,d2 + bsr recv_byte + move.b d0,d2 + bsr recv_byte + lsl.l #8,d2 + move.b d0,d2 + bsr recv_byte + lsl.l #8,d2 + move.b d0,d2 + move.l d2,d0 + rts + +# send 1 byte in d0 +# in: a1 - data port +# trash: d1,d2 +send_byte: + send_one_byte + rts + +.macro switch_to_output +0: /*Lwait_tl_low: PC should switch to rx mode before lowering tl */ + move.b (a1),d0 + btst.b #4,d0 + bne 0b /*Lwait_tl_low*/ + + move.b #0x4f,(0xa1000b).l + move.b #0x40,(a1) +.endm + +.equ sat_maxsize, (80*8+0x200) /* sprites+max_align */ + +# make sure cache is invalidated +# note: VRAM copy doesn't seem to help here +# note2: cache is updated as data is written +# in: d0 - vdp reg5, a0 = 0xc00000 +# trash: d1,d2,a2 +invalidate_sprite_cache: + move.w #0x8f02,4(a0) /* auto increment 2 */ + lsl.b #1,d0 /* upper byte of sat address */ + move.b d0,d1 + lsr.b #6,d1 /* 15:14 dst addr */ + and.b #0x3f,d0 /* assemble cmd */ + lsl.w #8,d0 + swap d0 + move.b d1,d0 + move.l d0,4(a0) + + move.l #0xffe000,a2 + move.l #sat_maxsize/2-1,d2 +0: + move.w (a0),(a2)+ + dbra d2,0b + + bset #30,d0 /* VRAM write */ + move.l d0,4(a0) + + move.l #0xffe000,a2 + move.l #sat_maxsize/2-1,d2 +0: + move.w (a2)+,(a0) + dbra d2,0b + rts + + + +do_transfer: + lea 0xa10005,a1 + move.b #0x40,(0xa1000b).l /* ctrl - all inputs except TH */ + move.b #0x00,(a1) + + bsr recv_byte + cmp.b #CMD_PREFIX,d0 + bne return + + bsr recv_byte + cmp.b #CMD_FIRST,d0 + bcs return + cmp.b #CMD_LAST+1,d0 + bcc return + sub.b #CMD_FIRST,d0 + + lsl.w #2,d0 + lea (jumptab,pc,d0),a0 + jmp (a0) +jumptab: + bra pcc_transfer_recv /* sent to us */ + bra pcc_transfer_send /* recv from us */ + bra pcc_jump + bra pcc_io + bra pcc_loadstate + bra pcc_vram_send + bra pcc_test_code + + +/* receive data from PC */ +pcc_transfer_recv: + bsr recv_ad + move.l d0,a0 + bsr recv_ad + move.l d0,d3 + +tr_recv_loop: + recv_one_byte + move.b d0,(a0)+ + subq.l #1,d3 + bgt tr_recv_loop + bra return + + +/* send data to PC */ +pcc_transfer_send: + bsr recv_ad + move.l d0,a0 + bsr recv_ad + move.l d0,d3 + + switch_to_output + +tr_send_loop: + move.b (a0)+,d0 + send_one_byte + subq.l #1,d3 + bgt tr_send_loop + bra return + + +/* call specified location */ +pcc_jump: + bsr recv_ad + move.l d0,a0 + jsr (a0) + bra return + + +/* do simple i/o commands */ +pcc_io: + moveq.l #0,d4 + bsr recv_byte + move.b d0,d4 + bsr recv_byte + lsl.l #8,d4 + move.b d0,d4 + +pcc_io_loop: + move.b #0x40,(0xa1000b).l /* input mode */ + + sub.w #1,d4 + bmi return + + bsr recv_byte + move.b d0,d3 /* cmd */ + + bsr recv_ad + move.l d0,a2 /* addr */ + + cmp.b #IOSEQ_W32, d3 + beq pcc_io_w32 + cmp.b #IOSEQ_W16, d3 + beq pcc_io_w16 + cmp.b #IOSEQ_W8, d3 + bne pcc_io_rx + +pcc_io_w8: + bsr recv_byte + move.b d0,(a2) + bra pcc_io_loop + +pcc_io_w16: + bsr recv_byte + move.b d0,d3 + bsr recv_byte + lsl.w #8,d3 + move.b d0,d3 + move.w d3,(a2) + bra pcc_io_loop + +pcc_io_w32: + bsr recv_byte + move.b d0,d3 + bsr recv_byte + lsl.w #8,d3 + move.b d0,d3 + bsr recv_byte + lsl.l #8,d3 + move.b d0,d3 + bsr recv_byte + lsl.l #8,d3 + move.b d0,d3 + move.l d3,(a2) + bra pcc_io_loop + +pcc_io_rx: + switch_to_output + + cmp.b #IOSEQ_R32, d3 + beq pcc_io_r32 + cmp.b #IOSEQ_R16, d3 + beq pcc_io_r16 + cmp.b #IOSEQ_R8, d3 + bne return + +pcc_io_r8: + move.b (a2),d0 + bsr send_byte + bra pcc_io_loop + +pcc_io_r16: + move.w (a2),d3 + move.w d3,d0 + lsr.w #8,d0 + bsr send_byte + move.b d3,d0 + bsr send_byte + bra pcc_io_loop + +pcc_io_r32: + move.l (a2),d3 + move.l d3,d0 + swap d0 + lsr.l #8,d0 + bsr send_byte + move.l d3,d0 + swap d0 + bsr send_byte + move.w d3,d0 + lsr.w #8,d0 + bsr send_byte + move.b d3,d0 + bsr send_byte + bra pcc_io_loop + + +/* PicoDrive savestate load */ +pcc_loadstate: + /* write VRAM */ + move.l #0xc00000,a0 + move.w #0x8f02,4(a0) /* auto increment 2 */ + + move.l #0x40000000,4(a0) + move.l #0x10000/2-1,d3 +tr_do_vram_loop: + bsr recv_word + move.w d0,(a0) + dbra d3, tr_do_vram_loop + + /* write cram */ + move.l #0xc0000000,4(a0) + move.l #0x80/2-1,d3 +tr_do_cram_loop: + bsr recv_word + move.w d0,(a0) + dbra d3, tr_do_cram_loop + + /* write vsram */ + move.l #0x40000010,4(a0) + move.l #0x80/2-1,d3 +tr_do_vsram_loop: + bsr recv_word + move.w d0,(a0) + dbra d3, tr_do_vsram_loop + + /* recv and write regs */ + lea 0xffe000,a3 + move.l a3,a2 + moveq.l #0x20-1,d3 +tr_do_vdpreg_recv_loop: + bsr recv_byte + move.b d0,(a2)+ + dbra d3, tr_do_vdpreg_recv_loop + + move.l a3,a2 + moveq.l #0,d3 +tr_do_vdpreg_loop: + move.b d3,d1 + or.b #0x80,d1 + lsl.w #8,d1 + move.b (d3,a2),d1 + move.w d1,4(a0) + addq.l #1,d3 + cmp.b #0x17,d3 /* FIXME: r23 might cause DMA or.. */ + bne 0f /* ..something and hang VDP.. */ + add.b #1,d3 /* ..so we skip it */ +0: + cmp.b #0x20,d3 + blt tr_do_vdpreg_loop + + moveq.l #0,d0 + move.b 5(a3),d0 + bsr invalidate_sprite_cache + + +0: bra 0b + + bra return + + +pcc_vram_send: + /* write VRAM */ + move.l #0xc00000,a0 + move.w #0x8f02,4(a0) /* auto increment 2 */ + move.l #0,4(a0) /* VRAM read, addr 0 */ + move.l #0x10000/2-1,d4 + + switch_to_output + +tr_vram_send_loop: + move.w (a0),d3 + move.w d3,d0 + lsr.w #8,d0 + bsr send_byte + move.b d3,d0 + bsr send_byte + dbra d4,tr_vram_send_loop + + bra return + + + +/* some random code */ +pcc_test_code: + bra return + + + +return: + move.b #0,(0xa1000b).l /* all inputs */ + move.l #0xffe000,a1 + move.l d0,(a1)+ /* last state for debug */ + move.l d1,(a1)+ + move.l d2,(a1)+ + move.l d3,(a1)+ + move.l a0,(a1)+ + rts +# bra return_to_main + + +# vim:filetype=asmM68k diff --git a/hexed/transfer.h b/hexed/transfer.h new file mode 100644 index 0000000..118b752 --- /dev/null +++ b/hexed/transfer.h @@ -0,0 +1,20 @@ +/* all data is big endian */ + +#define CMD_PREFIX 0x5a +#define CMD_PC_SEND 0xc1 /* send to MD: addr[3], len[3], data[] */ +#define CMD_PC_RECV 0xc2 /* recv from MD: addr[3], len[3], data[] */ +#define CMD_JUMP 0xc3 /* jump to addr: addr[3] */ +#define CMD_IOSEQ 0xc4 /* perform i/o ops: count[2], [type[1], addr[3], data[{0,1,2,4}]]* */ +#define CMD_LOADSTATE 0xc5 /* load PD state: vram[64k], cram[128], vsram[128], vdp[32] */ +#define CMD_VRAM_RECV 0xc6 /* recv from MD: vram[64k] */ +#define CMD_TEST 0xc7 /* test code */ + +#define CMD_FIRST CMD_PC_SEND +#define CMD_LAST CMD_TEST + +#define IOSEQ_R8 0xb0 +#define IOSEQ_R16 0xb1 +#define IOSEQ_R32 0xb2 +#define IOSEQ_W8 0xb3 +#define IOSEQ_W16 0xb4 +#define IOSEQ_W32 0xb5 diff --git a/mdpcjoy/mdpcjoy.c b/mdpcjoy/mdpcjoy.c new file mode 100644 index 0000000..8ae6f82 --- /dev/null +++ b/mdpcjoy/mdpcjoy.c @@ -0,0 +1,111 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int main() +{ + int i, ret, fd; + int dpad = 0; + + for (i = 0;; i++) + { + int support = 0; + char name[64]; + + snprintf(name, sizeof(name), "/dev/input/event%d", i); + fd = open(name, O_RDONLY); + if (fd == -1) + break; + + /* check supported events */ + ret = ioctl(fd, EVIOCGBIT(0, sizeof(support)), &support); + if (ret == -1) { + printf("ioctl failed on %s\n", name); + goto skip; + } + + if (!(support & (1 << EV_KEY))) + goto skip; + if (!(support & (1 << EV_ABS))) + goto skip; + + ioctl(fd, EVIOCGNAME(sizeof(name)), name); + printf("found \"%s\" (type %08x)\n", name, support); + break; + +skip: + close(fd); + fd = -1; + } + + if (fd == -1) { + printf("no suitable devs\n"); + return 1; + } + + ret = ioperm(888, 3, 1); + if (ret != 0) { + perror("ioperm"); + return 1; + } + + outb(0xc0, 890); /* switch to output mode, TL and TR high */ + outb(0x0f, 888); /* Dx high */ + + while (1) + { + struct input_event ev; + int rd; + + rd = read(fd, &ev, sizeof(ev)); + if (rd < (int) sizeof(ev)) { + perror("in_evdev: error reading"); + return 1; + } + + if (ev.type == EV_KEY) { + int val = 0xc0; + if (ev.code & 1) { + if (ev.value) + val |= 2; + else + val &= ~2; + } else { + if (ev.value) + val |= 8; + else + val &= ~8; + } + outb(val, 890); + } + else if (ev.type == EV_ABS) + { + if (ev.code == ABS_X) { + if (ev.value < 128) + dpad |= 4; + else if (ev.value > 128) + dpad |= 8; + else + dpad &= ~0x0c; + } + if (ev.code == ABS_Y) { + if (ev.value < 128) + dpad |= 1; + else if (ev.value > 128) + dpad |= 2; + else + dpad &= ~3; + } + outb(~dpad & 0x0f, 888); + } + } + + return 0; +} + diff --git a/mega-usb/Makefile b/mega-usb/Makefile new file mode 100644 index 0000000..8d5879e --- /dev/null +++ b/mega-usb/Makefile @@ -0,0 +1,9 @@ +CFLAGS += -Wall -ggdb +ifndef DEBUG +CFLAGS += -O2 +endif + +all: mega-usb + +clean: + $(RM) mega-usb diff --git a/mega-usb/mega-usb.c b/mega-usb/mega-usb.c new file mode 100644 index 0000000..2649797 --- /dev/null +++ b/mega-usb/mega-usb.c @@ -0,0 +1,371 @@ +/* + * Tool for USB communication with Mega Everdrive + * Copyright (c) 2013,2014 notaz + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#define _BSD_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include // hton +#include +#include + +static int setup(int fd) +{ + struct termios tty; + int ret; + + memset(&tty, 0, sizeof(tty)); + + ret = tcgetattr(fd, &tty); + if (ret != 0) + { + perror("tcgetattr"); + return 1; + } + + tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP + | INLCR | IGNCR | ICRNL | IXON); + tty.c_oflag &= ~OPOST; + tty.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); + tty.c_cflag &= ~(CSIZE | PARENB); + tty.c_cflag |= CS8; + + //tty.c_cc[VMIN] = 1; + //tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout + + ret = tcsetattr(fd, TCSANOW, &tty); + if (ret != 0) { + perror("tcsetattr"); + return ret; + } + + return 0; +} + +static int write_to_cart(int fd, const void *data, size_t size) +{ + int ret; + + ret = write(fd, data, size); + if (ret != size) { + fprintf(stderr, "write %d/%zd: ", ret, size); + perror(""); + exit(1); + //return -1; + } + + return 0; +} + +static int read_from_cart(int fd, void *data, size_t size) +{ + size_t got = 0; + int ret; + + while (got < size) { + ret = read(fd, (char *)data + got, size - got); + if (ret <= 0) { + fprintf(stderr, "read %d %zd/%zd: ", + ret, got, size); + perror(""); + exit(1); + //return -1; + } + got += ret; + } + + return 0; +} + +#define send_cmd(fd, cmd) \ + write_to_cart(fd, cmd, strlen(cmd)) + +static int read_check_byte(int fd, char expect) +{ + char r = '0'; + int ret; + + ret = read_from_cart(fd, &r, 1); + if (ret != 0) { + fprintf(stderr, "missing response, need '%c'\n", expect); + return -1; + } + + if (r != expect) { + fprintf(stderr, "unexpected response: '%c', need '%c'\n", + r, expect); + return -1; + } + + return 0; +} + +static int write_with_check(int fd, const void *data, size_t size, char chk) +{ + int ret; + + ret = write_to_cart(fd, data, size); + if (ret) + return ret; + + ret = read_check_byte(fd, chk); + if (ret != 0) { + if (size < 16) + fprintf(stderr, "data sent: '%16s'\n", + (const char *)data); + exit(1); + //return -1; + } + + return 0; +} + +#define send_cmd_check_k(fd, cmd) \ + write_with_check(fd, cmd, strlen(cmd), 'k') + +static int send_file(int fd, const char *fname, const char *cmd) +{ + char buf[0x10000]; + int retval = -1; + FILE *f = NULL; + size_t blocksz; + size_t size; + int blocks; + int ret; + int i; + + f = fopen(fname, "rb"); + if (f == NULL) { + fprintf(stderr, "fopen %s: ", fname); + perror(""); + return -1; + } + + fseek(f, 0, SEEK_END); + size = ftell(f); + fseek(f, 0, SEEK_SET); + if (size > 0xf00000) { + fprintf(stderr, "size too large: %zd\n", size); + goto out; + } + + if (cmd[1] == 'f') + blocksz = 1024; + else + blocksz = sizeof(buf); + + blocks = (size + blocksz - 1) / blocksz; + + send_cmd(fd, cmd); + ret = write_with_check(fd, &blocks, 1, 'k'); + if (ret) + return ret; + + // at this point, 'd' will arrive even if we don't + // write any more data, what's the point of that? + // probably a timeout? + + for (i = 0; i < blocks; i++) { + ret = fread(buf, 1, blocksz, f); + if (i != blocks - 1 && ret != blocksz) { + fprintf(stderr, "failed to read block %d/%d\n", + i, blocks); + } + if (ret < blocksz) + memset(buf + ret, 0, blocksz - ret); + + write_to_cart(fd, buf, blocksz); + } + + ret = read_check_byte(fd, 'd'); + if (ret) + goto out; + + retval = 0; +out: + if (f != NULL) + fclose(f); + + return retval; +} + +static int recv_file(int fd, const char *fname, unsigned int addr, + unsigned int size) +{ + int retval = -1; + char *buf = NULL; + FILE *f = NULL; + struct { + unsigned int addr; + unsigned int size; + } addr_size; + int ret; + + f = fopen(fname, "wb"); + if (f == NULL) { + fprintf(stderr, "fopen %s: ", fname); + perror(""); + return -1; + } + + buf = malloc(size); + if (buf == NULL) { + fprintf(stderr, "OOM?\n"); + goto out; + } + + send_cmd(fd, "*xd"); + + addr_size.addr = htonl(addr); + addr_size.size = htonl(size); + ret = write_with_check(fd, &addr_size, sizeof(addr_size), 'k'); + if (ret) + return ret; + + ret = read_from_cart(fd, buf, size); + if (ret) + goto out; + + ret = fwrite(buf, 1, size, f); + if (ret != size) { + fprintf(stderr, "fwrite %d/%d: ", ret, size); + perror(""); + goto out; + } + + retval = 0; +out: + if (f != NULL) + fclose(f); + free(buf); + + return retval; +} + +static void usage(const char *argv0) +{ + printf("usage:\n" + "%s [-d ] [-f ] command(s)\n" + "known commands for ED OS:\n" + " *g - upload game\n" + " *w - upload and start OS\n" + " *o - upload and start OS\n" + " *f - upload (and start?) FPGA firmware\n" + " *s - start last ROM (same as pressing start in menu)\n" + " *r - run SDRAM contents as mapper x:\n" + " s - sms, m - md, o - OS app, c - cd BIOS, M - md10m\n" + "upload commands must be followed by -f \n" + "custom OS commands:\n" + " *xd - download memory\n" + , argv0); + exit(1); +} + +static void invarg(int argc, char *argv[], int arg) +{ + if (arg < argc) + fprintf(stderr, "invalid arg %d: \"%s\"\n", arg, argv[arg]); + else + fprintf(stderr, "missing required argument %d\n", arg); + exit(1); +} + +int main(int argc, char *argv[]) +{ + const char *portname = "/dev/ttyUSB0"; + const char *pending_cmd = NULL; + int ret = -1; + int arg = 1; + int fd; + + if (argc < 2 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) + usage(argv[0]); + + if (!strcmp(argv[arg], "-d")) { + arg++; + if (argv[arg] != NULL) + portname = argv[arg]; + else + invarg(argc, argv, arg); + arg++; + } + + fd = open(portname, O_RDWR | O_NOCTTY | O_SYNC); + if (fd < 0) { + fprintf(stderr, "open %s: ", portname); + perror(""); + return 1; + } + + setup(fd); + + send_cmd_check_k(fd, " *T"); + + for (; arg < argc; arg++) { + if (!strcmp(argv[arg], "-f")) { + arg++; + if (argv[arg] == NULL) + invarg(argc, argv, argc); + if (pending_cmd == NULL) + // assume game upload + pending_cmd = "*g"; + + ret = send_file(fd, argv[arg], pending_cmd); + if (ret) + return ret; + + pending_cmd = NULL; + continue; + } + if (argv[arg + 1] && !strcmp(argv[arg + 1], "-f")) { + /* we'll avoid sending command if there are + * problems with specified file */ + pending_cmd = argv[arg]; + continue; + } + /* custom OS commands */ + if (!strcmp(argv[arg], "*xd")) { + unsigned int addr, size; + if (arg + 3 >= argc) + invarg(argc, argv, argc); + addr = strtoul(argv[++arg], NULL, 0); + size = strtoul(argv[++arg], NULL, 0); + ret = recv_file(fd, argv[++arg], addr, size); + if (ret) + return ret; + + continue; + } + + /* passthrough */ + ret = send_cmd_check_k(fd, argv[arg]); + } + + return ret; +} diff --git a/megaed-stop-md/Makefile b/megaed-stop-md/Makefile new file mode 100644 index 0000000..56894ab --- /dev/null +++ b/megaed-stop-md/Makefile @@ -0,0 +1,40 @@ +CROSS = m68k-elf- +CC = $(CROSS)gcc +AS = $(CROSS)as +LD = $(CROSS)ld +OBJCOPY = $(CROSS)objcopy + +ASFLAGS += -m68000 --register-prefix-optional --bitwise-or -pic +ASFLAGS_CC += -Wa,-m68000 -Wa,--register-prefix-optional -Wa,--bitwise-or -Wa,-pic +CFLAGS += -Wall -g -O1 -m68000 -fomit-frame-pointer +LDLIBS += $(shell $(CC) -print-file-name=libgcc.a) + +TARGET = megaed_stop_md +OBJS = sega_gcc.o main.o data.o + +all: $(TARGET).bin + +$(TARGET).elf: $(OBJS) + $(LD) -o $@ -Tsega.ld -Map $(TARGET).map $^ $(LDLIBS) + +clean: + $(RM) $(TARGET).bin $(OBJS) $(TARGET).elf $(TARGET).map + $(RM) maketest test.bin + +%.bin: %.elf + $(OBJCOPY) -I elf32-m68k -O binary $^ $@ + +%.o: %.S + $(CC) -c -o $@ $^ $(ASFLAGS_CC) + +data.s: test.bin + +test.bin: + gcc -o maketest maketest.c + ./maketest + +rel: $(TARGET).bin + mkdir -p /tmp/$(TARGET)/src/ + cp $^ /tmp/$(TARGET)/ + $(MAKE) clean + cp -a * /tmp/$(TARGET)/src/ diff --git a/megaed-stop-md/UNLICENSE b/megaed-stop-md/UNLICENSE new file mode 100644 index 0000000..68a49da --- /dev/null +++ b/megaed-stop-md/UNLICENSE @@ -0,0 +1,24 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to diff --git a/megaed-stop-md/data.s b/megaed-stop-md/data.s new file mode 100644 index 0000000..ceac4b8 --- /dev/null +++ b/megaed-stop-md/data.s @@ -0,0 +1,17 @@ +.section .rodata + +# I don't know why multiple different .align don't work.. +.align 0x8000 + +.global font_base +font_base: +.incbin "font.bin" + +.align 0x8000 +.global test_data +test_data: +.incbin "test.bin" +.global test_data_end +test_data_end: + +# vim:filetype=asmM68k:ts=4:sw=4:expandtab diff --git a/megaed-stop-md/font.bin b/megaed-stop-md/font.bin new file mode 100644 index 0000000..c11cc37 Binary files /dev/null and b/megaed-stop-md/font.bin differ diff --git a/megaed-stop-md/main.c b/megaed-stop-md/main.c new file mode 100644 index 0000000..618f3b5 --- /dev/null +++ b/megaed-stop-md/main.c @@ -0,0 +1,333 @@ +/* + * This software is released into the public domain. + * See UNLICENSE file in top level directory. + */ +#include +#include + +#define u8 unsigned char +#define u16 unsigned short +#define u32 unsigned int + +#define GFX_DATA_PORT 0xC00000 +#define GFX_CTRL_PORT 0xC00004 + +#define TILE_MEM_END 0xB000 + +#define FONT_LEN 128 +#define TILE_FONT_BASE (TILE_MEM_END - FONT_LEN * 32) + +/* note: using ED menu's layout here.. */ +#define WPLANE (TILE_MEM_END + 0x0000) +#define HSCRL (TILE_MEM_END + 0x0800) +#define SLIST (TILE_MEM_END + 0x0C00) +#define APLANE (TILE_MEM_END + 0x1000) +#define BPLANE (TILE_MEM_END + 0x3000) + +#define read8(a) \ + *((volatile u8 *) (a)) +#define read16(a) \ + *((volatile u16 *) (a)) +#define read32(a) \ + *((volatile u32 *) (a)) +#define write16(a, d) \ + *((volatile u16 *) (a)) = (d) +#define write32(a, d) \ + *((volatile u32 *) (a)) = (d) + +#define GFX_WRITE_VRAM_ADDR(adr) \ + (((0x4000 | ((adr) & 0x3FFF)) << 16) | ((adr) >> 14) | 0x00) +#define GFX_WRITE_VSRAM_ADDR(adr) \ + (((0x4000 | ((adr) & 0x3FFF)) << 16) | ((adr) >> 14) | 0x10) +#define GFX_WRITE_CRAM_ADDR(adr) \ + (((0xC000 | ((adr) & 0x3FFF)) << 16) | ((adr) >> 14) | 0x00) + +#define VDP_setReg(r, v) \ + write16(GFX_CTRL_PORT, 0x8000 | ((r) << 8) | (v)) + +enum { + VDP_MODE1 = 0x00, + VDP_MODE2 = 0x01, + VDP_NT_SCROLLA = 0x02, + VDP_NT_WIN = 0x03, + VDP_NT_SCROLLB = 0x04, + VDP_SAT_BASE = 0x05, + VDP_BACKDROP = 0x07, + VDP_MODE3 = 0x0b, + VDP_MODE4 = 0x0c, + VDP_HSCROLL = 0x0d, + VDP_AUTOINC = 0x0f, + VDP_SCROLLSZ = 0x10, +}; + +/* cell counts */ +#define LEFT_BORDER 1 /* lame TV */ +#define PLANE_W 64 +#define PLANE_H 32 +#define CSCREEN_H 28 + +static void VDP_drawTextML(const char *str, u16 plane_base, + u16 x, u16 y) +{ + const u8 *src = (const u8 *)str; + u16 basetile = 0; + int max_len = 40 - LEFT_BORDER; + int len; + u32 addr; + + x += LEFT_BORDER; + + for (len = 0; str[len] && len < max_len; len++) + ; + if (len > (PLANE_W - x)) + len = PLANE_W - x; + + addr = plane_base + ((x + (PLANE_W * y)) << 1); + write32(GFX_CTRL_PORT, GFX_WRITE_VRAM_ADDR(addr)); + + while (len-- > 0) { + write16(GFX_DATA_PORT, + basetile | ((*src++) - 32 + TILE_FONT_BASE / 32)); + } +} + +static int printf_ypos; + +static void printf_line(int x, const char *buf) +{ + u32 addr; + int i; + + VDP_drawTextML(buf, APLANE, x, printf_ypos++ & (PLANE_H - 1)); + + if (printf_ypos >= CSCREEN_H) { + /* clear next line */ + addr = APLANE; + addr += (PLANE_W * (printf_ypos & (PLANE_H - 1))) << 1; + write32(GFX_CTRL_PORT, GFX_WRITE_VRAM_ADDR(addr)); + for (i = 0; i < 40 / 2; i++) + write32(GFX_DATA_PORT, 0); + + /* scroll plane */ + write32(GFX_CTRL_PORT, GFX_WRITE_VSRAM_ADDR(0)); + write16(GFX_DATA_PORT, (printf_ypos - CSCREEN_H + 1) * 8); + } +} + +#define PRINTF_LEN 40 + +static int printf(const char *fmt, ...) +{ + static const char hexchars[] = "0123456789abcdef"; + static int printf_xpos; + char c, buf[PRINTF_LEN + 11 + 1]; + const char *s; + va_list ap; + int ival; + u32 uval; + int d = 0; + int i, j; + + va_start(ap, fmt); + for (d = 0; *fmt; ) { + int prefix0 = 0; + int fwidth = 0; + + c = *fmt++; + if (d < PRINTF_LEN) + buf[d] = c; + + if (c != '%') { + if (c == '\n') { + buf[d] = 0; + printf_line(printf_xpos, buf); + d = 0; + printf_xpos = 0; + continue; + } + d++; + continue; + } + if (d >= PRINTF_LEN) + continue; + + if (*fmt == '0') { + prefix0 = 1; + fmt++; + } + + while ('1' <= *fmt && *fmt <= '9') { + fwidth = fwidth * 10 + *fmt - '0'; + fmt++; + } + + switch (*fmt++) { + case '%': + d++; + break; + case 'd': + case 'i': + ival = va_arg(ap, int); + if (ival < 0) { + buf[d++] = '-'; + ival = -ival; + } + for (i = 1000000000; i >= 10; i /= 10) + if (ival >= i) + break; + for (; i >= 10; i /= 10) { + buf[d++] = '0' + ival / i; + ival %= i; + } + buf[d++] = '0' + ival; + break; + case 'x': + uval = va_arg(ap, int); + while (fwidth > 1 && uval < (1 << (fwidth - 1) * 4)) { + buf[d++] = prefix0 ? '0' : ' '; + fwidth--; + } + for (j = 1; j < 8 && uval >= (1 << j * 4); j++) + ; + for (j--; j >= 0; j--) + buf[d++] = hexchars[(uval >> j * 4) & 0x0f]; + break; + case 's': + s = va_arg(ap, char *); + while (*s && d < PRINTF_LEN) + buf[d++] = *s++; + break; + default: + // don't handle, for now + d++; + va_arg(ap, void *); + break; + } + } + buf[d] = 0; + va_end(ap); + + if (d != 0) { + // line without \n + VDP_drawTextML(buf, APLANE, printf_xpos, + printf_ypos & (PLANE_H - 1)); + printf_xpos += d; + } + + return d; // wrong.. +} + +extern u32 font_base[]; +extern u8 test_data[]; +extern u8 test_data_end[]; + +int main() +{ + volatile u32 *vptr; + u32 old; + u8 bad = 0; + u8 *p, val; + int i, t, len; + + /* z80 */ + write16(0xa11100, 0x100); + write16(0xa11200, 0); + + /* setup VDP */ + while (read16(GFX_CTRL_PORT) & 2) + ; + + VDP_setReg(VDP_MODE1, 0x04); + VDP_setReg(VDP_MODE2, 0x64); + VDP_setReg(VDP_MODE3, 0x00); + VDP_setReg(VDP_MODE4, 0x81); + VDP_setReg(VDP_NT_SCROLLA, APLANE >> 10); + VDP_setReg(VDP_NT_SCROLLB, BPLANE >> 13); + VDP_setReg(VDP_SAT_BASE, SLIST >> 9); + VDP_setReg(VDP_HSCROLL, HSCRL >> 10); + VDP_setReg(VDP_AUTOINC, 2); + VDP_setReg(VDP_SCROLLSZ, 0x01); + VDP_setReg(VDP_BACKDROP, 0); + + /* clear name tables */ + write32(GFX_CTRL_PORT, GFX_WRITE_VRAM_ADDR(APLANE)); + for (i = 0; i < PLANE_W * PLANE_H / 2; i++) + write32(GFX_DATA_PORT, 0); + + write32(GFX_CTRL_PORT, GFX_WRITE_VRAM_ADDR(BPLANE)); + for (i = 0; i < PLANE_W * PLANE_H / 2; i++) + write32(GFX_DATA_PORT, 0); + + /* SAT, h. scroll */ + write32(GFX_CTRL_PORT, GFX_WRITE_VRAM_ADDR(SLIST)); + write32(GFX_DATA_PORT, 0); + + write32(GFX_CTRL_PORT, GFX_WRITE_VRAM_ADDR(HSCRL)); + write32(GFX_DATA_PORT, 0); + + /* scroll plane vscroll */ + write32(GFX_CTRL_PORT, GFX_WRITE_VSRAM_ADDR(0)); + write32(GFX_DATA_PORT, 0); + printf_ypos = 0; + + /* load font */ + write32(GFX_CTRL_PORT, GFX_WRITE_VRAM_ADDR(TILE_FONT_BASE)); + for (i = 0; i < FONT_LEN * 32 / 4; i++) + write32(GFX_DATA_PORT, font_base[i]); + + /* set colors */ + write32(GFX_CTRL_PORT, GFX_WRITE_CRAM_ADDR(0)); + write32(GFX_DATA_PORT, 0); + write32(GFX_CTRL_PORT, GFX_WRITE_CRAM_ADDR(15 * 2)); // font + write16(GFX_DATA_PORT, 0xeee); + + printf("\n"); + printf("MD version: %02x\n", read8(0xa10001)); + printf("ROM witable? "); + + vptr = (void *)0x120; + old = *vptr; + *vptr ^= ~0; + printf(*vptr == old ? "no" : "yes"); + printf("\n\n"); + + p = test_data; + len = test_data_end - test_data; + + for (t = 1; ; t++) { + printf("executing stop.. "); + for (i = 0; i < 5 * 60; i++) + asm volatile("stop #0x2000" ::: "cc"); + printf("done\n"); + + printf("checking memory..\n"); + + val = 0; + for (i = 0; i < len; i++) { + if (p[i] != val) { + printf("bad: %06x: got %02x, expected %02x\n", + &p[i], p[i], val); + bad = 1; + } + val++; + } + + printf("done. Try %d: test ", t); + if (bad) { + printf("FAILED\n"); + break; + } + printf("PASSED\n"); + } + + write32(GFX_CTRL_PORT, GFX_WRITE_CRAM_ADDR(0)); + write16(GFX_DATA_PORT, 0x008); + + /* there are not enough STOP opcodes in this world :D */ + while (1) + asm volatile("stop #0x2000" ::: "cc"); + + return 0; +} + +// vim:ts=4:sw=4:expandtab diff --git a/megaed-stop-md/maketest.c b/megaed-stop-md/maketest.c new file mode 100644 index 0000000..9ebe038 --- /dev/null +++ b/megaed-stop-md/maketest.c @@ -0,0 +1,17 @@ +#include + +int main() +{ + FILE *f; + int i; + + f = fopen("test.bin", "wb"); + if (f == NULL) + return 1; + + for (i = 0; i < 0x200000 - 0x10000; i++) + fwrite(&i, 1, 1, f); + fclose(f); + + return 0; +} diff --git a/megaed-stop-md/sega.ld b/megaed-stop-md/sega.ld new file mode 100644 index 0000000..0921912 --- /dev/null +++ b/megaed-stop-md/sega.ld @@ -0,0 +1,117 @@ +OUTPUT_ARCH(m68k) +SEARCH_DIR(.) +/*GROUP(-lbcc -lc -lgcc)*/ +__DYNAMIC = 0; + +/* + * Setup the memory map of the SEGA Genesis. + * stack grows down from high memory. + * + * The memory map look like this: + * +--------------------+ <- low memory + * | .text | + * | _etext | + * | ctor list | the ctor and dtor lists are for + * | dtor list | C++ support + * +--------------------+ + * | .data | initialized data goes here + * | _edata | + * +--------------------+ + * | .bss | + * | __bss_start | start of bss, cleared by crt0 + * | _end | start of heap, used by sbrk() + * +--------------------+ + * . . + * . . + * . . + * | __stack | top of stack + * +--------------------+ + */ +MEMORY +{ + rom : ORIGIN = 0x00000000, LENGTH = 0x00400000 + ram : ORIGIN = 0x00ff0000, LENGTH = 0x00010000 +} + +/* + * allocate the stack to be at the top of memory, since the stack + * grows down + */ + +PROVIDE (__stack = 0x00fffff0); + +/* + * Initalize some symbols to be zero so we can reference them in the + * crt0 without core dumping. These functions are all optional, but + * we do this so we can have our crt0 always use them if they exist. + * This is so BSPs work better when using the crt0 installed with gcc. + * We have to initalize them twice, so we cover a.out (which prepends + * an underscore) and coff object file formats. + */ +PROVIDE (hardware_init_hook = 0); +PROVIDE (_hardware_init_hook = 0); +PROVIDE (software_init_hook = 0); +PROVIDE (_software_init_hook = 0); + +SECTIONS +{ + .text 0x00000000: + { + *(.text) + . = ALIGN(0x4); + __CTOR_LIST__ = .; + LONG((__CTOR_END__ - __CTOR_LIST__) / 4 - 2) + *(.ctors) + LONG(0) + __CTOR_END__ = .; + __DTOR_LIST__ = .; + LONG((__DTOR_END__ - __DTOR_LIST__) / 4 - 2) + *(.dtors) + LONG(0) + __DTOR_END__ = .; + *(.rodata*) +/* + *(.gcc_except_table) + + __INIT_SECTION__ = . ; + *(.init) + SHORT (0x4e75) + + __FINI_SECTION__ = . ; + *(.fini) + SHORT (0x4e75) +*/ + _etext = .; + *(.lit) + } > rom + + .data 0xff0000 : + { + *(.shdata) + *(.data) + _edata = .; + } > ram + + /* .bss 0xff0100 : */ + .bss BLOCK (0x4) : + { + __bss_start = . ; + *(.shbss) + *(.bss) + *(COMMON) + *(.eh_fram) + *(.eh_frame) + _end = ALIGN (0x8); + __end = _end; + } > ram + + .stab 0 (NOLOAD) : + { + *(.stab) + } + + .stabstr 0 (NOLOAD) : + { + *(.stabstr) + } +} diff --git a/megaed-stop-md/sega_gcc.s b/megaed-stop-md/sega_gcc.s new file mode 100644 index 0000000..5619334 --- /dev/null +++ b/megaed-stop-md/sega_gcc.s @@ -0,0 +1,41 @@ + dc.l 0, RST, exc__, exc__, exc__, exc__, exc__, exc__ + dc.l exc__, exc__, exc__, exc__, exc__, exc__, exc__, exc__ + dc.l exc__, exc__, exc__, exc__, exc__, exc__, exc__, exc__ + dc.l exc__, exc__, exc__, exc__, HBL, exc__, VBL, exc__ + dc.l exc__, exc__, exc__, exc__, exc__, exc__, exc__, exc__ + dc.l exc__, exc__, exc__, exc__, exc__, exc__, exc__, exc__ + dc.l exc__, exc__, exc__, exc__, exc__, exc__, exc__, exc__ + dc.l exc__, exc__, exc__, exc__, exc__, exc__, exc__, exc__ + + .ascii "SEGA " + .ascii "MEGA-ED SDRAM vs STOP " + .ascii "MEGA-ED SDRAM vs STOP " + .ascii "GM 00000000-00" + .byte 0x00,0x00 + .ascii "JD " + .byte 0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00 + .byte 0x00,0xff,0x00,0x00,0xff,0xff,0xff,0xff + .ascii " " + .ascii " " + .ascii " " + .ascii "JUE " + +RST: + move.w #0x2700, %sr + + move.b (0xA10001), %d0 + andi.b #0x0F, %d0 + beq.s 0f + move.l #0x53454741, (0xA14000) /* 'SEGA' */ +0: + moveq.l #0, %d0 + movea.l %d0, %a7 + move.l %a7, %usp + bra main + +HBL: +VBL: +exc__: + rte + +# vim:filetype=asmM68k:ts=4:sw=4:expandtab diff --git a/megaed-stop/Makefile b/megaed-stop/Makefile new file mode 100644 index 0000000..fe8f346 --- /dev/null +++ b/megaed-stop/Makefile @@ -0,0 +1,39 @@ +CROSS = m68k-elf- +CC = $(CROSS)gcc +AS = $(CROSS)as +LD = $(CROSS)ld +OBJCOPY = $(CROSS)objcopy + +ASFLAGS += -m68000 --register-prefix-optional --bitwise-or -pic +ASFLAGS_CC += -Wa,-m68000 -Wa,--register-prefix-optional -Wa,--bitwise-or -Wa,-pic +CFLAGS += -Wall -g -O1 -m68000 -fomit-frame-pointer +LDLIBS += $(shell $(CC) -print-file-name=libgcc.a) + +TARGET = megaed_stop +OBJS = sega_gcc.o main.o + +all: $(TARGET).bin + +$(TARGET).elf: $(OBJS) + $(LD) -o $@ -Ted_app.ld -Map $(TARGET).map $^ $(LDLIBS) + +$(TARGET)_e.bin: $(TARGET).bin + dd if=/dev/zero of=$@ bs=1M count=1 + dd if=$^ of=$@ bs=1M seek=1 + dd if=$^ of=$@ conv=notrunc + +clean: + $(RM) $(TARGET).bin $(OBJS) $(TARGET).elf $(TARGET).map + + +%.bin: %.elf + $(OBJCOPY) -I elf32-m68k -O binary $^ $@ + +%.o: %.S + $(CC) -c -o $@ $^ $(ASFLAGS_CC) + +rel: $(TARGET).bin + mkdir -p /tmp/$(TARGET)/src/ + cp $^ /tmp/$(TARGET)/ + $(MAKE) clean + cp -a * /tmp/$(TARGET)/src/ diff --git a/megaed-stop/UNLICENSE b/megaed-stop/UNLICENSE new file mode 100644 index 0000000..68a49da --- /dev/null +++ b/megaed-stop/UNLICENSE @@ -0,0 +1,24 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to diff --git a/megaed-stop/ed_app.ld b/megaed-stop/ed_app.ld new file mode 100644 index 0000000..bd40362 --- /dev/null +++ b/megaed-stop/ed_app.ld @@ -0,0 +1,116 @@ +OUTPUT_ARCH(m68k) +SEARCH_DIR(.) +/*GROUP(-lbcc -lc -lgcc)*/ +__DYNAMIC = 0; + +/* + * Setup the memory map of the SEGA Genesis. + * stack grows down from high memory. + * + * The memory map look like this: + * +--------------------+ <- low memory + * | .text | + * | _etext | + * | ctor list | the ctor and dtor lists are for + * | dtor list | C++ support + * +--------------------+ + * | .data | initialized data goes here + * | _edata | + * +--------------------+ + * | .bss | + * | __bss_start | start of bss, cleared by crt0 + * | _end | start of heap, used by sbrk() + * +--------------------+ + * . . + * . . + * . . + * | __stack | top of stack + * +--------------------+ + */ +MEMORY +{ + rom : ORIGIN = 0x00100000, LENGTH = 0x00300000 + ram : ORIGIN = 0x00ff0100, LENGTH = 0x0000FF00 +} + +/* + * allocate the stack to be at the top of memory, since the stack + * grows down + */ + +PROVIDE (__stack = 0x00fffff0); + +/* + * Initalize some symbols to be zero so we can reference them in the + * crt0 without core dumping. These functions are all optional, but + * we do this so we can have our crt0 always use them if they exist. + * This is so BSPs work better when using the crt0 installed with gcc. + * We have to initalize them twice, so we cover a.out (which prepends + * an underscore) and coff object file formats. + */ +PROVIDE (hardware_init_hook = 0); +PROVIDE (_hardware_init_hook = 0); +PROVIDE (software_init_hook = 0); +PROVIDE (_software_init_hook = 0); + +SECTIONS +{ + .text 0x00100000: + { + *(.text) + . = ALIGN(0x4); + __CTOR_LIST__ = .; + LONG((__CTOR_END__ - __CTOR_LIST__) / 4 - 2) + *(.ctors) + LONG(0) + __CTOR_END__ = .; + __DTOR_LIST__ = .; + LONG((__DTOR_END__ - __DTOR_LIST__) / 4 - 2) + *(.dtors) + LONG(0) + __DTOR_END__ = .; + *(.rodata*) + *(.gcc_except_table) + + __INIT_SECTION__ = . ; + *(.init) + SHORT (0x4e75) /* rts */ + + __FINI_SECTION__ = . ; + *(.fini) + SHORT (0x4e75) /* rts */ + + _etext = .; + *(.lit) + } > rom + + .data 0xff0100 : + { + *(.shdata) + *(.data) + _edata = .; + } > ram + + /* .bss 0xff0100 : */ + .bss BLOCK (0x4) : + { + __bss_start = . ; + *(.shbss) + *(.bss) + *(COMMON) + *(.eh_fram) + *(.eh_frame) + _end = ALIGN (0x8); + __end = _end; + } > ram + + .stab 0 (NOLOAD) : + { + *(.stab) + } + + .stabstr 0 (NOLOAD) : + { + *(.stabstr) + } +} diff --git a/megaed-stop/edos.h b/megaed-stop/edos.h new file mode 100644 index 0000000..58025e3 --- /dev/null +++ b/megaed-stop/edos.h @@ -0,0 +1,153 @@ +/* + * File: edos.h + * Author: krik + * + * Created on 29 Ìàðò 2012 ã., 1:29 + */ + +#ifndef _EDOS_H +#define _EDOS_H + +//#include "segalib.h" + +/* + * saddr: address in sectors + * slen: lenght in sectors + * wr_slen: how many sectors will be written + * sector size 512 bytes + * dma reading of usb and SD available only if data destination located in rom area (0-0x3ffffff). dma reading not available for genesis ram + * destination address for dma reading must be aligned to 512b + * one mbyte of sdram can be mapped to one of four banks in rom space. osSetMemMap(u16) can be used for mapping configuration. + * os code located in last mbyte of sdram and should be mapped in bank 0 + * user code located in begin of sdram. default mapping 0x210f means that end of sdram (OS) mapped to area 0-0x0fffff, first mbyte of user code mapped to 0x100000-0x1fffff, + * memory configuration: + * genesis address: 0x000000-0x0fffff, physical sdram address: 0xf00000-0xffffff OS + * genesis address: 0x100000-0x3fffff, physical sdram address: 0x000000-0x2fffff user code (current application) + * 0xff0000-0xff00ff OS dma code + * first 256bytes of genesis ram must be reserved for OS + * */ + + +#define MEM_ERR_SPI_RD_TIMEOUT 120 + +#define ERR_FILE_TOO_BIG 140 +#define ERR_WRON_OS_SIZE 142 +#define ERR_OS_VERIFY 143 +#define ERR_OS_VERIFY2 144 +#define ERR_BAD_DMA_ADDRESS 145 +#define ERR_MUST_NOT_RET 146 + +//100 - 119 fat errors +#define FAT_ERR_NOT_EXIST 100 +#define FAT_ERR_EXIST 101 +#define FAT_ERR_NAME 102 +#define FAT_ERR_OUT_OF_FILE 103 +#define FAT_ERR_BAD_BASE_CLUSTER 104; +#define FAT_ERR_NO_FRE_SPACE 105 +#define FAT_ERR_NOT_FILE 106 +#define FAT_ERR_FILE_MODE 107 +#define FAT_ERR_ROT_OVERFLOW 108 +#define FAT_ERR_OUT_OF_TABLE 109 +#define FAT_ERR_INIT 110 +#define FAT_LFN_BUFF_OVERFLOW 111 +#define FAT_DISK_NOT_READY 112 +#define FAT_ERR_SIZE 113 +#define FAT_ERR_RESIZE 114 + + +#define DISK_ERR_INIT 50 +#define DISK_ERR_RD1 62 +#define DISK_ERR_RD2 63 + +#define DISK_ERR_WR1 64 +#define DISK_ERR_WR2 65 +#define DISK_ERR_WR3 66 +#define DISK_ERR_WR4 67 +#define DISK_ERR_WR5 68 + +typedef struct { + u32 entry_cluster; + u32 size; + u32 hdr_sector; + u16 hdr_idx; + u8 name[256]; + u16 is_dir; +} FatFullRecord; + +typedef struct { + u8(*diskWrite)(u32 saddr, u8 *buff, u16 slen); + u8(*diskRead)(u32 saddr, void *buff, u16 slen);//*dst must be alligned to 512bytes and be in range 0x100000-0x3fffff. *dst can be located in genesis ram also, but transfer will be slow in this case + u8(*usbReadByte)();//loop inside of function waiting until usbRdReady != 0 + void (*usbWriteByte)(u8 dat);//loop inside of function waiting until usbWrReady != 0 + u8(*usbReadDma)(u16 *dst, u16 slen);//*dst must be alligned to 512bytes and be in range 0x100000-0x3fffff + u8(*usbReadPio)(u16 *dst, u16 slen); + u8(*usbRdReady)(); //return 1 if some data comes from pc + u8(*usbWrReady)(); //return 1 usb ready to send byte + void (*osSetMemMap)(u16 map); //memoty configuration 4x1Mb + u16(*osGetOsVersion)(); + u16(*osGetFirmVersion)(); + void (*osGetSerial)(u32 * buff); // 8bytes uniq serial number + void (*VDP_setReg)(u8 reg, u8 value);//os vdp functions should be used, otherwise system may hang while udb/sd dma + void (*VDP_vintOn)(); + void (*VDP_vintOff)(); + void (*memInitDmaCode)();//copy dma routine to genesis ram + u8(*fatReadDir)(FatFullRecord * frec);//get next record in current dir + void(*fatOpenDir)(u32 entry_cluster);//arg is entry cluster ot dir or 0. zero arg means that need to open root dir + u8(*fatOpenFileByeName)(u8 *name, u32 wr_slen);//wr_slen write len, or 0 if reading + u8(*fatOpenFile)(FatFullRecord *rec, u32 wr_slen);//wr_slen is write len, or 0 if reading + u8(*fatReadFile)(void *dst, u32 slen); + u8(*fatWriteFile)(void *src, u32 slen); + u8(*fatCreateRecIfNotExist)(u8 *name, u8 is_dir); + u8(*fatSkipSectors)(u32 slen); +} OsRoutine; + + +extern OsRoutine *ed_os; +void edInit(); + + +//stereo dac. 8bit for each channel. +//any writing to this port enables dac output, any reading from this port disables dac output. +#define REG_DAC *((volatile u16*) (0xA1300E)) + + +//stuff for direct access to usb and spi. not recommended for use. OS function should be used for best compatibility +#define _SPI_SS 0 +#define _SPI_FULL_SPEED 1 +#define _SPI_SPI16 2 +#define _SPI_AREAD 3 + +//spi port (sd interface) +#define SPI_PORT *((volatile u16*) (0xA13000)) +#define SPI_CFG_PORT *((volatile u16*) (0xA13002)) + +//16bit or 8bit spi mode +#define SPI16_ON SPI_CFG_PORT |= (1 << _SPI_SPI16) +#define SPI16_OFF SPI_CFG_PORT &= ~(1 << _SPI_SPI16) + +//spi autoread. means that not need to write something to spi port before than read +#define SPI_AR_ON SPI_CFG_PORT |= (1 << _SPI_AREAD) +#define SPI_AR_OFF SPI_CFG_PORT &= ~(1 << _SPI_AREAD) + +//spi chip select +#define SPI_SS_OFF SPI_CFG_PORT |= (1 << _SPI_SS) +#define SPI_SS_ON SPI_CFG_PORT &= ~(1 << _SPI_SS) + +//spi speed. low speed need only for sd init +#define SPI_HI_SPEED_ON SPI_CFG_PORT |= (1 << _SPI_FULL_SPEED) +#define SPI_HI_SPEED_OFF SPI_CFG_PORT &= ~(1 << _SPI_FULL_SPEED) + +//usb-serial port +#define FIFO_PORT *((volatile u16*) (0xA1300A)) + +//spi and usb state +#define STATE_PORT *((volatile u16*) (0xA1300C)) +#define _STATE_SPI_READY 0 +#define _STATE_FIFO_WR_READY 1 +#define _STATE_FIFO_RD_READY 2 +#define IS_FIFO_RD_READY (STATE_PORT & (1 << _STATE_FIFO_RD_READY)) +#define IS_FIFO_WR_READY (STATE_PORT & (1 << _STATE_FIFO_WR_READY)) + + +#endif /* _EDOS_H */ + diff --git a/megaed-stop/main.c b/megaed-stop/main.c new file mode 100644 index 0000000..4fbac7a --- /dev/null +++ b/megaed-stop/main.c @@ -0,0 +1,291 @@ +/* + * This software is released into the public domain. + * See UNLICENSE file in top level directory. + */ +#include +#include + +#define u8 unsigned char +#define u16 unsigned short +#define u32 unsigned int + +#include "edos.h" + +#define GFX_DATA_PORT 0xC00000 +#define GFX_CTRL_PORT 0xC00004 + +#define TILE_MEM_END 0xB000 + +#define FONT_LEN 128 +#define TILE_FONT_BASE (TILE_MEM_END / 32 - FONT_LEN) + +/* note: using ED menu's layout here.. */ +#define WPLANE (TILE_MEM_END + 0x0000) +#define HSCRL (TILE_MEM_END + 0x0800) +#define SLIST (TILE_MEM_END + 0x0C00) +#define APLANE (TILE_MEM_END + 0x1000) +#define BPLANE (TILE_MEM_END + 0x3000) + +#define read8(a) \ + *((volatile u8 *) (a)) +#define read16(a) \ + *((volatile u16 *) (a)) +#define read32(a) \ + *((volatile u32 *) (a)) +#define write16(a, d) \ + *((volatile u16 *) (a)) = (d) +#define write32(a, d) \ + *((volatile u32 *) (a)) = (d) + +#define GFX_WRITE_VRAM_ADDR(adr) \ + (((0x4000 | ((adr) & 0x3FFF)) << 16) | ((adr) >> 14) | 0x00) +#define GFX_WRITE_VSRAM_ADDR(adr) \ + (((0x4000 | ((adr) & 0x3FFF)) << 16) | ((adr) >> 14) | 0x10) + +enum { + VDP_MODE1 = 0x00, + VDP_MODE2 = 0x01, + VDP_BACKDROP = 0x07, + VDP_MODE3 = 0x0b, + VDP_MODE4 = 0x0c, + VDP_AUTOINC = 0x0f, + VDP_SCROLLSZ = 0x10, +}; + +/* cell counts */ +#define LEFT_BORDER 1 /* lame TV */ +#define PLANE_W 64 +#define PLANE_H 32 +#define CSCREEN_H 28 + +static void VDP_drawTextML(const char *str, u16 plane_base, + u16 x, u16 y) +{ + const u8 *src = (const u8 *)str; + u16 basetile = 0; + int max_len = 40 - LEFT_BORDER; + int len; + u32 addr; + + x += LEFT_BORDER; + + for (len = 0; str[len] && len < max_len; len++) + ; + if (len > (PLANE_W - x)) + len = PLANE_W - x; + + addr = plane_base + ((x + (PLANE_W * y)) << 1); + write32(GFX_CTRL_PORT, GFX_WRITE_VRAM_ADDR(addr)); + + while (len-- > 0) { + write16(GFX_DATA_PORT, + basetile | ((*src++) - 32 + TILE_FONT_BASE)); + } +} + +static int printf_ypos; + +static void printf_line(int x, const char *buf) +{ + u32 addr; + int i; + + VDP_drawTextML(buf, APLANE, x, printf_ypos++ & (PLANE_H - 1)); + + if (printf_ypos >= CSCREEN_H) { + /* clear next line */ + addr = APLANE; + addr += (PLANE_W * (printf_ypos & (PLANE_H - 1))) << 1; + write32(GFX_CTRL_PORT, GFX_WRITE_VRAM_ADDR(addr)); + for (i = 0; i < 40 / 2; i++) + write32(GFX_DATA_PORT, 0); + + /* scroll plane */ + write32(GFX_CTRL_PORT, GFX_WRITE_VSRAM_ADDR(0)); + write16(GFX_DATA_PORT, (printf_ypos - CSCREEN_H + 1) * 8); + } +} + +#define PRINTF_LEN 40 + +static int printf(const char *fmt, ...) +{ + static const char hexchars[] = "0123456789abcdef"; + static int printf_xpos; + char c, buf[PRINTF_LEN + 11 + 1]; + const char *s; + va_list ap; + int ival; + u32 uval; + int d = 0; + int i, j; + + va_start(ap, fmt); + for (d = 0; *fmt; ) { + int prefix0 = 0; + int fwidth = 0; + + c = *fmt++; + if (d < PRINTF_LEN) + buf[d] = c; + + if (c != '%') { + if (c == '\n') { + buf[d] = 0; + printf_line(printf_xpos, buf); + d = 0; + printf_xpos = 0; + continue; + } + d++; + continue; + } + if (d >= PRINTF_LEN) + continue; + + if (*fmt == '0') { + prefix0 = 1; + fmt++; + } + + while ('1' <= *fmt && *fmt <= '9') { + fwidth = fwidth * 10 + *fmt - '0'; + fmt++; + } + + switch (*fmt++) { + case '%': + d++; + break; + case 'd': + case 'i': + ival = va_arg(ap, int); + if (ival < 0) { + buf[d++] = '-'; + ival = -ival; + } + for (i = 1000000000; i >= 10; i /= 10) + if (ival >= i) + break; + for (; i >= 10; i /= 10) { + buf[d++] = '0' + ival / i; + ival %= i; + } + buf[d++] = '0' + ival; + break; + case 'x': + uval = va_arg(ap, int); + while (fwidth > 1 && uval < (1 << (fwidth - 1) * 4)) { + buf[d++] = prefix0 ? '0' : ' '; + fwidth--; + } + for (j = 1; j < 8 && uval >= (1 << j * 4); j++) + ; + for (j--; j >= 0; j--) + buf[d++] = hexchars[(uval >> j * 4) & 0x0f]; + break; + case 's': + s = va_arg(ap, char *); + while (*s && d < PRINTF_LEN) + buf[d++] = *s++; + break; + default: + // don't handle, for now + d++; + va_arg(ap, void *); + break; + } + } + buf[d] = 0; + va_end(ap); + + if (d != 0) { + // line without \n + VDP_drawTextML(buf, APLANE, printf_xpos, + printf_ypos & (PLANE_H - 1)); + printf_xpos += d; + } + + return d; // wrong.. +} + +int main() +{ + OsRoutine *ed; + u8 seed, bad = 0; + u8 *p, val; + int i, t, len; + + ed = (OsRoutine *) *(u32 *)0x1A0; + ed->memInitDmaCode(); + + ed->VDP_setReg(VDP_MODE1, 0x04); + ed->VDP_setReg(VDP_MODE2, 0x64); + ed->VDP_setReg(VDP_AUTOINC, 2); + ed->VDP_setReg(VDP_SCROLLSZ, 0x01); + + /* clear name tables */ + write32(GFX_CTRL_PORT, GFX_WRITE_VRAM_ADDR(APLANE)); + for (i = 0; i < PLANE_W * PLANE_H / 2; i++) + write32(GFX_DATA_PORT, 0); + + write32(GFX_CTRL_PORT, GFX_WRITE_VRAM_ADDR(BPLANE)); + for (i = 0; i < PLANE_W * PLANE_H / 2; i++) + write32(GFX_DATA_PORT, 0); + + /* scroll planes */ + write32(GFX_CTRL_PORT, GFX_WRITE_VSRAM_ADDR(0)); + write32(GFX_DATA_PORT, 0); + + /* note: relying on ED menu's font setup here.. */ + + printf("\n"); + printf("MD version: %02x\n", read8(0xa10001)); + printf("ED os/fw: %d/%d\n\n", ed->osGetOsVersion(), + ed->osGetFirmVersion()); + + seed = read8(0xC00009); + p = (void *)0x200000; + len = 0x200000; + printf("filling SDRAM, seed=%02x.. ", seed); + + val = seed; + for (i = 0; i < len; i++) + p[i] = val++; + + printf("done.\n"); + + for (t = 1; ; t++) { + printf("executing stop.. "); + for (i = 0; i < 5 * 60; i++) + asm volatile("stop #0x2000"); + printf("done\n"); + + printf("checking memory..\n"); + + val = seed; + for (i = 0; i < len; i++) { + if (p[i] != val) { + printf("bad: %06x: got %02x, expected %02x\n", + &p[i], p[i], val); + bad = 1; + } + val++; + } + + printf("done. Try %d: test ", t); + if (bad) { + printf("FAILED\n"); + break; + } + printf("PASSED\n"); + } + + /* there are not enough STOP opcodes in this world :D */ + while (1) + asm volatile("stop #0x2000"); + + return 0; +} + +// vim:ts=4:sw=4:expandtab diff --git a/megaed-stop/sega_gcc.s b/megaed-stop/sega_gcc.s new file mode 100644 index 0000000..927da4e --- /dev/null +++ b/megaed-stop/sega_gcc.s @@ -0,0 +1,43 @@ + dc.l 0, 0x200, exc__, exc__, exc__, exc__, exc__, exc__ + dc.l exc__, exc__, exc__, exc__, exc__, exc__, exc__, exc__ + dc.l exc__, exc__, exc__, exc__, exc__, exc__, exc__, exc__ + dc.l exc__, exc__, exc__, exc__, HBL, exc__, VBL, exc__ + dc.l exc__, exc__, exc__, exc__, exc__, exc__, exc__, exc__ + dc.l exc__, exc__, exc__, exc__, exc__, exc__, exc__, exc__ + dc.l exc__, exc__, exc__, exc__, exc__, exc__, exc__, exc__ + dc.l exc__, exc__, exc__, exc__, exc__, exc__, exc__, exc__ + + .ascii "SEGA EVERDRIVE " + .ascii "MEGA-ED SDRAM vs STOP " + .ascii "MEGA-ED SDRAM vs STOP " + .ascii "GM 00000000-00" + .byte 0x00,0x00 + .ascii "JD " + .byte 0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00 + .byte 0x00,0xff,0x00,0x00,0xff,0xff,0xff,0xff + .ascii " " + .ascii " " + .ascii " " + .ascii "JUE " + +RST: + move.w #0x2700, %sr +/* magic ED app init */ + move.w #0x0000, (0xA13006) + jmp init_ed.l +init_ed: + move.w #0x210f, (0xA13006) + move.l #HBL, (0x70) + move.l #VBL, (0x78) + + moveq #0, %d0 + movea.l %d0, %a7 + move %a7, %usp + bra main + +HBL: +VBL: +exc__: + rte + +# vim:filetype=asmM68k:ts=4:sw=4:expandtab diff --git a/megaed-sv/Makefile b/megaed-sv/Makefile new file mode 100644 index 0000000..24f0965 --- /dev/null +++ b/megaed-sv/Makefile @@ -0,0 +1,33 @@ +CROSS = m68k-elf- +CC = $(CROSS)gcc +AS = $(CROSS)as +LD = $(CROSS)ld +OBJCOPY = $(CROSS)objcopy + +ASFLAGS += -m68000 --register-prefix-optional --bitwise-or -pic +ASFLAGS_CC += -Wa,-m68000 -Wa,--register-prefix-optional -Wa,--bitwise-or -Wa,-pic +CFLAGS += -Wall -g -O1 -m68000 -fomit-frame-pointer +LDLIBS += $(shell $(CC) -print-file-name=libgcc.a) + +TARGET = megaedsv +OBJS = sega_gcc.o main.o asmtools.o + +all: $(TARGET).bin + +$(TARGET).elf: $(OBJS) + $(LD) -o $@ -Ted_app.ld -Map $(TARGET).map $^ $(LDLIBS) + +$(TARGET)_e.bin: $(TARGET).bin + dd if=/dev/zero of=$@ bs=1M count=1 + dd if=$^ of=$@ bs=1M seek=1 + dd if=$^ of=$@ conv=notrunc + +clean: + $(RM) $(TARGET).bin $(OBJS) $(TARGET).elf $(TARGET).map + + +%.bin: %.elf + $(OBJCOPY) -I elf32-m68k -O binary $^ $@ + +%.o: %.S + $(CC) -c -o $@ $^ $(ASFLAGS_CC) diff --git a/megaed-sv/asmtools.h b/megaed-sv/asmtools.h new file mode 100644 index 0000000..ff3c42b --- /dev/null +++ b/megaed-sv/asmtools.h @@ -0,0 +1,5 @@ +void read_joy_responses(u8 resp[8*5]); +void test_joy_read_log(u8 *dest, int size, int do_sync); +void test_joy_read_log_vsync(u8 *dest, int size); +void test_byte_write(u8 *dest, int size, int seed); +void run_game(u16 mapper, int tas_sync); diff --git a/megaed-sv/asmtools.s b/megaed-sv/asmtools.s new file mode 100644 index 0000000..dc75b6c --- /dev/null +++ b/megaed-sv/asmtools.s @@ -0,0 +1,414 @@ +# Assemble with gas +# --register-prefix-optional --bitwise-or + +.macro ldarg arg, stacksz, reg + move.l (4 + \arg * 4 + \stacksz)(%sp), \reg +.endm + + +.global read_joy_responses /* u8 *rbuf */ +read_joy_responses: + ldarg 0, 0, a1 + movem.l d2-d7, -(sp) + movea.l #0xa10003, a0 + move.b #0x40, (6,a0) + move.b #0x40, (a0) + +.macro one_test val + move.l #100/12-1, d0 +0: + dbra d0, 0b + move.b \val, d0 + move.b d0, (a0) + move.b (a0), d0 + move.b (a0), d1 + move.b (a0), d2 + move.b (a0), d3 + move.b (a0), d4 + move.b (a0), d5 + move.b (a0), d6 + move.b (a0), d7 + move.b d0, (a1)+ + move.b d1, (a1)+ + move.b d2, (a1)+ + move.b d3, (a1)+ + move.b d4, (a1)+ + move.b d5, (a1)+ + move.b d6, (a1)+ + move.b d7, (a1)+ +.endm + + move.w #0x2700, sr + one_test #0x00 + one_test #0x40 + one_test #0x00 + one_test #0x40 + one_test #0x00 + move.w #0x2000, sr + movem.l (sp)+, d2-d7 + rts + + +/* expects: + * a0 = #0xa10003 + * d0 = #0 + * d1 = #0x40 + * trashes d2, d3 + */ +sync_with_teensy: +0: /* wait for special code */ + move.b d1, (a0) + move.b (a0), d2 + move.b d0, (a0) + move.b (a0), d3 + and.b #0x3f, d2 + cmp.b d2, d3 + bne 0b + cmp.b #0x25, d2 + bne 0b + +0: /* wait for special code to end */ + cmp.b (a0), d2 + beq 0b + + move.b d1, (a0) + move.l #8000000/50/18, d2 + +0: /* wait enough for teensy to setup it's stuff */ + subq.l #1, d2 /* 8 */ + bgt.s 0b /* 10 */ + + rts + + +.macro t_nop + /* + * when communicating with 3.3V teensy: + * - no nops: see old value on multiple pins randomly + * - 1 nop: only TR often shows old value + * - 2 nops: ? + */ + nop + nop +.endm + + +.global test_joy_read_log /* u8 *dest, int size, int do_sync */ +test_joy_read_log: + ldarg 0, 0, a1 + ldarg 1, 0, d0 + ldarg 2, 0, d1 + movem.l d2-d7, -(sp) + movea.l #0xa10003, a0 + move.l d0, d7 + move.l d1, d6 + + moveq.l #0, d0 + move.l #0x40, d1 + move.b d1, (6,a0) + move.b d1, (a0) + + tst.l d6 + beq.s 2f + bsr sync_with_teensy + +2: /* save data */ + move.b d0, (a0) + t_nop + move.b (a0), d2 + move.b d1, (a0) + t_nop + move.b (a0), d3 + move.b d0, (a0) + t_nop + move.b (a0), d4 + move.b d1, (a0) + t_nop + move.b (a0), d5 +.if 0 + /* broken on Mega-ED v9?? */ + move.b d2, (a1)+ + move.b d3, (a1)+ + move.b d4, (a1)+ + move.b d5, (a1)+ +.else + lsl.w #8, d2 + move.b d3, d2 + move.w d2, (a1)+ + lsl.w #8, d4 + move.b d5, d4 + move.w d4, (a1)+ +.endif + + /* delay for teensy, 128 not enough.. */ + move.l #256, d2 +0: + dbra d2, 0b + + subq.l #4, d7 + bgt.s 2b + + movem.l (sp)+, d2-d7 + rts + + +.global test_joy_read_log_vsync /* u8 *dest, int size */ +test_joy_read_log_vsync: + ldarg 0, 0, a1 + ldarg 1, 0, d0 + movem.l d2-d7/a2, -(sp) + movea.l #0xa10003, a0 + movea.l #0xc00005, a2 + move.l d0, d7 + + move.l #0x40, d1 + moveq.l #0, d0 + move.b d1, (6,a0) + move.b d1, (a0) + + bsr sync_with_teensy + +2: /* save data */ + move.b d0, (a0) + move.b (a0), d2 + move.b d1, (a0) + move.b (a0), d3 + move.b d2, (a1)+ + move.b d3, (a1)+ + + /* wait for next vsync */ + moveq.l #3, d2 +0: + btst d2, (a2) + bne.s 0b +0: + btst d2, (a2) + beq.s 0b + + subq.l #2, d7 + bgt.s 2b + + movem.l (sp)+, d2-d7/a2 + rts + + +.global test_byte_write /* u8 *dest, int size, int seed */ +test_byte_write: + ldarg 0, 0, a0 + ldarg 1, 0, d0 + ldarg 2, 0, d1 + movem.l d2-d7, -(sp) + + move.l a0, a1 + add.l d0, a1 + move.l d1, d7 +0: + move.b d7, d0 + addq.b #1, d7 + move.b d7, d1 + addq.b #1, d7 + move.b d7, d2 + addq.b #1, d7 + move.b d7, d3 + addq.b #1, d7 + move.b d7, d4 + addq.b #1, d7 + move.b d7, d5 + addq.b #1, d7 + move.b d7, d6 + addq.b #1, d7 + + move.b d0, (a0)+ + move.b d1, (a0)+ + move.b d2, (a0)+ + move.b d3, (a0)+ + move.b d4, (a0)+ + move.b d5, (a0)+ + move.b d6, (a0)+ + move.b d7, (a0)+ + addq.b #1, d7 + cmp.l a1, a0 + blt.s 0b + + movem.l (sp)+, d2-d7 + rts + + +.global run_game /* u16 mapper, int tas_sync */ +run_game: + move.w #0x2700, sr + ldarg 0, 0, d7 + ldarg 1, 0, d6 + movea.l #0xa10000, a6 + movea.l #0xc00000, a5 + movea.l #0xc00005, a4 + movea.l #0xc00004, a3 + moveq.l #0x00, d0 + move.b #0x40, d1 /* d2 is tmp */ + move.b #0xff, d3 /* d4 is temp */ + moveq.l #0x00, d5 /* progress cnt */ + movea.l d0, a7 + move.b d1, (0x09,a6) /* CtrlA */ + move.b d0, (0x0b,a6) /* CtrlB */ + move.b d0, (0x0d,a6) /* CtrlC */ + move.b d0, (0x13,a6) /* S-CtrlA */ + move.b d3, (0x0f,a6) /* TxDataA */ + move.b d0, (0x19,a6) /* S-CtrlB */ + move.b d3, (0x15,a6) /* TxDataB */ + move.b d0, (0x1f,a6) /* S-CtrlC */ + move.b d3, (0x1b,a6) /* TxDataC */ + + move.w #0xcbaf, (0xA13006) /* some scratch area */ + + move.l #0xff0000, a1 + move.l #0x10000/4/4-1, d2 +0: + move.l d0, (a1)+ + move.l d0, (a1)+ + move.l d0, (a1)+ + move.l d0, (a1)+ + dbra d2, 0b + + lea (run_game_r,pc), a0 + move.l #0xffff80, a1 + move.l #(run_game_r_end - run_game_r)/2-1, d2 +0: + move.w (a0)+, (a1)+ + dbra d2, 0b + + tst.l d6 + beq.s sync_hvc + + movea.l #0xa10003, a0 + bsr sync_with_teensy /* trashes d3 */ + move.l d0, (-4,a7) + +sync_hvc: + addq.l #1, d6 /* attempt counter */ + + /* set up for progress vram write (x,y - tile #) */ + /* GFX_WRITE_VRAM_ADDR(0xc000 + (x + 64 * y) * 2) */ + /* d = d5 + '0' - 32 + 0xB000/32 - 128 = d5 + 0x510 */ + move.l #(0x40000003 | ((36 + 64*1) << 17)), (a3) + add.w #0x510, d5 + move.w d5, (a5) + move.w #('/'+0x4e0), (a5) + move.w #('4'+0x4e0), (a5) + + lea hexchars, a1 + move.l #(0x40000003 | ((31 + 64*2) << 17)), (a3) + moveq.l #8-1, d5 +0: + rol.l #4, d3 + move.b d3, d4 + and.l #0x0f, d4 + move.b (d4,a1), d4 + add.w #0x4e0, d4 + move.w d4, (a5) + dbra d5, 0b + + movea.l #0xc00008, a0 + movea.l #0x3ff000, a1 + movea.l #0xffffe0, a2 + + /* wait for active display */ + moveq.l #3, d2 +0: + btst d2, (a4) /* 8 */ + beq.s 0b /* 10 */ +0: + btst d2, (a4) + bne.s 0b + + /* flood the VDP FIFO */ +.rept 5 + move.w d0, (a5) +.endr + + /* these seem stable for both 50Hz/60Hz */ + move.l (a0), (a1)+ /* #0xff07ff09 */ + move.l (a0), (a1)+ /* #0xff00ff11 */ + move.l (a0), (a1)+ /* #0xff18ff1a */ + move.l (a0), (a1)+ /* #0xff21ff23 */ + move.l (a0), (a1)+ /* #0xff2aff28 */ + move.l (a0), (a1)+ /* #0xff33ff34 */ + move.l (a0), (a1)+ /* #0xff3cff3e */ + move.l (a0), (a1)+ /* #0xff45ff47 */ + + /* as long as exactly 8 or more RAM writes are performed here, */ + /* after multiple tries RAM refresh somehow eventually syncs */ + /* after cold boot, only 50Hz syncs to always same values though, */ + /* so values below are 50Hz */ + move.l (a0), (a2)+ /* #0xff4eff4f */ + move.l (a0), (a2)+ /* #0xff58ff59 */ + move.l (a0), (a2)+ /* #0xff60ff62 */ + move.l (a0), (a2)+ /* #0xff69ff6b */ + move.l (a0), (a2)+ /* #0xff72ff74 */ + move.l (a0), (a2)+ /* #0xff7bff7c */ + move.l (a0), (a2)+ /* #0xff83ff85 */ + move.l (a0), (a2)+ /* #0xff8eff8f */ + + sub.l #4*8, a1 + sub.l #4*8, a2 + + moveq.l #1, d5 + move.l (0x00,a1), d3 + cmp.l #0xff07ff09, d3 + bne.w sync_hvc + + moveq.l #2, d5 + move.l (0x04,a1), d3 + cmp.l #0xff00ff11, d3 /* mystery value */ + bne.w sync_hvc + + moveq.l #3, d5 + move.l (0x1c,a1), d3 + cmp.l #0xff45ff47, d3 + bne.w sync_hvc + + btst.b #6, (0xa10001) + bne.s sync_hvc_50hz + +sync_hvc_60hz: + /* unable to get stable RAM between cold boots :( */ + moveq.l #4, d5 + move.l (0x1c,a2), d3 + cmp.l #0xff8dff8f, d3 /* unstable */ + beq.s sync_hvc_end + cmp.l #0xff8cff8e, d3 /* stable? */ + beq.s sync_hvc_end + cmp.l #0xff8eff90, d3 + beq.s sync_hvc_end + bra.w sync_hvc + +sync_hvc_50hz: + moveq.l #4, d5 + move.l (0x1c,a2), d3 + cmp.l #0xff8eff8f, d3 /* RAM */ + bne.w sync_hvc + +sync_hvc_end: + movea.l d0, a0 + movea.l #0xA13000, a1 + + move.b d0, (0x09,a6) /* CtrlA */ + move.b d1, (0x03,a6) + + jmp 0xffff80 + +run_game_r: + move.w #0x3210, (0x06,a1) /* 0xA13006 */ + move.w d7, (0x10,a1) /* 0xA13010 */ + move.w d0, (a1) /* 0xA13000 */ + + move.l (a0)+, a7 + move.l (a0), a0 + + jmp (a0) +run_game_r_end: + +hexchars: + dc.b '0','1','2','3','4','5','6','7' + dc.b '8','9','a','b','c','d','e','f' + +# vim:filetype=asmM68k:ts=4:sw=4:expandtab diff --git a/megaed-sv/ed_app.ld b/megaed-sv/ed_app.ld new file mode 100644 index 0000000..bd40362 --- /dev/null +++ b/megaed-sv/ed_app.ld @@ -0,0 +1,116 @@ +OUTPUT_ARCH(m68k) +SEARCH_DIR(.) +/*GROUP(-lbcc -lc -lgcc)*/ +__DYNAMIC = 0; + +/* + * Setup the memory map of the SEGA Genesis. + * stack grows down from high memory. + * + * The memory map look like this: + * +--------------------+ <- low memory + * | .text | + * | _etext | + * | ctor list | the ctor and dtor lists are for + * | dtor list | C++ support + * +--------------------+ + * | .data | initialized data goes here + * | _edata | + * +--------------------+ + * | .bss | + * | __bss_start | start of bss, cleared by crt0 + * | _end | start of heap, used by sbrk() + * +--------------------+ + * . . + * . . + * . . + * | __stack | top of stack + * +--------------------+ + */ +MEMORY +{ + rom : ORIGIN = 0x00100000, LENGTH = 0x00300000 + ram : ORIGIN = 0x00ff0100, LENGTH = 0x0000FF00 +} + +/* + * allocate the stack to be at the top of memory, since the stack + * grows down + */ + +PROVIDE (__stack = 0x00fffff0); + +/* + * Initalize some symbols to be zero so we can reference them in the + * crt0 without core dumping. These functions are all optional, but + * we do this so we can have our crt0 always use them if they exist. + * This is so BSPs work better when using the crt0 installed with gcc. + * We have to initalize them twice, so we cover a.out (which prepends + * an underscore) and coff object file formats. + */ +PROVIDE (hardware_init_hook = 0); +PROVIDE (_hardware_init_hook = 0); +PROVIDE (software_init_hook = 0); +PROVIDE (_software_init_hook = 0); + +SECTIONS +{ + .text 0x00100000: + { + *(.text) + . = ALIGN(0x4); + __CTOR_LIST__ = .; + LONG((__CTOR_END__ - __CTOR_LIST__) / 4 - 2) + *(.ctors) + LONG(0) + __CTOR_END__ = .; + __DTOR_LIST__ = .; + LONG((__DTOR_END__ - __DTOR_LIST__) / 4 - 2) + *(.dtors) + LONG(0) + __DTOR_END__ = .; + *(.rodata*) + *(.gcc_except_table) + + __INIT_SECTION__ = . ; + *(.init) + SHORT (0x4e75) /* rts */ + + __FINI_SECTION__ = . ; + *(.fini) + SHORT (0x4e75) /* rts */ + + _etext = .; + *(.lit) + } > rom + + .data 0xff0100 : + { + *(.shdata) + *(.data) + _edata = .; + } > ram + + /* .bss 0xff0100 : */ + .bss BLOCK (0x4) : + { + __bss_start = . ; + *(.shbss) + *(.bss) + *(COMMON) + *(.eh_fram) + *(.eh_frame) + _end = ALIGN (0x8); + __end = _end; + } > ram + + .stab 0 (NOLOAD) : + { + *(.stab) + } + + .stabstr 0 (NOLOAD) : + { + *(.stabstr) + } +} diff --git a/megaed-sv/edos.h b/megaed-sv/edos.h new file mode 100644 index 0000000..58025e3 --- /dev/null +++ b/megaed-sv/edos.h @@ -0,0 +1,153 @@ +/* + * File: edos.h + * Author: krik + * + * Created on 29 Ìàðò 2012 ã., 1:29 + */ + +#ifndef _EDOS_H +#define _EDOS_H + +//#include "segalib.h" + +/* + * saddr: address in sectors + * slen: lenght in sectors + * wr_slen: how many sectors will be written + * sector size 512 bytes + * dma reading of usb and SD available only if data destination located in rom area (0-0x3ffffff). dma reading not available for genesis ram + * destination address for dma reading must be aligned to 512b + * one mbyte of sdram can be mapped to one of four banks in rom space. osSetMemMap(u16) can be used for mapping configuration. + * os code located in last mbyte of sdram and should be mapped in bank 0 + * user code located in begin of sdram. default mapping 0x210f means that end of sdram (OS) mapped to area 0-0x0fffff, first mbyte of user code mapped to 0x100000-0x1fffff, + * memory configuration: + * genesis address: 0x000000-0x0fffff, physical sdram address: 0xf00000-0xffffff OS + * genesis address: 0x100000-0x3fffff, physical sdram address: 0x000000-0x2fffff user code (current application) + * 0xff0000-0xff00ff OS dma code + * first 256bytes of genesis ram must be reserved for OS + * */ + + +#define MEM_ERR_SPI_RD_TIMEOUT 120 + +#define ERR_FILE_TOO_BIG 140 +#define ERR_WRON_OS_SIZE 142 +#define ERR_OS_VERIFY 143 +#define ERR_OS_VERIFY2 144 +#define ERR_BAD_DMA_ADDRESS 145 +#define ERR_MUST_NOT_RET 146 + +//100 - 119 fat errors +#define FAT_ERR_NOT_EXIST 100 +#define FAT_ERR_EXIST 101 +#define FAT_ERR_NAME 102 +#define FAT_ERR_OUT_OF_FILE 103 +#define FAT_ERR_BAD_BASE_CLUSTER 104; +#define FAT_ERR_NO_FRE_SPACE 105 +#define FAT_ERR_NOT_FILE 106 +#define FAT_ERR_FILE_MODE 107 +#define FAT_ERR_ROT_OVERFLOW 108 +#define FAT_ERR_OUT_OF_TABLE 109 +#define FAT_ERR_INIT 110 +#define FAT_LFN_BUFF_OVERFLOW 111 +#define FAT_DISK_NOT_READY 112 +#define FAT_ERR_SIZE 113 +#define FAT_ERR_RESIZE 114 + + +#define DISK_ERR_INIT 50 +#define DISK_ERR_RD1 62 +#define DISK_ERR_RD2 63 + +#define DISK_ERR_WR1 64 +#define DISK_ERR_WR2 65 +#define DISK_ERR_WR3 66 +#define DISK_ERR_WR4 67 +#define DISK_ERR_WR5 68 + +typedef struct { + u32 entry_cluster; + u32 size; + u32 hdr_sector; + u16 hdr_idx; + u8 name[256]; + u16 is_dir; +} FatFullRecord; + +typedef struct { + u8(*diskWrite)(u32 saddr, u8 *buff, u16 slen); + u8(*diskRead)(u32 saddr, void *buff, u16 slen);//*dst must be alligned to 512bytes and be in range 0x100000-0x3fffff. *dst can be located in genesis ram also, but transfer will be slow in this case + u8(*usbReadByte)();//loop inside of function waiting until usbRdReady != 0 + void (*usbWriteByte)(u8 dat);//loop inside of function waiting until usbWrReady != 0 + u8(*usbReadDma)(u16 *dst, u16 slen);//*dst must be alligned to 512bytes and be in range 0x100000-0x3fffff + u8(*usbReadPio)(u16 *dst, u16 slen); + u8(*usbRdReady)(); //return 1 if some data comes from pc + u8(*usbWrReady)(); //return 1 usb ready to send byte + void (*osSetMemMap)(u16 map); //memoty configuration 4x1Mb + u16(*osGetOsVersion)(); + u16(*osGetFirmVersion)(); + void (*osGetSerial)(u32 * buff); // 8bytes uniq serial number + void (*VDP_setReg)(u8 reg, u8 value);//os vdp functions should be used, otherwise system may hang while udb/sd dma + void (*VDP_vintOn)(); + void (*VDP_vintOff)(); + void (*memInitDmaCode)();//copy dma routine to genesis ram + u8(*fatReadDir)(FatFullRecord * frec);//get next record in current dir + void(*fatOpenDir)(u32 entry_cluster);//arg is entry cluster ot dir or 0. zero arg means that need to open root dir + u8(*fatOpenFileByeName)(u8 *name, u32 wr_slen);//wr_slen write len, or 0 if reading + u8(*fatOpenFile)(FatFullRecord *rec, u32 wr_slen);//wr_slen is write len, or 0 if reading + u8(*fatReadFile)(void *dst, u32 slen); + u8(*fatWriteFile)(void *src, u32 slen); + u8(*fatCreateRecIfNotExist)(u8 *name, u8 is_dir); + u8(*fatSkipSectors)(u32 slen); +} OsRoutine; + + +extern OsRoutine *ed_os; +void edInit(); + + +//stereo dac. 8bit for each channel. +//any writing to this port enables dac output, any reading from this port disables dac output. +#define REG_DAC *((volatile u16*) (0xA1300E)) + + +//stuff for direct access to usb and spi. not recommended for use. OS function should be used for best compatibility +#define _SPI_SS 0 +#define _SPI_FULL_SPEED 1 +#define _SPI_SPI16 2 +#define _SPI_AREAD 3 + +//spi port (sd interface) +#define SPI_PORT *((volatile u16*) (0xA13000)) +#define SPI_CFG_PORT *((volatile u16*) (0xA13002)) + +//16bit or 8bit spi mode +#define SPI16_ON SPI_CFG_PORT |= (1 << _SPI_SPI16) +#define SPI16_OFF SPI_CFG_PORT &= ~(1 << _SPI_SPI16) + +//spi autoread. means that not need to write something to spi port before than read +#define SPI_AR_ON SPI_CFG_PORT |= (1 << _SPI_AREAD) +#define SPI_AR_OFF SPI_CFG_PORT &= ~(1 << _SPI_AREAD) + +//spi chip select +#define SPI_SS_OFF SPI_CFG_PORT |= (1 << _SPI_SS) +#define SPI_SS_ON SPI_CFG_PORT &= ~(1 << _SPI_SS) + +//spi speed. low speed need only for sd init +#define SPI_HI_SPEED_ON SPI_CFG_PORT |= (1 << _SPI_FULL_SPEED) +#define SPI_HI_SPEED_OFF SPI_CFG_PORT &= ~(1 << _SPI_FULL_SPEED) + +//usb-serial port +#define FIFO_PORT *((volatile u16*) (0xA1300A)) + +//spi and usb state +#define STATE_PORT *((volatile u16*) (0xA1300C)) +#define _STATE_SPI_READY 0 +#define _STATE_FIFO_WR_READY 1 +#define _STATE_FIFO_RD_READY 2 +#define IS_FIFO_RD_READY (STATE_PORT & (1 << _STATE_FIFO_RD_READY)) +#define IS_FIFO_WR_READY (STATE_PORT & (1 << _STATE_FIFO_WR_READY)) + + +#endif /* _EDOS_H */ + diff --git a/megaed-sv/main.c b/megaed-sv/main.c new file mode 100644 index 0000000..a0741b6 --- /dev/null +++ b/megaed-sv/main.c @@ -0,0 +1,696 @@ +#include +#include + +#define u8 unsigned char +#define u16 unsigned short +#define u32 unsigned int + +#define noinline __attribute__((noinline)) +#define _packed __attribute__((packed)) + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) + +#include "edos.h" +#include "asmtools.h" + +extern u16 start_hvc; + +#define GFX_DATA_PORT 0xC00000 +#define GFX_CTRL_PORT 0xC00004 + +#define TILE_MEM_END 0xB000 + +#define FONT_LEN 128 +#define TILE_FONT_BASE (TILE_MEM_END / 32 - FONT_LEN) + +/* note: using ED menu's layout here.. */ +#define WPLANE (TILE_MEM_END + 0x0000) +#define HSCRL (TILE_MEM_END + 0x0800) +#define SLIST (TILE_MEM_END + 0x0C00) +#define APLANE (TILE_MEM_END + 0x1000) +#define BPLANE (TILE_MEM_END + 0x3000) + +#define read8(a) \ + *((volatile u8 *) (a)) +#define read16(a) \ + *((volatile u16 *) (a)) +#define read32(a) \ + *((volatile u32 *) (a)) +#define write8(a, d) \ + *((volatile u8 *) (a)) = (d) +#define write16(a, d) \ + *((volatile u16 *) (a)) = (d) +#define write32(a, d) \ + *((volatile u32 *) (a)) = (d) + +#define GFX_WRITE_VRAM_ADDR(adr) \ + (((0x4000 | ((adr) & 0x3FFF)) << 16) | ((adr) >> 14) | 0x00) +#define GFX_WRITE_VSRAM_ADDR(adr) \ + (((0x4000 | ((adr) & 0x3FFF)) << 16) | ((adr) >> 14) | 0x10) + +enum { + VDP_MODE1 = 0x00, + VDP_MODE2 = 0x01, + VDP_BACKDROP = 0x07, + VDP_MODE3 = 0x0b, + VDP_MODE4 = 0x0c, + VDP_AUTOINC = 0x0f, + VDP_SCROLLSZ = 0x10, +}; + +/* cell counts */ +#define LEFT_BORDER 1 /* lame TV */ +#define PLANE_W 64 +#define PLANE_H 32 +#define CSCREEN_H 28 + +static noinline void VDP_drawTextML(const char *str, u16 plane_base, + u16 x, u16 y) +{ + const u8 *src = (const u8 *)str; + u16 basetile = 0; + int max_len = 40 - LEFT_BORDER; + int len; + u32 addr; + + x += LEFT_BORDER; + + for (len = 0; str[len] && len < max_len; len++) + ; + if (len > (PLANE_W - x)) + len = PLANE_W - x; + + addr = plane_base + ((x + (PLANE_W * y)) << 1); + write32(GFX_CTRL_PORT, GFX_WRITE_VRAM_ADDR(addr)); + + while (len-- > 0) { + write16(GFX_DATA_PORT, + basetile | ((*src++) - 32 + TILE_FONT_BASE)); + } +} + +static int printf_ypos; + +static void printf_line(int x, const char *buf) +{ + u32 addr; + int i; + + VDP_drawTextML(buf, APLANE, x, printf_ypos++ & (PLANE_H - 1)); + + if (printf_ypos >= CSCREEN_H) { + /* clear next line */ + addr = APLANE; + addr += (PLANE_W * (printf_ypos & (PLANE_H - 1))) << 1; + write32(GFX_CTRL_PORT, GFX_WRITE_VRAM_ADDR(addr)); + for (i = 0; i < 40 / 2; i++) + write32(GFX_DATA_PORT, 0); + + /* scroll plane */ + write32(GFX_CTRL_PORT, GFX_WRITE_VSRAM_ADDR(0)); + write16(GFX_DATA_PORT, (printf_ypos - CSCREEN_H + 1) * 8); + } +} + +#define PRINTF_LEN 40 + +static noinline int printf(const char *fmt, ...) +{ + static const char hexchars[] = "0123456789abcdef"; + static int printf_xpos; + char c, buf[PRINTF_LEN + 11 + 1]; + const char *s; + va_list ap; + int ival; + u32 uval; + int d = 0; + int i, j; + + va_start(ap, fmt); + for (d = 0; *fmt; ) { + int prefix0 = 0; + int fwidth = 0; + + c = *fmt++; + if (d < PRINTF_LEN) + buf[d] = c; + + if (c != '%') { + if (c == '\n') { + buf[d] = 0; + printf_line(printf_xpos, buf); + d = 0; + printf_xpos = 0; + continue; + } + d++; + continue; + } + if (d >= PRINTF_LEN) + continue; + + if (*fmt == '0') { + prefix0 = 1; + fmt++; + } + + while ('1' <= *fmt && *fmt <= '9') { + fwidth = fwidth * 10 + *fmt - '0'; + fmt++; + } + + switch (*fmt++) { + case '%': + d++; + break; + case 'd': + case 'i': + ival = va_arg(ap, int); + if (ival < 0) { + buf[d++] = '-'; + ival = -ival; + } + for (i = 1000000000; i >= 10; i /= 10) + if (ival >= i) + break; + for (; i >= 10; i /= 10) { + buf[d++] = '0' + ival / i; + ival %= i; + } + buf[d++] = '0' + ival; + break; + case 'x': + uval = va_arg(ap, int); + while (fwidth > 1 && uval < (1 << (fwidth - 1) * 4)) { + buf[d++] = prefix0 ? '0' : ' '; + fwidth--; + } + for (j = 1; j < 8 && uval >= (1 << j * 4); j++) + ; + for (j--; j >= 0; j--) + buf[d++] = hexchars[(uval >> j * 4) & 0x0f]; + break; + case 's': + s = va_arg(ap, char *); + while (*s && d < PRINTF_LEN) + buf[d++] = *s++; + break; + default: + // don't handle, for now + d++; + va_arg(ap, void *); + break; + } + } + buf[d] = 0; + va_end(ap); + + if (d != 0) { + // line without \n + VDP_drawTextML(buf, APLANE, printf_xpos, + printf_ypos & (PLANE_H - 1)); + printf_xpos += d; + } + + return d; // wrong.. +} + +static u8 gethex(char c) +{ + if ('0' <= c && c <= '9') + return c - '0'; + if ('a' <= c && c <= 'f') + return c - 'a' + 10; + if ('A' <= c && c <= 'F') + return c - 'A' + 10; + return 0; +} + +static const char *exc_names[] = { + NULL, + NULL, + "Bus Error", + "Address Error", + "Illegal Instruction", + "Zero Divide", + "CHK Instruction", + "TRAPV Instruction", + "Privilege Violation", /* 8 8 */ + "Trace", + "Line 1010 Emulator", + "Line 1111 Emulator", + NULL, + NULL, + NULL, + "Uninitialized Interrupt", + NULL, /* 10 16 */ + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + "Spurious Interrupt", /* 18 24 */ + "l1 irq", + "l2 irq", + "l3 irq", + "l4 irq", + "l5 irq", + "l6 irq", + "l7 irq", +}; + +struct exc_frame { + u32 dr[8]; + u32 ar[8]; + u16 ecxnum; // from handler + union { + struct { + u16 sr; + u32 pc; + } g _packed; + struct { + u16 fc; + u32 addr; + u16 ir; + u16 sr; + u32 pc; + } bae _packed; // bus/address error frame + }; +} _packed; + +int xtttt(void) { return sizeof(struct exc_frame); } + +void exception(const struct exc_frame *f) +{ + int i; + + while (read16(GFX_CTRL_PORT) & 2) + ; + write16(GFX_CTRL_PORT, 0x8000 | (VDP_MODE1 << 8) | 0x04); + write16(GFX_CTRL_PORT, 0x8000 | (VDP_MODE2 << 8) | 0x44); + /* adjust scroll */ + write32(GFX_CTRL_PORT, GFX_WRITE_VSRAM_ADDR(0)); + write16(GFX_DATA_PORT, + printf_ypos >= CSCREEN_H ? + (printf_ypos - CSCREEN_H + 1) * 8 : 0); + + printf("exception %i ", f->ecxnum); + if (f->ecxnum < ARRAY_SIZE(exc_names) && exc_names[f->ecxnum] != NULL) + printf("(%s)", exc_names[f->ecxnum]); + if (f->ecxnum < 4) + printf(" (%s)", (f->bae.fc & 0x10) ? "r" : "w"); + printf(" \n"); + + if (f->ecxnum < 4) { + printf(" PC: %08x SR: %04x \n", f->bae.pc, f->bae.sr); + printf("addr: %08x IR: %04x FC: %02x \n", + f->bae.addr, f->bae.ir, f->bae.fc); + } + else { + printf(" PC: %08x SR: %04x \n", f->g.pc, f->g.sr); + } + for (i = 0; i < 8; i++) + printf(" D%d: %08x A%d: %08x \n", i, f->dr[i], i, f->ar[i]); + printf(" \n"); +} + +void vbl(void) +{ +} + +static int usb_read_while_ready(OsRoutine *ed, + void *buf_, unsigned int maxlen) +{ + u8 *buf = buf_; + unsigned int r = 0; + + while (ed->usbRdReady() && r < maxlen) + buf[r++] = ed->usbReadByte(); + + return r; +} + +static int usb_read(OsRoutine *ed, void *buf_, unsigned int maxlen) +{ + u8 *buf = buf_; + unsigned int r = 0; + + while (r < maxlen) + buf[r++] = ed->usbReadByte(); + + return r; +} + +static int usb_write(OsRoutine *ed, const void *buf_, unsigned int maxlen) +{ + const u8 *buf = buf_; + unsigned int r = 0; + + while (r < maxlen) + ed->usbWriteByte(buf[r++]); + + return r; +} + +/* + * TH = 1 : ?1CBRLDU 3-button pad return value (not read) + * TH = 0 : ?0SA00DU 3-button pad return value + * TH = 1 : ?1CBRLDU 3-button pad return value + * TH = 0 : ?0SA0000 D3-0 are forced to '0' + * TH = 1 : ?1CBMXYZ Extra buttons returned in D3-0 + * TH = 0 : ?0SA1111 D3-0 are forced to '1' + */ +static void test_joy_latency(int *min_out, int *max_out) +{ + u8 rbuf[8 * 6]; + int min = 8; + int max = 0; + int i, v, b, e; + + for (i = 0; i < 64; i++) { + read_joy_responses(rbuf); + + for (b = 0; b < 8 * 4; b++) { + v = b & 7; + e = (b & 0x08) ? 0x0c : 0; + if ((rbuf[b] & 0x0c) == e) { + if (v < min) + min = v; + } + else if (v > max) + max = v; + } + } + + /* print out the last test */ + for (b = 0; b < 8 * 5; b++) { + printf(" %02x", rbuf[b]); + if ((b & 7) == 7) + printf("\n"); + } + printf("\n"); + + *min_out = min; + *max_out = max; +} + +static int do_test(OsRoutine *ed, u8 b3) +{ + int min = 0, max = 0; + int i, t, len, seed; + u8 *p, v; + + switch (b3) + { + case '0': + printf("reading..\n"); + test_joy_read_log((void *)0x200000, 0x20000, 1); + //test_joy_read_log((void *)0xff0200, 0x0f000, 1); + printf("done\n"); + return 0; + case '1': + printf("reading w/vsync..\n"); + test_joy_read_log_vsync((void *)0x200000, 3600 * 2); + printf("done\n"); + return 0; + case '2': + case '3': + printf("3btn_idle test..\n"); + p = (void *)0x200000; + len = 0x20000; + test_joy_read_log(p, len, b3 == '3'); + for (i = 0; i < len; i++) { + static const u8 e[2] = { 0x33, 0x7f }; + v = e[i & 1]; + if (p[i] != v) + printf("%06x: bad: %02x %02x\n", &p[i], p[i], v); + } + printf("done\n"); + return 0; + case '4': + printf("3btn_idle data test..\n"); + p = (void *)0x200000; + len = 0x20000; + for (i = 0; i < len; i++) { + static const u8 e[2] = { 0x33, 0x7f }; + v = e[i & 1]; + if (p[i] != v) + printf("%06x: bad: %02x %02x\n", &p[i], p[i], v); + } + printf("done\n"); + return 0; + case '5': + seed = read8(0xC00009); + printf("testing, seed=%02x\n", seed); + p = (void *)0x200000; + len = 0x100000; + test_byte_write(p, len, seed); + for (t = 0; t < 2; t++) { + for (i = 0; i < len; i++) { + v = (u8)(i + seed); + if (p[i] != v) + printf("%06x: bad: %02x %02x\n", &p[i], p[i], v); + } + printf("done (%d)\n", t); + } + return 0; + case 'j': + test_joy_latency(&min, &max); + printf("latency: %d - %d\n\n", min, max); + return 0; + default: + break; + } + + return -1; +} + +static int do_custom(OsRoutine *ed, u8 b3) +{ + struct { + unsigned int addr; + unsigned int size; + } d; + + switch (b3) + { + case 'd': + usb_read(ed, &d, sizeof(d)); + ed->usbWriteByte('k'); + printf("sending %i bytes from %06x..\n", d.size, d.addr); + usb_write(ed, (void *)d.addr, d.size); + printf("done.\n"); + return 1; + default: + break; + } + + return -1; +} + +#define MTYPE_OS 0 +#define MTYPE_MD 1 +#define MTYPE_SSF 2 +#define MTYPE_CD 3 +#define MTYPE_SMS 4 +#define MTYPE_10M 5 +#define MTYPE_32X 6 + +static int do_run(OsRoutine *ed, u8 b3, int tas_sync) +{ + u8 mapper = 0; + + switch (b3) + { + case 's': + mapper = MTYPE_SMS | (7 << 4); + break; + case 'm': + mapper = MTYPE_MD; + break; + case 'o': + mapper = MTYPE_OS; + break; + case 'c': + mapper = MTYPE_CD; + break; + case '3': + mapper = MTYPE_32X; + break; + case 'M': + mapper = MTYPE_10M; + break; + case 'n': + // raw numer: hex XX: mtype | x; + // x: bits [4-7]: SRAM_ON, SRAM_3M_ON, SNAP_SAVE_ON, MKEY + mapper = gethex(ed->usbReadByte()) << 4; + mapper |= gethex(ed->usbReadByte()); + break; + default: + return -1; + } + + printf("syncing and starting mapper %x..\n", mapper); + + while (read16(GFX_CTRL_PORT) & 2) + ; + ed->VDP_setReg(VDP_MODE1, 0x04); + ed->VDP_setReg(VDP_MODE2, 0x44); + + ed->usbWriteByte('k'); + + run_game(mapper, tas_sync); + /* should not get here.. */ + + return -1; +} + +void setup_z80(void) +{ + u8 *mem = (u8 *)0xa00000; + int i; + + write8(0xa11100, 1); + write8(0xa11200, 1); + + while (read8(0xa11100) & 1) + ; + + /* must use byte access */ + for (i = 0x2000; i > 0; i--) + *mem++ = 0; + + /* console starts with reset on, busreq off, + * gens starts with busreq on, keep that for gmv.. */ +} + +int main() +{ + OsRoutine *ed; + u8 buf[16]; + int len; + int i, d, ret; + + ed = (OsRoutine *) *(u32 *)0x1A0; + ed->memInitDmaCode(); + + /* setup VDP */ + while (read16(GFX_CTRL_PORT) & 2) + ; + + ed->VDP_setReg(VDP_MODE1, 0x04); + ed->VDP_setReg(VDP_MODE2, 0x64); + ed->VDP_setReg(VDP_AUTOINC, 2); + ed->VDP_setReg(VDP_SCROLLSZ, 0x01); + + /* clear name tables */ + write32(GFX_CTRL_PORT, GFX_WRITE_VRAM_ADDR(APLANE)); + for (i = 0; i < PLANE_W * PLANE_H / 2; i++) + write32(GFX_DATA_PORT, 0); + + write32(GFX_CTRL_PORT, GFX_WRITE_VRAM_ADDR(BPLANE)); + for (i = 0; i < PLANE_W * PLANE_H / 2; i++) + write32(GFX_DATA_PORT, 0); + + /* scroll planes */ + write32(GFX_CTRL_PORT, GFX_WRITE_VSRAM_ADDR(0)); + write32(GFX_DATA_PORT, 0); + + /* note: relying on ED menu's font setup here.. */ + + printf("\n"); + printf("version: %02x, hvc: %04x %04x\n", + read8(0xa10001), start_hvc, read16(0xc00008)); + printf("ED os/fw: %d/%d\n\n", ed->osGetOsVersion(), + ed->osGetFirmVersion()); + + setup_z80(); + + for (;;) { + if (!ed->usbRdReady()) { + /* note: stop corrupts SDRAM */ + //asm volatile("stop #0x2000"); + asm volatile( + "move.l #1000/10, %0\n" + "0: dbra %0, 0b\n" : "=r" (i) :: "cc"); + continue; + } + + buf[0] = ed->usbReadByte(); + if (buf[0] == ' ') + continue; + if (buf[0] != '*') { + d = 1; + goto bad_input; + } + + /* note: OS uses Twofgsr */ + buf[1] = ed->usbReadByte(); + switch (buf[1]) { + case 'T': + ed->usbWriteByte('k'); + break; + case 'g': + len = ed->usbReadByte() * 128; + printf("loading %d bytes.. ", len * 512); + ed->usbWriteByte('k'); + ed->usbReadDma((void *)0x200000, len); + ed->usbWriteByte('d'); + printf("done\n"); + break; + case 'r': + case 'R': + buf[2] = ed->usbReadByte(); + ret = do_run(ed, buf[2], buf[1] == 'R'); + if (ret != 0) { + d = 3; + goto bad_input; + } + printf("run returned??\n"); + break; + + /* custom */ + case 't': + buf[2] = ed->usbReadByte(); + ret = do_test(ed, buf[2]); + if (ret != 0) { + d = 3; + goto bad_input; + } + ed->usbWriteByte('k'); + break; + case 'x': + buf[2] = ed->usbReadByte(); + ret = do_custom(ed, buf[2]); + if (ret == 1) + break; + if (ret != 0) { + d = 3; + goto bad_input; + } + ed->usbWriteByte('k'); + break; + default: + d = 2; + goto bad_input; + } + + continue; + +bad_input: + ret = usb_read_while_ready(ed, buf + d, sizeof(buf) - d); + buf[d + ret] = 0; + printf("bad cmd: %s\n", buf); + /* consume all remaining data */ + while (ed->usbRdReady()) + usb_read_while_ready(ed, buf, sizeof(buf)); + + ed->usbWriteByte('b'); + } + + return 0; +} + +// vim:ts=4:sw=4:expandtab diff --git a/megaed-sv/sega_gcc.s b/megaed-sv/sega_gcc.s new file mode 100644 index 0000000..897acdf --- /dev/null +++ b/megaed-sv/sega_gcc.s @@ -0,0 +1,222 @@ +exc_tab: + dc.l 0, 0x200, exc02, exc03, exc04, exc05, exc06, exc07 + dc.l exc08, exc09, exc0a, exc0b, exc0c, exc0d, exc0e, exc0f + dc.l exc10, exc11, exc12, exc13, exc14, exc15, exc16, exc17 + dc.l exc18, exc19, exc1a, exc1b, HBL, exc1d, VBL, exc1f + dc.l exc20, exc21, exc22, exc23, exc24, exc25, exc26, exc27 + dc.l exc28, exc29, exc2a, exc2b, exc2c, exc2d, exc2e, exc2f + dc.l exc30, exc31, exc32, exc33, exc34, exc35, exc3e, exc37 + dc.l exc38, exc39, exc3a, exc3b, exc3c, exc3d, exc3e, exc3f + + .ascii "SEGA EVERDRIVE " + .ascii "MEGA-ED host " + .ascii "MEGA-ED host " + .ascii "GM 00000000-00" + .byte 0x00,0x00 + .ascii "JD " + .byte 0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00 + .byte 0x00,0xff,0x00,0x00,0xff,0xff,0xff,0xff + .ascii " " + .ascii " " + .ascii " " + .ascii "JUE " + +RST: + move.w (0xc00008), start_hvc + move.w #0x2700, %sr +/* magic ED app init */ + move.w #0x0000, (0xA13006) + jmp init_ed.l +init_ed: +/* relocate to bank a, so that other ROMs can be loaded */ + move.w #0x0a0f, (0xA13006) + movea.l #0x100000, %a0 + movea.l #0x200000, %a1 + move.l #0x100000/4/4-1, %d0 +0: + move.l (a0)+, (a1)+ + move.l (a0)+, (a1)+ + move.l (a0)+, (a1)+ + move.l (a0)+, (a1)+ + dbra %d0, 0b + + move.w #0x10af, (0xA13006) + + lea exc_tab, %a0 + adda.l #4*2, %a0 + movea.l #4*2, %a1 + move.l #64-2-1, %d0 +0: + move.l (a0)+, (a1)+ + dbra %d0, 0b + + moveq #0, %d0 + movea.l %d0, %a7 + move %a7, %usp + move.w #0x2000, %sr + bra main + +HBL: + rte + +VBL: + movem.l %d0-%d1/%a0-%a1,-(%sp) + jsr vbl + movem.l (%sp)+,%d0-%d1/%a0-%a1 + rte + +pre_exception: + move.w #0x2700, %sr + movem.l %d0-%d7/%a0-%a7,-(%sp) + move.l %sp, %d0 + move.l %d0,-(%sp) + jsr exception +0: + bra 0b + + +* Standard 32X startup code for MD side at 0x3F0 + .org 0x3F0 + + .word 0x287C,0xFFFF,0xFFC0,0x23FC,0x0000,0x0000,0x00A1,0x5128 + .word 0x46FC,0x2700,0x4BF9,0x00A1,0x0000,0x7001,0x0CAD,0x4D41 + .word 0x5253,0x30EC,0x6600,0x03E6,0x082D,0x0007,0x5101,0x67F8 + .word 0x4AAD,0x0008,0x6710,0x4A6D,0x000C,0x670A,0x082D,0x0000 + .word 0x5101,0x6600,0x03B8,0x102D,0x0001,0x0200,0x000F,0x6706 + .word 0x2B78,0x055A,0x4000,0x7200,0x2C41,0x4E66,0x41F9,0x0000 + .word 0x04D4,0x6100,0x0152,0x6100,0x0176,0x47F9,0x0000,0x04E8 + .word 0x43F9,0x00A0,0x0000,0x45F9,0x00C0,0x0011,0x3E3C,0x0100 + .word 0x7000,0x3B47,0x1100,0x3B47,0x1200,0x012D,0x1100,0x66FA + .word 0x7425,0x12DB,0x51CA,0xFFFC,0x3B40,0x1200,0x3B40,0x1100 + .word 0x3B47,0x1200,0x149B,0x149B,0x149B,0x149B,0x41F9,0x0000 + .word 0x04C0,0x43F9,0x00FF,0x0000,0x22D8,0x22D8,0x22D8,0x22D8 + .word 0x22D8,0x22D8,0x22D8,0x22D8,0x41F9,0x00FF,0x0000,0x4ED0 + .word 0x1B7C,0x0001,0x5101,0x41F9,0x0000,0x06BC,0xD1FC,0x0088 + .word 0x0000,0x4ED0,0x0404,0x303C,0x076C,0x0000,0x0000,0xFF00 + .word 0x8137,0x0002,0x0100,0x0000,0xAF01,0xD91F,0x1127,0x0021 + .word 0x2600,0xF977,0xEDB0,0xDDE1,0xFDE1,0xED47,0xED4F,0xD1E1 + .word 0xF108,0xD9C1,0xD1E1,0xF1F9,0xF3ED,0x5636,0xE9E9,0x9FBF + .word 0xDFFF,0x4D41,0x5253,0x2049,0x6E69,0x7469,0x616C,0x2026 + .word 0x2053,0x6563,0x7572,0x6974,0x7920,0x5072,0x6F67,0x7261 + .word 0x6D20,0x2020,0x2020,0x2020,0x2020,0x2043,0x6172,0x7472 + .word 0x6964,0x6765,0x2056,0x6572,0x7369,0x6F6E,0x2020,0x2020 + .word 0x436F,0x7079,0x7269,0x6768,0x7420,0x5345,0x4741,0x2045 + .word 0x4E54,0x4552,0x5052,0x4953,0x4553,0x2C4C,0x5444,0x2E20 + .word 0x3139,0x3934,0x2020,0x2020,0x2020,0x2020,0x2020,0x2020 + .word 0x2020,0x2020,0x2020,0x2020,0x2020,0x2020,0x2020,0x2020 + .word 0x2020,0x2020,0x2020,0x524F,0x4D20,0x5665,0x7273,0x696F + .word 0x6E20,0x312E,0x3000,0x48E7,0xC040,0x43F9,0x00C0,0x0004 + .word 0x3011,0x303C,0x8000,0x323C,0x0100,0x3E3C,0x0012,0x1018 + .word 0x3280,0xD041,0x51CF,0xFFF8,0x4CDF,0x0203,0x4E75,0x48E7 + .word 0x81C0,0x41F9,0x0000,0x063E,0x43F9,0x00C0,0x0004,0x3298 + .word 0x3298,0x3298,0x3298,0x3298,0x3298,0x3298,0x2298,0x3341 + .word 0xFFFC,0x3011,0x0800,0x0001,0x66F8,0x3298,0x3298,0x7000 + .word 0x22BC,0xC000,0x0000,0x7E0F,0x3340,0xFFFC,0x3340,0xFFFC + .word 0x3340,0xFFFC,0x3340,0xFFFC,0x51CF,0xFFEE,0x22BC,0x4000 + .word 0x0010,0x7E09,0x3340,0xFFFC,0x3340,0xFFFC,0x3340,0xFFFC + .word 0x3340,0xFFFC,0x51CF,0xFFEE,0x4CDF,0x0381,0x4E75,0x8114 + .word 0x8F01,0x93FF,0x94FF,0x9500,0x9600,0x9780,0x4000,0x0080 + .word 0x8104,0x8F02,0x48E7,0xC140,0x43F9,0x00A1,0x5180,0x08A9 + .word 0x0007,0xFF80,0x66F8,0x3E3C,0x00FF,0x7000,0x7200,0x337C + .word 0x00FF,0x0004,0x3341,0x0006,0x3340,0x0008,0x4E71,0x0829 + .word 0x0001,0x000B,0x66F8,0x0641,0x0100,0x51CF,0xFFE8,0x4CDF + .word 0x0283,0x4E75,0x48E7,0x8180,0x41F9,0x00A1,0x5200,0x08A8 + .word 0x0007,0xFF00,0x66F8,0x3E3C,0x001F,0x20C0,0x20C0,0x20C0 + .word 0x20C0,0x51CF,0xFFF6,0x4CDF,0x0181,0x4E75,0x41F9,0x00FF + .word 0x0000,0x3E3C,0x07FF,0x7000,0x20C0,0x20C0,0x20C0,0x20C0 + .word 0x20C0,0x20C0,0x20C0,0x20C0,0x51CF,0xFFEE,0x3B7C,0x0000 + .word 0x1200,0x7E0A,0x51CF,0xFFFE,0x43F9,0x00A1,0x5100,0x7000 + .word 0x2340,0x0020,0x2340,0x0024,0x1B7C,0x0003,0x5101,0x2E79 + .word 0x0088,0x0000,0x0891,0x0007,0x66FA,0x7000,0x3340,0x0002 + .word 0x3340,0x0004,0x3340,0x0006,0x2340,0x0008,0x2340,0x000C + .word 0x3340,0x0010,0x3340,0x0030,0x3340,0x0032,0x3340,0x0038 + .word 0x3340,0x0080,0x3340,0x0082,0x08A9,0x0000,0x008B,0x66F8 + .word 0x6100,0xFF12,0x08E9,0x0000,0x008B,0x67F8,0x6100,0xFF06 + .word 0x08A9,0x0000,0x008B,0x6100,0xFF3C,0x303C,0x0040,0x2229 + .word 0x0020,0x0C81,0x5351,0x4552,0x6700,0x0092,0x303C,0x0080 + .word 0x2229,0x0020,0x0C81,0x5344,0x4552,0x6700,0x0080,0x21FC + .word 0x0088,0x02A2,0x0070,0x303C,0x0002,0x7200,0x122D,0x0001 + .word 0x1429,0x0080,0xE14A,0x8242,0x0801,0x000F,0x660A,0x0801 + .word 0x0006,0x6700,0x0058,0x6008,0x0801,0x0006,0x6600,0x004E + .word 0x7020,0x41F9,0x0088,0x0000,0x3C28,0x018E,0x4A46,0x6700 + .word 0x0010,0x3429,0x0028,0x0C42,0x0000,0x67F6,0xB446,0x662C + .word 0x7000,0x2340,0x0028,0x2340,0x002C,0x3E14,0x2C7C,0xFFFF + .word 0xFFC0,0x4CD6,0x7FF9,0x44FC,0x0000,0x6014,0x43F9,0x00A1 + .word 0x5100,0x3340,0x0006,0x303C,0x8000,0x6004,0x44FC,0x0001 + +.macro exc_stub num +exc\num: + move.w #0x\num, -(%sp) + jmp pre_exception +.endm + +exc_stub 02 +exc_stub 03 +exc_stub 04 +exc_stub 05 +exc_stub 06 +exc_stub 07 +exc_stub 08 +exc_stub 09 +exc_stub 0a +exc_stub 0b +exc_stub 0c +exc_stub 0d +exc_stub 0e +exc_stub 0f +exc_stub 10 +exc_stub 11 +exc_stub 12 +exc_stub 13 +exc_stub 14 +exc_stub 15 +exc_stub 16 +exc_stub 17 +exc_stub 18 +exc_stub 19 +exc_stub 1a +exc_stub 1b +# exc_stub 1c +exc_stub 1d +# exc_stub 1e +exc_stub 1f +exc_stub 20 +exc_stub 21 +exc_stub 22 +exc_stub 23 +exc_stub 24 +exc_stub 25 +exc_stub 26 +exc_stub 27 +exc_stub 28 +exc_stub 29 +exc_stub 2a +exc_stub 2b +exc_stub 2c +exc_stub 2d +exc_stub 2e +exc_stub 2f +exc_stub 30 +exc_stub 31 +exc_stub 32 +exc_stub 33 +exc_stub 34 +exc_stub 35 +exc_stub 36 +exc_stub 37 +exc_stub 38 +exc_stub 39 +exc_stub 3a +exc_stub 3b +exc_stub 3c +exc_stub 3d +exc_stub 3e +exc_stub 3f + +.bss +.align 2 +.global start_hvc +start_hvc: + .word 0 + +# vim:filetype=asmM68k:ts=4:sw=4:expandtab diff --git a/mx/linux/Makefile b/mx/linux/Makefile new file mode 100644 index 0000000..d97f9fb --- /dev/null +++ b/mx/linux/Makefile @@ -0,0 +1,11 @@ + +CC ?= $(CROSS)gcc + +CFLAGS += -Wall -O2 -ggdb -fno-strict-aliasing +LDLIBS += -lusb +TARGET = mx_flasher + +all: $(TARGET) + +clean: + $(RM) $(TARGET) diff --git a/mx/linux/mx_flasher.c b/mx/linux/mx_flasher.c new file mode 100644 index 0000000..1bec278 --- /dev/null +++ b/mx/linux/mx_flasher.c @@ -0,0 +1,1232 @@ +/* + * Copyright (c) 2009, Gražvydas Ignotas + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the organization nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include + + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; +#define array_size(x) (sizeof(x) / sizeof(x[0])) + +static const struct { + unsigned short vendor; + unsigned short product; + const char *name; +} g_devices[] = { + { 0x03eb, 0x202a, "16MX+U Game Device" }, + { 0x03eb, 0x202b, "32MX+U Game Device" }, + { 0x03eb, 0x202c, "16MX+US Game Device" }, + { 0x03eb, 0x202d, "32MX+UF Game Device" }, +}; + +#define VERSION "0.91" + +//#define IO_BLK_SIZE 0x2000 /* 8K - unreliable? */ +#define IO_BLK_SIZE 0x800 +#define IO_RAM_BLK_SIZE 256 + +#define CMD_ATM_READY 0x22 +#define CMD_SEC_GET_NAME 'G' /* filename r/w */ +#define CMD_SEC_PUT_NAME 'P' +#define CMD_SEC_DEVID 'L' /* read flash device ID */ +#define CMD_SEC_ERASE 'E' +#define CMD_SEC_READY 'C' /* is flash ready? */ +#define CMD_SEC_READ 'R' +#define CMD_SEC_WRITE 'W' +#define CMD_SEC_RAM_READ 'D' /* not implemented? */ +#define CMD_SEC_RAM_WRITE 'U' +#define CMD_SEC_COMPAT '$' /* set RAM mode */ + +/* bus controllers */ +#define CTL_DATA_BUS 0x55 +#define CTL_ADDR_BUS 0xAA + +#define W_COUNTER 0xA0 +#define W_CNT_WRITE 0x01 +#define W_CNT_READ 0x00 + +#define FILENAME_ROM0 0 +#define FILENAME_ROM1 1 +#define FILENAME_RAM 2 + +/* windows app sets to 0x80 on init + * checkboxes use 0x41 0x42 0x43 (?) + * r,w Ram/ROM uses 0x23/0x21 + */ +#define C_MODE_4M_NORAM 0x41 /* RAM always off */ +#define C_MODE_4M_RAM 0x42 /* RAM switched by game */ +#define C_MODE_2M_RAM 0x43 +#define C_RAM_TMP_OFF 0x21 +#define C_RAM_TMP_ON 0x23 + +typedef struct { + u8 magic[4]; + u8 reserved[8]; + u8 write_flag; + u8 reserved2[2]; + u8 magic2; + u8 mx_cmd; + union { /* 0x11 */ + struct { + u8 which_device; + } dev_info; + struct { + u8 addrb2; /* most significant (BE) */ + u8 addrb1; + u8 addrb0; + u8 param; /* 64 byte usb packets for i/o */ + u8 param2; + } rom_rw; + struct { + u8 which; + } filename, mode; + struct { + u8 cmd; + u8 action; + u8 b0; /* LE */ + u8 b1; + u8 b2; + u8 b3; + } write_cnt; + struct { + u8 which; + u8 dev_id; + } rom_id; + }; + u8 pad[8]; +} dev_cmd_t; + +typedef struct { + u8 firmware_ver[4]; + u8 bootloader_ver[4]; + char names[56]; +} dev_info_t; + +typedef struct { + u32 start_addr; + u32 end_addr; + u32 page_size; +} page_table_t; + +static const page_table_t p_AM29LV320DB[] = +{ + { 0x000000, 0x00ffff, 0x002000 }, + { 0x010000, 0x3fffff, 0x010000 }, + { 0x000000, 0x000000, 0x000000 }, +}; + +static const page_table_t p_AM29LV320DT[] = +{ + { 0x000000, 0x3effff, 0x010000 }, + { 0x3f0000, 0x3fffff, 0x002000 }, + { 0x000000, 0x000000, 0x000000 }, +}; + +static const page_table_t p_2x_16[] = +{ + { 0x000000, 0x003fff, 0x004000 }, + { 0x004000, 0x007fff, 0x002000 }, + { 0x008000, 0x00ffff, 0x008000 }, + { 0x010000, 0x1fffff, 0x010000 }, + { 0x200000, 0x203fff, 0x004000 }, + { 0x204000, 0x207fff, 0x002000 }, + { 0x208000, 0x20ffff, 0x008000 }, + { 0x210000, 0x3fffff, 0x010000 }, + { 0x000000, 0x000000, 0x000000 }, +}; + +/*****************************************************************************/ + +static void prepare_cmd(dev_cmd_t *dev_cmd, u8 cmd) +{ + memset(dev_cmd, 0, sizeof(*dev_cmd)); + + memcpy(dev_cmd->magic, "USBC", 4); + dev_cmd->magic2 = 0x67; /* MySCSICommand, EXCOMMAND */ + dev_cmd->mx_cmd = cmd; +} + +static int write_data(struct usb_dev_handle *dev, void *data, int len) +{ + int ret = usb_bulk_write(dev, 0x03, data, len, 2000); + if (ret < 0) { + fprintf(stderr, "failed to write:\n"); + fprintf(stderr, "%s (%d)\n", usb_strerror(), ret); + } else if (ret != len) + printf("write_cmd: wrote only %d of %d bytes\n", ret, len); + + return ret; +} + +static int write_cmd(struct usb_dev_handle *dev, dev_cmd_t *cmd) +{ + return write_data(dev, cmd, sizeof(*cmd)); +} + +static int read_data(struct usb_dev_handle *dev, void *buff, int size) +{ + int ret = usb_bulk_read(dev, 0x82, buff, size, 2000); + if (ret < 0) { + fprintf(stderr, "failed to read:\n"); + fprintf(stderr, "%s (%d)\n", usb_strerror(), ret); + } +/* + else if (ret != size) + printf("read_data: read only %d of %d bytes\n", ret, size); +*/ + return ret; +} + +static int read_info(struct usb_dev_handle *device, u8 ctl_id, dev_info_t *info) +{ + dev_cmd_t cmd; + int ret; + + prepare_cmd(&cmd, CMD_ATM_READY); + cmd.dev_info.which_device = ctl_id; + memset(info, 0, sizeof(*info)); + + ret = write_cmd(device, &cmd); + if (ret < 0) + return ret; + + ret = read_data(device, info, sizeof(*info)); + if (ret < 0) + return ret; + + return 0; +} + +static void printf_info(dev_info_t *info) +{ + printf(" firmware version: %X.%X.%X%c\n", info->firmware_ver[0], + info->firmware_ver[1], info->firmware_ver[2], info->firmware_ver[3]); + printf(" bootloader version: %X.%X.%X%c\n", info->bootloader_ver[0], + info->bootloader_ver[1], info->bootloader_ver[2], info->bootloader_ver[3]); + info->names[sizeof(info->names) - 1] = 0; + printf(" device name: %s\n", info->names); +} + +static void print_progress(u32 done, u32 total) +{ + int i, step; + + printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); + printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); /* 20 */ + printf("\b\b\b\b\b\b"); + printf("%06x/%06x |", done, total); + + step = total / 20; + for (i = step; i <= total; i += step) + printf("%c", done >= i ? '=' : '-'); + printf("| %3d%%", done * 100 / total); + fflush(stdout); +} + +static int read_filename(struct usb_dev_handle *dev, char *dst, int len, u8 which) +{ + char buff[65]; + dev_cmd_t cmd; + int ret; + + prepare_cmd(&cmd, CMD_SEC_GET_NAME); + cmd.filename.which = which; + memset(buff, 0, sizeof(buff)); + + ret = write_cmd(dev, &cmd); + if (ret < 0) + return ret; + + ret = read_data(dev, buff, 64); + if (ret < 0) + return ret; + + strncpy(dst, buff, len); + dst[len - 1] = 0; + + return 0; +} + +static int write_filename(struct usb_dev_handle *dev, const char *fname, u8 which) +{ + dev_cmd_t cmd; + char buff[64]; + int ret, len; + + len = strlen(fname); + if (len > 63) + len = 63; + strncpy(buff, fname, len); + buff[len] = 0; + + prepare_cmd(&cmd, CMD_SEC_PUT_NAME); + cmd.filename.which = which; + + ret = write_cmd(dev, &cmd); + if (ret < 0) + return ret; + + return write_data(dev, buff, len + 1); +} + +static int read_erase_counter(struct usb_dev_handle *dev, u32 *val) +{ + dev_info_t dummy_info; + dev_cmd_t cmd; + u8 buff[4]; + int ret; + + /* must perform dummy info read here, + * or else device hangs after close (firmware bug?) */ + ret = read_info(dev, CTL_DATA_BUS, &dummy_info); + if (ret < 0) + return ret; + + prepare_cmd(&cmd, CMD_ATM_READY); + cmd.write_cnt.cmd = W_COUNTER; + cmd.write_cnt.action = W_CNT_READ; + + ret = write_cmd(dev, &cmd); + if (ret < 0) + return ret; + + ret = read_data(dev, buff, sizeof(buff)); + if (ret < 0) + return ret; + + *val = *(u32 *)buff; + return 0; +} + +static int read_flash_rom_id(struct usb_dev_handle *dev, int is_second, u32 *val) +{ + dev_cmd_t cmd; + u8 buff[2]; + int ret; + + prepare_cmd(&cmd, CMD_SEC_DEVID); + cmd.rom_id.which = is_second ? 0x10 : 0; + cmd.rom_id.dev_id = 0; + + ret = write_cmd(dev, &cmd); + if (ret < 0) + return ret; + + ret = read_data(dev, buff, sizeof(buff)); + if (ret < 0) + return ret; + + *val = *(u16 *)buff << 16; + + cmd.rom_id.dev_id = 1; + ret = write_cmd(dev, &cmd); + if (ret < 0) + return ret; + + ret = read_data(dev, buff, sizeof(buff)); + if (ret < 0) + return ret; + + *val |= *(u16 *)buff; + return 0; +} + +static const page_table_t *get_page_table(u32 rom_id) +{ + switch (rom_id) { + case 0x0100F922: + return p_AM29LV320DB; + case 0x0100F422: + return p_AM29LV320DT; + case 0x01004922: + case 0xC2004922: + return p_2x_16; + default: + fprintf(stderr, "unrecognized ROM id: %08x\n", rom_id); + } + + return NULL; +} + +static int get_page_size(const page_table_t *table, u32 addr, u32 *size) +{ + const page_table_t *t; + + for (t = table; t->end_addr != 0; t++) { + if (addr >= t->start_addr && addr <= t->end_addr) { + *size = t->page_size; + return 0; + } + } + + if (addr == t[-1].end_addr + 1) + return 1; /* no more */ + + fprintf(stderr, "get_page_size: failed on addr %06x\n", addr); + return -1; +} + +static int set_ram_mode(struct usb_dev_handle *dev, u8 mode) +{ + dev_cmd_t cmd; + u8 buff[2]; + int ret; + + prepare_cmd(&cmd, CMD_SEC_COMPAT); + cmd.write_flag = 1; + cmd.mode.which = mode; + + ret = write_cmd(dev, &cmd); + if (ret < 0) + goto end; + + ret = read_data(dev, buff, sizeof(buff)); + +end: + if (ret < 0) + fprintf(stderr, "warning: failed to set RAM mode\n"); + return ret; +} + +/* limitations: + * - bytes must be multiple of 64 + * - bytes must be less than 16k + * - must perform even number of reads, or dev hangs on exit (firmware bug?) */ +static int rw_dev_block(struct usb_dev_handle *dev, u32 addr, void *buffer, int bytes, int mx_cmd) +{ + dev_cmd_t cmd; + int ret; + + prepare_cmd(&cmd, mx_cmd); + if (mx_cmd == CMD_SEC_WRITE || mx_cmd == CMD_SEC_RAM_WRITE) + cmd.write_flag = 1; + cmd.rom_rw.addrb2 = addr >> (16 + 1); + cmd.rom_rw.addrb1 = addr >> (8 + 1); + cmd.rom_rw.addrb0 = addr >> 1; + cmd.rom_rw.param = bytes / 64; + if (mx_cmd == CMD_SEC_WRITE || mx_cmd == CMD_SEC_RAM_WRITE) + cmd.rom_rw.param2 = 1; /* ? */ + + ret = write_cmd(dev, &cmd); + if (ret < 0) + return ret; + + bytes &= ~63; + + if (mx_cmd == CMD_SEC_WRITE || mx_cmd == CMD_SEC_RAM_WRITE) + ret = write_data(dev, buffer, bytes); + else + ret = read_data(dev, buffer, bytes); + if (ret < 0) + return ret; + + if (ret != bytes) + fprintf(stderr, "rw_dev_block warning: done only %d/%d bytes\n", ret, bytes); + + return ret; +} + +static int read_write_rom(struct usb_dev_handle *dev, u32 addr, void *buffer, int bytes, int is_write) +{ + int mx_cmd = is_write ? CMD_SEC_WRITE : CMD_SEC_READ; + int total_bytes = bytes; + u8 *buff = buffer; + u8 dummy[64 * 4]; + int count, ret; + + if (addr & 1) + fprintf(stderr, "read_write_rom: can't handle odd address %06x, " + "LSb will be ignored\n", addr); + if (bytes & 63) + fprintf(stderr, "read_write_rom: byte count must be multiple of 64, " + "last %d bytes will not be handled\n", bytes & 63); + + set_ram_mode(dev, C_RAM_TMP_OFF); + + printf("%s flash ROM...\n", is_write ? "writing to" : "reading"); + + /* do i/o in blocks */ + for (count = 0; bytes >= IO_BLK_SIZE; count++) { + print_progress(buff - (u8 *)buffer, total_bytes); + + ret = rw_dev_block(dev, addr, buff, IO_BLK_SIZE, mx_cmd); + if (ret < 0) + return ret; + buff += IO_BLK_SIZE; + addr += IO_BLK_SIZE; + bytes -= IO_BLK_SIZE; + } + print_progress(buff - (u8 *)buffer, total_bytes); + + ret = 0; + if (bytes != 0) { + ret = rw_dev_block(dev, addr, buff, bytes, mx_cmd); + count++; + print_progress(total_bytes, total_bytes); + } + + if ((count & 1) && !is_write) + /* work around rw_dev_block() limitation 3 (works for reads only?) */ + rw_dev_block(dev, 0, dummy, sizeof(dummy), 0); + + printf("\n"); + return ret; +} + +static int read_write_ram(struct usb_dev_handle *dev, void *buffer, int bytes, int is_write) +{ + int mx_cmd = is_write ? CMD_SEC_RAM_WRITE : CMD_SEC_READ; + int total_bytes = bytes; + u8 *buff = buffer; + u32 addr = 0x200000; + int i, ret = 0; + + if (bytes % IO_RAM_BLK_SIZE) + fprintf(stderr, "read_write_ram: byte count must be multiple of %d, " + "last %d bytes will not be handled\n", IO_RAM_BLK_SIZE, + bytes % IO_RAM_BLK_SIZE); + + set_ram_mode(dev, C_RAM_TMP_ON); + + printf("%s RAM...\n", is_write ? "writing to" : "reading"); + + /* do i/o in blocks */ + while (bytes >= IO_RAM_BLK_SIZE) { + print_progress(buff - (u8 *)buffer, total_bytes); + + ret = rw_dev_block(dev, addr, buff, IO_RAM_BLK_SIZE, mx_cmd); + if (ret < 0) + return ret; + buff += IO_RAM_BLK_SIZE; + addr += IO_RAM_BLK_SIZE; + bytes -= IO_RAM_BLK_SIZE; + } + print_progress(buff - (u8 *)buffer, total_bytes); + + /* only D0-D7 connected.. */ + for (i = 0; i < total_bytes; i += 2) + ((u8 *)buffer)[i] = 0; + + printf("\n"); + return ret; + +} + +static int increment_erase_cnt(struct usb_dev_handle *dev) +{ + dev_cmd_t cmd; + u8 buff[4]; + u32 cnt; + int ret; + + ret = read_erase_counter(dev, &cnt); + if (ret != 0) + return ret; + + if (cnt == (u32)-1) { + fprintf(stderr, "flash erase counter maxed out!\n"); + fprintf(stderr, "(wow, did you really erase so many times?)\n"); + return -1; + } + + cnt++; + + prepare_cmd(&cmd, CMD_ATM_READY); + cmd.write_cnt.cmd = W_COUNTER; + cmd.write_cnt.action = W_CNT_WRITE; + cmd.write_cnt.b3 = cnt >> 24; + cmd.write_cnt.b2 = cnt >> 16; + cmd.write_cnt.b1 = cnt >> 8; + cmd.write_cnt.b0 = cnt; + + ret = write_cmd(dev, &cmd); + if (ret < 0) + return ret; + + ret = read_data(dev, buff, sizeof(buff)); + if (ret < 0) + return ret; + + return cnt; +} + +static int erase_page(struct usb_dev_handle *dev, u32 addr, int whole) +{ + dev_cmd_t cmd; + u8 buff[5]; + int i, ret; + + prepare_cmd(&cmd, CMD_SEC_ERASE); + cmd.write_flag = 1; + cmd.rom_rw.addrb2 = addr >> (16 + 1); + cmd.rom_rw.addrb1 = addr >> (8 + 1); + cmd.rom_rw.addrb0 = addr >> 1; + cmd.rom_rw.param = whole ? 0x10 : 0; + + ret = write_cmd(dev, &cmd); + if (ret < 0) + return ret; + + ret = read_data(dev, buff, sizeof(buff)); + if (ret < 0) + return ret; + + prepare_cmd(&cmd, CMD_SEC_READY); + cmd.rom_rw.addrb2 = addr >> (16 + 1); + cmd.rom_rw.addrb1 = addr >> (8 + 1); + cmd.rom_rw.addrb0 = addr >> 1; + + for (i = 0; i < 100; i++) { + ret = write_cmd(dev, &cmd); + if (ret < 0) + return ret; + + ret = read_data(dev, buff, sizeof(buff)); + if (ret < 0) + return ret; + + if (ret > 4 && buff[4] == 1) + break; + + usleep((whole ? 600 : 20) * 1000); + } + + if (i == 100) { + fprintf(stderr, "\ntimeout waiting for erase to complete\n"); + return -1; + } + + return 0; +} + +static int erase_seq(struct usb_dev_handle *dev, u32 size) +{ + const page_table_t *table; + u32 addr, page_size = 0; + u32 rom0_id, rom1_id; + int count, ret; + + ret = read_flash_rom_id(dev, 0, &rom0_id); + if (ret < 0) + return ret; + + ret = read_flash_rom_id(dev, 1, &rom1_id); + if (ret < 0) + return ret; + + if (rom0_id != rom1_id) + fprintf(stderr, "Warning: flash ROM ids differ: %08x %08x\n", + rom0_id, rom1_id); + + table = get_page_table(rom0_id); + if (table == NULL) + return -1; + + ret = increment_erase_cnt(dev); + if (ret < 0) + fprintf(stderr, "warning: coun't increase erase counter\n"); + + printf("erasing flash... (erase count=%u)\n", ret); + + for (addr = 0, count = 0; addr < size; addr += page_size, count++) { + print_progress(addr, size); + + ret = erase_page(dev, addr, 0); + if (ret < 0) + return ret; + + ret = get_page_size(table, addr, &page_size); + if (ret != 0) + break; + } + + if (count & 1) + /* ??? */ + /* must submit even number of erase commands (fw bug?) */ + erase_page(dev, 0, 0); + + print_progress(addr, size); + printf("\n"); + + return ret; +} + +static int erase_all(struct usb_dev_handle *dev, u32 size) +{ + int ret; + + ret = increment_erase_cnt(dev); + if (ret < 0) + fprintf(stderr, "warning: couldn't increase erase counter\n"); + + printf("erasing flash0, count=%u ...", ret); + fflush(stdout); + + ret = erase_page(dev, 0xaaa, 1); + if (ret != 0) + return ret; + + if (size > 0x200000) { + printf(" done.\n"); + printf("erasing flash1..."); + fflush(stdout); + + ret = erase_page(dev, 0x200aaa, 1); + } + + printf(" done.\n"); + return ret; +} + +static int print_device_info(struct usb_dev_handle *dev) +{ + u32 counter, rom0_id, rom1_id; + dev_info_t info; + int ret; + + printf("data bus controller:\n"); + ret = read_info(dev, CTL_DATA_BUS, &info); + if (ret < 0) + return ret; + printf_info(&info); + + printf("address bus controller:\n"); + ret = read_info(dev, CTL_ADDR_BUS, &info); + if (ret < 0) + return ret; + printf_info(&info); + + ret = read_erase_counter(dev, &counter); + if (ret < 0) + return ret; + printf("flash erase count: %u\n", counter); + + ret = read_flash_rom_id(dev, 0, &rom0_id); + if (ret < 0) + return ret; + printf("flash rom0 id: %08x\n", rom0_id); + + ret = read_flash_rom_id(dev, 1, &rom1_id); + if (ret < 0) + return ret; + printf("flash rom1 id: %08x\n", rom1_id); + + return 0; +} + +static int print_game_info(struct usb_dev_handle *dev) +{ + char fname[65]; + int ret; + + ret = read_filename(dev, fname, sizeof(fname), FILENAME_ROM0); + if (ret < 0) + return ret; + printf("ROM filename: %s\n", fname); + + ret = read_filename(dev, fname, sizeof(fname), FILENAME_RAM); + if (ret < 0) + return ret; + printf("SRAM filename: %s\n", fname); + + return 0; +} + +static int read_file(const char *fname, void **buff_out, int *size, int limit) +{ + int file_size, ret; + void *data; + FILE *file; + + file = fopen(fname, "rb"); + if (file == NULL) { + fprintf(stderr, "can't open file: %s\n", fname); + return -1; + } + + fseek(file, 0, SEEK_END); + file_size = ftell(file); + fseek(file, 0, SEEK_SET); + if (file_size > limit) + fprintf(stderr, "warning: input file \"%s\" too large\n", fname); + if (file_size < 0) { + fprintf(stderr, "bad/empty file: %s\n", fname); + goto fail; + } + + data = malloc(file_size); + if (data == NULL) { + fprintf(stderr, "low memory\n"); + goto fail; + } + + ret = fread(data, 1, file_size, file); + if (ret != file_size) { + fprintf(stderr, "failed to read file: %s", fname); + perror(""); + goto fail; + } + + *buff_out = data; + *size = file_size; + fclose(file); + return 0; + +fail: + fclose(file); + return -1; +} + +static int write_file(const char *fname, void *buff, int size) +{ + FILE *file; + int ret; + + file = fopen(fname, "wb"); + if (file == NULL) { + fprintf(stderr, "can't open for writing: %s\n", fname); + return -1; + } + + ret = fwrite(buff, 1, size, file); + if (ret != size) { + fprintf(stderr, "write failed to %s", fname); + perror(""); + } else + printf("saved to \"%s\".\n", fname); + fclose(file); + + return 0; +} + +static usb_dev_handle *get_device(void) +{ + struct usb_dev_handle *handle; + struct usb_device *dev; + struct usb_bus *bus; + int i, ret; + + ret = usb_find_busses(); + if (ret <= 0) { + fprintf(stderr, "Can't find USB busses\n"); + return NULL; + } + + ret = usb_find_devices(); + if (ret <= 0) { + fprintf(stderr, "Can't find USB devices\n"); + return NULL; + } + + bus = usb_get_busses(); + for (; bus; bus = bus->next) + { + for (dev = bus->devices; dev; dev = dev->next) + { + for (i = 0; i < array_size(g_devices); i++) + { + if (dev->descriptor.idVendor == g_devices[i].vendor && + dev->descriptor.idProduct == g_devices[i].product) + goto found; + } + } + } + + fprintf(stderr, "device not found.\n"); + return NULL; + +found: + printf("found %s.\n", g_devices[i].name); + + handle = usb_open(dev); + if (handle == NULL) { + fprintf(stderr, "failed to open device:\n"); + fprintf(stderr, "%s\n", usb_strerror()); + return NULL; + } + + ret = usb_set_configuration(handle, 1); + if (ret != 0) { + fprintf(stderr, "couldn't set configuration for /*/bus/usb/%s/%s:\n", + bus->dirname, dev->filename); + fprintf(stderr, "%s (%d)\n", usb_strerror(), ret); + return NULL; + } + + ret = usb_claim_interface(handle, 0); + if (ret != 0) { + fprintf(stderr, "couldn't claim /*/bus/usb/%s/%s:\n", + bus->dirname, dev->filename); + fprintf(stderr, "%s (%d)\n", usb_strerror(), ret); + return NULL; + } + + return handle; +} + +static void release_device(struct usb_dev_handle *device) +{ + usb_release_interface(device, 0); + usb_close(device); +} + +static void usage(const char *app_name) +{ + printf("Flasher tool for MX game devices\n" + "written by Grazvydas \"notaz\" Ignotas\n"); + printf("v" VERSION " (" __DATE__ ")\n\n"); + printf("Usage:\n" + "%s [-i] [-g] [-e] [-r [file]] [-w ] ...\n" + " -i print some info about connected device\n" + " -g print some info about game ROM inside device\n" + " -e[1] erase whole flash ROM in device, '1' uses different erase method\n" + " -m[1-3] set MX mode: 2M+RAM, 4M no RAM, 4M+RAM\n" + " -f skip file check\n" + " -r [file] copy game image from device to file; can autodetect filename\n" + " -w write file to device; also does erase\n" + " -sr [file] read save RAM to file\n" + " -sw write save RAM file to device\n" + " -sc clear save RAM\n" + " -v with -w or -sw: verify written file\n", + app_name); +} + +int main(int argc, char *argv[]) +{ + char *r_fname = NULL, *w_fname = NULL, *sr_fname = NULL, *sw_fname = NULL; + void *r_fdata = NULL, *w_fdata = NULL, *sr_fdata = NULL, *sw_fdata = NULL; + int do_read_ram = 0, do_clear_ram = 0, do_verify = 0, do_check = 1; + int pr_dev_info = 0, pr_rom_info = 0, do_read = 0, mx_mode = 0; + int erase_method = 0, do_erase_size = 0; + int w_fsize = 0, sw_fsize = 0; + struct usb_dev_handle *device; + char fname_buff[65]; + int i, ret = 0; + + for (i = 1; i < argc; i++) + { + if (argv[i][0] != '-') + break; + + switch (argv[i][1]) { + case 'i': + pr_dev_info = 1; + break; + case 'g': + pr_rom_info = 1; + break; + case 'e': + do_erase_size = 0x400000; + if (argv[i][2] == '1') + erase_method = 1; + break; + case 'f': + do_check = 0; + break; + case 'v': + do_verify = 1; + break; + case 'm': + mx_mode = argv[i][2]; + break; + case 'r': + do_read = 1; + if (argv[i+1] && argv[i+1][0] != '-') + r_fname = argv[++i]; + break; + case 'w': + if (argv[i+1] && argv[i+1][0] != '-') + w_fname = argv[++i]; + else + goto breakloop; + break; + case 's': + switch (argv[i][2]) { + case 'r': + do_read_ram = 1; + if (argv[i+1] && argv[i+1][0] != '-') + sr_fname = argv[++i]; + break; + case 'w': + if (argv[i+1] && argv[i+1][0] != '-') + sw_fname = argv[++i]; + else + goto breakloop; + break; + case 'c': + do_clear_ram = 1; + break; + default: + goto breakloop; + } + break; + default: + goto breakloop; + } + } + +breakloop: + if (i <= 1 || i < argc) { + usage(argv[0]); + return 1; + } + + /* preparations */ + if (w_fname != NULL) { + /* check extension */ + ret = strlen(w_fname); + if (do_check && (w_fname[ret - 4] == '.' || w_fname[ret - 3] == '.' || + w_fname[ret - 2] == '.') && + strcasecmp(&w_fname[ret - 4], ".gen") != 0 && + strcasecmp(&w_fname[ret - 4], ".bin") != 0 && + strcasecmp(&w_fname[ret - 4], ".32x") != 0) { + fprintf(stderr, "\"%s\" doesn't look like a game ROM, aborting " + "(use -f to disable this check)\n", w_fname); + return 1; + } + + ret = read_file(w_fname, &w_fdata, &w_fsize, 0x400000); + if (ret < 0) + return 1; + + /* align size to 64 */ + ret = (w_fsize + 63) & ~63; + if (w_fsize != ret) { + printf("ROM image size is %d, padding to %d\n", w_fsize, ret); + w_fdata = realloc(w_fdata, ret); + if (w_fdata == NULL) { + fprintf(stderr, "low mem\n"); + return 1; + } + memset((char *)w_fdata + w_fsize, 0, ret - w_fsize); + w_fsize = ret; + } + + if (do_erase_size < w_fsize) + do_erase_size = w_fsize; + } + if (sw_fname != NULL) { + ret = read_file(sw_fname, &sw_fdata, &sw_fsize, 0x8000*2); + if (ret < 0) + return 1; + } + if (sw_fdata != NULL || do_clear_ram) { + if (sw_fsize < 0x8000*2) { + sw_fdata = realloc(sw_fdata, 0x8000*2); + if (sw_fdata == NULL) { + fprintf(stderr, "low mem\n"); + return 1; + } + memset((u8 *)sw_fdata + sw_fsize, 0, 0x8000*2 - sw_fsize); + } + sw_fsize = 0x8000*2; + } + if (w_fname == NULL && sw_fname == NULL && do_verify) { + fprintf(stderr, "warning: -w or -sw not specified, -v ignored.\n"); + do_verify = 0; + } + + /* init */ + usb_init(); + + device = get_device(); + if (device == NULL) + return 1; + + /* info */ + if (pr_dev_info) { + ret = print_device_info(device); + if (ret < 0) + goto end; + } + + if (pr_rom_info) { + ret = print_game_info(device); + if (ret < 0) + goto end; + } + + /* erase */ + if (do_erase_size != 0) { + if (erase_method) + ret = erase_all(device, do_erase_size); + else + ret = erase_seq(device, do_erase_size); + if (ret < 0) + goto end; + } + + /* write flash */ + if (w_fdata != NULL) { + char *p; + + ret = read_write_rom(device, 0, w_fdata, w_fsize, 1); + if (ret < 0) + goto end; + + p = strrchr(w_fname, '/'); + p = (p == NULL) ? w_fname : p + 1; + + ret = write_filename(device, p, FILENAME_ROM0); + if (ret < 0) + fprintf(stderr, "warning: failed to save ROM filename\n"); + } + + /* write ram */ + if (sw_fdata != NULL) { + char *p, *t; + + ret = read_write_ram(device, sw_fdata, sw_fsize, 1); + if (ret < 0) + goto end; + + memset(fname_buff, 0, sizeof(fname_buff)); + p = fname_buff; + if (sw_fname != NULL) { + p = strrchr(sw_fname, '/'); + p = (p == NULL) ? sw_fname : p + 1; + } else if (w_fname != NULL) { + t = strrchr(w_fname, '/'); + t = (t == NULL) ? w_fname : t + 1; + + strncpy(fname_buff, t, sizeof(fname_buff)); + fname_buff[sizeof(fname_buff) - 1] = 0; + ret = strlen(fname_buff); + if (ret > 4 && fname_buff[ret - 4] == '.') + strcpy(&fname_buff[ret - 4], ".srm"); + } + + ret = write_filename(device, p, FILENAME_RAM); + if (ret < 0) + fprintf(stderr, "warning: failed to save RAM filename\n"); + } + + /* set mode */ + if (mx_mode || w_fsize > 0x200000) { + if (mx_mode == 0) + mx_mode = '3'; + printf("MX mode set to "); + switch (mx_mode) { + case '1': + printf("2M with RAM.\n"); + mx_mode = C_MODE_2M_RAM; + break; + case '2': + printf("4M, no RAM.\n"); + mx_mode = C_MODE_4M_NORAM; + break; + default: + printf("4M with RAM.\n"); + mx_mode = C_MODE_4M_RAM; + break; + } + set_ram_mode(device, mx_mode); + } + + /* read flash */ + if (do_read && r_fname == NULL) { + ret = read_filename(device, fname_buff, sizeof(fname_buff), FILENAME_ROM0); + if (ret < 0) + return ret; + r_fname = fname_buff; + if (r_fname[0] == 0) + r_fname = "rom.gen"; + } + + if (r_fname != NULL || do_verify) { + r_fdata = malloc(0x400000); + if (r_fdata == NULL) { + fprintf(stderr, "low mem\n"); + goto end; + } + + ret = read_write_rom(device, 0, r_fdata, 0x400000, 0); + if (ret < 0) + goto end; + } + + if (r_fname != NULL) + write_file(r_fname, r_fdata, 0x400000); + + /* read ram */ + if (do_read_ram && sr_fname == NULL) { + ret = read_filename(device, fname_buff, sizeof(fname_buff), FILENAME_RAM); + if (ret < 0) + return ret; + sr_fname = fname_buff; + if (sr_fname[0] == 0) + sr_fname = "rom.srm"; + } + + if (sr_fname != NULL || do_verify) { + sr_fdata = malloc(0x8000*2); + if (sr_fdata == NULL) { + fprintf(stderr, "low mem\n"); + goto end; + } + + ret = read_write_ram(device, sr_fdata, 0x8000*2, 0); + if (ret < 0) + goto end; + } + + if (sr_fname != NULL) + write_file(sr_fname, sr_fdata, 0x8000*2); + + /* verify */ + if (do_verify && w_fdata != NULL && r_fdata != NULL) { + ret = memcmp(w_fdata, r_fdata, w_fsize); + if (ret == 0) + printf("flash verification passed.\n"); + else + printf("flash verification FAILED!\n"); + } + + if (do_verify && sw_fdata != NULL && sr_fdata != NULL) { + ret = memcmp(sw_fdata, sr_fdata, 0x8000*2); + if (ret == 0) + printf("RAM verification passed.\n"); + else + printf("RAM verification FAILED!\n"); + } + + printf("all done.\n"); + ret = 0; + +end: + if (w_fdata != NULL) + free(w_fdata); + if (r_fdata != NULL) + free(r_fdata); + + release_device(device); + + return ret; +} + diff --git a/mx/linux/sms2mx.c b/mx/linux/sms2mx.c new file mode 100644 index 0000000..6b084ea --- /dev/null +++ b/mx/linux/sms2mx.c @@ -0,0 +1,58 @@ +#include +#include + +#define IN_SIZE 0x8000 +#define OUT_SIZE 0x400000 +static unsigned char buff[OUT_SIZE], buff_in[IN_SIZE]; + +int main(int argc, char *argv[]) +{ + FILE *fi, *fo; + int size, bsize; + int i, o; + + if (argc != 3) { + fprintf(stderr, "usage:\n%s \n", argv[0]); + return 1; + } + + fi = fopen(argv[1], "rb"); + if (fi == NULL) { + fprintf(stderr, "can't open: %s\n", argv[1]); + return 1; + } + + fo = fopen(argv[2], "wb"); + if (fo == NULL) { + fprintf(stderr, "can't open: %s\n", argv[2]); + return 1; + } + + fseek(fi, 0, SEEK_END); + size = ftell(fi); + fseek(fi, 0, SEEK_SET); + + if (size > IN_SIZE) { + fprintf(stderr, "ROMs > 32k won't work\n"); + size = IN_SIZE; + } + + if (fread(buff_in, 1, size, fi) != size) + fprintf(stderr, "failed to read %s\n", argv[1]); + + memset(buff, 0, sizeof(buff)); + + for (bsize = 1; bsize < size; bsize <<= 1) + ; + + for (i = o = 0; o < sizeof(buff); i = (i + 1) & (bsize - 1), o += 2) + buff[o+1] = buff_in[i]; + + if (fwrite(buff, 1, OUT_SIZE, fo) != OUT_SIZE) + fprintf(stderr, "failed to write to %s\n", argv[2]); + fclose(fi); + fclose(fo); + + return 0; +} + diff --git a/nshtest/Makefile b/nshtest/Makefile new file mode 100644 index 0000000..bfe4a04 --- /dev/null +++ b/nshtest/Makefile @@ -0,0 +1,21 @@ +CROSS = m68k-elf- +AS = $(CROSS)as +LD = $(CROSS)ld +OBJCOPY = $(CROSS)objcopy + +ASFLAGS = -m68000 --register-prefix-optional --bitwise-or + +TARGET = nshtest.bin +OBJS = sega_gcc.o test.o + +all : $(TARGET) + +$(TARGET) : a.out + $(OBJCOPY) -I elf32-m68k -O binary $^ $@ + +a.out : $(OBJS) + $(LD) -Tmd.ld -Map $(TARGET).map $^ + +clean: + $(RM) $(TARGET) $(OBJS) $(TARGET).map a.out + diff --git a/nshtest/md.ld b/nshtest/md.ld new file mode 100644 index 0000000..208bfa7 --- /dev/null +++ b/nshtest/md.ld @@ -0,0 +1,122 @@ +OUTPUT_ARCH(m68k) +SEARCH_DIR(.) +/*GROUP(-lbcc -lc -lgcc)*/ +__DYNAMIC = 0; + +/* + * Setup the memory map of the SEGA Genesis. + * stack grows down from high memory. + * + * The memory map look like this: + * +--------------------+ <- low memory + * | .text | + * | _etext | + * | ctor list | the ctor and dtor lists are for + * | dtor list | C++ support + * +--------------------+ + * | .data | initialized data goes here + * | _edata | + * +--------------------+ + * | .bss | + * | __bss_start | start of bss, cleared by crt0 + * | _end | start of heap, used by sbrk() + * +--------------------+ + * . . + * . . + * . . + * | __stack | top of stack + * +--------------------+ + */ +/* +MEMORY +{ + rom : ORIGIN = 0x00000000, LENGTH = 0x00400000 + ram : ORIGIN = 0xffff0000, LENGTH = 0x00010000 +} +*/ + +MEMORY { + ram : ORIGIN = 0x0, LENGTH = 0xfffffff +} + +/* + * allocate the stack to be at the top of memory, since the stack + * grows down + */ + +PROVIDE (__stack = 0x00fffff0); + +PROVIDE (ram = 0xffff0000); +/* + * Initalize some symbols to be zero so we can reference them in the + * crt0 without core dumping. These functions are all optional, but + * we do this so we can have our crt0 always use them if they exist. + * This is so BSPs work better when using the crt0 installed with gcc. + * We have to initalize them twice, so we cover a.out (which prepends + * an underscore) and coff object file formats. + */ +PROVIDE (hardware_init_hook = 0); +PROVIDE (_hardware_init_hook = 0); +PROVIDE (software_init_hook = 0); +PROVIDE (_software_init_hook = 0); + +SECTIONS +{ + .text 0x00000000: + { + *(.text) + . = ALIGN(0x4); + __CTOR_LIST__ = .; + LONG((__CTOR_END__ - __CTOR_LIST__) / 4 - 2) + *(.ctors) + LONG(0) + __CTOR_END__ = .; + __DTOR_LIST__ = .; + LONG((__DTOR_END__ - __DTOR_LIST__) / 4 - 2) + *(.dtors) + LONG(0) + __DTOR_END__ = .; + *(.rodata) + *(.gcc_except_table) + + __INIT_SECTION__ = . ; + *(.init) + SHORT (0x4e75) /* rts */ + + __FINI_SECTION__ = . ; + *(.fini) + SHORT (0x4e75) /* rts */ + + _etext = .; + *(.lit) + } > ram + + .data BLOCK (0x4) : + { + *(.shdata) + *(.data) + _edata = .; + } > ram + + .bss 0xff0000 : + { + __bss_start = . ; + *(.shbss) + *(.bss) + *(COMMON) + *(.eh_fram) + *(.eh_frame) + _end = ALIGN (0x8); + __end = _end; + } > ram + + .stab 0 (NOLOAD) : + { + *(.stab) + } + + .stabstr 0 (NOLOAD) : + { + *(.stabstr) + } +} diff --git a/nshtest/sega_gcc.s b/nshtest/sega_gcc.s new file mode 100644 index 0000000..a295692 --- /dev/null +++ b/nshtest/sega_gcc.s @@ -0,0 +1,443 @@ +*------------------------------------------------------- +* +* Sega startup code for the GNU Assembler +* Translated from: +* Sega startup code for the Sozobon C compiler +* Written by Paul W. Lee +* Modified from Charles Coty's code +* +*------------------------------------------------------- + + dc.l 0x0,0x200 + dc.l INT,INT,INT,INT,INT,INT,INT + dc.l INT,INT,INT,INT,INT,INT,INT,INT + dc.l INT,INT,INT,INT,INT,INT,INT,INT + dc.l INT,INT,INT,HBL,INT,VBL,INT,INT + dc.l INT,INT,INT,INT,INT,INT,INT,INT + dc.l INT,INT,INT,INT,INT,INT,INT,INT + dc.l INT,INT,INT,INT,INT,INT,INT,INT + dc.l INT,INT,INT,INT,INT,INT,INT + .ascii "SEGA GENESIS " + .ascii "notaz's Shadow / Hilight test " + .ascii "NOTAZ'S SHADOW HILIGHT TEST " + .ascii "GM 00000000-00" + .byte 0xa5,0xfb + .ascii "JD " + .byte 0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00 + .byte 0x00,0xff,0x00,0x00,0xff,0xff,0xff,0xff + .ascii " " + .ascii " " + .ascii " " + .ascii "JUE " +*debugee: +* bra debugee + tst.l 0xa10008 + bne SkipJoyDetect + tst.w 0xa1000c +SkipJoyDetect: + bne SkipSetup + lea Table,%a5 + movem.w (%a5)+,%d5-%d7 + movem.l (%a5)+,%a0-%a4 +* Check Version Number + move.b -0x10ff(%a1),%d0 + andi.b #0x0f,%d0 + beq WrongVersion +* Sega Security Code (SEGA) + move.l #0x53454741,0x2f00(%a1) +WrongVersion: + move.w (%a4),%d0 + moveq #0x00,%d0 + movea.l %d0,%a6 + move %a6,%usp +* Set VDP registers + moveq #0x17,%d1 +FillLoop: + move.b (%a5)+,%d5 + move.w %d5,(%a4) + add.w %d7,%d5 + dbra %d1,FillLoop + move.l (%a5)+,(%a4) + move.w %d0,(%a3) + move.w %d7,(%a1) + move.w %d7,(%a2) +L0250: + btst %d0,(%a1) + bne L0250 +* Put initial values into a00000 + moveq #0x25,%d2 +Filla: + move.b (%a5)+,(%a0)+ + dbra %d2,Filla + move.w %d0,(%a2) + move.w %d0,(%a1) + move.w %d7,(%a2) +L0262: + move.l %d0,-(%a6) + dbra %d6,L0262 + move.l (%a5)+,(%a4) + move.l (%a5)+,(%a4) +* Put initial values into c00000 + moveq #0x1f,%d3 +Filc0: + move.l %d0,(%a3) + dbra %d3,Filc0 + move.l (%a5)+,(%a4) +* Put initial values into c00000 + moveq #0x13,%d4 +Fillc1: + move.l %d0,(%a3) + dbra %d4,Fillc1 +* Put initial values into c00011 + moveq #0x03,%d5 +Fillc2: + move.b (%a5)+,0x0011(%a3) + dbra %d5,Fillc2 + move.w %d0,(%a2) + movem.l (%a6),%d0-%d7/%a0-%a6 + move #0x2700,%sr +SkipSetup: + bra Continue +Table: + dc.w 0x8000, 0x3fff, 0x0100, 0x00a0, 0x0000, 0x00a1, 0x1100, 0x00a1 + dc.w 0x1200, 0x00c0, 0x0000, 0x00c0, 0x0004, 0x0414, 0x302c, 0x0754 + dc.w 0x0000, 0x0000, 0x0000, 0x812b, 0x0001, 0x0100, 0x00ff, 0xff00 + dc.w 0x0080, 0x4000, 0x0080, 0xaf01, 0xd91f, 0x1127, 0x0021, 0x2600 + dc.w 0xf977, 0xedb0, 0xdde1, 0xfde1, 0xed47, 0xed4f, 0xd1e1, 0xf108 + dc.w 0xd9c1, 0xd1e1, 0xf1f9, 0xf3ed, 0x5636, 0xe9e9, 0x8104, 0x8f01 + dc.w 0xc000, 0x0000, 0x4000, 0x0010, 0x9fbf, 0xdfff + +Continue: + tst.w 0x00C00004 + +* set stack pointer +* clr.l %a7 + move.w #0,%a7 + +* user mode + move.w #0x2300,%sr + +* clear Genesis RAM + lea 0xff0000,%a0 + moveq #0,%d0 +clrram: move.w #0,(%a0)+ + subq.w #2,%d0 + bne clrram + +*---------------------------------------------------------- +* +* Load driver into the Z80 memory +* +*---------------------------------------------------------- + +* halt the Z80 + move.w #0x100,0xa11100 +* reset it + move.w #0x100,0xa11200 + + lea Z80Driver,%a0 + lea 0xa00000,%a1 + move.l #Z80DriverEnd,%d0 + move.l #Z80Driver,%d1 + sub.l %d1,%d0 +Z80loop: + move.b (%a0)+,(%a1)+ + subq.w #1,%d0 + bne Z80loop + +* enable the Z80 + move.w #0x0,0xa11100 + +*---------------------------------------------------------- + jmp main + +INT: + rte + +HBL: + /* addq.l #1,htimer */ + rte + +VBL: + /* addq.l #1,vtimer */ + move.l #vtimer,a0 + addq.l #1,(a0) + rte + +*------------------------------------------------ +* +* Get a random number. This routine +* was found in TOS. +* +* Output +* ------ +* d0 = random number +* +*------------------------------------------------ + + .globl random + +random: + move.l rand_num,%d0 + tst.l %d0 + bne .L1 + moveq #16,%d1 + lsl.l %d1,%d0 + or.l htimer,%d0 + move.l %d0,rand_num +.L1: + move.l #-1153374675,-(%sp) + move.l rand_num,-(%sp) + bsr lmul + addq.w #8,%sp + addq.l #1,%d0 + move.l %d0,rand_num + + lsr.l #8,%d0 + and.l #16777215,%d0 + rts + + +*------------------------------------------------ +* +* Copyright (c) 1988 by Sozobon, Limited. Author: Johann Ruegg +* +* Permission is granted to anyone to use this software for any purpose +* on any computer system, and to redistribute it freely, with the +* following restrictions: +* 1) No charge may be made other than reasonable charges for reproduction. +* 2) Modified versions must be clearly marked as such. +* 3) The authors are not responsible for any harmful consequences +* of using this software, even if they result from defects in it. +* +*------------------------------------------------ + +ldiv: + move.l 4(%a7),%d0 + bpl ld1 + neg.l %d0 +ld1: + move.l 8(%a7),%d1 + bpl ld2 + neg.l %d1 + eor.b #0x80,4(%a7) +ld2: + bsr i_ldiv /* d0 = d0/d1 */ + tst.b 4(%a7) + bpl ld3 + neg.l %d0 +ld3: + rts + +lmul: + move.l 4(%a7),%d0 + bpl lm1 + neg.l %d0 +lm1: + move.l 8(%a7),%d1 + bpl lm2 + neg.l %d1 + eor.b #0x80,4(%a7) +lm2: + bsr i_lmul /* d0 = d0*d1 */ + tst.b 4(%a7) + bpl lm3 + neg.l %d0 +lm3: + rts + +lrem: + move.l 4(%a7),%d0 + bpl lr1 + neg.l %d0 +lr1: + move.l 8(%a7),%d1 + bpl lr2 + neg.l %d1 +lr2: + bsr i_ldiv /* d1 = d0%d1 */ + move.l %d1,%d0 + tst.b 4(%a7) + bpl lr3 + neg.l %d0 +lr3: + rts + +ldivu: + move.l 4(%a7),%d0 + move.l 8(%a7),%d1 + bsr i_ldiv + rts + +lmulu: + move.l 4(%a7),%d0 + move.l 8(%a7),%d1 + bsr i_lmul + rts + +lremu: + move.l 4(%a7),%d0 + move.l 8(%a7),%d1 + bsr i_ldiv + move.l %d1,%d0 + rts +* +* A in d0, B in d1, return A*B in d0 +* +i_lmul: + move.l %d3,%a2 /* save d3 */ + move.w %d1,%d2 + mulu %d0,%d2 /* d2 = Al * Bl */ + + move.l %d1,%d3 + swap %d3 + mulu %d0,%d3 /* d3 = Al * Bh */ + + swap %d0 + mulu %d1,%d0 /* d0 = Ah * Bl */ + + add.l %d3,%d0 /* d0 = (Ah*Bl + Al*Bh) */ + swap %d0 + clr.w %d0 /* d0 = (Ah*Bl + Al*Bh) << 16 */ + + add.l %d2,%d0 /* d0 = A*B */ + move.l %a2,%d3 /* restore d3 */ + rts +* +*A in d0, B in d1, return A/B in d0, A%B in d1 +* +i_ldiv: + tst.l %d1 + bne nz1 + +* divide by zero +* divu #0,%d0 /* cause trap */ + move.l #0x80000000,%d0 + move.l %d0,%d1 + rts +nz1: + move.l %d3,%a2 /* save d3 */ + cmp.l %d1,%d0 + bhi norm + beq is1 +* AB and B is not 0 +norm: + cmp.l #1,%d1 + bne not1 +* B==1, so ret A, rem 0 + clr.l %d1 + move.l %a2,%d3 /* restore d3 */ + rts +* check for A short (implies B short also) +not1: + cmp.l #0xffff,%d0 + bhi slow +* A short and B short -- use 'divu' + divu %d1,%d0 /* d0 = REM:ANS */ + swap %d0 /* d0 = ANS:REM */ + clr.l %d1 + move.w %d0,%d1 /* d1 = REM */ + clr.w %d0 + swap %d0 + move.l %a2,%d3 /* restore d3 */ + rts +* check for B short +slow: + cmp.l #0xffff,%d1 + bhi slower +* A long and B short -- use special stuff from gnu + move.l %d0,%d2 + clr.w %d2 + swap %d2 + divu %d1,%d2 /* d2 = REM:ANS of Ahi/B */ + clr.l %d3 + move.w %d2,%d3 /* d3 = Ahi/B */ + swap %d3 + + move.w %d0,%d2 /* d2 = REM << 16 + Alo */ + divu %d1,%d2 /* d2 = REM:ANS of stuff/B */ + + move.l %d2,%d1 + clr.w %d1 + swap %d1 /* d1 = REM */ + + clr.l %d0 + move.w %d2,%d0 + add.l %d3,%d0 /* d0 = ANS */ + move.l %a2,%d3 /* restore d3 */ + rts +* A>B, B > 1 +slower: + move.l #1,%d2 + clr.l %d3 +moreadj: + cmp.l %d0,%d1 + bhs adj + add.l %d2,%d2 + add.l %d1,%d1 + bpl moreadj +* we shifted B until its >A or sign bit set +* we shifted #1 (d2) along with it +adj: + cmp.l %d0,%d1 + bhi ltuns + or.l %d2,%d3 + sub.l %d1,%d0 +ltuns: + lsr.l #1,%d1 + lsr.l #1,%d2 + bne adj +* d3=answer, d0=rem + move.l %d0,%d1 + move.l %d3,%d0 + move.l %a2,%d3 /* restore d3 */ + rts +*---------------------------------------------------------- +* +* Z80 Sound Driver +* +*---------------------------------------------------------- +Z80Driver: + dc.b 0xc3,0x46,0x00,0x00,0x00,0x00,0x00,0x00 + dc.b 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 + dc.b 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 + dc.b 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 + dc.b 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 + dc.b 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 + dc.b 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 + dc.b 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 + dc.b 0x00,0x00,0x00,0x00,0x00,0x00,0xf3,0xed + dc.b 0x56,0x31,0x00,0x20,0x3a,0x39,0x00,0xb7 + dc.b 0xca,0x4c,0x00,0x21,0x3a,0x00,0x11,0x40 + dc.b 0x00,0x01,0x06,0x00,0xed,0xb0,0x3e,0x00 + dc.b 0x32,0x39,0x00,0x3e,0xb4,0x32,0x02,0x40 + dc.b 0x3e,0xc0,0x32,0x03,0x40,0x3e,0x2b,0x32 + dc.b 0x00,0x40,0x3e,0x80,0x32,0x01,0x40,0x3a + dc.b 0x43,0x00,0x4f,0x3a,0x44,0x00,0x47,0x3e + dc.b 0x06,0x3d,0xc2,0x81,0x00,0x21,0x00,0x60 + dc.b 0x3a,0x41,0x00,0x07,0x77,0x3a,0x42,0x00 + dc.b 0x77,0x0f,0x77,0x0f,0x77,0x0f,0x77,0x0f + dc.b 0x77,0x0f,0x77,0x0f,0x77,0x0f,0x77,0x3a + dc.b 0x40,0x00,0x6f,0x3a,0x41,0x00,0xf6,0x80 + dc.b 0x67,0x3e,0x2a,0x32,0x00,0x40,0x7e,0x32 + dc.b 0x01,0x40,0x21,0x40,0x00,0x7e,0xc6,0x01 + dc.b 0x77,0x23,0x7e,0xce,0x00,0x77,0x23,0x7e + dc.b 0xce,0x00,0x77,0x3a,0x39,0x00,0xb7,0xc2 + dc.b 0x4c,0x00,0x0b,0x78,0xb1,0xc2,0x7f,0x00 + dc.b 0x3a,0x45,0x00,0xb7,0xca,0x4c,0x00,0x3d + dc.b 0x3a,0x45,0x00,0x06,0xff,0x0e,0xff,0xc3 + dc.b 0x7f,0x00 +Z80DriverEnd: + + diff --git a/nshtest/test.s b/nshtest/test.s new file mode 100644 index 0000000..3802920 --- /dev/null +++ b/nshtest/test.s @@ -0,0 +1,443 @@ +################################################## +# # +# Assemble with gas # +# --register-prefix-optional --bitwise-or # +# # +################################################## + +.text +.globl main + +################################################## +# # +# Register and bitmask definitions # +# # +################################################## + +.equ GFXDATA, 0xc00000 +.equ GFXCNTL, 0xc00004 + +.equ VDP0_E_HBI, 0x10 +.equ VDP0_E_DISPLAY, 0x02 +.equ VDP0_PLTT_FULL, 0x04 + +.equ VDP1_SMS_MODE, 0x80 +.equ VDP1_E_DISPLAY, 0x40 +.equ VDP1_E_VBI, 0x20 +.equ VDP1_E_DMA, 0x10 +.equ VDP1_NTSC, 0x00 +.equ VDP1_PAL, 0x08 +.equ VDP1_RESERVED, 0x04 + +.equ VDP12_SPR_SHADOWS, 0x08 +.equ VDP12_SCREEN_V224, 0x00 +.equ VDP12_SCREEN_V448, 0x04 +.equ VDP12_PROGRESSIVE, 0x00 +.equ VDP12_INTERLACED, 0x02 +.equ VDP12_SCREEN_H256, 0x00 +.equ VDP12_SCREEN_H320, 0x81 + +.equ VDP16_MAP_V32, 0x00 +.equ VDP16_MAP_V64, 0x10 +.equ VDP16_MAP_V128, 0x30 +.equ VDP16_MAP_H32, 0x00 +.equ VDP16_MAP_H64, 0x01 +.equ VDP16_MAP_H128, 0x03 + + + +################################################## +# # +# MACROS # +# # +################################################## + + +/* Write val to VDP register reg */ +.macro write_vdp_reg reg val + move.w #((\reg << 8) + 0x8000 + \val),(a3) +.endm + + +/* For immediate addresses */ +.macro VRAM_ADDR reg adr + move.l #(((0x4000 + (\adr & 0x3fff)) << 16) + (\adr >> 14)),\reg +.endm + + +/* For indirect (variable) addresses. + Destroys d6-d7. */ +.macro VRAM_ADDR_var reg adr + move.l \adr,d6 + move.l \adr,d7 + and.w #0x3fff,d6 + lsr.w #7,d7 + lsr.w #7,d7 + add.w #0x4000,d6 + lsl.l #7,d6 + lsl.l #7,d6 + lsl.l #2,d6 + or.l d7,d6 + move.l d6,\reg +.endm + + +.macro CRAM_ADDR reg adr + move.l #(((0xc000 + (\adr & 0x3fff)) << 16) + (\adr >> 14)),\reg +.endm + + +/* For indirect (variable) addresses */ +.macro CRAM_ADDR_var reg adr + move.l \adr,d6 + move.l \adr,d7 + and.w #0x3fff,d6 + lsr.w #7,d7 + lsr.w #7,d7 + add.w #0xc000,d6 + lsl.l #7,d6 + lsl.l #7,d6 + lsl.l #2,d6 + or.l d7,d6 + move.l d6,\reg +.endm + + +.macro VSCROLL_ADDR reg adr + move.l #(((0x4000 + (\adr & 0x3fff)) << 16) + ((\adr >> 14) | 0x10)),\reg +.endm + + +.macro HSCROLL_ADDR reg adr + move.l #(((0x4000 + (\adr & 0x3fff)) << 16) + (\adr >> 14)),\reg +.endm + + +################################################# +# # +# DATA # +# # +################################################# + +colors: + dc.w 0x0040,0x0080,0x000e,0x00e0,0x0e00,0x00ee +pattern: + dc.l 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000 + dc.l 0x22334455,0x22334455,0x22334455,0x22334455,0x22334455,0x22334455,0x22334455,0x22334455 + /* shadow sprite */ + dc.l 0x00000fff + dc.l 0x0000ffff + dc.l 0x00ffffff + dc.l 0x00ffffff + dc.l 0x0fffffff + dc.l 0xffffffff + dc.l 0xffffffff + dc.l 0xffffffff + /* */ + dc.l 0xffffffff + dc.l 0xffffffff + dc.l 0xffffffff + dc.l 0x0fffffff + dc.l 0x00ffffff + dc.l 0x00ffffff + dc.l 0x0000ffff + dc.l 0x00000fff + /* */ + dc.l 0xfff00000 + dc.l 0xffff0000 + dc.l 0xffffff00 + dc.l 0xffffff00 + dc.l 0xfffffff0 + dc.l 0xffffffff + dc.l 0xffffffff + dc.l 0xffffffff + /* */ + dc.l 0xffffffff + dc.l 0xffffffff + dc.l 0xffffffff + dc.l 0xfffffff0 + dc.l 0xffffff00 + dc.l 0xffffff00 + dc.l 0xffff0000 + dc.l 0xfff00000 + /* hilight sprite */ + dc.l 0x00000eee + dc.l 0x0000eeee + dc.l 0x00eeeeee + dc.l 0x00eeeeee + dc.l 0x0eeeeeee + dc.l 0xeeeeeeee + dc.l 0xeeeeeeee + dc.l 0xeeeeeeee + /* */ + dc.l 0xeeeeeeee + dc.l 0xeeeeeeee + dc.l 0xeeeeeeee + dc.l 0x0eeeeeee + dc.l 0x00eeeeee + dc.l 0x00eeeeee + dc.l 0x0000eeee + dc.l 0x00000eee + /* */ + dc.l 0xeee00000 + dc.l 0xeeee0000 + dc.l 0xeeeeee00 + dc.l 0xeeeeee00 + dc.l 0xeeeeeee0 + dc.l 0xeeeeeeee + dc.l 0xeeeeeeee + dc.l 0xeeeeeeee + /* */ + dc.l 0xeeeeeeee + dc.l 0xeeeeeeee + dc.l 0xeeeeeeee + dc.l 0xeeeeeee0 + dc.l 0xeeeeee00 + dc.l 0xeeeeee00 + dc.l 0xeeee0000 + dc.l 0xeee00000 + + +sprite_data: + /* Y size link attr X */ + dc.w 10+128; dc.b 0x05; dc.b 1; dc.w 0x6002; dc.w 0 + dc.w 30+128; dc.b 0x05; dc.b 2; dc.w 0x6006; dc.w 0 + dc.w 60+128; dc.b 0x05; dc.b 3; dc.w 0xe002; dc.w 0 + dc.w 80+128; dc.b 0x05; dc.b 4; dc.w 0xe006; dc.w 0 + dc.w 120+128; dc.b 0x05; dc.b 5; dc.w 0x6002; dc.w 0 + dc.w 140+128; dc.b 0x05; dc.b 6; dc.w 0x6006; dc.w 0 + dc.w 170+128; dc.b 0x05; dc.b 7; dc.w 0xe002; dc.w 0 + dc.w 190+128; dc.b 0x05; dc.b 0; dc.w 0xe006; dc.w 0 +sprite_data_end: + + +################################################## +# # +# MAIN PROGRAM # +# # +################################################## + +main: + /* Initialize VDP */ + jsr init_gfx + + /* Load color data */ + movea.l #0,a3 + move.l #colors,a4 + moveq.l #6,d4 + jsr load_colors + + /* load patterns */ + movea.l #0,a3 + movea.l #pattern,a4 + move.l #10,d4 + jsr load_tiles + + /* generate A layer map */ + movea.l #0xe000+10*2,a6 + move.l #28-1,d4 +lmaploop0: + movea.l a6,a3 + jsr load_prepare + + moveq.l #6-1,d3 +0: move.l #0x00010001,(a3) + dbra d3,0b + + moveq.l #9-1,d3 +0: move.l #0x80018001,(a3) + dbra d3,0b + + add.l #64*2,a6 + dbra d4,lmaploop0 + + /* generate B layer map */ + movea.l #0xc000+64*14*2,a3 + jsr load_prepare + + move.l #64*14/2-1,d3 +0: move.l #0x80008000,(a3) + dbra d3,0b + + /* upload sprite data */ + movea.l #0xfc00,a3 + jsr load_prepare + movea.l #sprite_data,a0 + + move.l #(sprite_data_end-sprite_data)/2-1,d3 +0: move.l (a0)+,(a3) + dbra d3,0b + + jsr wait_vsync + +################################################## +# # +# MAIN LOOP # +# # +################################################## + +forever: + movea.l #vtimer,a0 + move.l (a0),d4 + and.w #0x1ff,d4 + movea.l #0xfc06,a6 + moveq.l #8-1,d5 + +0: + movea.l a6,a3 + jsr load_prepare + move.w d4,(a3) + addq.w #8,a6 + dbra d5,0b + + jsr wait_vsync + bra forever + + + +################################################# +# # +# Initialize VDP registers # +# # +################################################# + +init_gfx: + move.l #GFXCNTL,a3 + write_vdp_reg 0,(VDP0_E_DISPLAY + VDP0_PLTT_FULL) + write_vdp_reg 1,(VDP1_E_VBI + VDP1_E_DISPLAY + VDP1_E_DMA + VDP1_RESERVED) + write_vdp_reg 2,(0xe000 >> 10) /* Screen map a adress */ + write_vdp_reg 3,(0xe000 >> 10) /* Window address */ + write_vdp_reg 4,(0xc000 >> 13) /* Screen map b address */ + write_vdp_reg 5,(0xfc00 >> 9) /* Sprite address */ + write_vdp_reg 6,0 + write_vdp_reg 7,1 /* Border color */ + write_vdp_reg 10,1 /* Lines per hblank interrupt */ + write_vdp_reg 11,0 /* 2-cell vertical scrolling */ + write_vdp_reg 12,(VDP12_SCREEN_V224 | VDP12_SCREEN_H320 | VDP12_SPR_SHADOWS) + write_vdp_reg 13,(0x6000 >> 10) /* Horizontal scroll address */ + write_vdp_reg 15,2 + write_vdp_reg 16,(VDP16_MAP_V32 + VDP16_MAP_H64) + write_vdp_reg 17,0 + write_vdp_reg 18,0xff + rts + + + +################################################# +# # +# Load tile data from ROM # +# # +# Parameters: # +# a3: VRAM base # +# a4: pattern address # +# d4: number of tiles to load # +# Destroys a2,d0,d6-d7... # +# # +################################################# + +load_tiles: + move.l #GFXCNTL,a2 + VRAM_ADDR_var d0,a3 + move.l d0,(a2) + lsl #3,d4 + + move.l #GFXDATA,a3 + subq.l #1,d4 +_copy_tile_data: + move.l (a4)+,(a3) + dbra d4,_copy_tile_data + + rts + + +load_prepare: + move.l #GFXCNTL,a2 + VRAM_ADDR_var d0,a3 + move.l d0,(a2) + move.l #GFXDATA,a3 + + rts + + +################################################# +# # +# Clear one of the screen maps # +# # +# Parameters: # +# a0: Map address # +# d0: Data to write to each map entry # +# # +################################################# + +clear_map: + move.l #GFXCNTL,a4 + VRAM_ADDR_var d1,a0 + move.l d1,(a4) + move.l #GFXDATA,a3 + move.w #1023,d1 /* Loop counter */ +_clear_map_loop: + move.w d0,(a3) + move.w d0,(a3) + dbra d1,_clear_map_loop + rts + + +################################################# +# # +# Load color data from ROM # +# # +# Parameters: # +# a3: CRAM base # +# a4: color list address # +# d4: number of colors to load # +# # +################################################# + +load_colors: + move.l #GFXCNTL,a2 + CRAM_ADDR_var d0,a3 + move.l d0,(a2) + + move.l #GFXDATA,a3 + subq.w #1,d4 +_copy_color_data: + move.w (a4)+,(a3) + dbra d4,_copy_color_data + + rts + + +################################################# +# # +# Wait for next VBlank interrupt # +# # +################################################# + +wait_vsync: + movea.l #vtimer,a0 + move.l (a0),a1 +_wait_change: + stop #0x2000 + cmp.l (a0),a1 + beq _wait_change + rts + + +################################################# +# # +# RAM DATA # +# # +################################################# + +.bss +.globl htimer +.globl vtimer +.globl rand_num +htimer: .long 0 +vtimer: .long 0 +rand_num: .long 0 +scrollx: .long 0 + +.end + +# vim:filetype=asmM68k diff --git a/teensytp/.gitignore b/teensytp/.gitignore new file mode 100644 index 0000000..850d10a --- /dev/null +++ b/teensytp/.gitignore @@ -0,0 +1,6 @@ +*.o +*.elf +*.hex +.*.swp +cscope.out +tags diff --git a/Makefile b/teensytp/Makefile similarity index 100% rename from Makefile rename to teensytp/Makefile diff --git a/host/Makefile b/teensytp/host/Makefile similarity index 100% rename from host/Makefile rename to teensytp/host/Makefile diff --git a/host/main.c b/teensytp/host/main.c similarity index 100% rename from host/main.c rename to teensytp/host/main.c diff --git a/main.c b/teensytp/main.c similarity index 100% rename from main.c rename to teensytp/main.c diff --git a/pkts.h b/teensytp/pkts.h similarity index 100% rename from pkts.h rename to teensytp/pkts.h diff --git a/teensy3/avr_functions.h b/teensytp/teensy3/avr_functions.h similarity index 100% rename from teensy3/avr_functions.h rename to teensytp/teensy3/avr_functions.h diff --git a/teensy3/core_pins.h b/teensytp/teensy3/core_pins.h similarity index 100% rename from teensy3/core_pins.h rename to teensytp/teensy3/core_pins.h diff --git a/teensy3/kinetis.h b/teensytp/teensy3/kinetis.h similarity index 100% rename from teensy3/kinetis.h rename to teensytp/teensy3/kinetis.h diff --git a/teensy3/mk20dx128.c b/teensytp/teensy3/mk20dx128.c similarity index 100% rename from teensy3/mk20dx128.c rename to teensytp/teensy3/mk20dx128.c diff --git a/teensy3/mk20dx128.h b/teensytp/teensy3/mk20dx128.h similarity index 100% rename from teensy3/mk20dx128.h rename to teensytp/teensy3/mk20dx128.h diff --git a/teensy3/mk20dx128.ld b/teensytp/teensy3/mk20dx128.ld similarity index 100% rename from teensy3/mk20dx128.ld rename to teensytp/teensy3/mk20dx128.ld diff --git a/teensy3/mk20dx256.ld b/teensytp/teensy3/mk20dx256.ld similarity index 100% rename from teensy3/mk20dx256.ld rename to teensytp/teensy3/mk20dx256.ld diff --git a/teensy3/nonstd.c b/teensytp/teensy3/nonstd.c similarity index 100% rename from teensy3/nonstd.c rename to teensytp/teensy3/nonstd.c diff --git a/teensy3/pins_arduino.h b/teensytp/teensy3/pins_arduino.h similarity index 100% rename from teensy3/pins_arduino.h rename to teensytp/teensy3/pins_arduino.h diff --git a/teensy3/pins_teensy.c b/teensytp/teensy3/pins_teensy.c similarity index 100% rename from teensy3/pins_teensy.c rename to teensytp/teensy3/pins_teensy.c diff --git a/teensy3/usb_desc.c b/teensytp/teensy3/usb_desc.c similarity index 100% rename from teensy3/usb_desc.c rename to teensytp/teensy3/usb_desc.c diff --git a/teensy3/usb_desc.h b/teensytp/teensy3/usb_desc.h similarity index 100% rename from teensy3/usb_desc.h rename to teensytp/teensy3/usb_desc.h diff --git a/teensy3/usb_dev.c b/teensytp/teensy3/usb_dev.c similarity index 100% rename from teensy3/usb_dev.c rename to teensytp/teensy3/usb_dev.c diff --git a/teensy3/usb_dev.h b/teensytp/teensy3/usb_dev.h similarity index 100% rename from teensy3/usb_dev.h rename to teensytp/teensy3/usb_dev.h diff --git a/teensy3/usb_mem.c b/teensytp/teensy3/usb_mem.c similarity index 100% rename from teensy3/usb_mem.c rename to teensytp/teensy3/usb_mem.c diff --git a/teensy3/usb_mem.h b/teensytp/teensy3/usb_mem.h similarity index 100% rename from teensy3/usb_mem.h rename to teensytp/teensy3/usb_mem.h diff --git a/teensy3/usb_names.h b/teensytp/teensy3/usb_names.h similarity index 100% rename from teensy3/usb_names.h rename to teensytp/teensy3/usb_names.h diff --git a/teensy3/usb_rawhid.c b/teensytp/teensy3/usb_rawhid.c similarity index 100% rename from teensy3/usb_rawhid.c rename to teensytp/teensy3/usb_rawhid.c diff --git a/teensy3/usb_rawhid.h b/teensytp/teensy3/usb_rawhid.h similarity index 100% rename from teensy3/usb_rawhid.h rename to teensytp/teensy3/usb_rawhid.h diff --git a/teensy3/usb_seremu.c b/teensytp/teensy3/usb_seremu.c similarity index 100% rename from teensy3/usb_seremu.c rename to teensytp/teensy3/usb_seremu.c diff --git a/teensy3/usb_seremu.h b/teensytp/teensy3/usb_seremu.h similarity index 100% rename from teensy3/usb_seremu.h rename to teensytp/teensy3/usb_seremu.h