logo.jpg

CBM ROM Loader

Informations provided by Luigi Di Fraia. This document is a work in progress, so it should be taken as a guideline for those wanting to know more about the original standard specifications.

Encoding

On the Commodore 64 CBM's ROM Loader uses 3 pulse types whose values have been observed to be close to:

  (S)hort  : TAP value $30
  (M)edium : TAP value $42
  (L)ong   : TAP value $56

In some of the literature from the 80s (e.g. Nick Hampshire's “Commodore 64 Kernal and Hardware Revealed”) the following durations are defined, which seem to apply to VIC 20 rather than to the Commodore 64:

  (S)hort  : 2840 Hz
  (M)edium : 1953 Hz
  (L)ong   : 1488 Hz

Any definition of these durations would be more appropriately expressed in clock cycles, rather than absolute timings. The reason is that the number of clock cycles that make up each pulse is independent of the machine, where the actual duration in seconds depends on the CPU frequency of the machine itself.

Field observations suggest that either the number of clock cycles has been changed in different versions of the CBM Kernal, or the tape deck circuitry has changed, or (very unlikely but still a possibility) some files for a machine have been recorded on a different machine. In fact, we have examples of C64 files (mainly old ones) using pulses whose duration is typical of VIC 20 files. In support of these speculations we also have examples of files that miss the “end-of-data marker” -see later- at the end of certain CBM files.

Pulses are always interpreted as a pair:

  (S,M) = 0 bit
  (M,S) = 1 bit
  (L,M) = new-data marker
  (L,S) = end-of-data marker

Framing

Each data byte is organized as follows:

  (?,?) (?,?) (?,?) (?,?) (?,?) (?,?) (?,?) (?,?) (?,?) (?,?)
    |     |     |     |     |     |     |     |     |     |
    |    bit0  bit1  bit2  bit3  bit4  bit5  bit6  bit7   |
    |                                                     |
data marker                                             checkbit

So that, each byte is encoded as a sequence of 20 pulses (10 pairs):

  1 data marker:

    data finishes when an "end-of-data marker" (L,S) is met.
    Older Kernal SAVE routines do not seem to save the "end-of-data marker",
    so it has to be assumed as a non-mandatory field.

The following data is NOT present if data marker is "end-of-data marker":

  8 bits of information in LSbF format.

  1 checkbit which is computed as:

    1 XOR bit0 XOR bit1 XOR bit2 XOR bit3 XOR bit4 XOR bit5 XOR bit6 XOR bit7. 

Structure

When a VIC20 or a C64 save a file to tape with the following:

  SAVE "MY PROGRAM", 1    (relocatable program file: secondary address being
                           0 or any even number, i.e. bit 0 clear)
  SAVE "MY PROGRAM", 1, 1 (non-relocatable program file: secondary address
                           being 1 or any odd number, i.e. bit 0 set)

they create 4 files:

  silence (roughly 0.333 seconds, which allows the motor to reach full speed before recording data)

  HEADER
  HEADER REPEATED

  silence (roughly 0.333 seconds, which allows the motor to reach full speed)

  DATA
  DATA REPEATED

Additionally, if bit 1 of the secondary address is set, an End-of-tape marker is
saved after the DATA REPEATED file (load address/end address and filename are the
ones used in the first two HEADER files):

  silence (roughly 0.333 seconds, which allows the motor to reach full speed)

  HEADER - End-of-tape marker
  HEADER - End-of-tape marker, REPEATED

When a SEQuential file is saved to tape with:

  OPEN N, 1, 1, "MY SEQ DATA" (no "End-of-tape marker" is saved)
  OPEN N, 1, 2, "MY SEQ DATA" ("End-of-tape marker" is saved after all files)

  PRINT# N, "DATA STARTS HERE..."
  ...
  PRINT# N, "... DATA..."
  ...
  PRINT# N, "STOP"

  CLOSE N

it's segmented, if required, and encapsulated into HEADER files. A padding is
automatically done, if required, since HEADER payload has a standard length (191
bytes). An empty HEADER (all "File name" and "body" bytes are $20) comes before
data:

  HEADER - SEQ file header
  HEADER - SEQ file header, REPEATED

One or more of these follow, depending on the SEQ data size:

  silence (duration is variable)

  HEADER - Data block for SEQ file
  HEADER - Data block for SEQ file, REPEATED

If an "End-of-tape marker" is requested, the OS saves an additional empty HEADER
just after the last "Data block for SEQ file":

  silence (roughly 0.333 seconds, which allows the motor to reach full speed)

  HEADER - End-of-tape marker
  HEADER - End-of-tape marker, REPEATED 

Leader

A ten second leader is written on the tape before recording of the data or program commences. This leader has two functions; first it allows the tape motor to reach the correct speed, and secondly the sequence of short pulses written on the leader is used to synchronize the read routine timing to the timing on the tape. The operating system can thus produce a correction factor which allows a very wide variation in tape speed without affecting reading.

The exact amount of short pulses is:

  - $6A00 (10 seconds) for HEADER 

Interrecord gaps

Interrecord gaps are primarily used in ASCII files and their function is to allow the tape motor time to decelerate after being turned off and accelerate to the correct speed when turned on prior to a block read or write. Each inter-record gap is approximately two seconds long and is recorded as a sequence of short pulses in the same manner as the ten second leader.

The exact amount of short pulses is:

  - $1500 (2 seconds) for DATA, and HEADER when it contains "Data block
    for SEQ file" 

Interblock gaps

There is also a gap between each file and its replication.

The exact amount of short pulses is:

  - $4F   before HEADER REPEATED and DATA REPEATED

Sync

It consists in a sync train (9 bytes).

Both HEADER and DATA blocks have the following sequence:

    $89 $88 $87 $86 $85 $84 $83 $82 $81

Both HEADER REPEATED and DATA REPEATED blocks have the same sequence with bit 7 clear:

    $09 $08 $07 $06 $05 $04 $03 $02 $01

HEADER

For any HEADER the following information is sent after the sync sequence:

  1 Byte   : File type.

    $01= relocatable program
    $02= Data block for SEQ file
    $03= non-relocatable program
    $04= SEQ file header
    $05= End-of-tape marker

  Here starts what I refer to as HEADER "payload".
  In case File type is not $02, the following bytes have this meaning:

    2 Bytes  : Start Address (LSBF).
    2 Bytes  : End Address+1 (LSBF).
    16 Bytes : File Name (PETSCII format, padded with blanks).

  When File type is $02, SEQ file data starts immediately after File Type thus
  allowing the use of those 20 bytes to store additional data.

  After the File Name there is HEADER "body": 171 bytes, often used by commercial
  loaders to store executable loader code or any additional data and code the
  loader or program may require.
  It encapsulates Data for segmented SEQ files too, as discussed before.

  The default behaviour of the Kernal SAVE command is to pad the File Name with
  blanks so that the total length of the name portion equals 187 bytes.

  Last Byte: Data checkbyte, computed as:

    0 XOR all other HEADER bytes, from "File type" to end of "body".

  After the checkbyte there may or may not be an "end-of-data marker".

DATA

For any DATA the following information is sent after the sync sequence:

  DATA body

  Last Byte: Data checkbyte, computed as:

    0 XOR all DATA "body" bytes.

  After the checkbyte there may or may not be an "end-of-data marker".

Trailer

Some trailing short pulses follow both HEADER REPEATED and DATA REPEATED. The standard amount is $4E pulses.

C64 Notes

HEADER blocks always load into the Tape Buffer at $033C.

If the File Type is relocatable program the start address for loading will be $0801 regardless of what may be written in the 'Start Address' field.

Header and SEQ overview

Disassembly

  ;[Generated by 6510 Dasm v2.1b (c)2004-05 Luigi Di Fraia]

  ;
  ;load RAM from a device
  ;
  JF49E  86  C3        STX $C3         ;set destination address from XY
         84  C4        STY $C4         
         6C  30  03    JMP ($0330)     ;load RAM (normally F4A5)

  ;
  ;standard load RAM entry
  ;
  WF4A5  85  93        STA $93         ;set load/verify switch to load
         A9  00        LDA #$00       
         85  90        STA $90         ;clear ST
         A5  BA        LDA $BA         ;if current device is keyboard (0)
         D0  03        BNE $F4B2       
  BF4AF  4C  13  F7    JMP $F713       ;indicate Illegal Device # Error


  BF4B2  C9  03        CMP #$03        ;if current device is the screen
         F0  F9        BEQ $F4AF       ;indicate error
         90  7B        BCC $F533       ;if not serial bus device
         A4  B7        LDY $B7         ;and if no filename,
         D0  03        BNE $F4BF       
         4C  10  F7    JMP $F710       ;indicate File Name Missing Error


  BF4BF  A6  B9        LDX $B9         ;move X to secondary address
         20  AF  F5    JSR $F5AF       ;handle load messages
         A9  60        LDA #$60        ;set current secondary address
         85  B9        STA $B9         
         20  D5  F3    JSR $F3D5       ;perform open of serial bus device
         A5  BA        LDA $BA         ;let A = current device
         20  09  ED    JSR $ED09       ;send TALK on serial bus
         A5  B9        LDA $B9         ;fetch secondary address
         20  C7  ED    JSR $EDC7       ;and send on serial bus
         20  13  EE    JSR $EE13       ;input a byte on serial bus
         85  AE        STA $AE         ;set I/O end address
         A5  90        LDA $90         
         4A            LSR             
         4A            LSR             
         B0  50        BCS $F530       ;if ST doesn't indicate a timeout (read)
         20  13  EE    JSR $EE13       ;input a byte on serial bus
         85  AF        STA $AF         ;set high byte of end address
         8A            TXA             
         D0  08        BNE $F4F0       ;if EOI is not low,
         A5  C3        LDA $C3         ;use destination address
         85  AE        STA $AE         ;as end address
         A5  C4        LDA $C4         ;ditto for high byte
         85  AF        STA $AF         
  BF4F0  20  D2  F5    JSR $F5D2       ;print LOAD or VERIFY
  BF4F3  A9  FD        LDA #$FD        ;clear timeout (read) bit
         25  90        AND $90         ;in ST
         85  90        STA $90         
         20  E1  FF    JSR $FFE1       ;check for Stop key
         D0  03        BNE $F501       ;if depressed
         4C  33  F6    JMP $F633       ;abort load


  BF501  20  13  EE    JSR $EE13       ;input a byte on serial bus
         AA            TAX             
         A5  90        LDA $90         ;if Timeout (read) set in ST
         4A            LSR             
         4A            LSR             
         B0  E8        BCS $F4F3       ;abort load
         8A            TXA             
         A4  93        LDY $93         ;if in verify mode
         F0  0C        BEQ $F51C       
         A0  00        LDY #$00       
         D1  AE        CMP ($AE),Y     ;compare byte read to memory
         F0  08        BEQ $F51E       
         A9  10        LDA #$10       
         20  1C  FE    JSR $FE1C       ;and set verify error on mismatch
         2C            .BYTE $2C       ;skip next instruction
  BF51C  91  AE        STA ($AE),Y     ;load byte to memory
  BF51E  E6  AE        INC $AE         ;bump load address
         D0  02        BNE $F524       
         E6  AF        INC $AF         
  BF524  24  90        BIT $90         ;if not end of file
         50  CB        BVC $F4F3       ;repeat
         20  EF  ED    JSR $EDEF       ;else send TALK on serial bus
         20  42  F6    JSR $F642       ;close serial bus
         90  79        BCC $F5A9       ;and exit
  BF530  4C  04  F7    JMP $F704       ;indicate File Not Found Error


  BF533  4A            LSR             ;if input device is not 1 (cassette)
         B0  03        BCS $F539       
         4C  13  F7    JMP $F713       ;indicate Illegal Device #


  BF539  20  D0  F7    JSR $F7D0       ;fetch tape buffer pointer
         B0  03        BCS $F541       
         4C  13  F7    JMP $F713       ;if invalid, indicate Illegal Device #


  BF541  20  17  F8    JSR $F817       ;display msgs and test buttons for read
         B0  68        BCS $F5AE       
         20  AF  F5    JSR $F5AF       ;handle load messages
  BF549  A5  B7        LDA $B7         ;if file name present
         F0  09        BEQ $F556       
         20  EA  F7    JSR $F7EA       ;search tape for file name
         90  0B        BCC $F55D       ;if no errors, continue
         F0  5A        BEQ $F5AE       ;exit if end of tape
         B0  DA        BCS $F530       ;error if not found
  BF556  20  2C  F7    JSR $F72C       ;since no file name, get next tape hdr
         F0  53        BEQ $F5AE       ;exit if end of tape found
         B0  D3        BCS $F530       ;indicate File Not found Error
  BF55D  A5  90        LDA $90         ;check ST for unrecoverable read error
         29  10        AND #$10       
         38            SEC             
         D0  4A        BNE $F5AE       ;and exit if so
         E0  01        CPX #$01        ;if not Program Header
         F0  11        BEQ $F579       
         E0  03        CPX #$03       
         D0  DD        BNE $F549       
  BF56C  A0  01        LDY #$01       
         B1  B2        LDA ($B2),Y     
         85  C3        STA $C3         ;reset load address from tape buffer
         C8            INY             
         B1  B2        LDA ($B2),Y     ;high byte also
         85  C4        STA $C4         
         B0  04        BCS $F57D       
  BF579  A5  B9        LDA $B9         
         D0  EF        BNE $F56C       
  BF57D  A0  03        LDY #$03        ;index low byte of end address
         B1  B2        LDA ($B2),Y     
         A0  01        LDY #$01       
         F1  B2        SBC ($B2),Y     ;compute length of block to load
         AA            TAX             
         A0  04        LDY #$04       
         B1  B2        LDA ($B2),Y     
         A0  02        LDY #$02       
         F1  B2        SBC ($B2),Y     
         A8            TAY             
         18            CLC             
         8A            TXA             
         65  C3        ADC $C3         
         85  AE        STA $AE         ;and set the end address of I/O area
         98            TYA             
         65  C4        ADC $C4         
         85  AF        STA $AF         
         A5  C3        LDA $C3         
         85  C1        STA $C1         ;set tape load address
         A5  C4        LDA $C4         
         85  C2        STA $C2         
         20  D2  F5    JSR $F5D2       ;display load messages
         20  4A  F8    JSR $F84A       ;load from cassette
         24            .BYTE $24       ;skip next instruction
  BF5A9  18            CLC             ;clear error flag
         A6  AE        LDX $AE         ;exit with end address in XY
         A4  AF        LDY $AF         
  BF5AE  60            RTS             

  ;---------------------------------

  ;
  ;get next file header from cassette
  ;
  SF72C  A5  93        LDA $93         ;save load/verify switch on stack
         48            PHA             
         20  41  F8    JSR $F841       ;read a block from tape
         68            PLA             
         85  93        STA $93         ;restore load/verify flag
         B0  32        BCS $F769       ;exit if read error
         A0  00        LDY #$00       
         B1  B2        LDA ($B2),Y     ;get first character in tape buffer
         C9  05        CMP #$05        ;if code for End of Tape
         F0  2A        BEQ $F769       ;return
         C9  01        CMP #$01       
         F0  08        BEQ $F74B       ;if not code for Program Header
         C9  03        CMP #$03        ;or "?"
         F0  04        BEQ $F74B       
         C9  04        CMP #$04       
         D0  E1        BNE $F72C       ;or Data Header, try next block
  BF74B  AA            TAX             
         24  9D        BIT $9D         ;if in direct mode,
         10  17        BPL $F767       
         A0  63        LDY #$63        ;point to message FOUND
         20  2F  F1    JSR $F12F       ;and print it
         A0  05        LDY #$05       
  BF757  B1  B2        LDA ($B2),Y     
         20  D2  FF    JSR $FFD2       ;print a file name character
         C8            INY             
         C0  15        CPY #$15        ;and repeat
         D0  F6        BNE $F757       ;for all characters
         A5  A1        LDA $A1         
         20  E0  E4    JSR $E4E0       ;pause
         EA            NOP             ;filler for patch
         18            CLC             
         88            DEY             
         60            RTS             

  ;---------------------------------

  ;
  ;read a block from cassette
  ;
  SF841  A9  00        LDA #$00       
         85  90        STA $90         ;clear ST
         85  93        STA $93         ;set load/verify switch to load
         20  D7  F7    JSR $F7D7       ;set tape buffer to I/O area
  SF84A  20  17  F8    JSR $F817       ;handle msgs and test sense for read
         B0  1F        BCS $F86E       
         78            SEI             ;disable IRQ
         A9  00        LDA #$00       
         85  AA        STA $AA         ;set gap
         85  B4        STA $B4         ;set no sync estabilished
         85  B0        STA $B0         ;set no special speed correction yet
         85  9E        STA $9E         ;initialize error log index for pass 1
         85  9F        STA $9F         ;and pass2
         85  9C        STA $9C         ;set no byte available yet
         A9  90        LDA #$90        ;set Flag mask
         A2  0E        LDX #$0E        ;index for cassette read IRQ address
         D0  11        BNE $F875       ;JMP

  ;
  ;write a block to cassette
  ;
  SF864  20  D7  F7    JSR $F7D7       ;initialize tape buffer pointer
  SF867  A9  14        LDA #$14
         85  AB        STA $AB         ;20 sync patterns
  SF86B  20  38  F8    JSR $F838       ;test sense and display msgs for output
  BF86E  B0  6C        BCS $F8DC
         78            SEI
         A9  82        LDA #$82        ;mask for ICR1 to honor TB1
         A2  08        LDX #$08        ;IRQ index for cassette write, part 1

  ;
  ;common code for cassette read & write
  ;
  BF875  A0  7F        LDY #$7F       
         8C  0D  DC    STY $DC0D       ;clear any pending mask in ICR1
         8D  0D  DC    STA $DC0D       ;then set mask for TB1
         AD  0E  DC    LDA $DC0E
         09  19        ORA #$19        ;+force load, one shot and TB1 to CRA1
         8D  0F  DC    STA $DC0F       ;to form CRB1
         29  91        AND #$91
         8D  A2  02    STA $02A2       ;and CRB1 activity register
         20  A4  F0    JSR $F0A4       ;condition flag bit in ICR2
         AD  11  D0    LDA $D011       
         29  EF        AND #$EF       
         8D  11  D0    STA $D011       ;disable the screen
         AD  14  03    LDA $0314       ;save standard IRQ vector
         8D  9F  02    STA $029F
         AD  15  03    LDA $0315
         8D  A0  02    STA $02A0
         20  BD  FC    JSR $FCBD       ;set new IRQ for cassette depending on X
         A9  02        LDA #$02
         85  BE        STA $BE         ;select phase 2
         20  97  FB    JSR $FB97       ;initialize cassette I/O variables
         A5  01        LDA $01
         29  1F        AND #$1F
         85  01        STA $01         ;start cassette motor
         85  C0        STA $C0         ;set tape motor interlock
         A2  FF        LDX #$FF       
  BF8B5  A0  FF        LDY #$FF       
  BF8B7  88            DEY             
         D0  FD        BNE $F8B7       ;delay 0.3 seconds
         CA            DEX             
         D0  F8        BNE $F8B5       
         58            CLI             
  BF8BE  AD  A0  02    LDA $02A0       ;test high byte of IRQ save area
         CD  15  03    CMP $0315       ;to determine if end of I/O
         18            CLC             
         F0  15        BEQ $F8DC       ;exit if so
         20  D0  F8    JSR $F8D0       ;else test Stop key
         20  BC  F6    JSR $F6BC       ;scan keyboard
         4C  BE  F8    JMP $F8BE       ;repeat

  ;---------------------------------

  ;
  ;set IRQ vector depending upon X
  ;
  SFCDB  BD  93  FD    LDA $FD9B-8,X   ;move low byte of address
         8D  14  03    STA $0314       ;into low byte of IRQ vector
         BD  94  FD    LDA $FD9B-7,X   ;then do high byte
         8D  15  03    STA $0315       
         60            RTS

  ;---------------------------------

  ;
  ;IRQ vectors
  ;
  TFD9B  .WORD $FC6A
         .WORD $FBDC
         .WORD $EA31
         .WORD $F92C

  ;---------------------------------

  ;
  ;cassette read IRQ routine
  ;
  BF92C  AE  07  DC    LDX $DC07       ;get TBH1
         A0  FF        LDY #$FF       
         98            TYA             ;and the complement of TBL1
         ED  06  DC    SBC $DC06       ;(time elapsed)
         EC  07  DC    CPX $DC07       ;if high byte not steady,
         D0  F2        BNE $F92C       ;repeat
         86  B1        STX $B1         ;else save high byte
         AA            TAX             
         8C  06  DC    STY $DC06       ;reset TBL1 to maximum
         8C  07  DC    STY $DC07       ;ditto TBH1
         A9  19        LDA #$19        ;force load, one-shot and Timer B
         8D  0F  DC    STA $DC0F       ;into CRB1
         AD  0D  DC    LDA $DC0D       
         8D  A3  02    STA $02A3       ;save ICR1
         98            TYA             
         E5  B1        SBC $B1         ;complement high byte
         86  B1        STX $B1         ;save low byte
         4A            LSR             ;elapsed time in A, ZB1
         66  B1        ROR $B1         ;/ 2
         4A            LSR             
         66  B1        ROR $B1         ;/ 4
         A5  B0        LDA $B0         ;get speed correction
         18            CLC             
         69  3C        ADC #$3C        ;+240 microseconds
         C5  B1        CMP $B1         ;if cycle shorter
         B0  4A        BCS $F9AC       ;dismiss
         A6  9C        LDX $9C         ;if byte available
         F0  03        BEQ $F969       
         4C  60  FA    JMP $FA60       ;receive it


  BF969  A6  A3        LDX $A3         ;test bit count and if beyond last bit,
         30  1B        BMI $F988       ;do end of byte
         A2  00        LDX #$00        ;assume bit value of 0
         69  30        ADC #$30        ;add 432 microseconds
         65  B0        ADC $B0         ;+ 2 * speed correction
         C5  B1        CMP $B1         ;if cycle shorter
         B0  1C        BCS $F993       ;record a 0
         E8            INX             ;assume bit value of 1
         69  26        ADC #$26        ;get 584 microseconds
         65  B0        ADC $B0         ;+ 3 * speed correction
         C5  B1        CMP $B1         ;if cycle shorter
         B0  17        BCS $F997       ;record a 1
         69  2C        ADC #$2C        ;get 760 microseconds
         65  B0        ADC $B0         ;+ 4 * speed correction
         C5  B1        CMP $B1         ;if cycle shorter
         90  03        BCC $F98B       
  BF988  4C  10  FA    JMP $FA10       ;go do end of byte


  BF98B  A5  B4        LDA $B4         ;if sync estabilished
         F0  1D        BEQ $F9AC       
         85  A8        STA $A8         ;set erroneous bits
         D0  19        BNE $F9AC       
  BF993  E6  A9        INC $A9         ;for a 0, increment 0/1 balance
         B0  02        BCS $F999       
  BF997  C6  A9        DEC $A9         ;for a 1, decrement 0/1 balance
  BF999  38            SEC             
         E9  13        SBC #$13        ;0/1 cutoff level
         E5  B1        SBC $B1         ;-cycle width
         65  92        ADC $92         
         85  92        STA $92         ;accumulated for speed correction
         A5  A4        LDA $A4         
         49  01        EOR #$01        ;flip cycle indication
         85  A4        STA $A4         
         F0  2B        BEQ $F9D5       ;if first cycle,
         86  D7        STX $D7         ;save bit value
  BF9AC  A5  B4        LDA $B4         ;if no sync yet
         F0  22        BEQ $F9D2       ;return from IRQ
         AD  A3  02    LDA $02A3       ;if ICR1 mask
         29  01        AND #$01       
         D0  05        BNE $F9BC       
         AD  A4  02    LDA $02A4       ;and last CRA1 mask shows no TA1 flag
         D0  16        BNE $F9D2       ;exit from IRQ
  BF9BC  A9  00        LDA #$00       
         85  A4        STA $A4         ;clear cycle count
         8D  A4  02    STA $02A4       ;and last CRA1 mask
         A5  A3        LDA $A3         ;if bit count indicated end of byte,
         10  30        BPL $F9F7       
         30  BF        BMI $F988       ;go do end of byte
  BF9C9  A2  A6        LDX #$A6       
         20  E2  F8    JSR $F8E2       ;schedule timer
         A5  9B        LDA $9B         ;if parity calculated does not match
         D0  B9        BNE $F98B       ;set erroneous bit flag
  BF9D2  4C  BC  FE    JMP $FEBC       ;exit from IRQ


  BF9D5  A5  92        LDA $92         ;if second cycle
         F0  07        BEQ $F9E0       ;check accumulated over/under time
         30  03        BMI $F9DE       
         C6  B0        DEC $B0         
         2C            .BYTE $2C       ;skip next instruction
  BF9DE  E6  B0        INC $E0         ;adapt speed correction accordingly
  BF9E0  A9  00        LDA #$00       
         85  92        STA $92         ;reset accumulated over/under time
         E4  D7        CPX $D7         ;if 2nd cycle = complement of cycle 1
         D0  0F        BNE $F9F7       ;include bit
         8A            TXA             
         D0  A0        BNE $F98B       ;if two 0 cycles
         A5  A9        LDA $A9         ;and 0/1 balance
         30  BD        BMI $F9AC       
         C9  10        CMP #$10        ;at least 16 "0" cycles extra
         90  B9        BCC $F9AC       
         85  96        STA $96         ;set sync detected
         B0  B5        BCS $F9AC       
  BF9F7  8A            TXA             
         45  9B        EOR $9B         ;calculate parity
         85  9B        STA $9B         
         A5  B4        LDA $B4         ;if no sync yet
         F0  D2        BEQ $F9D2       ;exit
         C6  A3        DEC $A3         ;decrement pending bit count
         30  C5        BMI $F9C9       ;after last bit, check parity
         46  D7        LSR $D7         ;include bit
         66  BF        ROR $BF         ;in byte being read
         A2  DA        LDX #$DA       
         20  E2  F8    JSR $F8E2       ;schedule timer
         4C  BC  FE    JMP $FEBC       ;exit from IRQ


  BFA10  A5  96        LDA $96         ;if sync detected
         F0  04        BEQ $FA18       
         A5  B4        LDA $B4         ;and not yet estabilished
         F0  07        BEQ $FA1F       
  BFA18  A5  A3        LDA $A3         ;or last bit done
         30  03        BMI $FA1F       
         4C  97  F9    JMP $F997       ;allow byte reception


  BFA1F  46  B1        LSR $B1         ;compute new speed correction value
         A9  93        LDA #$93       
         38            SEC             
         E5  B1        SBC $B1         
         65  B0        ADC $B0         
         0A            ASL             
         AA            TAX             
         20  E2  F8    JSR $F8E2       ;schedule timer
         E6  9C        INC $9C         ;indicate byte available
         A5  B4        LDA $B4         ;if not yet estabilished
         D0  11        BNE $FA44       
         A5  96        LDA $96         ;but sync detected
         F0  26        BEQ $FA5D       
         85  A8        STA $A8         ;set error bits
         A9  00        LDA #$00       
         85  96        STA $96         ;clear sync detected
         A9  81        LDA #$81        ;set TA1 bit
         8D  0D  DC    STA $DC0D       ;in ICR1
         85  B4        STA $B4         ;set sync estabilished
  BFA44  A5  96        LDA $96         ;move sync status
         85  B5        STA $B5         ;to saved sync status
         F0  09        BEQ $FA53       
         A9  00        LDA #$00        ;if not detected,
         85  B4        STA $B4         ;indicate sync not estabilished
         A9  01        LDA #$01       
         8D  0D  DC    STA $DC0D       
  BFA53  A5  BF        LDA $BF         ;clear TA mask in ICR1
         85  BD        STA $BD         ;save byte read
         A5  A8        LDA $A8         
         05  A9        ORA $A9         ;accumulate possible errors
         85  B6        STA $B6         
  BFA5D  4C  BC  FE    JMP $FEBC       ;exit from IRQ

  ;---------------------------------

  ;
  ;schedule CIA1 Timer A depending on parameter in X
  ;
  SF8E2  86  B1        STX $B1         ;save entry parameter
         A5  B0        LDA $B0         ;get speed correction
         0A            ASL             ;* 2
         0A            ASL             ;* 4
         18            CLC             
         65  B0        ADC $B0         ;add speed correction
         18            CLC             
         65  B1        ADC $B1         ;and parameter
         85  B1        STA $B1         ;save low order
         A9  00        LDA #$00       
         24  B0        BIT $B0         ;if speed correction is positive
         30  01        BMI $F8F7       
         2A            ROL             ;set high oreder in A
  BF8F7  06  B1        ASL $B1         ;* 2
         2A            ROL             
         06  B1        ASL $B1         ;* 4
         2A            ROL             
         AA            TAX             
  BF8FE  AD  06  DC    LDA $DC06       ;wait until no change of
         C9  16        CMP #$16        ;TBL1 changing
         90  F9        BCC $F8FE       ;while it still must be read
         65  B1        ADC $B1         :add low order offset to TBL1
         8D  04  DC    STA $DC04       ;and store in TAL1
         8A            TXA             
         6D  07  DC    ADC $DC07       ;add high order offset to TBH1
         8D  05  DC    STA $DC05       ;and store in TAH1
         AD  A2  02    LDA $02A2       
         8D  0E  DC    STA $DC0E       ;set CRA1 from CRB1 activity register
         8D  A4  02    STA $02A4       ;and save it
         AD  0D  DC    LDA $DC0D       
         29  10        AND #$10       
         F0  09        BEQ $F92A       ;if Flag bit is not set
         A9  F9        LDA #$F9        ;set exit address on stack
         48            PHA             
         A9  2A        LDA #$2A       
         48            PHA             
         4C  43  FF    JMP $FF43       ;and simulate an IRQ


  BF92A  58            CLI             ;else allow IRQ and exit
         60            RTS 

Tapes using this loader

Database entryWiki entry
1994 (Ten Years After)1994 (Ten Years After)
2 Player Super League2 Player Super League
3-D Glooper3-D Glooper
3D Speed Duel3D Speed Duel
3D Tanx3D Tanx
3D Time Trek3D Time Trek
Activision Decathlon, TheActivision Decathlon, The
Alien RescueAlien Rescue
American FootballAmerican Football
An Introduction to basic: Part 1An Introduction to basic: Part 1
AnnihilatorAnnihilator
Anter-PlanterAnter-Planter
Ape CrazeApe Craze
Arcadia 64Arcadia 64
Arena 3000Arena 3000
ArmageddonArmageddon
ArmageddonArmageddon
Assembler 64Assembler 64
Astral ZoneAstral Zone
Attack of the Mutant CamelsAttack of the Mutant Camels
AttackerAttacker
Azimuth Head Alignment KitAzimuth Head Alignment Kit
Aztec ChallengeAztec Challenge
Aztec ChallengeAztec Challenge
Aztec ChallengeAztec Challenge
Barrel JumpBarrel Jump
Bath TimeBath Time
Bilder PuzzleBilder Puzzle
Biology 'O' LevelBiology 'O' Level
Bionic GrannyBionic Granny
Black HoleBlack Hole
BlaggerBlagger
BMX Jungle BikeBMX Jungle Bike
BMX RacersBMX Racers
BogglesBoggles
BongoBongo
Booga-Boo (The Flea)Booga-Boo (The Flea)
BrandsBrands
BrandsBrands
Bumping BuggiesBumping Buggies
Bunny ZapBunny Zap
Burger ChaseBurger Chase
Burger TimeBurger Time
Burnin' RubberBurnin' Rubber
Cannonball BattleCannonball Battle
Castle of Skull LordCastle of Skull Lord
Caverns of DoomCaverns of Doom
Chain ReactionChain Reaction
Chinese JugglerChinese Juggler
Chomper ManChomper Man
Commodore Computer Club Nº 3Commodore Computer Club Nº 3
Commodore Computer Club Nº13Commodore Computer Club Nº13
Computer-OrgelComputer-Orgel
Cops 'n' RobbersCops 'n' Robbers
Cosmic CapersCosmic Capers
Cosmic CommandoCosmic Commando
Cosmic SplitCosmic Split
Counter AttackCounter Attack
Cracks of FireCracks of Fire
Crazy BalloonCrazy Balloon
Crazy CavemanCrazy Caveman
Crazy KongCrazy Kong
Crazy KongCrazy Kong
Crush, Crumble and Chomp!Crush, Crumble and Chomp!
Cup FootballCup Football
CyclonsCyclons
CyclonsCyclons
Dancing FeatsDancing Feats
Dancing MonsterDancing Monster
Davy King of the Wild FrontierDavy King of the Wild Frontier
Death StarDeath Star
DecathlonDecathlon
Defender 64Defender 64
Depth ChargeDepth Charge
Derby DashDerby Dash
Designer's Pencil, TheDesigner's Pencil, The
Designer's Pencil, TheDesigner's Pencil, The
Dicky's DiamondsDicky's Diamonds
Do Your SumsDo Your Sums
Dots & BoxesDots & Boxes
DynamiteDynamite
EarthquakeEarthquake
EgbertEgbert
Election Game, TheElection Game, The
Escape-MCPEscape-MCP
Espionage IslandEspionage Island
ExchangeExchange
Fabulous Wanda and the Secret of Life, the Universe and Everything, TheFabulous Wanda and the Secret of Life, the Universe and Everything, The
Face AcheFace Ache
Face MakerFace Maker
Falcon PatrolFalcon Patrol
Faulty TowersFaulty Towers
Fire AntFire Ant
Flight SimulatorFlight Simulator
Flying FeathersFlying Feathers
Flying FeathersFlying Feathers
Forbidden ForestForbidden Forest
Forbidden FruitForbidden Fruit
Force FieldForce Field
Force, TheForce, The
ForestlandForestland
Frogger 64Frogger 64
FroggyFroggy
FroggyFroggy
FrogmanFrogman
Galactic AssaultGalactic Assault
Galactic AttackGalactic Attack
Galactic Dog FightGalactic Dog Fight
GalaxionsGalaxions
Games DesignerGames Designer
GhostsGhosts
Go Racing with Peter O'SullevanGo Racing with Peter O'Sullevan
Goblin TowersGoblin Towers
GolfGolf
Goodness GraciousGoodness Gracious
Grab-a-CrabGrab-a-Crab
Grandmaster ChessGrandmaster Chess
Graphics DesignerGraphics Designer
Graphics EditorGraphics Editor
Great Adventure PackGreat Adventure Pack
Great Nordic War, TheGreat Nordic War, The
GridrunnerGridrunner
GridtrapGridtrap
GuardianGuardian
GusherGusher
HangmanHangman
Harrier Attack!Harrier Attack!
Haunted HouseHaunted House
Heathrow Air Traffic ControlHeathrow Air Traffic Control
Heroes of KarnHeroes of Karn
HexapawnHexapawn
High RiseHigh Rise
Hover BovverHover Bovver
Humpty Dumpty Meets the Fuzzy WuzziesHumpty Dumpty Meets the Fuzzy Wuzzies
HunchbackHunchback
Hungry HoraceHungry Horace
HustlerHustler
In the BeginningIn the Beginning
Inca CurseInca Curse
InfernoInferno
IntruderIntruder
Ivasive ActionIvasive Action
Jet FlightJet Flight
JetmobileJetmobile
Jinn GenieJinn Genie
Jumpin JackJumpin Jack
Jungle StoryJungle Story
KaktusKaktus
Kami-KazeKami-Kaze
Kick-OffKick-Off
Knights of the DesertKnights of the Desert
KongKong
Kongo KongKongo Kong
Krystals of ZongKrystals of Zong
Krystals of ZongKrystals of Zong
LabyrinthLabyrinth
Labyrinth of the CreatorLabyrinth of the Creator
Lancer LordsLancer Lords
Laser ZoneLaser Zone
Lickey RouteLickey Route
Lord of the BalrogsLord of the Balrogs
Lunar LandingLunar Landing
MaggotmaniaMaggotmania
MangroveMangrove
Manic MinerManic Miner
MarathonMarathon
MatrixMatrix
Maze EaterMaze Eater
MaziacsMaziacs
MegahawkMegahawk
MegawarzMegawarz
MetamorphosisMetamorphosis
Metro BlitzMetro Blitz
Millie-BugMillie-Bug
Mind WarpMind Warp
Missile CommandMissile Command
Missile CommandMissile Command
Moby DickMoby Dick
MonopoleMonopole
MonopoleMonopole
Moon BuggyMoon Buggy
MothershipMothership
Motor ManiaMotor Mania
MotorwayMotorway
Mr. WimpyMr. Wimpy
Mr. WizMr. Wiz
Munch ManiaMunch Mania
MurderMurder
Mushroom AlleyMushroom Alley
Music 64Music 64
NavaroneNavarone
NeoclypsNeoclyps
Neptune's DaughtersNeptune's Daughters
NimNim
Noughts and CrossesNoughts and Crosses
Number PuzzlerNumber Puzzler
O'Riley's MineO'Riley's Mine
OdysseyOdyssey
Old BonesOld Bones
OrbitronOrbitron
OrbitterOrbitter
Orc AttackOrc Attack
OutbackOutback
OvertakeOvertake
PakacudaPakacuda
Panic 64Panic 64
ParachuteParachute
ParatroopersParatroopers
PastfinderPastfinder
PedroPedro
Pesky PainterPesky Painter
PhaserPhaser
Pilot 64Pilot 64
Pinball WizardPinball Wizard
Pitfall!Pitfall!
Planet of DeathPlanet of Death
PlanetsPlanets
Plasma BoltPlasma Bolt
PlopPlop
Plumb Crazy!Plumb Crazy!
Plumb Crazy!Plumb Crazy!
PontoonPontoon
PooyanPooyan
Potty Painter in the JunglePotty Painter in the Jungle
ProtectorProtector
Psion AttackPsion Attack
Pub QuestPub Quest
PunchyPunchy
Purple TurtlesPurple Turtles
Quasar ZoneQuasar Zone
Quest of Merravid, TheQuest of Merravid, The
Quintic WarriorQuintic Warrior
QuinxQuinx
Radar LandingRadar Landing
Rasen MaherRasen Maher
RatsRats
RattlerRattler
RenaissanceRenaissance
Renaissance OthelloRenaissance Othello
Revenge of the Mutant CamelsRevenge of the Mutant Camels
Ring of PowerRing of Power
River RescueRiver Rescue
Rocket LaunchRocket Launch
RoxRox
Scuba DiveScuba Dive
Ship of DoomShip of Doom
Ship of the LineShip of the Line
Silicon WarriorSilicon Warrior
Siren CitySiren City
Sitting TargetSitting Target
Ski JumpSki Jump
SkrambleSkramble
SkrambleSkramble
Slicker Puzzle, TheSlicker Puzzle, The
SlurpySlurpy
Smash the WindowsSmash the Windows
SnookerSnooker
SnookerSnooker
SnowmenSnowmen
Soccer QSoccer Q
Son of BlaggerSon of Blagger
Sooper FrootSooper Froot
Space MissionSpace Mission
Space SearchSpace Search
Space ShipSpace Ship
Space Shuttle: A Journey into SpaceSpace Shuttle: A Journey into Space
Space WalkSpace Walk
SpiratesSpirates
Sprite ManSprite Man
Spritemaker 64Spritemaker 64
Stalag 1Stalag 1
Star CommandStar Command
Star CommandoStar Commando
StartrekStartrek
Stellar WarsStellar Wars
Sting 64Sting 64
StixStix
StixStix
Sub HuntSub Hunt
SubmarinesSubmarines
Super DogfightSuper Dogfight
Super Skramble!Super Skramble!
Super SpySuper Spy
Super TrekSuper Trek
SupercudaSupercuda
Tank AtakTank Atak
TankerTanker
Thin IceThin Ice
Thinker, TheThinker, The
Titanic: The Adventure Begins...Titanic: The Adventure Begins...
Toddler TutorToddler Tutor
Token of GhallToken of Ghall
Tombs of XeiopsTombs of Xeiops
Tool Box: Typing TutorTool Box: Typing Tutor
Touch Typing TutorTouch Typing Tutor
Transylvanian TowerTransylvanian Tower
Trax!Trax!
Tribble TroubleTribble Trouble
Troopa TruckTroopa Truck
TrullTrull
Tunnel EscapeTunnel Escape
Turbo Extended BasicTurbo Extended Basic
Turbo TapeTurbo Tape
UniverseUniverse
Vagan AttackVagan Attack
Vixplode-64Vixplode-64
VulturesVultures
Wheelin' WallieWheelin' Wallie
Who Dares WinsWho Dares Wins
Widows RevengeWidows Revenge
Wilder WestenWilder Westen
World Cup IIWorld Cup II
World GeographyWorld Geography
XanagramsXanagrams
YantzeeYantzee
ZenjiZenji
ZylogonZylogon

See also


Personal Tools