REM >A.DTXASM
REM Assembly part of DTX
REM BBC tape to serial transfer program
REM by Greg Cook 29/Jul/2002
REM Non-Tube compatible

IFPAGE<&1B00THENSTOP

REM Constants
sizeof_near_ptr%=2:REM 6502 vector
sizeof_far_ptr%=4:REM OSWORD 5/6 and OSFILE address

REM Assembly options
code%=&1900
firstpass%=0
secondpass%=3

REM Avoiding OSWORD 5/6 where we can
sizeof_ptr%=sizeof_near_ptr%

REM 6502 can only address 64K
sizeof_size_t%=2 

REM Static global zero page locations
zp_base=&70
block=zp_base
ptr=block+sizeof_near_ptr%
lgt=ptr+sizeof_ptr%
crc=lgt+sizeof_size_t%

REM Local functions and I/O handlers
FOR pass%=firstpass% TO secondpass% STEP secondpass%-firstpass%
P%=code%
PROCdt_init
PROCdt_event
PROCdt_wrch
PROCcrc16
PROClibmos
NEXT

OSCLI "SAVE M.DTX "+STR$~(code%)+" "+STR$~(P%)+" "+STR$~(code%OR&FFFF0000)+" "+STR$~(dt_init OR&FFFF0000)

PRINT "In DTX, re-type second line to read:"'"J%=";bfl;":D%=";crc16;":IFPAGE<";P%+255A.NOT255;"STOP"'"then save the modified DTX."

END

DEF PROCcrc16
LOCAL off_ptr%, off_lgt%, off_crc%

REM Order of parameters in block
off_ptr%=0
off_lgt%=off_ptr%+sizeof_ptr%
off_crc%=off_lgt%+sizeof_size_t%

[OPT pass%
.crc16
CLD

STX block:STY block+1

\ copy length
LDX #sizeof_size_t%-1:LDY #off_lgt%+sizeof_size_t%-1
.cp_lgt_1:LDA (block),Y
.cp_lgt_1b:STA lgt,X:DEY:DEX:BPL cp_lgt_1

\ copy pointer and old crc
.cp_ptr_1:LDX #sizeof_ptr%-1:LDY #off_ptr%+sizeof_ptr%-1
.cp_ptr_1b:LDA (block),Y:STA ptr,X:DEY:DEX:BPL cp_ptr_1b

LDY #off_crc%+1
LDA (block),Y:STA crc+1:DEY:LDA (block),Y:STA crc

\ dec & test length
.byteloop LDX #0:CLC
.dec_lgt_1:LDA lgt,X:SBC #0:STA lgt,X:BCS getbyte
INX:CPX #sizeof_size_t%:BMI dec_lgt_1

\ length ran out, return crc to block and exit
LDY #off_crc%+1
LDA crc+1:STA (block),Y:DEY:LDA crc:STA (block),Y
.crc_exit LDX block:LDY block+1
RTS

\ get next byte (OSWORD 5 only reads I/O memory?)
.getbyte LDY #0:LDA (ptr),Y
\ LDX #ptr MOD256;LDY #ptr DIV256;LDA #5;JSR OSword;LDX #sizeof_far_ptr%;LDA ptr,X

\ swap bytes and xor new one into LSB
LDX crc:EOR crc+1:STA crc:STX crc+1

\ loopless shift register emulation
LSR A:LSR A:LSR A:LSR A:EOR crc:STA crc
AND #&F0:LSR A:LSR A:LSR A:EOR crc+1:STA crc+1
LDA crc:ASL A:ASL A:ASL A:TAX:ASL A:ASL A:EOR crc:STA crc
TXA:ROL A:EOR crc+1:STA crc+1

\inc pointer, loop
LDX #0
.inc_ptr_1:INC ptr,X:BNE byteloop
INX:CPX #sizeof_ptr%:BMI inc_ptr_1
BPL byteloop
]

ENDPROC

DEF PROCdt_init
[OPT pass%

.dt_init
\ Install wrch wrapper
LDX wrchV:LDY wrchV+1
STX old_wrchV:STY old_wrchV+1
LDX #dt_wrch MOD256:LDY #dt_wrch DIV256
STX wrchV:STY wrchV+1

\ Install event handler
LDX #dt_event MOD256: LDY #dt_event DIV256
STX evntV:STY evntV+1

\ Enable field sync event and return
LDA #14:LDX #4:JMP OSbyte
]

ENDPROC

DEF PROCdt_event
[OPT pass%

.dt_event
\ Save state
PHP:PHA

\ Clear locked bit in block flag
LDA &3CA:PHA:AND #&FE:STA &3CA

\ Record any 1s written
PLA:AND #&1:ORA bfl:STA bfl

\ Cracks - don't enable except for the games shown

\ Manic Miner - clear high byte of block number
\ LDA #0
\ STA &3C7

\ Eagle's Wing - hide changing character of filename
\ LDA &3B9
\ STA &3D9

\ Compare block numbers
\ A new block validates the last block's flag
LDA &B4:CMP bno:BEQ sameblock:STA bno
LDA bfl:ASL A:ORA bfl:STA bfl

.sameblock
\ Restore state and return
PLA:PLP
RTS
]

bfl=P%:P%=P%+1
bno=P%:P%=P%+1

ENDPROC

DEF PROCdt_wrch
[OPT pass%

.dt_wrch
\ Test for ? preceded by CR,
\ indicating tape error (even if *OPT 1,0)
\ Ignore LF
CMP #&0A:BNE dt_wrch_done
CMP #&0D:BNE write_buffer_and_cascade
.newl
LDA cbf:CMP #ASC("?"):BNE newl_done
LDA bfl:AND #&FE:STA bfl
.newl_done
LDA #&0D
.write_buffer_and_cascade
STA cbf
.dt_wrch_done
\ Continue with original handler
JMP (old_wrchV)
]

cbf=P%:P%=P%+1
old_wrchV=P%:P%=P%+sizeof_near_ptr%

ENDPROC

DEF PROClibmos
REM Documented and undocumented OS code entry points and vectors

REM Standard routines, OS 1.20, OS 2.00, all?
OScli=&FFF7:OSbyte=&FFF4:OSword=&FFF1:OSwrch=&FFEE
OSnewl=&FFE7:OSasci=&FFE3:OSrdch=&FFE0:OSfile=&FFDD
OSargs=&FFDA:OSbget=&FFD7:OSbput=&FFD4:OSgbpb=&FFD1
OSfind=&FFCE

REM Standard vectors, 0S 1.20, OS 2.00, all?
userV=&200:brkV=&202:irq1V=&204:irq2V=&206
cliV=&208:byteV=&20A:wordV=&20C:wrchV=&20E
rdchV=&210:fileV=&212:argsV=&214:bgetV=&216
bputV=&218:gbpbV=&21A:findV=&21C:fscV=&21E
evntV=&220:uptV=&222

REM additional routines, OS 2.00
OSrdsc=&FFB9:OSwrsc=&FFB3

ENDPROC

DEF PROClibmos_undoc

REM Undocumented locations applications have been seen to use
REM Use with caution!
GSread=&FFC5:GSinit=&FFC2:OSrdrm=&FFB9

REM undocumented locations internal to the OS
REM Use with extreme caution!
NVwrch=&FFCB:NVrdch=&FFC8:OSeven=&FFBF:NVvdu=&FFBC
netV=&224:vduV=&226:keyV=&228:insV=&22A
remV=&22C:cnpV=&22E:ind1V=&230:ind2V=&232
ind3V=&234

ENDPROC
