; i2cdump.asm DEBUG SET 0 ; general register usage: ; A5 = $C00000 VDP data - PSG at $0011(A5) ; A6 = $C00004 VDP control/status ; A7 = $FFFFxx stack pointer LIST OFF INCLUDE gen.h LIST ON IF ..undef DEBUG DEBUG SET 0 ENDIF IF DEBUG LIST OFF INCLUDE genbug.i LIST ON ELSE DEBUG SET 0 MACRO DEBUG_INIT ENDM MACRO DEBUG ENDM ENDIF ;----------------------------------------------------------------------- ; VRAM layout ; ; 0000 - 7FFF pattern generator table (size 8000) ; 8000 - BFFF unused ; C000 - CFFF scroll A name table base (max size 1000) ; D800 - DFFF sprite attribute table base (max size 0A00) ; E000 - EFFF scroll B name table base (max size 1000) ; F000 - F7FF window name table base (max size 0800) ; FC00 - FFFF H-scroll table base (max size 0400) ;----------------------------------------------------------------------- PatternTbl EQU $0000 ; pattern table base (fixed) NameATbl EQU $C000 ; name table base for scroll A SprtAttrTbl EQU $D800 ; sprite attribute table base NameBTbl EQU $E000 ; name table base for scroll B NameWTbl EQU $F000 ; name table base for window HScrollTbl EQU $FC00 ; H-scroll table base (V-scroll table is in VSRAM) ; pre-formatted for VDP command register, add (offset<<16) Pattern_R EQU $00000000 ; 0000 pattern table base (fixed) NameA_R EQU $00000003 ; C000 name table base for scroll A SprtAttr_R EQU $18000003 ; D800 sprite attribute table base NameB_R EQU $20000003 ; E000 name table base for scroll B NameW_R EQU $30000003 ; F000 name table base for window HScroll_R EQU $3C000003 ; FC00 H-scroll table base (V-scroll table is in VSRAM) Pattern_W EQU $40000000 ; 0000 pattern table base (fixed) NameA_W EQU $40000003 ; C000 name table base for scroll A SprtAttr_W EQU $58000003 ; D800 sprite attribute table base NameB_W EQU $60000003 ; E000 name table base for scroll B NameW_W EQU $70000003 ; F000 name table base for window HScroll_W EQU $7C000003 ; FC00 H-scroll table base (V-scroll table is in VSRAM) ;----------------------------------------------------------------------- ; RAM usage ;----------------------------------------------------------------------- SEG RAM ORG $FFFF0000 RAMBase EQU * ; first half of RAM, can't use abs.w addressing mode Buffer DS 256 ORG $FFFF8000 ; starting at this address, abs.w mode is valid VTimer DS 4 ; tick count since startup Ticks DS 1 EVEN I2C_port EQU $200000 SDA_0_SCL_0 EQU $00 ; 00 SDA=0 SCL=0 SDA_0_SCL_1 EQU $40 ; 40 SDA=0 SCL=1 SDA_1_SCL_0 EQU $80 ; 80 SDA=1 SCL=0 SDA_1_SCL_1 EQU $C0 ; C0 SDA=1 SCL=1 DFFBE88 EQU $FFBE88 ; word, for controller #1 DFFBE8A EQU $FFBE8A ; word, for controller #2 DFFCAEE EQU $FFCAEE ; 128-byte buffer FFCAEE-FFCB6D? DFFCB6C EQU DFFCAEE+126; byte, write-only DFFCDF2 EQU $FFCDF2 ; word - timeout limit DFFCDF4 EQU $FFCDF4 ; word - timeout counter, set to FFFF if failure DFFCDF6 EQU $FFCDF6 ; long - saves A0 in I2CReadBlock DFFCDFA EQU $FFCDFA ; long - saves D0 in I2CReadBlock DFFCDFE EQU $FFCDFE ; long - saves D1 in I2CReadBlock DFFCE02 EQU $FFCE02 ; word - counter initialized from D1 in I2CReadBlock DFFCE04 EQU $FFCE04 ; word/byte DFFCE05 EQU DFFCE04+1 ; byte? DFFCE06 EQU $FFCE06 ; long DFFCE0A EQU $FFCE0A ; long DFFCE0E EQU $FFCE0E ; word, = 0 1 or -1, write-only UStack EQU $00000000 ; user-mode stack at top of RAM (unused?) Stack EQU UStack-256 ; supervisor-mode stack below user-mode stack RAMend EQU $FFFFFFFF ; check if space left for stack IF (* >= Stack-512) ERROR RAM area too large! ENDIF ;----------------------------------------------------------------------- ; exception vectors ;----------------------------------------------------------------------- SEG CODE ORG $000000 ROMBase DC.L Stack ; startup SP DC.L Start ; startup PC DC.L BusError ; Bus error exception DC.L AddrError ; Address error exception DC.L Illegal ; Illegal instruction exception DC.L DivZero ; Divide by Zero exception DC.L CHK ; CHK exception DC.L TRAP ; TRAP exception DC.L RTE ; Privilege Violation DC.L Trace DC.L LineA ; line 1010 emulator DC.L LineF ; line 1111 emulator DS.L 4,RTE ; unassigned/uninitialized DS.L 8,RTE ; unassigned DC.L RTE ; spurious interrupt DC.L Int ; interrupt level 1 (lowest priority) DC.L ExtInt ; interrupt level 2 = external interrupt DC.L Int ; interrupt level 3 DC.L HSync ; interrupt level 4 = H-sync interrupt DC.L Int ; interrupt level 5 DC.L VSync ; interrupt level 6 = V-sync interrupt DC.L Int ; interrupt level 7 (highest priority) DS.L 15,RTE ; TRAP instruction vectors DC.L Trap15 ; TRAP #15 DS.L 16,RTE ; unassigned ;----------------------------------------------------------------------- ; cartridge info header ;----------------------------------------------------------------------- DC.B "SEGA GENESIS " ; must start with "SEGA" DC.B "(C)BRUCE" ; copyright DC.B "2007.MAY" ; date DC.B "I2CDUMP " ; cart name DC.B "I2CDUMP " ; cart name (alt. language) DC.B "GM MK-0000 -00" ; program type / catalog number DC.W $0000 ; ROM checksum DC.B "J " ; hardware used DC.L ROMBase,ROMend ; ROM start/end RAMspec DC.L RAMBase,RAMEnd ; RAM start/end DC.B " " ; backup RAM info DC.B " " ; modem info Version DC.B "v000 2007-05-09 " ; comment DC.B "JUE " ; regions allowed ;----------------------------------------------------------------------- ; generic exception handler ;----------------------------------------------------------------------- VSync ADDQ.L #1,VTimer ; increment VSync counter ExtInt HSync RTE RTE IF DEBUG ELSE BusError AddrError ADDQ.L #8,A7 ; remove extra crap from stack Illegal DivZero CHK TRAP Trace LineA LineF Int Trap15 if 1 MOVE.L #NameA_W,D6 MOVE.L D6,(A6) MOVE.L 2(A7),D0 ; get caller's PC BSR PutHex8 BRA.S . endif RTE ENDIF ;----------------------------------------------------------------------- ; main entry point ;----------------------------------------------------------------------- Start ; initialize registers LEA InitRegs(PC),A1 MOVEM.L (A1)+,A3-A6 ; initialize TMSS MOVE.B (A3),D0 ; A10001 test the hardware version ANDI.B #$0F,D0 BEQ.B .1 ; branch if no TMSS MOVE.L #'SEGA',(A4) ; A14000 disable TMSS .1 MOVE.W (A6),D0 ; C00004 read VDP status (interrupt acknowledge?) ; initialize USP, and set D0=0 MOVEQ #0,D0 ; == UStack MOVEA.L D0,A0 MOVE A0,USP ; If this isn't written to the VDP within a few dozen cycles of startup, ; the OS X version of SDLMESS makes the window small. Why? Who the fuck knows. ; It's annoying and flickery when it happens, so let's not let it happen. MOVE.W #$8C81,(A6) ; reg 12 = mode register 4: 40 cell horizontal mode, no interlace ; initialize VDP registers MOVEQ #24-1,D1 ; length of video initialization block MOVE.W #$8000,D7 ; first register number .2: MOVE.B (A1)+,D7 ; get next video control byte (high word is command!) MOVE.W D7,(A6) ; C00004 send write register command to VDP ADD.W #$0100,D7 ; point to next VDP register DBRA D1,.2 ; loop for rest of block ; initialize RAM MOVE.L RAMspec,A0 ; get start of RAM MOVE.W #$4000-1,D1 ; get size of RAM in longwords .2a MOVE.L D0,(A0)+ DBRA D1,.2a ; DMA is now set up for 65535-byte fill of VRAM, let's do it MOVE.L #$40000080,(A6) ; C00004 = VRAM write to $0000 (what is the 80 bit for?) MOVE.W D0,(A5) ; C00000 = write zero to VRAM (starts DMA fill) .3: MOVE.W (A6),D4 ; C00004 read VDP status BTST #1,D4 ; test DMA busy flag BNE.B .3 ; loop while DMA busy ; initialize CRAM MOVE.L #$81048F02,(A6) ; C00004 reg 1 = 0x04, reg 15 = 0x02: blank, auto-increment=2 MOVE.L #$C0000000,(A6) ; C00004 write CRAM address $0000 MOVEQ #32-1,D1 ; loop for 32 CRAM registers .4: MOVE.L D0,(A5) ; C00000 clear CRAM register DBRA D1,.4 ; initialize VSRAM MOVE.L #$40000010,(A6) ; C00004 VSRAM write address $0000 MOVEQ #20-1,D1 ; loop for 20 VSRAM registers .5: MOVE.L D0,(A5) ; C00000 clear VSRAM register DBRA D1,.5 ; initialize PSG MOVEQ #4-1,D1 ; loop for 4 PSG registers .6: MOVE.B (A1)+,$0011(A5) ; C00011 copy PSG initialization commands DBRA D1,.6 BSR.W InitCRAM ; set up colors in CRAM LEA Font(PC),A0 ; get address and size of font data MOVE.L #FontSize/4-1,D1 MOVE.L #Pattern_W+($00*32<<16),(A6) ; C00004 VRAM write to start of font ; MOVE.L #$4C200000,(A6) ; C00004 VRAM write to $0C20 .7: MOVE.L (A0)+,(A5) ; C00000 write next longword of charset to VDP DBRA D1,.7 ; loop until done ; MOVE.W #$8144,(A6) ; C00004 reg 1 = 0x44 unblank display ; MOVE.W #$8104,(A6) ; C00004 reg 1 = 0x04 blank display ;----------------------------------------------------------------------- DEBUG_INIT ; DEBUG MOVE.W #$2500,SR ; enable V-sync interrupt MOVE.W #$8134,(A6) ; C00004 reg 1 = 0x34 enable V-sync interrupt and DMA MOVE.W #$8174,(A6) ; C00004 reg 1 = 0x74 unblank display, enable V-sync interrupt and DMA ; initialize joypad ports MOVEQ #$40,D0 ; all bits input, except TH=output MOVE.B D0,P_control_1 ; MOVEQ #0,P_data_1 MOVE.B D0,P_control_2 ; MOVEQ #0,P_data_2 MOVE.B D0,P_control_3 ; MOVEQ #0,P_data_3 MOVE.W #$8174,(A6) ; C00004 reg 1 = 0x74 unblank display, enable V-sync interrupt and DMA ;----------------------------------------------------------------------- if 0 ; LEA Buffer,A0 LEA ROMBase,A0 MOVE.L #$1C0,D1 BSR.B DumpIt else BSR.W I2CInit ; reset some flags, then send nine I2C starts and an I2C stop? MOVEQ #0,D0 LEA Buffer,A0 MOVE.L #128,D1 BSR I2CReadBlock MOVE.L #NameA_W+((27*128)<<16),(A6) MOVE.W DFFCDF4,D0 BSR PutHex4 LEA Buffer,A0 MOVE.L #128,D1 BSR.B DumpIt endif DEBUG loop bra loop ;----------------------------------------------------------------------- DumpIt MOVE.L #NameA_W,D6 MOVE.L D6,(A6) MOVE.L #0,D3 ; current address .10 MOVE.L D3,D0 ANDI.B #$0F,D0 BNE.S .20 MOVE.L D3,D0 BSR.W PutHex4 MOVE.B #' ',(A5) .20 MOVE.B D3,D0 ANDI.B #15,D0 BEQ.B .30 ANDI.B #3,D0 BNE.S .30 MOVE.B #' ',(A5) .30 MOVE.B (A0)+,D0 BSR.W PutHex2 ADDQ.W #1,D3 MOVE.B D3,D0 ANDI.B #15,D0 BNE.B .40 ADDI.L #128<<16,D6 MOVE.L D6,(A6) .40 SUBQ.W #1,D1 BNE.B .10 RTS ;----------------------------------------------------------------------- ;----------------------------------------------------------------------- ; send I2C start ; SCL = 1 1 0 ; SDA = 1 0 0 I2CStart NOP NOP NOP NOP NOP MOVE.W #SDA_1_SCL_1,I2C_port NOP NOP NOP NOP NOP NOP NOP MOVE.W #SDA_0_SCL_1,I2C_port NOP NOP NOP NOP NOP NOP NOP MOVE.W #SDA_0_SCL_0,I2C_port NOP RTS ;----------------------------------------------------------------------- ; send I2C stop ; SCL = 0 1 1 0 ; SDA = 0 0 1 1 I2CStop MOVE.W #SDA_0_SCL_0,I2C_port NOP NOP NOP NOP NOP NOP MOVE.W #SDA_0_SCL_1,I2C_port NOP NOP NOP NOP NOP MOVE.W #SDA_1_SCL_1,I2C_port NOP NOP NOP NOP NOP MOVE.W #SDA_1_SCL_0,I2C_port NOP RTS ;----------------------------------------------------------------------- ; clock out high bit of D0.W ; SCL = 0 1 0 ; SDA = high bit shifted out of D0 I2CWriteBit LSL.W #1,D0 ROXR.B #1,D1 BCLR #6,D1 ; SCL = 0 MOVE.W D1,I2C_port NOP NOP NOP NOP BSET #6,D1 ; SCL = 1 MOVE.W D1,I2C_port NOP NOP NOP NOP BCLR #6,D1 ; SCL = 0 MOVE.W D1,I2C_port RTS ;----------------------------------------------------------------------- ; clock in low bit of D0 ; SCL = 0 1 0 ; SDA = 1 1 1 ; SDA bit shifted into low bit of D0 I2CReadBit MOVE.W #SDA_1_SCL_0,I2C_port NOP NOP NOP NOP MOVE.W #SDA_1_SCL_1,I2C_port NOP NOP NOP NOP NOP NOP MOVE.W I2C_port,D1 ; read SDA MOVE.W #SDA_1_SCL_0,I2C_port ASL.B #1,D1 ROXL.W #1,D0 RTS ;----------------------------------------------------------------------- ; send 0 bit (ACK) ; SCL = 0 1 0 ; SDA = 0 0 0 I2CAck MOVE.W #SDA_0_SCL_0,I2C_port NOP NOP NOP NOP NOP NOP NOP MOVE.W #SDA_0_SCL_1,I2C_port NOP NOP NOP NOP NOP NOP NOP MOVE.W #SDA_0_SCL_0,I2C_port NOP RTS ;----------------------------------------------------------------------- ; send 1 bit (NACK) ; SCL = 0 1 0 ; SDA = 1 1 1 I2CNak MOVE.W #SDA_1_SCL_0,I2C_port NOP NOP NOP NOP NOP NOP NOP MOVE.W #SDA_1_SCL_1,I2C_port NOP NOP NOP NOP NOP NOP NOP MOVE.W #SDA_1_SCL_0,I2C_port NOP RTS ;----------------------------------------------------------------------- ; read a bit into D7.bit1 ; SCL = 0 1 0 ; SDA = 1 1 1 ; D1.bit7 = SDA I2CReadAck MOVE.W #SDA_1_SCL_0,I2C_port NOP MOVE.W #SDA_1_SCL_1,I2C_port NOP NOP NOP NOP NOP NOP NOP MOVE.W I2C_port,D1 ; read SDA MOVE.W #SDA_1_SCL_0,I2C_port NOP RTS ;----------------------------------------------------------------------- ; send nine I2C starts and an I2C stop? ; this may be used to ensure that the EEPROM is not in the middle of ; an incomplete operation ; SCL = 0-1 1 0-0-1 1 0-0-1 1 0-0-1 1 0-0-1 1 0-...-0 1 1 0 ; SDA = 1-1 0 0-1-1 0 0-1-1 0 0-1-1 0 0-1-1 0 0-...-0 0 1 1 I2CInit MOVE.W #$000A,DFFCDF2 ; reset timeout limit = ten tries MOVE.W #$0000,DFFCDF4 ; reset timeout counter I2CReset MOVE.W #6500,D0 ; delay a while .10 NOP DBRA D0,.10 MOVE.W #$0008,D0 ; do nine I2C starts .20 MOVE.W #SDA_1_SCL_0,I2C_port ; get SDA ready for next I2C start NOP NOP NOP NOP NOP NOP BSR.W I2CStart ; send I2C start DBRA D0,.20 BSR.W I2CStop ; send I2C stop RTS ;----------------------------------------------------------------------- ; read I2C block (Atmel 24C01 specific) ; D0 = memory address ; D1.W = buffer size ; A0 = buffer address I2CReadBlock MOVE.W #$0000,DFFCDF4 ; reset timeout counter MOVE.W D1,DFFCE02 MOVE.L A0,DFFCDF6 MOVE.L D0,DFFCDFA MOVE.L D1,DFFCDFE BRA.S .20 .10 BSR.B I2CReset ; send nine I2C starts and an I2C stop? .20 MOVEA.L DFFCDF6,A0 MOVE.L DFFCDFA,D0 BSR.W I2CStart ; send I2C start ANDI.W #$007F,D0 LSL.W #1,D0 ORI.W #$0001,D0 ; set read bit LSL.W #8,D0 ; align to top of word BSR.W I2CWriteBit ; clock out high bit of D0 BSR.W I2CWriteBit ; clock out high bit of D0 BSR.W I2CWriteBit ; clock out high bit of D0 BSR.W I2CWriteBit ; clock out high bit of D0 BSR.W I2CWriteBit ; clock out high bit of D0 BSR.W I2CWriteBit ; clock out high bit of D0 BSR.W I2CWriteBit ; clock out high bit of D0 BSR.W I2CWriteBit ; clock out high bit of D0 BSR.W I2CReadAck ; read a bit into D7.bit1 TST.B D1 ; check ACK flag BPL.S .30 ; branch if ACK from device ADDQ.W #1,DFFCDF4 ; increment timeout counter BMI.S .98 ; branch if timeout overflow MOVE.W DFFCDF4,D1 CMP.W DFFCDF2,D1 ; compare against timeout limit BPL.S .98 ; branch if timeout overflow BSR.W I2CReset ; send nine I2C starts and an I2C stop? BRA.S .10 ; try to send device address again .30 BSR.W I2CReadBit ; clock in low bit of D0 BSR.W I2CReadBit ; clock in low bit of D0 BSR.W I2CReadBit ; clock in low bit of D0 BSR.W I2CReadBit ; clock in low bit of D0 BSR.W I2CReadBit ; clock in low bit of D0 BSR.W I2CReadBit ; clock in low bit of D0 BSR.W I2CReadBit ; clock in low bit of D0 BSR.W I2CReadBit ; clock in low bit of D0 MOVE.B D0,(A0)+ ; save byte to buffer SUBQ.W #1,DFFCE02 ; decrement buffer counter BEQ.S .40 ; branch to send NACK if last byte BSR.W I2CAck ; send 0 bit (ACK) BRA.S .30 .40 BSR.W I2CNak ; send 1 bit (NACK) BSR.W I2CStop ; send I2C stop .99 MOVEA.L DFFCDF6,A0 MOVE.L DFFCDFA,D0 MOVE.L DFFCDFE,D1 RTS .98 MOVE.W #$FFFF,DFFCDF4 ; timeout counter = failure BRA.S .99 ;----------------------------------------------------------------------- ; write I2C byte (Atmel 24C01 specific) ; D0 = memory address ; A0 = buffer address I2CWriteByte MOVE.W #$0000,DFFCDF4 ; reset timeout counter MOVE.L A0,DFFCE06 MOVE.L D0,DFFCE0A MOVE.L D1,-(A7) BRA.S .20 .10 BSR.W I2CReset ; send nine I2C starts and an I2C stop? .20 MOVEA.L DFFCE06,A0 MOVE.L DFFCE0A,D0 BSR.W I2CStart ; send I2C start ANDI.W #$007F,D0 LSL.W #1,D0 ; (don't set low bit = write operation) LSL.W #8,D0 ; align to top of word MOVE.W D0,DFFCE04 BSR.W I2CWriteBit ; clock out high bit of D0 BSR.W I2CWriteBit ; clock out high bit of D0 BSR.W I2CWriteBit ; clock out high bit of D0 BSR.W I2CWriteBit ; clock out high bit of D0 BSR.W I2CWriteBit ; clock out high bit of D0 BSR.W I2CWriteBit ; clock out high bit of D0 BSR.W I2CWriteBit ; clock out high bit of D0 BSR.W I2CWriteBit ; clock out high bit of D0 BSR.W I2CReadAck ; read a bit into D7.bit1 TST.B D1 ; check ACK flag BPL.S .30 ; branch if ACK from device ADDQ.W #1,DFFCDF4 ; increment timeout counter BMI.W .98 ; branch if timeout overflow MOVE.W DFFCDF4,D1 CMP.W DFFCDF2,D1 ; compare against timeout limit BPL.W .98 ; branch if timeout overflow BSR.W I2CReset ; send nine I2C starts and an I2C stop? BRA.S .10 ; try to send device address again .30 MOVE.B (A0),D0 LSL.W #8,D0 BSR.W I2CWriteBit ; clock out high bit of D0 BSR.W I2CWriteBit ; clock out high bit of D0 BSR.W I2CWriteBit ; clock out high bit of D0 BSR.W I2CWriteBit ; clock out high bit of D0 BSR.W I2CWriteBit ; clock out high bit of D0 BSR.W I2CWriteBit ; clock out high bit of D0 BSR.W I2CWriteBit ; clock out high bit of D0 BSR.W I2CWriteBit ; clock out high bit of D0 BSR.W I2CReadAck ; read a bit into D7.bit1 TST.B D1 ; check ACK flag BPL.S .40 ; branch if ACK from device ADDQ.W #1,DFFCDF4 ; increment timeout counter BMI.S .98 ; branch if timeout overflow MOVE.W DFFCDF4,D1 CMP.W DFFCDF2,D1 ; compare against timeout limit BPL.S .98 ; branch if timeout overflow BSR.W I2CReset ; send nine I2C starts and an I2C stop? BRA.W .10 ; try to send device address again .40 BSR.W I2CStop ; send I2C stop MOVE.W #5400,D0 ; delay a while .50 NOP DBRA D0,.50 CLR.L D0 ; clear high bytes of D0 MOVE.B DFFCE04,D0 ; get memory address LSR.L #1,D0 ; shift out the R/W bit (this gets ignored later?) MOVEQ #$01,D1 ; buffer size = 1 byte MOVE.L DFFCE0A,D0 ; memory address LEA DFFCE05,A0 ; buffer address BSR.W I2CReadBlock ; read I2C block TST.W DFFCDF4 BMI.S .98 ; branch if failure MOVEA.L DFFCE06,A0 MOVE.B DFFCE05,D0 CMP.B (A0),D0 BPL.S .99 ADDQ.W #1,DFFCDF4 ; increment timout counter BMI.S .98 ; branch if timeout overflow MOVE.W DFFCDF4,D1 CMP.W DFFCDF2,D1 ; compare against timeout limit BPL.S .98 ; branch if timeout overflow BSR.W I2CReset ; send nine I2C starts and an I2C stop? BRA.W .10 ; try to send device address again .99 MOVEA.L DFFCE06,A0 MOVE.L DFFCE0A,D0 MOVE.L (A7)+,D1 RTS .98 MOVE.W #$FFFF,DFFCDF4 ; timeout counter = failure BRA.B .99 ;----------------------------------------------------------------------- ;----------------------------------------------------------------------- HexAsc2 MOVE.W D0,D1 ; save low nibble for later LSR.B #4,D0 BSR.S HexAsc1 ; convert high nibble to hex SWAP D0 ; save ASCII of high nibble in high word of D0 MOVE.B D1,D0 HexAsc1 ANDI.W #$0F,D0 MOVE.B HexDigits(PC,D0.W),D0 RTS HexDigits DB '0123456789ABCDEF' ;----------------------------------------------------------------------- ; put hex numbers to the current VRAM address (for debugging) PutHex8 SWAP.W D0 BSR.S PutHex4 SWAP.W D0 PutHex4 move.l d0,-(a7) ROR.L #8,D0 BSR.S PutHex2 ; ROL.L #8,D0 move.l (a7)+,d0 PutHex2 MOVEM.L D0/D1,-(A7) ; ANDI.L #255,D0 BSR HexAsc2 MOVE.L D0,(A5) MOVEM.L (A7)+,D1/D0 RTS ;----------------------------------------------------------------------- ; Set up colors in CRAM ;----------------------------------------------------------------------- InitCRAM LEA CRAM_tab(PC),A0 MOVE.W (A0)+,D0 ; get length word MOVE.L #$C0000000,(A6) ; C00004 CRAM write address = $0000 .10 MOVE.W (A0)+,(A5) ; C00000 write next word to video DBRA D0,.10 ; loop until done RTS ; CRAM initialization (note: palette data is BGR) CRAM_tab DC.W (CRAM_end-*)/2-2 ; number of table entries - 1 DC.W $222,$000,$2D2,$6F6,$F22,$F64,$12B,$FD4,$22F,$66F,$2DD,$9DD,$292,$B4D,$BBB,$FFF CRAM_end ; TMS9918A palette: ; ; R G B ; 0 = transparent ; 1 = 00 00 00 black ; 2 = 22 DD 22 med green ; 3 = 66 FF 66 lt green ; 4 = 22 22 FF dk blue ; 5 = 44 66 FF purple ; 6 = BB 22 11 dk red / brown ; 7 = 44 DD FF cyan / aqua ; 8 = FF 22 22 red ; 9 = FF 66 66 pink ; A = DD DD 22 olive ; B = DD DD 99 lt brown/yellow ; C = 22 99 22 dk green ; D = DD 44 BB magenta-ish ; E = BB BB BB lt gray ; F = FF FF FF white ; colors: 0 = transparent 4 = dk blue 8 = red C = dk. green ; 1 = black 5 = purple 9 = pink D = magenta-ish ; 2 = med. green 6 = dk. red A = olive E = lt. gray ; fg/bg 3 = lt. green 7 = aqua B = lt. brown F = white ;----------------------------------------------------------------------- InitRegs ; DC.L $00008000 ; D7 = VDP register 0 write command (data goes in low byte) DC.L HW_Version ; A3 = A10001 used for hardware version and TMSS registers DC.L TMSS_reg ; A4 = A14000 TMSS register DC.L VDP_data ; A5 = C00000 VDP data DC.L VDP_ctrl ; A6 = C00004 VDP control / status ; A1 = pointer to the following data: ; VDP register initialization (24 bytes) DC.B $04 ; reg 0 = mode register 1: no H interrupt DC.B $14 ; reg 1 = mode register 2: blanked, no V interrupt, DMA enable DC.B $30 ; reg 2 = name table base for scroll A: $C000 DC.B $3C ; reg 3 = name table base for window: $F000 DC.B $07 ; reg 4 = name table base for scroll B: $E000 DC.B $6C ; reg 5 = sprite attribute table base: $D800 DC.B $00 ; reg 6 = unused register: $00 DC.B $00 ; reg 7 = background color: $00 = plt 0 color 0 DC.B $00 ; reg 8 = unused register: $00 DC.B $00 ; reg 9 = unused register: $00 DC.B $FF ; reg 10 = H interrupt register: $FF (esentially off) DC.B $00 ; reg 11 = mode register 3: disable ext int, full H/V scroll DC.B $81 ; reg 12 = mode register 4: 40 cell horizontal mode, no interlace DC.B $37 ; reg 13 = H scroll table base: $FC00 DC.B $00 ; reg 14 = unused register: $00 DC.B $01 ; reg 15 = auto increment: $01 DC.B $01 ; reg 16 = scroll size: V=32 cell, H=64 cell DC.B $00 ; reg 17 = window H position: $00 DC.B $00 ; reg 18 = window V position: $00 DC.B $FF ; reg 19 = DMA length count low: $xxFF DC.B $FF ; reg 20 = DMA length count high: $FFxx DC.B $00 ; reg 21 = DMA source address low: $xxxx00 DC.B $00 ; reg 22 = DMA source address mid: $xx00xx DC.B $80 ; reg 23 = DMA source address high: VRAM fill, addr = $00xxxx ; PSG initialization: set all channels to minimum volume DC.B $9F,$BF,$DF,$FF EVEN ;----------------------------------------------------------------------- ; pattern table initialization Font HEX 11111111 11111111 11111111 11111111 ; 00 = BLANK HEX 11111111 11111111 11111111 11111111 HEX 11111111 11111111 11111111 11111111 ; 01 = HEX 11111111 11111111 11111111 11111111 HEX 11111111 11111111 11111111 11111111 ; 02 = HEX 11111111 11111111 11111111 11111111 HEX 11111111 11111111 11111111 11111111 ; 03 = HEX 11111111 11111111 11111111 11111111 HEX 11111111 11111111 11111111 11111111 ; 04 = HEX 11111111 11111111 11111111 11111111 HEX 11111111 11111111 11111111 11111111 ; 05 = HEX 11111111 11111111 11111111 11111111 HEX 11111111 11111111 11111111 11111111 ; 06 = HEX 11111111 11111111 11111111 11111111 HEX 11111111 11111111 11111111 11111111 ; 07 = HEX 11111111 11111111 11111111 11111111 HEX 11111111 11111111 11111111 11111111 ; 08 = HEX 11111111 11111111 11111111 11111111 HEX 11111111 11111111 11111111 11111111 ; 09 = HEX 11111111 11111111 11111111 11111111 HEX 11111111 11111111 11111111 11111111 ; 0A = HEX 11111111 11111111 11111111 11111111 HEX 11111111 11111111 11111111 11111111 ; 0B = HEX 11111111 11111111 11111111 11111111 HEX 11111111 11111111 11111111 11111111 ; 0C = HEX 11111111 11111111 11111111 11111111 HEX 11111111 11111111 11111111 11111111 ; 0D = HEX 11111111 11111111 11111111 11111111 HEX 11111111 11111111 11111111 11111111 ; 0E = HEX 11111111 11111111 11111111 11111111 HEX 11111111 11111111 11111111 11111111 ; 0F = HEX 11111111 11111111 11111111 11111111 HEX 11111111 11111111 11111111 11111111 ; 10 = HEX 11111111 11111111 11111111 11111111 HEX 11111111 11111111 11111111 11111111 ; 11 = HEX 11111111 11111111 11111111 11111111 HEX 11111111 11111111 11111111 11111111 ; 12 = HEX 11111111 11111111 11111111 11111111 HEX 11111111 11111111 11111111 11111111 ; 13 = HEX 11111111 11111111 11111111 11111111 HEX 11111111 11111111 11111111 11111111 ; 14 = HEX 11111111 11111111 11111111 11111111 HEX 11111111 11111111 11111111 11111111 ; 15 = HEX 11111111 11111111 11111111 11111111 HEX 11111111 11111111 11111111 11111111 ; 16 = HEX 11111111 11111111 11111111 11111111 HEX 11111111 11111111 11111111 11111111 ; 17 = HEX 11111111 11111111 11111111 11111111 HEX 11111111 11111111 11111111 11111111 ; 18 = HEX 11111111 11111111 11111111 11111111 HEX 11111111 11111111 11111111 11111111 ; 19 = HEX 11111111 11111111 11111111 11111111 HEX 11111111 11111111 11111111 11111111 ; 1A = HEX 11111111 11111111 11111111 11111111 HEX 11111111 11111111 11111111 11111111 ; 1B = HEX 11111111 11111111 11111111 11111111 HEX 11111111 11111111 11111111 11111111 ; 1C = HEX 11111111 11111111 11111111 11111111 HEX 11FFFF11 1F1111F1 F11FF11F F1F1111F ; 1D = (C) HEX F1F1111F F11FF11F 1F1111F1 11FFFF11 HEX 11FFFFF1 1111F111 1111F111 1111F111 ; 1E = T HEX 11111111 11111111 11111111 11111111 HEX F111F111 FF1FF111 F1F1F111 F1F1F111 ; 1F = M HEX 11111111 11111111 11111111 11111111 HEX 11111111 11111111 11111111 11111111 ; 20 = SPACE HEX 11111111 11111111 11111111 11111111 HEX 111F1111 11FFF111 11FFF111 11FF1111 ; 21 = ! HEX 11F11111 11111111 1FF11111 11111111 HEX 1FF11FF1 1FF11FF1 1F111F11 11111111 ; 22 = " HEX 11111111 11111111 11111111 11111111 HEX 1FF1FF11 1FF1FF11 FFFFFFF1 1FF1FF11 ; 23 = # HEX FFFFFFF1 1FF1FF11 1FF1FF11 11111111 HEX 111FF111 11FFFFF1 1F1FF111 11FFFF11 ; 24 = $ HEX 111FF1F1 1FFFFF11 111FF111 11111111 HEX 11111111 FF111FF1 FF11FF11 111FF111 ; 25 = % HEX 11FFF111 1FF11FF1 FF111FF1 11111111 HEX 1FFF1111 FF11F111 F1111F11 1FFF1111 ; 26 = & HEX FF1FF1F1 F111FF11 1FFF1FF1 11111111 HEX 11FF1111 11FF1111 1FF11111 11111111 ; 27 = ' HEX 11111111 11111111 11111111 11111111 HEX 111FF111 11FF1111 1FF11111 1FF11111 ; 28 = ( HEX 1FF11111 11FF1111 111FF111 11111111 HEX 11FF1111 111FF111 1111FF11 1111FF11 ; 29 = ) HEX 1111FF11 111FF111 11FF1111 11111111 HEX 111F1111 FF1F1FF1 1FFFFF11 11FFF111 ; 2A = * HEX 1FFFFF11 FF1F1FF1 111F1111 11111111 HEX 111F1111 11FF1111 11FF1111 FFFFFF11 ; 2B = + HEX 11FF1111 11FF1111 11F11111 11111111 HEX 11111111 11111111 11111111 11111111 ; 2C = , HEX 11111111 11FF1111 11FF1111 1FF11111 HEX 11111111 11111111 11111111 1FFFFFF1 ; 2D = - HEX FFFFFF11 11111111 11111111 11111111 HEX 11111111 11111111 11111111 11111111 ; 2E = . HEX 11111111 11FF1111 11FF1111 11111111 HEX 11111111 11111FF1 1111FF11 111FF111 ; 2F = / HEX 11FF1111 1FF11111 FF111111 11111111 HEX 11FFF111 1F11FF11 FF111FF1 FF111FF1 ; 30 = 0 HEX FF111FF1 1FF11F11 11FFF111 11111111 HEX 11FF1111 1FFF1111 11FF1111 11FF1111 ; 31 = 1 HEX 11FF1111 11FF1111 FFFFFF11 11111111 HEX 1FFFFF11 FF111FF1 1111FFF1 11FFFF11 ; 32 = 2 HEX 1FFFF111 FFF11111 FFFFFFF1 11111111 HEX 1FFFFFF1 1111FF11 111FF111 11FFFF11 ; 33 = 3 HEX 11111FF1 FF111FF1 1FFFFF11 11111111 HEX 111FFF11 11FFFF11 1FF1FF11 FF11FF11 ; 34 = 4 HEX FFFFFFF1 1111FF11 1111FF11 11111111 HEX FFFFFF11 FF111111 FFFFFF11 11111FF1 ; 35 = 5 HEX 11111FF1 FF111FF1 1FFFFF11 11111111 HEX 11FFFF11 1FF11111 FF111111 FFFFFF11 ; 36 = 6 HEX FF111FF1 FF111FF1 1FFFFF11 11111111 HEX FFFFFFF1 FF111FF1 1111FF11 111FF111 ; 37 = 7 HEX 11FF1111 11FF1111 11FF1111 11111111 HEX 1FFFF111 FF111F11 FFF11F11 1FFFF111 ; 38 = 8 HEX F11FFFF1 F1111FF1 1FFFFF11 11111111 HEX 1FFFFF11 FF111FF1 FF111FF1 1FFFFFF1 ; 39 = 9 HEX 11111FF1 1111FF11 1FFFF111 11111111 HEX 11111111 11111111 11FF1111 11FF1111 ; 3A = : HEX 11111111 11FF1111 11FF1111 11111111 HEX 11111111 11111111 11FF1111 11FF1111 ; 3B = ; HEX 11111111 11FF1111 11FF1111 1FF11111 HEX 1111FF11 111FF111 11FF1111 1FF11111 ; 3C = < HEX 11FF1111 111FF111 1111FF11 11111111 HEX 11111111 11111111 1FFFFF11 11111111 ; 3D = = HEX 1FFFFF11 11111111 11111111 11111111 HEX 1FF11111 11FF1111 111FF111 1111FF11 ; 3E = > HEX 111FF111 11FF1111 1FF11111 11111111 HEX 1FFFF111 FF11FF11 1111FF11 111FF111 ; 3F = ? HEX 11FF1111 11111111 11FF1111 11111111 HEX 1FFFFF11 FF111FF1 FF11FFF1 FF1F1FF1 ; 40 = @ HEX FF1FFF11 FF111111 1FFFFF11 11111111 HEX 11FFF111 1FF1FF11 FF111FF1 FFFFFFF1 ; 41 = A HEX FF111FF1 FF111FF1 FF111FF1 11111111 HEX FF1FF111 FFF11FF1 FF111FF1 FFFFFF11 ; 42 = B HEX FF111FF1 FF111FF1 FFFFFF11 11111111 HEX 11FFFF11 1FF11FF1 FF111111 FF111111 ; 43 = C HEX FF111111 1FF11FF1 11FFFF11 11111111 HEX FF1FF111 FFF1FF11 FF111FF1 FF111FF1 ; 44 = D HEX FF111FF1 FF11FF11 FFFFF111 11111111 HEX FFFFFFF1 1FF111F1 1FF11111 1FFFF111 ; 45 = E HEX 1FF11111 1FF111F1 FFFFFFF1 11111111 HEX FFFFFFF1 1FF111F1 1FF11111 1FFFF111 ; 46 = F HEX 1FF11111 1FF11111 FFFF1111 11111111 HEX 11FFFF11 1FF11FF1 FF111111 FF11FFF1 ; 47 = G HEX FF111FF1 1FF1FFF1 11FFF1F1 11111111 HEX FF111FF1 FF111FF1 FF111FF1 FFFFFFF1 ; 48 = H HEX FF111FF1 FF111FF1 FF111FF1 11111111 HEX 1FFFF111 11FF1111 11FF1111 11FF1111 ; 49 = I HEX 11FF1111 11FF1111 1FFFF111 11111111 HEX 11FFFFF1 1111FF11 1111FF11 1111FF11 ; 4A = J HEX 1111FF11 FF11FF11 1FFFF111 11111111 HEX FF11FF11 FF11FF11 FF1FF111 FFFF1111 ; 4B = K HEX FF1FF111 FF11FFF1 FF111FF1 11111111 HEX FFFF1111 1FF11111 FF111111 FF111111 ; 4C = L HEX FF111FF1 FF111FF1 FFFFFF11 11111111 HEX FF111FF1 FFF1FFF1 FFFFFFF1 FF1F1FF1 ; 4D = M HEX FF111FF1 FF111FF1 FF111FF1 11111111 HEX FF111FF1 FFF11FF1 FFFF1FF1 FF1FFFF1 ; 4E = N HEX FF11FFF1 FF111FF1 FF111FF1 11111111 HEX 11FFF111 1FF1FF11 FF111FF1 FF111FF1 ; 4F = O HEX FF111FF1 1FF1FF11 11FFF111 11111111 HEX FF1FFF11 FFF11FF1 FF111FF1 FFFFFF11 ; 50 = P HEX FF111111 FF111111 FF111111 11111111 HEX 11FFF111 1FF1FF11 FF111FF1 FF1F1FF1 ; 51 = Q HEX FF11FFF1 1FF1FF11 11FFF1F1 11111111 HEX FF1FFF11 FFF11FF1 FF111FF1 FF1FF111 ; 52 = R HEX FF1FF111 FF11FFF1 FF111FF1 11111111 HEX 1FFFFF11 FF111FF1 FF111111 1FFFFF11 ; 53 = S HEX 11111FF1 FF111FF1 1FFFFF11 11111111 HEX FFFFFF11 F1FF1F11 11FF1111 11FF1111 ; 54 = T HEX 11FF1111 11FF1111 1FFFF111 11111111 HEX FFF11FF1 1FF11FF1 FF111FF1 FF111FF1 ; 55 = U HEX FF111FF1 FFF1FF11 1FFFF111 11111111 HEX FFF11FF1 1FF11FF1 FF111FF1 FF111FF1 ; 56 = V HEX FF11FF11 1FFFF111 11FF1111 11111111 HEX FFF11FF1 1FF11FF1 FF111FF1 FF1F1FF1 ; 57 = W HEX FFFFFFF1 FFF1FFF1 FF111FF1 11111111 HEX FF111FF1 FF111FF1 1FF1FF11 11FFF111 ; 58 = X HEX 1FF1FF11 FF111FF1 FF111FF1 11111111 HEX 1FF11FF1 FF111FF1 FF111FF1 1FF1FF11 ; 59 = Y HEX 11FFF111 FFFF1111 FFF11111 11111111 HEX FFFFFFF1 FF111FF1 1111FF11 11FFF111 ; 5A = Z HEX 1FF11FF1 FF111FF1 FFFFFF11 11111111 HEX 11FFFF11 11FF1111 11FF1111 11FF1111 ; 5B = [ HEX 11FF1111 11FF1111 11FFFF11 11111111 HEX 11111111 FF111111 1FF11111 11FF1111 ; 5C = \ HEX 111FF111 1111FF11 11111FF1 11111111 HEX 1FFFF111 111FF111 111FF111 111FF111 ; 5D = ] HEX 111FF111 111FF111 1FFFF111 11111111 HEX 111F1111 11FFF111 1FF1FF11 FF111FF1 ; 5E = ^ HEX 11111111 11111111 11111111 11111111 HEX 11111111 11111111 11111111 11111111 ; 5F = _ HEX 11111111 11111111 FFFFFFF1 11111111 HEX 11FF1111 11FF1111 111FF111 11111111 ; 60 = ` HEX 11111111 11111111 11111111 11111111 HEX 11111111 11111111 1FFFFFF1 FF111FF1 ; 61 = a HEX FF111FF1 FF11FFF1 1FFF1FF1 11111111 HEX FF111111 FF111111 FF1FFF11 FFF11FF1 ; 62 = b HEX FF111FF1 FF111FF1 1FFFFF11 11111111 HEX 11111111 11111111 1FFFFF11 FF111FF1 ; 63 = c HEX FF111111 FF111FF1 1FFFFF11 11111111 HEX 11111FF1 11111FF1 1FFF1FF1 FF11FFF1 ; 64 = d HEX FF111FF1 FF111FF1 1FFFFF11 11111111 HEX 11111111 11111111 1FFFFF11 FF111FF1 ; 65 = e HEX FFFFFFF1 FF111111 1FFFFF11 11111111 HEX 111FFF11 11FF1111 11FF1111 1FFFF111 ; 66 = f HEX 11FF1111 11FF1111 1FFFF111 11111111 HEX 11111111 11111111 1FFFFF11 FF111111 ; 67 = g HEX FF111FF1 FF111FF1 1FFFF1F1 11111111 HEX FF111111 FF111111 FF1FFF11 FFF11FF1 ; 68 = h HEX FF111FF1 FF11FF11 FF11FFF1 11111111 HEX 11111111 11111111 11FFFF11 111FF111 ; 69 = i HEX 111FF111 111FF111 11FFFF11 11111111 HEX 11111111 11111111 1FFFFFF1 1111FF11 ; 6A = j HEX 1111FF11 1111FF11 FF11FF11 1FFFF111 HEX FF111111 FF111111 FF11FF11 FF1FFF11 ; 6B = k HEX FFFFF111 FF11FFF1 FF111FF1 11111111 HEX 11FFF111 111FF111 111FF111 111FF111 ; 6C = l HEX 111FF111 111FF111 11FFFF11 11111111 HEX 11111111 11111111 FF1FFF11 FFFFFFF1 ; 6D = m HEX FF1F1FF1 FF111F11 FF11FFF1 11111111 HEX 11111111 11111111 FF1FFF11 FFF11FF1 ; 6E = n HEX FF111FF1 FF11FF11 FF11FFF1 11111111 HEX 11111111 11111111 1FFFFF11 FF111FF1 ; 6F = o HEX FF111FF1 FF111FF1 1FFFFF11 11111111 HEX 11111111 11111111 1FFFFF11 FF111FF1 ; 70 = p HEX FFF11FF1 FF1FFF11 FF111111 FF111111 HEX 11111111 11111111 1FFFFF11 FF111FF1 ; 71 = q HEX FF11FFF1 1FFF1FF1 11111FF1 11111FF1 HEX 11111111 11111111 FF1FFF11 FFF11FF1 ; 72 = r HEX FF111FF1 FFFFFF11 FF111FF1 11111111 HEX 11111111 11111111 1FFFFF11 FFF111F1 ; 73 = s HEX 11FFF111 F111FFF1 1FFFFF11 11111111 HEX 1111FF11 111FF111 1FFFFFF1 11FF1111 ; 74 = t HEX 11FF1111 11FF1FF1 111FFF11 11111111 HEX 11111111 11111111 FFF11FF1 1FF11FF1 ; 75 = u HEX FF111FF1 FF11FFF1 1FFF1FF1 11111111 HEX 11111111 11111111 FFF11FF1 1FF11FF1 ; 76 = v HEX FF111FF1 FF11FF11 1FFFF111 11111111 HEX 11111111 11111111 FF111FF1 FF1F1FF1 ; 77 = w HEX FFFFFFF1 FFF1FFF1 FF111FF1 11111111 HEX 11111111 11111111 FF111FF1 1FF1FF11 ; 78 = x HEX 11FFF111 1FF1FF11 FF111FF1 11111111 HEX 11111111 11111111 1FF11FF1 FF111FF1 ; 79 = y HEX FF111FF1 1FFFFFF1 11111FF1 1FFFFF11 HEX 11111111 11111111 FFFFFFF1 111FFF11 ; 7A = z HEX 11FFF111 1FFF1111 FFFFFFF1 11111111 if 0 ; enable custom SEGA characters HEX 17777711 77111771 77111111 17777711 ; 7B = S HEX 11111771 77111771 17777711 11111111 HEX 17777771 77111111 77111111 77777711 ; 7C = E HEX 77111111 77111111 17777771 11111111 HEX 17777711 77111771 77111111 77117771 ; 7D = G HEX 77111771 77111771 17777771 11111111 HEX 11177111 11777711 11777711 17711771 ; 7E = A HEX 17711771 77111177 77177777 11111111 else HEX 111FF111 11FF1111 11FF1111 1FF11111 ; 7B = { HEX 11FF1111 11FF1111 111FF111 11111111 HEX 11FF1111 11FF1111 11FF1111 11111111 ; 7C = | HEX 11FF1111 11FF1111 11FF1111 11111111 HEX 1FF11111 11FF1111 11FF1111 111FF111 ; 7D = } HEX 11FF1111 11FF1111 1FF11111 11111111 HEX 1FF11111 F1FF1F11 111FF111 11111111 ; 7E = ~ HEX 11111111 11111111 11111111 11111111 endif HEX F1F1F1F1 1F1F1F11 F1F1F1F1 1F1F1F11 ; 7F = DEL HEX F1F1F1F1 1F1F1F11 F1F1F1F1 11111111 FontSize = * - Font ;----------------------------------------------------------------------- ROMEND END