763 lines
26 KiB
C
763 lines
26 KiB
C
/* kx10_pipanel.c: PDP-10 PiDP10 front panel.
|
|
|
|
Copyright (c) 2022, Richard Cornwell
|
|
Based on code by Oscar Vermeulen
|
|
|
|
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
|
|
RICHARD CORNWELL 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 Richard Cornwell shall not be
|
|
used in advertising or otherwise to promote the sale, use or other dealings
|
|
in this Software without prior written authorization from Richard Cornwell
|
|
|
|
*/
|
|
|
|
#if PIDP10
|
|
|
|
/* The following includes are ok since this code can only be run on a
|
|
* Rasberry PI under Linux.
|
|
*
|
|
* To Build this:
|
|
* make PIDP10=1 pdp10-ka
|
|
*/
|
|
#include <pthread.h> /* Needed for pthread */
|
|
#include <unistd.h> /* Needed for sleep/geteuid */
|
|
#include <sys/types.h>
|
|
#include <editline/readline.h>
|
|
#include "pinctrl/gpiolib.h"
|
|
#include "kx10_defs.h"
|
|
|
|
extern uint64 SW; /* Switch register */
|
|
extern t_addr AS; /* Address switches */
|
|
extern uint64 MB; /* Memory Bus register */
|
|
extern uint64 MI; /* Memory indicator register */
|
|
extern uint8 MI_flag; /* Memory indicator mode */
|
|
extern uint32 FLAGS; /* Flags register */
|
|
extern uint8 RUN; /* Run flag */
|
|
extern uint32 IR; /* Instruction register */
|
|
extern uint32 AC; /* Accumulator */
|
|
extern uint8 IX; /* Index register */
|
|
extern uint8 IND; /* Indirect flag */
|
|
extern t_addr AB; /* Memory address register */
|
|
extern t_addr PC; /* Program counter register */
|
|
#if KA | KI
|
|
extern int nxm_stop; /* Stop if non-existent memory access */
|
|
extern int adr_cond; /* Address stop condition */
|
|
#endif
|
|
extern uint8 IOB_PI; /* Pending Interrupt requests */
|
|
extern uint8 PIR; /* Current Interrupt requests */
|
|
extern uint8 PIH; /* Currently held interrupts */
|
|
extern uint8 PIE; /* Currently enabled interrupts */
|
|
extern int pi_enable; /* Interrupt system enabled */
|
|
extern uint8 prog_stop; /* Program stop */
|
|
extern uint8 examine_sw; /* Examine memory */
|
|
extern uint8 deposit_sw; /* Deposit memory */
|
|
extern uint8 sing_inst_sw;/* Execute single instruction */
|
|
extern uint8 xct_sw; /* Execute an instruction */
|
|
extern uint8 stop_sw; /* Stop the simulator */
|
|
extern uint8 MI_disable; /* Disable MI display */
|
|
extern int watch_stop; /* Memory Stop */
|
|
extern uint32 rdrin_dev; /* Read in device. */
|
|
extern uint8 MI_disable; /* Disable MI */
|
|
int repeat_sw; /* Repeat switch state */
|
|
int par_stop; /* Parity stop */
|
|
int pwr_off; /* Power off system */
|
|
int rep_rate; /* Rate of repeat function */
|
|
int rep_count; /* Count down to repeat trigger */
|
|
|
|
/* led row 0 */
|
|
#define MB_MASK0 RMASK /* 18-35 */
|
|
#define MB_V_0 0 /* right */
|
|
|
|
/* led row 1 */
|
|
#define MB_MASK1 LMASK /* 0-17 */
|
|
#define MB_V_1 18 /* right */
|
|
|
|
/* led row 2 */
|
|
#define AB_MASK2 RMASK /* 18-35 */
|
|
#define AB_V_2 0 /* right */
|
|
|
|
/* led row 3 */
|
|
#define IX_MASK3 017
|
|
#define IX_V_3 0 /* left */
|
|
#define IND_LAMP 020
|
|
#define AC_MASK3 017
|
|
#define AC_V_3 5 /* left */
|
|
#define IR_MASK3 0777 /* 0-9 */
|
|
#define IR_V_3 9 /* left */
|
|
|
|
/* led row 4 */
|
|
#define PC_MASK4 RMASK /* 18-35 */
|
|
#define PC_V_4 0 /* right */
|
|
|
|
/* led row 5 */
|
|
#define PI_IOB_MASK5 0177
|
|
#define PI_IOB_V_5 7 /* left */
|
|
#define PI_ENB_MASK5 0177
|
|
#define PI_ENB_V_5 0 /* left */
|
|
#define PROG_STOP_LAMP 0040000
|
|
#define USER_LAMP 0100000
|
|
#define MEM_STOP_LAMP 0200000
|
|
#define PWR_LAMP 0400000
|
|
|
|
/* led row 6 */
|
|
#define PI_REQ_MASK6 0177
|
|
#define PI_REQ_V_6 0 /* left */
|
|
#define PI_PRO_MASK6 0177
|
|
#define PI_PRO_V_6 7 /* left */
|
|
#define RUN_LAMP 0040000
|
|
#define PION_LAMP 0100000
|
|
#define PI_LAMP 0200000
|
|
#define MI_LAMP 0400000
|
|
|
|
/* switch row 0 */
|
|
#define SR_MASK0 RMASK
|
|
#define SR_V_0 0 /* Left */
|
|
|
|
/* switch row 1 */
|
|
#define SR_MASK1 LMASK
|
|
#define SR_V_1 18 /* Left */
|
|
|
|
/* Switch row 2 */
|
|
#define MA_SW_MASK3 RMASK
|
|
#define MA_SW_V_3 0 /* Left */
|
|
|
|
/* Switch row 3 */
|
|
#define EXAM_NEXT 000001 /* SW=0 */
|
|
#define EXAM_THIS 000002 /* SW=1 */
|
|
#define XCT_SW 000004 /* SW=2 Set xct_inst */
|
|
#define RESET_SW 000010 /* SW=3 Call reset */
|
|
#define STOP_SW 000020 /* SW=4 Set RUN = 0 */
|
|
#define CONT_SW 000040 /* SW=5 call sim_instr */
|
|
#define START_SW 000100 /* SW=6 Call reset then sim_instr */
|
|
#define READ_SW 000200 /* SW=7 Boot function */
|
|
#define DEP_NEXT 000400 /* SW=8 */
|
|
#define DEP_THIS 001000 /* SW=9 */
|
|
|
|
/* Switch row 4 */
|
|
#define ADR_BRK_SW 000001 /* Address Break */
|
|
#define ADR_STOP_SW 000002 /* Address stop */
|
|
#define WRITE_SW 000004 /* Write stop */
|
|
#define DATA_FETCH 000010 /* Data fetch stop */
|
|
#define INST_FETCH 000020 /* Instruct fetch stop */
|
|
#define REP_SW 000040 /* Repeat switch */
|
|
#define NXM_STOP 000100 /* set nxm_stop */
|
|
#define PAR_STOP 000200 /* Nop */
|
|
#define SING_CYCL 000400 /* Nop */
|
|
#define SING_INST 001000 /* set sing_inst */
|
|
|
|
int xrows[3] = { 4, 17, 27 };
|
|
int xIO = 22; /* GPIO 22: */
|
|
int cols[18] = { 21,20,16,12,7,8,25,24,23,18,10,9,11,5,6,13,19,26 };
|
|
|
|
long intervl = 50000;
|
|
|
|
struct {
|
|
int last_state; /* last state */
|
|
int state; /* Stable state */
|
|
int debounce; /* Debounce timer */
|
|
int changed; /* Switch changed state */
|
|
} switch_state[16];
|
|
|
|
|
|
|
|
void *blink(void *ptr); /* the real-time GPIO multiplexing process to start up */
|
|
pthread_t blink_thread;
|
|
int blink_thread_terminate = 0;
|
|
|
|
t_stat gpio_mux_thread_start()
|
|
{
|
|
int res;
|
|
res = pthread_create(&blink_thread, NULL, blink, &blink_thread_terminate);
|
|
if (res) {
|
|
return sim_messagef(SCPE_IERR,
|
|
"Error creating gpio_mux thread, return code %d\n", res);
|
|
}
|
|
sim_messagef(SCPE_OK, "Created blink_thread\n");
|
|
sleep(2); /* allow 2 sec for multiplex to start */
|
|
return SCPE_OK;
|
|
}
|
|
|
|
|
|
/*
|
|
* Debounce a momentary switch.
|
|
*/
|
|
static void debounce_sw(int state, int sw)
|
|
{
|
|
if (switch_state[sw].state == state) {
|
|
if (switch_state[sw].debounce != 0) {
|
|
switch_state[sw].debounce--;
|
|
} else {
|
|
if (switch_state[sw].last_state != switch_state[sw].state) {
|
|
switch_state[sw].changed = 1;
|
|
}
|
|
switch_state[sw].last_state = switch_state[sw].state;
|
|
}
|
|
} else {
|
|
switch_state[sw].debounce = 8;
|
|
switch_state[sw].changed = 0;
|
|
switch_state[sw].state = state;
|
|
}
|
|
}
|
|
|
|
static t_addr
|
|
read_sw()
|
|
{
|
|
int col, row, i;
|
|
t_uint64 sw;
|
|
t_addr new_as;
|
|
struct timespec spec;
|
|
|
|
gpio_set_drive(xIO, DRIVE_HIGH);
|
|
for (i = 0; i < 18; i++) {
|
|
gpio_set_dir(cols[i], DIR_INPUT);
|
|
}
|
|
|
|
spec.tv_sec = 0;
|
|
new_as = 0;
|
|
for (row=0; row<5; row++) {
|
|
/* Select row address */
|
|
for (i = 0; i < 3; i++) {
|
|
if ((row & (1 << i)) == 0) {
|
|
gpio_set_drive(xrows[i], DRIVE_LOW);
|
|
} else {
|
|
gpio_set_drive(xrows[i], DRIVE_HIGH);
|
|
}
|
|
}
|
|
spec.tv_nsec = intervl/10;
|
|
nanosleep(&spec, NULL);
|
|
sw = 0;
|
|
for (i = 0; i < 18; i++) {
|
|
if (gpio_get_level(cols[i])) {
|
|
sw |= 1 << i;
|
|
}
|
|
}
|
|
/* Map row to values */
|
|
switch (row) {
|
|
default:
|
|
case 0:
|
|
SW = (SW & SR_MASK1) | ((~sw << SR_V_0) & SR_MASK0);
|
|
break;
|
|
|
|
case 1:
|
|
SW = (SW & SR_MASK0) | ((~sw << SR_V_1) & SR_MASK1);
|
|
break;
|
|
|
|
case 2:
|
|
new_as = (t_addr)(~sw << MA_SW_V_3) & MA_SW_MASK3;
|
|
break;
|
|
|
|
case 3: /* Momentary switches */
|
|
for (col = 0; col < 10; col++) {
|
|
int state = (sw & (1 << col)) == 0;
|
|
debounce_sw(state, col);
|
|
}
|
|
break;
|
|
|
|
case 4:
|
|
#if KA | KI
|
|
adr_cond = 0;
|
|
adr_cond |= ((sw & INST_FETCH) == 0) ? ADR_IFETCH : 0;
|
|
adr_cond |= ((sw & DATA_FETCH) == 0) ? ADR_DFETCH : 0;
|
|
adr_cond |= ((sw & WRITE_SW) == 0) ? ADR_WRITE : 0;
|
|
adr_cond |= ((sw & ADR_STOP_SW) == 0) ? ADR_STOP : 0;
|
|
adr_cond |= ((sw & ADR_BRK_SW) == 0) ? ADR_BREAK : 0;
|
|
nxm_stop = (sw & NXM_STOP) == 0;
|
|
#endif
|
|
sing_inst_sw = ((sw & SING_INST) == 0) ||
|
|
((sw & SING_CYCL) == 0);
|
|
/* PAR_STOP handle special features */
|
|
par_stop = (sw & PAR_STOP) == 0;
|
|
/* SING_CYCL no function yet */
|
|
repeat_sw = (sw & REP_SW) == 0;
|
|
break;
|
|
}
|
|
}
|
|
return new_as;
|
|
}
|
|
|
|
void *blink(void *ptr)
|
|
{
|
|
int *terminate = (int *)ptr;
|
|
int col, row, i;
|
|
int num_gpios, ret;
|
|
uint32 leds;
|
|
t_addr new_as;
|
|
struct timespec spec;
|
|
struct sched_param sp;
|
|
|
|
spec.tv_sec = 0;
|
|
sp.sched_priority = 98; // maybe 99, 32, 31?
|
|
if (pthread_setschedparam(pthread_self(), SCHED_FIFO, &sp))
|
|
fprintf(stderr, "warning: failed to set RT priority\n");
|
|
|
|
ret = gpiolib_init();
|
|
if (ret < 0) {
|
|
sim_messagef(SCPE_IERR, "Unable to initialize gpiolib- %d\n", ret);
|
|
return (void *)-1;
|
|
}
|
|
|
|
num_gpios = ret;
|
|
|
|
if (num_gpios == 0) {
|
|
sim_messagef(SCPE_IERR, "No GPIO chips found\n");
|
|
return (void *)-1;
|
|
}
|
|
|
|
ret = gpiolib_mmap();
|
|
if (ret) {
|
|
if (ret == EACCES && geteuid()) {
|
|
sim_messagef(SCPE_IERR, "Must be root\n");
|
|
} else {
|
|
sim_perror("Failed to mmap gpiolib");
|
|
}
|
|
return (void *)-1;
|
|
}
|
|
|
|
/* Initialize GPIO pins */
|
|
gpio_set_fsel(xIO, GPIO_FSEL_OUTPUT);
|
|
gpio_set_dir(xIO, DIR_OUTPUT);
|
|
gpio_set_drive(xIO, DRIVE_HIGH);
|
|
|
|
/* Row address pins */
|
|
for (row = 0; row < 3; row++) {
|
|
gpio_set_fsel(xrows[row], GPIO_FSEL_OUTPUT);
|
|
gpio_set_dir(xrows[row], DIR_OUTPUT);
|
|
gpio_set_drive(xrows[row], DRIVE_HIGH);
|
|
}
|
|
|
|
/* Columns */
|
|
for (col = 0; col < 10; col++) {
|
|
gpio_set_fsel(cols[col], GPIO_FSEL_INPUT);
|
|
gpio_set_pull(cols[col], PULL_UP);
|
|
}
|
|
|
|
/* Read initial value of switches */
|
|
new_as = read_sw();
|
|
sim_messagef(SCPE_OK, "PiDP-10 FP on\n");
|
|
|
|
|
|
/* start the actual multiplexing */
|
|
|
|
while (*terminate == 0)
|
|
{
|
|
/* Set to point to switchs while updating digits */
|
|
gpio_set_drive(xIO, DRIVE_HIGH);
|
|
/* Set direction of columns to output */
|
|
for (i = 0; i < 18; i++) {
|
|
gpio_set_dir(cols[i], DIR_OUTPUT);
|
|
}
|
|
|
|
/* Display each row */
|
|
for (row=0; row<7; row++) { /* 7 rows of LEDS get lit */
|
|
switch (row) {
|
|
default:
|
|
case 0:
|
|
leds = (((MI_flag)? MI : MB) & MB_MASK0) >> MB_V_0;
|
|
break;
|
|
case 1:
|
|
leds = (((MI_flag)? MI : MB) & MB_MASK1) >> MB_V_1;
|
|
break;
|
|
case 2:
|
|
if (par_stop) {
|
|
leds = rdrin_dev & 0777;
|
|
leds |= rep_rate << 12;
|
|
leds |= MI_disable << 10;
|
|
} else {
|
|
leds = (AB & AB_MASK2) >> AB_V_2;
|
|
}
|
|
break;
|
|
|
|
case 3:
|
|
leds = (IR & IR_MASK3) << IR_V_3;
|
|
leds |= (AC & AC_MASK3) << AC_V_3;
|
|
leds |= (IND) ? IND_LAMP : 0;
|
|
leds |= (IX & IX_MASK3) << IX_V_3;
|
|
break;
|
|
|
|
case 4:
|
|
leds = (PC & PC_MASK4) >> PC_V_4;
|
|
break;
|
|
|
|
case 5:
|
|
leds = PWR_LAMP;
|
|
leds |= (IOB_PI & PI_IOB_MASK5) << PI_IOB_V_5;
|
|
leds |= (PIE & PI_ENB_MASK5) << PI_ENB_V_5;
|
|
leds |= (FLAGS & USER) ? USER_LAMP : 0;
|
|
leds |= (prog_stop) ? PROG_STOP_LAMP: 0;
|
|
leds |= (watch_stop) ? MEM_STOP_LAMP: 0;
|
|
break;
|
|
|
|
case 6:
|
|
leds = (RUN) ? RUN_LAMP : 0;
|
|
leds |= (pi_enable) ? PION_LAMP : 0;
|
|
leds |= (PIR & PI_REQ_MASK6) << PI_REQ_V_6;
|
|
leds |= (PIH & PI_PRO_MASK6) << PI_PRO_V_6;
|
|
leds |= (MI_flag) ? PI_LAMP : MI_LAMP;
|
|
break;
|
|
}
|
|
|
|
/* Select correct row to display */
|
|
for (i = 0; i < 3; i++) {
|
|
if ((row & (1 << i)) == 0) {
|
|
gpio_set_drive(xrows[i], DRIVE_LOW);
|
|
} else {
|
|
gpio_set_drive(xrows[i], DRIVE_HIGH);
|
|
}
|
|
}
|
|
|
|
/* Update the leds for output */
|
|
for (i = 0; i < 18; i++) {
|
|
if ((leds & (1 << i)) == 0) {
|
|
gpio_set_drive(cols[i], DRIVE_HIGH);
|
|
} else {
|
|
gpio_set_drive(cols[i], DRIVE_LOW);
|
|
}
|
|
}
|
|
|
|
/* Select output */
|
|
gpio_set_drive(xIO, DRIVE_LOW);
|
|
spec.tv_nsec = intervl;
|
|
nanosleep(&spec, NULL);
|
|
/* Deselect output */
|
|
gpio_set_drive(xIO, DRIVE_HIGH);
|
|
spec.tv_nsec = intervl/10;
|
|
nanosleep(&spec, NULL);
|
|
}
|
|
|
|
/* Read in switches */
|
|
new_as = read_sw();
|
|
|
|
/* If running, check for switch changes */
|
|
if (par_stop) {
|
|
/* Process all momentary switches */
|
|
for (col = 0; col < 10; col++) {
|
|
if (switch_state[col].changed && switch_state[col].state) {
|
|
switch_state[col].changed = 0;
|
|
switch (col) {
|
|
case 1: /* Examine this */
|
|
rep_rate = (new_as >> 14) & 0xf;
|
|
break;
|
|
|
|
case 4: /* Stop function */
|
|
stop_sw = 1;
|
|
pwr_off = 1;
|
|
break;
|
|
|
|
case 5: /* Continue */
|
|
MI_disable = !MI_disable;
|
|
if (MI_disable)
|
|
MI_flag = 0;
|
|
break;
|
|
|
|
#if KA | KI
|
|
case 7: /* ReadIN */
|
|
rdrin_dev = 0774 & new_as;
|
|
break;
|
|
#endif
|
|
|
|
case 0: /* Examine next */
|
|
case 2: /* Execute function */
|
|
case 3: /* Reset function */
|
|
case 6: /* Start */
|
|
case 8: /* Deposit next */
|
|
case 9: /* Deposit this */
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
AS = new_as;
|
|
}
|
|
|
|
/* Check repeat count */
|
|
if (rep_count > 0 && --rep_count == 0) {
|
|
for (col = 0; col < 10; col++) {
|
|
switch_state[col].changed = switch_state[col].state;
|
|
}
|
|
}
|
|
|
|
/* Process switch changes if running */
|
|
if (RUN) {
|
|
for (col = 0; col < 10; col++) {
|
|
if (switch_state[col].changed && switch_state[col].state) {
|
|
/* If repeat switch set, trigger timer */
|
|
if (repeat_sw) {
|
|
rep_count = (rep_rate + 1) * 16;
|
|
}
|
|
switch (col) {
|
|
case 1: /* Examine this */
|
|
examine_sw = 1;
|
|
MI_flag = 0;
|
|
switch_state[col].changed = 0;
|
|
break;
|
|
|
|
case 0: /* Examine next */
|
|
case 5: /* Continue */
|
|
case 6: /* Start */
|
|
case 7: /* ReadIN */
|
|
case 8: /* Deposit next */
|
|
default:
|
|
switch_state[col].changed = 0;
|
|
break;
|
|
|
|
case 2: /* Execute function */
|
|
xct_sw = 1;
|
|
switch_state[col].changed = 0;
|
|
break;
|
|
|
|
case 3: /* Reset function */
|
|
stop_sw = 1;
|
|
break;
|
|
|
|
case 4: /* Stop function */
|
|
stop_sw = 1;
|
|
switch_state[col].changed = 0;
|
|
break;
|
|
|
|
case 9: /* Deposit this */
|
|
deposit_sw = 1;
|
|
MI_flag = 0;
|
|
switch_state[col].changed = 0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* done with reading the switches,
|
|
* so start the next cycle of lighting up LEDs
|
|
*/
|
|
}
|
|
|
|
/* received terminate signal, close down */
|
|
gpio_set_drive(xIO, DRIVE_HIGH);
|
|
for (i = 0; i < 18; i++) {
|
|
gpio_set_dir(cols[i], DIR_INPUT);
|
|
}
|
|
|
|
for (row = 0; row < 3; row++) {
|
|
gpio_set_drive(xrows[row], DRIVE_HIGH);
|
|
}
|
|
|
|
}
|
|
|
|
volatile int input_wait;
|
|
static char *input_buffer = NULL;
|
|
|
|
/*
|
|
* Handler for EditLine package when line is complete.
|
|
*/
|
|
static void
|
|
read_line_handler(char *line)
|
|
{
|
|
if (line != NULL) {
|
|
input_buffer = line;
|
|
input_wait = 0;
|
|
add_history(line);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Process input from stdin or switches.
|
|
*/
|
|
static char *
|
|
vm_read(char *cptr, int32 sz, FILE *file)
|
|
{
|
|
struct timeval tv = {0,10000}; /* Wait for 10ms */
|
|
fd_set read_set;
|
|
int fd = fileno(file); /* What to wait on */
|
|
int col;
|
|
|
|
if (input_buffer != NULL)
|
|
free(input_buffer);
|
|
rl_callback_handler_install(sim_prompt, (rl_vcpfunc_t*) &read_line_handler);
|
|
input_wait = 1;
|
|
input_buffer = NULL;
|
|
while (input_wait) {
|
|
FD_ZERO(&read_set);
|
|
FD_SET(fd, &read_set);
|
|
tv.tv_sec = 0;
|
|
tv.tv_usec = 10000;
|
|
(void)select(fd+1, &read_set, NULL, NULL, &tv);
|
|
if (FD_ISSET(fd, &read_set)) {
|
|
rl_callback_read_char();
|
|
} else {
|
|
if (pwr_off) {
|
|
if ((input_buffer = (char *)malloc(20)) != 0) {
|
|
strcpy(input_buffer, "quit\r");
|
|
stop_sw = 1;
|
|
pwr_off = 0;
|
|
input_wait = 0;
|
|
}
|
|
break;
|
|
}
|
|
|
|
/* Process switches */
|
|
for (col = 0; col < 10; col++) {
|
|
if (switch_state[col].changed && switch_state[col].state) {
|
|
/* If repeat switch set, trigger timer */
|
|
if (repeat_sw) {
|
|
rep_count = (rep_rate + 1) * 16;
|
|
}
|
|
switch (col) {
|
|
case 0: /* Examine next */
|
|
AB++;
|
|
MB = (AB < 020) ? FM[AB] : M[AB];
|
|
MI_flag = 0;
|
|
break;
|
|
|
|
case 1: /* Examine this */
|
|
AB = AS;
|
|
MB = (AS < 020) ? FM[AS] : M[AS];
|
|
MI_flag = 0;
|
|
break;
|
|
|
|
case 2: /* Execute function */
|
|
if ((input_buffer = (char *)malloc(20)) != 0) {
|
|
strcpy(input_buffer, "step\r");
|
|
xct_sw = 1;
|
|
input_wait = 0;
|
|
}
|
|
break;
|
|
|
|
case 3: /* Reset function */
|
|
if ((input_buffer = (char *)malloc(20)) != 0) {
|
|
strcpy(input_buffer, "reset all\r");
|
|
input_wait = 0;
|
|
}
|
|
break;
|
|
|
|
case 4: /* Stop function */
|
|
break;
|
|
|
|
case 5: /* Continue */
|
|
if ((input_buffer = (char *)malloc(10)) != 0) {
|
|
strcpy(input_buffer,
|
|
(sing_inst_sw) ? "step\r" : "cont\r");
|
|
input_wait = 0;
|
|
}
|
|
break;
|
|
|
|
case 6: /* Start */
|
|
if ((input_buffer = (char *)malloc(20)) != 0) {
|
|
sprintf(input_buffer, "run %06o\r", AS);
|
|
input_wait = 0;
|
|
}
|
|
break;
|
|
|
|
#if KA | KI
|
|
case 7: /* ReadIN */
|
|
if ((input_buffer = (char *)malloc(20)) != 0) {
|
|
DEVICE *dptr;
|
|
int i;
|
|
|
|
/* Scan all devices to find match */
|
|
for (i = 0; (dptr = sim_devices[i]) != NULL; i++) {
|
|
DIB *dibp = (DIB *) dptr->ctxt;
|
|
if (dibp && !(dptr->flags & DEV_DIS) &&
|
|
(dibp->dev_num == (rdrin_dev & 0774))) {
|
|
if (dptr->numunits > 1)
|
|
sprintf(input_buffer, "boot %s0\r",
|
|
dptr->name);
|
|
else
|
|
sprintf(input_buffer, "boot %s\r",
|
|
dptr->name);
|
|
input_wait = 0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
/* If we did not find a boot device, free command */
|
|
if (input_wait) {
|
|
free(input_buffer);
|
|
input_buffer = NULL;
|
|
sim_messagef(SCPE_OK, "Device %03o not found\n",
|
|
rdrin_dev);
|
|
}
|
|
break;
|
|
#endif
|
|
|
|
case 8: /* Deposit next */
|
|
AB++;
|
|
if (AB < 020) {
|
|
FM[AB] = SW;
|
|
MB = FM[AB];
|
|
} else {
|
|
M[AB] = SW;
|
|
MB = M[AB];
|
|
}
|
|
MI_flag = 0;
|
|
break;
|
|
|
|
case 9: /* Deposit this */
|
|
AB = AS;
|
|
if (AS < 020) {
|
|
FM[AS] = SW;
|
|
MB = FM[AS];
|
|
} else {
|
|
M[AS] = SW;
|
|
MB = M[AS];
|
|
}
|
|
MI_flag = 0;
|
|
break;
|
|
}
|
|
switch_state[col].changed = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
rl_callback_handler_remove();
|
|
return input_buffer;
|
|
}
|
|
|
|
static void
|
|
vm_post(t_bool from_scp)
|
|
{
|
|
}
|
|
|
|
/*
|
|
* Start panel thread, and install console read functions.
|
|
*/
|
|
t_stat pi_panel_start(void)
|
|
{
|
|
int terminate = 1;
|
|
int i,j;
|
|
t_stat r;
|
|
|
|
/* start up multiplexing thread */
|
|
r = gpio_mux_thread_start();
|
|
sim_vm_read = &vm_read;
|
|
sim_vm_post = &vm_post;
|
|
return r;
|
|
}
|
|
|
|
/*
|
|
* Stop display thread.
|
|
*/
|
|
void pi_panel_stop(void)
|
|
{
|
|
if (blink_thread_terminate == 0) {
|
|
blink_thread_terminate=1;
|
|
sim_vm_read = NULL;
|
|
|
|
sleep (2); /* allow threads to close down */
|
|
}
|
|
}
|
|
|
|
#endif
|