MOS TECH BASIC versions

Despite all the versions you see on the download page, there is only one official and original binary known of the MOS TECH BASIC for the 6502 KIM and that is my V1.1 (ID 01) loaded from my original tape. There is another tape known recently, owned by my friend Gerben Voort, and we hope to be able to read that tape.

Every other version is a derivate, in the 80ties or in the past years.

There are also sources of Microsoft Basic for the 6502. The official source, in PDP-11 MACRO source format has been declared open not so long ago.
The title is ‘M6502 8K VER 1.1 BY MICRO-SOFT’. Yes the name of the company was originally MICRO-SOFT!

Many years before the official source, Michael Steyl of pagetable.com reconstructed the source, based upon my binary dump. A perfect start to create derivate versions!

Versions known in the 80ties

  • KB-9
    Created by Microsoft, only distributed by Johnson Computers (afaik). Binary available.
    On the tape label: 2000-4260 ID #01 St 4065
    Oldest known documentation available, scanned.
  • KB-6
    Mentioned in the documentation of ID #01. Not available.
    6 digit precision floating point, smaller in size.
  • KB-9 ID #101
    Distributed by Johnson Computers
    On the tape label: 2000-437D ID #101 St 4065 S/N 217 and 233. Binary not available (yet).
    Mentioned in the documentation of the versions distributed by Johnson Computer with ID #101. Binary not available. Two versions of the documentation known and scanned.
    This version seems to be the V1.1 KB-9 with added Hypertape and BLOCKMOVE routines at the end of the binary. With the alternative start addresses the hypertape routine can be moved to $0200 or $0300 and the SAVE command patched to the hypertape routine. Or with the standard start at $4065 hypertape can be skipped.
    All KB-9 internal addresses are the same.
  • KB-9P
    Mentioned in the documentation of the versions distributed by Johnson Computer with ID #101, Binary not available.
    KB-9P is a stripped version of KB-9 fit for burning into a ROM. SIN-COS-ATN is not available.

My MSBasic for the KIM-1 cassette


Another MOS TECH BASIC for KIM-1, lower serial number


Thanks Gerben Voort


How to build and adapt KB-9 and KB-6

Sources of KB-9 Microsoft Basic v1.1

Adapt KB-9, first step make it faster and smaller

In the previous section the pagetable article was shown, with resources to recreate from source many 6502 Basic’s, like KB-9.

Here an example how I, quick and dirty, used this to create a KB-9 named V1.2 which is smaller and faster than the original.

This is how to prepare for it (Windows, can be done also on Linux)

  1. Download and unpack the archive of pagetable in a folder on your PC.
  2. Download and unpack the CC65 package, a C compiler, from which only the assembler and linker is used. I used the Windows binaries.
  3. Copy CA65.EXE, LD65.EXE and longbranch.mac from the CC65 package to the folder where you unpacked the MS Basic source.

Do the adaptations as described below or your own:

  1. To save you the work I have collected the adaptations described above in this archive for your convenience here.
  2. Change whatever you like in the source. It is quite a complicated construction, with macros for every variant, so look carefully at the listing file what really is produced.
    Start with no adaptations and then go on studying the listing file and testing. The KIM-1 Simulator is a good tool for testing! Load the symbol table file to see what is where.
  3. Assemble and link with this simple batch file makekb9v2.bat, resulting in an object, a binary, a listing file and a symbol label file.
ca65 -D kb9 msbasic.s -o tmp/kb9v2.o -l tmp/kb9v2.lst
ld65 -C kb9.cfg tmp/kb9v2.o -o tmp/kb9v2.bin -Ln tmp/kb9v2.lbl
  • Repeat step 4 and 5 until you are satisfied with the adaptations. The articles listed are a good source of inspiration.
  • These are the adaptations done in V1.2 use the ROR instruction and suppress nulls sent to the terminal and Clear decimal and fix GET
    I changed this:

      • In define_kim.s make a comment of the following two lines:
    ;CONFIG_NULL := 1                     
    ;CONFIG_ROR_WORKAROUND := 1             ; patch HO 2021
    
    • In init.s add this line at label COLD_START
      COLD_START:
      .ifdef SYM1
              jsr     ACCESS
      .endif
      .ifdef KBD
        .
        .
        .
      .else
        .ifndef CBM2
              cld                     ; patch for KIM-1 HO 2021
              ldx     #$FF
              stx     CURLIN+1
      

      Change line 493 init.s

        .ifdef KIM
              .byte   "MOS TECH 6502 BASIC V1.2"
      
    • do the fix in the “GET handling (see below)
    • Add backspace handling to correct typing errors
    • Change the version number in inline.s line 493 to “MOS TECH 6502 BASIC V1.2

    Assemble and link with the batch file makekb9v2.bat, this will deliver in the folder tmp
    – kb9v2.bin file : load as usual at $20001
    – kb9v12.lbl text file
    – kb9v12lst textfile

    Start KB9 V2 now at location $3FB1, label COLD_START (used to be $4065, so we gained some RAM), see the lbl file for other addresses.

    KB-6

    I know KB-6 existed. The ‘6’ stands for the precision in digits of the floating point number. In the documentation KB-6 is described.
    Never seen a version in the wild. So the reconstruction here is not checked with the original, addresses in the reconstruction from the linker differ from the documentation.
    Perhaps the ROR workaround or the insertion of CLD in the init.s caused this.

    KB-6 can be ‘reconstructed’ since other versions of 6 digit Microsoft Basic are in the ‘pagetable sources’.
    It takes one define added in define_kim.s, changes on the original file are now:

    ; CONFIG_NULL := 1                      ; patch HO 2021
    ;CONFIG_ROR_WORKAROUND := 1             ; patch HO 2021
    CONFIG_SMALL := 1                       ; patch H0 2021
    

    Assemble and link as above, replace kb9v12 with kb6v12 in the batch file. See the archive for a working batch file.
    COLD_START moves to $3D50, size shrinks to 8K.

    As you can see in the following screenshots it works! Note the number of digits is less, as expected. It should be faster also.

    Microsoft Basic for the KIM-1 KB-9

    Microsoft Basic for the KIM-1 KB-6, less precision, smaller program size


    The GET bug

    The bug was described and fixed first by an article in the KIM User notes 17

    From the pagetable sources:
    BUG: The beq/bne L2AF8 below is supposed to be always taken. For this to happen, the last load must be a 0 for beq and != 0 for bne.
    The original Microsoft code had ldx/ldy/bne here, which was only correct for a non-ZP INPUTBUFFER. Commodore fixed it in CBMBASIC V1 by swapping the ldx and the ldy. It was broken on KIM, but okay on APPLE and CBM2, because these used a non-ZP INPUTBUFFER. Microsoft fixed this somewhere after KIM and before MICROTAN, by using beq instead of bne in the ZP case.

      .ifdef CBM1
         ldy  >(INPUTBUFFER-1)
         ldx  <(INPUTBUFFER-1)
      .else 
         ldx  >(INPUTBUFFER-1)
         ldy  <(INPUTBUFFER-1)
    ..
         beq 08
    

    You can easily fix this in KB9 by changing the branch in $2AEE from $D0 (bne) to $F0 (beq).
    I have fixed this in the source of KB9V2 (KB6 does not have the GET statement) .

    Use the backspace key to correct typing errors

    Correcting typing errors can be done with the _ key ($5F). On a video terminal, like we use nowadays it can be done with backspace.
    The way characters are handled by the input routine do not allow to just replace the compare with _ (C9 5F) with 08 for backspace.

    A trick by Jim W4JBM can be used to reuse the BELL handling (07) to a backspace.
    Replace in inline.s

    INLINAIM:
        .endif
        .ifndef CONFIG_NO_LINE_EDITING
            cmp     #$07
            beq     L2443
    

    with

    INLINAIM:
        .ifndef CONFIG_NO_LINE_EDITING
            cmp     #$08 
            beq     L2420
    
    In the original KB9.BIN you can do that with
    poke 9260,8
    poke 9262,241
    

    V2 adaptations to V1.2 by Eduardo Casino
    (after applying all above)
    The start address is moved to $2000 by changing this in header.s

    		.segment "HEADER"
    .ifdef KBD
            jmp     LE68C
            .byte   $00,$13,$56
    .endif
    .ifdef KIM
            jmp     COLD_START
    .endif
    .ifdef AIM65
            jmp     COLD_START
            jmp     RESTART
            .word   AYINT,GIVAYF
    .endif
    .ifdef SYM1
            jmp     PR_WRITTEN_BY
    .endif
    

    Change line 493 init.s

      .ifdef KIM
            .byte   "MOS TECH 6502 BASIC V2.0"
    

    Assemble and link with

    ca65 -D kb9 msbasic.s -o tmp/kb9v2.o -l tmp/kb9v2.lst
    ld65 -C kb9.cfg tmp/kb9v2.o -o tmp/kb9v2.bin -Ln tmp/kb9v2.lbl
    

    KB6 V2
    Change this in defines_kim.s (after applying all above)
    CONFIG_SMALL := 1

    Assemble and link with

    ca65 -D kb9 msbasic.s -o tmp/kb6v2.o -l tmp/kb6v2.lst
    ld65 -C kb9.cfg tmp/kb6v2.o -o tmp/kb6v2.bin -Ln tmp/kb6v2.lbl
    

    See the downloads for the binary files.

    Another MOS TECH BASIC for KIM-1, lower serial number


    Thanks Gerben Voort

    The KIM-1, TIM and Jolt explained

    During the hot summer days, locked up in house because of the heat, I made a deep dive into the KIM-1 and the TIM/Jolt software and hardware.

    50 years of working with a KIM-1:
    The KIM-1 Explained

    The Jolt, one of the first 6502 SBC’s, so nicely reproduced now:
    The TIM/Jolt explained.

    Jolt manuals and documents

    Documents

    Jolt Replica User manual
    Jolt User Newsletter
    DEMON software manual
    (this manual has an alternative listing of the TIM 6530-004 monitor)

    Alter memory or registers

    Sample session

     *  7052 B0 00 FF 00 FF
    .M  0200 00 00 00 00 00 00 00 00
    .:  0200 33 44 55
    .M  0200 33 44 55 00 00 00 00 00
    .R  7052 B0 00 FF 00 FF
    .:  3455 55 55 55 55 55
    .R  3455 55 55 55 55 55
    .M  00F6 55 34 55 55 55 55 55 02
    .M  7000 85 F9 A9 23 D0 55 A9 16
    .:  7000 77?
    .?
    .
    

    The ‘:’ command reacts different upon previous actions:

    • if the previous command was M, the current address types in with M is printed and bytes can be typed in that will be placed at the current PC. The current address is incremented and the next byte can be entered, till maximum 8 are entered 85
    • if the previous command was R the program counter has to be typed and the 5 registers PS A X Y Z (or less by pressing ENTER).
    • after a ‘:’ command, the next ‘:’ will behave the same as following the M command

    Note the current address and the Program Counter are not the same. The GO command requires the Program Counter to be set to the desired address.

    0282   70E0             ;
    0283   70E0             ;  READ AND STORE BYTE.  NO STORE IF SPACE OR RCNT=0.
    0284   70E0             ;
    0285   70E0 20 B3 73    BYTE   JSR RDOB          ; CHAR IN A, CY=0 IF SP
    0286   70E3 90 10              BCC BY3           ; SPACE
    0287   70E5             ;
    0288   70E5 A2 00              LDX #0            ; STORE BYTE
    0289   70E7 81 EE              STA (TMP0,X)
    0290   70E9             ;
    0291   70E9 C1 EE              CMP (TMP0,X)      ; TEST FOR VALID WRITE (RAM)
    0292   70EB F0 05              BEQ BY2
    0293   70ED 68                 PLA               ; ERR, CLEAR JSR ADR IN STACK
    0294   70EE 68                 PLA
    0295   70EF 4C BA 70           JMP ERROPR
    0296   70F2             ;
    0297   70F2 20 7C 72    BY2    JSR CADD          ; INCR CKSUM
    0298   70F5 20 97 73    BY3    JSR INCTMP        ; GO INCR TMPO ADR
    0299   70F8 C6 FE              DEC RCNT
    0300   70FA 60                 RTS
    

    BYTE

    What is happening here?

    • Read a byte (two hex characters) (285)
    • if space skip writing databyte (286, 289)
    • store as binary in current address and increment current address (289)
    • if databyte read back is not equal databyte then error out of caller also (291-295)
    • add to checksum (checksum is part of L command) (297)
    • increment address to store into (298)
    • decrement number of bytes to write (299)
    0272   70D0 A5 EE       PUTP   LDA TMP0          ; MOVE TMP0 TO PCH,PCL
    0273   70D2 85 F6              STA PCL
    0274   70D4 A5 EF              LDA TMP0+1
    0275   70D6 85 F7              STA PCH
    0276   70D8 60                 RTS
    
    0302   70FB A9 F8       SETR   LDA #FLGS         ; SET TO ACCESS REGS
    0303   70FD 85 EE              STA TMP0
    0304   70FF A9 00              LDA #0
    0305   7101 85 EF              STA TMP0+1
    0306   7103 A9 05              LDA #5
    0307   7105 60                 RTS
    

    PUTP
    Move current address in TMP0 to Program Counter PCL

    SETR

    • The address of the saved registers is loaded in TMP0, TMP0+1
    • A is laoded with 5, to let DSPLYM show the registers SP A X Y Z
    0349   713A             ;  ALTER LAST DISPLAYED ITEM (ADR IN TMPC)
    0350   713A             ;
    0351   713A C6 E9       ALTER  DEC PREVC         ; R INDEX = 1
    0352   713C D0 0D              BNE A3
    0353   713E             ;
    0354   713E 20 A4 73           JSR RDOA          ; CY=0 IF SP
    0355   7141 90 03              BCC A2            ; SPACE
    0356   7143 20 D0 70           JSR PUTP          ; ALTER PC
    0357   7146 20 FB 70    A2     JSR SETR          ; ALTER R*S
    0358   7149 D0 05              BNE A4            ; JMP A4 (SETR RETURNS ACC = 5)
    0359   714B 20 9A 72    A3     JSR WROA          ; ALTER M, TYPE ADR
    0360   714E A9 08              LDA #8            ; SET CNT=8
    0361   7150             ;
    0362   7150 85 FE       A4     STA RCNT
    0363   7152 20 77 73    A5     JSR SPACE         ; PRESERVES Y
    0364   7155 20 E0 70           JSR BYTE
    0365   7158 D0 F8              BNE A5
    0366   715A F0 D8       A9     BEQ BEQS1
    
    0345   7134 4C 86 70    BEQS1  JMP START
    

    What is happening here?

    • decrement previous command index(set in START) :=1 R=2 M=3 (351-352)
    • if > 0 then M command, also resets R command mode (358)
    • else previous was R command: read address and put in Program counter (354-358, 362)
    • set current address to registers (FLGS) and 5 bytes to write (357)
    • M command: show address, 8 bytes to write (360-361
    • loop bytes to write
      • print space (363)
      • read and store byte (if not space) (364)
      • if error entering byte then error out via BYTE
      • until all bytes to write are done(365)
    • back to START for next command 366, 345)

    ASCII Conversion Routine

    A very compact and obscure looking routine. But a clever use of the Carry flag underneath!

    0673   7358 18          ASCII  CLC
    0674   7359 69 06              ADC #6
    0675   735B 69 F0              ADC #$F0
    0676   735D 90 02              BCC ASC1
    0677   735F 69 06              ADC #$06
    0678   7361             ;
    0679   7361 69 3A       ASC1   ADC #$3A
    0680   7363 48                 PHA           ; TEST FOR LETTER B IN ADR DURING WBNPF
    0681   7364 C9 42              CMP 'B'       ;
    0682   7366 D0 0A              BNE ASCX
    0683   7368 A5 FD              LDA SAVX
    0684   736A C9 07              CMP #NCMDS
    0685   736C D0 04              BNE ASCX      ; NOT WB CMD
    0686   736E 68                 PLA
    0687   736F A9 20              LDA ' '       ; FOR WB, BLANK 0&#039;S IN ADR
    0688   7371 48                 PHA
    0689   7372 68          ASCX   PLA
    0690   7373 60                 RTS
    

    ASCII
    Convert the low nibble in A to ASCII hex. Call it with the upper nibble containing 0.
    A returned has the ASCII equivalent of the byte value.

    What is happening here?

    • clear the Carry flag (673)
    • A is shifted into a range that later allows the Carry flag to distinguish between numeric digits (0–9) and alphabetic digits (A–F) (674)
    • Adding $F0 causes only values A–F to generate a carry.(675)
      Input Accumulator Carry
      0–9 $F6–$FF 0
      A–F $00–$05 1
    • Carry is clear, the value was 0–9. Otherwise an extra ADC $06 is executed before the final addition.(677)
    • Add $3A to make it ASCII ((679)
    • if the character is ‘B” and the current command is WH BNPF repalce with ‘ ‘
      to suppress illegal characters in the BNPF format

    Note that suppressing ‘F’ is also part of the BNPF format definition. It is not done on the TIM for unknown reasons.

    Examples

    Input = 5

    5 + 6      = 11
    11 + $F0   = $FB   Carry=0
    $FB + $3A  = $35   ASCII '5'
    

    Input = A (10)

    10 + 6     = 16
    16 + $F0   = $00   Carry=1
    00 + 6 + C = $07
    07 + $3A   = $41   ASCII 'A'
    

    Write hex routines

    These routines are called from the command handlers to display data.

    0537   729A             ;  WRITE ADR FROM TMP0 STORES
    0538   729A             ;
    0539   729A A2 01       WROA   LDX #1
    0540   729C D0 0A              BNE WROA1
    0541   729E A2 05       WROA4  LDX #5
    0542   72A0 D0 06              BNE WROA1
    0543   72A2 A2 07       WROA6  LDX #7
    0544   72A4 D0 02              BNE WROA1
    0545   72A6 A2 09       WRPC   LDX #9
    0546   72A8 B5 ED       WROA1  LDA TMP0-1,X
    0547   72AA 48                 PHA
    0548   72AB B5 EE              LDA TMP0,X
    0549   72AD 20 B1 72           JSR WROB
    0550   72B0 68                 PLA
    

    [/code]
    0551 72B1 ;
    0552 72B1 ; WRITE BYTE – A = BYTE
    0553 72B1 ; UNPACK BYTE DATA INTO TWO ASCII CHARS: A=BYTE; X,A=CHARS
    0554 72B1 ;
    0555 72B1 48 WROB PHA
    0556 72B2 4A LSR A
    0557 72B3 4A LSR A
    0558 72B4 4A LSR A
    0559 72B5 4A LSR A
    0560 72B6 20 58 73 JSR ASCII ; CONVERT TO ASCII
    0561 72B9 AA TAX
    0562 72BA 68 PLA
    0563 72BB 29 0F AND #$0F
    0564 72BD 20 58 73 JSR ASCII
    [/code]

    0565   72C0             ;
    0566   72C0             ;  WRITE 2 CHARS - X,A = CHARS
    0567   72C0             ;
    0568   72C0 48          WRTWO  PHA
    0569   72C1 8A                 TXA
    0570   72C2 20 C6 72           JSR WRT
    0571   72C5 68                 PLA
    

    Additions to the EMMA system documentation

    Additions to the EMMA system documentation, thanks Keith Norman

    Emma Hardware Manual
    Eprom Programmer
    Mac User Manual

    CRLF to serial

    
    0104   0000             CRDLY  =227  $E3         ;DELAY FOR CR IN BIT-TIMES
    
    0162   701E A0 01              LDY #1            ; SET TO MEASURE 2 BITS
    0163   7020 84 E3              STY CRDLY         ;INIT OR DELAY TIME PARAMETER
    
    0565   72C0             ;
    0566   72C0             ;  WRITE 2 CHARS - X,A = CHARS
    0567   72C0             ;
    0568   72C0 48          WRTWO  PHA
    0569   72C1 8A                 TXA
    0570   72C2 20 C6 72           JSR WRT
    0571   72C5 68                 PLA
    0572   72C6             ;
    0573   72C6             ;  WRITE SERIAL OUTPUT
    0574   72C6             ;  A = CHAR TO BE OUTPUT
    0575   72C6             ;
    0576   72C6 20 1D 73    WRT    JSR DLY2
     ...
    
    
    0528   728A A2 0D       CRLF   LDX #$0D
    0529   728C A9 0A              LDA #$0A
    0530   728E 20 C0 72           JSR WRTWO
    0531   7291 A6 E3              LDX CRDLY         ;BIT-TIME COUNT FOR DELAY
    0532   7293 20 1D 73    CR1    JSR DLY2          ;DELAY OF ONE BIT-TIME
    0533   7296 CA                 DEX
    0534   7297 D0 FA              BNE CR1
    0535   7299 60                 RTS
    

    WRTWO
    – print characters in X and A, A first via WRT
    – fall through in WRT.

    CRLF
    – print CR and LF via WRTWO
    – wait (CRDLY * serial bit time)

    The wait can be extended by increasing the default of CRDLY of 1, obviously to give a slow teletype a chance to perform a CRLF.

    WH write MOS papertape

    TIM can write MOS Technology papertape format. Not the whole format as defined in the KIM-1 manual, the last end record is not written, as you can see in this example session.

    .WH 7000 7100
    ;18700085F9A923D055A9168D036EA208BDF7739DF7FFCAD0F786EA0F19
    ;18701886E786E8CA9A4C5070E3AD026E4A90FA8E046EAD056E10040BF3
    ;187030E6EAD0F4984D026E2901F0EF8810ECAD046E49FF4A46EA900D9F
    ;187048020980C8F0F685EB580085F968482910F0270A85FED84A860C84
    ;187060FA84FB6885F86869FF85F66869FF85F7BA86FC208A72A6FE10D9
    ;187078A92A20C072A952D016A5F96CF8FFA90085E785E4208A72A90E4A
    ;1870902E20C67220E972A206DD0671D019A5FD85E986FDA97185ED0E1D
    ;1870A8BD0D7185ECE003B0032074736CEC00CA10DFA93F20C672900C5A
    ;1870C0C538A5F0E5EE85E5A5F1E5EFA805E560A5EE85F6A5EF85F71291
    ;1870D860A90095EE95EF6020B3739010A20081EEC1EEF00568684C0D87
    ;1170F0BA70207C72209773C6FE60A9F885EEA9000AB4
    .
    

    The format is similar to what the KIM-1 reads and writes.
    Only the end record is not written by TIM.

    A record is made up of:

    ‘;’ XX YYYY D..D CCCC

    where
    XX is number of databytes
    YYYY is load address
    D..D are XX databytes
    CCCC is checksum, sum of XX YYYY and D.D)

    The Jolt Simulator end Convert 8 bit hex utility know this format as ‘TIM’ file.

    0421   71C2 20 E9 72    WO     JSR RDOC          ; RD 2ND CMD CHAR
    0422   71C5 85 FE              STA TMPC
    0423   71C7 20 77 73           JSR SPACE
    0424   71CA 20 A4 73           JSR RDOA
    0425   71CD 20 87 73           JSR T2T2         ; SA TO TMP2
    0426   71D0 20 77 73           JSR SPACE         ; SPACE BEFORE NEXT ADDRESS
    0427   71D3 20 A4 73           JSR RDOA
    0428   71D6 20 87 73           JSR T2T2          ; SA TO TMP0, EA TO TMP2
    0429   71D9 20 E9 72           JSR RDOC          ; DELAY FOR FINAL CR
    0430   71DC A5 FE              LDA TMPC
    0431   71DE             ;
    0432   71DE C9 48              CMP #'H'
    0433   71E0 D0 59              BNE WB
    

    WO
    What is happening here?

    • character after the W is read INTO tmpc(421-422
    • a space is printed (423)
    • Start address is read into TMP0 (424-425)
    • End address address is read into TMP2 (428-429)
    • Any character is read to end the commandline (429)
    • if second character in TMPC is B then goto WB (write BNPF format) (432-433)
    • else continue with WH0

    Helper subroutines with arguments in TMP0 locations

    
    0707   7387 A2 02       T2T2   LDX #2
    0708   7389 B5 ED       T2T21  LDA TMP0-1,X
    0709   738B 48                 PHA
    0710   738C B5 EF              LDA TMP2-1,X
    0711   738E 95 ED              STA TMP0-1,X
    0712   7390 68                 PLA
    0713   7391 95 EF              STA TMP2-1,X
    0714   7393 CA                 DEX
    0715   7394 D0 F3              BNE T2T21
    0716   7396 60                 RTS
    0717   7397             ;
    0718   7397             ;INCREMENT (TMP0,TMP0+1) BY 1
    0719   7397 E6 EE       INCTMP INC TMP0          ;LOW BYTE
    0720   7399 F0 01              BEQ INCT1
    0721   739B 60                 RTS
    0722   739C             ;
    0723   739C E6 EF       INCT1  INC TMP0+1        ;HIGH BYTE
    0724   739E F0 01              BEQ SETWRP
    0725   73A0 60                 RTS
    0726   73A1             ;
    0727   73A1 E6 E4       SETWRP INC WRAP          ;POINTER HAS WRAPPED AROUND - SET FLAG
    0728   73A3 60                 RTS
    0729   73A4             ;
    
    0262   70C1 38          DCMP   SEC               ; TMP2-TMP0 DOUBLE SUBTRACT
    0263   70C2 A5 F0              LDA TMP2
    0264   70C4 E5 EE              SBC TMP0
    0265   70C6 85 E5              STA DIFF
    0266   70C8 A5 F1              LDA TMP2+1
    0267   70CA E5 EF              SBC TMP0+1
    0268   70CC A8                 TAY               ; RETURN HIGH ORDER PART IN Y
    0269   70CD 05 E5              ORA DIFF          ; OR LO FOR EQU TEST
    0270   70CF 60                 RTS
    
    0278   70D9 A9 00       ZTMP   LDA #0            ; CLEAR REGS
    0279   70DB 95 EE              STA TMP0,X
    0280   70DD 95 EF              STA TMP0+1,X
    0281   70DF 60                 RTS
    
    0518   727C 48          CADD   PHA               ; SAVE A
    0519   727D 18                 CLC
    0520   727E 65 F2              ADC TMP4
    0521   7280 85 F2              STA TMP4
    0522   7282 A5 F3              LDA TMP4+1
    0523   7284 69 00              ADC #0
    0524   7286 85 F3              STA TMP4+1
    0525   7288 68                 PLA               ; RESTORE A
    0526   7289 60                 RTS
    
    

    T2T2
    – exchange TMP0 and TMP2 addresses

    INCTMP

    Increment address in TMP0 (low) and TMP0+1 (high) with 1
    – increment low part of address TMP0
    – if wrapped over then increment high part of address TMP0+1
    – if high part wrapped over to 0000 the set WRAP flag to true

    ZTMP
    -zero TMP0+X an TMP0+1 locations

    CADD
    – add byte in A to 16 bit checksum in TMP4 and TMP4+1, A saved

    DCMP
    – subtract TMP2-TMP0 and leave result in DIFF and Y

    WH

    0434   71E2             ;
    0435   71E2 A6 E4       WH0    LDX WRAP      ;IF ADDR HAS WRAPPED AROUND
    0436   71E4 D0 52              BNE BCCST     ;THEN TERMINATE WRITE OPERATION
    0437   71E6             ;
    0438   71E6 20 8A 72           JSR CRLF
    0439   71E9 A2 18              LDX #24
    0440   71EB 86 FE              STX RCNT      ; RCNT=24
    0441   71ED A2 04              LDX #4        ; CLEAR CKSUM
    0442   71EF 20 D9 70           JSR ZTMP
    0443   71F2             ;
    0444   71F2 A9 3B              LDA #59	     ; write ;
    0445   71F4 20 C6 72           JSR WROC      ; WR RCD MARK
    0446   71F7             ;
    0447   71F7 20 C1 70           JSR DCMP      ; EA-SA (TMP0+2-TMP0) DIFF IN LOC DIFF,+1
    0448   71FA 98                 TYA           ; MS BYTE OF DIFF
    0449   71FB D0 0A              BNE WH1
    0450   71FD A5 E5              LDA DIFF
    0451   71FF C9 17              CMP #23
    0452   7201 B0 04              BCS WH1       ; DIFF GT 24
    0453   7203 85 FE              STA RCNT      ; INCR LAST RCNT
    0454   7205 E6 FE              INC RCNT
    0455   7207 A5 FE       WH1    LDA RCNT
    0456   7209 20 7C 72           JSR CADD      ; ADD TO CKSUM
    0457   720C 20 B1 72           JSR WROB      ; RCC CNT IN A
    0458   720F A5 EF              LDA TMP0+1    ; SA HO
    0459   7211 20 7C 72           JSR CADD
    0460   7214 20 B1 72           JSR WROB
    0461   7217 A5 EE              LDA TMP0      ; SA LO
    0462   7219 20 7C 72           JSR CADD
    0463   721C 20 B1 72           JSR WROB
    0464   721F             ;
    0465   721F A0 00       WH2    LDY #0
    0466   7221 B1 EE              LDA (TMP0),Y
    0467   7223             ;
    0468   7223 20 7C 72           JSR CADD      ; INC CKSUM, PRESERVES A
    0469   7226 20 B1 72           JSR WROB
    0470   7229 20 97 73           JSR INCTMP    ; INC SA
    0471   722C C6 FE              DEC RCNT
    0472   722E D0 EF              BNE WH2       ; LOOP FOR OP TO 24 BYTE
    0473   7230             ;
    0474   7230 20 9E 72           JSR WROA4     ; WRITE CKSUM
    0475   7233             ;
    0476   7233 20 C1 70           JSR DCMP
    0477   7236 B0 AA              BCS WH0       ; LOOP WHILE EA GT OR = SA
    0478   7238 4C 86 70    BCCST  JMP START
    

    What is happening here?
    called from WO so
    – start address in TMP0
    – end address in TMP0+2

    • loop records, print lines
      • back to START if address wraps around 0 (from (435-436, 478)
      • write CRLF (438)
      • record count = 24, hex $18 (439-440)
      • zero checksum low and high in TMP0+3,4 = TMP4 (441-442)
      • print ; (444-445)
      • check if end address – startaddres in DIFF
      • if DIFF > 23 end record line
      • next record count
      • add to checksum ((456)
      • print record count (453-457)
      • print start address 458-463)
      • loop data bytes in this record
        • get databyte (465-466)
        • print databyte and add to checksum (468-469)
        • increment TMP and check wrap (470)
    • until all bytes between start address and end address are dumped