1
0
mirror of https://github.com/simh/simh.git synced 2026-02-16 20:52:19 +00:00

Notes For V3.7-0

1. New Features

1.1 3.7-0

1.1.1 SCP

- Added SET THROTTLE and SET NOTHROTTLE commands to regulate simulator
  execution rate and host resource utilization.
- Added idle support (based on work by Mark Pizzolato).
- Added -e to control error processing in nested DO commands (from
  Dave Bryan).

1.1.2 HP2100

- Added Double Integer instructions, 1000-F CPU, and Floating Point
  Processor (from Dave Bryan).
- Added 2114 and 2115 CPUs, 12607B and 12578A DMA controllers, and
  21xx binary loader protection (from Dave Bryan).

1.1.3 Interdata

- Added SET IDLE and SET NOIDLE commands to idle the simulator in wait
  state.

1.1.4 PDP-11

- Added SET IDLE and SET NOIDLE commands to idle the simulator in wait
  state (WAIT instruction executed).
- Added TA11/TU60 cassette support.

1.1.5 PDP-8

- Added SET IDLE and SET NOIDLE commands to idle the simulator in wait
  state (keyboard poll loop or jump-to-self).
- Added TA8E/TU60 cassette support.

1.1.6 PDP-1

- Added support for 16-channel sequence break system.
- Added support for PDP-1D extended features and timesharing clock.
- Added support for Type 630 data communications subsystem.

1.1.6 PDP-4/7/9/15

- Added SET IDLE and SET NOIDLE commands to idle the simulator in wait
  state (keyboard poll loop or jump-to-self).

1.1.7 VAX, VAX780

- Added SET IDLE and SET NOIDLE commands to idle the simulator in wait
  state (more than 200 cycles at IPL's 0, 1, or 3 in kernel mode).

1.1.8 PDP-10

- Added SET IDLE and SET NOIDLE commands to idle the simulator in wait
  state (operating system dependent).
- Added CD20 (CD11) support.

2. Bugs Fixed

Please see the revision history on http://simh.trailing-edge.com or
in the source module sim_rev.h.
This commit is contained in:
Bob Supnik
2007-02-03 14:59:00 -08:00
committed by Mark Pizzolato
parent 15919a2dd7
commit 53d02f7fa7
161 changed files with 18604 additions and 6903 deletions

View File

@@ -1,4 +1,4 @@
// DMS R2V12 SLET without RPG, for debugging only
/* DMS R2V12 SLET without RPG, for debugging only */
0x0001, 0x7c50, 0x032f, 0x0008,
0x0002, 0x11de, 0x05a2, 0x000b,

View File

@@ -9,15 +9,17 @@
* Mail to sim@ibm1130.org
*/
// 03 ctrl-C => Program stop (not handled here)
// 05 ctrl-E => Simulator stop (not handled here)
// 08 ctrl-H => Backspace
// 0D ctrl-M (Enter) => EOF
// 11 ctrl-Q => Interrupt request (not handled here)
// 12 ctrl-R => "cent" (R because that's where cent is on the 1130 keyboard)
// 15 ctrl-U => Erase Field
// 7E ~ => "not"
// FF Del => Backspace again
/*
* 03 ctrl-C => Program stop (not handled here)
* 05 ctrl-E => Simulator stop (not handled here)
* 08 ctrl-H => Backspace
* 0D ctrl-M (Enter) => EOF
* 11 ctrl-Q => Interrupt request (not handled here)
* 12 ctrl-R => "cent" (R because that's where cent is on the 1130 keyboard)
* 15 ctrl-U => Erase Field
* 7E ~ => "not"
* FF Del => Backspace again
*/
static uint16 ascii_to_conin[] = /* ASCII to ((hollerith << 4) | special key flags) */
{

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -27,11 +27,11 @@
#define MAX(a,b) (((a) >= (b)) ? (a) : (b))
#ifndef _WIN32
int strnicmp (char *a, char *b, int n);
int strcmpi (char *a, char *b);
int strnicmp (const char *a, const char *b, int n);
int strcmpi (const char *a, const char *b);
#endif
// #define GUI_SUPPORT // uncomment to compile the GUI extensions. It's defined in the windows ibm1130.mak makefile
/* #define GUI_SUPPORT uncomment to compile the GUI extensions. It's defined in the windows ibm1130.mak makefile */
/* ------------------------------------------------------------------------ */
/* Architectural constants */
@@ -40,14 +40,13 @@
#define INIMEMSIZE (16384) /* 16Kwords */
#define MEMSIZE (cpu_unit.capac)
#define UNIT_MSIZE (1 << (UNIT_V_UF + 7)) /* flag for memory size setting */
#define ILL_ADR_FLAG 0x40000000 /* an impossible 1130 address */
/* ------------------------------------------------------------------------ */
/* Global state */
extern int cgi; // TRUE if we are running as a CGI program
extern int cgi; /* TRUE if we are running as a CGI program */
extern int cgiwritable; /* TRUE if we can write the disk images back to the image file in CGI mode */
extern int sim_gui;
extern uint16 M[]; /* core memory, up to 32Kwords (note: don't even think about trying 64K) */
@@ -58,6 +57,7 @@ extern int32 SAR, SBR; /* storage address/buffer registers */
extern int32 OP, TAG, CCC; /* instruction decoded pieces */
extern int32 CES; /* console entry switches */
extern int32 ACC, EXT; /* accumulator and extension */
extern int32 ARF; /* arithmetic factor register, a nonaddressable internal CPU register */
extern int32 RUNMODE; /* processor run/step mode */
extern int32 ipl; /* current interrupt level (-1 = not handling irq) */
extern int32 iplpending; /* interrupted IPL's */
@@ -71,9 +71,11 @@ extern int32 int_mask; /* current active interrupt mask (ipl sensitive) */
extern int32 mem_mask;
extern int32 cpu_dsw; /* CPU device status word */
extern int32 sim_int_char; /* interrupt character */
extern int32 con_dsw; /* has program stop and int run bits */
extern t_bool running;
extern t_bool power;
extern t_bool cgi; /* TRUE if we are running as a CGI program */
extern t_bool cgiwritable; /* TRUE if we can write to the disk image file in CGI mode */
extern t_stat reason; /* CPU execution loop control */
#define WAIT_OP 1 /* wait state causes: wait instruction, invalid instruction*/
@@ -131,15 +133,19 @@ void WriteW (int32 a, int32 d);
#define STOP_PHASE_BREAK 7 /* phase load break */
#define STOP_CRASH 8 /* program has crashed badly */
#define STOP_TIMED_OUT 9 /* simulation time limit exceeded */
#define STOP_IMMEDIATE 10 /* simulator stop key pressed (immediate stop) */
#define STOP_BREAK 11 /* simulator break key pressed */
#define STOP_STEP 12 /* step count expired */
#define STOP_OTHER 13 /* other reason, probably error returned by sim_process_event() */
#define IORETURN(f,v) ((f)? (v): SCPE_OK) /* cond error return */
#define INT_REQ_0 0x01 /* bits for interrupt levels (ipl, iplpending, int_req, int_mask) */
#define INT_REQ_1 0x02
#define INT_REQ_2 0x04
#define INT_REQ_3 0x08
#define INT_REQ_4 0x10
#define INT_REQ_5 0x20
#define INT_REQ_5 0x01 /* bits for interrupt levels (ipl, iplpending, int_req, int_mask) */
#define INT_REQ_4 0x02
#define INT_REQ_3 0x04
#define INT_REQ_2 0x08
#define INT_REQ_1 0x10
#define INT_REQ_0 0x20
#define XIO_UNUSED 0x00 /* XIO commands */
#define XIO_WRITE 0x01
@@ -156,7 +162,7 @@ void WriteW (int32 a, int32 d);
#define ILSW_0_1442_CARD 0x8000 /* ILSW 0 is not really defined on the 1130 */
#define ILSW_1_1132_PRINTER 0x8000 // had these backwards!
#define ILSW_1_1132_PRINTER 0x8000 /* had these backwards! */
#define ILSW_1_SCA 0x4000
#define ILSW_2_1131_DISK 0x8000
@@ -215,13 +221,13 @@ void WriteW (int32 a, int32 d);
#define ILSW_4_SAC_BIT_09 0x0040
#define ILSW_4_SAC_BIT_10 0x0020
#define ILSW_4_SAC_BIT_11 0x0010
#define ILSW_4_T2741_TERMINAL 0x0010 /* APL\1130 nonstandard serial interface uses this bit */
#define ILSW_4_SAC_BIT_12 0x0008
#define ILSW_4_SAC_BIT_13 0x0004
#define ILSW_4_SAC_BIT_14 0x0002
#define ILSW_4_SAC_BIT_15 0x0001
#define ILSW_5_INT_RUN 0x8000
#define ILSW_5_PROGRAM_STOP 0x8000
#define ILSW_5_INT_RUN_PROGRAM_STOP 0x8000 /* this replaces both ILSW_5_INT_RUN and ILSW_5_PROGRAM_STOP */
#define ILSW_5_SAC_BIT_01 0x4000
#define ILSW_5_SAC_BIT_02 0x2000
#define ILSW_5_SAC_BIT_03 0x1000
@@ -238,26 +244,27 @@ void WriteW (int32 a, int32 d);
#define ILSW_5_SAC_BIT_14 0x0002
#define ILSW_5_SAC_BIT_15 0x0001
//* CPU DSW bits
/* CPU DSW bits */
#define CPU_DSW_PROGRAM_STOP 0x8000
#define CPU_DSW_INT_RUN 0x4000
/* prototypes: xio handlers */
void xio_1131_console (int32 addr, int32 func, int32 modify); // console keyboard and printer
void xio_1142_card (int32 addr, int32 func, int32 modify); // standard card reader/punch
void xio_1134_papertape (int32 addr, int32 func, int32 modify); // paper tape reader/punch
void xio_disk (int32 addr, int32 func, int32 modify, int drv); // internal CPU disk
void xio_1627_plotter (int32 addr, int32 func, int32 modify); // XY plotter
void xio_1132_printer (int32 addr, int32 func, int32 modify); // standard line printer
void xio_1131_switches (int32 addr, int32 func, int32 modify); // console buttons & switches
void xio_1231_optical (int32 addr, int32 func, int32 modify); // optical mark page reader
void xio_2501_card (int32 addr, int32 func, int32 modify); // alternate high-speed card reader
void xio_1131_synch (int32 addr, int32 func, int32 modify); // synchronous communications adapter
void xio_system7 (int32 addr, int32 func, int32 modify); // system/7 interprocessor IO link
void xio_1403_printer (int32 addr, int32 func, int32 modify); // alternate high-speed printer
void xio_2250_display (int32 addr, int32 func, int32 modify); // vector display processor
void xio_1131_console (int32 addr, int32 func, int32 modify); /* console keyboard and printer */
void xio_1142_card (int32 addr, int32 func, int32 modify); /* standard card reader/punch */
void xio_1134_papertape (int32 addr, int32 func, int32 modify); /* paper tape reader/punch */
void xio_disk (int32 addr, int32 func, int32 modify, int drv); /* internal CPU disk */
void xio_1627_plotter (int32 addr, int32 func, int32 modify); /* XY plotter */
void xio_1132_printer (int32 addr, int32 func, int32 modify); /* standard line printer */
void xio_1131_switches (int32 addr, int32 func, int32 modify); /* console buttons & switches */
void xio_1231_optical (int32 addr, int32 func, int32 modify); /* optical mark page reader */
void xio_2501_card (int32 addr, int32 func, int32 modify); /* alternate high-speed card reader */
void xio_sca (int32 addr, int32 func, int32 modify); /* synchronous communications adapter */
void xio_system7 (int32 addr, int32 func, int32 modify); /* system/7 interprocessor IO link */
void xio_1403_printer (int32 addr, int32 func, int32 modify); /* alternate high-speed printer */
void xio_2250_display (int32 addr, int32 func, int32 modify); /* vector display processor */
void xio_t2741_terminal (int32 addr, int32 func, int32 modify); /* IO selectric via nonstandard serial interface for APL */
void xio_error (char *msg);
void bail (char *msg);
@@ -267,6 +274,8 @@ t_stat cr_rewind (void);
t_stat cr_detach (UNIT *uptr);
void calc_ints (void); /* recalculate interrupt bitmask */
void trace_io (char *fmt, ...); /* debugging printout */
void trace_both (char *fmt, ...); /* debugging printout */
t_stat register_cmd (char *name, t_stat (*action)(int32 flag, char *ptr), int arg, char *help);
void scp_panic (char *msg); /* bail out of simulator */
char *upcase(char *str);
void break_simulation (t_stat reason); /* let a device halt the simulation */

View File

@@ -14,6 +14,13 @@ commands may NOT be accurate. This should probably be fixed.
* or modifications.
*
* Revision History
* 05-dec-06 Added cgiwritable mode
*
* 19-Dec-05 We no longer issue an operation complete interrupt if an INITR, INITW
* or CONTROL operation is attemped on a drive that is not online. DATA_ERROR
* is now only indicated in the DSW when
*
* 02-Nov-04 Addes -s option to boot to leave switches alone.
* 15-jun-03 moved actual read on XIO read to end of time interval,
* as the APL boot card required 2 instructions to run between the
* time read was initiated and the time the data was read (a jump and a wait)
@@ -29,7 +36,7 @@ commands may NOT be accurate. This should probably be fixed.
#include "ibm1130_defs.h"
#include "memory.h"
#define TRACE_DMS_IO // define to enable debug of DMS phase IO
#define TRACE_DMS_IO /* define to enable debug of DMS phase IO */
#ifdef TRACE_DMS_IO
extern int32 sim_switches;
@@ -86,7 +93,7 @@ static t_stat dsk_attach (UNIT *uptr, char *cptr);
static t_stat dsk_detach (UNIT *uptr);
static t_stat dsk_boot (int unitno, DEVICE *dptr);
static void diskfail (UNIT *uptr, int errflag);
static void diskfail (UNIT *uptr, int dswflag, int unitflag, t_bool do_interrupt);
/* DSK data structures
@@ -180,16 +187,17 @@ extern void void_backtrace (int afrom, int ato);
void xio_disk (int32 iocc_addr, int32 func, int32 modify, int drv)
{
int i, rev, nsteps, newcyl, sec, nwords;
uint32 newpos; // changed from t_addr to uint32 in anticipation of simh 64-bit development
uint32 newpos; /* changed from t_addr to uint32 in anticipation of simh 64-bit development */
char msg[80];
UNIT *uptr = dsk_unit+drv;
int16 buf[DSK_NUMWD];
if (! BETWEEN(drv, 0, DSK_NUMDR-1)) { // hmmm, invalid drive */
if (func != XIO_SENSE_DEV) { // tried to use it, too
// just do nothing, as if the controller isn't there. NAMCRA at N0116300 tests for drives by attempting reads
// sprintf(msg, "Op %x on invalid drive number %d", func, drv);
// xio_error(msg);
if (! BETWEEN(drv, 0, DSK_NUMDR-1)) { /* hmmm, invalid drive */
if (func != XIO_SENSE_DEV) { /* tried to use it, too */
/* just do nothing, as if the controller isn't there. NAMCRA at N0116300 tests for drives by attempting reads
sprintf(msg, "Op %x on invalid drive number %d", func, drv);
xio_error(msg);
*/
}
return;
}
@@ -199,7 +207,7 @@ void xio_disk (int32 iocc_addr, int32 func, int32 modify, int drv)
switch (func) {
case XIO_INITR:
if (! IS_ONLINE(uptr)) { /* disk is offline */
diskfail(uptr, UNIT_HARDERR); /* make error stick till reset or attach */
diskfail(uptr, 0, 0, FALSE);
break;
}
@@ -219,11 +227,12 @@ void xio_disk (int32 iocc_addr, int32 func, int32 modify, int drv)
sec = modify & 0x07; /* get sector on cylinder */
if ((modify & 0x0080) == 0) { /* it's a real read if it's not a read check */
// ah. We have a problem. The APL boot card counts on there being time for at least one
// more instruction to execute between the XIO read and the time the data starts loading
// into core. So, we have to defer the actual read operation a bit. Might as well wait
// until it's time to issue the operation complete interrupt. This means saving the
// IO information, then performing the actual read in dsk_svc.
/* ah. We have a problem. The APL boot card counts on there being time for at least one
* more instruction to execute between the XIO read and the time the data starts loading
* into core. So, we have to defer the actual read operation a bit. Might as well wait
* until it's time to issue the operation complete interrupt. This means saving the
* IO information, then performing the actual read in dsk_svc.
*/
newpos = (uptr->CYL*DSK_NUMSC*DSK_NUMSF + sec)*2*DSK_NUMWD;
@@ -248,12 +257,12 @@ void xio_disk (int32 iocc_addr, int32 func, int32 modify, int drv)
case XIO_INITW:
if (! IS_ONLINE(uptr)) { /* disk is offline */
diskfail(uptr, UNIT_HARDERR); /* make error stick till reset or attach */
diskfail(uptr, 0, 0, FALSE);
break;
}
if (uptr->flags & UNIT_RONLY) { /* oops, write to RO disk? permanent error */
diskfail(uptr, UNIT_HARDERR);
if (uptr->flags & UNIT_RONLY) { /* oops, write to RO disk? permanent error until disk is powered off/on */
diskfail(uptr, DSK_DSW_DATA_ERROR, UNIT_HARDERR, FALSE);
break;
}
@@ -312,7 +321,7 @@ void xio_disk (int32 iocc_addr, int32 func, int32 modify, int drv)
case XIO_CONTROL: /* step fwd/rev */
if (! IS_ONLINE(uptr)) {
diskfail(uptr, UNIT_HARDERR);
diskfail(uptr, 0, 0, FALSE);
break;
}
@@ -364,19 +373,24 @@ void xio_disk (int32 iocc_addr, int32 func, int32 modify, int drv)
/* diskfail - schedule an operation complete that sets the error bit */
static void diskfail (UNIT *uptr, int errflag)
static void diskfail (UNIT *uptr, int dswflag, int unitflag, t_bool do_interrupt)
{
int drv = uptr - dsk_unit;
sim_cancel(uptr); /* cancel any pending ops */
SETBIT(uptr->flags, errflag); /* set the error flag */
SETBIT(dsk_dsw[drv], dswflag); /* set any specified DSW bits */
SETBIT(uptr->flags, unitflag); /* set any specified unit flag bits */
uptr->FUNC = DSK_FUNC_FAILED; /* tell svc routine why it failed */
sim_activate(uptr, 1); /* schedule an immediate op complete interrupt */
if (do_interrupt)
sim_activate(uptr, 1); /* schedule an immediate op complete interrupt */
}
t_stat dsk_svc (UNIT *uptr)
{
int drv = uptr - dsk_unit, i, nwords, sec;
int16 buf[DSK_NUMWD];
uint32 newpos; // changed from t_addr to uint32 in anticipation of simh 64-bit development
uint32 newpos; /* changed from t_addr to uint32 in anticipation of simh 64-bit development */
int32 iocc_addr;
if (uptr->FUNC == DSK_FUNC_IDLE) /* service function called with no activity? not good, but ignore */
@@ -415,16 +429,16 @@ t_stat dsk_svc (UNIT *uptr)
dsk_lastio[drv] = IO_READ;
uptr->pos = newpos;
}
fxread(buf, 2, DSK_NUMWD, uptr->fileref); // read whole sector so we're in position for next read
fxread(buf, 2, DSK_NUMWD, uptr->fileref); /* read whole sector so we're in position for next read */
uptr->pos = newpos + 2*DSK_NUMWD;
}
void_backtrace(iocc_addr, iocc_addr + nwords - 1); // mark prev instruction as altered
void_backtrace(iocc_addr, iocc_addr + nwords - 1); /* mark prev instruction as altered */
trace_io("* DSK%d read %d words from %d.%d (%x, %x) to M[%04x-%04x]", drv, nwords, uptr->CYL, sec, uptr->CYL*8 + sec, newpos, iocc_addr & mem_mask,
(iocc_addr + nwords - 1) & mem_mask);
// // this will help debug the monitor by letting me watch phase loading
/* this will help debug the monitor by letting me watch phase loading */
if (raw_disk_debug)
printf("* DSK%d XIO @ %04x read %d words from %d.%d (%x, %x) to M[%04x-%04x]\n", drv, prev_IAR, nwords, uptr->CYL, sec, uptr->CYL*8 + sec, newpos, iocc_addr & mem_mask,
(iocc_addr + nwords - 1) & mem_mask);
@@ -448,7 +462,7 @@ t_stat dsk_svc (UNIT *uptr)
}
uptr->FUNC = DSK_FUNC_IDLE; // we're done with this operation
uptr->FUNC = DSK_FUNC_IDLE; /* we're done with this operation */
return SCPE_OK;
}
@@ -459,8 +473,8 @@ t_stat dsk_reset (DEVICE *dptr)
UNIT *uptr;
#ifdef TRACE_DMS_IO
// add the WHERE command. It finds the phase that was loaded at given address and indicates
// the offset in the phase
/* add the WHERE command. It finds the phase that was loaded at given address and indicates */
/* the offset in the phase */
register_cmd("WHERE", &where_cmd, 0, "w{here} address find phase and offset of an address\n");
register_cmd("PHDEBUG", &phdebug_cmd, 0, "ph{debug} off|phlo phhi break on phase load\n");
register_cmd("FDUMP", &fdump_cmd, 0, NULL);
@@ -487,14 +501,14 @@ static t_stat dsk_attach (UNIT *uptr, char *cptr)
int drv = uptr - dsk_unit;
t_stat rval;
sim_cancel(uptr); // cancel current IO
sim_cancel(uptr); /* cancel current IO */
dsk_lastio[drv] = IO_NONE;
if (uptr->flags & UNIT_ATT) // dismount current disk
if (uptr->flags & UNIT_ATT) /* dismount current disk */
if ((rval = dsk_detach(uptr)) != SCPE_OK)
return rval;
uptr->CYL = 0; // reset the device
uptr->CYL = 0; /* reset the device */
uptr->FUNC = DSK_FUNC_IDLE;
dsk_dsw[drv] = DSK_DSW_CARRIAGE_HOME;
@@ -502,18 +516,18 @@ static t_stat dsk_attach (UNIT *uptr, char *cptr)
CLRBIT(ILSW[2], dsk_ilswbit[drv]);
calc_ints();
if (sim_switches & SWMASK('M')) // if memory mode (e.g. for CGI), buffer the file
SETBIT(uptr->flags, UNIT_BUFABLE);
if (sim_switches & SWMASK('M')) /* if memory mode (e.g. for CGI), buffer the file */
SETBIT(uptr->flags, UNIT_BUFABLE|UNIT_MUSTBUF);
if (sim_switches & SWMASK('R')) // read lock mode
if (sim_switches & SWMASK('R')) /* read lock mode */
SETBIT(uptr->flags, UNIT_RO|UNIT_ROABLE|UNIT_RONLY);
if (cgi && (sim_switches & SWMASK('M'))) { // if cgi and memory mode,
sim_switches |= SWMASK('R'); // have attach_unit open file in readonly mode
SETBIT(uptr->flags, UNIT_ROABLE|UNIT_MUSTBUF); // but don't set the UNIT_RONLY flag so DMS can write to the buffered image
if (cgi && (sim_switches & SWMASK('M')) && ! cgiwritable) { /* if cgi and memory mode, but writable option not specified */
sim_switches |= SWMASK('R'); /* have attach_unit open file in readonly mode */
SETBIT(uptr->flags, UNIT_ROABLE); /* but don't set the UNIT_RONLY flag so DMS can write to the buffered image */
}
if ((rval = attach_unit(uptr, quotefix(cptr))) != SCPE_OK) { // mount new disk
if ((rval = attach_unit(uptr, quotefix(cptr))) != SCPE_OK) { /* mount new disk */
SETBIT(dsk_dsw[drv], DSK_DSW_NOT_READY);
return rval;
}
@@ -536,7 +550,7 @@ static t_stat dsk_detach (UNIT *uptr)
sim_cancel(uptr);
if ((rval = detach_unit (uptr)) != SCPE_OK)
if ((rval = detach_unit(uptr)) != SCPE_OK)
return rval;
CLRBIT(ILSW[2], dsk_ilswbit[drv]);
@@ -555,7 +569,7 @@ static t_stat dsk_detach (UNIT *uptr)
return SCPE_OK;
}
// boot routine - if they type BOOT DSK, load the standard boot card.
/* boot routine - if they type BOOT DSK, load the standard boot card. */
static t_stat dsk_boot (int unitno, DEVICE *dptr)
{
@@ -585,7 +599,7 @@ struct tag_slet {
int16 nwords;
int16 sector;
} slet[MAXSLET] = {
# include "dmsr2v12slet.h" // without RPG, use this info until overwritten by actual data from disk
# include "dmsr2v12slet.h" /* without RPG, use this info until overwritten by actual data from disk */
};
#pragma pack()
@@ -599,7 +613,7 @@ int nseg = 0;
static void enable_dms_tracing (int newsetting)
{
nseg = 0; // clear the segment map
nseg = 0; /* clear the segment map */
if ((newsetting && trace_dms) || ! (newsetting || trace_dms))
return;
@@ -678,7 +692,7 @@ static t_stat where_cmd (int flag, char *ptr)
return SCPE_OK;
}
// savesector - save info on a sector just read. THIS IS NOT YET TESTED
/* savesector - save info on a sector just read. THIS IS NOT YET TESTED */
static void addseg (int i)
{
@@ -713,14 +727,14 @@ static void savesector (int addr, int offset, int len, int phid, char *name)
if (! trace_dms)
return;
addr++; // first word is sector address, so account for that
addr++; /* first word is sector address, so account for that */
len--;
for (i = 0; i < nseg; i++) {
if (addr >= (mseg[i].addr+mseg[i].len)) // entirely after this entry
if (addr >= (mseg[i].addr+mseg[i].len)) /* entirely after this entry */
continue;
if (mseg[i].addr < addr) { // old one starts before this. split it
if (mseg[i].addr < addr) { /* old one starts before this. split it */
addseg(i);
mseg[i].len = addr-mseg[i].addr;
i++;
@@ -731,7 +745,7 @@ static void savesector (int addr, int offset, int len, int phid, char *name)
break;
}
addseg(i); // add new segment. Old one ends up after this
addseg(i); /* add new segment. Old one ends up after this */
if (i >= MAXMSEG)
return;
@@ -742,12 +756,12 @@ static void savesector (int addr, int offset, int len, int phid, char *name)
mseg[i].len = len;
mseg[i].name = name;
i++; // delete any segments completely covered
i++; /* delete any segments completely covered */
while (i < nseg && (mseg[i].addr+mseg[i].len) <= (addr+len))
delseg(i);
if (i < nseg && mseg[i].addr < (addr+len)) { // old one extends past this. Retain the end
if (i < nseg && mseg[i].addr < (addr+len)) { /* old one extends past this. Retain the end */
mseg[i].len = (mseg[i].addr+mseg[i].len) - (addr+len);
mseg[i].addr = addr+len;
}
@@ -755,19 +769,19 @@ static void savesector (int addr, int offset, int len, int phid, char *name)
static void tracesector (int iswrite, int nwords, int addr, int sector)
{
int i, phid = 0, sletind = -1, offset = 0;
int i, phid = 0, offset = 0;
char *name = NULL;
if (nwords < 3 || ! trace_dms)
return;
switch (sector) { // explicitly known sector name
switch (sector) { /* explicitly known sector name */
case 0: name = "ID/COLD START"; break;
case 1: name = "DCOM"; break;
case 2: name = "RESIDENT IMAGE"; break;
case 3:
case 4:
case 5: name = "SLET"; // save just-read or written SLET info
case 5: name = "SLET"; /* save just-read or written SLET info */
memmove(&slet[(320/4)*(sector-3)], &M[addr+1], nwords*2);
break;
case 6: name = "RELOAD TABLE"; break;
@@ -777,9 +791,9 @@ static void tracesector (int iswrite, int nwords, int addr, int sector)
printf("* %04x: %3d /%04x %c %3d.%d ",
prev_IAR, nwords, addr, iswrite ? 'W' : 'R', sector/8, sector%8);
if (name == NULL) { // look up sector in SLET
if (name == NULL) { /* look up sector in SLET */
for (i = 0; i < MAXSLET; i++) {
if (slet[i].phid == 0) // not found
if (slet[i].phid == 0) /* not found */
goto done;
else if (slet[i].sector > sector) {
if (--i >= 0) {
@@ -792,17 +806,17 @@ static void tracesector (int iswrite, int nwords, int addr, int sector)
goto done;
}
if (slet[i].sector == sector) {
phid = slet[i].phid; // we found the starting sector
phid = slet[i].phid; /* we found the starting sector */
break;
}
}
if (i >= MAXSLET) // was not found
if (i >= MAXSLET) /* was not found */
goto done;
name = "?";
for (i = sizeof(phase)/sizeof(phase[0]); --i >= 0; ) {
if (phase[i].phid == phid) { // look up name
if (phase[i].phid == phid) { /* look up name */
name = phase[i].name;
break;
}
@@ -816,7 +830,7 @@ done:
putchar('\n');
if (phid >= phdebug_lo && phid <= phdebug_hi && offset == 0)
break_simulation(STOP_PHASE_BREAK); // break on read of first sector of indicated phases
break_simulation(STOP_PHASE_BREAK); /* break on read of first sector of indicated phases */
if (name != NULL && *name != '?' && ! iswrite)
savesector(addr, offset, nwords, phid, name);
@@ -824,12 +838,12 @@ done:
static t_stat fdump_cmd (int flags, char *cptr)
{
int addr = 0x7a24; // address of next statement;
int addr = 0x7a24; /* address of next statement */
int sofst = 0x7a26, symaddr;
int cword, nwords, stype, has_stnum, strel = 1, laststno = 0;
addr = M[addr & mem_mask] & mem_mask; // get address of first statement
sofst = M[sofst & mem_mask] & mem_mask; // get address of symbol table
addr = M[addr & mem_mask] & mem_mask; /* get address of first statement */
sofst = M[sofst & mem_mask] & mem_mask ; /* get address of symbol table */
for (;;) {
cword = M[addr];
@@ -851,7 +865,7 @@ static t_stat fdump_cmd (int flags, char *cptr)
printf(" [%04x %04x %04x]", M[symaddr], M[symaddr+1], M[symaddr+2]);
}
if (stype == 0x5000) { // error record
if (stype == 0x5000) { /* error record */
printf(" (err %d)", M[addr+1]);
}
@@ -872,4 +886,4 @@ static t_stat fdump_cmd (int flags, char *cptr)
return SCPE_OK;
}
#endif // TRACE_DMS_IO
#endif /* TRACE_DMS_IO */

View File

@@ -1,60 +1,61 @@
// ibm1130_fmt.c : interpret tabs in 1130 Assembler or Fortran source
// Bob Flanders
// -------------------------------------------------------------------------------------------
//
// These routines are used by ibm1130_cr.c when the user has indicated
// that the input text is formatted with tabs. Input lines are edited
// into the appropriate column format. Three edit modes are recognized:
//
// Assembler mode:
// Input lines of the form
//
// [label]<whitespace>[opcode]<tab>[tag][L]<tab>[argument]
//
// are rearranged so that the input fields are placed in the appropriate columns
//
// The label must start on the first character of the line. If there is no label,
// the first character(s) before the opcode must be whitespace. Following the opcode, there
// MUST be a tab character, followed by the format and tag. Following the format and tag
// may be exactly one whitespace character, and then starts the argument.
//
// Input lines with * in column 1 and blank lines are turned into Assembler comments,
// with the * in the Opcode field.
//
// Assembler directive lines at the beginning of the deck must be preceded by
// ! to indicate that they are not comments. For example,
//
// !*LIST
// * This is a comment
//
// Fortran mode:
// Input lines of the form
//
// [label]<tab>statement
//
// or
//
// [label]<tab>Xcontinuation
//
// where X is a non alphabetic contination character are rearranged in the
// appropriate manner:
//
// 1 2
// 12345678901234567890...
// ------------------------
// label statement
// labelXcontinuation
//
// However, you must take care that you don't end up with statement text after column 72.
//
// Input lines with * or C in column 1 are left alone (comments and directives)
//
// (The ! escape is not used before Fortran directives as before Assembler directives)
//
// Tab mode:
// Tabs are replaced with spaces. Tab settings are assumed to be eight characters wide,
// as is standard for vi, notepad, etc.
// -------------------------------------------------------------------------------------------
/*********************************************************************************************
* ibm1130_fmt.c : interpret tabs in 1130 Assembler or Fortran source
* Bob Flanders
* -------------------------------------------------------------------------------------------
*
* These routines are used by ibm1130_cr.c when the user has indicated
* that the input text is formatted with tabs. Input lines are edited
* into the appropriate column format. Three edit modes are recognized:
*
* Assembler mode:
* Input lines of the form
*
* [label]<whitespace>[opcode]<tab>[tag][L]<tab>[argument]
*
* are rearranged so that the input fields are placed in the appropriate columns
*
* The label must start on the first character of the line. If there is no label,
* the first character(s) before the opcode must be whitespace. Following the opcode, there
* MUST be a tab character, followed by the format and tag. Following the format and tag
* may be exactly one whitespace character, and then starts the argument.
*
* Input lines with * in column 1 and blank lines are turned into Assembler comments,
* with the * in the Opcode field.
*
* Assembler directive lines at the beginning of the deck must be preceded by
* ! to indicate that they are not comments. For example,
*
* !*LIST
* * This is a comment
*
* Fortran mode:
* Input lines of the form
*
* [label]<tab>statement
*
* or
*
* [label]<tab>Xcontinuation
*
* where X is a non alphabetic contination character are rearranged in the
* appropriate manner:
*
* 1 2
* 12345678901234567890...
* ------------------------
* label statement
* labelXcontinuation
*
* However, you must take care that you don't end up with statement text after column 72.
*
* Input lines with * or C in column 1 are left alone (comments and directives)
*
* (The ! escape is not used before Fortran directives as before Assembler directives)
*
* Tab mode:
* Tabs are replaced with spaces. Tab settings are assumed to be eight characters wide,
* as is standard for vi, notepad, etc.
*********************************************************************************************/
#include <stdio.h>
#include <stdlib.h>
@@ -63,10 +64,10 @@
#include <string.h>
#include "ibm1130_fmt.h"
#define MAXLINE 81 // maximum output line size
#define WORKSZ 256 // size for tab work area
#define TAGOFFSET 12 // offset for tag field
#define FMTOFFSET 11 // offset for format field
#define MAXLINE 81 /* maximum output line size */
#define WORKSZ 256 /* size for tab work area */
#define TAGOFFSET 12 /* offset for tag field */
#define FMTOFFSET 11 /* offset for format field */
#define MIN(a,b) ((a < b) ? a : b)
#define AMSG " with Assembler Reformat"
@@ -77,227 +78,236 @@
#define FFORMAT "%-5.5s %-74.74s"
#define FCONTFMT "%-5.5s%-75.75s"
char gszLabel[6]; // work area for label
char gszArg[MAXLINE]; // .. argument
char gszOutput[MAXLINE]; // .. output
short gaiAsmTabs[] = {7,12,15,20,25,30,35,40,45,52,0};// tab stops for assembler
char gszLabel[6]; /* work area for label */
char gszArg[MAXLINE]; /* .. argument */
char gszOutput[MAXLINE]; /* .. output */
short gaiAsmTabs[] = {7,12,15,20,25,30,35,40,45,52,0};/* tab stops for assembler */
short gaiPlainTabs[] = {9, 17, 25, 33, 41, 49, 57, 65, 73, 0};// tab stops for just plain tabs
short gaiPlainTabs[] = {9, 17, 25, 33, 41, 49, 57, 65, 73, 0};/* tab stops for just plain tabs */
// ///////////////
// helper routines
/*
* helper routines
*/
///////////////////////////////////////////////////
// ExpandTabs: Expand tabs to spaces
/*************************************************
* ExpandTabs: Expand tabs to spaces
*/
char* ExpandTabs(char* p_szInbuf, // expand tabs .. input buffer
char* p_szOutbuf, // .. output buffer
short* p_aiTabs) // .. array of tab stops (1 based) -- 0 end of array
char* ExpandTabs(char* p_szInbuf, /* expand tabs .. input buffer */
char* p_szOutbuf, /* .. output buffer */
short* p_aiTabs) /* .. array of tab stops (1 based) -- 0 end of array */
{
short iI, // input position
iO, // output position
iT; // next tab stop
short iI, /* input position */
iO, /* output position */
iT; /* next tab stop */
char cX; // character to test
char cX; /* character to test */
iI = 0; // init input position
iO = 0; // init output position
iT = 0; // init tab stop
iI = 0; /* init input position */
iO = 0; /* init output position */
iT = 0; /* init tab stop */
while ((cX = *(p_szInbuf + iI)) != 0) // while there are characters
while ((cX = *(p_szInbuf + iI)) != 0) /* while there are characters */
{
if (cX == '\t') // q. tab character?
{ // a. yes ..
while ((p_aiTabs[iT] <= iO + 1) // search for next valid stop ..
&& (p_aiTabs[iT] != 0)) // .. or end of table
iT++; // .. go to next tab
if (cX == '\t') /* q. tab character? */
{ /* a. yes .. */
while ((p_aiTabs[iT] <= iO + 1) /* search for next valid stop .. */
&& (p_aiTabs[iT] != 0)) /* .. or end of table */
iT++; /* .. go to next tab */
if (p_aiTabs[iT] != 0) // q. end of tab array?
{ // a. no ..
while (iO < (p_aiTabs[iT] - 1)) // fill to tab with blanks
*(p_szOutbuf + iO++) = ' '; // .. put in a blank
if (p_aiTabs[iT] != 0) /* q. end of tab array? */
{ /* a. no .. */
while (iO < (p_aiTabs[iT] - 1)) /* fill to tab with blanks */
*(p_szOutbuf + iO++) = ' '; /* .. put in a blank */
}
else // Otherwise ...
*(p_szOutbuf + iO++) = ' '; // .. Translate to blank
else /* Otherwise ... */
*(p_szOutbuf + iO++) = ' '; /* .. Translate to blank */
}
else // Otherwise .. not tab
*(p_szOutbuf + iO++) = cX; // .. save the input char
else /* Otherwise .. not tab */
*(p_szOutbuf + iO++) = cX; /* .. save the input char */
iI++; // next input character
iI++; /* next input character */
}
*(p_szOutbuf + iO) = 0; // end the string..
return p_szOutbuf; // .. return output area addr
*(p_szOutbuf + iO) = 0; /* end the string.. */
return p_szOutbuf; /* .. return output area addr */
}
/////////////////////////////////////
// extract next token, modify pointer
/*************************************************
* extract next token, modify pointer
*/
char* GetToken(char* p_szOut, // output location
int p_iLen, // max output length
char**p_pszToken) // pointer to input token
char* GetToken(char* p_szOut, /* output location */
int p_iLen, /* max output length */
char**p_pszToken) /* pointer to input token */
{
int iI; // work integer
char* pszX; // work pointer
int iI; /* work integer */
char* pszX; /* work pointer */
pszX = *p_pszToken; // get pointer to token
pszX = *p_pszToken; /* get pointer to token */
for (iI = 0; *(pszX + iI) && (!isspace(*(pszX + iI)));) // while not whitespace & not end
iI++; // .. count token length
for (iI = 0; *(pszX + iI) && (!isspace(*(pszX + iI)));) /* while not whitespace & not end */
iI++; /* .. count token length */
memset(p_szOut, 0, p_iLen); // zero out output area
memset(p_szOut, 0, p_iLen); /* zero out output area */
if (iI > 0) // q. any chars?
strncpy(p_szOut, *p_pszToken, MIN(iI, p_iLen-1)); // a. yes.. copy max of p_iLen-1
if (iI > 0) /* q. any chars? */
strncpy(p_szOut, *p_pszToken, MIN(iI, p_iLen-1)); /* a. yes.. copy max of p_iLen-1 */
*p_pszToken += iI; // point beyond token
return p_szOut; // .. return token pointer
*p_pszToken += iI; /* point beyond token */
return p_szOut; /* .. return token pointer */
}
/////////////////////////////////////////////////////////
// EditToAsm - convert tab-formatted text line to 1130 Assembler format
/*************************************************
* EditToAsm - convert tab-formatted text line to 1130 Assembler format
*/
char *EditToAsm (char* p_pszEdit) // convert line to 1130 assembler
char *EditToAsm (char* p_pszEdit) /* convert line to 1130 assembler */
{
char pszLine[MAXLINE]; // source line
char pszWork[WORKSZ]; // work buffer
char acTFWrk[2]; // tag/format work area
size_t iI; // work integer
char pszLine[MAXLINE]; /* source line */
char pszWork[WORKSZ]; /* work buffer */
char acTFWrk[2]; /* tag/format work area */
size_t iI; /* work integer */
if (p_pszEdit == NULL) // q. null request?
return AMSG; // a. yes .. return display message
if (p_pszEdit == NULL) /* q. null request? */
return AMSG; /* a. yes .. return display message */
if (*p_pszEdit == '!') // leave lines starting with ! alone
if (*p_pszEdit == '!') /* leave lines starting with ! alone */
return EditToWhitespace(p_pszEdit+1);
if (*p_pszEdit == '*') // q. comment line?
{ // a. yes..
strncpy(pszWork, EditToWhitespace(p_pszEdit), MAXLINE); // .. convert any tabs
sprintf(gszOutput, ACOMMENTFMT, pszWork); // .. put the comment out there in the opcode column
return gszOutput; // .. and return it
if (*p_pszEdit == '*') /* q. comment line? */
{ /* a. yes.. */
strncpy(pszWork, EditToWhitespace(p_pszEdit), MAXLINE); /* .. convert any tabs */
sprintf(gszOutput, ACOMMENTFMT, pszWork); /* .. put the comment out there in the opcode column */
return gszOutput; /* .. and return it */
}
strncpy(pszLine, p_pszEdit, MAXLINE-1); // copy the line local
strncpy(pszLine, p_pszEdit, MAXLINE-1); /* copy the line local */
ExpandTabs(pszLine, pszWork, gaiAsmTabs); // expand the tabs
strncpy(pszLine, pszWork, MAXLINE-1); // copy the line back
ExpandTabs(pszLine, pszWork, gaiAsmTabs); /* expand the tabs */
strncpy(pszLine, pszWork, MAXLINE-1); /* copy the line back */
for (iI = strlen(pszLine); iI--;) // trim trailing whitespace
for (iI = strlen(pszLine); iI--;) /* trim trailing whitespace */
{
if (*(pszLine + iI) <= ' ') // q. space or less?
*(pszLine + iI) = 0; // a. yes .. remove it
else // otherwise
break; // .. done. Leave loop.
if (*(pszLine + iI) <= ' ') /* q. space or less? */
*(pszLine + iI) = 0; /* a. yes .. remove it */
else /* otherwise */
break; /* .. done. Leave loop. */
}
if (strlen(pszLine) == 0) // q. blank line?
{ // a. yes .. Assembler abhors these so
sprintf(gszOutput, ABLANKLINE); // format as comment statement
return gszOutput; // .. and return it
if (strlen(pszLine) == 0) /* q. blank line? */
{ /* a. yes .. Assembler abhors these so */
sprintf(gszOutput, ABLANKLINE); /* format as comment statement */
return gszOutput; /* .. and return it */
}
// TODO: Add code to process a strip switch
// comment?
/* TODO: Add code to process a strip switch
* comment?
*/
if (strlen(pszLine) > (TAGOFFSET + 1)) // q. line long enough?
{ // a. yes.. reorder tag/format
memcpy(acTFWrk, pszLine + FMTOFFSET, 2); // get tag/format
memset((pszLine + FMTOFFSET), ' ', 2); // .. blank 'em out
if (strlen(pszLine) > (TAGOFFSET + 1)) /* q. line long enough? */
{ /* a. yes.. reorder tag/format */
memcpy(acTFWrk, pszLine + FMTOFFSET, 2); /* get tag/format */
memset((pszLine + FMTOFFSET), ' ', 2); /* .. blank 'em out */
for (iI = 0; iI < 2; iI ++)
if (isalpha(acTFWrk[iI])) // q. alpha char?
*(pszLine + FMTOFFSET) = acTFWrk[iI]; // a. yes .. make it format
else if (isdigit(acTFWrk[iI])) // q. digit?
*(pszLine + TAGOFFSET) = acTFWrk[iI]; // a. yes .. make it the tag
if (isalpha(acTFWrk[iI])) /* q. alpha char? */
*(pszLine + FMTOFFSET) = acTFWrk[iI]; /* a. yes .. make it format */
else if (isdigit(acTFWrk[iI])) /* q. digit? */
*(pszLine + TAGOFFSET) = acTFWrk[iI]; /* a. yes .. make it the tag */
}
sprintf(gszOutput, AFORMAT, pszLine); // format the line
sprintf(gszOutput, AFORMAT, pszLine); /* format the line */
return gszOutput; // return formatted line
return gszOutput; /* return formatted line */
}
/////////////////////////////////////////////////////////
// EditToFortran - convert tab-formatted input text line to FORTRAN format
// (a la DEC Fortran)
/*************************************************
* EditToFortran - convert tab-formatted input text line to FORTRAN format
* (a la DEC Fortran)
*/
char *EditToFortran(char* p_pszEdit) // convert line to 1130 assembler
char *EditToFortran(char* p_pszEdit) /* convert line to 1130 assembler */
{
char pszLine[MAXLINE]; // source line
char* pszWork; // work pointer
size_t iI; // work integer
int bContinue; // true if continue
char pszLine[MAXLINE]; /* source line */
char* pszWork; /* work pointer */
size_t iI; /* work integer */
int bContinue; /* true if continue */
if (p_pszEdit == NULL) // q. null request?
return FMSG; // a. yes .. return display message
if (p_pszEdit == NULL) /* q. null request? */
return FMSG; /* a. yes .. return display message */
if (strchr(p_pszEdit, '\t') == NULL) // q. no tab in the line?
return p_pszEdit; // a. nope, return line as is, assume it's formatted correctly
if (strchr(p_pszEdit, '\t') == NULL) /* q. no tab in the line? */
return p_pszEdit; /* a. nope, return line as is, assume it's formatted correctly */
if (*p_pszEdit == 'C' || *p_pszEdit == '*' || *p_pszEdit == '\0') // q. comment or directive or blank line?
{ // a. yes.. don't restructure
if (*p_pszEdit == 'C' || *p_pszEdit == '*' || *p_pszEdit == '\0') /* q. comment or directive or blank line? */
{ /* a. yes.. don't restructure */
return EditToWhitespace(p_pszEdit);
}
strncpy(pszLine, p_pszEdit, MAXLINE-1); // copy the line local
strncpy(pszLine, p_pszEdit, MAXLINE-1); /* copy the line local */
for (iI = strlen(pszLine); iI--;) // trim trailing whitespace
for (iI = strlen(pszLine); iI--;) /* trim trailing whitespace */
{
if (*(pszLine + iI) <= ' ') // q. space or less?
*(pszLine + iI) = 0; // a. yes .. remove it
else // otherwise
break; // .. done. Leave loop.
if (*(pszLine + iI) <= ' ') /* q. space or less? */
*(pszLine + iI) = 0; /* a. yes .. remove it */
else /* otherwise */
break; /* .. done. Leave loop. */
}
// TODO: Add code to process a strip switch
// comment?
/*
* TODO: Add code to process a strip switch
* comment?
*/
pszWork = (char*) pszLine; // set pointer to line
GetToken(gszLabel, 6, &pszWork); // get the line, if any.
pszWork = (char*) pszLine; /* set pointer to line */
GetToken(gszLabel, 6, &pszWork); /* get the line, if any. */
pszWork++; // skip tab/whitespace
pszWork++; /* skip tab/whitespace */
// continuation...
bContinue = ((isdigit(*pszWork) && (*pszWork != '0')) // if first char non-zero digit
|| (!isspace(*pszWork) && !isalpha(*pszWork))); // .. or non-alpha non-blank
/* continuation... */
bContinue = ((isdigit(*pszWork) && (*pszWork != '0')) /* if first char non-zero digit */
|| (!isspace(*pszWork) && !isalpha(*pszWork))); /* .. or non-alpha non-blank */
memset(gszArg, 0, MAXLINE); // .. and arguments
memset(gszArg, 0, MAXLINE); /* .. and arguments */
strncpy(gszArg, pszWork, 75); // copy rest to argument
strncpy(gszArg, pszWork, 75); /* copy rest to argument */
sprintf(gszOutput, (bContinue) ? FCONTFMT : FFORMAT, // format the line
gszLabel, // .. statement #
gszArg); // .. code
sprintf(gszOutput, (bContinue) ? FCONTFMT : FFORMAT, /* format the line */
gszLabel, /* .. statement # */
gszArg); /* .. code */
return gszOutput; // return formatted line
return gszOutput; /* return formatted line */
}
/////////////////////////////////////////////////////////
// EditToWhitespace - expand tabs at 8 space intervals.
/*************************************************
* EditToWhitespace - expand tabs at 8 space intervals.
*/
char* EditToWhitespace(char *p_pszEdit)
{
int iI; /* work integer */
char pszLine[MAXLINE]; // source line
char pszWork[WORKSZ]; // work buffer
int iI; /* work integer */
char pszLine[MAXLINE]; /* source line */
char pszWork[WORKSZ]; /* work buffer */
if (p_pszEdit == NULL) // q. null request?
return AMSG; // a. yes .. return display message
if (p_pszEdit == NULL) /* q. null request? */
return AMSG; /* a. yes .. return display message */
strncpy(pszLine, p_pszEdit, MAXLINE-1); // copy the line local
strncpy(pszLine, p_pszEdit, MAXLINE-1); /* copy the line local */
ExpandTabs(pszLine, pszWork, gaiPlainTabs); // expand the tabs
strncpy(gszOutput, pszWork, MAXLINE-1); // copy the line back
ExpandTabs(pszLine, pszWork, gaiPlainTabs); /* expand the tabs */
strncpy(gszOutput, pszWork, MAXLINE-1); /* copy the line back */
for (iI = strlen(gszOutput); iI--;) // look at each character
for (iI = strlen(gszOutput); iI--;) /* look at each character */
{
if (*(gszOutput + iI) <= ' ') // q. space or less?
*(gszOutput + iI) = 0; // a. yes .. remove it
else // otherwise
break; // .. done. Leave loop.
if (*(gszOutput + iI) <= ' ') /* q. space or less? */
*(gszOutput + iI) = 0; /* a. yes .. remove it */
else /* otherwise */
break; /* .. done. Leave loop. */
}
return gszOutput; /* ... return buffer */
return gszOutput; /* ... return buffer */
}

View File

@@ -12,6 +12,6 @@
/* ibm1130_asm.h: definition of routines in ibm1130_asm.c
*/
char* EditToAsm(char*); // convert edit format to 1130 assembler format
char* EditToFortran(char*); // convert edit format to Fortran format
char* EditToWhitespace(char*); // clean white space, tabstops every 8 positions
char* EditToAsm(char*); /* convert edit format to 1130 assembler format */
char* EditToFortran(char*); /* convert edit format to Fortran format */
char* EditToWhitespace(char*); /* clean white space, tabstops every 8 positions */

View File

@@ -3,11 +3,11 @@
/* ibm1130_gdu.c: IBM 1130 2250 Graphical Display Unit
(Under construction)
// stuff to fix:
// "store revert" might be backwards?
// alpha keyboard is not implemented
// pushbuttons are not implemented
// there is something about interrupts being deferred during a subroutine transition?
stuff to fix:
"store revert" might be backwards?
alpha keyboard is not implemented
pushbuttons are not implemented
there is something about interrupts being deferred during a subroutine transition?
Based on the SIMH package written by Robert M Supnik
@@ -21,13 +21,13 @@
* Mail to simh@ibm1130.org
*/
#define BLIT_MODE // normally defined, undefine when debugging generate_image()
//#define DEBUG_LIGHTPEN // normally undefined, define to visualize light-pen sensing
#define BLIT_MODE /* define for better performance, undefine when debugging generate_image() */
/* #define DEBUG_LIGHTPEN */ /* define to debug light-pen sensing */
#define DEFAULT_GDU_RATE 20 // default frame rate
#define DEFAULT_PEN_THRESHOLD 3 // default looseness of light-pen hit
#define INDWIDTH 32 // width of an indicator (there are two columns of these)
#define INITSIZE 512 // initial window size
#define DEFAULT_GDU_RATE 20 /* default frame rate */
#define DEFAULT_PEN_THRESHOLD 3 /* default looseness of light-pen hit */
#define INDWIDTH 32 /* width of an indicator (there are two columns of these) */
#define INITSIZE 512 /* initial window size */
#define GDU_DSW_ORDER_CONTROLLED_INTERRUPT 0x8000
#define GDU_DSW_KEYBOARD_INTERUPT 0x4000
@@ -109,7 +109,7 @@ static t_stat gdu_reset (DEVICE *dptr)
void xio_2250_display (int32 addr, int32 func, int32 modify)
{
// ignore commands to nonexistent device
/* ignore commands if device is nonexistent */
}
t_bool gdu_active (void)
@@ -118,7 +118,7 @@ t_bool gdu_active (void)
}
/* -------------------------------------------------------------------------------------- */
#else // GUI_SUPPORT defined
#else /* GUI_SUPPORT defined */
/******* PLATFORM INDEPENDENT CODE ********************************************************/
@@ -127,7 +127,6 @@ static int xmouse, ymouse, lpen_dist, lpen_dist2; // current mouse pointer, scal
static double sfactor; // current scaling factor
static t_bool last_abs = TRUE; // last positioning instruction was absolute
static t_bool mouse_present = FALSE; // mouse is/is not in the window
static void clear_interrupts (void);
static void set_indicators (int32 new_inds);
static void start_regeneration (void);
@@ -239,23 +238,27 @@ static void start_regeneration (void)
{
SETBIT(gdu_dsw, GDU_DSW_BUSY);
if (gdu_unit.flags & UNIT_DISPLAYED) {
StartGDUUpdates();
}
else {
if ((gdu_unit.flags & UNIT_DISPLAYED) == 0) {
if (! CreateGDUWindow())
return;
SETBIT(gdu_unit.flags, UNIT_DISPLAYED);
}
StartGDUUpdates();
}
static void halt_regeneration (void)
{
// halt_regeneration gets called at end of every refresh interation, so it should NOT black out the
// screen -- this is why it was flickering so badly. The lower level code (called on a timer)
// should check to see if GDU_DSW_BUSY is clear, and if it it still zero after several msec,
// only then should it black out the screen and call StopGDUUpdates.
if (gdu_dsw & GDU_DSW_BUSY) {
StopGDUUpdates();
// StopGDUUpdates(); // let lower level code discover this during next refresh
CLRBIT(gdu_dsw, GDU_DSW_BUSY);
}
EraseGDUScreen();
// EraseGDUScreen(); // let cessation of regeneration erase it (eventually)
}
static void notify_window_closed (void)
@@ -264,7 +267,9 @@ static void notify_window_closed (void)
StopGDUUpdates();
CLRBIT(gdu_dsw, GDU_DSW_BUSY);
}
CLRBIT(gdu_unit.flags, UNIT_DISPLAYED);
gdu_reset(&gdu_dev);
}
@@ -671,7 +676,7 @@ static HPEN hRedPen = NULL;
#endif
static HBRUSH hGrayBrush, hDarkBrush;
static HPEN hBlackPen;
static int halted = 0; // number of time intervals that GDU has been halted w/o a regeneration
static LRESULT APIENTRY GDUWndProc (HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam);
static DWORD WINAPI GDUPump (LPVOID arg);
@@ -719,11 +724,6 @@ static t_bool CreateGDUWindow (void)
{
static BOOL did_atexit = FALSE;
if (hwGDU != NULL) { // window already exists
StartGDUUpdates();
return TRUE;
}
hInstance = GetModuleHandle(NULL);
if (hGDUPump == INVALID_HANDLE_VALUE)
@@ -878,7 +878,7 @@ static void gdu_WM_PAINT (HWND hWnd)
static void gdu_WM_SIZE (HWND hWnd, UINT state, int cx, int cy)
{
InvalidateRect(hWnd, NULL, FALSE);
InvalidateRect(hWnd, NULL, TRUE);
}
// tweak the sizing rectangle during a resize to guarantee a square window
@@ -912,6 +912,16 @@ static void gdu_WM_TIMER (HWND hWnd, UINT id)
HDC hDC;
if (running) { // if CPU is running, update picture
if ((gdu_dsw & GDU_DSW_BUSY) == 0) { // regeneration is not to occur
if (++halted >= 4) { // stop the timer if four timer intervals go by with the display halted
EraseGDUScreen(); // screen goes black due to cessation of refreshing
StopGDUUpdates(); // might as well kill the timer
return;
}
}
else
halted = 0;
#ifdef BLIT_MODE
hDC = GetDC(hWnd); // blit the new image right over the old
PaintImage(hDC, FALSE);
@@ -964,7 +974,7 @@ static void DrawPoint (int x, int y)
static void UpdateGDUIndicators(void)
{
if (hwGDU != NULL)
InvalidateRect(hwGDU, NULL, TRUE);
InvalidateRect(hwGDU, NULL, FALSE); // no need to erase the background -- the draw routine fully paints the indicator
}
static void CheckGDUKeyboard (void)
@@ -981,6 +991,7 @@ static void StartGDUUpdates (void)
msec = (gdu_rate == 0) ? (1000 / DEFAULT_GDU_RATE) : 1000/gdu_rate;
idTimer = SetTimer(hwGDU, 1, msec, NULL);
}
halted = 0;
}
static void StopGDUUpdates (void)
@@ -988,6 +999,7 @@ static void StopGDUUpdates (void)
if (idTimer != 0) {
KillTimer(hwGDU, 1);
idTimer = 0;
halted = 10000;
}
}
@@ -1086,8 +1098,6 @@ static DWORD WINAPI GDUPump (LPVOID arg)
ShowWindow(hwGDU, SW_SHOWNOACTIVATE); /* display it */
UpdateWindow(hwGDU);
StartGDUUpdates();
while (GetMessage(&msg, hwGDU, 0, 0)) { /* message pump - this basically loops forevermore */
TranslateMessage(&msg);
DispatchMessage(&msg);

View File

@@ -11,6 +11,9 @@
* This is not a supported product, but I welcome bug reports and fixes.
* Mail to simh@ibm1130.org
*
* 30-Dec-05 BLK Fixed mask for IAR and SAR register display and added display
* of Arithmetic Factor, per Carl Claunch.
*
* 09-Apr-04 BLK Changed code to use stock windows cursor IDC_HAND if available
*
* 02-Dec-02 BLK Changed display, added printer and card reader icons
@@ -33,9 +36,9 @@
#define UPDATE_BY_TIMER
#ifdef UPDATE_BY_TIMER
# define UPDATE_INTERVAL 20 // set to desired number of updates/second
# define UPDATE_INTERVAL 20 /* set to desired number of updates/second */
#else
# define UPDATE_INTERVAL 5000 // GUI: set to 100000/f where f = desired updates/second of 1130 time
# define UPDATE_INTERVAL 5000 /* GUI: set to 100000/f where f = desired updates/second of 1130 time */
#endif
#define UNIT_V_CR_EMPTY (UNIT_V_UF + 5) /* NOTE: THESE MUST MATCH THE DEFINITION IN ibm1130_cr.c */
@@ -46,8 +49,9 @@
#define UNIT_V_PHYSICAL_PTR (UNIT_V_UF + 10) /* NOTE: THESE MUST MATCH THE DEFINITION IN ibm1130_prt.c */
#define UNIT_PHYSICAL_PTR (1u << UNIT_V_PHYSICAL_PTR)
// I think I had it wrong; Program Load actually does start the processor after
// reading in the card?
/* I think I had it wrong; Program Load actually does start the processor after
* reading in the card?
*/
#define PROGRAM_LOAD_STARTS_CPU
@@ -86,7 +90,7 @@ DEVICE console_dev = {
NULL, NULL, NULL
};
// reset for the "console" display device
/* reset for the "console" display device */
extern char *read_line (char *cptr, int size, FILE *stream);
extern FILE *sim_log;
@@ -117,8 +121,8 @@ extern UNIT prt_unit;
t_stat console_reset (DEVICE *dptr)
{
if (! sim_gui) {
SETBIT(console_unit.flags, UNIT_DIS); // disable the GUI
CLRBIT(console_unit.flags, UNIT_DISPLAY); // turn the GUI off
SETBIT(console_unit.flags, UNIT_DIS); /* disable the GUI */
CLRBIT(console_unit.flags, UNIT_DISPLAY); /* turn the GUI off */
}
update_gui(FALSE);
@@ -158,19 +162,19 @@ void scp_panic (char *msg)
#define IDC_RESET 14
#define IDC_PROGRAM_LOAD 15
#define IDC_TEAR 16 // standard button
#define IDC_1442 17 // device images
#define IDC_TEAR 16 /* standard button */
#define IDC_1442 17 /* device images */
#define IDC_1132 18
#define LAMPTIME 500 // 500 msec delay on updating
#define LAMPTIME 500 /* 500 msec delay on updating */
#define FLASH_TIMER_ID 1
#define UPDATE_TIMER_ID 2
#define RUNSWITCH_X 689 // center of the run mode switch dial
#define RUNSWITCH_X 689 /* center of the run mode switch dial */
#define RUNSWITCH_Y 107
#define TOGGLES_X 122 // left edge of series of toggle switches
#define TOGGLES_X 122 /* left edge of series of toggle switches */
#define TXTBOX_X 200 // text labels showing attached devices
#define TXTBOX_X 200 /* text labels showing attached devices */
#define TXTBOX_Y 300
#define TXTBOX_WIDTH 195
#define TXTBOX_HEIGHT 12
@@ -238,19 +242,18 @@ static struct tag_btn {
TXTBOX_X+40, TXTBOX_Y+25, 35, 12, "Tear", TRUE, FALSE, 0, NULL, NULL, NULL, FALSE,
635, 238, 110, 110, "EMPTY_1442", TRUE, FALSE, 0, NULL, NULL, NULL, FALSE,
635, 366, 110, 110, "EMPTY_1132", TRUE, FALSE, 0, NULL, NULL, NULL, FALSE,
// 635, 366, 110, 110, "EMPTY_1132", TRUE, FALSE, 0, NULL, NULL, NULL, FALSE,
};
#define NBUTTONS (sizeof(btn) / sizeof(btn[0]))
#define STATE_1442_EMPTY 0 // no cards (no file attached)
#define STATE_1442_FULL 1 // cards in hopper (file attached at BOF)
#define STATE_1442_MIDDLE 2 // cards in hopper and stacker (file attached, neither EOF nor BOF)
#define STATE_1442_EOF 3 // cards in stacker (file attached, at EOF)
#define STATE_1442_HIDDEN 4 // simulator is attached to physical card reader
#define STATE_1442_EMPTY 0 /* no cards (no file attached) */
#define STATE_1442_FULL 1 /* cards in hopper (file attached at BOF) */
#define STATE_1442_MIDDLE 2 /* cards in hopper and stacker (file attached, neither EOF nor BOF) */
#define STATE_1442_EOF 3 /* cards in stacker (file attached, at EOF) */
#define STATE_1442_HIDDEN 4 /* simulator is attached to physical card reader */
#define STATE_1132_EMPTY 0 // no paper hanging out of printer
#define STATE_1132_FULL 1 // paper hanging out of printer
#define STATE_1132_HIDDEN 2 // printer is attached to physical printer
#define STATE_1132_EMPTY 0 /* no paper hanging out of printer */
#define STATE_1132_FULL 1 /* paper hanging out of printer */
#define STATE_1132_HIDDEN 2 /* printer is attached to physical printer */
static struct tag_txtbox {
int x, y;
@@ -309,9 +312,9 @@ static void destroy_console_window (void)
int i;
if (hConsoleWnd != NULL)
SendMessage(hConsoleWnd, WM_CLOSE, 0, 0); // cross thread call is OK
SendMessage(hConsoleWnd, WM_CLOSE, 0, 0); /* cross thread call is OK */
if (hPump != INVALID_HANDLE_VALUE) { // this is not the most graceful way to do it
if (hPump != INVALID_HANDLE_VALUE) { /* this is not the most graceful way to do it */
TerminateThread(hPump, 0);
hPump = INVALID_HANDLE_VALUE;
PumpID = 0;
@@ -338,10 +341,11 @@ static void destroy_console_window (void)
NIXOBJECT(btn[i].hbrDark);
}
// if (class_defined) {
// UnregisterClass(hInstance, szConsoleClassName);
// class_defined = FALSE;
// }
/* if (class_defined) {
UnregisterClass(hInstance, szConsoleClassName);
class_defined = FALSE;
}
*/
}
/* ------------------------------------------------------------------------
@@ -350,7 +354,7 @@ static void destroy_console_window (void)
static int shown_iar = 0, shown_sar = 0, shown_sbr = 0, shown_afr = 0, shown_acc = 0, shown_ext = 0;
static int shown_op = 0, shown_tag = 0, shown_irq = 0, shown_ccc = 0, shown_cnd = 0, shown_wait = 0;
static int shown_ces = 0, shown_runmode = MODE_RUN;
static int shown_ces = 0, shown_arf = 0, shown_runmode = MODE_RUN;
static int CND;
/* ------------------------------------------------------------------------
@@ -402,7 +406,7 @@ void update_gui (BOOL force)
static int32 displayed = 0;
RECT xin;
if ((int32)(console_unit.flags & UNIT_DISPLAY) != displayed) { // setting has changed
if ((int32)(console_unit.flags & UNIT_DISPLAY) != displayed) { /* setting has changed */
displayed = console_unit.flags & UNIT_DISPLAY;
if (displayed)
init_console_window();
@@ -438,6 +442,8 @@ void update_gui (BOOL force)
{shown_iar = IAR; RedrawRegion(hConsoleWnd, 75, 8, 364, 32);} /* lamps: don't bother erasing bkgnd */
if (SAR != shown_sar)
{shown_sar = SAR; RedrawRegion(hConsoleWnd, 75, 42, 364, 65);}
if (ARF != shown_arf)
{shown_arf = ARF; RedrawRegion(hConsoleWnd, 75, 114, 364, 136);}
if (ACC != shown_acc)
{shown_acc = ACC; RedrawRegion(hConsoleWnd, 75, 141, 364, 164);}
if (EXT != shown_ext)
@@ -465,7 +471,7 @@ void update_gui (BOOL force)
int_lamps = 0;
// this loop works with lamp buttons that are calculated on-the-fly only
/* this loop works with lamp buttons that are calculated on-the-fly only */
for (i = 0; i < NBUTTONS; i++) {
if (btn[i].pushable)
continue;
@@ -475,26 +481,28 @@ void update_gui (BOOL force)
state = hFlashTimer || (running && ! wait_state);
break;
// this button is always off
// case IDC_PARITY_CHECK:
/* this button is always off
case IDC_PARITY_CHECK
*/
// these buttons are enabled/disabled directly
// case IDC_POWER_ON:
// case IDC_FILE_READY:
// case IDC_FORMS_CHECK:
// case IDC_KEYBOARD_SELECT:
// case IDC_DISK_UNLOCK:
/* these buttons are enabled/disabled directly
case IDC_POWER_ON:
case IDC_FILE_READY:
case IDC_FORMS_CHECK:
case IDC_KEYBOARD_SELECT:
case IDC_DISK_UNLOCK:
*/
default:
continue;
}
if (state != btn[i].state) { // state has changed
if (state != btn[i].state) { /* state has changed */
EnableWindow(btn[i].hBtn, state);
btn[i].state = state;
}
}
if (force) { // if force flag is set, update text region
if (force) { /* if force flag is set, update text region */
SetRect(&xin, TXTBOX_X, TXTBOX_Y, TXTBOX_X+TXTBOX_WIDTH, TXTBOX_BOTTOM+2*TXTBOX_HEIGHT);
InvalidateRect(hConsoleWnd, &xin, TRUE);
}
@@ -584,9 +592,9 @@ static int occurs (char *txt, char ch)
}
/* ------------------------------------------------------------------------
// turns out to get properly colored buttons you have to paint them yourself. Sheesh.
// On the plus side, this lets do a better job of aligning the button text than
// the button would by itself.
* turns out to get properly colored buttons you have to paint them yourself. Sheesh.
* On the plus side, this lets do a better job of aligning the button text than
* the button would by itself.
* ------------------------------------------------------------------------ */
void PaintButton (LPDRAWITEMSTRUCT dis)
@@ -616,7 +624,7 @@ void PaintButton (LPDRAWITEMSTRUCT dis)
LineTo(dis->hDC, dis->rcItem.left, dis->rcItem.top);
}
else if (down) {
// do the three-D thing
/* do the three-D thing */
hOldPen = SelectObject(dis->hDC, hDkGreyPen);
MoveToEx(dis->hDC, dis->rcItem.left, dis->rcItem.bottom-2, NULL);
LineTo(dis->hDC, dis->rcItem.left, dis->rcItem.top);
@@ -776,7 +784,7 @@ static DWORD WINAPI Pump (LPVOID arg)
hcArrow = LoadCursor(NULL, IDC_ARROW);
#ifdef IDC_HAND
hcHand = LoadCursor(NULL, IDC_HAND); // use stock object provided by Windows
hcHand = LoadCursor(NULL, IDC_HAND); /* use stock object provided by Windows */
if (hcHand == NULL)
hcHand = LoadCursor(hInstance, MAKEINTRESOURCE(IDC_MYHAND));
#else
@@ -816,12 +824,13 @@ static DWORD WINAPI Pump (LPVOID arg)
EnableWindow(btn[i].hBtn, btn[i].state);
}
// This isn't needed anymore, now that we have the big printer icon -- it acts like a button now
// i = IDC_TEAR;
// btn[i].hBtn = CreateWindow("BUTTON", btn[i].txt, WS_CHILD|WS_VISIBLE|BS_CENTER,
// btn[i].x, btn[i].y, btn[i].wx, btn[i].wy, hConsoleWnd, (HMENU) i, hInstance, NULL);
//
// SendMessage(btn[i].hBtn, WM_SETFONT, (WPARAM) hTinyFont, TRUE);
/* This isn't needed anymore, now that we have the big printer icon -- it acts like a button now
* i = IDC_TEAR;
* btn[i].hBtn = CreateWindow("BUTTON", btn[i].txt, WS_CHILD|WS_VISIBLE|BS_CENTER,
* btn[i].x, btn[i].y, btn[i].wx, btn[i].wy, hConsoleWnd, (HMENU) i, hInstance, NULL);
*
* SendMessage(btn[i].hBtn, WM_SETFONT, (WPARAM) hTinyFont, TRUE);
*/
hbm1442_full = LoadBitmap(hInstance, "FULL_1442");
hbm1442_empty = LoadBitmap(hInstance, "EMPTY_1442");
@@ -836,7 +845,6 @@ static DWORD WINAPI Pump (LPVOID arg)
btn[i].x, btn[i].y, btn[i].wx, btn[i].wy, hConsoleWnd, (HMENU) i, hInstance, NULL);
btn[i].state = STATE_1442_EMPTY;
// wx = SendMessage(btn[i].hBtn, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM) hbm1442_full);
wx = SendMessage(btn[i].hBtn, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM) hbm1442_empty);
i = IDC_1132;
@@ -847,13 +855,6 @@ static DWORD WINAPI Pump (LPVOID arg)
wx = SendMessage(btn[i].hBtn, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM) hbm1132_empty);
// for (i = 0; i < NTXTBOXES; i++) {
// txtbox[i].hBox = CreateWindow("EDIT", txtbox[i].txt,
// WS_CHILD|WS_VISIBLE|ES_LEFT|ES_READONLY,
// txtbox[i].x, txtbox[i].y, TXTBOX_WIDTH, TXTBOX_HEIGHT, hConsoleWnd, (HMENU) (i+100), hInstance, NULL);
// SendMessage(txtbox[i].hBox, WM_SETFONT, (WPARAM) hTinyFont, TRUE);
// }
GetWindowRect(hConsoleWnd, &r); /* get window size as created */
wx = r.right - r.left + 1;
wy = r.bottom - r.top + 1;
@@ -991,7 +992,7 @@ void DrawRunmode (HDC hDC, int mode)
* than a mouse-region test. Return value TRUE means the cursor is over a hotspot.
* ------------------------------------------------------------------------ */
static BOOL HandleClick (HWND hWnd, int xh, int yh, BOOL actual)
static BOOL HandleClick (HWND hWnd, int xh, int yh, BOOL actual, BOOL rightclick)
{
int b, x, r, ang, i;
@@ -1054,9 +1055,10 @@ static void DrawConsole (HDC hDC, PAINTSTRUCT *ps)
SetBkMode(hDC, TRANSPARENT); /* overlay letters w/o changing background */
DrawBits(hDC, 76, 15, shown_iar, 16, 0x3FFF, digits);
DrawBits(hDC, 76, 48, shown_sar, 16, 0x3FFF, digits);
DrawBits(hDC, 76, 15, shown_iar, 16, mem_mask, digits); /* register holds only 15 bits */
DrawBits(hDC, 76, 48, shown_sar, 16, mem_mask, digits); /* but let's display only used bits */
DrawBits(hDC, 76, 81, shown_sbr, 16, 0xFFFF, digits);
DrawBits(hDC, 76, 114, shown_arf, 16, 0xFFFF, digits);
DrawBits(hDC, 76, 147, shown_acc, 16, 0xFFFF, digits);
DrawBits(hDC, 76, 180, shown_ext, 16, 0xFFFF, digits);
@@ -1124,10 +1126,10 @@ static void DrawConsole (HDC hDC, PAINTSTRUCT *ps)
void flash_run (void)
{
EnableWindow(btn[IDC_RUN].hBtn, TRUE); // enable the run lamp
EnableWindow(btn[IDC_RUN].hBtn, TRUE); /* enable the run lamp */
if (hFlashTimer != 0)
KillTimer(hConsoleWnd, FLASH_TIMER_ID); // (re)schedule lamp update
KillTimer(hConsoleWnd, FLASH_TIMER_ID); /* (re)schedule lamp update */
hFlashTimer = SetTimer(hConsoleWnd, FLASH_TIMER_ID, LAMPTIME, NULL);
}
@@ -1154,10 +1156,12 @@ void HandleCommand (HWND hWnd, WORD wNotify, WORD idCtl, HWND hwCtl)
reset_all(0);
if (running && ! power) { /* turning off */
reason = STOP_POWER_OFF;
// this prevents message pump from running, which unfortunately locks up
// the emulator thread when it calls gui_run(FALSE) which calls EnableWindow on the Run lamp
// while (running)
// Sleep(10); /* wait for execution thread to exit */
/* wait for execution thread to exit */
/* this prevents message pump from running, which unfortunately locks up
* the emulator thread when it calls gui_run(FALSE) which calls EnableWindow on the Run lamp
* while (running)
* Sleep(10);
*/
}
btn[IDC_POWER_ON].state = power;
@@ -1175,7 +1179,7 @@ void HandleCommand (HWND hWnd, WORD wNotify, WORD idCtl, HWND hwCtl)
case MODE_INT_RUN:
case MODE_RUN:
case MODE_SI:
stuff_cmd("go");
stuff_cmd("cont");
break;
case MODE_DISP: /* display core and advance IAR */
@@ -1196,16 +1200,17 @@ void HandleCommand (HWND hWnd, WORD wNotify, WORD idCtl, HWND hwCtl)
case IDC_PROGRAM_STOP:
if (running) { /* potential race condition here */
GUI_BEGIN_CRITICAL_SECTION
SETBIT(cpu_dsw, CPU_DSW_PROGRAM_STOP);
SETBIT(ILSW[5], ILSW_5_PROGRAM_STOP);
int_req |= INT_REQ_5;
SETBIT(con_dsw, CPU_DSW_PROGRAM_STOP);
SETBIT(ILSW[5], ILSW_5_INT_RUN_PROGRAM_STOP);
int_req |= INT_REQ_5; /* note: calc_ints() is not needed in this case */
int_lamps |= INT_REQ_5;
GUI_END_CRITICAL_SECTION
}
break;
case IDC_LOAD_IAR:
if (! running) {
IAR = CES & 0x3FFF; /* set IAR from console entry switches */
IAR = CES & mem_mask; /* set IAR from console entry switches */
}
break;
@@ -1214,12 +1219,13 @@ void HandleCommand (HWND hWnd, WORD wNotify, WORD idCtl, HWND hwCtl)
case IDC_IMM_STOP:
if (running) {
reason = STOP_WAIT; /* terminate execution without setting wait_mode */
// this prevents message pump from running, which unfortunately locks up
// the emulator thread when it calls gui_run(FALSE) which calls EnableWindow on the Run lamp
// while (running)
// Sleep(10); /* wait for execution thread to exit */
reason = STOP_IMMEDIATE; /* terminate execution without setting wait_mode */
/* wait for execution thread to exit */
/* this prevents message pump from running, which unfortunately locks up
* the emulator thread when it calls gui_run(FALSE) which calls EnableWindow on the Run lamp
* while (running)
* Sleep(10);
*/
}
break;
@@ -1290,10 +1296,6 @@ LRESULT CALLBACK ConsoleWndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPa
SetRect(&rbmp, 0, 0, bmwid, bmht);
if (IntersectRect(&xsect, &clip, &rbmp))
BitBlt(hDC, xsect.left, xsect.top, xsect.right-xsect.left+1, xsect.bottom-xsect.top+1, hCDC, xsect.left, xsect.top, SRCCOPY);
// rbmp.top = rbmp.bottom;
// rbmp.bottom += 200;
// if (IntersectRect(&xsect, &clip, &rbmp))
// FillRect(hDC, &xsect, hbBlack);
return TRUE; /* let Paint do this so we know what the update region is (ps.rcPaint) */
case WM_PAINT:
@@ -1318,11 +1320,15 @@ LRESULT CALLBACK ConsoleWndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPa
case WM_SETCURSOR:
GetCursorPos(&p);
ScreenToClient(hWnd, &p);
SetCursor(HandleClick(hWnd, p.x, p.y, FALSE) ? hcHand : hcArrow);
SetCursor(HandleClick(hWnd, p.x, p.y, FALSE, FALSE) ? hcHand : hcArrow);
return TRUE;
case WM_LBUTTONDOWN:
HandleClick(hWnd, LOWORD(lParam), HIWORD(lParam), TRUE);
HandleClick(hWnd, LOWORD(lParam), HIWORD(lParam), TRUE, FALSE);
break;
case WM_RBUTTONDOWN:
HandleClick(hWnd, LOWORD(lParam), HIWORD(lParam), TRUE, TRUE);
break;
case WM_CTLCOLORBTN:
@@ -1339,7 +1345,7 @@ LRESULT CALLBACK ConsoleWndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPa
break;
case WM_DROPFILES:
accept_dropped_file((HANDLE) wParam); // console window - dragged file is a script or card deck
accept_dropped_file((HANDLE) wParam); /* console window - dragged file is a script or card deck */
break;
default:
@@ -1368,7 +1374,7 @@ void forms_check (int set)
EnableWindow(btn[IDC_FORMS_CHECK].hBtn, printerstatus);
if (btn[IDC_FORMS_CHECK].clr != oldcolor)
InvalidateRect(btn[IDC_FORMS_CHECK].hBtn, NULL, TRUE); // change color in any case
InvalidateRect(btn[IDC_FORMS_CHECK].hBtn, NULL, TRUE); /* change color in any case */
}
}
@@ -1389,7 +1395,7 @@ void print_check (int set)
EnableWindow(btn[IDC_FORMS_CHECK].hBtn, printerstatus);
if (btn[IDC_FORMS_CHECK].clr != oldcolor)
InvalidateRect(btn[IDC_FORMS_CHECK].hBtn, NULL, TRUE); // change color in any case
InvalidateRect(btn[IDC_FORMS_CHECK].hBtn, NULL, TRUE); /* change color in any case */
}
}
@@ -1425,34 +1431,34 @@ static void accept_dropped_file (HANDLE hDrop)
POINT pt;
HWND hWndDrop;
nfiles = DragQueryFile(hDrop, 0xFFFFFFFF, NULL, 0); // get file count,
DragQueryFile(hDrop, 0, fname, sizeof(fname)); // get first filename
DragQueryPoint(hDrop, &pt); // get location of drop
nfiles = DragQueryFile(hDrop, 0xFFFFFFFF, NULL, 0); /* get file count, */
DragQueryFile(hDrop, 0, fname, sizeof(fname)); /* get first filename */
DragQueryPoint(hDrop, &pt); /* get location of drop */
DragFinish(hDrop);
if (nfiles <= 0) // hmm, this seems unlikely to occur, but better check
if (nfiles <= 0) /* hmm, this seems unlikely to occur, but better check */
return;
if (running) { // can only accept a drop while processor is stopped
if (running) { /* can only accept a drop while processor is stopped */
MessageBeep(0);
return;
}
if ((hWndDrop = ChildWindowFromPoint(hConsoleWnd, pt)) == btn[IDC_1442].hBtn)
cardreader = TRUE; // file was dropped onto 1442 card reader
cardreader = TRUE; /* file was dropped onto 1442 card reader */
else if (hWndDrop == NULL || hWndDrop == hConsoleWnd)
cardreader = FALSE; // file was dropped onto console window, not a button
cardreader = FALSE; /* file was dropped onto console window, not a button */
else {
MessageBeep(0); // file was dropped onto another button
MessageBeep(0); /* file was dropped onto another button */
return;
}
if (nfiles > 1) { // oops, we wouldn't know what order to read them in
if (nfiles > 1) { /* oops, we wouldn't know what order to read them in */
MessageBox(hConsoleWnd, "You may only drop one file at a time", "", MB_OK);
return;
}
// if shift key is down, prepend @ to name (make it a deck file)
/* if shift key is down, prepend @ to name (make it a deck file) */
deckfile = ((GetKeyState(VK_SHIFT) & 0x8000) && cardreader) ? "@" : "";
sprintf(cmd, "%s \"%s%s\"", cardreader ? "attach cr" : "do", deckfile, fname);
@@ -1466,22 +1472,18 @@ static void tear_printer (void)
if ((prt_unit.flags & UNIT_ATT) == 0)
return;
strcpy(filename, prt_unit.filename); // save current attached filename
strcpy(filename, prt_unit.filename); /* save current attached filename */
if (! stuff_and_wait("detach prt", 1000, 0)) // detach it
if (! stuff_and_wait("detach prt", 1000, 0)) /* detach it */
return;
sprintf(cmd, "view \"%s\"", filename); // spawn notepad to view it
sprintf(cmd, "view \"%s\"", filename); /* spawn notepad to view it */
if (! stuff_and_wait(cmd, 3000, 500))
return;
// no, now we have them click the card reader icon twice to unload the deck. more flexible that way
// if (! stuff_and_wait("detach cr", 1000, 0)) // detach the card reader so they can edit the deck file
// return;
remove(filename); /* delete the file */
remove(filename); // delete the file
sprintf(cmd, "attach prt \"%s\"", filename); // reattach
sprintf(cmd, "attach prt \"%s\"", filename); /* reattach */
stuff_cmd(cmd);
}
@@ -1582,24 +1584,25 @@ void stuff_cmd (char *cmd)
SetEvent(hCmdReadyEvent); /* notify main thread a line is ready */
}
// my_yield - process GUI messages. It's not apparent why stuff_and_wait would block,
// since it sleeps in the GUI thread while scp runs in the main thread. However,
// at the end of every command scp calls update_gui, which can result in messages
// being sent to the GUI thread. So, the GUI thread has to process messages while
// stuff_and_wait is waiting.
/* my_yield - process GUI messages. It's not apparent why stuff_and_wait would block,
* since it sleeps in the GUI thread while scp runs in the main thread. However,
* at the end of every command scp calls update_gui, which can result in messages
* being sent to the GUI thread. So, the GUI thread has to process messages while
* stuff_and_wait is waiting.
*/
static void my_yield (void)
{
MSG msg;
// multitask
/* multitask */
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
// stuff_and_wait -- stuff a command and wait for the emulator to process the command
// and come back to prompt for another
/* stuff_and_wait -- stuff a command and wait for the emulator to process the command
* and come back to prompt for another
*/
t_bool stuff_and_wait (char *cmd, int timeout, int delay)
{
@@ -1650,5 +1653,5 @@ void remark_cmd (char *remark)
}
}
#endif // _WIN32 defined
#endif // GUI_SUPPORT defined
#endif /* _WIN32 defined */
#endif /* GUI_SUPPORT defined */

634
Ibm1130/ibm1130_plot.c Normal file
View File

@@ -0,0 +1,634 @@
/* ibm1130_plot.c: IBM 1130 1627 plotter emulation
Based on the SIMH simulator package written by Robert M Supnik
Brian Knittel
Revision History
2004.10.22 - Written.
2006.1.2 - Rewritten as plotter routine by Carl V Claunch
* (C) Copyright 2004, Brian Knittel.
* You may freely use this program, but: it offered strictly on an AS-IS, AT YOUR OWN
* RISK basis, there is no warranty of fitness for any purpose, and the rest of the
* usual yada-yada. Please keep this notice and the copyright in any distributions
* or modifications.
*
* This is not a supported product, but I welcome bug reports and fixes.
* Mail to simh@ibm1130.org
*/
#include "ibm1130_defs.h"
#ifndef ENABLE_PLOT_SUPPORT
DEVICE plot_dev = {
"PLOT", NULL, NULL, NULL,
0, 16, 16, 1, 16, 16,
NULL, NULL, NULL,
NULL, NULL, NULL};
void xio_1627_plotter (int32 addr, int32 func, int32 modify)
{
/* silently eat any plotter commands */
}
#else
#include "gd.h"
/***************************************************************************************
* 1627 model 1 plotter (based on Calcomp 535 which was sold as IBM 1627)
*
* - 11" wide carriage, addressible in .01" steps
* - continous sheet paper up to 120' in length
* - sheet moveable in .01" steps, either direction
* - switchable pen, in various colors and line widths
*
* Simulator implementation will create a JPEG image corresponding to a
* landscape mode sheet of paper, the width of the carriage at 11".
* A diagram of more than 8" of paper travel will span printed pages
* in landscape mode.
*
* When an 'att plot' command is issued a file is created based on the
* default or currently set values of paper length, starting
* position of the pen in both X and Y axes, pen color and pen width.
* Based on the number of logical pages of paper, the command will create
* the proper size canvas internally and create the output JPEG file.
*
* When a 'det plot' command is issued, the plotter image will be converted
* into the file that was specified during the attach process. The
* image is not viewable until this point, unless an examine plot is
* issued which will dump the current state of the paper into the file.
*
* The 'set plot' command can set pen width, paper length, pen color,
* current carriage X and Y coordinates. Paper length can be set
* to alter the default of 800 (8"); changes are ignored until
* the next 'attach' command. The current carriage x and y positions
* can be set at any time and will go into effect immediately, just
* as the pen color and pen width can be altered on the fly.
*
* NOTE: requires gd library and definition of ENABLE_PLOT_SUPPORT in makefile or Visual C configuration
* gd is not included in the main simh and ibm1130.org distributions at the present time.
***************************************************************************************/
#define PLOT1627_DSW_OP_COMPLETE 0x8000
#define PLOT1627_DSW_BUSY 0x0200
#define PLOT1627_DSW_NOT_READY 0x0100
#define IS_ONLINE(u) (((u)->flags & (UNIT_ATT|UNIT_DIS)) == UNIT_ATT)
#define IS_DEBUG ((plot_unit->flags & UNIT_DEBUG) == UNIT_DEBUG)
#define IS_PENDOWN ((plot_unit->flags & UNIT_PEN) == UNIT_PEN)
static t_stat plot_svc (UNIT *uptr); /* activity routine */
static t_stat plot_reset (DEVICE *dptr); /* reset of 1130 */
static t_stat plot_attach (UNIT *uptr, char *cptr); /* attach, loads plotter */
static t_stat plot_detach (UNIT *uptr); /* detach and save image */
static t_stat plot_examine (UNIT *uptr); /* update file with current canvas */
static t_stat plot_set_length (UNIT *uptr, int32 val, char * ptr, void *desc); /* set paper length */
static t_stat plot_set_pos (UNIT *uptr, int32 val, char * ptr, void *desc); /* reset current X/Y position */
static t_stat plot_show_vals(FILE *fp, UNIT *uptr, int32 val, void *descrip); /* print x, y and length */
static t_stat plot_show_nl(FILE *fp, UNIT *uptr, int32 val, void *descrip); /* overcome wacky simh behavior */
static void update_pen(void); /* will ensure pen action is correct when changes made */
static t_stat plot_validate_change (UNIT *uptr, int32 val, char * ptr, void *desc); /* when set command issued */
static void process_cmd(void); /* does actual drawing for plotter */
extern int32 sim_switches; /* switches set on simh command */
static int16 plot_dsw = 0; /* device status word */
static int16 plot_cmd = 0; /* the command to process */
static int32 plot_wait = 1000; /* plotter movement wait */
static int32 plot_xpos = 0; /* current X position */
static int32 plot_xmax = 799; /* end of paper */
static int32 plot_ypos = 0; /* current Y position */
static int32 plot_ymax = 1099; /* right edge of carriage */
#define PEN_DOWN 0x80000000
#define PEN_UP 0x00000000
static int32 plot_pen = PEN_UP; /* current pen position */
static int black_pen; /* holds color black */
static int blue_pen; /* holds color blue */
static int red_pen; /* holds color red */
static int green_pen; /* holds color green */
static int yellow_pen; /* holds yellow color */
static int purple_pen; /* holds color purple */
static int ltgrey_pen; /* holds light grey */
static int grey_pen; /* holds grey */
static int white_background; /* holds white of paper roll */
static int plot_pwidth; /* set and display variable */
static int plot_pcolor; /* set and display variable */
static int need_update = 0; /* flag to force and update_pen() */
static gdImagePtr image; /* pointer to our canvas */
#define UNIT_V_COLOR (UNIT_V_UF + 0) /* color of selected pen - 3 bits */
#define UNIT_V_WIDTH (UNIT_V_UF + 3) /* width of pen - two bits */
#define UNIT_V_NOOP (UNIT_V_UF + 5) /* dummy for set/show commands */
#define UNIT_V_DEBUG (UNIT_V_UF + 6) /* for -d switch on attach command */
#define UNIT_V_PEN (UNIT_V_UF + 7) /* track pen state */
#define UNIT_WIDTH (3u << UNIT_V_WIDTH) /* two bits */
#define UNIT_COLOR (7u << UNIT_V_COLOR) /* three bits */
#define UNIT_NOOP (1u << UNIT_V_NOOP) /* dummy for set/show */
#define UNIT_DEBUG (1u << UNIT_V_DEBUG) /* shows debug mode on */
#define UNIT_PEN (1u << UNIT_V_PEN) /* the pen state bit */
#define PEN_BLACK (0u << UNIT_V_COLOR)
#define PEN_RED (1u << UNIT_V_COLOR)
#define PEN_BLUE (2u << UNIT_V_COLOR)
#define PEN_GREEN (3u << UNIT_V_COLOR)
#define PEN_YELLOW (4u << UNIT_V_COLOR)
#define PEN_PURPLE (5u << UNIT_V_COLOR)
#define PEN_LTGREY (6u << UNIT_V_COLOR)
#define PEN_GREY (7u << UNIT_V_COLOR)
#define SET_COLOR(op) {plot_unit[0].flags &= ~UNIT_COLOR; plot_unit[0].flags |= (op);}
#define GET_COLOR (plot_unit[0].flags & UNIT_COLOR)
#define BLACK 0,0,0
#define BLUE 0,0,255
#define RED 255,0,0
#define GREEN 0,255,0
#define YELLOW 200,200,0
#define PURPLE 150,0,150
#define LTGREY 200,200,200
#define GREY 120,120,120
#define WHITE 255,255,255
#define PEN_SINGLE (0u << UNIT_V_WIDTH)
#define PEN_DOUBLE (1u << UNIT_V_WIDTH)
#define PEN_TRIPLE (2u << UNIT_V_WIDTH)
#define PEN_QUAD (3u << UNIT_V_WIDTH)
#define GET_WIDTH() (plot_unit[0].flags & UNIT_WIDTH)
#define SET_WIDTH(cd) {plot_unit[0].flags &= ~UNIT_WIDTH; un.flags |= (cd);}
UNIT plot_unit[] = {
{ UDATA (&plot_svc, UNIT_ATTABLE, 0) },
};
REG plot_reg[] = {
{ HRDATA (DSW, plot_dsw, 16) }, /* device status word */
{ DRDATA (WTIME, plot_wait, 24), PV_LEFT }, /* plotter movement wait */
{ DRDATA (Xpos, plot_xpos, 32), PV_LEFT }, /* Current X Position*/
{ DRDATA (Ypos, plot_ypos, 32), PV_LEFT }, /* Current Y Position*/
{ FLDATA (PenDown, plot_pen, 0)}, /* Current pen position - 1 = down */
{ DRDATA (PaperSize, plot_xmax, 32), PV_LEFT }, /* Length of paper in inches */
{ NULL } };
MTAB plot_mod[] = {
{ UNIT_COLOR, PEN_BLACK, "black", "BLACK", &plot_validate_change},
{ UNIT_COLOR, PEN_RED, "red", "RED", &plot_validate_change},
{ UNIT_COLOR, PEN_BLUE, "blue", "BLUE", &plot_validate_change},
{ UNIT_COLOR, PEN_GREEN, "green", "GREEN", &plot_validate_change},
{ UNIT_COLOR, PEN_YELLOW, "yellow", "YELLOW", &plot_validate_change},
{ UNIT_COLOR, PEN_PURPLE, "purple", "PURPLE", &plot_validate_change},
{ UNIT_COLOR, PEN_LTGREY, "ltgrey", "LTGREY", &plot_validate_change},
{ UNIT_COLOR, PEN_GREY, "grey", "GREY", &plot_validate_change},
{ UNIT_WIDTH, PEN_SINGLE, "1.0", "1.0", &plot_validate_change},
{ UNIT_WIDTH, PEN_DOUBLE, "2.0", "2.0", &plot_validate_change},
{ UNIT_WIDTH, PEN_TRIPLE, "3.0", "3.0", &plot_validate_change},
{ UNIT_WIDTH, PEN_QUAD, "4.0", "4.0", &plot_validate_change},
{ UNIT_PEN, UNIT_PEN, "pendown", "PENDOWN", &plot_validate_change},
{ UNIT_PEN, 0, "penup", "PENUP", &plot_validate_change},
/* below is dummy entry to trigger the show routine and print extended values */
{ UNIT_NOOP, 0, "", NULL, NULL, &plot_show_vals},
/* extended entries must allow parm for both unit and dev, but
* then they will print the value twice for a 'show plot' command
* therefore they are set to not display unless explicity requested
* and the special dummy NOOP entry will cause the print of these values */
{ MTAB_XTD | MTAB_VAL | MTAB_VUN | MTAB_VDV | MTAB_NMO, 2,
"length", "LENGTH", &plot_set_length, &plot_show_nl, &plot_reg[5]},
{ MTAB_XTD | MTAB_VAL | MTAB_VDV | MTAB_VUN | MTAB_NMO, 0,
"Xpos", "XPOS", &plot_set_pos, &plot_show_nl, &plot_reg[2]},
{ MTAB_XTD | MTAB_VAL | MTAB_VDV | MTAB_VUN | MTAB_NMO, 1,
"Ypos", "YPOS", &plot_set_pos, &plot_show_nl, &plot_reg[3]},
{ 0 } };
DEVICE plot_dev = {
"PLOT", plot_unit, plot_reg, plot_mod,
1, 16, 16, 1, 16, 16,
NULL, NULL, plot_reset,
NULL, plot_attach, plot_detach};
/* xio_1627_plotter - XIO command interpreter for the 1627 plotter model 1 */
void xio_1627_plotter (iocc_addr, iocc_func, iocc_mod)
{
char msg[80];
if (! IS_ONLINE(plot_unit) ) {
SETBIT(plot_dsw, PLOT1627_DSW_NOT_READY); /* set not ready */
if (IS_DEBUG) printf("Plotter has no paper, ignored\n");
return; /* and ignore */
}
switch (iocc_func) {
case XIO_READ: /* read XIO */
xio_error("Read XIO not supported by 1627 plotter");
break;
case XIO_WRITE: /* write: do one plotter operation */
if ((plot_dsw & PLOT1627_DSW_NOT_READY)) {
if (IS_DEBUG) printf("Wrote to non-ready Plotter\n");
break;
}
plot_cmd = (uint16) ( M[iocc_addr & mem_mask] >> 10 ); /* pick up command */
process_cmd(); /* interpret command */
sim_activate(plot_unit, plot_wait); /* schedule interrupt */
SETBIT(plot_dsw, PLOT1627_DSW_BUSY); /* mark it busy */
break;
case XIO_SENSE_DEV: /* sense device status */
ACC = plot_dsw; /* get current status */
if (iocc_mod & 0x01) { /* reset interrupts */
CLRBIT(plot_dsw, PLOT1627_DSW_OP_COMPLETE);
CLRBIT(ILSW[3], ILSW_3_1627_PLOTTER);
}
break;
case XIO_CONTROL: /* control XIO */
xio_error("Control XIO not supported by 1627 plotter");
break;
default:
sprintf(msg, "Invalid 1627 Plotter XIO function %x", iocc_func);
xio_error(msg);
}
return;
}
// plot_svc - 1627 plotter operation complete
static t_stat plot_svc (UNIT *uptr)
{
CLRBIT(plot_dsw, PLOT1627_DSW_BUSY); /* clear reader busy flag */
SETBIT(plot_dsw, PLOT1627_DSW_OP_COMPLETE); /* indicate read complete */
SETBIT(ILSW[3], ILSW_3_1627_PLOTTER); /* initiate interrupt */
calc_ints();
return SCPE_OK;
}
/* plot_reset - reset emulated plotter */
static t_stat plot_reset (DEVICE *dptr)
{
char * buf;
int32 size;
sim_cancel(plot_unit);
CLRBIT(plot_dsw, PLOT1627_DSW_BUSY | PLOT1627_DSW_OP_COMPLETE);
if (IS_DEBUG) printf("reset routine for Plotter\n");
CLRBIT(ILSW[3], ILSW_3_1627_PLOTTER);
calc_ints();
return SCPE_OK;
}
/* plot_attach - attach file to simulated plotter */
static t_stat plot_attach (UNIT *uptr, char *cptr)
{
t_stat result;
CLRBIT(uptr->flags, UNIT_DEBUG);
if (sim_switches & SWMASK('D')) SETBIT(uptr->flags, UNIT_DEBUG);
/* get the output file by using regular attach routine */
result = attach_unit(uptr, cptr);
if (result != SCPE_OK) {
if (IS_DEBUG) printf("problem attaching file\n");
return result;
}
SETBIT(plot_dsw, PLOT1627_DSW_NOT_READY); /* assume failure */
/* set up our canvas at the desired size */
image = gdImageCreate(plot_ymax+1,plot_xmax+1); /* create our canvas */
if (image == NULL) {
if (IS_DEBUG) printf("problem creating image canvas\n");
return SCPE_MEM;
}
/* set up the basic colors after image created */
white_background = gdImageColorAllocate(image,WHITE); /* white is background */
black_pen = gdImageColorAllocate(image,BLACK); /* load up black color */
blue_pen = gdImageColorAllocate(image,BLUE); /* load up blue color */
red_pen = gdImageColorAllocate(image,RED); /* load up red color */
green_pen = gdImageColorAllocate(image,GREEN); /* load up green color */
yellow_pen = gdImageColorAllocate(image,YELLOW); /* load up yellow color */
purple_pen = gdImageColorAllocate(image,PURPLE); /* load up purple color */
ltgrey_pen = gdImageColorAllocate(image,LTGREY); /* load up light grey color */
grey_pen = gdImageColorAllocate(image,GREY); /* load up grey color */
if ( (white_background == -1) || (black_pen == -1) ||
(red_pen == -1) || (blue_pen == -1) || (green_pen == -1) ||
(purple_pen == -1) || (ltgrey_pen == -1) || (grey_pen == -1) ) {
if (IS_DEBUG) printf("problem allocating pen colors\n");
return SCPE_MEM;
}
CLRBIT(plot_dsw, PLOT1627_DSW_NOT_READY); /* we're in business */
update_pen(); /* routine to ensure pen is okay */
return SCPE_OK;
}
/* pen updating routine, called at attach and whenever we reset the values */
void update_pen (void)
{
int color;
int width;
if (!IS_ONLINE(plot_unit)) return; /* only do this if attached */
/* pick up latest color as active pen */
color = GET_COLOR;
switch (color) {
case PEN_BLACK:
plot_pcolor = black_pen;
break;
case PEN_RED:
plot_pcolor = red_pen;
break;
case PEN_BLUE:
plot_pcolor = blue_pen;
break;
case PEN_GREEN:
plot_pcolor = green_pen;
break;
case PEN_YELLOW:
plot_pcolor = yellow_pen;
break;
case PEN_PURPLE:
plot_pcolor = purple_pen;
break;
case PEN_LTGREY:
plot_pcolor = ltgrey_pen;
break;
case PEN_GREY:
plot_pcolor = grey_pen;
break;
default:
if (IS_DEBUG) printf("invalid pen color state\n");
plot_pcolor = black_pen;
break;
}
/* set up anti-aliasing for the line */
gdImageSetAntiAliased(image, plot_pcolor);
/* pick up latest width for pen */
width = GET_WIDTH();
switch (width) {
case PEN_SINGLE:
plot_pwidth = 1;
gdImageSetThickness(image, 1);
break;
case PEN_TRIPLE:
plot_pwidth = 3;
gdImageSetThickness(image, 3);
break;
case PEN_DOUBLE:
plot_pwidth = 2;
gdImageSetThickness(image, 2);
break;
case PEN_QUAD:
plot_pwidth = 4;
gdImageSetThickness(image, 4);
break;
default:
if (IS_DEBUG) printf("invalid pen width\n");
plot_pwidth = 1;
gdImageSetThickness(image, 1);
break;
}
/* now ensure the pen state is accurate */
plot_pen = IS_PENDOWN ? PEN_DOWN : PEN_UP;
return;
}
/* plot_detach - detach file from simulated plotter */
static t_stat plot_detach (UNIT *uptr)
{
char * buf;
int32 size;
FILE * fp;
int32 result;
SETBIT(plot_dsw, PLOT1627_DSW_NOT_READY);
/* copy images to files, close files, set device to detached, free gd memory */
buf = gdImageGifPtr(image,&size);
if (! buf) {
if (IS_DEBUG) printf("failure creating GIF in-memory\n");
return SCPE_MEM;
}
fp = uptr->fileref; /* get file attached to unit */
if (! fseek(fp,0,SEEK_SET)) { /* first we reset to begin of file */
if (IS_DEBUG) printf("wrote out GIF to file\n");
result = fwrite(buf,1,size,fp); /* write out our image to the file */
}
gdFree(buf); /* free up the memory of GIF format */
gdImageDestroy(image); /* free up the canvas memory */
if (result != size) { /* some problem writing it */
if (IS_DEBUG) printf("error in write of image file\n");
return SCPE_IOERR;
}
return detach_unit(uptr); /* have simh close the file */
}
/* process_cmd - implement the drawing actions of the plotter */
static void process_cmd (void)
{
int32 oldx, oldy;
/* first see if we set any changes to pen or position, do an update */
if (need_update) {
update_pen();
need_update = 0;
}
/* will move pen one step or flip pen up or down */
oldx = plot_xpos;
oldy = plot_ypos;
switch (plot_cmd) {
case 1: /* raise pen command */
plot_pen = PEN_UP;
plot_unit->flags = plot_unit->flags & (~UNIT_PEN);
return;
break;
case 2: /* +Y command */
plot_ypos = plot_ypos + 1;
break;
case 4: /* -Y command */
plot_ypos = plot_ypos - 1;
break;
case 8: /* -X command */
plot_xpos = plot_xpos - 1;
break;
case 10: /* -X +Y command */
plot_xpos = plot_xpos - 1;
plot_ypos = plot_ypos + 1;
break;
case 12: /* -X -Y command */
plot_xpos = plot_xpos - 1;
plot_ypos = plot_ypos - 1;
break;
case 16: /* +X command */
plot_xpos = plot_xpos + 1;
break;
case 18: /* +X +Y command */
plot_xpos = plot_xpos + 1;
plot_ypos = plot_ypos + 1;
break;
case 20: /* +X -Y pen command */
plot_xpos = plot_xpos + 1;
plot_ypos = plot_ypos - 1;
break;
case 32: /* lower pen command */
plot_pen = PEN_DOWN;
plot_unit->flags = plot_unit->flags | UNIT_PEN;
return;
break;
default:
if (IS_DEBUG) printf("invalid plotter command\n");
return;
break;
}
/* check to see if carriage has moved off any edge */
if ((plot_xpos > (plot_xmax+1)) || (plot_ypos > (plot_ymax+1)) ||
(plot_xpos < 0) || (plot_ypos < 0)) {
/* if so, ignore as 1627 has no way of signalling error */
if (IS_DEBUG) printf(
"attempted to move carriage off paper edge %d %d for command %d\n",
plot_xpos,plot_ypos,plot_cmd);
return;
}
/* only draw a line if the pen was down during the movement command */
if (plot_pen) {
gdImageLine(image, plot_ymax-plot_ypos, plot_xmax-plot_xpos, plot_ymax-oldy, plot_xmax-oldx, gdAntiAliased);
/* semantics are 0,0 point is lower right */
}
return;
}
/* plot_set_length - validate and store the length of the paper */
static t_stat plot_set_length (UNIT *uptr, int32 set, char *ptr, void *desc)
{
char *cptr;
int32 val;
#define LONGEST_ROLL 1440000 /* longest is 120', 14400", 1,440,000 .01"s */
val = strtotv (ptr, &cptr, (uint32) 10); /* sim routine to get value */
if ((val < 1) | (val >= LONGEST_ROLL)) { /* check valid range */
if (IS_DEBUG) printf("setting paper more than 120' or less than 1 inch\n");
return SCPE_ARG;
}
/* origin zero drawing, reduce by 1 but show command will fudge by adding it back */
*((int32 *)((REG *) desc)->loc) = val - 1;
return SCPE_OK;
}
/* plot_set_pos - validate and store the new position of the carriage */
static t_stat plot_set_pos (UNIT *uptr, int32 set, char *ptr, void *desc)
{
char *cptr;
int32 val;
int32 max;
max = (set == 1) ? plot_ymax : plot_xmax;
val = strtotv (ptr, &cptr, (uint32) 10);
if ((val < 0) | (val > max)) {
if (IS_DEBUG) printf("error moving carriage off paper edge\n");
return SCPE_ARG;
}
*((int32 *)((REG *) desc)->loc) = val;
return SCPE_OK;
}
/* routine to display the paper length and carriage position
* cannot use regular simh routine because it prints values twice,
* once for device and once for unit
*/
static t_stat plot_show_vals (FILE *fp, UNIT *uptr, int32 val, void *descrip)
{
fprintf(fp, "length=%d, Xpos=%d, Ypos=%d",plot_xmax+1, plot_xpos,plot_ypos);
return SCPE_OK;
}
/* routine to add a terminating NL character when 'show plot length'
* or equivalent for xpos or ypos is issued, as simh will not append for us */
static t_stat plot_show_nl(FILE *fp, UNIT *uptr, int32 val, void *descrip)
{
int32 disp;
char *label;
disp = (val == 2) ? plot_xmax + 1 : ((val == 1) ? plot_ypos : plot_xpos);
label = (val == 2) ? "length=" : ((val == 1) ? "Ypos=" : "Xpos=");
fprintf(fp, "%s%d\n", label, disp);
return SCPE_OK;
}
/* plot_validate_change - force the update_pen routine to be called after user changes pen setting */
static t_stat plot_validate_change (UNIT *uptr, int32 set, char *ptr, void *desc)
{
need_update = 1;
return SCPE_OK;
}
#endif /* ENABLE_PLOT_SUPPORT */

View File

@@ -5,6 +5,17 @@
Brian Knittel
Revision History
2006.12.06 - Moved CGI stuff out of this routine into cgi1130 main() module.
2006.07.06 - Made 1403 printer 132 columns wide, was 120 previously
2006.01.03 - Fixed bug in prt_attach, found and fixed by Carl Claunch. Detach followed
by reattach of 1403-mode printer left device permanently not-ready.
2004.11.08 - HACK for demo mode: in physical (-p) mode, multiple consecutive formfeeds are suppressed.
This lets us do a formfeed at the end of a job to kick the last page out
without getting another blank page at the beginning of the next job.
2003.12.02 - Added -p option for physical line printer output (flushes
output buffer after each line). When using a physical printer on
Windows, be sure to set printer to "send output directly to printer"
@@ -36,6 +47,7 @@
*/
#include "ibm1130_defs.h"
#include <stdlib.h> /* needed for atexit, for cgi mode */
/***************************************************************************************
* 1132 PRINTER
@@ -87,6 +99,8 @@ static int32 prt_fwait = 100; /* fast wait, for 1403 operations */
static int32 prt_twait = 50; /* transfer wait, for 1403 operations */
#define SKIPTARGET (uptr->u4) /* target for skip operation */
static t_bool formfed = FALSE; /* last line printed was a formfeed */
#define UNIT_V_FORMCHECK (UNIT_V_UF + 0) /* out of paper error */
#define UNIT_V_DATACHECK (UNIT_V_UF + 1) /* printer overrun error */
#define UNIT_V_SKIPPING (UNIT_V_UF + 2) /* printer skipping */
@@ -145,12 +159,13 @@ DEVICE prt_dev = {
NULL, NULL, &prt_reset,
NULL, prt_attach, prt_detach};
#define PRT_COLUMNS 120
#define PRT_ROWLEN 120
#define MAX_OVPRINT 20
#define MAX_COLUMNS 120
#define MAX_OVPRINT 20
#define PRT1132_COLUMNS 120
#define PRT1403_COLUMNS 120 /* the 1130's version of the 1403 printed in 120 columns only (see Functional Characteristics) */
static char prtbuf[PRT_ROWLEN*MAX_OVPRINT];
static int nprint[PRT_COLUMNS], ncol[MAX_OVPRINT], maxnp;
static char prtbuf[MAX_COLUMNS*MAX_OVPRINT];
static int nprint[MAX_COLUMNS], ncol[MAX_OVPRINT], maxnp;
static int prt_nchar, prt_row; /* current printwheel position, current page row */
static int prt_nnl; /* number of queued newlines */
@@ -178,18 +193,18 @@ static struct tag_ccpunches { /* list of rows and punches on tape */
int row, channels;
}
ccpunches[] = {
2, CC_CHANNEL_1, // channel 1 = top of form
62, CC_CHANNEL_12 // channel 12 = bottom of form
2, CC_CHANNEL_1, /* channel 1 = top of form */
62, CC_CHANNEL_12 /* channel 12 = bottom of form */
},
cccgi[] = {
2, CC_CHANNEL_1 // channel 1 = top of form; no bottom of form
2, CC_CHANNEL_1 /* channel 1 = top of form; no bottom of form */
};
#include "ibm1130_prtwheel.h"
extern int32 sim_switches;
// cc_format_1132 and cc_format_1403 - turn cctape bits into proper format for DSW or status read
/* cc_format_1132 and cc_format_1403 - turn cctape bits into proper format for DSW or status read */
static int cc_format_1132 (int bits)
{
@@ -200,7 +215,7 @@ static int cc_format_1132 (int bits)
#define cc_format_1403(bits) (bits)
// reset_prt_line - clear the print line following paper advancement
/* reset_prt_line - clear the print line following paper advancement */
static void reset_prt_line (void)
{
@@ -209,116 +224,116 @@ static void reset_prt_line (void)
maxnp = 0;
}
// save_1132_prt_line - fire hammers for character 'ch'
/* save_1132_prt_line - fire hammers for character 'ch' */
static t_bool save_1132_prt_line (int ch)
{
int i, r, addr = 32;
int32 mask = 0, wd = 0;
for (i = 0; i < PRT_COLUMNS; i++) {
if (mask == 0) { // fetch next word from memory
for (i = 0; i < PRT1132_COLUMNS; i++) {
if (mask == 0) { /* fetch next word from memory */
mask = 0x8000;
wd = M[addr++];
}
if (wd & mask) { // hammer is to fire in this column
if (wd & mask) { /* hammer is to fire in this column */
if ((r = nprint[i]) < MAX_OVPRINT) {
if (ncol[r] <= i) { // we haven't moved this far yet
if (ncol[r] == 0) // first char in this row?
memset(prtbuf+r*PRT_ROWLEN, ' ', PRT_COLUMNS); // blank out the new row
ncol[r] = i+1; // remember new row length
if (ncol[r] <= i) { /* we haven't moved this far yet */
if (ncol[r] == 0) /* first char in this row? */
memset(prtbuf+r*MAX_COLUMNS, ' ', PRT1132_COLUMNS); /* blank out the new row */
ncol[r] = i+1; /* remember new row length */
}
prtbuf[r*PRT_ROWLEN + i] = (char) ch; // save the character
prtbuf[r*MAX_COLUMNS + i] = (char) ch; /* save the character */
nprint[i]++; // remember max overprintings for this column
nprint[i]++; /* remember max overprintings for this column */
maxnp = MAX(maxnp, nprint[i]);
}
}
mask >>= 1; // prepare to examine next bit
mask >>= 1; /* prepare to examine next bit */
}
return wd & 1; // return TRUE if the last word has lsb set, which means all bits had been set
return wd & 1; /* return TRUE if the last word has lsb set, which means all bits had been set */
}
// write_line - write collected line to output file. No need to trim spaces as the hammers
// are never fired for them, so ncol[r] is the last printed position on each line.
/* write_line - write collected line to output file. No need to trim spaces as the hammers
* are never fired for them, so ncol[r] is the last printed position on each line.
*/
static void newpage (FILE *fd)
static void newpage (FILE *fd, t_bool physical_printer)
{
if (cgi)
fputs("<HR>\n", fd);
else
putc('\f', fd); // formfeed
else if (! formfed) {
putc('\f', fd);
if (physical_printer) {
fflush(fd); /* send the ff out to the printer immediately */
formfed = TRUE; /* hack: inhibit consecutive ff's */
}
}
}
static void flush_prt_line (FILE *fd, int spacemode, t_bool phys_flush)
static void flush_prt_line (FILE *fd, int spacemode, t_bool physical_printer)
{
int r;
if (! (spacemode || maxnp)) // nothing to do
if (! (spacemode || maxnp)) /* nothing to do */
return;
prt_row = (prt_row+1) % PRT_PAGELENGTH; // NEXT line
prt_row = (prt_row+1) % PRT_PAGELENGTH; /* NEXT line */
if (spacemode && ! maxnp) { // spacing only
if (spacemode && ! maxnp) { /* spacing only */
if (prt_row == 0 && prt_nnl) {
#ifdef _WIN32
if (! cgi)
putc('\r', fd); // DOS/Windows: end with cr/lf
putc('\r', fd); /* DOS/Windows: end with cr/lf */
#endif
putc('\n', fd); // otherwise end with lf
if (spacemode & UNIT_SKIPPING) // add formfeed if we crossed page boundary while skipping
newpage(fd);
putc('\n', fd); /* otherwise end with lf */
if (spacemode & UNIT_SKIPPING) /* add formfeed if we crossed page boundary while skipping */
newpage(fd, physical_printer);
prt_nnl = 0;
}
else
else {
prt_nnl++;
formfed = FALSE;
}
prt_unit->pos++; // note something written
prt_unit->pos++; /* note something written */
return;
}
if (prt_nnl) { // there are queued newlines
// if we spaced to top of form, don't emit formfeed. We'd only ever emit the formfeed if we skipped via control tape channels
// if (prt_row == 0 && prt_nnl) { // we spaced to top of form
//#ifdef _WIN32
// if (! cgi)
// putc('\r', fd); // DOS/Windows: end with cr/lf
//#endif
// putc('\n', fd); // otherwise end with lf
// newpage(fd);
// prt_nnl = 0;
// }
// else {
while (prt_nnl > 0) { // spit out queued newlines
if (prt_nnl) { /* there are queued newlines */
while (prt_nnl > 0) { /* spit out queued newlines */
#ifdef _WIN32
if (! cgi)
putc('\r', fd); // DOS/Windows: end with cr/lf
if (! cgi)
putc('\r', fd); /* DOS/Windows: end with cr/lf */
#endif
putc('\n', fd); // otherwise end with lf
prt_nnl--;
}
// }
putc('\n', fd); /* otherwise end with lf */
prt_nnl--;
}
}
for (r = 0; r < maxnp; r++) {
if (r > 0)
putc('\r', fd); // carriage return between overprinted lines
fxwrite(&prtbuf[r*PRT_ROWLEN], 1, ncol[r], fd);
putc('\r', fd); /* carriage return between overprinted lines */
fxwrite(&prtbuf[r*MAX_COLUMNS], 1, ncol[r], fd);
}
reset_prt_line();
prt_unit->pos++; // note something written
prt_nnl++; // queue a newline
prt_unit->pos++; /* note something written */
prt_nnl++; /* queue a newline */
if (phys_flush) // if physical printer, send buffered output to device
if (physical_printer) /* if physical printer, send buffered output to device */
fflush(fd);
formfed = FALSE; /* note that something is now on the page */
}
// 1132 printer commands
/* 1132 printer commands */
#define PRT_CMD_START_PRINTER 0x0080
#define PRT_CMD_STOP_PRINTER 0x0040
@@ -347,7 +362,7 @@ void xio_1132_printer (int32 iocc_addr, int32 func, int32 modify)
switch (func) {
case XIO_READ:
M[iocc_addr & mem_mask] = (uint16) (codewheel1132[prt_nchar].ebcdic << 8);
M[iocc_addr & mem_mask] = codewheel1132[prt_nchar].ebcdic << 8;
if ((uptr->flags & UNIT_PRINTING) == 0) /* if we're not printing, advance this after every test */
prt_nchar = (prt_nchar + 1) % WHEELCHARS_1132;
@@ -364,31 +379,31 @@ void xio_1132_printer (int32 iocc_addr, int32 func, int32 modify)
case XIO_CONTROL:
if (modify & PRT_CMD_START_PRINTER) {
SETBIT(uptr->flags, UNIT_PRINTING);
// mytrace(1, "printing");
/* mytrace(1, "printing"); */
}
if (modify & PRT_CMD_STOP_PRINTER) {
CLRBIT(uptr->flags, UNIT_PRINTING);
// mytrace(0, "printing");
/* mytrace(0, "printing"); */
}
if (modify & PRT_CMD_START_CARRIAGE) {
SETBIT(uptr->flags, UNIT_SKIPPING);
// mytrace(1, "skipping");
/* mytrace(1, "skipping"); */
}
if (modify & PRT_CMD_STOP_CARRIAGE) {
CLRBIT(uptr->flags, UNIT_SKIPPING);
// mytrace(0, "skipping");
/* mytrace(0, "skipping"); */
}
if (modify & PRT_CMD_SPACE) {
SETBIT(uptr->flags, UNIT_SPACING);
// mytrace(1, "space");
/* mytrace(1, "space"); */
}
sim_cancel(uptr);
if (uptr->flags & (UNIT_SKIPPING|UNIT_SPACING|UNIT_PRINTING)) { // busy bits = doing something
if (uptr->flags & (UNIT_SKIPPING|UNIT_SPACING|UNIT_PRINTING)) { /* busy bits = doing something */
SETBIT(PRT_DSW, PRT1132_DSW_PRINTER_BUSY);
sim_activate(uptr, prt_cwait);
}
@@ -419,14 +434,14 @@ static t_stat prt_svc (UNIT *uptr)
return IS_1403(uptr) ? prt1403_svc(uptr) : prt1132_svc(uptr);
}
// prt1132_svc - emulated timeout for 1132 operation
/* prt1132_svc - emulated timeout for 1132 operation */
static t_stat prt1132_svc (UNIT *uptr)
{
if (PRT_DSW & PRT1132_DSW_NOT_READY) { // cancel operation if printer went offline
if (PRT_DSW & PRT1132_DSW_NOT_READY) { /* cancel operation if printer went offline */
SETBIT(uptr->flags, UNIT_FORMCHECK);
SET_ACTION(uptr, 0);
forms_check(TRUE); // and turn on forms check lamp
forms_check(TRUE); /* and turn on forms check lamp */
return SCPE_OK;
}
@@ -436,7 +451,7 @@ static t_stat prt1132_svc (UNIT *uptr)
CLRBIT(PRT_DSW, PRT1132_DSW_CHANNEL_MASK|PRT1132_DSW_PRINTER_BUSY|PRT1132_DSW_CARRIAGE_BUSY);
SETBIT(PRT_DSW, cc_format_1132(cctape[prt_row]) | PRT1132_DSW_SPACE_RESPONSE);
SETBIT(ILSW[1], ILSW_1_1132_PRINTER);
CLRBIT(uptr->flags, UNIT_SPACING); // done with this
CLRBIT(uptr->flags, UNIT_SPACING); /* done with this */
calc_ints();
}
@@ -445,7 +460,7 @@ static t_stat prt1132_svc (UNIT *uptr)
flush_prt_line(uptr->fileref, UNIT_SKIPPING, IS_PHYSICAL(uptr));
CLRBIT(PRT_DSW, PRT1132_DSW_CHANNEL_MASK);
SETBIT(PRT_DSW, cc_format_1132(cctape[prt_row]));
} while ((cctape[prt_row] & CC_1132_BITS) == 0); // slew directly to a cc tape punch
} while ((cctape[prt_row] & CC_1132_BITS) == 0); /* slew directly to a cc tape punch */
SETBIT(PRT_DSW, cc_format_1132(cctape[prt_row]) | PRT1132_DSW_SKIP_RESPONSE);
SETBIT(ILSW[1], ILSW_1_1132_PRINTER);
@@ -453,21 +468,21 @@ static t_stat prt1132_svc (UNIT *uptr)
}
if (uptr->flags & UNIT_PRINTING) {
if (! save_1132_prt_line(codewheel1132[prt_nchar].ascii)) { // save previous printed line
SETBIT(uptr->flags, UNIT_DATACHECK); // buffer wasn't set in time
if (! save_1132_prt_line(codewheel1132[prt_nchar].ascii)) { /* save previous printed line */
SETBIT(uptr->flags, UNIT_DATACHECK); /* buffer wasn't set in time */
SET_ACTION(uptr, 0);
print_check(TRUE); // and turn on forms check lamp
print_check(TRUE); /* and turn on forms check lamp */
return SCPE_OK;
}
prt_nchar = (prt_nchar + 1) % WHEELCHARS_1132; // advance print drum
prt_nchar = (prt_nchar + 1) % WHEELCHARS_1132; /* advance print drum */
SETBIT(PRT_DSW, PRT1132_DSW_READ_EMITTER_RESPONSE); // issue interrupt to tell printer to set buffer
SETBIT(ILSW[1], ILSW_1_1132_PRINTER); // we'll save the printed stuff just before next emitter response (later than on real 1130)
SETBIT(PRT_DSW, PRT1132_DSW_READ_EMITTER_RESPONSE); /* issue interrupt to tell printer to set buffer */
SETBIT(ILSW[1], ILSW_1_1132_PRINTER); /* we'll save the printed stuff just before next emitter response (later than on real 1130) */
calc_ints();
}
if (uptr->flags & (UNIT_SPACING|UNIT_SKIPPING|UNIT_PRINTING)) { // still doing something
if (uptr->flags & (UNIT_SPACING|UNIT_SKIPPING|UNIT_PRINTING)) { /* still doing something */
SETBIT(PRT_DSW, PRT1132_DSW_PRINTER_BUSY);
sim_activate(uptr, prt_cwait);
}
@@ -483,18 +498,18 @@ void save_1403_prt_line (int32 addr)
unsigned char ebcdic;
int32 wd;
for (i = 0; i < PRT_COLUMNS; i++) {
if (even) { // fetch next word from memory
for (i = 0; i < PRT1403_COLUMNS; i++) {
if (even) { /* fetch next word from memory */
wd = M[addr++];
ebcdic = (unsigned char) ((wd >> 8) & 0x7F);
even = FALSE;
}
else {
ebcdic = (unsigned char) (wd & 0x7F); // use low byte of previously fetched word
ebcdic = (unsigned char) (wd & 0x7F); /* use low byte of previously fetched word */
even = TRUE;
}
ch = ' '; // translate ebcdic to ascii. Don't bother checking for parity errors
ch = ' '; /* translate ebcdic to ascii. Don't bother checking for parity errors */
for (j = 0; j < WHEELCHARS_1403; j++) {
if (codewheel1403[j].ebcdic == ebcdic) {
ch = codewheel1403[j].ascii;
@@ -504,14 +519,14 @@ void save_1403_prt_line (int32 addr)
if (ch > ' ') {
if ((r = nprint[i]) < MAX_OVPRINT) {
if (ncol[r] <= i) { // we haven't moved this far yet
if (ncol[r] == 0) // first char in this row?
memset(prtbuf+r*PRT_ROWLEN, ' ', PRT_COLUMNS); // blank out the new row
ncol[r] = i+1; // remember new row length
if (ncol[r] <= i) { /* we haven't moved this far yet */
if (ncol[r] == 0) /* first char in this row? */
memset(prtbuf+r*MAX_COLUMNS, ' ', PRT1403_COLUMNS); /* blank out the new row */
ncol[r] = i+1; /* remember new row length */
}
prtbuf[r*PRT_ROWLEN + i] = (char) ch; // save the character
prtbuf[r*MAX_COLUMNS + i] = (char) ch; /* save the character */
nprint[i]++; // remember max overprintings for this column
nprint[i]++; /* remember max overprintings for this column */
maxnp = MAX(maxnp, nprint[i]);
}
}
@@ -568,15 +583,15 @@ void xio_1403_printer (int32 iocc_addr, int32 func, int32 modify)
static t_stat prt1403_svc(UNIT *uptr)
{
if (PRT_DSW & PRT1403_DSW_NOT_READY) { // cancel operation if printer went offline
if (PRT_DSW & PRT1403_DSW_NOT_READY) { /* cancel operation if printer went offline */
SET_ACTION(uptr, 0);
forms_check(TRUE); // and turn on forms check lamp
forms_check(TRUE); /* and turn on forms check lamp */
}
else if (uptr->flags & UNIT_TRANSFERRING) { // end of transfer
else if (uptr->flags & UNIT_TRANSFERRING) { /* end of transfer */
CLRBIT(uptr->flags, UNIT_TRANSFERRING);
SETBIT(uptr->flags, UNIT_PRINTING); // schedule "print complete"
SETBIT(uptr->flags, UNIT_PRINTING); /* schedule "print complete" */
SETBIT(PRT_DSW, PRT1403_DSW_TRANSFER_COMPLETE); // issue transfer complete interrupt
SETBIT(PRT_DSW, PRT1403_DSW_TRANSFER_COMPLETE); /* issue transfer complete interrupt */
SETBIT(ILSW[4], ILSW_4_1403_PRINTER);
}
else if (uptr->flags & UNIT_PRINTING) {
@@ -584,14 +599,14 @@ static t_stat prt1403_svc(UNIT *uptr)
CLRBIT(PRT_DSW, PRT1403_DSW_PRINTER_BUSY);
SETBIT(PRT_DSW, PRT1403_DSW_PRINT_COMPLETE);
SETBIT(ILSW[4], ILSW_4_1403_PRINTER); // issue print complete interrupt
SETBIT(ILSW[4], ILSW_4_1403_PRINTER); /* issue print complete interrupt */
}
else if (uptr->flags & UNIT_SKIPPING) {
do { // find line with exact match of tape punches
do { /* find line with exact match of tape punches */
flush_prt_line(uptr->fileref, UNIT_SKIPPING, IS_PHYSICAL(uptr));
} while (cctape[prt_row] != SKIPTARGET); // slew directly to requested cc tape punch
} while (cctape[prt_row] != SKIPTARGET); /* slew directly to requested cc tape punch */
CLRBIT(uptr->flags, UNIT_SKIPPING); // done with this
CLRBIT(uptr->flags, UNIT_SKIPPING); /* done with this */
CLRBIT(PRT_DSW, PRT1403_DSW_CARRIAGE_BUSY);
SETBIT(PRT_DSW, PRT1403_DSW_CARRIAGE_COMPLETE);
@@ -600,7 +615,7 @@ static t_stat prt1403_svc(UNIT *uptr)
else if (uptr->flags & UNIT_SPACING) {
flush_prt_line(uptr->fileref, UNIT_SPACING, IS_PHYSICAL(uptr));
CLRBIT(uptr->flags, UNIT_SPACING); // done with this
CLRBIT(uptr->flags, UNIT_SPACING); /* done with this */
CLRBIT(PRT_DSW, PRT1403_DSW_CARRIAGE_BUSY);
SETBIT(PRT_DSW, PRT1403_DSW_CARRIAGE_COMPLETE);
@@ -610,7 +625,7 @@ static t_stat prt1403_svc(UNIT *uptr)
if (uptr->flags & (UNIT_PRINTING|UNIT_SKIPPING|UNIT_SPACING|UNIT_TRANSFERRING))
sim_activate(uptr, prt_fwait);
CLRBIT(PRT_DSW, PRT1403_DSW_CH9|PRT1403_DSW_CH12); // set the two CC bits in the DSW
CLRBIT(PRT_DSW, PRT1403_DSW_CH9|PRT1403_DSW_CH12); /* set the two CC bits in the DSW */
if (cctape[prt_row] & CC_CHANNEL_9)
SETBIT(PRT_DSW, PRT1403_DSW_CH9);
if (cctape[prt_row] & CC_CHANNEL_12)
@@ -646,16 +661,17 @@ static t_stat prt_reset (DEVICE *dptr)
UNIT *uptr = &prt_unit[0];
int i;
// add a DELETE filename command so we can be sure to have clean listings
/* add a DELETE filename command so we can be sure to have clean listings */
register_cmd("DELETE", &delete_cmd, 0, "del{ete} filename remove file\n");
sim_cancel(uptr);
memset(cctape, 0, sizeof(cctape)); // copy punch list into carriage control tape image
memset(cctape, 0, sizeof(cctape)); /* copy punch list into carriage control tape image */
if (cgi)
if (cgi) {
for (i = 0; i < (sizeof(cccgi)/sizeof(cccgi[0])); i++)
cctape[cccgi[i].row-1] |= cccgi[i].channels;
}
else
for (i = 0; i < (sizeof(ccpunches)/sizeof(ccpunches[0])); i++)
cctape[ccpunches[i].row-1] |= ccpunches[i].channels;
@@ -697,6 +713,7 @@ static t_stat prt_attach (UNIT *uptr, char *cptr)
t_stat rval;
/* assume failure */
SETBIT(PRT_DSW, IS_1132(uptr) ? PRT1132_DSW_NOT_READY : PRT1403_DSW_NOT_READY);
formfed = FALSE;
if (uptr->flags & UNIT_ATT) {
if ((rval = prt_detach(uptr)) != SCPE_OK) {
@@ -745,7 +762,7 @@ static t_stat prt_attach (UNIT *uptr, char *cptr)
reset_prt_line();
if (IS_1132(uptr)) {
PRT_DSW = (uint16) ((PRT_DSW & ~PRT1132_DSW_CHANNEL_MASK) | cc_format_1132(cctape[prt_row]));
PRT_DSW = (PRT_DSW & ~PRT1132_DSW_CHANNEL_MASK) | cc_format_1132(cctape[prt_row]);
if (IS_ONLINE(uptr))
CLRBIT(PRT_DSW, PRT1132_DSW_NOT_READY);
@@ -758,10 +775,11 @@ static t_stat prt_attach (UNIT *uptr, char *cptr)
SETBIT(PRT_DSW, PRT1403_DSW_CH12);
if (IS_ONLINE(uptr))
CLRBIT(PRT_DSW, PRT1132_DSW_NOT_READY);
CLRBIT(PRT_DSW, PRT1403_DSW_NOT_READY); /* fixed by Carl Claunch */
}
forms_check(FALSE);
return SCPE_OK;
}
@@ -769,7 +787,8 @@ static t_stat prt_detach (UNIT *uptr)
{
t_stat rval;
flush_prt_line(uptr->fileref, TRUE, TRUE);
if (uptr->flags & UNIT_ATT)
flush_prt_line(uptr->fileref, TRUE, TRUE);
if (uptr->fileref == stdout) {
CLRBIT(uptr->flags, UNIT_ATT);
@@ -797,3 +816,4 @@ static t_stat prt_detach (UNIT *uptr)
forms_check(FALSE);
return SCPE_OK;
}

View File

@@ -81,7 +81,7 @@ DEVICE ptp_dev = {
/* xio_1134_papertape - XIO command interpreter for the 1134 paper tape reader and 1055 paper tape punch */
void xio_1134_papertape (int iocc_addr, int iocc_func, int iocc_mod)
void xio_1134_papertape (int32 iocc_addr, int32 iocc_func, int32 iocc_mod)
{
char msg[80];
@@ -118,7 +118,7 @@ void xio_1134_papertape (int iocc_addr, int iocc_func, int iocc_mod)
}
}
// ptr_svc - emulated timeout - 1134 read operation complete
/* ptr_svc - emulated timeout - 1134 read operation complete */
static t_stat ptr_svc (UNIT *uptr)
{
@@ -141,7 +141,7 @@ static t_stat ptr_svc (UNIT *uptr)
return SCPE_OK;
}
// ptp_svc - emulated timeout -- 1055 punch operation complete
/* ptp_svc - emulated timeout -- 1055 punch operation complete */
static t_stat ptp_svc (UNIT *uptr)
{
@@ -245,37 +245,37 @@ static t_stat ptr_boot (int unitno, DEVICE *dptr)
}
if (leader) {
if ((ch & 0x7F) == 0x7F) // ignore leading rubouts or "delete" characters
if ((ch & 0x7F) == 0x7F) /* ignore leading rubouts or "delete" characters */
continue;
leader = FALSE; // after first nonrubout, any punch in channel 5 terminates load
leader = FALSE; /* after first nonrubout, any punch in channel 5 terminates load */
}
// this is untested -- not sure of actual byte ordering
/* this is untested -- not sure of actual byte ordering */
val = (val << 4) | (ch & 0x0F); // get next nybble
val = (val << 4) | (ch & 0x0F); /* get next nybble */
if (++nch == 4) { // if we now have four nybbles, store the word
if (++nch == 4) { /* if we now have four nybbles, store the word */
M[addr & mem_mask] = (uint16) val;
addr++; // prepare for next word
addr++; /* prepare for next word */
nch = 0;
val = 0;
}
if (ch & 0x10) { // channel 5 punch terminates load
if (ch & 0x10) { /* channel 5 punch terminates load */
start = TRUE;
break;
}
}
if (! start) // if we didn't get a valid load, report EOF error
if (! start) /* if we didn't get a valid load, report EOF error */
return SCPE_EOF;
if ((rval = reset_all(0)) != SCPE_OK) // force a reset
if ((rval = reset_all(0)) != SCPE_OK) /* force a reset */
return rval;
IAR = 0; // start running at address 0
IAR = 0; /* start running at address 0 */
return SCPE_OK;
}

1164
Ibm1130/ibm1130_sca.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -91,16 +91,13 @@
static void badio (char *dev)
{
// the real 1130 just ignores attempts to use uninstalled devices. They get tested
// at times, so it's best to just be quiet about this
// printf("%s I/O is not yet supported", dev);
/* the real 1130 just ignores attempts to use uninstalled devices. They get tested
* at times, so it's best to just be quiet about this
* printf("%s I/O is not yet supported", dev);
*/
}
// void xio_1134_papertape (int32 addr, int32 func, int32 modify) {badio("papertape");}
void xio_1627_plotter (int32 addr, int32 func, int32 modify) {badio("plotter");}
void xio_1231_optical (int32 addr, int32 func, int32 modify) {badio("optical mark");}
void xio_2501_card (int32 addr, int32 func, int32 modify) {badio("2501 card");}
void xio_1131_synch (int32 addr, int32 func, int32 modify) {badio("SCA");}
void xio_system7 (int32 addr, int32 func, int32 modify) {badio("System 7");}
/* ---------------------------------------------------------------------------- */
@@ -120,7 +117,7 @@ extern int cgi;
static int32 tti_dsw = 0; /* device status words */
static int32 tto_dsw = 0;
static int32 con_dsw = 0;
int32 con_dsw = 0;
static unsigned char conout_map[256]; /* 1130 console code to ASCII translation. 0 = undefined, 0xFF = IGNR_ = no output */
static unsigned char conin_map[256]; /* input mapping */
@@ -211,9 +208,10 @@ DEVICE tti_dev = {
tto_reg TTO register list
*/
// 14-Nov-03 -- the wait time was SERIAL_OUT_WAIT, but recent versions of SIMH reduced
// this to 100, and wouldn't you know it, APL\1130 has about 120 instructions between the XIO WRITE
// to the console and the associated WAIT.
/* 14-Nov-03 -- the wait time was SERIAL_OUT_WAIT, but recent versions of SIMH reduced
* this to 100, and wouldn't you know it, APL\1130 has about 120 instructions between the XIO WRITE
* to the console and the associated WAIT.
*/
UNIT tto_unit = { UDATA (&tto_svc, 0, 0), 200 };
@@ -279,7 +277,7 @@ void xio_1131_console (int32 iocc_addr, int32 func, int32 modify)
ch = (ReadW(iocc_addr) >> 8) & 0xFF; /* get character to write */
tto_unit.buf = emit_conout_character(ch); /* output character and save write status */
// fprintf(stderr, "[CONOUT] %02x\n", ch);
/* fprintf(stderr, "[CONOUT] %02x\n", ch); */
SETBIT(tto_dsw, TT_DSW_PRINTER_BUSY);
sim_activate(&tto_unit, tto_unit.wait); /* schedule interrupt */
@@ -300,10 +298,10 @@ void xio_1131_console (int32 iocc_addr, int32 func, int32 modify)
xio_error(msg);
}
// fprintf(stderr, "After XIO %04x %04x\n", tti_dsw, tto_dsw);
/* fprintf(stderr, "After XIO %04x %04x\n", tti_dsw, tto_dsw); */
}
// emit_conout_character - write character with 1130 console code 'ch'
/* emit_conout_character - write character with 1130 console code 'ch' */
t_stat emit_conout_character (int ch)
{
@@ -342,12 +340,12 @@ t_stat emit_conout_character (int ch)
return map_conout_character(ch);
}
static void Beep (void) // notify user keyboard was locked or key was bad
static void Beep (void) /* notify user keyboard was locked or key was bad */
{
sim_putchar(7);
}
// tti_svc - keyboard polling (never stops)
/* tti_svc - keyboard polling (never stops) */
static t_stat tti_svc (UNIT *uptr)
{
@@ -386,7 +384,7 @@ static t_stat tti_svc (UNIT *uptr)
if (temp == PROGRAM_STOP_KEY) { /* simulate the program stop button */
SETBIT(con_dsw, CPU_DSW_PROGRAM_STOP);
SETBIT(ILSW[5], ILSW_5_PROGRAM_STOP);
SETBIT(ILSW[5], ILSW_5_INT_RUN_PROGRAM_STOP);
calc_ints();
#ifdef DEBUG_CONSOLE
@@ -417,16 +415,13 @@ static t_stat tti_svc (UNIT *uptr)
printf("[%04x]", tti_unit.buf & 0xFFFF);
#endif
// CLRBIT(tti_dsw, TT_DSW_KEYBOARD_BUSY); /* clear busy flag (unselect keyboard) */
// keyboard_selected(FALSE);
SETBIT(tti_unit.flags, KEYBOARD_LOCKED); /* prevent further keystrokes */
SETBIT(tti_dsw, TT_DSW_KEYBOARD_RESPONSE); /* queue interrupt */
SETBIT(ILSW[4], ILSW_4_CONSOLE);
calc_ints();
// fprintf(stderr, "TTI interrupt svc SET %04x %04x\n", tti_dsw, tto_dsw);
/* fprintf(stderr, "TTI interrupt svc SET %04x %04x\n", tti_dsw, tto_dsw); */
return SCPE_OK;
}
@@ -450,14 +445,14 @@ static t_stat tti_reset (DEVICE *dptr)
return SCPE_OK;
}
// basic_attach - fix quotes in filename, then call standard unit attach routine
/* basic_attach - fix quotes in filename, then call standard unit attach routine */
t_stat basic_attach (UNIT *uptr, char *cptr)
{
return attach_unit(uptr, quotefix(cptr)); /* fix quotes in filenames & attach */
}
// quotefix - strip off quotes around filename, if present
/* quotefix - strip off quotes around filename, if present */
char * quotefix (char * cptr)
{
@@ -492,7 +487,7 @@ static t_stat tto_svc (UNIT *uptr)
SETBIT(ILSW[4], ILSW_4_CONSOLE);
calc_ints();
// fprintf(stderr, "TTO interrupt svc SET %04x %04x\n", tti_dsw, tto_dsw);
/* fprintf(stderr, "TTO interrupt svc SET %04x %04x\n", tti_dsw, tto_dsw); */
return (t_stat) tto_unit.buf; /* return status saved during output conversion */
}
@@ -648,7 +643,7 @@ static struct { /* default output mapping for APLPLUS font */
#define NCONOUT_TO_APL (sizeof(conout_to_APL)/sizeof(conout_to_APL[0]))
static OS_MAP default_os_map[] = // overstrike mapping for APLPLUS font
static OS_MAP default_os_map[] = /* overstrike mapping for APLPLUS font */
{
'\x8a', 2, "\x5e\x7e",
'\x8b', 2, "\x9f\x7e",
@@ -717,12 +712,12 @@ static void strsort (int n, unsigned char *s)
unsigned char temp;
int i, big;
while (--n > 0) { // repeatedly
big = 0; // find largest value of s[0]...s[n]
while (--n > 0) { /* repeatedly */
big = 0; /* find largest value of s[0]...s[n] */
for (i = 1; i <= n; i++)
if (s[i] > s[big]) big = i;
temp = s[n]; // put largest value at end of array
temp = s[n]; /* put largest value at end of array */
s[n] = s[big];
s[big] = temp;
}
@@ -730,10 +725,10 @@ static void strsort (int n, unsigned char *s)
/* file format:
[font XXX] // font named XXX
OUT // failure character
OUT IN // single character mapping
OUT IN IN ... // overstrike mapping
[font XXX] font named XXX
OUT failure character
OUT IN single character mapping
OUT IN IN ... overstrike mapping
*/
@@ -742,35 +737,35 @@ static void set_conout_mapping (int32 flags)
curcol = 0;
maxcol = 0;
// set the default mappings. We may later override them with settings from an ini file
/* set the default mappings. We may later override them with settings from an ini file */
set_default_mapping(flags);
}
// finish_conout_mapping - sort the finalized overstrike mapping
/* finish_conout_mapping - sort the finalized overstrike mapping */
static void finish_conout_mapping (int32 flags)
{
int i, n, big;
OS_MAP temp;
for (i = 0; i < n_os_mappings; i++) // sort the inlist strings individually
for (i = 0; i < n_os_mappings; i++) /* sort the inlist strings individually */
strsort(os_map[i].nin, os_map[i].inlist);
for (n = n_os_mappings; --n > 0; ) { // then sort the os_map array itself with insertion sort
big = 0; // find largest value of s[0]...s[n]
for (n = n_os_mappings; --n > 0; ) { /* then sort the os_map array itself with insertion sort */
big = 0; /* find largest value of s[0]...s[n] */
for (i = 1; i <= n; i++)
if (os_map_comp(os_map+i, os_map+big) > 0) big = i;
if (big != n) {
temp = os_map[n]; // put largest value at end of array
temp = os_map[n]; /* put largest value at end of array */
os_map[n] = os_map[big];
os_map[big] = temp;
}
}
}
// validate_conout_mapping - called when set command gets a new value
/* validate_conout_mapping - called when set command gets a new value */
static t_stat validate_conout_mapping (UNIT *uptr, int32 match, char *cvptr, void *desc)
{
@@ -793,7 +788,7 @@ static void reset_mapping (void)
conin_map[i] = (unsigned char) i; /* default conin_map is identity map */
}
// set_default_mapping - create standard font and overstrike map
/* set_default_mapping - create standard font and overstrike map */
static void set_default_mapping (int32 flags)
{
@@ -824,10 +819,10 @@ static void set_default_mapping (int32 flags)
break;
}
finish_conout_mapping(flags); // sort conout mapping if necessary
finish_conout_mapping(flags); /* sort conout mapping if necessary */
}
// sim_putstr - write a string to the console
/* sim_putstr - write a string to the console */
t_stat sim_putstr (char *s)
{
@@ -843,7 +838,7 @@ t_stat sim_putstr (char *s)
return SCPE_OK;
}
// map_conout_character - translate and write a single character
/* map_conout_character - translate and write a single character */
static t_stat map_conout_character (int ch)
{
@@ -857,54 +852,54 @@ static t_stat map_conout_character (int ch)
return (tto_unit.flags & ENABLE_ANSI) ? sim_putstr((char *) red_ribbon) : SCPE_OK;
if ((ch = conout_map[ch & 0xFF]) == 0)
ch = '?'; // unknown character? print ?
ch = '?'; /* unknown character? print ? */
if (ch == '\n') { // newline: reset overstrike buffer
if (ch == '\n') { /* newline: reset overstrike buffer */
curcol = 0;
maxcol = -1;
}
else if (ch == '\r') { // carriage return: rewind to column 0
else if (ch == '\r') { /* carriage return: rewind to column 0 */
curcol = 0;
maxcol = -1; // assume it advances paper too
maxcol = -1; /* assume it advances paper too */
}
else if (ch == '\b') { // backspace: back up one character
else if (ch == '\b') { /* backspace: back up one character */
if (curcol > 0)
curcol--;
}
else if (n_os_mappings && ch != (unsigned char) IGNR_) {
if (curcol >= MAX_OUTPUT_COLUMNS)
map_conout_character('\x81'); // precede with automatic carriage return/line feed, I guess
map_conout_character('\x81'); /* precede with automatic carriage return/line feed, I guess */
if (curcol > maxcol) { // first time in this column, no overstrike possible yet
if (curcol > maxcol) { /* first time in this column, no overstrike possible yet */
os_buf[curcol].nin = 0;
maxcol = curcol;
}
if (ch != ' ' && ch != 0) { // (if it's not a blank or unknown)
if (ch != ' ' && ch != 0) { /* (if it's not a blank or unknown) */
os_buf[curcol].inlist[os_buf[curcol].nin] = (unsigned char) ch;
strsort(++os_buf[curcol].nin, os_buf[curcol].inlist);
}
if (os_buf[curcol].nin == 0) // if nothing but blanks seen,
ch = ' '; // output is a blank
else if (os_buf[curcol].nin == 1) { // if only one printing character seen, display it
if (os_buf[curcol].nin == 0) /* if nothing but blanks seen, */
ch = ' '; /* output is a blank */
else if (os_buf[curcol].nin == 1) { /* if only one printing character seen, display it */
ch = os_buf[curcol].inlist[0];
}
else { // otherwise look up mapping
else { /* otherwise look up mapping */
ch = '?';
for (i = 0; i < n_os_mappings; i++) {
cmp = os_map_comp(&os_buf[curcol], &os_map[i]);
if (cmp == 0) { // a hit
if (cmp == 0) { /* a hit */
ch = os_map[i].ch;
break;
}
else if (cmp < 0) // not found
else if (cmp < 0) /* not found */
break;
}
}
if (curcol < MAX_OUTPUT_COLUMNS) // this should now never happen, as we automatically return
if (curcol < MAX_OUTPUT_COLUMNS) /* this should now never happen, as we automatically return */
curcol++;
}

View File

@@ -3,6 +3,7 @@
Based on PDP-11 simulator written by Robert M Supnik
Revision History
0.27 2005Mar08 - Added sca device
0.26 2002Apr24 - Added !BREAK in card deck file to stop simulator
0.25 2002Apr18 - Fixed some card reader problems. It starts the reader
properly if you attach a deck while it's waiting to a read.
@@ -27,9 +28,9 @@
#include <ctype.h>
#include <stdarg.h>
extern DEVICE cpu_dev, console_dev, dsk_dev, cr_dev, cp_dev, ptr_dev, ptp_dev;
extern DEVICE tti_dev, tto_dev, prt_dev, log_dev;
extern DEVICE gdu_dev, console_dev;
extern DEVICE cpu_dev, console_dev, dsk_dev, cr_dev, cp_dev, ptr_dev, ptp_dev, t2741_dev;
extern DEVICE tti_dev, tto_dev, prt_dev, log_dev, sca_dev;
extern DEVICE gdu_dev, console_dev, plot_dev;
extern UNIT cpu_unit;
extern REG cpu_reg[];
@@ -61,8 +62,11 @@ DEVICE *sim_devices[] = {
&prt_dev, /* 1132 printer */
&ptr_dev, /* 1134 paper tape reader */
&ptp_dev, /* 1055 paper tape punch */
&sca_dev, /* Synchronous communications adapter option */
&console_dev, /* console display (windows GUI) */
&gdu_dev, /* 2250 display */
&t2741_dev, /* nonstandard serial interface used by APL\1130 */
&plot_dev, /* plotter device, in ibm1130_plot.c */
NULL
};
@@ -76,7 +80,11 @@ const char *sim_stop_messages[] = {
"!BREAK in card deck file",
"Phase load break",
"Program has run amok",
"Run time limit exceeded"
"Run time limit exceeded",
"Immediate Stop key requested",
"Simulator break key pressed",
"Simulator step count expired",
"Simulator IO error",
};
/* Loader. IPL is normally performed by card reader (boot command). This function
@@ -106,13 +114,13 @@ t_stat my_load (FILE *fileref, char *cptr, char *fnam)
int iaddr = -1, runaddr = -1, val, nwords;
while (fgets(line, sizeof(line), fileref) != NULL) {
for (c = line; *c && *c <= ' '; c++) // find first nonblank
for (c = line; *c && *c <= ' '; c++) /* find first nonblank */
;
if (*c == '\0' || *c == '#' || *c == '/' || *c == ';')
continue; // empty line or comment
continue; /* empty line or comment */
if (*c == '@') { // set load address
if (*c == '@') { /* set load address */
if (sscanf(c+1, "%x", &iaddr) != 1)
return SCPE_FMT;
}
@@ -124,7 +132,7 @@ t_stat my_load (FILE *fileref, char *cptr, char *fnam)
if (sscanf(c+1, "%x", &val) != 1)
return SCPE_FMT;
CES = val & 0xFFFF; // preload console entry switches
CES = val & 0xFFFF; /*preload console entry switches */
}
else if (*c == 'z' || *c == 'Z') {
if (sscanf(c+1, "%x", &nwords) != 1)
@@ -145,11 +153,11 @@ t_stat my_load (FILE *fileref, char *cptr, char *fnam)
if (iaddr == -1)
return SCPE_FMT;
WriteW(iaddr, val); // store data
WriteW(iaddr, val); /*store data */
iaddr++;
}
else
return SCPE_FMT; // unexpected data
return SCPE_FMT; /*unexpected data */
}
if (runaddr != -1)
@@ -166,14 +174,14 @@ t_stat my_save (FILE *fileref, char *cptr, char *fnam)
fprintf(fileref, "@0000\r\n");
for (iaddr = 0; iaddr < nwords; iaddr++) {
val = ReadW(iaddr);
if (val == 0) // queue up zeroes
if (val == 0) /*queue up zeroes */
nzeroes++;
else {
if (nzeroes >= 4) { // spit out a Z directive
if (nzeroes >= 4) { /*spit out a Z directive */
fprintf(fileref, "Z%04x\r\n", nzeroes);
nzeroes = 0;
}
else { // write queued zeroes literally
else { /*write queued zeroes literally */
while (nzeroes > 0) {
fprintf(fileref, " 0000\r\n");
nzeroes--;
@@ -182,7 +190,7 @@ t_stat my_save (FILE *fileref, char *cptr, char *fnam)
fprintf(fileref, " %04x\r\n", val);
}
}
if (nzeroes >= 4) { // emit any queued zeroes
if (nzeroes >= 4) { /*emit any queued zeroes */
fprintf(fileref, "Z%04x\r\n", nzeroes);
nzeroes = 0;
}
@@ -241,7 +249,7 @@ static char *opcode[] = {
"AND ", "OR ", "EOR ", "?1F ",
};
static char relative[] = { // true if short mode displacements are IAR relative
static char relative[] = { /*true if short mode displacements are IAR relative */
FALSE, TRUE, FALSE, FALSE,
FALSE, TRUE, FALSE, FALSE,
TRUE, FALSE, FALSE, FALSE,
@@ -287,10 +295,11 @@ t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, UNIT *uptr, int32 sw)
cflag = (uptr == NULL) || (uptr == &cpu_unit);
// if (sw & SWMASK ('A')) { /* ASCII? not useful */
// fprintf (of, (c1 < 040)? "<%03o>": "%c", c1);
// return SCPE_OK;
// }
/* if (sw & SWMASK ('A')) { // ASCII? not useful
fprintf (of, (c1 < 040)? "<%03o>": "%c", c1);
return SCPE_OK;
}
*/
if (sw & SWMASK ('C')) /* character? not useful -- make it EBCDIC */
sw |= SWMASK('E');
@@ -349,7 +358,7 @@ t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, UNIT *uptr, int32 sw)
DSPLC &= 0x003F;
eaddr = DSPLC;
}
else if ((OP == 0x08 && F)|| OP == 0x09) { // BSI L and BSC any
else if ((OP == 0x08 && F)|| OP == 0x09) { /* BSI L and BSC any */
if (OP == 0x09 && (IR & 0x40))
mnem = "BOSC";
@@ -368,7 +377,7 @@ t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, UNIT *uptr, int32 sw)
fprintf(of, "%04x %s %c%c %s ", IR & 0xFFFF, mnem, F ? (INDIR ? 'I' : 'L') : ' ', tagc[TAG], tst);
return SCPE_OK;
}
else if (OP == 0x0e && TAG == 0) { // MDX with no tag => MDM or jump
else if (OP == 0x0e && TAG == 0) { /* MDX with no tag => MDM or jump */
if (F) {
fprintf(of, "%04x %s %c%c %04x,%x (%d) ", IR & 0xFFFF, "MDM ", (INDIR ? 'I' : 'L'), tagc[TAG], eaddr & 0xFFFF, DSPLC & 0xFFFF, DSPLC);
return -1;
@@ -446,47 +455,47 @@ t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw)
#ifndef _WIN32
int strnicmp (char *a, char *b, int n)
int strnicmp (const char *a, const char *b, int n)
{
int ca, cb;
for (;;) {
if (--n < 0) // still equal after n characters? quit now
if (--n < 0) /* still equal after n characters? quit now */
return 0;
if ((ca = *a) == 0) // get character, stop on null terminator
if ((ca = *a) == 0) /* get character, stop on null terminator */
return *b ? -1 : 0;
if (ca >= 'a' && ca <= 'z') // fold lowercase to uppercase
if (ca >= 'a' && ca <= 'z') /* fold lowercase to uppercase */
ca -= 32;
cb = *b;
if (cb >= 'a' && cb <= 'z')
cb -= 32;
if ((ca -= cb) != 0) // if different, return comparison
if ((ca -= cb) != 0) /* if different, return comparison */
return ca;
a++, b++;
}
}
int strcmpi (char *a, char *b)
int strcmpi (const char *a, const char *b)
{
int ca, cb;
for (;;) {
if ((ca = *a) == 0) // get character, stop on null terminator
if ((ca = *a) == 0) /* get character, stop on null terminator */
return *b ? -1 : 0;
if (ca >= 'a' && ca <= 'z') // fold lowercase to uppercase
if (ca >= 'a' && ca <= 'z') /* fold lowercase to uppercase */
ca -= 32;
cb = *b;
if (cb >= 'a' && cb <= 'z')
cb -= 32;
if ((ca -= cb) != 0) // if different, return comparison
if ((ca -= cb) != 0) /* if different, return comparison */
return ca;
a++, b++;

388
Ibm1130/ibm1130_t2741.c Normal file
View File

@@ -0,0 +1,388 @@
/***************************************************************************************
* Nonstandard serial attachment for remote 2741 terminal (IO selectric) used by APL\1130
* This implementation may be incomplete and/or incorrect
***************************************************************************************/
#include "ibm1130_defs.h"
#include "sim_sock.h"
#include "sim_tmxr.h"
#define DEBUG_T2741
static TMLN t2741_ldsc = { 0 }; /* line descr for telnet attachment */
static TMXR t2741_tmxr = { 1, 0, 0, &t2741_ldsc }; /* line mux for telnet attachment */
#define T2741_DSW_TRANSMIT_NOT_READY 0x4000
#define T2741_DSW_READ_RESPONSE 0x1000
#define T2741_DSW_READ_OVERRUN 0x0800
#define T2741_DSW_ATTENTION 0x0010
#define IS_ONLINE(u) (((u)->flags & (UNIT_ATT|UNIT_DIS)) == UNIT_ATT)
#define UNIT_V_PHYSICAL_TERM (UNIT_V_UF + 0) /* indicates not telnet but attachment to real terminal */
#define UNIT_V_UPCASE (UNIT_V_UF + 1) /* indicates upshift performed */
#define UNIT_V_SENDING (UNIT_V_UF + 2) /* indicates not telnet but attachment to real terminal */
#define UNIT_V_RECEIVING (UNIT_V_UF + 3) /* indicates not telnet but attachment to real terminal */
#define UNIT_PHYSICAL_TERM (1u << UNIT_V_PHYSICAL_TERM)
#define UNIT_UPCASE (1u << UNIT_V_UPCASE)
#define UNIT_SENDING (1u << UNIT_V_SENDING)
#define UNIT_RECEIVING (1u << UNIT_V_RECEIVING)
#define CODE_SHIFTUP 0x1C00
#define CODE_SHIFTDOWN 0x7C00
#define CODE_CIRCLEC 0x1F00
#define CODE_CIRCLED 0x1600
#define CODE_RETURN 0x5B00
#define CODE_LINEFEED 0x3B00
#define CODE_ATTENTION 0x0001 /* pseudocode, never really returned as a received character */
#define CODE_UNKNOWN 0x0000
static t_stat t2741_svc (UNIT *uptr);
static t_stat t2741_reset (DEVICE *dptr);
static t_stat t2741_attach (UNIT *uptr, char *cptr);
static t_stat t2741_detach (UNIT *uptr);
static uint16 ascii_to_t2741 (int ascii);
static char * t2741_to_ascii (uint16 code);
static void set_transmit_notready (void);
static uint16 t2741_dsw = T2741_DSW_TRANSMIT_NOT_READY; /* device status word */
static uint32 t2741_swait = 200; /* character send wait */
static uint32 t2741_rwait = 2000; /* character receive wait */
static uint16 t2741_char = 0; /* last character received */
static int overrun = FALSE;
static uint32 t2741_socket = 1130;
UNIT t2741_unit[1] = {
{ UDATA (&t2741_svc, UNIT_ATTABLE, 0) },
};
REG t2741_reg[] = {
{ HRDATA (DSW, t2741_dsw, 16) }, /* device status word */
{ DRDATA (RTIME, t2741_rwait, 24), PV_LEFT }, /* character receive wait */
{ DRDATA (STIME, t2741_swait, 24), PV_LEFT }, /* character send wait */
{ DRDATA (SOCKET, t2741_socket,16), PV_LEFT }, /* socket number */
{ HRDATA (LASTCHAR, t2741_char, 16), PV_LEFT }, /* last character read */
{ NULL } };
DEVICE t2741_dev = {
"T2741", t2741_unit, t2741_reg, NULL,
1, 16, 16, 1, 16, 16,
NULL, NULL, t2741_reset,
NULL, t2741_attach, t2741_detach};
/* xio_t2741_terminal - XIO command interpreter for the terminal adapter */
void xio_t2741_terminal (int32 iocc_addr, int32 iocc_func, int32 iocc_mod)
{
char msg[80];
uint16 code;
switch (iocc_func) {
case XIO_READ: /* read: return last character read */
code = t2741_char & 0xFF00;
M[iocc_addr & mem_mask] = code;
overrun = FALSE;
#ifdef DEBUG_T2741
/* trace_both("T2741 %04x READ %02x %s", prev_IAR, code >> 8, t2741_to_ascii(code)); */
#endif
break;
case XIO_WRITE: /* write: initiate character send */
code = M[iocc_addr & mem_mask] & 0xFF00;
#ifdef DEBUG_T2741
trace_both("T2741 %04x SEND %02x %s", prev_IAR, code >> 8, t2741_to_ascii(code));
#endif
SETBIT(t2741_dsw, T2741_DSW_TRANSMIT_NOT_READY);
SETBIT(t2741_unit->flags, UNIT_SENDING);
if (code == CODE_SHIFTUP)
SETBIT(t2741_unit->flags, UNIT_UPCASE);
else if (code == CODE_SHIFTDOWN)
CLRBIT(t2741_unit->flags, UNIT_UPCASE);
sim_activate(t2741_unit, t2741_swait); /* schedule interrupt */
break;
case XIO_SENSE_DEV: /* sense device status */
ACC = t2741_dsw;
#ifdef DEBUG_T2741
/* trace_both("T2741 %04x SENS %04x%s", prev_IAR, t2741_dsw, (iocc_mod & 0x01) ? " reset" : ""); */
#endif
if (iocc_mod & 0x01) { /* reset interrupts */
CLRBIT(t2741_dsw, T2741_DSW_READ_RESPONSE);
CLRBIT(ILSW[4], ILSW_4_T2741_TERMINAL);
}
break;
case XIO_CONTROL: /* control: do something to interface */
#ifdef DEBUG_T2741
trace_both("T2741 %04x CTRL %04x", prev_IAR, iocc_mod &0xFF);
#endif
SETBIT(t2741_unit->flags, UNIT_RECEIVING); /* set mode to receive mode */
if (IS_ONLINE(t2741_unit) && (t2741_char != 0 || ! feof(t2741_unit->fileref))) {
sim_activate(t2741_unit, t2741_rwait);
t2741_char = (CODE_CIRCLED >> 8); /* first character received after turnaround is circled */
}
break;
default:
sprintf(msg, "Invalid T2741 XIO function %x", iocc_func);
xio_error(msg);
}
}
static void set_transmit_notready (void)
{
if (IS_ONLINE(t2741_unit) && ! (t2741_unit->flags & UNIT_SENDING))
CLRBIT(t2741_dsw, T2741_DSW_TRANSMIT_NOT_READY);
else
SETBIT(t2741_dsw, T2741_DSW_TRANSMIT_NOT_READY);
}
static t_stat t2741_svc (UNIT *uptr)
{
int ch = EOF;
uint16 code;
if (uptr->flags & UNIT_SENDING) { /* xmit: no interrupt, as far as I know. just clr busy bit */
CLRBIT(uptr->flags, UNIT_SENDING);
set_transmit_notready();
}
if (uptr->flags & UNIT_RECEIVING) { /* rcv: fire interrupt */
t2741_char <<= 8;
if (t2741_char == 0) { /* there is no 2nd character from previous ascii input */
if ((ch = getc(t2741_unit->fileref)) == EOF)
t2741_char = 0;
else {
if (ch == '\r') { /* if we get CR, jump to LF */
if ((ch = getc(t2741_unit->fileref)) != '\n') {
ungetc(ch, t2741_unit->fileref);
ch = '\r';
}
}
if (ch == '\027') {
t2741_char = CODE_LINEFEED; /* attention key sends line feed character */
#ifdef DEBUG_T2741
trace_both("T2741 ---- ATTENTION");
#endif
SETBIT(t2741_dsw, T2741_DSW_ATTENTION); /* no character returned ? */
}
else {
t2741_char = ascii_to_t2741(ch); /* translate to 2741 code(s) */
}
}
}
code = t2741_char & 0xFF00;
if (t2741_char != 0) {
if (overrun) /* previous character was not picked up! */
SETBIT(t2741_dsw, T2741_DSW_READ_OVERRUN);
SETBIT(t2741_dsw, T2741_DSW_READ_RESPONSE);
SETBIT(ILSW[4], ILSW_4_T2741_TERMINAL); /* issue interrupt */
calc_ints();
#ifdef DEBUG_T2741
trace_both("T2741 ---- RCVD %02x '%s' RDRESP%s%s", code >> 8, t2741_to_ascii(code),
(t2741_dsw & T2741_DSW_READ_OVERRUN) ? "|OVERRUN" : "",
(t2741_dsw & T2741_DSW_ATTENTION) ? "|ATTENTION" : "");
#endif
overrun = TRUE; /* arm overrun flag */
}
if (t2741_char == CODE_CIRCLEC) /* end of line (CIRCLEC after RETURN) auto downshifts */
CLRBIT(t2741_unit->flags, UNIT_UPCASE);
if (t2741_char == 0 || code == CODE_CIRCLEC)
CLRBIT(uptr->flags, UNIT_RECEIVING); /* on enter or EOF, stop typing */
else
sim_activate(t2741_unit, t2741_rwait); /* schedule next character to arrive */
}
return SCPE_OK;
}
static t_stat t2741_attach (UNIT *uptr, char *cptr)
{
int rval;
if ((rval = attach_unit(uptr, cptr)) == SCPE_OK) { /* use standard attach */
t2741_char = 0;
overrun = FALSE;
CLRBIT(t2741_unit->flags, UNIT_UPCASE);
if ((t2741_unit->flags & UNIT_RECEIVING) && ! feof(t2741_unit->fileref))
sim_activate(t2741_unit, t2741_rwait); /* schedule interrupt */
}
set_transmit_notready();
return rval;
}
static t_stat t2741_detach (UNIT *uptr)
{
t_stat rval;
if (t2741_unit->flags & UNIT_RECEIVING) /* if receive was pending, cancel interrupt */
sim_cancel(t2741_unit);
t2741_char = 0;
overrun = FALSE;
rval = detach_unit(uptr); /* use standard detach */
set_transmit_notready();
return rval;
}
static t_stat t2741_reset (DEVICE *dptr)
{
sim_cancel(t2741_unit);
CLRBIT(t2741_unit->flags, UNIT_SENDING|UNIT_RECEIVING|UNIT_UPCASE);
t2741_char = 0;
t2741_dsw = 0;
overrun = FALSE;
set_transmit_notready();
CLRBIT(ILSW[4], ILSW_4_T2741_TERMINAL);
calc_ints();
return SCPE_OK;
}
static struct tag_t2741_map {
int code;
int lcase, ucase;
t_bool shifts;
} t2741_map[] = {
{0x4F00, 'A', 'a', TRUE},
{0x3700, 'B', 'b', TRUE},
{0x2F00, 'C', 'c', TRUE},
{0x2A00, 'D', 'd', TRUE},
{0x2900, 'E', 'e', TRUE},
{0x6700, 'F', '_', TRUE},
{0x6200, 'G', 'g', TRUE},
{0x3200, 'H', 'h', TRUE},
{0x4C00, 'I', 'i', TRUE},
{0x6100, 'J', 'j', TRUE},
{0x2C00, 'K', '\'', TRUE},
{0x3100, 'L', 'l', TRUE},
{0x4300, 'M', '|', TRUE},
{0x2500, 'N', 'n', TRUE},
{0x5100, 'O', 'o', TRUE},
{0x6800, 'P', '*', TRUE},
{0x6D00, 'Q', '?', TRUE},
{0x4A00, 'R', 'r', TRUE},
{0x5200, 'S', 's', TRUE},
{0x2000, 'T', '~', TRUE},
{0x2600, 'U', 'u', TRUE},
{0x4600, 'V', 'v', TRUE},
{0x5700, 'W', 'w', TRUE},
{0x2300, 'X', 'x', TRUE},
{0x7300, 'Y', 'y', TRUE},
{0x1500, 'Z', 'z', TRUE},
{0x1300, '0', '&', TRUE},
{0x0200, '1', '?', TRUE},
{0x0400, '2', '?', TRUE},
{0x0700, '3', '<', TRUE},
{0x1000, '4', '?', TRUE},
{0x0800, '5', '=', TRUE},
{0x0D00, '6', '?', TRUE},
{0x0B00, '7', '>', TRUE},
{0x0E00, '8', '?', TRUE},
{0x1600, '9', '|', TRUE},
{0x7000, '/', '\\', TRUE},
{0x7600, '+', '-', TRUE},
{0x6400, '?', '?', TRUE},
{0x4000, '<', '>', TRUE},
{0x6B00, '[', '(', TRUE},
{0x4900, ']', ')', TRUE},
{0x6E00, ',', ';', TRUE},
{0x4500, '.', ':', TRUE},
{0x0100, ' ', 0, FALSE},
{0x5B00, '\r', 0, FALSE},
{0x3B00, '\n', 0, FALSE},
{0x5D00, '\b', 0, FALSE},
{0x5E00, '\t', 0, FALSE},
{0x0001, '\027', 0, FALSE},
};
static uint16 ascii_to_t2741 (int ascii)
{
int i;
uint16 rval = 0;
ascii &= 0xFF;
if (ascii == '\n') /* turn newlines into returns + CIRCLED? */
return CODE_RETURN | (CODE_CIRCLEC >> 8);
for (i = sizeof(t2741_map)/sizeof(t2741_map[0]); --i >= 0; ) {
if (t2741_map[i].shifts) {
if (t2741_map[i].lcase == ascii) {
rval = t2741_map[i].code;
if (t2741_unit->flags & UNIT_UPCASE) {
CLRBIT(t2741_unit->flags, UNIT_UPCASE);
rval = CODE_SHIFTDOWN | (rval >> 8);
}
return rval;
}
if (t2741_map[i].ucase == ascii) {
rval = t2741_map[i].code;
if (! (t2741_unit->flags & UNIT_UPCASE)) {
SETBIT(t2741_unit->flags, UNIT_UPCASE);
rval = CODE_SHIFTUP | (rval >> 8);
}
return rval;
}
}
else if (t2741_map[i].lcase == ascii)
return t2741_map[i].code;
}
return CODE_UNKNOWN;
}
static char * t2741_to_ascii (uint16 code)
{
int i;
static char string[2] = {'?', '\0'};
switch (code) {
case CODE_SHIFTUP: return "SHIFTUP";
case CODE_SHIFTDOWN: return "SHIFTDN";
case CODE_CIRCLEC: return "CIRCLEC";
case CODE_CIRCLED: return "CIRCLED";
}
for (i = sizeof(t2741_map)/sizeof(t2741_map[0]); --i >= 0; ) {
if (t2741_map[i].code == code) {
if (t2741_map[i].shifts) {
string[0] = (t2741_unit->flags & UNIT_UPCASE) ? t2741_map[i].ucase : t2741_map[i].lcase;
return string;
}
switch (t2741_map[i].lcase) {
case ' ': return " ";
case '\r': return "RETURN";
case '\n': return "LINEFEED";
case '\b': return "BS";
case '\t': return "IDLE";
}
break;
}
}
return "?";
}