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:
576
imlac/imlac_cpu.c
Normal file
576
imlac/imlac_cpu.c
Normal 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
136
imlac/imlac_crt.c
Normal 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
77
imlac/imlac_defs.h
Normal 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
485
imlac/imlac_dp.c
Normal 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
641
imlac/imlac_kbd.c
Normal 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
113
imlac/imlac_pt.c
Normal 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
533
imlac/imlac_sys.c
Normal 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
290
imlac/imlac_tty.c
Normal 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);
|
||||
}
|
||||
Reference in New Issue
Block a user