summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2013-10-20 04:52:30 (GMT)
committerH. Peter Anvin <hpa@zytor.com>2013-10-20 05:22:59 (GMT)
commit7a80c330bc82d5b4df5e88db3ff1e5dfdedc8dfa (patch)
treeb300dec200ff7d34397819f13b459773d74b11f4
parent2db7072611d2b361f8fa9c0e8145b04652a88fbc (diff)
downloadabc80sim-7a80c330bc82d5b4df5e88db3ff1e5dfdedc8dfa.zip
abc80sim-7a80c330bc82d5b4df5e88db3ff1e5dfdedc8dfa.tar.gz
abc80sim-7a80c330bc82d5b4df5e88db3ff1e5dfdedc8dfa.tar.bz2
abc80sim-7a80c330bc82d5b4df5e88db3ff1e5dfdedc8dfa.tar.xz
Replace the old UNX:/LIB: device with PR:/PRA:/PRB: from FPGA project
Replace the old UNX:/LIB: devices with the PR:/PRA:/PRB: device from the ABC80-in-FPGA project. This allows printing, and shares both the ROM and the backend code with the FPGA project for consistent behavior. Signed-off-by: H. Peter Anvin <hpa@zytor.com>
-rw-r--r--.gitignore3
-rw-r--r--Makefile14
-rw-r--r--abc80.c2
-rw-r--r--abcdev.asm211
-rw-r--r--abcdev.binbin260 -> 0 bytes
-rw-r--r--abcprint.c55
-rw-r--r--abcprintd.h35
-rwxr-xr-xbin2c.pl1
-rw-r--r--fileop.c574
-rw-r--r--io.c295
-rw-r--r--print.c172
-rw-r--r--printer.binbin0 -> 722 bytes
-rw-r--r--rom.h2
-rw-r--r--ufddos.binbin4096 -> 4096 bytes
14 files changed, 888 insertions, 476 deletions
diff --git a/.gitignore b/.gitignore
index 673553b..0162c6c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,3 +7,6 @@ abcdisk
abcdir
abcrom40.c
abcrom80.c
+ufddos.c
+printer.c
+abc80
diff --git a/Makefile b/Makefile
index 4da4fbc..39dff14 100644
--- a/Makefile
+++ b/Makefile
@@ -35,11 +35,17 @@ PERL = perl
O = o
X =
-GENO = abcrom40.$(O) abcrom80.$(O) abcdev.$(O) ufddos.$(O)
+GENO = abcrom40.$(O) abcrom80.$(O) ufddos.$(O) printer.$(O)
GENC = abcrom40.c abcrom80.c abcdev.c ufddos.c
-OBJS = abc80.$(O) clock.$(O) sdlscrn.$(O) z80.$(O) abc80_mem.$(O) io.$(O) abcfont.$(O) disk.$(O) z80dis.$(O) $(GENO)
-SRCS = abc80.c clock.c sdlscrn.c z80.c abc80_mem.c io.c abcfont.c disk.c z80dis.c abcrom40.c abcrom80.c $(GENC)
+OBJS = abc80.$(O) clock.$(O) sdlscrn.$(O) z80.$(O) abc80_mem.$(O) io.$(O) \
+ abcfont.$(O) disk.$(O) \
+ abcprint.$(O) print.$(O) fileop.$(O) \
+ z80dis.$(O) $(GENO)
+SRCS = abc80.c clock.c sdlscrn.c z80.c abc80_mem.c io.c \
+ abcfont.c disk.c \
+ abcprint.c print.c fileop.c \
+ z80dis.c abcrom40.c abcrom80.c $(GENC)
HDRS = clock.h screen.h z80.h patchlevel.h
.SUFFIXES: .c .h .$(O) .bin
@@ -58,7 +64,7 @@ abc80$(X): $(OBJS)
abcrom40.c: abcrom40.bin bin2c.pl
abcrom80.c: abcrom80.bin bin2c.pl
-abcdev.c: abcdev.bin bin2c.pl
+printer.c: printer.bin bin2c.pl
ufddos.c: ufddos.bin bin2c.pl
abc80.$(O): clock.h screen.h z80.h patchlevel.h
diff --git a/abc80.c b/abc80.c
index 65008a0..74103fc 100644
--- a/abc80.c
+++ b/abc80.c
@@ -137,7 +137,7 @@ int main(int argc, char **argv)
*/
if (!no_device) {
load_rom(&ufddos);
- load_rom(&abcdev);
+ load_rom(&printer);
}
/*
diff --git a/abcdev.asm b/abcdev.asm
deleted file mode 100644
index fe21481..0000000
--- a/abcdev.asm
+++ /dev/null
@@ -1,211 +0,0 @@
-;
-; This is the "device driver" for the UNX:
-; device in the ABC80 emulator.
-;
-; It communicates with the "device" through port 255
-;
-
-;
-; Some useful definitions
-;
-Devlst EQU 0FE0AH ; Device list root
-Buf0 EQU 0F500H ; First disk buffer
-Closef EQU 00023H ; Close file subroutine
-
-;
-; This position in the memory is sampled by
-; the ABC80 initialization routine and if
-; it is not 0 it makes a CALL to the address.
-;
- ORG 0404BH
- JP Init
- JP Exit
-;
-; Define an entry in device list.
-;
-Unxdev:
- DEFW Defdev
- ASCII 'UNX'
- DEFW Unxtab
-
-;
-; Define another entry with epmty name to
-; make it the default device.
-;
-Defdev:
- DEFW Libdev
- ASCII ' '
- DEFW Unxtab
-
-;
-; This is another special device for reading the
-; directory contents.
-;
-Libdev:
- DEFW 0
- ASCII 'LIB'
- DEFW Libtab
-
-;
-; Initialization routine.
-; Install the entrys above in the device list
-;
-Init:
- LD HL,(Devlst)
- LD (Libdev),HL
- LD HL,Unxdev
- LD (Devlst),HL
- JP 6543h ; Initialize DOS
-
-;
-; Jumptable at device driver entry
-;
-Unxtab:
- JP Open
- JP Prepare
- JP Close
- JP 00015H ; Input
- JP 0001BH ; Print
- JP Blockin
- JP Blockout
-
-;
-; Open a file for reading and initialize
-; the file info block.
-;
-Open:
- LD A,0 ; Open file
-UOpen2: LD B,(IX+2) ; File number
- OUT (0FFH),A ; Call "device"
- IN A,(0FFH) ; Get result status
- CP 0 ; OK?
- JR Z,UOpenOK
- RST 2 ; Error
- DEFB 128+21 ; ERR 21 (Can't find file)
- ; Find the buffer to use
-UOpenOK:LD HL,Buf0
-ULoop1: INC H
- DJNZ ULoop1
- ; Init device info block
- LD (IX+7),132 ; Line length (not used)
- LD (IX+8),L ; Buffer address
- LD (IX+9),H
- LD (IX+0AH),L ; Read/write position
- LD (IX+0BH),H
- LD (IX+0DH),253 ; No of free chars in buffer
- LD (IX+0EH),0 ; Buffer is clean
- LD (HL),3 ; Write EOT at start
-
- AND A ; Clear carry
- RET
-
-;
-; Open a file for writing (mostly the same as Open).
-;
-Prepare:
- LD A,1 ; Prepare file...
- JP UOpen2 ; ...then same as open
-
-;
-; Close a file
-;
-Close:
- BIT 7,(IX+0EH) ; Buffer dirty?
- CALL NZ,Closef ; Call BASIC's "close file"
- LD A,2 ; Close file
- LD B,(IX+2) ; File number
- OUT (0FFH),A ; Call "device"
- AND A ; Clear carry
- RET
-
-;
-; Read a block from a file
-;
-Blockin:
- LD L,(IX+8) ; Get buffer address
- LD H,(IX+9)
- LD A,3 ; Read buffer from file
- LD B,(IX+2) ; File number
- OUT (0FFH),A ; Call "device"
- RET
-
-;
-; Write a block to a file
-;
-Blockout:
- LD L,(IX+8) ; Get buffer address
- LD H,(IX+9)
- LD A,4 ; Write buffer to file
- LD B,(IX+2) ; File number
- OUT (0FFH),A ; Call "device"
- LD (IX+0DH),253 ; No of free chars in buffer
- SET 0,(IX+0EH) ; Buffer is clean
- EX DE,HL ; ??
- RET
-
-
-;
-; Jumptable at device driver entry
-;
-Libtab:
- JP Libopen
- JP LibPrep
- JP Libclose
- JP Libinput
- JP Libprint
- JP Libblin
- JP Libblout
-
-
-Libopen:
- LD A,0 ; Open directory file
- LD B,(IX+2) ; File number
- OUT (0FEH),A ; Call "device"
- CP 0 ; OK?
- JR Z,LOpenOK
- RST 2 ; Error
- DEFB 128+21 ; ERR 21 (Can't find file)
-LOpenOK:LD (IX+7),40 ; Line length
- LD (IX+6),0 ; Line position
- AND A ; Clear carry
- RET
-
-Libprep:
- RST 2 ; Error
- DEFB 128+39 ; ERR 39 (Not allowed to write)
-
-Libclose:
- LD A,1 ; Close directory file
- LD B,(IX+2) ; File number
- OUT (0FEH),A ; Call "device"
- AND A ; Clear carry
- RET
-
-Libinput:
- LD B,(IX+2) ; File number
-Linp: LD A,C
- AND A
- JP Z,Full
- IN A,(0FEH)
- LD (HL),A
- INC HL
- DEC C
- CP 3 ; End of file?
- JP NZ,Lskip
- RST 2
- DEFB 128+34
-Lskip: CP 0DH ; Return?
- JP NZ,Linp
- JP Ready
-Full: DEC HL
- LD (HL),0DH
-Ready: AND A
- RET
-
-Libprint:
-Libblin:
-Libblout:
- RET
-
-Exit: HALT
- END
diff --git a/abcdev.bin b/abcdev.bin
deleted file mode 100644
index 062a3e9..0000000
--- a/abcdev.bin
+++ /dev/null
Binary files differ
diff --git a/abcprint.c b/abcprint.c
new file mode 100644
index 0000000..cc003c0
--- /dev/null
+++ b/abcprint.c
@@ -0,0 +1,55 @@
+#include "abcprintd.h"
+
+void printer_reset(void)
+{
+ static int init = 0;
+
+ if (!init) {
+ fileop_prefix = "abcdir/";
+ abcprint_init();
+ }
+}
+
+void printer_out(int sel, int port, int value)
+{
+ unsigned char v = value;
+
+ (void)sel;
+
+ switch (port) {
+ case 0:
+ abcprint(&v, 1);
+ break;
+
+ case 4:
+ abcprint_init();
+ break;
+
+ default:
+ break;
+ }
+}
+
+int printer_in(int sel, int port)
+{
+ int v;
+
+ (void)sel;
+
+ switch (port) {
+ case 0:
+ v = abcprint_read();
+ break;
+
+ case 1:
+ v = abcprint_poll() ? 0x40 : 0;
+ break;
+
+ default:
+ v = -1;
+ break;
+ }
+
+ return v;
+}
+
diff --git a/abcprintd.h b/abcprintd.h
new file mode 100644
index 0000000..805ad56
--- /dev/null
+++ b/abcprintd.h
@@ -0,0 +1,35 @@
+#ifndef ABCPRINTD_H
+#define ABCPRINTD_H
+
+#include <ctype.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <locale.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <wchar.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#ifndef O_TEXT
+# define O_TEXT 0
+#endif
+#ifndef O_BINARY
+# define O_BINARY 0
+#endif
+
+extern int lpr_argc;
+extern const char **lpr_argv;
+extern void abcprint_init(void);
+extern void abcprint(const void *, size_t);
+extern int abcprint_read(void);
+extern int abcprint_poll(void);
+extern bool file_op(unsigned char);
+extern const char *fileop_prefix;
+
+#endif
diff --git a/bin2c.pl b/bin2c.pl
index 658b7df..e208072 100755
--- a/bin2c.pl
+++ b/bin2c.pl
@@ -32,6 +32,7 @@ $table_name =~ s/\.[^\.]*$//; # Drop extension
unless (defined ($offset)) {
$offset = 0x404b if ($table_name eq 'abcdev');
$offset = 0x6000 if ($table_name =~ /dos$/);
+ $offset = 0x7800 if ($table_name eq 'printer');
}
open(IN, '<', $input_file)
diff --git a/fileop.c b/fileop.c
new file mode 100644
index 0000000..d259c38
--- /dev/null
+++ b/fileop.c
@@ -0,0 +1,574 @@
+#include "abcprintd.h"
+
+const char *fileop_prefix;
+
+#define BUF_SIZE 512
+
+static unsigned char output_buf[BUF_SIZE];
+static int output_head, output_tail;
+
+static char *make_path(const char *filename)
+{
+ char *p;
+ int pl = strlen(fileop_prefix);
+ int fl = strlen(filename);
+
+ p = malloc(pl + fl + 2);
+ if (!p) {
+ perror("malloc");
+ exit(1);
+ }
+
+ sprintf(p, "%s%s%s", fileop_prefix,
+ (pl > 0 &&
+#ifdef WIN32
+ fileop_prefix[pl-1] != ':' &&
+ fileop_prefix[pl-1] != '\\' &&
+#endif
+ fileop_prefix[pl-1] != ':') ? "/" : "",
+ filename);
+
+ return p;
+}
+
+int abcprint_read(void)
+{
+ int c;
+
+ if (output_head == output_tail) {
+ return -1;
+ } else {
+ c = output_buf[output_head];
+ output_head = (output_head + 1) % BUF_SIZE;
+ return c;
+ }
+}
+
+int abcprint_poll(void)
+{
+ return output_head != output_tail;
+}
+
+static void output_bytes(const void *buf, size_t count)
+{
+ const unsigned char *bp = buf;
+
+ while (count--) {
+ int nt = (output_tail + 1) % BUF_SIZE;
+
+ if (nt == output_head)
+ return; /* Output buffer full - data lost */
+
+ output_buf[output_tail] = *bp++;
+ output_tail = nt;
+ }
+}
+
+static enum {
+ st_op,
+ st_filename,
+ st_len,
+ st_data
+} state = st_op;
+static int byte_count = 4;
+static unsigned char cmd[4];
+static unsigned char *bytep = cmd;
+static struct file_data *filemap[65536];
+
+struct file_data {
+ FILE *f;
+ DIR *d;
+};
+
+static void send_reply(int status)
+{
+ unsigned char reply[4];
+
+ reply[0] = 0xff;
+ reply[1] = cmd[0];
+ reply[2] = cmd[1];
+ reply[3] = status;
+
+ output_bytes(reply, 4);
+}
+
+/* Returns the status code, use send_reply(do_close(ix)) if reply desired */
+static int do_close(uint16_t ix)
+{
+ struct file_data *fm = filemap[ix];
+
+ if (fm) {
+ if (fm->f)
+ fclose(fm->f);
+ if (fm->d)
+ closedir(fm->d);
+ free(fm);
+ filemap[ix] = NULL;
+ return 0;
+ } else {
+ return 128+45; /* "Fel logiskt filnummer" */
+ }
+}
+
+static void do_closeall(void)
+{
+ int ix;
+
+ for (ix = 0; ix <= 65535; ix++)
+ if (filemap[ix])
+ do_close(ix);
+
+ if (cmd[0] == 0xA8)
+ send_reply(0);
+}
+
+static void unmangle_filename(char *out, const char *in)
+{
+ static const wchar_t my_tolower[256] =
+ L"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017"
+ L"\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037"
+ L" !\"#¤%&'()*+,-./0123456789:;<=>?"
+ L"éabcdefghijklmnopqrstuvwxyzäöåü_"
+ L"éabcdefghijklmnopqrstuvwxyzäöåü\377"
+ L"\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ L"\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237"
+ L"\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257"
+ L"\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277"
+ L"\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317"
+ L"\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337"
+ L"\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357"
+ L"\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377";
+ int i;
+
+ wctomb(NULL, 0);
+
+ for (i = 0; i < 8; i++) {
+ if (*in != ' ')
+ out += wctomb(out, my_tolower[(unsigned char)*in]);
+ in++;
+ }
+
+ if (memcmp(in, " ", 3) && memcmp(in, "Ufd", 3)) {
+ out += wctomb(out, L'.');
+ for (i = 0; i < 3; i++) {
+ if (*in != ' ')
+ out += wctomb(out, my_tolower[(unsigned char)*in]);
+ in++;
+ }
+ }
+
+ *out = '\0';
+}
+
+static void do_open(uint16_t ix, char *name)
+{
+ int err;
+ struct file_data *fm;
+ static const char *modes[6] = {"r+t", "r+b", "w+t", "w+b", "rt", "rb" };
+ char path_buf[64];
+ char *path;
+
+ if (!fileop_prefix) {
+ send_reply(128+42); /* Skivan ej klar */
+ return;
+ }
+
+ do_close(ix);
+
+ unmangle_filename(path_buf, name);
+ path = make_path(path_buf[0] ? path_buf : ".");
+ if (!path) {
+ send_reply(128+42);
+ return;
+ }
+
+ fm = calloc(1, sizeof(struct file_info *));
+ if (!fm) {
+ free(path);
+ send_reply(128+42);
+ return;
+ }
+
+ if (!path_buf[0]) {
+ /* Empty filename (readdir) */
+
+ if ((cmd[0] & 3) == 0) {
+ fm->d = opendir(path);
+ } else {
+ errno = ENOENT; /* File not found */
+ }
+ } else {
+ /* Actual filename */
+
+ fm->f = fopen(path, modes[cmd[0] & 3]);
+ if (!fm->f && errno == EACCES && !(cmd[0] & 2)) {
+ fm->f = fopen(path, modes[(cmd[0] & 1)+4]);
+ }
+ }
+
+ free(path);
+
+ if (!fm->f && !fm->d) {
+ free(fm);
+ switch (errno) {
+#if 0 /* Enable this? */
+ case EACCES:
+ err = 128+39;
+ break;
+ case EROFS:
+ err = 128+43;
+ break;
+ case EIO:
+ case ENOTDIR:
+ err = 128+48;
+ break;
+#endif
+ default:
+ err = 128+21;
+ break;
+ }
+ send_reply(err);
+ return;
+ }
+
+ filemap[ix] = fm;
+
+ send_reply(0);
+}
+
+static void do_read_block(uint16_t ix, uint16_t len)
+{
+ struct file_data *fm = filemap[ix];
+ int err;
+ unsigned char *data;
+ int dlen;
+
+ if (!fm || !fm->f) {
+ send_reply(128+45);
+ return;
+ }
+
+ data = calloc(len+2, 1);
+ if (!data) {
+ send_reply(128+42); /* "Skivan ej klar" */
+ return;
+ }
+
+ clearerr(fm->f);
+ dlen = fread(data+2, 1, len, fm->f);
+ if (dlen == 0) {
+ if (ferror(fm->f)) {
+ switch (errno) {
+ case EBADF:
+ err = 128+44; /* Logisk fil ej öppen */
+ break;
+ case EIO:
+ err = 128+35; /* Checksummafel vid läsning */
+ break;
+ default:
+ err = 128+48; /* Fel i biblioteket */
+ break;
+ }
+ } else {
+ /* EOF */
+ err = 128+34; /* Slut på filen */
+ }
+ send_reply(err);
+ free(data);
+ return;
+ }
+
+ send_reply(0);
+
+ data[0] = len;
+ data[1] = len >> 8;
+ output_bytes(data, len+2);
+ free(data);
+}
+
+/*
+ * Returns length for OK, 0 for failure
+ */
+static int mangle_for_readdir(char *dst, const char *src)
+{
+ static const wchar_t srcset[] =
+ L"0123456789_."
+ L"ÉABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÅÜÆØ"
+ L"éabcdefghijklmnopqrstuvwxyzäöåüæø";
+ static const char dstset[] =
+ "0123456789_."
+ "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^[\\"
+ "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^[\\";
+ char *d;
+ const char *s;
+ wchar_t sc;
+ const wchar_t *scp;
+ char dc;
+ int n;
+ char mangle_buf[12], unmangle_buf[64];
+
+ s = src;
+
+ memset(mangle_buf, ' ', 11);
+ mangle_buf[11] = '\0';
+
+ mbtowc(NULL, NULL, 0); /* Reset the shift state */
+
+ d = mangle_buf;
+ while (d < mangle_buf+11 && (n = mbtowc(&sc, s, (size_t)~0)) > 0) {
+ s += n;
+
+ if ( (scp = wcschr(srcset, sc)) ) {
+ dc = dstset[scp - srcset];
+ } else {
+ dc = '_';
+ }
+
+ if ( dc == '.' )
+ d = mangle_buf+8;
+ else
+ *d++ = dc;
+ }
+
+ unmangle_filename(unmangle_buf, mangle_buf);
+
+ if (strcmp(unmangle_buf, src))
+ return 0; /* Not round-trippable */
+
+ /* Compact to 8.3 notation */
+ d = dst;
+ s = mangle_buf;
+ for (n = 0; n < 8; n++) {
+ if (*s != ' ')
+ *d++ = *s;
+ s++;
+ }
+ if (memcmp(s, " ", 3)) {
+ *d++ = '.';
+ for (n = 0; n < 3; n++) {
+ if (*s != ' ')
+ *d++ = *s;
+ s++;
+ }
+ }
+ *d = '\0';
+
+ return d - dst;
+}
+
+
+static void do_input(uint16_t ix)
+{
+ struct file_data *fm = filemap[ix];
+ int err;
+ char data[BUF_SIZE], data1[2*BUF_SIZE];
+ char *path;
+ char *p, *q, c;
+ int dlen;
+ struct dirent *de;
+ struct stat st;
+
+ if (!fm) {
+ send_reply(128+45);
+ return;
+ }
+
+ if (fm->f) {
+ clearerr(fm->f);
+ if (!fgets(data, sizeof data, fm->f)) {
+ if (ferror(fm->f)) {
+ switch (errno) {
+ case EBADF:
+ err = 128+44; /* Logisk fil ej öppen */
+ break;
+ case EIO:
+ err = 128+35; /* Checksummafel vid läsning */
+ break;
+ default:
+ err = 128+48; /* Fel i biblioteket */
+ break;
+ }
+ } else {
+ /* EOF */
+ err = 128+34; /* Slut på filen */
+ }
+ } else {
+ /* Strip CR and change LF -> CR LF */
+ for (p = data, q = data1+2 ; (c = *p) ; p++) {
+ switch (c) {
+ case '\r':
+ break;
+ case '\n':
+ *q++ = '\r';
+ /* fall through */
+ default:
+ *q++ = c;
+ break;
+ }
+ }
+ dlen = q - (data1+2);
+ err = 0;
+ }
+ } else if (fm->d) {
+ while ( (de = readdir(fm->d)) ) {
+ if (de->d_name[0] != '.' &&
+ (dlen = mangle_for_readdir(data1+2, de->d_name))) {
+ bool ok;
+ path = make_path(de->d_name);
+ if (!path) {
+ err = 128+42;
+ goto err;
+ }
+ ok = !stat(path, &st) && S_ISREG(st.st_mode);
+ free(path);
+ if (ok)
+ break;
+ }
+ }
+ if (de) {
+ dlen += sprintf(data1+2+dlen, ",%lu\r\n",
+ ((unsigned long)st.st_size + 252)/253);
+ err = 0;
+ } else {
+ err = 128+34;
+ }
+ } else {
+ err = 128+44;
+ }
+
+ err:
+ send_reply(err);
+ if (!err) {
+ data1[0] = dlen;
+ data1[1] = dlen >> 8;
+ output_bytes(data1, dlen+2);
+ }
+}
+
+static void do_print(uint16_t ix, uint16_t len, void *data)
+{
+ struct file_data *fm = filemap[ix];
+ int err;
+
+ if (!fm || !fm->f) {
+ send_reply(128+45);
+ return;
+ }
+
+ err = 0;
+ if (fwrite(data, 1, len, fm->f) != len || fflush(fm->f)) {
+ switch (errno) {
+ case EACCES:
+ err = 128+39; /* Filen skrivskyddad */
+ break;
+ case ENOSPC:
+ case EFBIG:
+ err = 128+41; /* Skivan full */
+ break;
+ case EROFS:
+ err = 128+43; /* Skivan skrivskyddad */
+ break;
+ case EBADF:
+ err = 128+44; /* Logisk fil ej öppen */
+ break;
+ case EIO:
+ err = 128+36; /* Checksummafel vid skrivning */
+ break;
+ default:
+ err = 128+48; /* Fel i biblioteket */
+ break;
+ }
+ }
+ send_reply(err);
+}
+
+bool file_op(unsigned char c)
+{
+ static unsigned char *data;
+ static char namebuf[12];
+ static unsigned char lenbuf[2];
+ uint16_t ix, len;
+
+ *bytep++ = c;
+ if (--byte_count)
+ return true; /* More to do... */
+
+ /* Otherwise, we have a full deck of *something* */
+
+ ix = (cmd[3] << 8) + cmd[2];
+ len = (lenbuf[1] << 8) + lenbuf[0];
+
+ switch (state) {
+ case st_op:
+ switch (cmd[0]) {
+ case 0xA0: /* OPEN TEXT */
+ case 0xA1: /* PREPARE TEXT */
+ case 0xA2: /* OPEN BINARY */
+ case 0xA3: /* PREPARE BINARY */
+ bytep = (void *)namebuf;
+ byte_count = 11;
+ state = st_filename;
+ return true;
+
+ case 0xA4: /* INPUT */
+ do_input(ix);
+ break;
+
+ case 0xA5: /* READ BLOCK */
+ case 0xA6: /* PRINT */
+ bytep = lenbuf;
+ byte_count = 2;
+ state = st_len;
+ return true;
+
+ case 0xA7: /* CLOSE */
+ send_reply(do_close(ix));
+ break;
+
+ case 0xA8: /* CLOSEALL */
+ case 0xA9:
+ do_closeall();
+ break;
+
+ default:
+ /* Unknown command */
+ send_reply(128+11);
+ break;
+ }
+ break;
+
+ case st_filename:
+ do_open(ix, namebuf);
+ break;
+
+ case st_len:
+ switch (cmd[0]) {
+ case 0xA5: /* READ BLOCK */
+ do_read_block(ix, len);
+ break;
+ case 0xA6: /* PRINT */
+ if (data)
+ free(data);
+ data = malloc(len);
+ if (!data)
+ send_reply(128+42); /* "Skivan ej klar" */
+ bytep = data;
+ byte_count = len;
+ state = st_data;
+ return true;
+ }
+ break;
+
+ case st_data:
+ do_print(ix, len, data);
+ free(data);
+ data = NULL;
+ break;
+ }
+
+ /* unless otherwise specified, back to command mode */
+ bytep = cmd;
+ byte_count = 4;
+ state = st_op;
+ return false;
+}
diff --git a/io.c b/io.c
index 8ab9da5..4ee8dac 100644
--- a/io.c
+++ b/io.c
@@ -23,8 +23,6 @@ static struct {
int mode;
} files[8];
-
-
/*
* Set a port to a value which the z80 can read later.
*/
@@ -34,247 +32,15 @@ set_in_port(int port, uchar value)
inports[port] = value;
}
-
-
-/*
- * Open the current directory
- * Register B holds logical file number.
- * Status is returned in the device port (255)
- * 0 == OK, 1 == FAIL
- */
-static void
-lib_open(void)
-{
- int fileno;
-
- fileno = (REG_B > 7 ? 0 : REG_B);
-
- if ((files[fileno].u.dp = opendir(".")) == NULL) {
- REG_A = 1;
- } else {
- files[fileno].mode = READ_MODE;
- REG_A = 0;
- }
-}
-
-
-/*
- * Close current directory.
- * Register B holds logical file number.
- */
-static void
-lib_close(void)
-{
- int fileno;
-
- fileno = (REG_B > 7 ? 0 : REG_B);
- closedir(files[fileno].u.dp);
- files[fileno].u.dp = NULL;
-}
-
-
-/*
- * Read a char from the current dir.
- */
-static struct dirent *de = NULL;
-static void
-lib_getchar(void)
-{
- int fileno;
- static int pos;
-
- fileno = (REG_B > 7 ? 0 : REG_B);
-
- if (de == NULL || pos == 40) {
- do {
- de = readdir(files[fileno].u.dp);
- if (de == NULL) {
- set_in_port(254, 3);
- return;
- }
- } while (de->d_name[0] == '.');
- }
-
- if (de == NULL || de->d_name[pos] == '\0') {
- set_in_port(254, 13);
- de = NULL;
- pos = 0;
- return;
- } else {
- set_in_port(254, de->d_name[pos++]);
- }
-}
-
-
-/*
- * File IO with device "UNX"
- */
-static void
-file_get_name(char filename[])
-{
- uchar *memory;
- int i, j;
-
- memory = mem_get_addr(REG_DE);
- j = 8;
- for (i = 0;i < 8; i++) {
- if (*memory != ' ') {
- filename[i] = *memory | 0x20;
- } else if (j == 8) {
- j = i;
- }
- memory++;
- }
- filename[j++] = '.';
- while (i < 11) {
- if (*memory == ' ') {
- break;
- }
- filename[j++] = *memory++ | 0x20;
- i++;
- }
- filename[j] = '\0';
-}
-
-
-/*
- * Open a file for reading.
- * Register B holds logical file number.
- * Status is returned in the device port (255)
- * 0 == OK, 1 == FAIL
- */
-static void
-file_open(void)
-{
- char filename[13];
- int fileno;
-
- file_get_name(filename);
- fileno = (REG_B > 7 ? 0 : REG_B);
-
- if ((files[fileno].u.fp = fopen(filename, "r")) == NULL) {
- set_in_port(255, 1);
- } else {
- files[fileno].mode = READ_MODE;
- set_in_port(255, 0);
- }
-}
-
-
-/*
- * Open a file for writing.
- * Register B holds logical file number.
- * Status is returned in the device port (255)
- * 0 == OK, 1 == FAIL
- */
-static void
-file_prepare(void)
-{
- char filename[12];
- int fileno;
-
- file_get_name(filename);
- fileno = (REG_B > 7 ? 0 : REG_B);
-
- if ((files[fileno].u.fp = fopen(filename, "w")) == NULL) {
- set_in_port(255, 1);
- } else {
- set_in_port(255, 0);
- files[fileno].mode = WRITE_MODE;
- }
-}
-
-
-/*
- * Close a file.
- * Register B holds logical file number.
- */
-static void
-file_close(void)
-{
- int fileno;
-
- fileno = (REG_B > 7 ? 0 : REG_B);
- fclose(files[fileno].u.fp);
- files[fileno].u.fp = NULL;
-}
-
-
-/*
- * Read next block from a file.
- * Register pair HL holds address to buffer where data should be placed.
- * Register B holds logical file number.
- */
-static void
-file_read_block(void)
-{
- int fileno;
- uchar *buf;
-
- buf = mem_get_addr(REG_HL);
- fileno = (REG_B > 7 ? 0 : REG_B);
- fread(buf, sizeof(uchar), 253, files[fileno].u.fp); /* Blocklen = 253 */
- *(buf+253) = 0x03; /* Set marker efter after blocketthe block so that
- INPUT know where it ends */
-}
-
-
-/*
- * Write next block to a file.
- * Register pair HL holds address to buffer where data should be placed.
- * Register B holds logical file number.
- */
-static void
-file_write_block(void)
-{
- int fileno;
- uchar *buf;
-
- buf = mem_get_addr(REG_HL);
- fileno = (REG_B > 7 ? 0 : REG_B);
- fwrite(buf, sizeof(uchar), 253, files[fileno].u.fp); /* Blocklen = 253 */
-}
-
-
-/*
- * Dispatch file IO functions.
- */
-static void
-file_io(uchar function)
-{
- switch (function) {
- case 0:
- file_open();
- break;
-
- case 1:
- file_prepare();
- break;
-
- case 2:
- file_close();
- break;
-
- case 3:
- file_read_block();
- break;
-
- case 4:
- file_write_block();
- break;
-
- default:
- break;
- }
-}
-
/* Select code for ABC/4680 bus */
int abcbus_select = -1;
-
extern void disk_reset(void);
extern void disk_out(int, int, int);
extern int disk_in(int, int);
+extern void printer_reset(void);
+extern void printer_out(int, int, int);
+extern int printer_in(int, int);
/*
* This function is called from the z80 at an OUT instruction.
@@ -287,25 +53,25 @@ z80_out(int port, uchar value)
if ( port == 1 )
abcbus_select = value & 0x3f;
- if ( port < 6 && abcbus_select != -1) {
- disk_out(abcbus_select, port, value);
- }
-
- if (port == 6 && value == 131) { /* beep */
- putchar(7);
- fflush(stdout);
- } else if (port == 255) { /* File IO */
- file_io(value);
- } else if (port == 254) {
- switch (value) {
- case 0:
- lib_open();
+ if (port < 6) {
+ switch (abcbus_select) {
+ case 36: /* HDx: */
+ case 44: /* MFx: */
+ case 45: /* MOx: */
+ case 46: /* SFx: */
+ disk_out(abcbus_select, port, value);
break;
-
- case 1:
- lib_close();
+
+ case 60: /* PRx: */
+ printer_out(abcbus_select, port, value);
+ break;
+
+ default:
break;
}
+ } else if (port == 6 && value == 131) { /* beep */
+ putchar(7);
+ fflush(stdout);
}
outports[port] = value;
}
@@ -320,13 +86,28 @@ z80_in(int port)
if ( port == 7 ) {
abcbus_select = -1;
disk_reset(); /* Reset ALL devices */
+ printer_reset();
}
if ( port == 0 || port == 1 ) {
- int v = 0xff;
+ int v;
- if ( abcbus_select != -1 )
+ switch (abcbus_select) {
+ case 36: /* HDx: */
+ case 44: /* MFx: */
+ case 45: /* MOx: */
+ case 46: /* SFx: */
v = disk_in(abcbus_select, port);
+ break;
+
+ case 60: /* PRx: */
+ v = printer_in(abcbus_select, port);
+ break;
+
+ default:
+ v = 0xff;
+ break;
+ }
return v;
}
@@ -339,10 +120,6 @@ z80_in(int port)
setmode40(0);
}
- if (port == 254) {
- lib_getchar();
- }
-
if (port == 56) {
int v = inports[port];
inports[port] &= ~0x80;
diff --git a/print.c b/print.c
new file mode 100644
index 0000000..aa9b03d
--- /dev/null
+++ b/print.c
@@ -0,0 +1,172 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2004-2013 H. Peter Anvin - All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+ * Bostom MA 02111-1307, USA; either version 2 of the License, or
+ * (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * print.c
+ *
+ * abcprintd backend - also usable for abc80sim
+ *
+ */
+
+#include "abcprintd.h"
+
+#include <sys/wait.h>
+
+int lpr_argc;
+const char **lpr_argv;
+
+enum output_state {
+ os_first, /* Brand new job */
+ os_percent, /* Job started with %, might be Postscript */
+ os_binary, /* Don't touch this */
+ os_text /* It's text, OK to modify */
+};
+
+static void print_setup(FILE **tfp, enum output_state *psp)
+{
+ FILE *tf = *tfp;
+ pid_t f;
+
+ if ( tf ) {
+ fflush(tf);
+ rewind(tf);
+
+ f = fork();
+
+ if ( f < 0 ) {
+ perror("fork");
+ exit(1);
+ } else if ( f == 0 ) {
+ dup2(fileno(tf), STDIN_FILENO);
+ fclose(tf);
+ execvp(lpr_argv[0], (char **)lpr_argv);
+ _exit(255);
+ } else {
+ fclose(tf);
+ while ( waitpid(f, NULL, 0) != f );
+ }
+ }
+
+ *tfp = tmpfile();
+ if ( !*tfp ) {
+ perror("tmpfile");
+ exit(1);
+ }
+ *psp = os_first;
+}
+
+static void output(int c, FILE *tf, enum output_state *psp)
+{
+ static const wchar_t abc_to_unicode[256] =
+ L"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017"
+ L"\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037"
+ L" !\"#¤%&\'()*+,-./0123456789:;<=>?"
+ L"ÉABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÅÜ_"
+ L"éabcdefghijklmnopqrstuvwxyzäöåü\x25a0"
+ L"\x20ac\x25a1\x201a\x0192\x201e\x2026\x2020\x2021"
+ L"\x02c6\x2030\x0160\x2039\x0152\x2190\x017d\x2192"
+ L"\x2191\x2018\x2019\x201c\x201d\x2022\x2013\x2014"
+ L"\x02dc\x2122\x0161\x203a\x0153\x2193\x017e\x0178"
+ L"\240\241\242\243$\245\246\247\250\251\252\253\254\255\256\257"
+ L"\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277"
+ L"\300\301\302\303[]\306\307\310@\312\313\314\315\316\317"
+ L"\320\321\322\323\324\325\\\327\330\331\332\333^\335\336\337"
+ L"\340\341\342\343{}\346\347\350`\352\353\354\355\356\357"
+ L"\360\361\362\363\364\365|\367\370\371\372\373~\375\376\377";
+
+ switch ( *psp ) {
+ case os_first:
+ if ( c == 27 )
+ *psp = os_binary;
+ else if ( c == '%' ) {
+ *psp = os_percent;
+ return;
+ } else {
+ *psp = os_text;
+ // fwrite(text_prefix, 1, sizeof text_prefix - 1, tf);
+ }
+ output(c, tf, psp);
+ break;
+
+ case os_percent:
+ if ( c == '!' ) {
+ *psp = os_binary;
+ } else {
+ *psp = os_text;
+ // fwrite(text_prefix, 1, sizeof text_prefix - 1, tf);
+ }
+ output('%', tf, psp);
+ output(c, tf, psp);
+ break;
+
+ case os_text:
+ if (c != '\r')
+ putwc(abc_to_unicode[(unsigned char)c], tf);
+ break;
+
+ case os_binary:
+ putc(c, tf);
+ break;
+ }
+}
+
+static FILE *tf = NULL;
+static enum output_state os;
+
+enum input_state {
+ is_normal, /* Normal operation */
+ is_ff, /* 0xFF received */
+ is_file, /* File operation in progress */
+};
+static enum input_state is;
+
+void abcprint_init(void)
+{
+ print_setup(&tf, &os);
+ is = is_normal;
+}
+
+void abcprint(const void *data, size_t len)
+{
+ const unsigned char *dp = data;
+ unsigned char c;
+
+ while (len--) {
+ c = *dp++;
+
+ switch ( is ) {
+ case is_normal:
+ if ( c == 0xff )
+ is = is_ff;
+ else
+ output(c, tf, &os);
+ break;
+
+ case is_ff:
+ if ( c == 0 ) {
+ print_setup(&tf, &os); /* BREAK received, end of job */
+ is = is_normal;
+ } else if ( c >= 0xa0 && c <= 0xbf ) {
+ /* Opcode range reserved for file ops */
+ is = file_op(c) ? is_file : is_normal;
+ } else {
+ output(c, tf, &os);
+ is = is_normal;
+ }
+ break;
+
+ case is_file:
+ is = file_op(c) ? is_file : is_normal;
+ break;
+ }
+ }
+}
diff --git a/printer.bin b/printer.bin
new file mode 100644
index 0000000..9a972d8
--- /dev/null
+++ b/printer.bin
Binary files differ
diff --git a/rom.h b/rom.h
index 0de3612..34d3115 100644
--- a/rom.h
+++ b/rom.h
@@ -9,6 +9,6 @@ struct rom {
unsigned int size;
};
-extern const struct rom abcrom40, abcrom80, abcdev, ufddos;
+extern const struct rom abcrom40, abcrom80, printer, ufddos;
#endif /* ROM_H */
diff --git a/ufddos.bin b/ufddos.bin
index 5aeea6c..1598f48 100644
--- a/ufddos.bin
+++ b/ufddos.bin
Binary files differ