From 2fbdf974338bde8576efdae40a819a76b2391033 Mon Sep 17 00:00:00 2001 From: "Juan J. Martinez" Date: Sun, 5 Nov 2023 11:22:55 +0000 Subject: Initial import of the open source release --- src/turboload.s | 250 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 250 insertions(+) create mode 100644 src/turboload.s (limited to 'src/turboload.s') 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 + -- cgit v1.2.3