.feature labels_without_colons .feature leading_dot_in_identifiers .feature c_comments .P02 ; normal 6502 .macro ADR val .addr val .endmacro .macro BLT val BCC val .endmacro .macro BGE val BCS val .endmacro ; Force APPLE 'text' to have high bit on; Will display as NORMAL characters .macro ASC text .repeat .strlen(text), I .byte .strat(text, I) | $80 .endrep .endmacro a_cr = $0d ; Carriage return. F8ROM_YXHEX = $F940 F8ROM_AXHEX = $F941 F8ROM_XHEX = $F944 ; print X register in hex -- kills X,A F8ROM_AHEX = $FDDA ; print A register in hex F8ROM_INIT = $FB2F F8ROM_HOME = $FC58 ; Kills A,Y F8ROM_CROUT = $FC62 ; carriage return out F8ROM_MONWAIT = $FCA8 ; wait for (A*A*2.5 + A*13.5 + 7) * 0.980 usec F8ROM_COUT = $FDED ; Load A with character to print F8ROM_RDKEY = $FD0C WRVEC = $03D0 ; warm re-entry point PHSOFF = $C080 PHSON = $C081 DISKOFF = $C088 DISKON = $C089 DRIVEA = $C08A DISK_LATCHR = $C08C DISK_LATCHW = $C08D DISK_MODER = $C08E DISK_MODEW = $C08F ;; Zero-page addresses used ;; 00/01: storage pointer for loops in nybble code ;; 02/03: second storage pointer for loops in nybble code ;; 04/05: lookup table indexer for the _trans table ;; FA/FB: DST pointer for memset ;; FC/FD: pointer to sector buffer ;; FF: scratch, used when erasing a track ZP_STORPTR = $00 ZP_STOR2 = $02 ZP_TRANSP = $04 DST = $FA ZP_SECTP = $FC ZP_SCRATCH = $FF .segment "CODE" START JMP Entry Entry JSR F8ROM_INIT JSR F8ROM_HOME LDY #>STARTMSG LDA #SECDATA STA ZP_SECTP+1 LDA #TRANS62 ; set up ZP_TRANSP to point at TRANS62 STA ZP_TRANSP+1 ; (a 64-byte lookup table) LDA #NYBDATA STA DST+1 LDA #ENDMSG ; All done, tell the user LDA #SECDATA JSR F8ROM_AHEX LDA #SECDATAMSG LDA #NYBDATA JSR F8ROM_AHEX LDA #NYBDATAMSG LDA #WPMSG LDA #WRITEMSG LDA #NYBDATA ; set up ZP_STORPTR to the start of NYBDATA STA ZP_STORPTR+1 LDA #NYBDATA STA ZP_STORPTR+1 ; high address LDA #SECTORMSG LDA #SECTORMSG2 LDA # 0x100 INY ; bytes STY ZP_STOR2+1 ;; Clear output buffer 0x157 bytes LDY #>SECTORMSG3 LDA #SECTORMSG4 LDA #= 0; idx6--) LDA #$01 STA IDX6 STA IDX6+1 ; IDX6 = 0x0101 @WorkLoopA LDY IDX6 ; val6 = input[idx6 & 0xFF] LDA (ZP_SECTP),Y STA VAL6 LDY IDX2 ; val2 = output[idx2]; LDA (ZP_STORPTR),Y STA VAL2 ;; val2 = (val2 << 1) | (val6 & 1); val6 >>= 1; LSR VAL6+1 ROR VAL6 ; val6 >>= 1, and C = old (val6&1) LDA VAL2 ROL ; A = (val2 << 1) | C STA VAL2 ; val2 = all that jazz ;; another round of the same LSR VAL6+1 ROR VAL6 ; val6 >>= 1, and C = old (val6&1) LDA VAL2 ROL ; A = (val2 << 1) | C STA VAL2 ; val2 = all that jazz LDY IDX2 ; output[idx2] = val2 LDA VAL2 STA (ZP_STORPTR),Y ;; if (idx6 < 0x100) { output[0x56+idx6] = val6; } LDA IDX6+1 CMP #01 BEQ @decidx2 LDA #$56 CLC ADC IDX6 BCC @storeLT100 ;; we need to store in ZP_STOR2 (the result overflowed) TAY ; Y = idx6 + 0x56 and is >= 0x100 LDA VAL6 STA (ZP_STOR2),Y JMP @decidx2 @storeLT100 TAY ; Y = idx6 + 0x56 and is < 0x100 LDA VAL6 STA (ZP_STORPTR),Y JMP @decidx2 @decidx2 ;; if (--idx2 < 0) { idx2 = 0x55; } ;; IDX2 never exceeds $55, so we can test using DEC and BMI/BPL DEC IDX2 BPL @dontresetidx2 ;; ... high bit is set, so we underflowed; reset IDX2 back to $55 LDA #$55 STA IDX2 @dontresetidx2 ;; End of WorkLoopA: 16-bit decrement idx6, and loop to @WorkLoopA ;; if it is >= 0 LDA IDX6 ; sets Z if it's zero BNE @simpledeclo ; if not zero, just decrement and continue LDA IDX6+1 ; low was zero, so repeat w/ high BEQ @DoneWorkloopA ; if high is also zero we're done DEC IDX6+1 @simpledeclo DEC IDX6 ;; continue loop JMP @WorkLoopA ;; Both IDX6 and IDX6+1 reached 0, so we are done the loop @DoneWorkloopA ;; Mask out the "extra" 2-bit data: ;; output[0x54] &= 0x0F; output[0x55] &= 0x0F; LDY #$54 LDA (ZP_STORPTR),Y AND #$0F STA (ZP_STORPTR),Y INY AND #$0F STA (ZP_STORPTR),Y ;; Loop over the data one more time to construct the actual output ;; and compute the checksum ;; Checksum is initialized to 0 above ;; for (int idx6=0; idx6<0x156; idx6++) LDY #>SECTORMSG5 LDA #= 0x56 - done loop JMP @WorkLoopB @incHigh INC IDX6+1 JMP @f @setCksum ;; output[342] = _trans[cksum] LDY CKSUM ; A = _trans[cksum] LDA (ZP_TRANSP),Y LDY #$56 STA (ZP_STOR2),Y ; output[0x100 + Y] = A ;; Add 0x157 to ZP_STORPTR (number of bytes we added to the buffer) INC ZP_STORPTR+1 ; add 0x100 LDA ZP_STORPTR CLC ADC #$57 BCC @nocarry INC ZP_STORPTR+1 @nocarry STA ZP_STORPTR @done RTS ;; set CNT, CNT+1, DST, DST+1, VALUE before calling memset @a LDY #0 LDA CNT ORA CNT+1 BEQ @fin LDA VALUE STA (DST),y INC DST BNE @b INC DST+1 @b DEC CNT LDA CNT CMP #$FF BNE @c DEC CNT+1 @c SEC BCS @a @fin RTS ;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Start of data segment ;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; STARTMSG ASC "Insert a blank floppy in s6d1 and press a key..." .byte $8D, $00 SECTORMSG ASC " : Making this sector of data..." .byte $00 SECTORMSG2 ASC "Building sector data chunk..." .byte $00 SECTORMSG3 ASC "Clearing output buffer..." .byte $00 SECTORMSG4 ASC "Constructing 6-and-2 data..." .byte $00 SECTORMSG5 ASC "Building checksum..." .byte $00 ENDMSG ASC "Test complete, no errors found." .byte $00 SECDATAMSG ASC " : sector data buffer" .byte $00 NYBDATAMSG ASC " : nybble data buffer" .byte $00 WPMSG ASC "Disk is write protected; aborting" .byte $00 WRITEMSG ASC "Writing fresh track..." .byte $00 ;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; variable space ;; ;; Many/all of these could be zero-page and not here. ;; They also don't need to be initialized to zero so they ;; could just be memory locations instead of byte defines. ;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; WAITCTR .byte $00, $00 CURHALFTRK .byte $00 DSTHALFTRK .byte $00 NYBCOUNT .byte $00 TARGETTRK .byte $00 TARGETSEC .byte $00 SECCOUNT .byte $00 IDX6 .byte $00, $00 IDX2 .byte $00 CKSUM .byte $00 VAL2 .byte $00 VAL6 .byte $00 CNT .byte $00, $00 VALUE .byte $00 ;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Block data area ;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; .align 256 ;; 6-and-2 DOS3.3 translation table (here so it doesn't ;; cross a page boundary) TRANS62 .byte $96, $97, $9a, $9b, $9d, $9e, $9f, $a6 .byte $a7, $ab, $ac, $ad, $ae, $af, $b2, $b3 .byte $b4, $b5, $b6, $b7, $b9, $ba, $bb, $bc .byte $bd, $be, $bf, $cb, $cd, $ce, $cf, $d3 .byte $d6, $d7, $d9, $da, $db, $dc, $dd, $de .byte $df, $e5, $e6, $e7, $e9, $ea, $eb, $ec .byte $ed, $ee, $ef, $f2, $f3, $f4, $f5, $f6 .byte $f7, $f9, $fa, $fb, $fc, $fd, $fe, $ff ;; scratch space for a sector of data ;; FIXME: is there an easier way to define a block so that ;; ca65 honors it and shows it properly in the lst? .align 256 SECDATA .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 ;; nybblized data that we precalculate ;; and then write to the track; or that we read in from the track ;; and store here .align 256 NYBDATA .byte $00