The DTV V2 (PAL) ROM disected ----------------------------- Version 0.3 2006-05-28 Written by Daniel Kahlin $Id: dtv2_kernal.txt,v 1.8 2006-05-28 08:27:58 tlr Exp $ History ------- Version 0.3 2006-05-28 - Added a description about a load routine bug. Version 0.2 2006-02-26 - Corrected the Sat bits in the User Port Conf. - Added a description of the directory entries. - Added a description of the file format. Version 0.1 2005-12-30 - Initial version. ROM Version: This information is valid for a DTV V2, batch "051005", flash image "2005 06 07 03:21:11" (stated at the bottom of the directory listing). The User Port Configuration bits: --------------------------------- PAL NTSC USR[0] 1 0 Pal-Ntsc USR[1] 1 0 PhaseAlt USR[2] 0 0 Sat0 USR[3] 1 1 Sat1 USR[4] 0 0 BurstLock USR[5] 0 0 Lockmode USR[6] 0 0 Tune USR[7] 1 0 PalBurst ATNin 0 0 ($01 bit 4) (XTal Select) Explanation of what the config code does: $D040 bits 1-0 = USR[1-0] (Burst phase alternate, PAL line timing) $D040 bits 7-2 = 0000000 (V1 Palette compatibility off) $D04F bits 3-0 = USR [5-2] (Burst lock with neg phase "walk", Burst lock, SAT1, SAT0) $D04E = 0 if ATNin=0 $D04E = 7 if USR[6]=0 and ATNin=1 $D04E = 6 if USR[6]=1 and ATNin=1 $D041=$1C, $D042=00, $D043=00 if USR[7]=0 and ATNin=0. $D041=$24, $D042=00, $D043=00 if USR[7]=1 and ATNin=0. $D041=$1C, $D042=13, $D043=2A if USR[7]=0 and ATNin=1. $D041=$24, $D042=31, $D043=5B if USR[7]=1 and ATNin=1. ($D04E is the Scan line timing adjust. $D041,$D042,$D042 sets the Burst rate modulus) Detailed listing of ROM differences: ------------------------------------ The DTV V2 ROM seems to be a patch upon the C64 Kernal version 3 (901227-03). ---------------------------------------------------------------------------- ;Kernal CINT (Initialize Screen and Keyboard) E518 20 36 F7 JSR $F736 ;was: JSR $E5A0 ---------------------------------------------------------------------------- E59A 20 36 F7 JSR $F736 ;was: JSR $E5A0 ---------------------------------------------------------------------------- F72C 60 RTS ;was: Get Next Tape File Header from Cassette F72D 4C F1 F8 JMP $F8F1 ;Jump #0: Reset Entry F730 4C 3C F7 JMP $F73C ;Jump #1: Load F733 4C FD F9 JMP $F9FD ;Jump #2: Save F736 4C 1D FA JMP $FA1D ;Jump #3: Reset Video Mode F739 4C 40 FA JMP $FA40 ;Jump #4: Reset Palette ---------------------------------------------------------------------------- ; Jump #1: Load F73C 85 93 STA $93 ;Set verify flag F73E A5 BA LDA $BA ;Get device number F740 C9 01 CMP #$01 ;=1 F742 F0 03 BEQ $F747 ;yes, load from flash. F744 4C A7 F4 JMP $F4A7 ;no, go to normal load. F747 08 PHP F748 78 SEI F749 A9 00 LDA #$00 F74B 85 93 STA $93 ;Clear Verify flag F74D A2 01 LDX #$01 F74F 8E 3F D0 STX $D03F ;Enable extended registers. F752 8D 07 D3 STA $D307 ;DMA source and destination step=1 F755 8D 09 D3 STA $D309 F758 8E 06 D3 STX $D306 F75B 8E 08 D3 STX $D308 ;--- F75E 20 4D F8 JSR $F84D ;Swap $f7-$012f to $0110f7 F761 A2 00 LDX #$00 ;Set Source Ptr = $010000 F763 86 F8 STX $F8 ;and Destination Ptr = $000100 F765 86 F9 STX $F9 F767 86 FD STX $FD F769 E8 INX F76A 86 FA STX $FA F76C A9 00 LDA #$00 F76E 85 FB STA $FB F770 A9 01 LDA #$01 F772 85 FC STA $FC ;--- F774 20 AF F5 JSR $F5AF ;Print "SEARCHING FOR " F777 20 B3 F8 JSR $F8B3 ;Set DMA Source from $F8-$FA F77A 20 C3 F8 JSR $F8C3 ;Set DMA Destination from $FB-$FD F77D A9 20 LDA #$20 ;One dir entry ($20 bytes) F77F 20 79 F8 JSR $F879 ;DMA Bytes (Acc=num bytes) F782 AD 00 01 LDA $0100 ;First byte of entry=00? F785 D0 07 BNE $F78E ;no, check filename. F787 20 4D F8 JSR $F84D ;Swap $f7-$012f to $0110f7 F78A 28 PLP F78B 4C 04 F7 JMP $F704 ;Exit with File Not Found F78E A5 B7 LDA $B7 F790 D0 07 BNE $F799 F792 20 4D F8 JSR $F84D ;Swap $f7-$012f to $0110f7 F795 28 PLP F796 4C 10 F7 JMP $F710 ;Exit with Missing Filename F799 C9 18 CMP #$18 ;Filename longer than 24 chars F79B 90 02 BCC $F79F ;No, continue F79D B0 E8 BCS $F787 ;Yes, File Not Found F79F A0 00 LDY #$00 ;Match filename F7A1 B1 BB LDA ($BB),Y F7A3 C9 2A CMP #$2A F7A5 F0 0F BEQ $F7B6 F7A7 D9 00 01 CMP $0100,Y F7AA D0 35 BNE $F7E1 ;mismatch, get next entry F7AC C8 INY F7AD C4 B7 CPY $B7 F7AF D0 F0 BNE $F7A1 F7B1 B9 00 01 LDA $0100,Y F7B4 D0 2B BNE $F7E1 ;--- differing lengths, get next entry F7B6 20 D2 F5 JSR $F5D2 ;Print "LOADING" F7B9 A2 05 LDX #$05 ;set source and dest from directory F7BB BD 18 01 LDA $0118,X ;entry F7BE 95 F8 STA $F8,X F7C0 CA DEX F7C1 10 F8 BPL $F7BB ;--- F7C3 A5 B9 LDA $B9 ;Secondary Address F7C5 D0 08 BNE $F7CF ;not 0, start loading F7C7 A5 C3 LDA $C3 ;set user specified load address F7C9 85 FB STA $FB F7CB A5 C4 LDA $C4 F7CD 85 FC STA $FC ;--- F7D0 ; Instruction parameter jumped to (was: Put Ptr to Tape Buffer in X/Y) F7CF 20 E9 F7 JSR $F7E9 ;Load File Body F7D2 20 4D F8 JSR $F84D ;Swap $f7-$012f to $0110f7 F7D5 A9 00 LDA #$00 F7D7 8D 3F D0 STA $D03F ;Disable extended registers F7DA 28 PLP F7DB A9 00 LDA #$00 ;Status ok. F7DD 85 90 STA $90 F7DF 18 CLC F7E0 60 RTS F7E1 A9 20 LDA #$20 F7E3 20 D5 F8 JSR $F8D5 ;Update Source Ptr F7E6 4C 77 F7 JMP $F777 F7EA ; Instruction parameter jumped to (was: Search Tape for a filename) ;Load File Body F7E9 A9 FE LDA #$FE ;Dest=$00FE F7EB 20 A5 F8 JSR $F8A5 ;Set DMA Destination from Acc F7EE 20 B3 F8 JSR $F8B3 ;Set DMA Source from $F8-$FA F7F1 20 88 F8 JSR $F888 ;Get byte + 1 byte look ahead F7F4 A5 FE LDA $FE ;Control byte F7F6 F0 4C BEQ $F844 ;=$00, finished...go exit. F7F8 30 12 BMI $F80C ;=Neg, go special F7FA AA TAX ;Positive, do copy F7FB 20 C3 F8 JSR $F8C3 ;Set DMA Destination from $FB-$FD F7FE 20 B3 F8 JSR $F8B3 ;Set DMA Source from $F8-$FA F801 8A TXA ;length F802 20 93 F8 JSR $F893 ;Do DMA (Acc=num bytes) F805 8A TXA ;length F806 20 E3 F8 JSR $F8E3 ;Update Destination Ptr F809 4C E9 F7 JMP $F7E9 ;Loop and do next. F80C 49 80 EOR #$80 ;Clear MSB. F80E 85 F7 STA $F7 ;Preserve length F810 A9 01 LDA #$01 ;Acc=1 F812 20 D5 F8 JSR $F8D5 ;Update Source Ptr F815 A6 FD LDX $FD ;X=Dest(High) F817 A4 FC LDY $FC ;Y=Dest(Middle) F819 D0 01 BNE $F81C ;TmpDest-$0100 F81B CA DEX F81C 88 DEY ;--- F81D A5 FB LDA $FB ;TmpDest+second-byte. F81F 18 CLC F820 65 FF ADC $FF F822 90 04 BCC $F828 F824 C8 INY F825 D0 01 BNE $F828 F827 E8 INX ;--- F828 8D 00 D3 STA $D300 ;Set DMA Source=TmpDest F82B 8C 01 D3 STY $D301 F82E 8A TXA F82F 09 40 ORA #$40 ;RAM F831 8D 02 D3 STA $D302 ;--- F834 20 C3 F8 JSR $F8C3 ;Set DMA Destination from $FB-$FD F837 A5 F7 LDA $F7 ;length F839 20 79 F8 JSR $F879 ;DMA Bytes (Acc=num bytes) F83C A5 F7 LDA $F7 ;length F83E 20 E3 F8 JSR $F8E3 ;Update Destination Ptr F841 4C E9 F7 JMP $F7E9 ;Loop and do next. F844 A6 FB LDX $FB ;Update load end addr, and exit F846 86 AE STX $AE F848 A4 FC LDY $FC F84A 84 AF STY $AF ;--- F84C 60 RTS ;Swap $f7-$012f to $0110f7 (always leaves with Y=$41) F84D A9 00 LDA #$00 F84F A0 40 LDY #$40 F851 8C 05 D3 STY $D305 ;Destination (High)=$00, RAM F854 C8 INY F855 8C 02 D3 STY $D302 ;Source (High)=$01, RAM F858 8D 0B D3 STA $D30B ;DMA Length (High)=0 F85B 8D 04 D3 STA $D304 ;Destination (Middle)=$00 F85E A9 10 LDA #$10 F860 8D 01 D3 STA $D301 ;Source (Middle)=$10 F863 A9 F7 LDA #$F7 F865 8D 00 D3 STA $D300 ;Source (Low)=$F7 F868 8D 03 D3 STA $D303 ;Destination (Low)=$F7 F86B A9 39 LDA #$39 F86D 8D 0A D3 STA $D30A ;DMA Length (Low)=$39 F870 A9 0F LDA #$0F ;Source Dir=pos, Dest Dir=pos, F872 8D 1F D3 STA $D31F ;Swap source with dest=1, Force Start=1 F875 4C 81 F8 JMP $F881 ;Check for DMA finished F878 60 RTS ;DMA Bytes (Acc=num bytes) F879 20 9C F8 JSR $F89C ;Set DMA Length F87C A9 0D LDA #$0D ;Source Dir=pos, Dest Dir=pos F87E 8D 1F D3 STA $D31F ;Force Start=1 F881 AD 1F D3 LDA $D31F ;Check for DMA finished F884 4A LSR A F885 B0 FA BCS $F881 F887 60 RTS ;Get byte + 1 byte look ahead F888 A9 02 LDA #$02 F88A 20 79 F8 JSR $F879 F88D A9 01 LDA #$01 F88F 20 D5 F8 JSR $F8D5 ;Update Source Ptr F892 60 RTS ;Do DMA (Acc=num bytes) F893 48 PHA F894 20 79 F8 JSR $F879 F897 68 PLA F898 20 D5 F8 JSR $F8D5 ;Update Source Ptr F89B 60 RTS ;Set DMA Length (Acc=length) F89C 8D 0A D3 STA $D30A F89F A9 00 LDA #$00 F8A1 8D 0B D3 STA $D30B F8A4 60 RTS ; Set DMA Destination from Acc F8A5 8D 03 D3 STA $D303 ;Destination (Low) F8A8 A9 00 LDA #$00 F8AA 8D 04 D3 STA $D304 ;Destination (Middle) = $00 F8AD A9 40 LDA #$40 F8AF 8D 05 D3 STA $D305 ;Destination (High) = $40 (RAM) F8B2 60 RTS ;Set DMA Source from $F8-$FA F8B3 A5 F8 LDA $F8 F8B5 8D 00 D3 STA $D300 ;Source (Low) F8B8 A5 F9 LDA $F9 F8BA 8D 01 D3 STA $D301 ;Source (Middle) F8BD A5 FA LDA $FA F8BF 8D 02 D3 STA $D302 ;Source (High) F8C2 60 RTS ; Set DMA Destination from $FB-$FD F8C3 A5 FB LDA $FB F8C5 8D 03 D3 STA $D303 ;Destination (Low) F8C8 A5 FC LDA $FC F8CA 8D 04 D3 STA $D304 ;Destination (Middle) F8CD A5 FD LDA $FD F8CF 09 40 ORA #$40 ;RAM F8D1 8D 05 D3 STA $D305 ;Destination (High) F8D4 60 RTS ;Update Source Ptr F8D5 18 CLC F8D6 65 F8 ADC $F8 F8D8 85 F8 STA $F8 F8DA 90 06 BCC $F8E2 F8DC E6 F9 INC $F9 F8DE D0 02 BNE $F8E2 F8E0 E6 FA INC $FA F8E2 60 RTS ;Update Destination Ptr F8E3 18 CLC F8E4 65 FB ADC $FB F8E6 85 FB STA $FB F8E8 90 06 BCC $F8F0 F8EA E6 FC INC $FC F8EC D0 02 BNE $F8F0 F8EE E6 FD INC $FD F8F0 60 RTS ---------------------------------------------------------------------------- ; Jump #0: Reset Entry F8F1 A2 FF LDX #$FF ;Reset Hook (from Jump #0) F8F3 78 SEI ;Kill interrupts F8F4 9A TXS ;Reset SP F8F5 D8 CLD ;Clear decimal mode F8F6 A9 FF LDA #$FF ;Set all joy-port pins high F8F8 8D 00 DC STA $DC00 ;to enable reading them. F8FB AD 00 DC LDA $DC00 F8FE 29 10 AND #$10 ;Check Left Button F900 D0 1C BNE $F91E ;No, skip resident check F902 32 EE SAC #$EE F904 A9 06 LDA #$06 ;Map $018000 at $8000 F906 32 00 SAC #$00 F908 A2 04 LDX #$04 ;Check for DTV80 at $018004 F90A BD 18 FA LDA $FA18,X F90D DD 04 80 CMP $8004,X F910 D0 06 BNE $F918 ;No, restore mapping and skip F912 CA DEX F913 10 F5 BPL $F90A F915 6C 00 80 JMP ($8000) ;Jump indir to $8000 ($018000) F918 32 EE SAC #$EE F91A A9 02 LDA #$02 ;Map $008000 at $8000 F91C 32 00 SAC #$00 F91E A2 00 LDX #$00 ;Initialize F920 8E 20 D0 STX $D020 ;Black border F923 8E 11 D0 STX $D011 ;Blank screen F926 20 A3 FD JSR $FDA3 F929 20 50 FD JSR $FD50 F92C 20 15 FD JSR $FD15 F92F 20 53 E4 JSR $E453 F932 20 BF E3 JSR $E3BF F935 AD 11 D0 LDA $D011 ;Wait for vertical blanking F938 10 FB BPL $F935 F93A AD 11 D0 LDA $D011 F93D 30 FB BMI $F93A ;--- F93F 20 A0 E5 JSR $E5A0 F942 A9 00 LDA #$00 F944 8D 20 D0 STA $D020 ;Black border F947 8D 11 D0 STA $D011 ;Blank Screen F94A 20 1B E5 JSR $E51B F94D 20 5E FF JSR $FF5E F950 58 CLI F951 A2 01 LDX #$01 ;Set video standard from User Port and $01 bits F953 8E 3F D0 STX $D03F F956 A9 00 LDA #$00 F958 8D 03 DD STA $DD03 F95B AD 01 DD LDA $DD01 F95E 85 AA STA $AA F960 29 03 AND #$03 F962 8D 40 D0 STA $D040 F965 A5 AA LDA $AA F967 4A LSR A F968 4A LSR A F969 29 0F AND #$0F F96B 8D 4F D0 STA $D04F F96E 24 AA BIT $AA F970 70 03 BVS $F975 F972 A9 07 LDA #$07 F974 2C .BYTE $2C F975 A9 06 LDA #$06 F977 8D 4E D0 STA $D04E F97A 24 AA BIT $AA F97C 30 03 BMI $F981 F97E A0 02 LDY #$02 F980 2C .BYTE $2C F981 A0 05 LDY #$05 F983 A5 01 LDA $01 F985 29 10 AND #$10 F987 D0 0A BNE $F993 F989 98 TYA F98A 18 CLC F98B 69 06 ADC #$06 F98D A8 TAY F98E A9 00 LDA #$00 F990 8D 4E D0 STA $D04E F993 A2 02 LDX #$02 F995 B9 0C FA LDA $FA0C,Y F998 9D 41 D0 STA $D041,X F99B 88 DEY F99C CA DEX F99D 10 F6 BPL $F995 F99F A9 00 LDA #$00 F9A1 8D 3F D0 STA $D03F ;--- F9A4 78 SEI F9A5 A9 7F LDA #$7F F9A7 8D 00 DC STA $DC00 ;Check F9AA AD 01 DC LDA $DC01 F9AD 29 04 AND #$04 F9AF D0 13 BNE $F9C4 ;no, auto boot F9B1 58 CLI ;yes, jump into basic F9B2 A9 0E LDA #$0E F9B4 8D 20 D0 STA $D020 F9B7 A9 06 LDA #$06 F9B9 8D 21 D0 STA $D021 F9BC A9 1B LDA #$1B F9BE 8D 11 D0 STA $D011 F9C1 6C 00 A0 JMP ($A000) F9C4 A2 FB LDX #$FB ;Auto boot "INTRO" from flash and go to $080D F9C6 9A TXS F9C7 A9 08 LDA #$08 F9C9 A8 TAY F9CA A2 01 LDX #$01 F9CC 20 BA FF JSR $FFBA F9CF AD FA F9 LDA $F9FA F9D2 A2 F5 LDX #$F5 F9D4 A0 F9 LDY #$F9 F9D6 20 BD FF JSR $FFBD F9D9 A9 00 LDA #$00 F9DB 20 D5 FF JSR $FFD5 F9DE 86 2D STX $2D F9E0 84 2E STY $2E F9E2 A9 93 LDA #$93 F9E4 8D 00 DD STA $DD00 F9E7 A9 15 LDA #$15 F9E9 8D 18 D0 STA $D018 F9EC 58 CLI F9ED A9 0B LDA #$0B F9EF 8D 11 D0 STA $D011 F9F2 6C FB F9 JMP ($F9FB) F9F5 49 4E 54 52 4F ; "INTRO" F9FA 05 .BYTE $05 ;length of name F9FB 0D 08 .WORD $080D ;start address ---------------------------------------------------------------------------- ; Jump #2: Save F9FD A5 BA LDA $BA ;Get device number F9FF C9 01 CMP #$01 ;Is it 1? FA01 F0 03 BEQ $FA06 ;yes, skip out. FA03 4C ED F5 JMP $F5ED ;no, go to normal save FA06 A9 00 LDA #$00 ;Save to flash FA08 85 90 STA $90 ;Set status ok. FA0A 18 CLC FA0B 60 RTS ;Exit ;Burst Rate Modulus table FA0C 1C 13 2A .BYTE $1C,$13,$2A ;NTSC, 32.64 MHz FA0F 24 31 5B .BYTE $24,$31,$5B ;PAL, 31.36 MHz FA12 1C 00 00 .BYTE $1C,$00,$00 ;NTSC, 32.7272 MHz FA15 24 00 00 .BYTE $24,$00,$00 ;PAL, 31.5279MHz FA18 C4 D4 D6 38 30 ; "DTV80" ---------------------------------------------------------------------------- ; Jump #3: Reset Video Mode FA1D A9 01 LDA #$01 FA1F 8D 3F D0 STA $D03F FA22 A2 07 LDX #$07 FA24 A9 00 LDA #$00 FA26 9D 36 D0 STA $D036,X FA29 9D 45 D0 STA $D045,X FA2C CA DEX FA2D 10 F7 BPL $FA26 FA2F 8D 4D D0 STA $D04D FA32 A9 76 LDA #$76 FA34 8D 36 D0 STA $D036 FA37 8D 3A D0 STA $D03A FA3A 20 40 FA JSR $FA40 FA3D 4C A0 E5 JMP $E5A0 ;Continue to load the VIC-II defaults ---------------------------------------------------------------------------- ; Jump #4: Reset Palette FA40 A9 01 LDA #$01 ;Reset Palette FA42 8D 3F D0 STA $D03F FA45 A2 0F LDX #$0F FA47 BD 56 FA LDA $FA56,X FA4A 9D 00 D2 STA $D200,X FA4D CA DEX FA4E 10 F7 BPL $FA47 FA50 A9 00 LDA #$00 FA52 8D 3F D0 STA $D03F FA55 60 RTS FA56 00 0F 36 BE 58 DB 86 FF ;Default Palette FA5E 29 26 3B 05 07 DF 9A 0A ; ---------------------------------------------------------------------------- ---------------------------------------------------------------------------- FCE2 4C 2D F7 JMP $F72D ;Reset Hook, was: LDX #$FF, SEI ---------------------------------------------------------------------------- ---------------------------------------------------------------------------- FD4C 30 F7 .WORD $F730 ;Load Vector, was: $F4A5 FD4E 33 F7 .WORD $F733 ;Save Vector, was: $F5ED ---------------------------------------------------------------------------- ROM Bugs -------- Tape I/O crashes: The patch replaces several tape routines, but all entry points are not patched, meaning that attempted tape operation may simply crash in a strange way. Kernal load from flash returns faulty address in X/Y: The kernal load routine is supposed to return the end address in X/Y. (lsb/msb) It also shall set $ae/$af to the end address. The routine at $f7e9 correctly sets the address in X/Y and $ae/$af, but unfortunately the swap routine at $f84d then overwrites Y with $41 every time. X/Y are used by basic to set up the end pointers $2d/$2e and others, so there are problems loading basic programs (and other programs that rely on $2d/$2e) from flash. Also note that the load routine will never return with an error. Kernal verify from flash will result in load: A kernal verify operation is not supported for flash, but will not be ignored. Instead a load operation will be performed. Directory Format ---------------- The directory is located at $010000-$013fff. Each entry is 32 bytes long: --- $00-$17 Filename max 24 bytes, padded with $00 $18-$1a Location of the file in flash. $1b-$1d Load address of file in RAM. $1e-$1f unused, always $00. --- Directory scanning stops when the first byte of the entry is $00. Note that the directory presented when doing LOAD"$" is just a file named "$", not the actual directory. File Format ----------- The files are compressed using a simple equal-sequence compression algorithm. Every chunk of data starts with a code-byte. If the code is $01-$7f, that number of bytes follow. If the code is $80-$ff, then len=code & $7f, and a second byte follows this copies len bytes of data from the current destination-$0100+secondbyte. If the code is $00, then we are done. To just store the data without any compression, put an $7f byte before every 127 bytes, and terminate with a $00 byte. --- eof