CSRCS = devlpr.c devtty.c devfd.c devfd3.c devhd.c devgfx.c
-CSRCS += devices.c main.c
+CSRCS += devices.c main.c devstringy.c
DISCARD_CSRCS = discard.c devhd_discard.c
ASRCS = trs80.s trs80-bank.s crt0.s vtsupport.s
-ASRCS += tricks.s commonmem.s floppy.s floppy3.s
+ASRCS += tricks.s commonmem.s floppy.s floppy3.s stringy.s
COBJS = $(CSRCS:.c=.rel)
AOBJS = $(ASRCS:.s=.rel)
max_mode = 1;
displaymap[1] = 1;
} else {
- uint8_t *fb = 0x3C00;
+ uint8_t *fb = (uint8_t *)0x3C00;
uint8_t c = *fb;
*fb = 128;
ioctrl = 0xB2;
#include <devtty.h>
#include <devgfx.h>
#include <devfd3.h>
+#include <devstringy.h>
#include <trs80.h>
struct devsw dev_tab[] = /* The device driver switch table */
{ lpr_open, lpr_close, no_rdwr, lpr_write, no_ioctl },
/* 4: /dev/mem etc System devices (one offs) */
{ no_open, no_close, sys_read, sys_write, sys_ioctl },
+ /* 5: reserved */
+ { nxio_open, no_close, no_rdwr, no_rdwr, no_ioctl },
+ /* 6: reserved */
+ { nxio_open, no_close, no_rdwr, no_rdwr, no_ioctl },
+ /* 7: reserved */
+ { nxio_open, no_close, no_rdwr, no_rdwr, no_ioctl },
+ /* 8: tape (for now - may move to 5 if lots of boxes have tape) */
+ { tape_open, tape_close, tape_read, tape_write, tape_ioctl },
};
bool validdev(uint16_t dev)
dev_tab[1].dev_open = fd3_open;
dev_tab[1].dev_read = fd3_read;
dev_tab[1].dev_write = fd3_write;
+ dev_tab[8].dev_open = nxio_open;
}
}
--- /dev/null
+#include <kernel.h>
+#include <version.h>
+#include <tape.h>
+#include <kdata.h>
+#include <devlpr.h>
+#include <printf.h>
+#include <devstringy.h>
+
+/*
+ * Stringy tape wrapper. Note that the asm code uses the ROM which
+ * also uses some values in 0x40xx (40B1 and 401A in particular)
+ */
+static uint8_t fileid = 255;
+static uint8_t mode;
+static uint8_t inpos = 0; /* in position */
+static uint8_t inio = 0;
+static int busy = 0;
+uint8_t tape_err;
+
+static int tape_error(void)
+{
+ uint8_t a = tape_err;
+ tape_err = 0;
+
+ /* EOF on read */
+ if (a & 0x80)
+ return 0;
+ /* BREAK */
+ if (a & 0x02)
+ udata.u_error = EINTR;
+ /* End of tape while writing */
+ else if (a & 0x04)
+ udata.u_error = ENOSPC;
+ /* Buffer too small (read) */
+ else if (a & 0x20)
+ udata.u_error = EINVAL; /* Not a good error for this really */
+ else
+ udata.u_error = EIO;
+ kprintf("tape: error %x\n", a);
+ return -1;
+}
+
+static int tape_rewind(void)
+{
+ if (!tape_op(0, TAPE_REWIND)) {
+ /* rewind */
+ fileid = 1;
+ inpos = 0;
+ return 0;
+ }
+ return tape_error();
+}
+
+int tape_open(uint8_t minor, uint16_t flag)
+{
+ minor; flag;
+
+ /* Check for the floppy tape ROM */
+ if (*((uint16_t *)0x3034) != 0x3C3C) {
+ udata.u_error = ENODEV;
+ return -1;
+ }
+ if (busy) {
+ udata.u_error = EBUSY;
+ return -1;
+ }
+
+ if (minor > 15 || tape_op(minor & 0x07, TAPE_SELECT)) {
+ udata.u_error = ENODEV;
+ return -1;
+ }
+ /* Can't open for mixed read/write at the same time */
+ if (O_ACCMODE(flag) == O_RDWR) {
+ udata.u_error = EINVAL;
+ return -1;
+ }
+ mode = O_ACCMODE(flag);
+
+ if ((minor & 0x08) || fileid == 255)
+ if (tape_rewind())
+ return -1;
+ /* Only one drive can be used at a time */
+ busy = 1;
+ inio = 0;
+ tape_err = 0;
+ return 0;
+}
+
+int tape_close(uint8_t minor)
+{
+ minor;
+ if (mode == O_WRONLY)
+ if (tape_op(fileid, TAPE_CLOSEW))
+ return tape_error();
+ return 0;
+}
+
+static int tape_rw(uint8_t op)
+{
+ if (!inpos) {
+ if (tape_op(fileid, TAPE_FIND) == 0)
+ inpos = 1;
+ else
+ return tape_error();
+
+ }
+ inio = 1;
+ udata.u_done = tape_op(fileid, op);
+ if (tape_err)
+ return tape_error();
+ return udata.u_done;
+}
+
+int tape_read(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+ used(minor);
+ used(rawflag);
+ used(flag);
+ return tape_rw(TAPE_READ);
+}
+
+int tape_write(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+ used(minor);
+ used(rawflag);
+ used(flag);
+ return tape_rw(TAPE_WRITE);
+}
+
+static struct mtstatus tapei = {
+ MT_TYPE_EXATRON,
+ 0,
+ ~0
+};
+
+int tape_ioctl(uint8_t minor, uarg_t op, char *ptr)
+{
+ used(minor);
+
+ switch(op) {
+ case MTSTATUS:
+ if (inpos)
+ tapei.mt_file = fileid;
+ else
+ tapei.mt_file = ~0;
+ return uput(&tapei, ptr, sizeof(tapei));
+ }
+ /* Now calls we can only make when not mid stream */
+ if (mode || inio)
+ goto bad;
+
+ switch (op) {
+ case MTREWIND:
+ return tape_rewind();
+ case MTSEEKF:
+ if (fileid > 99)
+ goto bad;
+ fileid++;
+ if (tape_op(fileid, TAPE_FIND))
+ goto bad;
+ inpos = 1;
+ return 0;
+ case MTSEEKB:
+ if (fileid < 2)
+ goto bad;
+ fileid--;
+ if (tape_op(fileid, TAPE_FIND))
+ goto bad;
+ inpos = 1;
+ return 0;
+ case MTERASE:
+ /* Erase from this point to the end of tape */
+ if (fileid > 99)
+ goto bad;
+ if (tape_op(fileid, TAPE_ERASE))
+ goto bad;
+ inpos = 0;
+ return 0;
+ default:
+ return -1;
+ }
+bad:
+ udata.u_error = EINVAL;
+ return -1;
+}
--- /dev/null
+
+
+/* Must match the order in tape_op in the asm */
+#define TAPE_WRITE 0
+#define TAPE_READ 1
+#define TAPE_CLOSEW 2
+#define TAPE_REWIND 3
+#define TAPE_FIND 4
+#define TAPE_SELECT 5
+#define TAPE_ERASE 6
+
+extern int tape_read(uint8_t minor, uint8_t rawflag, uint8_t flag);
+extern int tape_write(uint8_t minor, uint8_t rawflag, uint8_t flag);
+extern int tape_ioctl(uint8_t minor, uarg_t op, char *ptr);
+extern int tape_open(uint8_t minor, uint16_t flag);
+extern int tape_close(uint8_t minor);
+
+extern int tape_op(uint8_t id, uint8_t op);
+
+
+
platform-trs80m1/devhd.rel
platform-trs80m1/devhd_discard.rel
platform-trs80m1/devgfx.rel
+platform-trs80m1/devstringy.rel
+platform-trs80m1/stringy.rel
platform-trs80m1/devices.rel
devio.rel
filesys.rel
--- /dev/null
+ .module stringy
+
+ .globl _tape_op
+ .globl _tape_err
+
+ .include "kernel.def"
+ .include "../kernel.def"
+
+ .area _COMMONMEM
+
+ .globl _tape_op
+
+ .globl go_slow
+ .globl go_fast
+
+_tape_op:
+ call go_slow
+ pop bc
+ pop de
+ push de ; file ID in D op in E
+ push bc
+ ld hl,(U_DATA__U_BASE)
+ ld bc,(U_DATA__U_COUNT)
+ xor a
+ ld (_tape_err),a
+ ld a,e
+ or a
+ jr z, write_op
+ dec a
+ jr z, read_op
+ dec a
+ jr z, closew_op
+ dec a
+ jr z, rewind_op
+ dec a
+ jr z, seekf_op
+ dec a
+ jr z, select_op
+ dec a
+ jr z, erase_op
+ ld hl,#0xFFFF
+ call go_fast
+ ret
+find_op:
+ ld a,d
+ call 0x300F
+ jr tape_error
+select_op:
+ ld a,d ; not a file ID but a drive ID this time
+ call 0x3012
+ jr tape_error
+seekf_op:
+ ld a,d
+ call 0x300F ; find file A
+tape_error:
+ push af
+ call go_fast
+ pop af
+ ld hl,#0 ; return 0 if good or -1 if bad and save err
+ ret z
+ dec hl
+ ld (_tape_err),a
+ ret
+closew_op:
+ ld a,d
+ ld bc,#0
+ call 0x3027 ; Write an EOF and the marker for the next
+ jr tape_error ; file ID
+rewind_op:
+ call 0x3000 ; Go back to start of tape (does not find
+ jr tape_error ; file 0 itself)
+read_op:
+ call 0x3003
+ push af
+ call go_fast
+ pop af
+ ld h,b
+ ld l,c ; actual bytes fetched
+ ret z
+rwerr:
+ ld (_tape_err),a
+ ld hl,#0xffff
+ ret
+write_op:
+ call 0x3006
+ push af
+ call go_fast
+ pop af
+ ld hl,(U_DATA__U_COUNT)
+ ret z
+ jr rwerr
+erase_op:
+ ld a,d
+ call 0x3024
+ jr tape_error
; The Model 3 sprinter type card uses port 95h the same way but
; also does automatic slow down when needed
;
+; Only allowed to mess with AF
+;
go_slow:
ld a,(_trs80_model)
or a