diff --git a/demos/tapemon/tapeload.c b/demos/tapemon/tapeload.c new file mode 100644 index 0000000..29d561d --- /dev/null +++ b/demos/tapemon/tapeload.c @@ -0,0 +1,126 @@ +#include +#include + +#pragma start_address(0x3000) + +byte *const HEX1L = 0x24; // End address of dump block +byte *const HEX1H = 0x25; // +byte *const HEX2L = 0x26; // Begin address of dump block +byte *const HEX2H = 0x27; // +byte *const LASTSTATE = 0x29; // Last input state +byte *const NUMPULSES = 0x30; // Number of long pulses to sync at the header +byte *const TAPEIN = 0xC081; // Tape input +byte *const DSP = 0xD012; // display data port + +void load_from_tape(word start_address, word end_address) +{ + *((word *)HEX1L) = end_address; + *((word *)HEX2L) = start_address; + + asm { + // synchronizes with the short header + +syncstart: lda #24 // 24 cycles (3 bytes of $ff) + sta NUMPULSES // count 24 cycles pulses + jsr fullcycle // skip the first full cycle (when looping) +nextsync: ldy #58 // full cycle duration + jsr fullcycle // read a full cycle + bcc syncstart // if short cycle found (c=0), redo from start + dec NUMPULSES // else long cycle found, decrease count + bne nextsync // if not 24 cycles, get next cycle + + // else read bit start and 32 bytes of data normally + // the following routine was copied directly from the ACI ROM + +notstart: ldy #31 // try to detect the much shorter start bit + jsr cmplevel // + bcs notstart // start bit not detected yet! + jsr cmplevel // wait for 2nd phase of start bit + ldy #58 // set threshold value in middle +rdbyte: ldx #8 // receiver 8 bits +rdbit: pha + jsr fullcycle // detect a full cycle + pla + rol // roll new bit into result + ldy #57 // set threshold value in middle + dex // decrement bit counter + bne rdbit // read next bit! + sta ($26,x) // save new byte *** same as "STA (HEX2L,X)" see KickC bug #756 https://gitlab.com/camelot/kickc/-/issues/756 + jsr incaddr // increment address + ldy #53 // compensate threshold with workload + bcc rdbyte // do next byte if not done yet! + bcs restidx // always taken! restore parse index +fullcycle: jsr cmplevel // wait for two level changes +cmplevel: dey // decrement time counter + lda TAPEIN // get tape in data + cmp LASTSTATE // same as before? + beq cmplevel // yes! + sta LASTSTATE // save new data + cpy #128 // compare threshold + rts + // [...] +incaddr: lda HEX2L // compare current address with + cmp HEX1L // end address + lda HEX2H + sbc HEX1H + inc HEX2L // and increment current address + bne nocarry // no carry to msb! + inc HEX2H +nocarry: rts + + // end of read routine "restidx" is the exit point + +restidx: rts + + } +} + +// converts the hexadecimal string argument to 16 bit word +word xtow(byte *str) { + word res=0; + + byte c; + for(byte i=0; c=str[i]; ++i) { + res = res << 4; + if(c<'A') res += (c-'0'); + else res += (c-'A'); + } + return res; +} + +byte keybuf[32]; + +void main() { + woz_puts("\r\rTAPE ALTERNATE LOAD\r"); + + word start_address; + word end_address; + + woz_puts("\rSTART ADDRESS: "); apple1_input_line(keybuf, 32); start_address = xtow(keybuf); + woz_puts("\rEND ADDRESS: "); apple1_input_line(keybuf, 32); end_address = xtow(keybuf); + + end_address += 1; // include checksum byte + + while(1) { + woz_puts("\r\rPRESS PLAY ON TAPE\r\r"); + + load_from_tape(start_address, end_address); + + // calculate checksum + byte chk = 0xFF; + for(byte *t=start_address; t #include -byte *const HEX1L = 0x24; // End address of dump block -byte *const HEX1H = 0x25; // -byte *const HEX2L = 0x26; // Begin address of dump block -byte *const HEX2H = 0x27; // -byte *const LASTSTATE = 0x29; // Last input state -byte *const NUMPULSES = 0x30; // Number of long pulses to sync at the header -byte *const TAPEIN = 0xC081; // Tape input -byte *const DSP = 0xD012; // display data port +__address(0x24) word ENDADDR; // End address of dump block +__address(0x26) word STARTADDR; // Begin address of dump block +__address(0x29) byte LASTSTATE; // Last input state +__address(0x30) byte NUMPULSES; // Number of long pulses to sync at the header +__address(0xC081) byte TAPEIN; // Tape input +__address(0xD012) byte DSP; // display data port -#define PACKETSIZE 64 +/* +#pragma zp_reserve(0x24) +#pragma zp_reserve(0x25) +#pragma zp_reserve(0x26) +#pragma zp_reserve(0x27) +#pragma zp_reserve(0x29) +#pragma zp_reserve(0x30) -const byte *RX_BUFFER = 0x200; -const byte *RX_BUFFER_END = (0x200+PACKETSIZE-1); +__export byte *const ENDADDR = (byte *) 0x24; // End address of dump block +__export byte *const STARTADDR = (byte *) 0x26; // Begin address of dump block +__export byte *const LASTSTATE = (byte *) 0x29; // Last input state +__export byte *const NUMPULSES = (byte *) 0x30; // Number of long pulses to sync at the header +__export byte *const TAPEIN = (byte *) 0xC081; // Tape input +__export byte *const DSP = (byte *) 0xD012; // display data port +*/ + +byte PACKETSIZE; + +byte reference_packet[256]; +byte *vmeter = "0123456789ABCDEF"; + +//byte *const RX_BUFFER = (byte *) 0x060c; //0x4200; +const byte RX_BUFFER[256]; // TODO ?????????????????????????????????????????? void read_packet() { + word RX_BUFFER_END = (word) RX_BUFFER + (word) PACKETSIZE - 1; + + ENDADDR = (word) RX_BUFFER_END; + STARTADDR = (word) RX_BUFFER; + + /* + *((word *)ENDADDR) = (word) RX_BUFFER_END; + *((word *)STARTADDR) = (word) RX_BUFFER; + */ + + /* + woz_putc('\r'); + woz_print_hex(*(STARTADDR+1)); woz_print_hex(*(STARTADDR)); + woz_putc('.'); + woz_print_hex(*(ENDADDR+1)); woz_print_hex(*(ENDADDR)); + */ + asm { - // set READ buffer pointers to $0200-$021F (32 characters) - lda #RX_BUFFER_END - lda HEX1H - - lda #RX_BUFFER - lda HEX2H - // synchronizes with the short header syncstart: lda #24 // 24 cycles (3 bytes of $ff) @@ -56,7 +79,7 @@ rdbit: pha ldy #57 // set threshold value in middle dex // decrement bit counter bne rdbit // read next bit! - sta ($26,x) // save new byte *** same as "STA (HEX2L,X)" see KickC bug #756 https://gitlab.com/camelot/kickc/-/issues/756 + sta (STARTADDR,x) // save new byte jsr incaddr // increment address ldy #53 // compensate threshold with workload bcc rdbyte // do next byte if not done yet! @@ -70,14 +93,14 @@ cmplevel: dey // decrement time counter cpy #128 // compare threshold rts // [...] -incaddr: lda HEX2L // compare current address with - cmp HEX1L // end address - lda HEX2H - sbc HEX1H - inc HEX2L // and increment current address - bne nocarry // no carry to msb! - inc HEX2H -nocarry: rts +incaddr: lda STARTADDR + sbc >ENDADDR // carry set if STARTADDR = ENDADDR + inc STARTADDR +no_inc_hi: rts // end of read routine "restidx" is the exit point @@ -86,11 +109,10 @@ restidx: rts } } -byte reference_packet[PACKETSIZE]; -byte *vmeter = "0123456789ABCDEF"; - void decode_packets() { + woz_puts("\rPACKET DECODER MONITOR\r"); + // fill the reference packet with the known values for(byte t=0;t>2]); + else { + if(PACKETSIZE == 32) woz_putc(vmeter[i>>1]); + if(PACKETSIZE == 64) woz_putc(vmeter[i>>2]); + if(PACKETSIZE == 128) woz_putc(vmeter[i>>3]); + if(PACKETSIZE == 255) woz_putc(vmeter[i>>4]); + } + + /* + if(apple1_readkey()=='D') { + woz_puts("\r\r"); + for(i=0;i 32,64,128,255 BYTES PACKETS\r" + "T SIMPLE TOGGLE MONITOR\r" + "D DUTY CYLE MONITOR\r\r" + "X EXIT\r\r" + ); + + byte key = apple1_getkey(); + if(key == '1') { PACKETSIZE = 32; decode_packets(); } + if(key == '2') { PACKETSIZE = 64; decode_packets(); } + if(key == '3') { PACKETSIZE = 128; decode_packets(); } + if(key == '4') { PACKETSIZE = 255; decode_packets(); } + if(key == 'T') simple_toggle_monitor(); + if(key == 'D') duty_cycle_monitor(); + if(key == 'X') woz_mon(); } }