From 7b3fdf571844435cae8c963b944da6d80b91a82b Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Fri, 3 Apr 2015 17:33:24 -0700 Subject: [PATCH] I1401: Bob Supnik added options to read cards and print line printer output from the console terminal window. --- I1401/i1401_cd.c | 186 ++++++++++++++++++++++++++++++++++++++-------- I1401/i1401_cpu.c | 1 - I1401/i1401_dp.c | 2 +- I1401/i1401_iq.c | 21 +++--- I1401/i1401_lp.c | 79 +++++++++++++------- 5 files changed, 222 insertions(+), 67 deletions(-) diff --git a/I1401/i1401_cd.c b/I1401/i1401_cd.c index 255dccd5..1a56f930 100644 --- a/I1401/i1401_cd.c +++ b/I1401/i1401_cd.c @@ -1,6 +1,6 @@ /* i1401_cd.c: IBM 1402 card reader/punch - Copyright (c) 1993-2010, Robert M. Supnik + Copyright (c) 1993-2015, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -35,6 +35,7 @@ Cards are represented as ASCII text streams terminated by newlines. This allows cards to be created and edited as normal files. + 28-Feb-15 RMS Added read from console 24-Mar-09 RMS Fixed read stacker operation in column binary mode Fixed punch stacker operation (Van Snyder) 28-Jun-07 RMS Added support for SS overlap modifiers @@ -50,11 +51,47 @@ 13-Apr-01 RMS Revised for register arrays */ +/* Read from console was requested by the 1401 restoration team at the + Computer History Museum. It allows small programs to be entered + quickly, without creating card files. Unfortunately, if input is + coming from the keyboard, then the card reader is not attached, + and it won't boot. + + To deal with this problem, the card reader must keep various + unit flags in a consistent state: + + ATTABLE? ATT? DFLT? state + + 0 0 0 impossible + 0 0 1 input from console + 0 1 0 impossible + 0 1 1 impossible + 1 0 0 waiting for file + 1 0 1 impossible + 1 1 0 input from file + 1 1 1 input from file, + default to console + after detach + + To maintain this state, starting from 100, means the + following: + + SET CDR DFLT set default flag + if !ATT, clear ATTABLE + SET CDR NODFLT clear default flag + ATTACH CDR set ATTABLE, attach + if error && DFLT, clear ATTABLE + DETACH CDR detach + if DFLT, clear ATTABLE +*/ + #include "i1401_defs.h" #include #define UNIT_V_PCH (UNIT_V_UF + 0) /* output conv */ #define UNIT_PCH (1 << UNIT_V_PCH) +#define UNIT_V_CONS (UNIT_V_UF + 1) /* input from console */ +#define UNIT_CONS (1 << UNIT_V_CONS) extern uint8 M[]; extern int32 ind[64], ssa, iochk; @@ -68,13 +105,19 @@ int32 cdp_buf_full = 0; /* punch buf full? */ t_stat cdr_svc (UNIT *uptr); t_stat cdr_boot (int32 unitno, DEVICE *dptr); t_stat cdr_attach (UNIT *uptr, char *cptr); +t_stat cdr_detach (UNIT *uptr); t_stat cdp_attach (UNIT *uptr, char *cptr); t_stat cdp_detach (UNIT *uptr); t_stat cdp_npr (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat cd_reset (DEVICE *dptr); +t_stat cdr_read_file (char *buf, int32 sz); +t_stat cdr_read_cons (char *buf, int32 sz); +t_stat cdr_chg_cons (UNIT *uptr, int32 val, char *cptr, void *desc); int32 bcd2asc (int32 c, UNIT *uptr); char colbin_to_bcd (uint32 cb); +extern void inq_puts (char *cptr); + /* Card reader data structures cdr_dev CDR descriptor @@ -97,11 +140,17 @@ REG cdr_reg[] = { { NULL } }; +MTAB cdr_mod[] = { + { UNIT_CONS, UNIT_CONS, "default to console", "DEFAULT", &cdr_chg_cons }, + { UNIT_CONS, 0 , "no default device", "NODEFAULT", &cdr_chg_cons }, + { 0 } + }; + DEVICE cdr_dev = { - "CDR", &cdr_unit, cdr_reg, NULL, + "CDR", &cdr_unit, cdr_reg, cdr_mod, 1, 10, 31, 1, 8, 7, NULL, NULL, &cd_reset, - &cdr_boot, &cdr_attach, NULL + &cdr_boot, &cdr_attach, &cdr_detach }; /* CDP data structures @@ -130,7 +179,6 @@ MTAB cdp_mod[] = { { UNIT_PCH, UNIT_PCH, "Fortran set", "FORTRAN" }, { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, NULL, "NPR", &cdp_npr, NULL }, - { 0 } }; @@ -179,7 +227,7 @@ DEVICE stack_dev = { t_stat read_card (int32 ilnt, int32 mod) { -int32 i, cbn, c1, c2; +int32 i, cbn, c1, c2, cbufsz; t_stat r; if (sim_is_active (&cdr_unit)) { /* busy? */ @@ -187,32 +235,19 @@ if (sim_is_active (&cdr_unit)) { /* busy? */ if ((r = cdr_svc (&cdr_unit))) /* process */ return r; } -if ((cdr_unit.flags & UNIT_ATT) == 0) /* attached? */ - return SCPE_UNATT; ind[IN_READ] = ind[IN_LST] = s1sel = s2sel = 0; /* default stacker */ cbn = ((ilnt == 2) || (ilnt == 5)) && (mod == BCD_C); /* col binary? */ +cbufsz = (cbn)? 2 * CBUFSIZE: CBUFSIZE; /* buffer size */ for (i = 0; i < (2 * CBUFSIZE) + 1; i++) /* clear extended buf */ cdr_buf[i] = 0; -fgets (cdr_buf, (cbn)? 2 * CBUFSIZE: CBUFSIZE, /* rd bin/char card */ - cdr_unit.fileref); -if (feof (cdr_unit.fileref)) /* eof? */ - return STOP_NOCD; -if (ferror (cdr_unit.fileref)) { /* error? */ - ind[IN_READ] = 1; - perror ("Card reader I/O error"); - clearerr (cdr_unit.fileref); - if (iochk) - return SCPE_IOERR; - return SCPE_OK; - } -cdr_unit.pos = ftell (cdr_unit.fileref); /* update position */ -if (ssa) { /* if last cd on */ - getc (cdr_unit.fileref); /* see if more */ - if (feof (cdr_unit.fileref)) /* eof? set flag */ - ind[IN_LST] = 1; - fseek (cdr_unit.fileref, cdr_unit.pos, SEEK_SET); - } -if (cbn) { /* column binary */ +if ((cdr_unit.flags & UNIT_ATT) != 0) /* attached? */ + r = cdr_read_file (cdr_buf, cbufsz); /* read from file */ +else if ((cdr_unit.flags & UNIT_CONS) != 0) /* default to console? */ + r = cdr_read_cons (cdr_buf, cbufsz); /* read from console */ +else return SCPE_UNATT; /* else can't read */ +if (r != SCPE_OK) /* read error? */ + return r; /* can't read */ +if (cbn) { /* column binary? */ for (i = 0; i < CDR_WIDTH; i++) { if (conv_old) { c1 = ascii2bcd (cdr_buf[i]); @@ -225,7 +260,7 @@ if (cbn) { /* column binary */ M[CD_CBUF1 + i] = (M[CD_CBUF1 + i] & WM) | c1; M[CD_CBUF2 + i] = (M[CD_CBUF2 + i] & WM) | c2; M[CDR_BUF + i] = colbin_to_bcd ((c1 << 6) | c2); - } /* end for i */ + } } /* end if col bin */ else { /* normal read */ for (i = 0; i < CDR_WIDTH; i++) { /* cvt to BCD */ @@ -369,6 +404,64 @@ else if (mod == BCD_EIGHT) return SCPE_OK; } +/* Read card from file */ + +t_stat cdr_read_file (char *buf, int32 sz) +{ +fgets (buf, sz, cdr_unit.fileref); /* rd bin/char card */ +if (feof (cdr_unit.fileref)) /* eof? */ + return STOP_NOCD; +if (ferror (cdr_unit.fileref)) { /* error? */ + ind[IN_READ] = 1; + perror ("Card reader I/O error"); + clearerr (cdr_unit.fileref); + if (iochk) + return SCPE_IOERR; + return SCPE_OK; + } +cdr_unit.pos = ftell (cdr_unit.fileref); /* update position */ +if (ssa) { /* if last cd on */ + getc (cdr_unit.fileref); /* see if more */ + if (feof (cdr_unit.fileref)) /* eof? set flag */ + ind[IN_LST] = 1; + fseek (cdr_unit.fileref, cdr_unit.pos, SEEK_SET); + } +return SCPE_OK; +} + +/* Read card from console */ + +t_stat cdr_read_cons (char *buf, int32 sz) +{ +int32 i, t; + +inq_puts ("[Enter card]\r\n"); +for (i = 0; i < sz; ) { + while (((t = sim_poll_kbd ()) == SCPE_OK) || /* wait for char */ + (t & SCPE_BREAK)) { + if (stop_cpu) /* stop? */ + return t; + } + if (t < SCPE_KFLAG) /* error? */ + return t; + t = t & 0177; + if ((t == '\r') || (t == '\n')) /* eol? */ + break; + if (t == 0177) { /* rubout? */ + if (i != 0) { /* anything? */ + buf[--i] = 0; + sim_putchar ('\\'); + } + } + else { + sim_putchar (t); + buf[i++] = t; + } + } +inq_puts ("\r\n"); +return SCPE_OK; +} + /* Card reader/punch reset */ t_stat cd_reset (DEVICE *dptr) @@ -379,12 +472,45 @@ sim_cancel (&cdr_unit); /* clear reader event */ return SCPE_OK; } +/* Set/clear default to console flag + + Caller will do actual bit field update on successful return */ + +t_stat cdr_chg_cons (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +if (val == 0) /* clear? */ + cdr_unit.flags |= UNIT_ATTABLE; /* attachable on */ +else if ((cdr_unit.flags & UNIT_ATT) == 0) /* set, unattached? */ + cdr_unit.flags &= ~UNIT_ATTABLE; /* attachable off */ +return SCPE_OK; +} + /* Card reader attach */ t_stat cdr_attach (UNIT *uptr, char *cptr) { +t_stat r; + ind[IN_LST] = ind[IN_READ] = 0; /* clear last card */ -return attach_unit (uptr, cptr); +cdr_unit.flags |= UNIT_ATTABLE; /* must be attachable */ +r = attach_unit (uptr, cptr); /* do attach */ +if ((r != SCPE_OK) && ((cdr_unit.flags & UNIT_CONS) != 0)) /* failed, default? */ + cdr_unit.flags &= ~UNIT_ATTABLE; /* clear attachable */ +return r; +} + +/* Card reader detach */ + +t_stat cdr_detach (UNIT *uptr) +{ +t_stat r; + +cdr_unit.flags |= UNIT_ATTABLE; /* must be attachable */ +r = detach_unit (uptr); /* detach */ +if (((cdr_unit.flags & UNIT_ATT) == 0) && /* attached clear? */ + ((cdr_unit.flags & UNIT_CONS) != 0)) /* default on? */ + cdr_unit.flags &= ~UNIT_ATTABLE; /* clear attachable */ +return r; } /* Bootstrap routine */ @@ -398,7 +524,7 @@ static const unsigned char boot_rom[] = { t_stat cdr_boot (int32 unitno, DEVICE *dptr) { -size_t i; +int32 i; extern int32 saved_IS; for (i = 0; i < CDR_WIDTH; i++) /* clear buffer */ diff --git a/I1401/i1401_cpu.c b/I1401/i1401_cpu.c index e78b624c..4f1c6839 100644 --- a/I1401/i1401_cpu.c +++ b/I1401/i1401_cpu.c @@ -207,7 +207,6 @@ InstHistory *hst = NULL; /* instruction history * t_bool conv_old = 0; /* old conversions */ extern int32 sim_emax; -extern t_value *sim_eval; t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); diff --git a/I1401/i1401_dp.c b/I1401/i1401_dp.c index d45c8287..8bc139ed 100644 --- a/I1401/i1401_dp.c +++ b/I1401/i1401_dp.c @@ -269,7 +269,7 @@ switch (fnc) { /* case on function */ for (;;) { /* loop */ qzr = (--cnt == 0); /* set zero latch */ dp_cvt_bin (dcf + DCF_CNT, DCF_CNT_LEN, cnt, MD_WM); /* redo count */ - if ((r = dp_rdsec (uptr, psec, flg, qwc))) /* read sector */ + if ((r = dp_rdsec (uptr, psec, flg, qwc))) /* read sector */ break; cnt = dp_get_cnt (dcf); /* get new count */ if (cnt < 0) /* bad count? */ diff --git a/I1401/i1401_iq.c b/I1401/i1401_iq.c index 99556db6..d1e32a5f 100644 --- a/I1401/i1401_iq.c +++ b/I1401/i1401_iq.c @@ -1,6 +1,6 @@ /* i1401_iq.c: IBM 1407 inquiry terminal - Copyright (c) 1993-2008, Robert M. Supnik + Copyright (c) 1993-2015, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,7 @@ inq 1407 inquiry terminal + 08-Mar-15 RMS Renamed puts_tty to inq_puts 20-Sep-05 RMS Revised for new code tables 22-Dec-02 RMS Added break support 07-Sep-01 RMS Moved function prototypes @@ -47,7 +48,7 @@ int32 inq_char = 033; /* request inq */ t_stat inq_svc (UNIT *uptr); t_stat inq_reset (DEVICE *dptr); -void puts_tty (char *cptr); +void inq_puts (char *cptr); /* INQ data structures @@ -96,7 +97,7 @@ switch (mod) { /* case on mod */ /* if (ind[IN_INR] == 0) */ /* return SCPE_OK; *//* return if no req */ ind[IN_INR] = 0; /* clear req */ - puts_tty ("[Enter]\r\n"); /* prompt */ + inq_puts ("[Enter]\r\n"); /* prompt */ for (i = 0; M[BS] != (BCD_GRPMRK + WM); i++) { /* until GM + WM */ while (((t = sim_poll_kbd ()) == SCPE_OK) || (t & SCPE_BREAK)) { @@ -110,11 +111,11 @@ switch (mod) { /* case on mod */ break; if (t == inq_char) { /* cancel? */ ind[IN_INC] = 1; /* set indicator */ - puts_tty ("\r\n[Canceled]\r\n"); + inq_puts ("\r\n[Canceled]\r\n"); return SCPE_OK; } if (i && ((i % INQ_WIDTH) == 0)) - puts_tty ("\r\n"); + inq_puts ("\r\n"); sim_putchar (t); /* echo */ if (flag == MD_WM) { /* word mark mode? */ if ((t == '~') && (wm_seen == 0)) @@ -132,7 +133,7 @@ switch (mod) { /* case on mod */ return STOP_NXM; } } - puts_tty ("\r\n"); + inq_puts ("\r\n"); M[BS++] = BCD_GRPMRK + WM; break; @@ -140,20 +141,20 @@ switch (mod) { /* case on mod */ for (i = 0; (t = M[BS++]) != (BCD_GRPMRK + WM); i++) { if ((flag == MD_WM) && (t & WM)) { if (i && ((i % INQ_WIDTH) == 0)) - puts_tty ("\r\n"); + inq_puts ("\r\n"); if (conv_old) sim_putchar ('~'); else sim_putchar ('`'); } if (i && ((i % INQ_WIDTH) == 0)) - puts_tty ("\r\n"); + inq_puts ("\r\n"); sim_putchar (bcd2ascii (t & CHAR, use_h)); if (ADDR_ERR (BS)) { BS = BA | (BS % MAXMEMSIZE); return STOP_NXM; } } - puts_tty ("\r\n"); + inq_puts ("\r\n"); break; default: /* invalid mod */ @@ -179,7 +180,7 @@ return SCPE_OK; /* Output multiple characters */ -void puts_tty (char *cptr) +void inq_puts (char *cptr) { if (cptr == NULL) return; diff --git a/I1401/i1401_lp.c b/I1401/i1401_lp.c index cec020da..64dd2522 100644 --- a/I1401/i1401_lp.c +++ b/I1401/i1401_lp.c @@ -1,6 +1,6 @@ /* i1401_lp.c: IBM 1403 line printer simulator - Copyright (c) 1993-2013, Robert M. Supnik + Copyright (c) 1993-2015, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,7 @@ lpt 1403 line printer + 08-Mar-15 RMS Added print to console option 16-Apr-13 RMS Fixed printer chain selection 19-Jan-07 RMS Added UNIT_TEXT flag 07-Mar-05 RMS Fixed bug in write_line (Van Snyder) @@ -48,6 +49,9 @@ int32 cctlnt = 66, cctptr = 0, lines = 0, lflag = 0; t_stat lpt_reset (DEVICE *dptr); t_stat lpt_attach (UNIT *uptr, char *cptr); t_stat space (int32 lines, int32 lflag); +t_stat lpt_puts (char *buf); + +extern void inq_puts (char *buf); char *pch_table_old[4] = { bcd_to_ascii_old, bcd_to_ascii_old, bcd_to_pca, bcd_to_pch @@ -58,8 +62,10 @@ char *pch_table[4] = { #define UNIT_V_FT (UNIT_V_UF + 0) #define UNIT_V_48 (UNIT_V_UF + 1) +#define UNIT_V_CONS (UNIT_V_UF + 2) #define UNIT_FT (1 << UNIT_V_FT) #define UNIT_48 (1 << UNIT_V_48) +#define UNIT_CONS (1 << UNIT_V_CONS) #define GET_PCHAIN(x) (((x) >> UNIT_V_FT) & 03) #define CHP(ch,val) ((val) & (1 << (ch))) @@ -89,6 +95,8 @@ MTAB lpt_mod[] = { { UNIT_48, 0, "64 character chain", "64" }, { UNIT_FT, UNIT_FT, "Fortran set", "FORTRAN" }, { UNIT_FT, 0, "business set", "BUSINESS" }, + { UNIT_CONS, UNIT_CONS, "default to console", "DEFAULT" }, + { UNIT_CONS, 0 , "no default device", "NODEFAULT" }, { UNIT_FT|UNIT_48, 0, NULL, "PCF" }, /* obsolete */ { UNIT_FT|UNIT_48, UNIT_48, NULL, "PCA" }, { UNIT_FT|UNIT_48, UNIT_FT|UNIT_48, NULL, "PCH" }, @@ -113,10 +121,9 @@ t_stat write_line (int32 ilnt, int32 mod) { int32 i, t, wm, sup; char *bcd2asc; +t_stat r; static char lbuf[LPT_WIDTH + 1]; /* + null */ -if ((lpt_unit.flags & UNIT_ATT) == 0) /* attached? */ - return SCPE_UNATT; wm = ((ilnt == 2) || (ilnt == 5)) && (mod == BCD_SQUARE); sup = ((ilnt == 2) || (ilnt == 5)) && (mod == BCD_S); ind[IN_LPT] = 0; /* clear error */ @@ -133,24 +140,15 @@ for (i = 0; i < LPT_WIDTH; i++) { /* convert print buf */ lbuf[LPT_WIDTH] = 0; /* trailing null */ for (i = LPT_WIDTH - 1; (i >= 0) && (lbuf[i] == ' '); i--) lbuf[i] = 0; -fputs (lbuf, lpt_unit.fileref); /* write line */ +if ((r = lpt_puts (lbuf)) != SCPE_OK) /* write line */ + return r; /* error? */ if (lines) /* cc action? do it */ - space (lines, lflag); + r = space (lines, lflag); else if (sup == 0) /* default? 1 line */ - space (1, FALSE); -else { - fputc ('\r', lpt_unit.fileref); /* sup -> overprint */ - lpt_unit.pos = ftell (lpt_unit.fileref); /* update position */ - } + r = space (1, FALSE); +else r = lpt_puts ("\r"); /* sup -> overprint */ lines = lflag = 0; /* clear cc action */ -if (ferror (lpt_unit.fileref)) { /* error? */ - ind[IN_LPT] = 1; - perror ("Line printer I/O error"); - clearerr (lpt_unit.fileref); - if (iochk) - return SCPE_IOERR; - } -return SCPE_OK; +return r; } /* Carriage control routine @@ -221,20 +219,51 @@ return SCPE_OK; t_stat space (int32 count, int32 sflag) { int32 i; +t_stat r; -if ((lpt_unit.flags & UNIT_ATT) == 0) - return SCPE_UNATT; cctptr = (cctptr + count) % cctlnt; /* adv cct, mod lnt */ if (sflag && CHP (0, cct[cctptr])) /* skip, top of form? */ - fputs ("\n\f", lpt_unit.fileref); /* nl, ff */ + r = lpt_puts ("\n\f"); /* nl, ff */ else { - for (i = 0; i < count; i++) - fputc ('\n', lpt_unit.fileref); + for (i = 0; (i < count); i++) + if ((r = lpt_puts ("\n")) != SCPE_OK) + break; } -lpt_unit.pos = ftell (lpt_unit.fileref); /* update position */ ind[IN_CC9] = CHP (9, cct[cctptr]) != 0; /* set indicators */ ind[IN_CC12] = CHP (12, cct[cctptr]) != 0; -return SCPE_OK; +return r; +} + + +/* Centralized string print routine + Prints to either a file or the console + + Note that if printing to the console, newline must be converted to crlf */ + +t_stat lpt_puts (char *buf) +{ +if ((lpt_unit.flags & UNIT_ATT) != 0) { /* attached? */ + fputs (buf, lpt_unit.fileref); /* print string */ + if (ferror (lpt_unit.fileref)) { /* error? */ + ind[IN_LPT] = 1; + perror ("Line printer I/O error"); + clearerr (lpt_unit.fileref); + if (iochk) + return SCPE_IOERR; + } + lpt_unit.pos = ftell (lpt_unit.fileref); /* update position */ + return SCPE_OK; + } +if ((lpt_unit.flags & UNIT_CONS) != 0) { /* default to cons? */ + if (buf[0] == '\n') { /* bare lf? */ + inq_puts ("\r"); /* cvt to crlf */ + lpt_unit.pos = lpt_unit.pos + 1; + } + inq_puts (buf); + lpt_unit.pos = lpt_unit.pos + strlen (buf); + return SCPE_OK; + } +return SCPE_UNATT; } /* Reset routine */