From 7029542b08d2376f986e2b53aac4f79e1fdeb833 Mon Sep 17 00:00:00 2001 From: Richard Cornwell Date: Fri, 15 Mar 2019 18:37:38 -0400 Subject: [PATCH] KA10: Added line buffering, and forms control support to LP. --- PDP10/ka10_lp.c | 258 +++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 209 insertions(+), 49 deletions(-) diff --git a/PDP10/ka10_lp.c b/PDP10/ka10_lp.c index 1843442..8047546 100644 --- a/PDP10/ka10_lp.c +++ b/PDP10/ka10_lp.c @@ -36,11 +36,15 @@ #define LP_DEVNUM 0124 #define STATUS u3 -#define CHL u4 -#define CHR u5 +#define COL u4 +#define POS u5 +#define LINE u6 + +#define UNIT_V_CT (UNIT_V_UF + 0) +#define UNIT_UC (1 << UNIT_V_CT) +#define UNIT_UTF8 (2 << UNIT_V_CT) +#define UNIT_CT (3 << UNIT_V_CT) -#define UNIT_V_UC (UNIT_V_UF + 0) -#define UNIT_UC (1 << UNIT_V_UC) #define PI_DONE 000007 #define PI_ERROR 000070 #define DONE_FLG 000100 @@ -49,6 +53,7 @@ #define CLR_LPT 002000 #define C96 002000 #define C128 004000 +#define DEL_FLG 0100000 @@ -62,6 +67,9 @@ t_stat lpt_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *lpt_description (DEVICE *dptr); int32 lpt_stopioe; +char lpt_buffer[134 * 3]; +uint8 lpt_chbuf[5]; /* Read in Character buffers */ + /* LPT data structures lpt_dev LPT device descriptor @@ -72,19 +80,22 @@ int32 lpt_stopioe; DIB lpt_dib = { LP_DEVNUM, 1, &lpt_devio, NULL }; UNIT lpt_unit = { - UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_TEXT, 0), SERIAL_OUT_WAIT + UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_TEXT, 0), 100 }; REG lpt_reg[] = { { DRDATA (STATUS, lpt_unit.STATUS, 18), PV_LEFT }, { DRDATA (TIME, lpt_unit.wait, 24), PV_LEFT }, { FLDATA (STOP_IOE, lpt_stopioe, 0) }, + { BRDATA(BUFF, lpt_buffer, 16, 8, sizeof(lpt_buffer)), REG_HRO}, + { BRDATA(CBUFF, lpt_chbuf, 16, 8, sizeof(lpt_chbuf)), REG_HRO}, { NULL } }; MTAB lpt_mod[] = { - {UNIT_UC, 0, "Lower case", "LC", NULL}, - {UNIT_UC, UNIT_UC, "Upper case", "UC", NULL}, + {UNIT_CT, 0, "Lower case", "LC", NULL}, + {UNIT_CT, UNIT_UC, "Upper case", "UC", NULL}, + {UNIT_CT, UNIT_UTF8, "UTF8 ouput", "UTF8", NULL}, { 0 } }; @@ -103,9 +114,11 @@ t_stat lpt_devio(uint32 dev, uint64 *data) { UNIT *uptr = &lpt_unit; switch(dev & 3) { case CONI: - *data = uptr->STATUS; + *data = uptr->STATUS & (PI_DONE|PI_ERROR|DONE_FLG|BUSY_FLG|ERR_FLG); if ((uptr->flags & UNIT_UC) == 0) *data |= C96; + if ((uptr->flags & UNIT_UTF8) == 0) + *data |= C128; if ((uptr->flags & UNIT_ATT) == 0) *data |= ERR_FLG; sim_debug(DEBUG_CONI, &lpt_dev, "LP CONI %012llo PC=%06o\n", *data, PC); @@ -114,31 +127,32 @@ t_stat lpt_devio(uint32 dev, uint64 *data) { case CONO: clr_interrupt(dev); sim_debug(DEBUG_CONO, &lpt_dev, "LP CONO %012llo PC=%06o\n", *data, PC); - uptr->STATUS = ((PI_DONE|PI_ERROR|DONE_FLG|BUSY_FLG) & *data); + uptr->STATUS &= ~0777; + uptr->STATUS |= ((PI_DONE|PI_ERROR|DONE_FLG|BUSY_FLG|CLR_LPT) & *data); if (*data & CLR_LPT) { - uptr->CHR = 0; - uptr->CHL = 0; + uptr->STATUS &= ~DONE_FLG; uptr->STATUS |= BUSY_FLG; sim_activate (&lpt_unit, lpt_unit.wait); } if ((uptr->flags & UNIT_ATT) == 0) { + uptr->STATUS |= ERR_FLG; set_interrupt(dev, (uptr->STATUS >> 3)); } - if (uptr->STATUS & DONE_FLG) + if ((uptr->STATUS & DONE_FLG) != 0) set_interrupt(dev, uptr->STATUS); break; case DATAO: - if ((uptr->STATUS & BUSY_FLG) == 0) { - uptr->CHL = (int32)(*data >> 15); - uptr->CHR = (*data >> 1) & 0037777; - uptr->STATUS |= BUSY_FLG; + if ((uptr->STATUS & DONE_FLG) != 0) { + int i, j; + for (j = 0, i = 29; i > 0; i-=7) + lpt_chbuf[j++] = ((uint8)(*data >> i)) & 0x7f; uptr->STATUS &= ~DONE_FLG; + uptr->STATUS |= BUSY_FLG; clr_interrupt(dev); sim_activate (&lpt_unit, lpt_unit.wait); - } - sim_debug(DEBUG_DATAIO, &lpt_dev, "LP DATO %012llo, %06o %06o PC=%06o\n", - *data, uptr->CHL, uptr->CHR, PC); + sim_debug(DEBUG_DATAIO, &lpt_dev, "LP DATO %012llo PC=%06o\n", *data, PC); + } break; case DATAI: *data = 0; @@ -147,53 +161,198 @@ t_stat lpt_devio(uint32 dev, uint64 *data) { return SCPE_OK; } - -/* Unit service */ -t_stat lpt_output(UNIT *uptr, char c) { - if (c == 0) - return SCPE_OK; - if (uptr->flags & UNIT_UC) - c = toupper(c); - fputc (c, uptr->fileref); /* print char */ - uptr->pos = ftell (uptr->fileref); + +void +lpt_printline(UNIT *uptr, int nl) { + int trim = 0; + /* Trim off trailing blanks */ + while (uptr->COL >= 0 && lpt_buffer[uptr->POS - 1] == ' ') { + uptr->COL--; + uptr->POS--; + trim = 1; + } + lpt_buffer[uptr->POS] = '\0'; + sim_debug(DEBUG_DETAIL, &lpt_dev, "LP output %d %d [%s]\n", uptr->COL, nl, lpt_buffer); + /* Stick a carraige return and linefeed as needed */ + if (uptr->COL != 0 || trim) + lpt_buffer[uptr->POS++] = '\r'; + if (nl) { + lpt_buffer[uptr->POS++] = '\n'; + uptr->LINE++; + } + sim_fwrite(&lpt_buffer, 1, uptr->POS, uptr->fileref); + uptr->COL = 0; + uptr->POS = 0; if (ferror (uptr->fileref)) { /* error? */ perror ("LPT I/O error"); clearerr (uptr->fileref); uptr->STATUS |= ERR_FLG; set_interrupt(LP_DEVNUM, (uptr->STATUS >> 3)); - return SCPE_IOERR; + return; } - return SCPE_OK; + return; +} + +uint16 utf_code[32] = { + 0x0000, /* Dot */ + 0x2193, /* Down arrow */ + 0x237a, /* APL Alpha */ + 0x03b2, /* Beta */ + 0x039b, /* Lambda */ + 0x2510, /* Box light down and left */ + 0x03b5, /* Epsilon */ + 0x03d6, /* Pi */ + 0x03bb, /* Lambda */ + 0x221d, /* proportional */ + 0x222b, /* Integral */ + 0x00b1, /* Plus minus */ + 0x2295, /* Circle plus */ + 0x221e, /* Infinity */ + 0x2202, /* Partial derivitive */ + 0x2282, /* Subset of */ + 0x2283, /* Superset of */ + 0x2229, /* Intersection */ + 0x222a, /* union */ + 0x2200, /* For all */ + 0x2203, /* Exists */ + 0x2295, /* Circle plus */ + 0x2194, /* Left right arrow */ + 0x2227, /* Logical and */ + 0x2192, /* Rightwards arror */ + 0x2014, /* Em dash */ + 0x2260, /* Not equal */ + 0x2264, /* Less than or equal */ + 0x2265, /* Greater than or equal */ + 0x2261, /* Identical too */ + 0x2228 /* Logical or */ + }; + +/* Unit service */ +void +lpt_output(UNIT *uptr, char c) { + + if (c == 0) + return; + if ((uptr->flags & UNIT_UC) && (c & 0140) == 0140) + c &= 0137; + if ((uptr->flags & UNIT_UTF8) && c < 040) { + uint16 u = utf_code[c & 0x1f]; + if (u > 0x7ff) { + lpt_buffer[uptr->POS++] = 0xe0 + ((u >> 12) & 0xf); + lpt_buffer[uptr->POS++] = 0x80 + ((u >> 6) & 0x3f); + lpt_buffer[uptr->POS++] = 0x80 + (u & 0x3f); + } else if (u > 0x7f) { + lpt_buffer[uptr->POS++] = 0xc0 + ((u >> 6) & 0x3f); + lpt_buffer[uptr->POS++] = 0x80 + (u & 0x3f); + } else { + lpt_buffer[uptr->POS++] = u & 0x7f; + } + uptr->COL++; + } else if (c >= 040) { + lpt_buffer[uptr->POS++] = c; + uptr->COL++; + } + if (uptr->COL == 132) + lpt_printline(uptr, 1); + return; } t_stat lpt_svc (UNIT *uptr) { t_stat r; char c; + int pos; + int cpos; + + if ((uptr->flags & DONE_FLG) != 0) { + set_interrupt(LP_DEVNUM, uptr->STATUS); + return SCPE_OK; + } if ((uptr->flags & UNIT_ATT) == 0) { uptr->STATUS |= ERR_FLG; + set_interrupt(LP_DEVNUM, (uptr->STATUS >> 3)); return SCPE_OK; } - c = (uptr->CHL >> 14) & 0177; - if ((r = lpt_output(uptr, c)) != SCPE_OK) - return r; - c = (uptr->CHL >> 7) & 0177; - if ((r = lpt_output(uptr, c)) != SCPE_OK) - return r; - c = uptr->CHL & 0177; - if ((r = lpt_output(uptr, c)) != SCPE_OK) - return r; - c = (uptr->CHR >> 7) & 0177; - if ((r = lpt_output(uptr, c)) != SCPE_OK) - return r; - c = uptr->CHR & 0177; - if ((r = lpt_output(uptr, c)) != SCPE_OK) - return r; + if (uptr->STATUS & CLR_LPT) { + for (pos = 0; pos < uptr->COL; lpt_buffer[pos++] = ' '); + uptr->POS = uptr->COL; + lpt_printline(uptr, 0); + uptr->STATUS &= ~(DEL_FLG|ERR_FLG|BUSY_FLG|CLR_LPT); + uptr->STATUS |= DONE_FLG; + set_interrupt(LP_DEVNUM, uptr->STATUS); + return SCPE_OK; + } + + for (cpos = 0; cpos < 5; cpos++) { + c = lpt_chbuf[cpos]; + if (uptr->STATUS & DEL_FLG) { + lpt_output(uptr, c); + uptr->STATUS &= ~DEL_FLG; + } else if (c == 0177) { /* Check for DEL Character */ + uptr->STATUS |= DEL_FLG; + } else if (c < 040) { /* Control character */ + switch(c) { + case 011: /* Horizontal tab, space to 8'th column */ + lpt_output(uptr, ' '); + while ((uptr->COL & 07) != 0) + lpt_output(uptr, ' '); + break; + case 015: /* Carriage return, print line */ + lpt_printline(uptr, 0); + break; + case 012: /* Line feed, print line, space one line */ + lpt_printline(uptr, 1); + uptr->LINE++; + break; + case 014: /* Form feed, skip to top of page */ + lpt_printline(uptr, 0); + sim_fwrite("\014", 1, 1, uptr->fileref); + uptr->LINE = 0; + break; + case 013: /* Vertical tab, Skip mod 20 */ + lpt_printline(uptr, 1); + while((uptr->LINE % 20) != 0) { + sim_fwrite("\r\n", 1, 2, uptr->fileref); + uptr->LINE++; + } + break; + case 020: /* Skip even lines */ + lpt_printline(uptr, 1); + while((uptr->LINE % 2) != 0) { + sim_fwrite("\r\n", 1, 2, uptr->fileref); + uptr->LINE++; + } + break; + case 021: /* Skip third lines */ + lpt_printline(uptr, 1); + while((uptr->LINE % 3) != 0) { + sim_fwrite("\r\n", 1, 2, uptr->fileref); + uptr->LINE++; + } + break; + case 022: /* Skip one line */ + lpt_printline(uptr, 1); + sim_fwrite("\r\n", 1, 2, uptr->fileref); + uptr->LINE+=2; + break; + case 023: /* Skip every 10 lines */ + lpt_printline(uptr, 1); + while((uptr->LINE % 10) != 0) { + sim_fwrite("\r\n", 1, 2, uptr->fileref); + uptr->LINE++; + } + break; + default: /* Ignore */ + break; + } + } else { + lpt_output(uptr, c); + } + } uptr->STATUS &= ~BUSY_FLG; uptr->STATUS |= DONE_FLG; set_interrupt(LP_DEVNUM, uptr->STATUS); - //fprintf(stderr, "LP IRQ\n\r"); return SCPE_OK; } @@ -202,9 +361,10 @@ t_stat lpt_svc (UNIT *uptr) t_stat lpt_reset (DEVICE *dptr) { UNIT *uptr = &lpt_unit; - uptr->CHR = 0; - uptr->CHL = 0; - uptr->STATUS = 0; + uptr->POS = 0; + uptr->COL = 0; + uptr->LINE = 1; + uptr->STATUS = DONE_FLG; clr_interrupt(LP_DEVNUM); sim_cancel (&lpt_unit); /* deactivate unit */ return SCPE_OK;