; This demonstrational code describes how to create a game for the ATARI ; 7800 console, that would pass the encrypted signature check inside the ; NTSC version of the 7800 BIOS, so that it would get access to the advanced ; features of the MARIA graphics chip. Also it explains how a game has to be ; set up to work properly on the NTSC 7800 console and on the PAL 7800 ; console alike. ; ; When the 7800 is powered up with a 7800 game cartridge inserted, the ; 7800 BIOS first combines the contends of the ROM with the signature key ; at addresses $FF80-$FFF7 and compares the result with an internal ; checksum. Only if the result matches the checksum, the BIOS will allow ; the usage of the MARIA graphics chip. Otherwise it would switch the ; console into TIA compatibility mode, so that the 7800 would behave like ; a 2600. The signature key that would compute together with your game ROM ; to match the checksum could only be provided by ATARI itself. ; ; But since 7800 games were also allowed to have extra RAM in the lower ; part of the address space or could have certain areas of the ROM ; swapped with other parts of a larger ROM to allow the use of more code ; and data than the 6502 address space would let you access, ATARI made ; it possible to exclude parts of the ROM from the encrypted signature ; check in steps of 4KB through the high nibble of the byte at $FFF9. ; Programmers who didn't want to have to get a new signature key every ; time they fount an error in a game that already was signed, used this ; to create games where only the minimum of 4KB of the ROM was signed. ; ; This is what we can use for our purpose. You will have to extract the ; last 4KB of one of those games with only the minimum of ROM signed, ; save it into a file called PICKLOCK.BIN and include that at the end ; of your own game. Unfortunately this will mean that you will have 4KB ; of ROM space less to use. Another downside of this method is that the ; system vectors are located in those 4KB, so that you will have to live ; with whatever vectors were used in the original game. Also ATARI's ; signature check required that the startup vector points into the signed ; part of the ROM, so that only games can be used where the programmer had ; the foresight to make the first instruction in his game a jump out of the ; signed area. ; ; For this code example we will use the last 4KB from ATARI's development ; cartridge, which fullfills all our requirements. Since it technically ; still is a violation of copyright to copy those games even in parts, ; the nessessary PICKLOCK.BIN file will not be included with this source ; code. If you manage to get ahold of this binary (or a binary of any ; other suiteable game) and you create a game around it, you will do ; the distribution of this game AT YOUR OWN RESPONSABILITY alone. ; ; The system vectors for our demo are: ; ; INTERRUPT: $5083 ; STARTUP: $D106 ; BRK-instruction: $D0C4 ; ; To compile this source code you will need DASM 2.12.04. If you want to ; use an older version of DASM, that doesn't support the INCBIN instruction, ; you will have to compile this demo to be only 44KB in size and add ; PICKLOCK.BIN later by hand. ; ; If everything works out as it should, the resulting binary will scroll ; the message "encryption check passed" over the bottom of the screen. ; Also it will scroll NTSC or PAL over the top of the screen depending ; on what type of 7800 console you execute it on. The NTSC/PAL issue ; will be discussed further down in this document. ; ; So now: on with the actual code! include MARIA.H SEG keytest-code ORG $4000 ; font data ; ; graphics data for 128 characters - line 8 dc.b $00,$7E,$7E,$00,$00,$7C,$7C,$00 dc.b $FF,$00,$FF,$78,$18,$E0,$C0,$99 dc.b $00,$00,$18,$00,$00,$78,$00,$FF dc.b $00,$00,$00,$00,$00,$00,$00,$00 dc.b $00,$00,$00,$00,$00,$00,$00,$00 dc.b $00,$00,$00,$00,$60,$00,$00,$00 dc.b $00,$00,$00,$00,$00,$00,$00,$00 dc.b $00,$00,$00,$60,$00,$00,$00,$00 dc.b $00,$00,$00,$00,$00,$00,$00,$00 dc.b $00,$00,$00,$00,$00,$00,$00,$00 dc.b $00,$00,$00,$00,$00,$00,$00,$00 dc.b $00,$00,$00,$00,$00,$00,$00,$FF dc.b $00,$00,$00,$00,$00,$00,$00,$F8 dc.b $00,$00,$78,$00,$00,$00,$00,$00 dc.b $F0,$1E,$00,$00,$00,$00,$00,$00 dc.b $00,$F8,$00,$00,$00,$00,$00,$00 ALIGN 256 ; graphics data for 128 characters - line 7 dc.b $00,$81,$FF,$10,$10,$38,$38,$00 dc.b $FF,$3C,$C3,$CC,$7E,$F0,$E6,$5A dc.b $80,$02,$3C,$66,$1B,$CC,$7E,$18 dc.b $18,$18,$00,$00,$00,$00,$00,$00 dc.b $00,$30,$00,$6C,$30,$C6,$76,$00 dc.b $18,$60,$00,$00,$30,$00,$30,$80 dc.b $7C,$FC,$FC,$78,$1E,$78,$78,$30 dc.b $78,$70,$30,$30,$18,$00,$60,$30 dc.b $78,$CC,$FC,$3C,$F8,$FE,$F0,$3E dc.b $CC,$78,$78,$E6,$FE,$C6,$C6,$38 dc.b $F0,$1C,$E6,$78,$78,$FC,$30,$C6 dc.b $C6,$78,$FE,$78,$02,$78,$00,$00 dc.b $00,$76,$DC,$78,$76,$78,$F0,$0C dc.b $E6,$78,$CC,$E6,$78,$C6,$CC,$78 dc.b $60,$0C,$F0,$F8,$18,$76,$30,$6C dc.b $C6,$0C,$FC,$1C,$18,$E0,$00,$FE ALIGN 256 ; graphics data for 128 characters - line 6 dc.b $00,$99,$E7,$38,$38,$7C,$7C,$18 dc.b $E7,$66,$99,$CC,$18,$70,$67,$3C dc.b $E0,$0E,$7E,$00,$1B,$38,$7E,$3C dc.b $18,$3C,$18,$30,$FE,$24,$FF,$18 dc.b $00,$00,$00,$6C,$F8,$66,$CC,$00 dc.b $30,$30,$66,$30,$30,$00,$30,$C0 dc.b $E6,$30,$CC,$CC,$0C,$CC,$CC,$30 dc.b $CC,$18,$30,$30,$30,$FC,$30,$00 dc.b $C0,$CC,$66,$66,$6C,$62,$60,$66 dc.b $CC,$30,$CC,$66,$66,$C6,$C6,$6C dc.b $60,$78,$66,$CC,$30,$CC,$78,$EE dc.b $6C,$30,$66,$60,$06,$18,$00,$00 dc.b $00,$CC,$66,$CC,$CC,$C0,$60,$7C dc.b $66,$30,$CC,$6C,$30,$D6,$CC,$CC dc.b $7C,$7C,$60,$0C,$34,$CC,$78,$FE dc.b $6C,$7C,$64,$30,$18,$30,$00,$C6 ALIGN 256 ; graphics data for 128 characters - line 5 dc.b $00,$BD,$C3,$7C,$7C,$FE,$FE,$3C dc.b $C3,$42,$BD,$CC,$3C,$30,$63,$E7 dc.b $F8,$3E,$18,$66,$1B,$6C,$7E,$7E dc.b $18,$7E,$0C,$60,$C0,$66,$FF,$3C dc.b $00,$30,$00,$FE,$0C,$30,$DC,$00 dc.b $60,$18,$3C,$30,$00,$00,$00,$60 dc.b $F6,$30,$60,$0C,$FE,$0C,$CC,$30 dc.b $CC,$0C,$00,$00,$60,$00,$18,$30 dc.b $DE,$FC,$66,$C0,$66,$68,$68,$CE dc.b $CC,$30,$CC,$6C,$62,$D6,$CE,$C6 dc.b $60,$DC,$6C,$1C,$30,$CC,$CC,$FE dc.b $38,$30,$32,$60,$0C,$18,$00,$00 dc.b $00,$7C,$66,$C0,$CC,$FC,$60,$CC dc.b $66,$30,$0C,$78,$30,$FE,$CC,$CC dc.b $66,$CC,$66,$78,$30,$CC,$CC,$FE dc.b $38,$CC,$30,$30,$18,$30,$00,$C6 ALIGN 256 ; graphics data for 128 characters - line 4 dc.b $ff,$81,$FF,$FE,$FE,$FE,$7C,$3C dc.b $C3,$42,$BD,$7D,$66,$30,$63,$E7 dc.b $FE,$FE,$18,$66,$7B,$6C,$00,$18 dc.b $18,$18,$FE,$FE,$C0,$FF,$7E,$7E dc.b $00,$30,$00,$6C,$78,$18,$76,$00 dc.b $60,$18,$FF,$FC,$00,$FC,$00,$30 dc.b $DE,$30,$38,$38,$CC,$0C,$F8,$18 dc.b $78,$7C,$00,$00,$C0,$00,$0C,$18 dc.b $DE,$CC,$7C,$C0,$66,$78,$78,$C0 dc.b $FC,$30,$0C,$78,$60,$FE,$DE,$C6 dc.b $7C,$CC,$7C,$70,$30,$CC,$CC,$D6 dc.b $38,$78,$18,$60,$18,$18,$C6,$00 dc.b $00,$0C,$7C,$CC,$7C,$CC,$F0,$CC dc.b $76,$30,$0C,$6C,$30,$FE,$CC,$CC dc.b $66,$CC,$76,$C0,$30,$CC,$CC,$D6 dc.b $5C,$CC,$98,$E0,$00,$1C,$00,$6C ALIGN 256 ; graphics data for 128 characters - line 3 dc.b $ff,$A5,$DB,$FE,$7C,$38,$38,$18 dc.b $E7,$66,$99,$0F,$66,$3F,$7F,$3C dc.b $F8,$3E,$7E,$66,$DB,$38,$00,$7E dc.b $7E,$18,$0C,$60,$C0,$66,$3C,$FF dc.b $00,$78,$6C,$FE,$C0,$CC,$38,$C0 dc.b $60,$18,$3C,$30,$00,$00,$00,$18 dc.b $CE,$30,$0C,$0C,$6C,$F8,$C0,$0C dc.b $CC,$CC,$30,$30,$60,$FC,$18,$0C dc.b $DE,$CC,$66,$C0,$66,$68,$68,$C0 dc.b $CC,$30,$0C,$6C,$60,$FE,$F6,$C6 dc.b $66,$CC,$66,$E0,$30,$CC,$CC,$C6 dc.b $6C,$CC,$8C,$60,$30,$18,$6C,$00 dc.b $18,$78,$60,$78,$0C,$78,$60,$76 dc.b $6C,$70,$0C,$66,$30,$CC,$F8,$78 dc.b $DC,$76,$DC,$7C,$7C,$CC,$CC,$C6 dc.b $C6,$CC,$FC,$30,$18,$30,$00,$38 ALIGN 256 ; graphics data for 128 characters - line 2 dc.b $00,$81,$FF,$FE,$38,$7C,$10,$00 dc.b $FF,$3C,$C3,$07,$66,$33,$63,$5A dc.b $E0,$0E,$3C,$66,$DB,$63,$00,$3C dc.b $3C,$18,$18,$30,$00,$24,$18,$FF dc.b $00,$78,$6C,$6C,$7C,$C6,$6C,$60 dc.b $30,$30,$66,$30,$00,$00,$00,$0C dc.b $C6,$70,$CC,$CC,$3C,$C0,$60,$CC dc.b $CC,$CC,$30,$30,$30,$00,$30,$CC dc.b $C6,$78,$66,$66,$6C,$62,$62,$66 dc.b $CC,$30,$0C,$66,$60,$EE,$E6,$6C dc.b $66,$CC,$66,$CC,$B4,$CC,$CC,$C6 dc.b $C6,$CC,$C6,$60,$60,$18,$38,$00 dc.b $30,$00,$60,$00,$0C,$00,$6C,$00 dc.b $60,$00,$00,$60,$30,$00,$00,$00 dc.b $00,$00,$00,$00,$30,$00,$00,$00 dc.b $00,$00,$00,$30,$18,$30,$DC,$10 ALIGN 256 ; graphics data for 128 characters - line 1 dc.b $00,$7E,$7E,$6C,$10,$38,$10,$00 dc.b $FF,$00,$FF,$0F,$3C,$3F,$7F,$99 dc.b $80,$02,$18,$66,$7F,$3E,$00,$18 dc.b $18,$18,$00,$00,$00,$00,$00,$00 dc.b $00,$30,$6C,$6C,$30,$00,$38,$60 dc.b $18,$60,$00,$00,$00,$00,$00,$06 dc.b $7C,$30,$78,$78,$1C,$FC,$38,$FC dc.b $78,$78,$00,$00,$18,$00,$60,$78 dc.b $7C,$30,$FC,$3C,$F8,$FE,$FE,$3C dc.b $CC,$78,$1E,$E6,$F0,$C6,$C6,$38 dc.b $FC,$78,$FC,$78,$FC,$CC,$CC,$C6 dc.b $C6,$CC,$FE,$78,$C0,$78,$10,$00 dc.b $30,$00,$E0,$00,$1C,$00,$38,$00 dc.b $E0,$30,$0C,$E0,$70,$00,$00,$00 dc.b $00,$00,$00,$00,$10,$00,$00,$00 dc.b $00,$00,$00,$1C,$18,$E0,$76,$00 ; This routine waits for the vertical blanking period to start ORG $5000 WaitVBLANK: WaitVBoff: bit MSTAT bmi WaitVBoff WaitVBon: bit MSTAT bpl WaitVBon rts ; At this address the execution will continue after an interrupt has ; occured. Here we change the horizontal position for the two lines of ; text to shift them continuously over the screen. In this example code ; the interrupt occurs in the scanline before the PAL/NTSC text starts ; displaying in every frame. ORG $5083 INTERRUPT: dec $182c ;change horiz. pos. of PAL/NTSC text dec $1834 ;change horiz. pos. of "encrypted..." rti ; At this address the execution will continue after a BRK instruction. ORG $d0c4 BRKroutine: rti ; At this address the execution starts right after the encrypted signature ; check was passed successfully. ORG $d106 START: sei ;disable interrupts cld lda #$07 ;lock the 7800 into MARIA mode sta INPTCTRL ; lda #$7f ;turn off DMA, since no output has sta CTRL ; been set up yet ldx #$ff ;set stack pointer to $01ff txs ; lda #$0f sta P0C2 ;white text lda #$00 sta BACKGRND ;on black background sta INPTCTRL ;not really nessessary but the sta OFFSET ; manual suggests it anyway lda #$40 ;the font data is located at $4000 sta CHBASE ; ; This loop copies the text data, DLL and DLs to the RAM at $1800 ldx #$00 CopyLoop: lda $e000,x sta $1800,x inx bne CopyLoop ; Differences between the NTSC and PAL 7800 consoles' output: ; NTSC PAL ; 15 15 automatic VBLANK lines ; 25 33 output lines, that can't be seen on many TVs ; 192 228 actual display lines ; 26 32 output lines, that can't be seen on many TVs ; 4 4 automatic VBLANK lines ; ; 262 312 total number of lines per frame ; 243 293 total number of DMA output lines per frame ; 60 50 frames per second ; ; So to make a NTSC game run properly on a PAL console, you can simply ; set up 25 extra blank lines before and after the normal NTSC display. ; Also you would have to adjust anything that is timed by counting the ; number of frames, since PAL consoles do less frames per second than ; NTSC consoles. The following routine detects if it is running on a ; NTSC or a PAL console by counting the number of scanlines per frame, ; so that you can make your game compatible with both TV standards. ; jsr WaitVBLANK ; WaitVBover: bit MSTAT ; bmi WaitVBover ;wait for the VBLANK to end lda #$4c ;prepare NTSC setup here ldx #$00 CountLines: bit MSTAT ;if not back in VBLANK bmi CompareCounter ; sta WSYNC ; then wait 2 scanlines, sta WSYNC ; dex ; decrease the counter bne CountLines ; and keep counting CompareCounter: cpx #$78 ;if less than 274 lines have passed bcs noPALsetup ; we are on NTSC lda #"P" ;prepare PAL setup here sta $1801 ; in this example we change the lda #"A" ; output text from "NTSC" to "PAL " sta $1802 ; and setup the display for a lda #"L" ; higher number of scanlines sta $1803 ; lda #" " ; sta $1804 ; lda #$40 ; noPALsetup sta DPPL ;setup the pointers for the output lda #$18 ; description (DLL) according to sta DPPH ; the PAL/NTSC test to $1840/$184C jsr WaitVBLANK ;wait until no DMA would happen lda #$43 ; then enable normal color output, sta CTRL ; turn on DMA, set one byte wide ; characters, make the border have ; the background color, enable ; transparent output, set screen ; mode to 320A or 320C MainLoop: jmp MainLoop ; here you could do game calculations ; This contains the text data, several DLs and the DLL. ; It gets copied to the RAM at $1800 for DMA timing reasons. ORG $e000 .byte " " ;$1800 - text data .byte "NTSC" .byte "encryption check passed" ALIGN 16 ;$1820 .byte $00,$60,$18,$1f,$00 ;DL for the blank lines .byte $00,$00 Align 8 ;$1828 .byte $01,$60,$18,$1c,160 ;DL for the NTSL/PAL text .byte $00,$00 Align 8 ;$1830 .byte $05,$60,$18,$09,160 ;DL for "encryption ..." .byte $00,$00 ; The DLL starts here - $1840 Align 16 .byte $00,$18,$20 ;do these 25 extra blank lines .byte $07,$18,$20 ; to center the NTSC display on .byte $07,$18,$20 ; PAL consoles/TVs .byte $07,$18,$20 ; .byte $00,$18,$20 ;25 blank lines that can't be seen .byte $07,$18,$20 ; on most NTSC TVs anyway .byte $07,$18,$20 ; .byte $87,$18,$20 ;if the highest bit of the first byte ; in a DLL entry is set, an interrupt ; will occur after the DMA for the ; last line in this block of scanlines ; has ended .byte $07,$18,$28 ;192 scanlines of actual display .byte $07,$18,$20 ; (here in steps of 8 lines which .byte $07,$18,$20 ; is the height of the characters) .byte $07,$18,$20 ; .byte $07,$18,$20 ; .byte $07,$18,$20 ; .byte $07,$18,$20 ; .byte $07,$18,$20 ; .byte $07,$18,$20 ; .byte $07,$18,$20 ; .byte $07,$18,$20 ; .byte $07,$18,$20 ; .byte $07,$18,$20 ; .byte $07,$18,$20 ; .byte $07,$18,$20 ; .byte $07,$18,$20 ; .byte $07,$18,$20 ; .byte $07,$18,$20 ; .byte $07,$18,$20 ; .byte $07,$18,$20 ; .byte $07,$18,$20 ; .byte $07,$18,$20 ; .byte $07,$18,$20 ; .byte $07,$18,$30 ; .byte $07,$18,$20 ;the DMA keeps doing another 26 lines .byte $07,$18,$20 ; which can't be seen on most NTSC .byte $07,$18,$20 ; TVs, so they are set to be blank .byte $01,$18,$20 ; .byte $07,$18,$20 ;on PAL consoles the DMA does .byte $07,$18,$20 ; another 25 blank lines to reach .byte $07,$18,$20 ; the final number of 293 scanlines .byte $00,$18,$20 ; per frame ; This includes the 4kb binary with a matching pair of gamecode/gamedata ; and it's corresponding encrypted signature key. It also sets the ; system vectors which you are forced to use in your game. ; In this example (binary from ATARI's development cartridge) they are: ; INTERRUPT: $5083 ; STARTUP: $D106 ; BRK-instruction: $D0C4 ORG $f000 incbin PICKLOCK.BIN ; Other binaries that might be usable: ; ; Basketbrawl ; INTERRUPT: JMP (00F0) ; STARTUP: $4D64 ; BRK-instruction: RTI ; include size: 4KB ; ; Double Dragon ; INTERRUPT: $4000 ; STARTUP: $448D ; BRK-instruction: $4000 ; include size: 4KB ; ; F18 Hornet ; INTERRUPT: $E2E0 ; STARTUP: LDA #$01/STA $8000/JMP $D800 ; BRK-instruction: RTI ; include size: 4KB ; ; Food Fight ; INTERRUPT: $B3C8 ; STARTUP: $B000 ; BRK-instruction: RTI ; include size: 8KB ; ; Galaga ; INTERRUPT: $B15D ; STARTUP: $B000 ; BRK-instruction: $B610 ; include size: 8KB ; ; Joust ; INTERRUPT: $9E35 ; STARTUP: $B000 ; BRK-instruction: $9F15 ; include size: 8KB ; ; Kung Fu Master ; INTERRUPT: $A376 ; STARTUP: CLI/CLD/LDX #$FF/TXS/LDA #$97/STA $01/JSR $8000 ; BRK-instruction: $A5D4 ; include size: 4KB ; ; Pete Rose Baseball ; INTERRUPT: $DA3B ; STARTUP: $DB10 ; BRK-instruction: $A5D4 ; include size: 4KB ; ; Tomcat F14 ; INTERRUPT: $EB1C ; STARTUP: $EB49 ; BRK-instruction: $D4A5 ; include size: 4KB ; ; Title Match Pro Wrestling ; INTERRUPT: $8CA5 ; STARTUP: $9B26 ; BRK-instruction: $A5D4 ; include size: 4KB