#include "flossiec.h" #include #include #include #include #ifndef FLOSSIEC_NODISPLAY #define FLOSSIEC_NODISPLAY 0 #endif #ifndef FLOSSIEC_NOIRQ #define FLOSSIEC_NOIRQ 0 #endif #ifndef FLOSSIEC_BORDER #define FLOSSIEC_BORDER 0 #endif #define VIA_ATNIN 0x80 #define VIA_ATNOUT 0x10 #define VIA_CLKOUT 0x08 #define VIA_DATAOUT 0x02 #define VIA_CLKIN 0x04 #define VIA_DATAIN 0x01 #define PORTB1 0x1800 #define PORTB2 0x1c00 #define WR 0x1d #ifdef FLOSSIEC_CODE #pragma code(FLOSSIEC_CODE) #endif #ifdef FLOSSIEC_BSS #pragma bss(FLOSSIEC_BSS) #endif __asm diskcode { nop nop lda #VIA_CLKOUT sta PORTB1 lda 0x0202 sta 0x0c lda 0x0203 sta 0x0d lda #$80 sta 0x03 ldx #0 l0: txa lsr lsr lsr lsr sta 0x0700,x inx bne l0 lr: lda 0x03 bmi lr sei ldx #0 l2: lda #0 sta PORTB1 lda 0x0600, x tay and #0x0f ora #VIA_DATAIN l1: bit PORTB1 bne l1 l3: sta PORTB1 tya asl and #0x0a sta PORTB1 lda 0x0700,y nop sta PORTB1 asl nop and #0x0a sta PORTB1 inx bne l2 lda #VIA_CLKOUT sta PORTB1 lda 0x0600 beq w1 sta 0x0c lda 0x0601 sta 0x0d lda #$80 sta 0x03 cli bne lr w1: sta PORTB1 cli rts } #define CIA2B_ATNOUT 0x08 #define CIA2B_CLKOUT 0x10 #define CIA2B_DATAOUT 0x20 #define CIA2B_CLKIN 0x40 #define CIA2B_DATAIN 0x80 #define CIA2PRA 0xdd00 static char remap[256]; static char rbuffer[256]; static char xbuffer[256]; static char flpos; static char xcmd; static char xi, xj; static char fldrive; static char flvxor; __noinline void fl_read_buf(void) { __asm { #if FLOSSIEC_NOIRQ php sei #endif lda CIA2PRA and #~CIA2B_CLKOUT sta accu sta CIA2PRA and #~CIA2B_DATAOUT sta accu + 1 l0: lda CIA2PRA and #CIA2B_CLKIN beq l0 #if !FLOSSIEC_NOIRQ php pla and #$04 beq iq #endif ldy #0 sec l1: ldx accu + 1 #if !FLOSSIEC_NODISPLAY l2: lda 0xd012 sbc #50 bcc w1 and #7 beq l2 #endif w1: stx CIA2PRA #if FLOSSIEC_BORDER inc 0xd020 #else nop nop nop #endif ldx accu nop lda CIA2PRA lsr lsr nop eor CIA2PRA lsr lsr nop eor CIA2PRA lsr lsr sec eor CIA2PRA stx CIA2PRA sta rbuffer, y iny bne l1 jmp done #if !FLOSSIEC_NOIRQ iq: ldy #0 sec l1i: ldx accu + 1 l2i: cli sei #if !FLOSSIEC_NODISPLAY lda 0xd012 sbc #50 bcc w1i and #7 beq l2i w1i: #endif stx CIA2PRA #if FLOSSIEC_BORDER inc 0xd020 #else nop nop nop #endif ldx accu nop lda CIA2PRA lsr lsr nop eor CIA2PRA lsr lsr nop eor CIA2PRA lsr lsr sec eor CIA2PRA stx CIA2PRA sta rbuffer, y iny bne l1i cli #endif done: #if FLOSSIEC_NOIRQ plp #endif } } inline char flossiec_get(void) { if (!flpos) { fl_read_buf(); flpos = 2; } return remap[rbuffer[flpos++]]; } void flossiec_decompress(void) { char i = 0, j = xj, cmd = xcmd; xi = 0; for(;;) { if (cmd & 0x80) { if (i < cmd) { char t = i - cmd; do { char ch = xbuffer[j++]; xbuffer[i++] = ch; } while (i != t); cmd = 0; } else { cmd -= i; do { char ch = xbuffer[j++]; xbuffer[i++] = ch; } while (i); break; } } else { char ch = flossiec_get(); if (cmd) { xbuffer[i++] = ch; cmd--; if (!i) break; } else { cmd = ch; if (!cmd) break; if (cmd & 0x80) { cmd ^= 0x7f; cmd++; j = i - flossiec_get(); } } } } xj = j; xcmd = cmd; } inline char flossiec_get_lzo(void) { if (!xi) flossiec_decompress(); return xbuffer[xi++]; } inline bool flossiec_eof(void) { return !remap[rbuffer[0]] && flpos >= remap[rbuffer[1]]; } char * flossiec_read(char * dp, unsigned size) { while (size) { *dp++ = flossiec_get(); size--; } return dp; } char * flossiec_read_lzo(char * dp, unsigned size) { char i = xi; dp -= i; size += i; while (size) { if (!i) flossiec_decompress(); if (size >= 256) { do { dp[i] = xbuffer[i]; i++; } while (i); dp += 256; size -= 256; } else { do { dp[i] = xbuffer[i]; i++; } while (i != (char)size); dp += i; break; } } xi = i; return dp; } static void vxorcheck(void) { char vxor = cia2.pra & 7; vxor ^= vxor >> 2; vxor ^= 0xff; if (vxor != flvxor) { flvxor = vxor; for(int i=0; i<256; i++) { char j = i ^ vxor; char d = ((j & 0x11) << 3) | (j & 0x66) | ((j & 0x88) >> 3); remap[i] = d; } } } bool flossiec_init(char drive) { fldrive = drive; flvxor = 0; iec_open(drive, 2, "#2"); iec_listen(drive, 2); for(char j=0; j<127; j++) iec_write(((char *)diskcode)[j]); iec_unlisten(); iec_close(drive, 2); iec_open(drive, 15, ""); return true; } void flossiec_shutdown(void) { iec_close(fldrive, 15); } bool flossiec_open(char track, char sector) { iec_listen(fldrive, 15); iec_write(P'U'); iec_write(P'4'); iec_write(track); iec_write(sector); iec_unlisten(); cia2.pra |= CIA2B_DATAOUT; #if FLOSSIEC_NODISPLAY vic.ctrl1 &= ~VIC_CTRL1_DEN; #endif vic_waitFrame(); vxorcheck(); vic_waitFrame(); flpos = 0; xi = 0; return true; } void flossiec_close(void) { cia2.pra |= CIA2B_DATAOUT; #if FLOSSIEC_NODISPLAY vic.ctrl1 |= VIC_CTRL1_DEN; #endif } bool flosskio_init(char drive) { fldrive = drive; flvxor = 0; krnio_setnam_n("#2", 2); krnio_open(2, drive, 2); krnio_write(2, (char *)diskcode, 128); krnio_close(2); krnio_setnam_n(nullptr, 0); krnio_open(15, drive, 15); return true; } void flosskio_shutdown(void) { krnio_close(15); } bool flosskio_open(char track, char sector) { krnio_chkout(15); krnio_chrout(P'U'); krnio_chrout(P'4'); krnio_chrout(track); krnio_chrout(sector); krnio_clrchn(); cia2.pra |= CIA2B_DATAOUT; #if FLOSSIEC_NODISPLAY vic.ctrl1 &= ~VIC_CTRL1_DEN; #endif vic_waitFrame(); vxorcheck(); vic_waitFrame(); flpos = 0; xi = 0; return true; } void flosskio_close(void) { cia2.pra |= CIA2B_DATAOUT; #if FLOSSIEC_NODISPLAY vic.ctrl1 |= VIC_CTRL1_DEN; #endif } static bool mapdir(const char * fnames, floss_blk * blks) { do { fl_read_buf(); char si = 0; do { if (remap[rbuffer[si + 2]] == 0x82) { char fname[17]; char j = 0; while (j < 16 && remap[rbuffer[si + j + 5]] != 0xa0) { fname[j] = remap[rbuffer[si + j + 5]]; j++; } fname[j] = 0; char sj = 0; char k = 0; while (fnames[sj]) { j = 0; while (fname[j] && fname[j] == fnames[sj]) { j++; sj++; } if (!fname[j] && (!fnames[sj] || fnames[sj] == ',')) { __assume(k < 128); blks[k].track = remap[rbuffer[si + 3]]; blks[k].sector = remap[rbuffer[si + 4]]; break; } while (fnames[sj] && fnames[sj++] != ',') ; k++; } } si += 32; } while (si); } while (remap[rbuffer[0]]); return true; } bool flosskio_mapdir(const char * fnames, floss_blk * blks) { if (flosskio_open(18, 1)) { mapdir(fnames, blks); flosskio_close(); return true; } return false; } bool flossiec_mapdir(const char * fnames, floss_blk * blks) { if (flossiec_open(18, 1)) { mapdir(fnames, blks); flossiec_close(); return true; } return false; }