1
0
mirror of https://github.com/simh/simh.git synced 2026-02-11 10:36:08 +00:00

IMLAC: Simulator for Imlac PDS-1.

This commit is contained in:
Lars Brinkhoff
2020-06-12 16:05:50 +02:00
parent d1f41d9c1f
commit f95ac7ddbd
16 changed files with 3429 additions and 3 deletions

576
imlac/imlac_cpu.c Normal file
View File

@@ -0,0 +1,576 @@
/* imlac_cpu.c: Imlac CPU simulator
Copyright (c) 2020, Lars Brinkhoff
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
LARS BRINKHOFF BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Lars Brinkhoff shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Lars Brinkhoff.
*/
#include "imlac_defs.h"
/* Debug */
#define DBG_CPU 0001
#define DBG_IRQ 0002
#define DBG_ROM 0004
/* Bootstrap ROM type. */
#define ROM_NONE 0
#define ROM_TTY 1
#define ROM_STTY 2
#define ROM_PTR 3
/* CPU state. */
static uint16 PC;
static uint16 AC;
static uint16 L;
static uint16 DS;
static uint16 IR;
static uint16 MA;
static uint16 MB;
static uint16 SWITCHES;
static int ion_delay = 0;
/* IRQ state. */
static uint16 ARM = 0177777;
static uint16 FLAGS = FLAG_SYNC | FLAG_TTY_T;
static uint16 ION;
/* ROM state. */
static int rom_type = ROM_NONE;
static int halt;
uint16 memmask = 017777;
/* Function declaration. */
static t_stat cpu_ex (t_value *vptr, t_addr ea, UNIT *uptr, int32 sw);
static t_stat cpu_dep (t_value val, t_addr ea, UNIT *uptr, int32 sw);
static t_stat cpu_reset (DEVICE *dptr);
static uint16 irq_iot (uint16, uint16);
static t_stat rom_set_type (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
static t_stat rom_show_type (FILE *st, UNIT *up, int32 v, CONST void *dp);
static UNIT cpu_unit = { UDATA (NULL, UNIT_FIX + UNIT_BINK, 020000) };
REG cpu_reg[] = {
{ ORDATAD (PC, PC, 13, "Program Counter") },
{ ORDATAD (AC, AC, 16, "Accumulator") },
{ ORDATAD (L, L, 1, "Link") },
{ ORDATAD (DS, DS, 16, "Data Switches") },
{ ORDATAD (IR, IR, 16, "Instruction") },
{ ORDATAD (MA, MA, 13, "Memory Address") },
{ ORDATAD (MB, MB, 16, "Memory Buffer") },
{ ORDATAD (SWITCHES, SWITCHES, 16, "Toggle switches") },
{ NULL }
};
static MTAB cpu_mod[] = {
{ MTAB_XTD|MTAB_VDV, 0, "IDLE", "IDLE", &sim_set_idle, &sim_show_idle },
{ MTAB_XTD|MTAB_VDV, 0, NULL, "NOIDLE", &sim_clr_idle, NULL },
{ 0 }
};
static DEBTAB cpu_deb[] = {
{ "CPU", DBG_CPU },
{ NULL, 0 }
};
DEVICE cpu_dev = {
"CPU", &cpu_unit, cpu_reg, cpu_mod,
0, 8, 16, 1, 8, 16,
&cpu_ex, &cpu_dep, &cpu_reset,
NULL, NULL, NULL, NULL, DEV_DEBUG, 0, cpu_deb,
NULL, NULL, NULL, NULL, NULL, NULL
};
static REG irq_reg[] = {
{ ORDATAD (ION, ION, 1, "Interrupts on") },
{ ORDATAD (FLAGS, FLAGS, 16, "Flagged interrupts") },
{ ORDATAD (ARM, ARM, 16, "Armed interrupts") },
{ NULL }
};
static IMDEV irq_imdev = {
3,
{ { 0010, irq_iot, { NULL, "RDI", NULL, NULL } },
{ 0014, irq_iot, { NULL, "ARM", NULL, NULL } },
{ 0016, irq_iot, { NULL, "IOF", "ION", NULL } } }
};
static DEBTAB irq_deb[] = {
{ "IRQ", DBG_IRQ },
{ NULL, 0 }
};
DEVICE irq_dev = {
"IRQ", NULL, irq_reg, NULL,
0, 8, 16, 1, 8, 16,
NULL, NULL, NULL,
NULL, NULL, NULL,
&irq_imdev, DEV_DEBUG, 0, irq_deb,
NULL, NULL, NULL, NULL, NULL, NULL
};
static MTAB rom_mod[] = {
{ MTAB_VDV|MTAB_VALR, 0, "TYPE", "TYPE", &rom_set_type, &rom_show_type },
{ 0 }
};
static DEBTAB rom_deb[] = {
{ "DBG", DBG_ROM },
{ NULL, 0 }
};
DEVICE rom_dev = {
"ROM", NULL, NULL, rom_mod,
0, 8, 16, 1, 8, 16,
NULL, NULL, NULL,
NULL, NULL, NULL, NULL, DEV_DEBUG, 0, rom_deb,
NULL, NULL, NULL, NULL, NULL, NULL
};
static void pcinc (int flag)
{
if (flag)
PC = (PC + 1) & memmask;
}
static void memaddr (uint16 addr)
{
MA = addr & memmask;
}
static void memrd (void)
{
MB = M[MA];
}
static void memwr (void)
{
if (rom_type == ROM_NONE || (MA & 0177740) != 040)
M[MA] = MB;
}
static void cpu_class1 (uint16 insn)
{
if (insn & 0000001) /* T1: CLA */
AC = 0;
if (insn & 0000010) /* T1: CLL */
L = 0;
if (insn & 0000002) /* T2: CMA */
AC = ~AC;
if (insn & 0000020) /* T2: CML */
L = !L;
if (insn & 0000004) /* T3: IAC */
AC++;
if (insn & 0000040) /* T3: ODA */
AC |= DS;
halt = !(insn & 0100000);
}
static void cpu_ral (int n)
{
int i, x;
for (i = 0; i < n; i++) {
x = L;
L = AC >> 15;
AC = (AC << 1) | x;
}
}
static void cpu_rar (int n)
{
int i, x;
for (i = 0; i < n; i++) {
x = L;
L = AC & 1;
AC = (x << 15) | (AC >> 1);
}
}
static void cpu_class2 (uint16 insn)
{
int n = insn & 3;
uint32 x;
if (insn & 0000100) /* DON */
dp_on (1);
switch (insn & 0000600) {
case 0000000: /* RAL */
cpu_ral (n);
break;
case 0000200: /* RAR */
cpu_rar (n);
break;
case 0000400: /* SAL */
AC = (AC & 0100000) | ((AC & 037777) << n);
break;
case 0000600: /* SAR */
if (AC & 0100000)
x = 01600000 >> n;
else
x = 0;
AC = x | ((AC & 077777) >> n);
break;
}
}
static void cpu_class3 (uint16 insn)
{
int skip = 0;
if (insn & 0001) /* ASZ */
skip |= (AC == 0);
if (insn & 0002) /* ASP */
skip |= !(AC & 0100000);
if (insn & 0004) /* LSZ */
skip |= (L == 0);
if (insn & 0010) /* DSF */
skip |= dp_is_on ();
if (insn & 0020) /* KSF */
skip |= FLAGS & FLAG_KBD;
if (insn & 0040) /* RSF */
skip |= FLAGS & FLAG_TTY_R;
if (insn & 0100) /* TSF */
skip |= FLAGS & FLAG_TTY_T;
if (insn & 0200) /* SSF */
skip |= FLAGS & FLAG_SYNC;
if (insn & 0400) /* HSF */
skip |= FLAGS & FLAG_PTR;
if (insn & 0100000)
skip = !skip;
pcinc (skip);
}
static void cpu_iot (uint16 insn)
{
SUBDEV *dev = dev_tab[(insn >> 3) & 077];
if (dev == NULL) {
sim_debug (DBG_CPU, &cpu_dev, "Unknown device IOT: %06o\n", IR);
return;
}
AC = dev->iot (insn, AC);
}
static void cpu_opr (uint16 insn)
{
switch (insn & 0177000) {
case 0000000:
case 0100000:
cpu_class1 (insn);
break;
case 0003000:
cpu_class2 (insn);
break;
case 0002000:
case 0102000:
cpu_class3 (insn);
break;
case 0001000:
cpu_iot (insn);
break;
default:
sim_debug (DBG_CPU, &cpu_dev, "Unknown instruction: %06o\n", IR);
break;
}
}
static void
cpu_insn (void)
{
uint32 t32;
uint16 tmp;
/* Fetch cycle. */
memaddr (PC);
memrd ();
IR = MB;
sim_interval--;
if (((IR >> 12) & 7) != 0) {
/* Memory referecing. */
memaddr ((IR & 03777) | (PC & 014000));
if (IR & 0100000) {
/* Defer cycle. */
if ((MA & 03770) == 010) {
/* Auto incrementing. */
memrd ();
MB++;
memwr ();
}
memaddr (M[MA]);
}
}
pcinc (1);
/* Execute cycle. */
switch ((IR >> 9) & 074) {
case 000: /* OPR */
cpu_opr (IR);
break;
case 004: /* LAW, LCW */
if (IR & 0100000)
AC = -(IR & 03777);
else
AC = IR & 03777;
break;
case 010: /* JMP */
PC = MA;
break;
case 020: /* DAC */
MB = AC;
memwr ();
break;
case 024: /* XAM */
memrd ();
tmp = MB;
MB = AC;
memwr ();
AC = tmp;
break;
case 030: /* ISZ */
memrd ();
MB++;
memwr ();
pcinc (MB == 0);
break;
case 034: /* JMS */
MB = PC;
memwr ();
PC = MA;
pcinc (1);
break;
case 044: /* AND */
memrd ();
AC &= MB;
break;
case 050: /* IOR */
memrd ();
AC |= MB;
break;
case 054: /* XOR */
memrd ();
AC ^= MB;
break;
case 060: /* LAC */
memrd ();
AC = MB;
break;
case 064: /* ADD */
memrd ();
t32 = AC;
t32 += MB;
AC = t32 & 0177777;
if (t32 & 0200000)
L ^= 1;
break;
case 070: /* SUB */
memrd ();
t32 = AC;
t32 -= MB;
AC = t32 & 0177777;
if (t32 & 0200000)
L ^= 1;
break;
case 074: /* SAM */
memrd ();
pcinc (AC == MB);
break;
default:
sim_debug (DBG_CPU, &cpu_dev, "Unknown instruction: %06o\n", IR);
break;
}
}
t_stat sim_instr (void)
{
t_stat reason;
if ((reason = build_dev_tab ()) != SCPE_OK)
return reason;
halt = 0;
for (;;) {
AIO_CHECK_EVENT;
if (sim_interval <= 0) {
if ((reason = sim_process_event()) != SCPE_OK)
return reason;
}
if (sim_brk_summ && sim_brk_test(PC, SWMASK('E')))
return STOP_IBKPT;
/* Check for interrupts. */
if (ION && (FLAGS & ARM)) {
sim_debug (DBG_IRQ, &irq_dev, "Interrupt: %06o\n", FLAGS & ARM);
M[0] = PC;
PC = 1;
ION = 0;
}
cpu_insn ();
if (sim_step != 0) {
if (--sim_step == 0)
return SCPE_STEP;
}
if (halt)
return STOP_HALT;
if (ion_delay && --ion_delay == 0) {
sim_debug (DBG_IRQ, &irq_dev, "Interrupts on\n");
ION = 1;
}
}
return SCPE_OK;
}
static t_stat cpu_ex (t_value *vptr, t_addr ea, UNIT *uptr, int32 sw)
{
if (vptr == NULL)
return SCPE_ARG;
if (ea >= 040000)
return SCPE_NXM;
*vptr = M[ea];
return SCPE_OK;
}
static t_stat cpu_dep (t_value val, t_addr ea, UNIT *uptr, int32 sw)
{
if (ea >= 040000)
return SCPE_NXM;
M[ea] = val & 0177777;
return SCPE_OK;
}
static t_bool cpu_is_pc_a_subroutine_call (t_addr **ret_addrs)
{
static t_addr returns[2] = { 0, 0 };
if ((M[PC] & 074000) == 034000) {
returns[0] = PC + 1;
*ret_addrs = returns;
return TRUE;
} else {
return FALSE;
}
}
static t_stat
cpu_reset (DEVICE *dptr)
{
sim_brk_types = SWMASK('D') | SWMASK('E');
sim_brk_dflt = SWMASK ('E');
sim_vm_is_subroutine_call = &cpu_is_pc_a_subroutine_call;
return SCPE_OK;
}
void
flag_on (uint16 flag)
{
FLAGS |= flag;
sim_debug (DBG_IRQ, &irq_dev, "Flag on %06o -> %06o\n", flag, FLAGS);
}
void
flag_off (uint16 flag)
{
FLAGS &= ~flag;
sim_debug (DBG_IRQ, &irq_dev, "Flag off %06o -> %06o\n", flag, FLAGS);
}
static uint16
irq_iot (uint16 insn, uint16 AC)
{
if ((insn & 0771) == 0101) { /* RDI */
AC |= FLAGS;
}
if ((insn & 0771) == 0141) { /* ARM */
ARM = AC;
}
if ((insn & 0771) == 0161) { /* IOF */
sim_debug (DBG_IRQ, &irq_dev, "Interrupts off\n");
ION = 0;
}
if ((insn & 0772) == 0162) { /* ION */
/* Delay the action until next instruction has executed. */
ion_delay = 2;
}
return AC;
}
void
rom_data (uint16 *data)
{
int i;
for (i = 0; i < 040; i++)
M[040 + i] = data[i];
}
static t_stat
rom_set_type (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{
t_stat r = SCPE_OK;
if (strcmp (cptr, "NONE") == 0) {
rom_type = ROM_NONE;
} else if (strcmp (cptr, "TTY") == 0) {
rom_type = ROM_TTY;
rom_tty ();
} else if (strcmp (cptr, "STTY") == 0) {
rom_type = ROM_STTY;
rom_stty ();
} else if (strcmp (cptr, "PTR") == 0) {
rom_type = ROM_PTR;
rom_ptr ();
} else
r = SCPE_ARG;
return r;
}
static t_stat
rom_show_type (FILE *st, UNIT *up, int32 v, CONST void *dp)
{
switch (rom_type) {
case ROM_NONE:
fprintf (st, "TYPE=NONE");
break;
case ROM_TTY:
fprintf (st, "TYPE=TTY");
break;
case ROM_STTY:
fprintf (st, "TYPE=STTY");
break;
case ROM_PTR:
fprintf (st, "TYPE=PTR");
break;
default:
fprintf (st, "TYPE=(invalid)");
break;
}
return SCPE_OK;
}

136
imlac/imlac_crt.c Normal file
View File

@@ -0,0 +1,136 @@
/* imlac_crt.c: Imlac CRT display
Copyright (c) 2020, Lars Brinkhoff
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
LARS BRINKHOFF BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Lars Brinkhoff shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Lars Brinkhoff.
*/
#include "imlac_defs.h"
#include "sim_video.h"
#include "display/imlac.h"
#include "display/display.h"
/* Function declaration. */
static t_stat crt_svc (UNIT *uptr);
static t_stat crt_reset (DEVICE *dptr);
static int crt_quit = FALSE;
/* Debug */
#define DBG 0001
static UNIT crt_unit = {
UDATA (&crt_svc, UNIT_IDLE, 0)
};
static DEBTAB crt_deb[] = {
{ "DBG", DBG },
{ NULL, 0 }
};
DEVICE crt_dev = {
"CRT", &crt_unit, NULL, NULL,
1, 8, 16, 1, 8, 16,
NULL, NULL, &crt_reset,
NULL, NULL, NULL,
NULL, DEV_DISABLE | DEV_DEBUG | DEV_DIS, 0, crt_deb,
NULL, NULL, NULL, NULL, NULL, NULL
};
static t_stat
crt_svc(UNIT *uptr)
{
#ifdef HAVE_LIBSDL
imlac_cycle (100, 0);
sim_activate_after (uptr, 100);
if (crt_quit) {
crt_quit = FALSE;
return SCPE_STOP;
}
#endif
return SCPE_OK;
}
static void crt_quit_callback (void)
{
crt_quit = TRUE;
}
static t_stat
crt_reset (DEVICE *dptr)
{
#ifdef HAVE_LIBSDL
if (dptr->flags & DEV_DIS) {
display_close (dptr);
sim_cancel (&crt_unit);
} else {
display_reset ();
imlac_init (dptr, 1);
sim_activate_abs (&crt_unit, 0);
vid_register_quit_callback (&crt_quit_callback);
}
#endif
return SCPE_OK;
}
void
crt_point (uint16 x, uint16 y)
{
sim_debug (DBG, &crt_dev, "Point %d,%d\n", x, y);
#ifdef HAVE_LIBSDL
if (crt_dev.flags & DEV_DIS)
return;
imlac_point ((x & 03777) >> 1, (y & 03777) >> 1);
#endif
}
void
crt_line (uint16 x1, uint16 y1, uint16 x2, uint16 y2)
{
sim_debug (DBG, &crt_dev, "Line %d,%d - %d,%d\n", x1, y1, x2, y2);
#ifdef HAVE_LIBSDL
if (crt_dev.flags & DEV_DIS)
return;
imlac_line ((x1 & 03777) >> 1, (y1 & 03777) >> 1,
(x2 & 03777) >> 1, (y2 & 03777) >> 1);
#endif
}
/* Hook called when CRT goes idle. */
void
crt_idle (void)
{
}
/* Display high voltage sync. */
void
crt_hvc (void)
{
}
void cpu_get_switches (unsigned long *p1, unsigned long *p2)
{
}
void cpu_set_switches (unsigned long p1, unsigned long p2)
{
}

77
imlac/imlac_defs.h Normal file
View File

@@ -0,0 +1,77 @@
/* imlac_defs.h: Imlac simulator definitions
Copyright (c) 2020, Lars Brinkhoff
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
LARS BRINKHOFF BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Lars Brinkhoff shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Lars Brinkhoff.
21-Apr-20 LB New simulator.
*/
#ifndef IMLAC_DEFS_H_
#define IMLAC_DEFS_H_ 0
#include "sim_defs.h"
#define STOP_HALT 1
#define STOP_IBKPT 2
#define STOP_ACCESS 3
#define FLAG_PTR 010000
#define FLAG_PTP 000400
#define FLAG_TTY_T 000040
#define FLAG_KBD 000020
#define FLAG_TTY_R 000010
#define FLAG_SYNC 000002
typedef struct {
uint16 num;
uint16 (*iot)(uint16 insn, uint16 AC);
const char *mnemonics[8];
} SUBDEV;
typedef struct {
int codes;
SUBDEV subdev[4];
} IMDEV;
extern t_bool build_dev_tab (void);
extern void flag_on (uint16 flag);
extern void flag_off (uint16 flag);
extern void dp_on (int flag);
extern uint16 dp_is_on (void);
extern void crt_point (uint16 x, uint16 y);
extern void crt_line (uint16 x1, uint16 y1, uint16 x2, uint16 y2);
extern void crt_idle (void);
extern void crt_hvc (void);
extern void rom_data (uint16 *data);
extern void rom_tty (void);
extern void rom_stty (void);
extern void rom_ptr (void);
extern REG cpu_reg[];
extern uint16 M[];
extern uint16 memmask;
extern SUBDEV *dev_tab[0100];
extern DEVICE cpu_dev, irq_dev, rom_dev, dp_dev, crt_dev, kbd_dev;
extern DEVICE tty_dev, ptr_dev, ptp_dev, sync_dev;
#endif /* IMLAC_DEFS_H_ */

485
imlac/imlac_dp.c Normal file
View File

@@ -0,0 +1,485 @@
/* imlac_dp.c: Imlac display processor
Copyright (c) 2020, Lars Brinkhoff
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
LARS BRINKHOFF BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Lars Brinkhoff shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Lars Brinkhoff.
*/
#include "imlac_defs.h"
/* Debug */
#define DBG 0001
static t_addr DPC;
static t_addr DT;
static uint16 ON = 0;
static uint16 HALT = 0;
static uint16 MODE = 0;
static uint16 XA, YA;
static uint16 SCALE = 2;
static uint16 BLOCK = 0;
static uint16 MIT8K;
static uint16 SGR;
static uint16 SYNC = 1;
/* Function declaration. */
static uint16 dp_iot (uint16, uint16);
static t_stat dp_svc (UNIT *uptr);
static uint16 sync_iot (uint16, uint16);
static t_stat sync_svc (UNIT *uptr);
static IMDEV dp_imdev = {
3,
{ { 0000, dp_iot, { NULL, NULL, NULL, "DLA" } },
{ 0001, dp_iot, { NULL, "CTB", "DOF", NULL } },
{ 0030, dp_iot, { NULL, NULL, NULL, "DCF" } } }
};
static UNIT dp_unit = {
UDATA (&dp_svc, UNIT_IDLE, 0)
};
static REG dp_reg[] = {
{ ORDATAD (DPC, DPC, 16, "Display program counter") },
{ ORDATAD (ON, ON, 1, "Display on") },
{ ORDATAD (HALT, HALT, 1, "Display halted") },
{ ORDATAD (MODE, MODE, 1, "Display mode") },
{ ORDATAD (DT, DT, 16, "Return address") },
{ ORDATAD (XA, XA, 11, "X accumulator") },
{ ORDATAD (YA, YA, 11, "Y accumulator") },
{ ORDATAD (SCALE, SCALE, 3, "Scale") },
{ ORDATAD (BLOCK, BLOCK, 3, "Block") },
{ ORDATAD (MIT8K, MIT8K, 1, "MIT 8K addressing") },
{ ORDATAD (SGR, SGR, 1, "Suppressed grid mode") },
{ NULL }
};
static DEBTAB dp_deb[] = {
{ "DBG", DBG },
{ NULL, 0 }
};
DEVICE dp_dev = {
"DP", &dp_unit, dp_reg, NULL,
1, 8, 16, 1, 8, 16,
NULL, NULL, NULL,
NULL, NULL, NULL, &dp_imdev, DEV_DEBUG, 0, dp_deb,
NULL, NULL, NULL, NULL, NULL, NULL
};
static UNIT sync_unit = {
UDATA (&sync_svc, UNIT_IDLE, 0)
};
static REG sync_reg[] = {
{ ORDATAD (SYNC, SYNC, 1, "Flag") },
{ NULL }
};
static IMDEV sync_imdev = {
1,
{ { 0007, sync_iot, { NULL, "SCF", "IOS", NULL } } }
};
static DEBTAB sync_deb[] = {
{ "DBG", DBG },
{ NULL, 0 }
};
DEVICE sync_dev = {
"SYNC", &sync_unit, sync_reg, NULL,
1, 8, 16, 1, 8, 16,
NULL, NULL, NULL,
NULL, NULL, NULL,
&sync_imdev, DEV_DEBUG, 0, sync_deb,
NULL, NULL, NULL, NULL, NULL, NULL
};
void
dp_on (int flag)
{
if (!ON && flag) {
MIT8K = 0;
sim_activate_abs (&dp_unit, 0);
sim_debug (DBG, &dp_dev, "Display on\n");
} else if (ON && !flag) {
sim_cancel (&dp_unit);
sim_debug (DBG, &dp_dev, "Display off\n");
crt_idle ();
if (SYNC && HALT)
flag_on (FLAG_SYNC);
}
ON = flag;
}
uint16
dp_is_on (void)
{
return ON;
}
static uint16
dp_iot (uint16 insn, uint16 AC)
{
if ((insn & 0771) == 0001) { /* DLZ */
sim_debug (DBG, &dp_dev, "DPC cleared\n");
DPC = 0;
}
if ((insn & 0772) == 0002) { /* DLA */
sim_debug (DBG, &dp_dev, "DPC set to %06o\n", AC);
DPC |= AC;
}
if ((insn & 0771) == 0011) { /* CTB */
;
}
if ((insn & 0772) == 0012) { /* DOF */
dp_on (0);
}
if ((insn & 0774) == 0304) { /* DCF */
HALT = 0;
}
return AC;
}
static t_stat
dp_opr(uint16 insn)
{
if ((insn & 04000) == 0) {
sim_debug (DBG, &dp_dev, "DHLT ");
HALT = 1;
}
else if (insn == 04000)
sim_debug (DBG, &dp_dev, "DNOP");
dp_on ((insn & 04000) != 0); /* DHLT */
switch (insn & 00014) {
case 000:
if (insn & 1) {
sim_debug (DBG, &dp_dev, "DADR ");
MIT8K = !MIT8K;
}
break;
case 004:
sim_debug (DBG, &dp_dev, "DSTS%o ", insn & 3);
SCALE = insn & 3;
if (SCALE == 0)
SCALE = 1;
else
SCALE *= 2;
break;
case 010:
sim_debug (DBG, &dp_dev, "DSTB%o ", insn & 3);
BLOCK = insn & 3;
break;
case 014:
sim_debug (DBG, &dp_dev, "DSTL%o ", insn & 3);
/* TODO: Light pen. */
break;
}
if (insn & 00020) { /* DDSP */
sim_debug (DBG, &dp_dev, "DDSP ");
crt_point (XA, YA);
}
if (insn & 00040) { /* DRJM */
sim_debug (DBG, &dp_dev, "DRJM ");
DPC = DT;
}
if (insn & 00100) { /* DDYM */
sim_debug (DBG, &dp_dev, "DDYM ");
YA -= 040;
}
if (insn & 00200) { /* DDXM */
sim_debug (DBG, &dp_dev, "DDXM ");
XA -= 040;
}
if (insn & 00400) { /* DIYM */
sim_debug (DBG, &dp_dev, "DIYM ");
YA += 040;
}
if (insn & 01000) { /* DIXM */
sim_debug (DBG, &dp_dev, "DIXM ");
XA += 040;
}
if (insn & 02000) { /* DHVC */
sim_debug (DBG, &dp_dev, "DHVC ");
crt_hvc ();
}
sim_debug (DBG, &dp_dev, "\n");
return SCPE_OK;
}
static void
jump (uint16 insn)
{
DPC = insn & 07777;
if (MIT8K)
DPC |= (insn & 0100000) >> 3;
else
DPC |= BLOCK << 12;
}
static void
dp_sgr (uint16 insn)
{
sim_debug (DBG, &dp_dev, "DSGR %o\n", insn & 7);
SGR = insn & 1;
if (insn & 1) {
sim_debug (DBG, &dp_dev, "Enter SGR mode\n");
} else {
sim_debug (DBG, &dp_dev, "Exit SGR mode\n");
}
if (insn & 2) {
sim_debug (DBG, &dp_dev, "SGR: Return\n");
}
if (insn & 4) {
sim_debug (DBG, &dp_dev, "SGR: Beam on\n");
} else {
sim_debug (DBG, &dp_dev, "SGR: Beam off\n");
}
}
static void
dp_opt (uint16 insn)
{
switch (insn & 07770) {
case 07660: /* ASG-1 */
case 07667:
break;
case 07720: /* VIC-1 */
case 07730:
break;
case 07740: /* MCI-1 */
case 07750:
break;
case 07760: /* STI-1 or LPA-1 */
break;
case 07770: /* SGR-1 */
dp_sgr (insn);
break;
default:
sim_debug (DBG, &dp_dev, "Unknown instruction: %06o ", insn);
break;
}
}
static void
dp_inc_vector (uint16 byte)
{
uint16 x1 = XA, y1 = YA;
uint16 dx, dy;
if (byte == 0200) {
sim_debug (DBG, &dp_dev, "P");
} else {
sim_debug (DBG, &dp_dev, "%s", byte & 0100 ? "B" : "D");
if (byte & 00040)
sim_debug (DBG, &dp_dev, "M");
sim_debug (DBG, &dp_dev, "%o", (byte >> 3) & 3);
if (byte & 00004)
sim_debug (DBG, &dp_dev, "M");
sim_debug (DBG, &dp_dev, "%o", byte & 3);
}
dx = SCALE * ((byte >> 3) & 3);
dy = SCALE * (byte & 3);
if (byte & 040)
XA -= dx;
else
XA += dx;
if (byte & 4)
YA -= dy;
else
YA += dy;
if (byte & 0100)
crt_line (x1, y1, XA, YA);
}
static void
dp_inc_escape (uint16 byte)
{
if (byte == 0100)
sim_debug (DBG, &dp_dev, "T");
else if (byte == 0140)
sim_debug (DBG, &dp_dev, "X");
else if (byte == 0151)
sim_debug (DBG, &dp_dev, "R");
else
sim_debug (DBG, &dp_dev, "%03o", byte);
if (byte & 0100)
MODE = 0;
if (byte & 040)
DPC = DT;
if (byte & 020)
XA += 040;
if (byte & 010)
XA &= 03740;
if (byte & 4) /* Enter PPM mode. */
;
if (byte & 2)
YA += 040;
if (byte & 1)
YA &= 03740;
}
static void
dp_inc (uint16 byte)
{
if (byte & 0200) {
/* Increment byte. */
dp_inc_vector (byte);
} else {
/* Escape byte. */
dp_inc_escape (byte);
}
}
static void
dp_deim (uint16 insn)
{
MODE = 1;
sim_debug (DBG, &dp_dev, "E,");
dp_inc (insn & 0377);
sim_debug (DBG, &dp_dev, "\n");
}
static void
dp_dlvh (uint16 insn1, uint16 insn2, uint16 insn3)
{
uint16 x1 = XA, y1 = YA;
uint16 m, n, dx, dy;
m = insn2 & 07777;
n = insn3 & 07777;
if (insn3 & 010000) {
dx = m;
dy = n;
} else {
dx = n;
dy = m;
}
if (insn3 & 040000)
XA -= SCALE * dx;
else
XA += SCALE * dx;
if (insn3 & 020000)
YA -= SCALE * dy;
else
YA += SCALE * dy;
if (insn2 & 020000)
crt_line (x1, y1, XA, YA);
}
static void
dp_insn (uint16 insn)
{
switch ((insn >> 12) & 7) {
case 0: /* DOPR */
dp_opr (insn);
break;
case 1: /* DLXA */
sim_debug (DBG, &dp_dev, "DLXA\n");
XA = (insn & 01777) << 1;
break;
case 2: /* DLYA */
sim_debug (DBG, &dp_dev, "DLYA\n");
YA = (insn & 01777) << 1;
break;
case 3: /* DEIM */
sim_debug (DBG, &dp_dev, "DEIM ");
dp_deim (insn);
break;
case 4: /* DLVH */
sim_debug (DBG, &dp_dev, "DLVH\n");
dp_dlvh (insn, M[DPC], M[DPC+1]);
DPC += 2;
break;
case 5: /* DJMS */
sim_debug (DBG, &dp_dev, "DJMS\n");
DT = DPC;
/* Fall through. */
case 6: /* DJMP */
sim_debug (DBG, &dp_dev, "DJMP\n");
jump (insn);
break;
case 7: /* optional */
dp_opt (insn);
break;
}
}
static t_stat
dp_svc(UNIT * uptr)
{
uint16 insn;
if (sim_brk_summ && sim_brk_test(DPC, SWMASK('D'))) {
sim_activate_abs (&dp_unit, 0);
return sim_messagef (SCPE_STOP, "Display processor breakpoint.\n");
}
sim_debug (DBG, &dp_dev, "%06o ", DPC);
insn = M[DPC];
DPC++;
if (MODE) {
sim_debug (DBG, &dp_dev, "INC ");
dp_inc (insn >> 8);
if (MODE) {
sim_debug (DBG, &dp_dev, ",");
dp_inc (insn & 0377);
}
sim_debug (DBG, &dp_dev, "\n");
} else
dp_insn (insn);
if (ON)
sim_activate_after (&dp_unit, 2);
return SCPE_OK;
}
static t_stat
sync_svc (UNIT *uptr)
{
sim_debug (DBG, &sync_dev, "40 Hz sync\n");
SYNC = 1;
if (SYNC && HALT)
flag_on (FLAG_SYNC);
sim_cancel (&sync_unit);
return SCPE_OK;
}
static uint16
sync_iot (uint16 insn, uint16 AC)
{
if ((insn & 0771) == 0071) { /* SCF */
sim_debug (DBG, &sync_dev, "Clear flag\n");
SYNC = 0;
flag_off (FLAG_SYNC);
sim_activate_after (&sync_unit, 25000);
}
if ((insn & 0772) == 0072) { /* IOS */
}
return AC;
}

641
imlac/imlac_kbd.c Normal file
View File

@@ -0,0 +1,641 @@
/* imlac_kbd.c: Imlac keyboard device
Copyright (c) 2020, Lars Brinkhoff
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
LARS BRINKHOFF BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Lars Brinkhoff shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Lars Brinkhoff.
*/
#include "imlac_defs.h"
#include "sim_video.h"
/* Debug */
#define DBG 0001
#define KBD_DISPLAY 1
#define KBD_CONSOLE 2
#define SHFT 00400
#define CTRL 01000
#define REPT 02000
#define META 00000
#define TOP 00000
static uint16 KBUF;
static uint16 modifiers;
static int kbd_type = KBD_DISPLAY;
/* Function declaration. */
static t_stat kbd_svc (UNIT *uptr);
static t_stat kbd_set_type (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
static t_stat kbd_show_type (FILE *st, UNIT *up, int32 v, CONST void *dp);
static t_stat kbd_reset (DEVICE *dptr);
static uint16 kbd_iot (uint16, uint16);
static UNIT kbd_unit = {
UDATA (&kbd_svc, UNIT_IDLE, 0)
};
static REG kbd_reg[] = {
{ ORDATAD (KBUF, KBUF, 16, "Keyboard buffer") },
{ NULL }
};
MTAB kbd_mod[] = {
{ MTAB_VDV|MTAB_VALR, 1, "TYPE", "TYPE", &kbd_set_type,
&kbd_show_type, NULL, "Set keyboard input type" },
{ 0 }
};
static IMDEV kbd_imdev = {
1,
{ { 0002, kbd_iot, { NULL, "KRB", "KCF", "KRC" } } }
};
static DEBTAB kbd_deb[] = {
{ "DBG", DBG },
{ NULL, 0 }
};
DEVICE kbd_dev = {
"KBD", &kbd_unit, kbd_reg, kbd_mod,
0, 8, 16, 1, 8, 16,
NULL, NULL, &kbd_reset,
NULL, NULL, NULL, &kbd_imdev,
DEV_DISABLE | DEV_DEBUG, 0, kbd_deb,
NULL, NULL, NULL, NULL, NULL, NULL
};
static int32 kbd_translate (int32 ch)
{
static int32 table[] = {
01240, 01301, 00202, 01303, 00204, 00205, 00206, 01307, /* ^@ - ^G */
00210, 00211, 00212, 01313, 00214, 00215, 00216, 00217,
01320, 01321, 01322, 01323, 01324, 01325, 01326, 01327,
00230, 01331, 01332, 00233, 00234, 00235, 00236, 01337,
00240, 00241, 00242, 00243, 00244, 00245, 00246, 00247, /* SPC - ' */
00250, 00251, 00252, 00253, 00254, 00255, 00256, 00257,
00260, 00261, 00262, 00263, 00264, 00265, 00266, 00267,
00270, 00271, 00272, 00273, 00274, 00275, 00276, 00277,
00300, 00301, 00302, 00303, 00304, 00305, 00306, 00307, /* @ - G */
00310, 00311, 00312, 00313, 00314, 00315, 00316, 00317, /* H - O */
00320, 00321, 00322, 00323, 00324, 00325, 00326, 00327, /* P - W */
00330, 00331, 00332, 00333, 00334, 00335, 00336, 00337, /* X - _ */
00340, 00341, 00342, 00343, 00344, 00345, 00346, 00347, /* ` - g */
00350, 00351, 00352, 00353, 00354, 00355, 00356, 00357,
00360, 00361, 00362, 00363, 00364, 00365, 00366, 00367,
00370, 00371, 00372, 00373, 00374, 00375, 00376, 00377
};
return table[ch];
}
static t_stat kbd_svc (UNIT *uptr)
{
t_stat ch = sim_poll_kbd ();
if ((ch & SCPE_KFLAG) == 0) {
sim_activate_after (&kbd_unit, 10000);
return ch;
}
if (ch & SCPE_BREAK)
KBUF = 0231;
else
KBUF = kbd_translate (ch & 0177);
flag_on (FLAG_KBD);
sim_debug (DBG, &kbd_dev, "Received character %03o\n", KBUF);
return SCPE_OK;
}
static int
kbd_modifiers (SIM_KEY_EVENT *ev)
{
uint16 code = 0;
switch (ev->key) {
case SIM_KEY_SHIFT_L:
case SIM_KEY_SHIFT_R:
code = SHFT;
break;
case SIM_KEY_CTRL_L:
case SIM_KEY_CTRL_R:
case SIM_KEY_CAPS_LOCK:
code = CTRL;
break;
case SIM_KEY_WIN_L:
case SIM_KEY_WIN_R:
code = TOP;
break;
case SIM_KEY_ALT_L:
case SIM_KEY_ALT_R:
code = META;
break;
}
if (ev->state == SIM_KEYPRESS_DOWN)
modifiers |= code;
else if (ev->state == SIM_KEYPRESS_UP)
modifiers &= ~code;
return code != 0;
}
static int
kbd_both (uint32 key)
{
uint16 code;
switch (key) {
case SIM_KEY_END:
code = 0002; // XMIT
break;
case SIM_KEY_DOWN:
code = 0004;
break;
case SIM_KEY_RIGHT:
code = 0005;
break;
case SIM_KEY_UP:
code = 0006;
break;
case SIM_KEY_LEFT:
code = 0010;
break;
case SIM_KEY_TAB:
code = 0011;
break;
#if 0
case SIM_KEY_:
code = 0012; // LF
break;
#endif
case SIM_KEY_PAGE_UP:
code = 0014; // FORM
break;
case SIM_KEY_ENTER:
code = 0015;
break;
case SIM_KEY_PAGE_DOWN:
code = 0016; // PAGE XMIT
break;
case SIM_KEY_HOME:
code = 0017;
break;
case SIM_KEY_KP_INSERT:
code = 0030; // KP_0
break;
case SIM_KEY_PAUSE:
code = 0031; // BRK
break;
case SIM_KEY_KP_DOWN:
code = 0032; // KP_2
break;
case SIM_KEY_ESC:
code = 0033;
break;
case SIM_KEY_KP_LEFT:
code = 0034; // KP_4
break;
case SIM_KEY_KP_5:
code = 0035; // KP_5
break;
case SIM_KEY_KP_RIGHT:
code = 0036; // KP_6
break;
case SIM_KEY_SPACE:
code = 0040;
break;
case SIM_KEY_BACKSPACE:
case SIM_KEY_DELETE:
code = 0177;
break;
default:
return 0;
}
return code | modifiers;
}
static int
kbd_shift (uint32 key)
{
uint16 code;
code = kbd_both (key);
if (code != 0)
return code;
switch (key) {
case SIM_KEY_0:
code = ')';
break;
case SIM_KEY_1:
code = '!';
break;
case SIM_KEY_2:
return CTRL + ';';
break;
case SIM_KEY_3:
code = '#';
break;
case SIM_KEY_4:
code = '$';
break;
case SIM_KEY_5:
code = '%';
break;
case SIM_KEY_6:
return CTRL + ':';
case SIM_KEY_7:
code = '&';
break;
case SIM_KEY_8:
code = '*';
break;
case SIM_KEY_9:
code = '(';
break;
case SIM_KEY_A:
code = 'A';
break;
case SIM_KEY_B:
code = 'B';
break;
case SIM_KEY_C:
code = 'C';
break;
case SIM_KEY_D:
code = 'D';
break;
case SIM_KEY_E:
code = 'E';
break;
case SIM_KEY_F:
code = 'F';
break;
case SIM_KEY_G:
code = 'G';
break;
case SIM_KEY_H:
code = 'H';
break;
case SIM_KEY_I:
code = 'I';
break;
case SIM_KEY_J:
code = 'J';
break;
case SIM_KEY_K:
code = 'K';
break;
case SIM_KEY_L:
code = 'L';
break;
case SIM_KEY_M:
code = 'M';
break;
case SIM_KEY_N:
code = 'N';
break;
case SIM_KEY_O:
code = 'O';
break;
case SIM_KEY_P:
code = 'P';
break;
case SIM_KEY_Q:
code = 'Q';
break;
case SIM_KEY_R:
code = 'R';
break;
case SIM_KEY_S:
code = 'S';
break;
case SIM_KEY_T:
code = 'T';
break;
case SIM_KEY_U:
code = 'U';
break;
case SIM_KEY_V:
code = 'V';
break;
case SIM_KEY_W:
code = 'W';
break;
case SIM_KEY_X:
code = 'X';
break;
case SIM_KEY_Y:
code = 'Y';
break;
case SIM_KEY_Z:
code = 'Z';
break;
case SIM_KEY_BACKQUOTE:
return CTRL + '6';
case SIM_KEY_MINUS:
return CTRL + '-';
case SIM_KEY_EQUALS:
code = '+';
break;
case SIM_KEY_LEFT_BRACKET:
return CTRL + '8';
case SIM_KEY_RIGHT_BRACKET:
return CTRL + '9';
case SIM_KEY_SEMICOLON:
code = ':';
break;
case SIM_KEY_SINGLE_QUOTE:
code = '"';
break;
case SIM_KEY_BACKSLASH:
case SIM_KEY_LEFT_BACKSLASH:
return CTRL + '0';
case SIM_KEY_COMMA:
code = '<';
break;
case SIM_KEY_PERIOD:
code = '>';
break;
case SIM_KEY_SLASH:
code = '?';
break;
default:
return 0;
}
return code | modifiers;
}
static int
kbd_noshift (uint32 key)
{
uint16 code;
code = kbd_both (key);
if (code != 0)
return code;
switch (key) {
case SIM_KEY_0:
code = '0';
break;
case SIM_KEY_1:
code = '1';
break;
case SIM_KEY_2:
code = '2';
break;
case SIM_KEY_3:
code = '3';
break;
case SIM_KEY_4:
code = '4';
break;
case SIM_KEY_5:
code = '5';
break;
case SIM_KEY_6:
code = '6';
break;
case SIM_KEY_7:
code = '7';
break;
case SIM_KEY_8:
code = '8';
break;
case SIM_KEY_9:
code = '9';
break;
case SIM_KEY_A:
code = 'a';
break;
case SIM_KEY_B:
code = 'b';
break;
case SIM_KEY_C:
code = 'c';
break;
case SIM_KEY_D:
code = 'd';
break;
case SIM_KEY_E:
code = 'e';
break;
case SIM_KEY_F:
code = 'f';
break;
case SIM_KEY_G:
code = 'g';
break;
case SIM_KEY_H:
code = 'h';
break;
case SIM_KEY_I:
code = 'i';
break;
case SIM_KEY_J:
code = 'j';
break;
case SIM_KEY_K:
code = 'k';
break;
case SIM_KEY_L:
code = 'l';
break;
case SIM_KEY_M:
code = 'm';
break;
case SIM_KEY_N:
code = 'n';
break;
case SIM_KEY_O:
code = 'o';
break;
case SIM_KEY_P:
code = 'p';
break;
case SIM_KEY_Q:
code = 'q';
break;
case SIM_KEY_R:
code = 'r';
break;
case SIM_KEY_S:
code = 's';
break;
case SIM_KEY_T:
code = 't';
break;
case SIM_KEY_U:
code = 'u';
break;
case SIM_KEY_V:
code = 'v';
break;
case SIM_KEY_W:
code = 'w';
break;
case SIM_KEY_X:
code = 'x';
break;
case SIM_KEY_Y:
code = 'y';
break;
case SIM_KEY_Z:
code = 'z';
break;
case SIM_KEY_BACKQUOTE:
code = CTRL + '7';
break;
case SIM_KEY_MINUS:
code = '-';
break;
case SIM_KEY_EQUALS:
code = SHFT + '=';
break;
case SIM_KEY_LEFT_BRACKET:
code = CTRL + ',';
break;
case SIM_KEY_RIGHT_BRACKET:
code = CTRL + '.';
break;
case SIM_KEY_SEMICOLON:
code = ';';
break;
case SIM_KEY_SINGLE_QUOTE:
code = SHFT + '\'';
break;
case SIM_KEY_BACKSLASH:
case SIM_KEY_LEFT_BACKSLASH:
code = CTRL + '/';
break;
case SIM_KEY_COMMA:
code = ',';
break;
case SIM_KEY_PERIOD:
code = '.';
break;
case SIM_KEY_SLASH:
code = '/';
break;
default:
return 0;
}
return code | modifiers;
}
static int
kbd_event (SIM_KEY_EVENT *ev)
{
sim_debug (DBG, &kbd_dev, "Key %s %s\n",
ev->state == SIM_KEYPRESS_UP ? "up" : "down",
vid_key_name (ev->key));
if (kbd_modifiers (ev))
return 0;
if (ev->state == SIM_KEYPRESS_DOWN) {
uint16 code;
if (modifiers & SHFT)
code = kbd_shift (ev->key);
else
code = kbd_noshift (ev->key);
if (code != 0) {
KBUF = code | 0200;
sim_debug (DBG, &kbd_dev, "Received character %03o\n", KBUF);
flag_on (FLAG_KBD);
}
} else if (ev->state == SIM_KEYPRESS_UP)
KBUF = 0;
return 0;
}
static t_stat
kbd_reset (DEVICE *dptr)
{
#ifdef HAVE_LIBSDL
vid_display_kb_event_process = NULL;
#endif
if (dptr->flags & DEV_DIS)
return SCPE_OK;
if (kbd_type == KBD_DISPLAY)
#ifdef HAVE_LIBSDL
vid_display_kb_event_process = kbd_event;
#else
;
#endif
else if (kbd_type == KBD_CONSOLE)
sim_activate_abs (&kbd_unit, 0);
else
return SCPE_ARG;
return SCPE_OK;
}
static uint16
kbd_iot (uint16 insn, uint16 AC)
{
if ((insn & 0771) == 0021) { /* KRC */
sim_debug (DBG, &kbd_dev, "Read character %03o\n", KBUF);
AC |= KBUF;
if (kbd_type == KBD_CONSOLE)
KBUF = 0;
}
if ((insn & 0772) == 0022) { /* KCF */
sim_debug (DBG, &kbd_dev, "Clear flag\n");
flag_off (FLAG_KBD);
if (kbd_type == KBD_CONSOLE)
sim_activate_after (&kbd_unit, 10000);
}
return AC;
}
static t_stat
kbd_set_type (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{
t_stat r = SCPE_OK;
if (strcmp (cptr, "DISPLAY") == 0)
kbd_type = KBD_DISPLAY;
else if (strcmp (cptr, "CONSOLE") == 0)
kbd_type = KBD_CONSOLE;
else
r = SCPE_ARG;
return r;
}
static t_stat
kbd_show_type (FILE *st, UNIT *up, int32 v, CONST void *dp)
{
switch (kbd_type) {
case KBD_DISPLAY:
fprintf (st, "TYPE=DISPLAY");
break;
case KBD_CONSOLE:
fprintf (st, "TYPE=CONSOLE");
break;
default:
fprintf (st, "TYPE=(invalid)");
break;
}
return SCPE_OK;
}

113
imlac/imlac_pt.c Normal file
View File

@@ -0,0 +1,113 @@
/* imlac_pt.c: Imlac paper tape reader and punch
Copyright (c) 2020, Lars Brinkhoff
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
LARS BRINKHOFF BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Lars Brinkhoff shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Lars Brinkhoff.
*/
#include "imlac_defs.h"
/* Function declaration. */
static uint16 ptr_iot (uint16, uint16);
static uint16 ptp_iot (uint16, uint16);
static t_stat ptr_boot (int32 u, DEVICE *dptr);
static uint16 ptr_rom[] = {
0060077, 0020010, 0104076, 0020020, 0001061, 0100011, 0002400, 0010046,
0001051, 0074075, 0010045, 0002400, 0010053, 0001051, 0003003, 0003003,
0003002, 0102400, 0010061, 0002400, 0010063, 0001051, 0120010, 0102400,
0010067, 0100011, 0030020, 0010053, 0110076, 0000002, 0037700, 0037677,
};
static IMDEV ptr_imdev = {
2,
{ { 0005, ptr_iot, { NULL, "HRB", "HOF", NULL } },
{ 0006, ptr_iot, { NULL, "HON", "STB", NULL } } }
};
DEVICE ptr_dev = {
"PTR", NULL, NULL, NULL,
0, 8, 16, 1, 8, 16,
NULL, NULL, NULL,
&ptr_boot, NULL, NULL,
&ptr_imdev, DEV_DISABLE | DEV_DEBUG | DEV_DIS, 0, NULL,
NULL, NULL, NULL, NULL, NULL, NULL
};
static IMDEV ptp_imdev = {
1,
{ { 0027, ptp_iot, { "PUN", NULL, NULL, "PSF" } } }
};
DEVICE ptp_dev = {
"PTP", NULL, NULL, NULL,
0, 8, 16, 1, 8, 16,
NULL, NULL, NULL,
NULL, NULL, NULL,
&ptp_imdev, DEV_DISABLE | DEV_DEBUG | DEV_DIS, 0, NULL,
NULL, NULL, NULL, NULL, NULL, NULL
};
static uint16
ptr_iot (uint16 insn, uint16 AC)
{
if ((insn & 0771) == 0051) { /* HRB */
AC |= 0;
}
if ((insn & 0772) == 0052) { /* HOF */
;
}
if ((insn & 0771) == 0061) { /* HON */
;
}
if ((insn & 0772) == 0062) { /* STB */
;
}
return AC;
}
static uint16
ptp_iot (uint16 insn, uint16 AC)
{
if ((insn & 0771) == 0271) { /* PUN */
;
}
if ((insn & 0772) == 0274) { /* PSF */
;
}
return SCPE_OK;
}
void
rom_ptr (void)
{
rom_data (ptr_rom);
}
static t_stat
ptr_boot (int32 u, DEVICE *dptr)
{
uint16 *PC = (uint16 *)sim_PC->loc;
set_cmd (0, "ROM TYPE=PTR");
*PC = 040;
return SCPE_OK;
}

533
imlac/imlac_sys.c Normal file
View File

@@ -0,0 +1,533 @@
/* imlac_sys.c: Imlac simulator interface
Copyright (c) 2020, Lars Brinkhoff
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
LARS BRINKHOFF BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Lars Brinkhoff shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Lars Brinkhoff.
21-Apr-20 LB New simulator.
*/
#include "imlac_defs.h"
int32 sim_emax = 1;
char sim_name[] = "Imlac";
uint16 M[040000];
SUBDEV *dev_tab[0100];
REG *sim_PC = &cpu_reg[0];
DEVICE *sim_devices[] = {
&cpu_dev,
&rom_dev,
&dp_dev, /* 0-1 */
&crt_dev,
&kbd_dev, /* 2 */
&tty_dev, /* 3-4 */
&ptr_dev, /* 5-6 */
&sync_dev, /* 7, 30 */
&irq_dev, /* 10, 14, 16 */
/* &prot_dev, / * 11 */
/* &pen_dev, / * 13 */
&ptp_dev, /* 27 */
/* &mse_dev, / * 70, 73 */
/* &bel_dev, / * 71 */
NULL
};
const char *sim_stop_messages[] = {
"Unknown error",
"HALT instruction",
"Breakpoint",
"Invalid access",
};
static t_stat
get4 (FILE *fileref, uint16 *x)
{
int c;
for (;;) {
c = Fgetc (fileref);
if (c == EOF)
return SCPE_IOERR;
if ((c & 0160) == 0100) {
*x = c & 017;
return SCPE_OK;
}
}
}
static t_stat
get8 (FILE *fileref, uint16 *x)
{
uint16 y;
if (get4 (fileref, x) != SCPE_OK)
return SCPE_IOERR;
if (get4 (fileref, &y) != SCPE_OK)
return SCPE_IOERR;
*x = (*x << 4) | y;
return SCPE_OK;
}
static t_stat
get16 (FILE *fileref, uint16 *x)
{
uint16 y;
if (get8 (fileref, x) != SCPE_OK)
return SCPE_IOERR;
if (get8 (fileref, &y) != SCPE_OK)
return SCPE_IOERR;
*x = (*x << 8) | y;
return SCPE_OK;
}
static t_stat
load_stty (FILE *fileref)
{
int verbose = sim_switches & SWMASK ('V');
uint16 *PC = (uint16 *)sim_PC->loc;
uint16 x, count, addr;
uint32 csum;
int i;
/* Discard block loader. */
for (i = 0; i < 65; i++) {
if (get16 (fileref, &x) != SCPE_OK)
return SCPE_IOERR;
}
for (;;) {
/* Read count and address. */
if (get8 (fileref, &count) != SCPE_OK)
return SCPE_IOERR;
if (get16 (fileref, &addr) != SCPE_OK)
return SCPE_IOERR;
/* Address all ones means done. */
if (addr == 0177777) {
*PC = 077713 & memmask;
return SCPE_OK;
}
if (verbose)
sim_messagef (SCPE_OK, "Address %06o: %d words.\n", addr, count);
csum = 0;
for (i = 0; i < count; i++) {
if (get16 (fileref, &x) != SCPE_OK)
return SCPE_IOERR;
M[(addr++) & memmask] = x;
csum += x;
if (csum & 0200000) {
csum++;
csum &= 0177777;
}
}
if (get16 (fileref, &x) != SCPE_OK)
return SCPE_IOERR;
if (x != csum)
return SCPE_CSUM;
}
}
t_stat
sim_load (FILE *fileref, CONST char *cptr, CONST char *fnam, int flag)
{
if (sim_switches & SWMASK ('T'))
;
if (sim_switches & SWMASK ('S'))
;
if (sim_switches & SWMASK ('M'))
;
if (sim_switches & SWMASK ('P'))
;
return load_stty (fileref);
}
t_bool build_dev_tab (void)
{
DEVICE *dev;
IMDEV *imdev;
int i, j;
memset (dev_tab, 0, sizeof dev_tab);
for (i = 0; (dev = sim_devices[i]) != NULL; i++) {
imdev = (IMDEV *)dev->ctxt;
if (imdev != NULL) {
for (j = 0; j < imdev->codes; j++)
dev_tab[imdev->subdev[j].num] = &imdev->subdev[j];
}
}
return SCPE_OK;
}
static t_stat fprint_class1 (FILE *of, uint16 insn)
{
switch (insn & 0777) {
case 0000: fprintf (of, "NOP"); break;
case 0001: fprintf (of, "CLA"); break;
case 0002: fprintf (of, "CMA"); break;
case 0003: fprintf (of, "STA"); break;
case 0004: fprintf (of, "IAC"); break;
case 0005: fprintf (of, "COA"); break;
case 0006: fprintf (of, "CIA"); break;
case 0010: fprintf (of, "CLL"); break;
case 0011: fprintf (of, "CAL"); break;
case 0020: fprintf (of, "CML"); break;
case 0030: fprintf (of, "STL"); break;
case 0040: fprintf (of, "ODA"); break;
case 0041: fprintf (of, "LDA"); break;
default: fprintf (of, "%06o", insn); break;
}
return SCPE_OK;
}
static t_stat fprint_class2 (FILE *of, uint16 insn)
{
switch (insn & 0770) {
case 0000: fprintf (of, "RAL %o", insn & 7); break;
case 0020: fprintf (of, "RAR %o", insn & 7); break;
case 0040: fprintf (of, "SAL %o", insn & 7); break;
case 0060: fprintf (of, "SAR %o", insn & 7); break;
case 0100: fprintf (of, "DON"); break;
default: fprintf (of, "%06o", insn); break;
}
return SCPE_OK;
}
static t_stat fprint_class3 (FILE *of, uint16 insn)
{
switch (insn & 0177777) {
case 0002001: fprintf (of, "ASZ"); break;
case 0102001: fprintf (of, "ASN"); break;
case 0002002: fprintf (of, "ASP"); break;
case 0102002: fprintf (of, "ASM"); break;
case 0002004: fprintf (of, "LSZ"); break;
case 0102004: fprintf (of, "LSN"); break;
case 0002010: fprintf (of, "DSF"); break;
case 0102010: fprintf (of, "DSN"); break;
case 0002020: fprintf (of, "KSF"); break;
case 0102020: fprintf (of, "KSN"); break;
case 0002040: fprintf (of, "RSF"); break;
case 0102040: fprintf (of, "RSN"); break;
case 0002100: fprintf (of, "TSF"); break;
case 0102100: fprintf (of, "TSN"); break;
case 0002200: fprintf (of, "SSF"); break;
case 0102200: fprintf (of, "SSN"); break;
case 0002400: fprintf (of, "HSF"); break;
case 0102400: fprintf (of, "HSN"); break;
default: fprintf (of, "%06o", insn); break;
}
return SCPE_OK;
}
static t_stat fprint_iot (FILE *of, uint16 insn)
{
SUBDEV *imdev;
imdev = dev_tab[(insn >> 3) & 077];
if (imdev != NULL && imdev->mnemonics[insn & 7] != NULL) {
fprintf (of, "%s", imdev->mnemonics[insn & 7]);
return SCPE_OK;
}
fprintf (of, "IOT %03o", insn & 0777);
return SCPE_OK;
}
static t_stat fprint_opr (FILE *of, uint16 insn)
{
switch ((insn >> 9) & 0177) {
case 0000:
fprintf (of, "HLT ");
if (insn == 0)
break;
/* Fall through. */
case 0100:
return fprint_class1 (of, insn);
case 0003:
return fprint_class2 (of, insn);
case 0002:
case 0102:
return fprint_class3 (of, insn);
case 0001:
return fprint_iot (of, insn);
default:
fprintf (of, "%06o", insn);
break;
}
return SCPE_OK;
}
static t_stat
fprint_cpu (FILE *of, uint16 insn, uint16 addr)
{
switch ((insn >> 9) & 074) {
case 000:
return fprint_opr (of, insn);
case 004:
if (insn & 0100000)
fprintf (of, "LWC %o", insn & 03777);
else
fprintf (of, "LAW %o", insn & 03777);
return SCPE_OK;
case 010:
fprintf (of, "JMP");
break;
case 020:
fprintf (of, "DAC");
break;
case 024:
fprintf (of, "XAM");
break;
case 030:
fprintf (of, "ISZ");
break;
case 034:
fprintf (of, "JMS");
break;
case 044:
fprintf (of, "AND");
break;
case 050:
fprintf (of, "IOR");
break;
case 054:
fprintf (of, "XOR");
break;
case 060:
fprintf (of, "LAC");
break;
case 064:
fprintf (of, "ADD");
break;
case 070:
fprintf (of, "SUB");
break;
case 074:
fprintf (of, "SAM");
break;
default:
fprintf (of, "%06o", insn);
break;
}
fprintf (of, " ");
if (insn & 0100000)
fprintf (of, "@");
fprintf (of, "%o", (insn & 03777) | (addr & 014000));
return SCPE_OK;
}
static t_stat
fprint_dopr (FILE *of, uint16 insn)
{
if (insn == 04000) {
fprintf (of, "DNOP");
return SCPE_OK;
}
switch (insn & 00014) {
case 000:
if (insn & 1)
fprintf (of, "DADR ");
break;
case 004:
fprintf (of, "DSTS %o ", insn & 3);
break;
case 010:
fprintf (of, "DSTB %o ", insn & 3);
break;
case 014:
fprintf (of, "Unknown DP instruction %06o", insn);
break;
}
if (insn & 00020)
fprintf (of, "DDSP ");
if (insn & 00040)
fprintf (of, "DRJM ");
if (insn & 00100)
fprintf (of, "DDYM ");
if (insn & 00200)
fprintf (of, "DDXM ");
if (insn & 00400)
fprintf (of, "DIYM ");
if (insn & 01000)
fprintf (of, "DIXM ");
if (insn & 02000)
fprintf (of, "DHVC ");
if ((insn & 04000) == 0)
fprintf (of, "DHLT ");
return SCPE_OK;
}
static t_stat
fprint_inc_byte (FILE *of, uint16 byte)
{
if (byte & 0200) {
if (byte == 0200) {
fprintf (of, "P");
return SCPE_OK;
}
fprintf (of, "%s", byte & 0100 ? "B" : "D");
if (byte & 00040)
fprintf (of, "M");
fprintf (of, "%o", (byte >> 3) & 3);
if (byte & 00004)
fprintf (of, "M");
fprintf (of, "%o", byte & 3);
} else {
if (byte == 0140)
fprintf (of, "X");
else if (byte == 0060)
fprintf (of, "E");
else if (byte == 0100)
fprintf (of, "T");
else if (byte == 0111)
fprintf (of, "N");
else if (byte == 0151)
fprintf (of, "R");
else if (byte == 0171)
fprintf (of, "F");
else {
if (byte & 0100)
fprintf (of, "ESC ");
if (byte & 0040)
fprintf (of, "RJM ");
if (byte & 0020)
fprintf (of, "+X ");
if (byte & 0010)
fprintf (of, "0X ");
if (byte & 0004)
fprintf (of, "PPM ");
if (byte & 0002)
fprintf (of, "+Y ");
if (byte & 0001)
fprintf (of, "0Y ");
}
}
return SCPE_OK;
}
static t_stat
fprint_deim (FILE *of, uint16 insn)
{
fprintf (of, "DEIM ");
fprint_inc_byte (of, (insn >> 8) & 0377);
fprintf (of, ",");
fprint_inc_byte (of, insn & 0377);
return SCPE_OK;
}
static t_stat
fprint_dp_opt (FILE *of, uint16 insn)
{
switch (insn) {
case 077771:
fprintf (of, "DGD");
break;
case 077775:
fprintf (of, "DGB");
break;
default:
fprintf (of, "Unknown DP instruction: %06o", insn);
break;
}
return SCPE_OK;
}
static t_stat
fprint_dp (FILE *of, uint16 insn, uint16 addr)
{
switch ((insn >> 12) & 7) {
case 0:
return fprint_dopr (of, insn);
case 1:
fprintf (of, "DLXA %o", insn & 07777);
break;
case 2:
fprintf (of, "DLYA %o", insn & 07777);
break;
case 3:
return fprint_deim (of, insn);
case 4:
fprintf (of, "DLVH %04o, %06o, %06o",
insn & 07777, M[addr + 1], M[addr + 2]);
return -2;
case 5:
fprintf (of, "DJMS %o", insn & 07777);
break;
case 6:
fprintf (of, "DJMP %o", insn & 07777);
break;
case 7:
return fprint_dp_opt (of, insn);
}
return SCPE_OK;
}
static t_stat fprint_inc (FILE *of, uint16 insn)
{
fprintf (of, "INC ");
fprint_inc_byte (of, (insn >> 8) & 0377);
fprintf (of, ",");
fprint_inc_byte (of, insn & 0377);
return SCPE_OK;
}
t_stat fprint_sym (FILE *of, t_addr addr, t_value *val,
UNIT *uptr, int32 sw)
{
t_stat reason;
if ((reason = build_dev_tab ()) != SCPE_OK)
return reason;
if (sw & SWMASK ('M'))
return fprint_cpu (of, *val, addr);
else if (sw & SWMASK ('D'))
return fprint_dp (of, *val, addr);
else if (sw & SWMASK ('I'))
return fprint_inc (of, *val);
else
return SCPE_ARG;
}
t_stat parse_sym (CONST char *cptr, t_addr addr, UNIT *uptr,
t_value *val, int32 sw)
{
t_stat reason;
*val = get_uint (cptr, 8, ~0, &reason);
if (reason != SCPE_OK)
return reason;
return 0;
}

290
imlac/imlac_tty.c Normal file
View File

@@ -0,0 +1,290 @@
/* imlac_tty.c: Imlac serial port device
Copyright (c) 2020, Lars Brinkhoff
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
LARS BRINKHOFF BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Lars Brinkhoff shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Lars Brinkhoff.
*/
#include "imlac_defs.h"
#include "sim_tmxr.h"
/* Debug */
#define DBG 0001
#define TTY_FILE 1 /* Attached to a file. */
#define TTY_PORT 2 /* Attached to a network port. */
static uint16 RBUF, TBUF;
static int tty_type = TTY_PORT;
/* Function declaration. */
static uint16 tty_iot (uint16, uint16);
static t_stat tty_r_svc (UNIT *uptr);
static t_stat tty_t_svc (UNIT *uptr);
static t_stat tty_set_type (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
static t_stat tty_show_type (FILE *st, UNIT *up, int32 v, CONST void *dp);
static t_stat tty_boot (int32 u, DEVICE *dptr);
static t_stat tty_attach (UNIT *uptr, CONST char *cptr);
static t_stat tty_detach (UNIT *uptr);
static TMLN tty_ldsc = { 0 };
static TMXR tty_desc = { 1, 0, 0, &tty_ldsc };
static uint16 tty_rom[] = {
0060077, 0020010, 0104076, 0020020, 0001032, 0100011, 0002040, 0010046,
0001031, 0074075, 0010044, 0002040, 0010053, 0001033, 0003003, 0003003,
0003002, 0002040, 0010061, 0001033, 0120010, 0100011, 0030020, 0010053,
0110076, 0000000, 0000000, 0000000, 0000000, 0000002, 0037700, 0037677,
};
static uint16 stty_rom[] = {
0001032, 0104101, 0020010, 0020020, 0104004, 0020021, 0100011, 0020022,
0100011, 0002040, 0010051, 0001033, 0020023, 0044075, 0074076, 0010050,
0060023, 0044077, 0024022, 0003003, 0003001, 0050022, 0020022, 0030021,
0010050, 0120010, 0030020, 0010044, 0110000, 0000160, 0000100, 0000017
};
static uint16 mtty_rom[] = {
0060077, 0020010, 0104076, 0020020, 0001032, 0100011, 0002040, 0010046,
0001031, 0074075, 0010044, 0002040, 0010053, 0001033, 0003003, 0003003,
0003002, 0002040, 0010061, 0001033, 0120010, 0100011, 0030020, 0010053,
0110076, 0004200, 0100040, 0001043, 0010040, 0000002, 0037700, 0037677,
};
static UNIT tty_unit[] = {
{ UDATA (&tty_r_svc, UNIT_IDLE+UNIT_ATTABLE, 0) },
{ UDATA (&tty_t_svc, UNIT_IDLE+UNIT_ATTABLE, 0) }
};
static REG tty_reg[] = {
{ ORDATAD (RB, RBUF, 8, "Receive buffer") },
{ ORDATAD (TB, TBUF, 8, "Transmit buffer") },
{ NULL }
};
MTAB tty_mod[] = {
{ MTAB_VDV|MTAB_VALR, 1, "TYPE", "TYPE", &tty_set_type,
&tty_show_type, NULL, "Set attach type" },
{ MTAB_VDV|MTAB_VALR, 1, NULL, "DISCONNECT",
&tmxr_dscln, NULL, &tty_desc, "Disconnect a specific line" },
{ UNIT_ATT, UNIT_ATT, "SUMMARY", NULL, NULL,
&tmxr_show_summ, (void *) &tty_desc, "Display a summary of line states" },
{ MTAB_VDV|MTAB_NMO, 1, "CONNECTIONS", NULL, NULL,
&tmxr_show_cstat, (void *) &tty_desc, "Display current connections" },
{ MTAB_VDV|MTAB_NMO, 0, "STATISTICS", NULL, NULL,
&tmxr_show_cstat, (void *) &tty_desc, "Display multiplexer statistics" },
{ 0 }
};
static IMDEV tty_imdev = {
2,
{ { 0003, tty_iot, { NULL, "RRB", "RCF", "RRC" } },
{ 0004, tty_iot, { NULL, "TPR", "TCF", "TPC" } } }
};
static DEBTAB tty_deb[] = {
{ "DBG", DBG },
{ NULL, 0 }
};
DEVICE tty_dev = {
"TTY", tty_unit, tty_reg, tty_mod,
2, 8, 16, 1, 8, 16,
NULL, NULL, NULL,
tty_boot, tty_attach, tty_detach,
&tty_imdev, DEV_DEBUG, 0, tty_deb,
NULL, NULL, NULL, NULL, NULL, NULL
};
static t_stat
tty_r_svc(UNIT *uptr)
{
int32 ch;
if ((uptr->flags & UNIT_ATT) == 0)
return SCPE_OK;
if (uptr->fileref != NULL) {
char buf;
if (sim_fread (&buf, 1, 1, uptr->fileref) == 1) {
sim_debug (DBG, &tty_dev, "Received character %03o\n", buf);
RBUF = buf;
flag_on (FLAG_TTY_R);
}
} else {
if (tty_ldsc.conn) {
tmxr_poll_rx (&tty_desc);
ch = tmxr_getc_ln (&tty_ldsc);
if (ch & TMXR_VALID) {
RBUF = sim_tt_inpcvt (ch, TT_GET_MODE (tty_unit[0].flags));
sim_debug (DBG, &tty_dev, "Received character %03o\n", RBUF);
flag_on (FLAG_TTY_R);
return SCPE_OK;
}
sim_activate_after (uptr, 200);
} else {
int32 ln = tmxr_poll_conn (&tty_desc);
if (ln >= 0) {
tty_ldsc.rcve = 1;
sim_debug (DBG, &tty_dev, "Connect\n");
sim_activate_after (uptr, 200);
} else {
sim_activate_after (uptr, 10000);
}
}
}
return SCPE_OK;
}
static t_stat
tty_t_svc(UNIT *uptr)
{
int32 ch;
tmxr_poll_tx (&tty_desc);
if (!tmxr_txdone_ln (&tty_ldsc))
return SCPE_OK;
ch = sim_tt_outcvt (TBUF, TT_GET_MODE (tty_unit[1].flags));
if (tmxr_putc_ln (&tty_ldsc, ch) == SCPE_STALL) {
sim_activate_after (&tty_unit[1], 200);
} else {
sim_debug (DBG, &tty_dev, "Transmitted character %03o\n", TBUF);
tmxr_poll_tx (&tty_desc);
flag_on (FLAG_TTY_T);
}
return SCPE_OK;
}
static uint16
tty_iot (uint16 insn, uint16 AC)
{
if ((insn & 0771) == 0031) { /* RRB */
sim_debug (DBG, &tty_dev, "Read character %03o\n", RBUF);
AC |= RBUF;
}
if ((insn & 0772) == 0032) { /* RCF */
sim_debug (DBG, &tty_dev, "Clear read flag\n");
flag_off (FLAG_TTY_R);
sim_activate_after (&tty_unit[0], 200);
}
if ((insn & 0771) == 0041) { /* TPR */
sim_debug (DBG, &tty_dev, "Write character %03o\n", AC);
TBUF = AC;
sim_activate_after (&tty_unit[1], 200);
}
if ((insn & 0772) == 0042) { /* TCF */
sim_debug (DBG, &tty_dev, "Clear transmit flag\n");
flag_off (FLAG_TTY_T);
}
return AC;
}
static t_stat
tty_set_type (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{
t_stat r = SCPE_OK;
if (strcmp (cptr, "FILE") == 0)
tty_type = TTY_FILE;
else if (strcmp (cptr, "PORT") == 0)
tty_type = TTY_PORT;
else
r = SCPE_ARG;
return r;
}
static t_stat
tty_show_type (FILE *st, UNIT *up, int32 v, CONST void *dp)
{
switch (tty_type) {
case TTY_FILE:
fprintf (st, "TYPE=FILE");
break;
case TTY_PORT:
fprintf (st, "TYPE=PORT");
break;
default:
fprintf (st, "TYPE=(invalid)");
break;
}
return SCPE_OK;
}
void rom_tty (void)
{
rom_data (tty_rom);
}
void rom_stty (void)
{
rom_data (stty_rom);
}
static t_stat tty_boot (int32 u, DEVICE *dptr)
{
uint16 *PC = (uint16 *)sim_PC->loc;
if (sim_switches & SWMASK ('T'))
set_cmd (0, "ROM TYPE=TTY");
else if (sim_switches & SWMASK ('S'))
set_cmd (0, "ROM TYPE=STTY");
else
return sim_messagef (SCPE_ARG, "Must specify one of -S or -T\n");
*PC = 040;
return SCPE_OK;
}
static t_stat
tty_attach (UNIT *uptr, CONST char *cptr)
{
t_stat r;
switch (tty_type) {
case TTY_PORT:
r = tmxr_attach (&tty_desc, uptr, cptr);
if (r != SCPE_OK)
return r;
sim_activate_abs (uptr, 0);
break;
case TTY_FILE:
r = attach_unit (uptr, cptr);
if (r != SCPE_OK)
return r;
break;
default:
return SCPE_ARG;
}
return SCPE_OK;
}
static t_stat
tty_detach (UNIT *uptr)
{
if (!(uptr->flags & UNIT_ATT))
return SCPE_OK;
if (sim_is_active (uptr))
sim_cancel (uptr);
return detach_unit (uptr);
}