aboutsummaryrefslogtreecommitdiff
path: root/src/turboload.s
diff options
context:
space:
mode:
authorJuan J. Martinez <jjm@usebox.net>2023-11-05 11:22:55 +0000
committerJuan J. Martinez <jjm@usebox.net>2023-11-05 11:31:28 +0000
commit2fbdf974338bde8576efdae40a819a76b2391033 (patch)
tree64d41a37470143f142344f9a439d96de3e7918c2 /src/turboload.s
downloadkitsunes-curse-2fbdf974338bde8576efdae40a819a76b2391033.tar.gz
kitsunes-curse-2fbdf974338bde8576efdae40a819a76b2391033.zip
Initial import of the open source release
Diffstat (limited to 'src/turboload.s')
-rw-r--r--src/turboload.s250
1 files changed, 250 insertions, 0 deletions
diff --git a/src/turboload.s b/src/turboload.s
new file mode 100644
index 0000000..0b6b984
--- /dev/null
+++ b/src/turboload.s
@@ -0,0 +1,250 @@
+;; Modified Topo soft loader
+;;
+;; Multi-colour bars in the border, aka "Spanish" style Spectrum variant loader.
+;;
+;; This loader uses standard Spectrum ROM timings. In fact it is essentially a CPC version of the
+;; Spectrum ROM loader itself.
+;;
+;;
+;; Loader form on cassette:
+;; Pilot tone (min 256 pulses)
+;; Sync pulse
+;; 1 byte sync byte (on spectrum 0 for header and &ff for data)
+;; n bytes of data (defined by DE register)
+;; 1 byte parity checksum
+;;
+;; Original had the following bugs:
+;; 1. bit 7 of R register had to be 1, otherwise it could change ram/rom configuration while loading
+;; 2. flags were not returned, so you didn't know if the data was read incorrectly or not
+;;
+;; It also had extra code that was unnecessary:
+;; 1. turning cassette motor on/off was complex, when in previous instructions they had turned it on anyway.
+;; 2. code for changing border colour presumably on a read error. but didn't seem to be used.
+;;
+;;
+;; Entry conditions:
+;;
+;; IX = start
+;; DE = length (D must not be &ff)
+;; A = sync byte expected
+;;
+;; Interrupts must be disabled
+;;
+;; Exit Conditions:
+;; Alternative register set is corrupted.
+;;
+;; carry clear - load ok
+;; carry set, zero set - time up
+;; carry set, zero reset - if esc pressed
+;;
+;; Use 2CDT to write Spectrum ROM blocks to a CDT. Note that at this time it will only write a sync byte of &ff.
+
+_turboload:
+
+inc d ;; reset the zero flag (D cannot hold &ff)
+ex af,af' ;; A register holds sync byte.
+dec d ;; restore D
+exx
+;; we need B' to be so we can write to gate-array i/o port for colour change when loading
+
+ld bc,#0x7f00+#0x10 ;; Gate-Array + border
+out (c),c ;; select pen index to change while loading (&10 is border)
+ld c,#0x54 ;; set to black
+out (c),c
+exx
+
+ld bc,#0xf40e ;; select AY register 14 (for reading keyboard)
+out (c),c
+
+ld bc,#0xf600+#0xc0+#0x10 ;; "AY write register" and enable tape motor
+out (c),c
+
+ld c,#0x10 ;; "AY inactive" and enable tape motor (register is latched into AY)
+out (c),c
+
+ld bc,#0xf792 ;; set PPI port A to read (so we can read keyboard data)
+out (c),c ;; this will also write 0 to port C and port A on CPC.
+
+ld bc,#0xf600+#0x40+#0x10+#0x8 ;; tape motor enable, "AY read register", select keyboard row 8
+ ;; (keys on this row: z, caps lock, a, tab, q, esc, 2, 1)
+ ;; we are only interested in ESC
+out (c),c
+
+;; make an initial read of cassette input
+ld a,#0xf5 ;; PPI port B
+in a,(#0) ;; read port (tape read etc)
+and #0x80 ;; isolate tape read data
+
+ld c,a
+cp a ;; set the zero flag
+l8107:
+ret nz ;; returns if esc key is pressed (was RET NZ)
+l8108:
+call l817b
+jr nc,l8107
+
+;; the wait is meant to be almost one second
+ld hl,#0x415
+l8110:
+djnz l8110
+dec hl
+ld a,h
+or l
+jr nz,l8110
+;; continue if only two edges are found within this allowed time period
+call l8177
+jr nc,l8107
+
+;; only accept leader signal
+l811c:
+ld b,#0x9c
+call l8177
+jr nc,l8107
+ld a,#0xb9
+cp b
+jr nc,l8108
+inc h
+jr nz,l811c
+
+;; on/off parts of sync pulse
+l812b:
+ld b,#0xc9
+call l817b
+jr nc,l8107
+ld a,b
+cp #0xd1
+jr nc,l812b
+l8137:
+call l817b
+ret nc
+
+ld h,#0 ;; parity matching byte (checksum)
+ld b,#0xb0 ;; timing constant for flag byte and data
+jr l815d
+
+l8145:
+ex af,af' ;; fetch the flags
+jr nz,l814d ;; jump if we are handling first byte
+;; L = data byte read from cassette
+;; store to RAM
+ld 0(ix),l
+jr l8157
+
+l814d:
+rr c ;; keep carry in safe place
+ ;; NOTE: Bit 7 is cassette read previous state
+ ;; We need to do a right shift so that cassette read moves into bit 6,
+ ;; our stored carry then goes into bit 7
+xor l ;; check sync byte is as we expect
+ret nz
+
+ld a,c ;; restore carry flag now
+rla ;; bit 7 goes into carry restoring it, bit 6 goes back to bit 7 to restore tape input value
+ld c,a
+inc de ;; increase counter to compensate for it's decrease
+jr l8159
+
+l8157:
+inc ix ;; increase destination
+l8159:
+dec de ;; decrease counter
+ex af,af' ;; save the flags
+
+ld b,#0xb2 ;; timing constant
+l815d:
+ld l,#1 ;; marker bit (defines number of bits to read, and finally becomes value read)
+l815f:
+call l8177
+ret nc
+
+ld a,#0xc3 ;; compare the length against approx 2,400T states, resetting the carry flag for a '0' and setting it for a '1'
+cp b
+rl l ;; include the new bit in the register
+ld b,#0xb0 ;; set timing constant for next bit
+jr nc,l815f
+
+;; L = data byte read
+;; combine with checksum
+ld a,h
+xor l
+ld h,a
+
+;; DE = count
+ld a,d
+or e
+jr nz,l8145
+
+exx
+ld c,#0x54 ;; make border black
+out (c),c
+exx
+
+ld bc,#0xf782 ;; set PPI port A for output
+out (c),c
+ld bc,#0xf600 ;; tape motor off, "AY inactive"
+out (c),c
+
+;; H = checksum byte
+;; H = 0 means checksum ok
+ld a,h
+cp #1
+;; return with carry flag set if the result is good
+;; carry clear otherwise
+ret
+
+
+;;------------------------------------------------------------
+l8177:
+call l817b ;; in effect call ld-edge-1 twice returning in between if there is an error
+ret nc
+
+;; wait 358T states before entering sampling loop
+l817b:
+ld a,#0x16 ;; [2]
+l817d:
+dec a ;; [1]
+jr nz,l817d ;; ([3]+[1])*&15+[2]
+
+and a
+l8181:
+inc b ;; count each pass
+ret z ;; return carry reset and zero set if time up.
+
+;; read keyboard
+ld a,#0xf4 ;; PPI port A
+in a,(#0) ;; read port and read keyboard through AY register 14
+and #0x04 ;; isolate state of bit 2 (ESC key)
+ ;; bit will be 0 if key is pressed
+xor #0x04 ;; has key been pressed?
+ret nz ;; quit (carry reset, zero reset)
+
+ld a,#0xf5 ;; PPI port B
+in a,(#0) ;; read port (tape read etc)
+xor c
+and #0x80 ;; isolate tape read
+jr z,l8181
+ld a,c ;; effectively toggle bit 7 of C
+cpl ;; which is the tape read state we want to see next
+ld c,a
+
+exx ;; swap to alternative register set so that we can change colour
+;; this sets colour and gives us the multi colour border
+;ld a,r ;; get R register
+;and #0x1f ;; ensure it is in range of colour value
+
+nop
+nop
+nop
+turbo_col:
+and #4
+
+or #0x40 ;; bit 7 = 0, bit 6 = 1
+out (c),a ;; write colour value
+nop ;; this is to ensure the number of cycles is the same
+ ;; compared to the replaced instructions
+ ;; (timings from toposoft loader)
+nop
+exx
+scf
+ret
+