TMSS
The TMSS (Trade Mark Security Software) is the little rom inside the console who will verify if the game is licenced by SEGA.
At startup the console with execute the TMSS code and not the cart one.
The TMSS will check if the string at 0x100 is either 'SEGA' or ' SEGA'. If it is, it will display "PRODUCED BY OR UNDER LICENCE FROM SEGA ENTERPRISES LTD" on the screen for about 2 seconds then start the game. If not it will simply display a black screen.
The code use two register, $A14000 and $A14101. While the first has currently unknown purpose (but it is possible that writing to it unlock the VDP), the second control the bankswitching between the cart and the TMSS rom.
Setting the first bit to 1 enable the cart, and setting it to 0 enable the TMSS.
Here is the code disassembled and commented.
.long 0xFFFF00
.long START
.long INT
.long INT
.long INT
.long INT
.long INT
.long INT
.long INT
.long INT
.long INT
.long INT
.long INT
.long INT
.long INT
.long INT
.long INT
.long INT
.long INT
.long INT
.long INT
.long INT
.long INT
.long INT
.long INT
.long INT
.long INT
.long INT
.long INT
.long INT
.long INT
.long INT
.long INT
.long INT
.long INT
.long INT
.long INT
.long INT
.long INT
.long INT
.long INT
.long INT
.long INT
.long INT
.long INT
.long INT
.long INT
.long INT
.long INT
.long INT
.long INT
.long INT
.long INT
.long INT
.long INT
.long INT
.long INT
.long INT
.long INT
.long INT
.long INT
.long INT
.long INT
.long INT
.ascii "SEGA GENESIS "
.ascii "(C)SEGA 1990.MAY"
.ascii "GENESIS OS "
.ascii "GENESIS OS "
.ascii "OS 00000000-00"
.word 0x5B74
.ascii " "
.long 0
.long 0x7FF
.long 0xFF0000
.long 0xFFFFFF
.ascii " "
.ascii " "
.ascii "U "
INT:
bra.s INT
START: lea reg_data_1, a5
movem.l (a5)+, d5-a4
move.b -0x10FF(a1), d0 | Read version register (0xA10001)
andi.b #0xF, d0
beq.s _version_00
move.l #'SEGA', 0x2F00(a1) | Enable VDP
_version_00:
move.w (a4), d0 | Read VDP control port ???
moveq #0, d0
movea.l d0, a6
move a6, usp | Set stack to 0x0
moveq #0x17, d1
_setup_vdp_reg:
move.b (a5)+, d5
move.w d5, (a4)
add.w d7, d5
dbf d1, _setup_vdp_reg
move.l #0x40000080, (a4) | VRAM Fill command
move.w d0, (a3) | FIll VRAM with 0x00
_wait_for_dma:
move.w (a4), d4
btst #1, d4
bne.s _wait_for_dma
move.l #0x81048F02, (a4) | DMA disable, autoinc to 2
move.l #0xC0000000, (a4) | Write to CRAM command
moveq #0x1F, d3
_clr_cram:
move.l d0, (a3)
dbf d3, _clr_cram
move.l #0x40000010, (a4) | Write to VSRAM command
moveq #0x13, d4
_clr_vsram:
move.l d0, (a3)
dbf d4, _clr_vsram
moveq #3, d5
_write_to_psg:
move.b (a5)+, 0x11(a3)
dbf d5, _write_to_psg
bra.s loc_2AA
reg_data_1: .long 0x8000 | d5
.long 0x3FFF | d6
.long 0x100 | d7
.long 0xA00000 | a0
.long 0xA11100 | a1
.long 0xA11200 | a2
.long 0xC00000 | a3
.long 0xC00004 | a4
.byte 4 | VDP Reg #0, Disable INT, Disable HV counter
.byte 0x14 | VDP Reg #1, Enable DMA
.byte 0x30 | VDP Reg #2, Scroll A at 0xC000
.byte 0x3C | VDP Reg #3, Window at 0xF000
.byte 7 | VDP Reg #4, Scroll B at 0xE000
.byte 0x6C | VDP Reg #5, Sprites at 0xD800
.byte 0 | VDP Reg #6
.byte 0 | VDP Reg #7
.byte 0 | VDP Reg #8
.byte 0 | VDP Reg #9
.byte 0xFF | VDP Reg #10
.byte 0 | VDP Reg #11, Full scroll
.byte 0x81 | VDP Reg #12, 40 H-Cell mode
.byte 0x37 | VDP Reg #13, H-Scroll data at 0xDC00
.byte 0 | VDP Reg #14
.byte 1 | VDP Reg #15, Autoinc to 1
.byte 1 | VDP Reg #16, H Scroll 64 Cell
.byte 0 | VDP Reg #17, Window at 0
.byte 0 | VDP Reg #18, Window at 0
.byte 0xFF | VDP Reg #19
.byte 0xFF | VDP Reg #20, DMA Counter to 0xFFFF
.byte 0 | VDP Reg #21
.byte 0 | VDP Reg #22
.byte 0x80 | VDP Reg #23, DMA source addr at 0x800000
.byte 0x9F
.byte 0xBF
.byte 0xDF
.byte 0xFF
loc_2AA:
lea (0xFFFFC000).w, a0
lea reg_data_2, a1
movem.l (a1)+, d4-d7/a2-a6
move.w #0x3F, d0
_copy_code_to_ram:
move.w (a1)+, (a0)+
dbf d0, _copy_code_to_ram
jsr 0xFFFFC000
loc_2C4:
bra.s loc_2C4
reg_data_2: .long 0x20534547 | d4
.long 0x45940003 | d5
.long 0xF7 | d6
.long 0x53454741 | d7
.long 0xA14000 | a2
.long 0xA14101 | a3
.long 0xC00004 | a4
.long 0xC00000 | a5
.long 0xA10001 | a6
test_cart:
bset #0, (a3) | a3 = 0xA14101, Disable TMSS rom and enable cart
cmp.l (0x100).w, d7 | Compare ROM offset 0x100 with 'SEGA'
beq.s _cart_ok
cmp.l (0x100).w, d4 | Compare ROM offset 0x100 with ' SEG'
bne.s loc_302
cmpi.b #0x41, (0x104).w | 'A' | Look for the missing 'A'
beq.s _cart_ok
loc_302:
bclr #0, (a3) | Disable cart and enable TMSS rom
move.b (a6), d0
andi.b #0xF, d0
beq.s locret_314
move.l #0, (a2)
locret_314:
rts
_cart_ok:
bclr #0, (a3) | Disable cart and enable TMSS rom
jsr (write_palette).l
move.l #0x4C200000, (a4) | Write to VRAM at 0xC20
_write_map:
move.l (a1)+, (a5)
dbf d6, _write_map
jsr (write_licence).l
move.w #0x8144, (a4) | Enable display
move.w #0x3C, d0
bsr.s delay
move.w #0x8104, (a4) | Disable display
move.b (a6), d0 | Read version register
andi.b #0xF, d0
beq.s loc_34E
move.l #0, (a2) | Write 0x0 to 0x14000
loc_34E:
bset #0, (a3) | Disable TMSS rom and enable cart
moveq #0, d0
movea.l d0, a0
movea.l (a0)+, sp | Set stack pointer to (0x0).l
movea.l (a0)+, a0 | Set a0 to (0x4).l
jmp (a0) | Jump to cart START vector
delay:
move.w #0x95CE, d1
loc_360:
dbf d1, loc_360
dbf d0, delay
rts
.word 1 | PAL size
.word 0xEEE | PAL #0 color #1 = white
.word 0xEE8
.long 0x1111100
.long 0x11000110
.long 0x11000110
.long 0x11000110
.long 0x11111110
.long 0x11000110
.long 0x11000110
.long 0
.long 0x11111100
.long 0x11000110
.long 0x11000110
.long 0x11111100
.long 0x11000110
.long 0x11000110
.long 0x11111100
.long 0
.long 0x11111110
.long 0x11000110
.long 0x11000110
.long 0x11000000
.long 0x11000110
.long 0x11000110
.long 0x11111110
.long 0
.long 0x11111100
.long 0x11000110
.long 0x11000110
.long 0x11000110
.long 0x11000110
.long 0x11000110
.long 0x11111100
.long 0
.long 0x11111110
.long 0x11000000
.long 0x11000000
.long 0x11111100
.long 0x11000000
.long 0x11000000
.long 0x11111110
.long 0
.long 0x11111110
.long 0x11000000
.long 0x11000000
.long 0x11111100
.long 0x11000000
.long 0x11000000
.long 0x11000000
.long 0
.long 0x11111110
.long 0x11000110
.long 0x11000000
.long 0x11001110
.long 0x11000110
.long 0x11000110
.long 0x11111110
.long 0
.long 0x11000110
.long 0x11000110
.long 0x11000110
.long 0x11111110
.long 0x11000110
.long 0x11000110
.long 0x11000110
.long 0
.long 0x111000
.long 0x111000
.long 0x111000
.long 0x111000
.long 0x111000
.long 0x111000
.long 0x111000
.long 0
.long 0x110
.long 0x110
.long 0x110
.long 0x110
.long 0x110
.long 0x1100110
.long 0x1111110
.long 0
.long 0x11000110
.long 0x11001100
.long 0x11111000
.long 0x11111000
.long 0x11001100
.long 0x11000110
.long 0x11000110
.long 0
.long 0x1100000
.long 0x1100000
.long 0x1100000
.long 0x1100000
.long 0x1100000
.long 0x1100000
.long 0x1111110
.long 0
.long 0x11000110
.long 0x11101110
.long 0x11111110
.long 0x11010110
.long 0x11000110
.long 0x11000110
.long 0x11000110
.long 0
.long 0x11000110
.long 0x11100110
.long 0x11110110
.long 0x11011110
.long 0x11001110
.long 0x11000110
.long 0x11000110
.long 0
.long 0x11111110
.long 0x11000110
.long 0x11000110
.long 0x11000110
.long 0x11000110
.long 0x11000110
.long 0x11111110
.long 0
.long 0x11111110
.long 0x11000110
.long 0x11000110
.long 0x11111110
.long 0x11000000
.long 0x11000000
.long 0x11000000
.long 0
.long 0x11111110
.long 0x11000110
.long 0x11000110
.long 0x11000110
.long 0x11001110
.long 0x11001110
.long 0x11111110
.long 0
.long 0x11111110
.long 0x11000110
.long 0x11000110
.long 0x11111100
.long 0x11000110
.long 0x11000110
.long 0x11000110
.long 0
.long 0x11111110
.long 0x11000110
.long 0x11000000
.long 0x11111110
.long 0x110
.long 0x11000110
.long 0x11111110
.long 0
.long 0x11111110
.long 0x111000
.long 0x111000
.long 0x111000
.long 0x111000
.long 0x111000
.long 0x111000
.long 0
.long 0x11000110
.long 0x11000110
.long 0x11000110
.long 0x11000110
.long 0x11000110
.long 0x11000110
.long 0x11111110
.long 0
.long 0x11000110
.long 0x11000110
.long 0x11000110
.long 0x11000110
.long 0x1101100
.long 0x111000
.long 0x10000
.long 0
.long 0x11000110
.long 0x11000110
.long 0x11000110
.long 0x11010110
.long 0x11111110
.long 0x11101110
.long 0x11000110
.long 0
.long 0x11000110
.long 0x11000110
.long 0x11101110
.long 0x1111100
.long 0x11101110
.long 0x11000110
.long 0x11000110
.long 0
.long 0x11000110
.long 0x11000110
.long 0x11000110
.long 0x1101100
.long 0x111000
.long 0x111000
.long 0x111000
.long 0
.long 0x11111110
.long 0x1110
.long 0x11100
.long 0x111000
.long 0x1110000
.long 0x11100000
.long 0x11111110
.long 0
.long 0
.long 0
.long 0
.long 0
.long 0
.long 0x1100000
.long 0x1100000
.long 0
.long 0x2222200
.long 0x22000220
.long 0x22000000
.long 0x2222200
.long 0x220
.long 0x22000220
.long 0x2222200
.long 0
.long 0x2222220
.long 0x22000000
.long 0x22000000
.long 0x22222200
.long 0x22000000
.long 0x22000000
.long 0x2222220
.long 0
.long 0x2222200
.long 0x22000220
.long 0x22000000
.long 0x22002220
.long 0x22000220
.long 0x22000220
.long 0x2222220
.long 0
.long 0x22000
.long 0x222200
.long 0x222200
.long 0x2200220
.long 0x2200220
.long 0x22000022
.long 0x22022222
.long 0
line_1: .ascii " produced by or"
.byte 0xFF | End of first line
line_2: .ascii " under license from"
.byte 0xFF | End of second line
line_3: .ascii "sega,enterprises ltd{"
.byte 0 | End of data
write_palette:
move.w (a1)+, d0 | Get palette size
move.l #0xC0020000, (a4) | Write to CRAM at 0x2
_write_palette:
move.w (a1)+, (a5)
dbf d0, _write_palette
rts
| End of function write_palette
write_licence:
move.l d5, (a4) | Write to VRAM at 0xC594
loc_79E:
moveq #0, d1
move.b (a1)+, d1
bmi.s loc_7AC
bne.s loc_7A8
rts
loc_7A8:
move.w d1, (a5)
bra.s loc_79E
loc_7AC:
addi.l #0x1000000, d5
bra.s write_licence