Can now boot the last test programs from floppy, and runs INSTRUCTION-C and PAGING-C without errors.
294 lines
8.1 KiB
C
294 lines
8.1 KiB
C
/*
|
|
* Copyright (c) 2023 Anders Magnusson.
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include "sim_defs.h"
|
|
#include "sim_tmxr.h"
|
|
|
|
#include "nd100_defs.h"
|
|
|
|
struct intr tti_int = { 0, 1 };
|
|
struct intr tto_int = { 0, 1 };
|
|
|
|
MTAB ttx_mod[];
|
|
|
|
int tti_status, tti_ctrl;
|
|
int tto_status, tto_ctrl;
|
|
|
|
t_stat tti_svc(UNIT *uptr);
|
|
t_stat tto_svc(UNIT *uptr);
|
|
t_stat tti_reset(DEVICE *dptr);
|
|
t_stat tto_reset(DEVICE *dptr);
|
|
t_stat tty_setpar(UNIT *uptr);
|
|
|
|
#define TT_ICTRL_EIRDY 0000001 /* enable int on dev ready */
|
|
#define TT_ICTRL_EIERR 0000002 /* enable int on error */
|
|
#define TT_ICTRL_ACT 0000004 /* set device active */
|
|
|
|
#define TT_ISTAT_IRDY 0000001 /* device ready gives interrupt */
|
|
#define TT_ISTAT_RDY 0000010 /* device ready for transfer */
|
|
|
|
#define TT_OCTRL_EIRDY 0000001 /* enable int on dev ready */
|
|
#define TT_OCTRL_EIERR 0000002 /* enable int on error */
|
|
#define TT_OCTRL_ACT 0000004 /* set device active */
|
|
|
|
#define TT_OSTAT_IRDY 0000001 /* device ready gives interrupt */
|
|
#define TT_OSTAT_EINT 0000002 /* error interrupt enabled */
|
|
#define TT_OSTAT_ACT 0000004 /* device active */
|
|
#define TT_OSTAT_RDY 0000010 /* device ready for transfer */
|
|
|
|
UNIT tti_unit = { UDATA (&tti_svc, 0, 0), KBD_POLL_WAIT };
|
|
|
|
REG tti_reg[] = {
|
|
{ ORDATA(BUF, tti_unit.buf, 8) },
|
|
{ ORDATA(ISTATUS, tti_status, 16) },
|
|
{ ORDATA(ICTRL, tti_ctrl, 16) },
|
|
{ DRDATA (TIME, tti_unit.wait, 24), },
|
|
{ NULL }
|
|
};
|
|
|
|
DEVICE tti_dev = {
|
|
"TTI", &tti_unit, tti_reg, ttx_mod,
|
|
1, 10, 31, 1, 8, 8,
|
|
NULL, NULL, &tti_reset,
|
|
NULL, NULL, NULL,
|
|
NULL, 0
|
|
};
|
|
|
|
UNIT tto_unit = { UDATA (&tto_svc, 0, 0), SERIAL_OUT_WAIT };
|
|
|
|
REG tto_reg[] = {
|
|
{ ORDATA(OSTATUS, tto_status, 16) },
|
|
{ ORDATA(OCTRL, tto_ctrl, 16) },
|
|
{ DRDATA(POS, tto_unit.pos, T_ADDR_W), PV_LEFT },
|
|
{ DRDATA(TIME, tto_unit.wait, 24), REG_NZ + PV_LEFT },
|
|
{ NULL }
|
|
};
|
|
|
|
MTAB ttx_mod[] = {
|
|
#if 0
|
|
{ TT_PAR, TT_PAR_EVEN, "even parity", "EVEN", &tty_setpar },
|
|
{ TT_PAR, TT_PAR_ODD, "odd parity", "ODD", &tty_setpar },
|
|
{ TT_PAR, TT_PAR_MARK, "mark parity", "MARK", &tty_setpar },
|
|
{ TT_PAR, TT_PAR_SPACE, "no parity", "NONE", &tty_setpar },
|
|
#endif
|
|
{ 0 }
|
|
};
|
|
|
|
DEVICE tto_dev = {
|
|
"TTO", &tto_unit, tto_reg, ttx_mod,
|
|
1, 10, 31, 1, 8, 8,
|
|
NULL, NULL, &tto_reset,
|
|
NULL, NULL, NULL,
|
|
NULL, 0
|
|
};
|
|
|
|
t_stat
|
|
tti_reset(DEVICE *dptr)
|
|
{
|
|
sim_cancel(&tti_unit);
|
|
return SCPE_OK;
|
|
}
|
|
|
|
t_stat
|
|
tto_reset(DEVICE *dptr)
|
|
{
|
|
sim_cancel(&tto_unit);
|
|
tto_status |= TT_OSTAT_RDY;
|
|
return SCPE_OK;
|
|
}
|
|
|
|
t_stat
|
|
tti_svc(UNIT *uptr)
|
|
{
|
|
int temp;
|
|
|
|
sim_activate (&tti_unit, tti_unit.wait);
|
|
if ((temp = sim_poll_kbd()) < SCPE_KFLAG)
|
|
return temp;
|
|
|
|
tti_unit.buf = temp & 0177;
|
|
if (tti_ctrl & TT_ICTRL_ACT) {
|
|
tti_status |= TT_ISTAT_RDY;
|
|
if (tti_ctrl & TT_ICTRL_EIRDY)
|
|
extint(12, &tti_int);
|
|
}
|
|
|
|
return SCPE_OK;
|
|
}
|
|
|
|
t_stat
|
|
tto_svc(UNIT *uptr)
|
|
{
|
|
int32 c;
|
|
t_stat r;
|
|
|
|
c = tto_unit.buf & 0177;
|
|
if ((r = sim_putchar_s (c)) != SCPE_OK) { /* output; error? */
|
|
sim_activate (uptr, uptr->wait); /* try again */
|
|
return ((r == SCPE_STALL)? SCPE_OK : r);/* !stall? report */
|
|
}
|
|
tto_status &= ~TT_OSTAT_ACT;
|
|
tto_status |= TT_OSTAT_RDY;
|
|
if (tto_ctrl & TT_OCTRL_EIRDY)
|
|
extint(10, &tto_int);
|
|
return SCPE_OK;
|
|
}
|
|
|
|
|
|
int
|
|
iox_tty(int addr)
|
|
{
|
|
int rv = 0;
|
|
|
|
/*
|
|
* First four addresses are input, following four are output.
|
|
*/
|
|
switch (addr & 07) {
|
|
case 0: /* read data */
|
|
regA = tti_unit.buf;
|
|
tti_status &= ~TT_ISTAT_RDY;
|
|
break;
|
|
|
|
case 1: /* Ignored */
|
|
break;
|
|
|
|
case 2: /* read input status reg */
|
|
regA = tti_status;
|
|
break;
|
|
|
|
case 3: /* Write control reg */
|
|
if ((tti_ctrl & TT_ICTRL_ACT) == 0 && (regA & TT_ICTRL_ACT))
|
|
sim_activate (&tti_unit, tti_unit.wait);
|
|
if ((regA & TT_ICTRL_ACT) == 0)
|
|
sim_cancel(&tti_unit);
|
|
tti_ctrl = regA;
|
|
if (tti_ctrl & TT_ICTRL_EIRDY)
|
|
tti_status |= TT_ISTAT_IRDY;
|
|
else
|
|
tti_status &= ~TT_ISTAT_IRDY;
|
|
break;
|
|
|
|
case 4: /* Ignored */
|
|
break;
|
|
|
|
case 5: /* Write data */
|
|
tto_unit.buf = regA & 0177;
|
|
tto_status &= ~TT_OSTAT_RDY;
|
|
tto_status |= TT_OSTAT_ACT;
|
|
sim_activate (&tto_unit, tto_unit.wait);
|
|
break;
|
|
|
|
case 6: /* Read output status */
|
|
regA = tto_status;
|
|
break;
|
|
|
|
case 7: /* Write output control reg */
|
|
/* Only interrupts are controlled */
|
|
tto_status = (tto_status & ~03) | (regA & 03);
|
|
break;
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
/*
|
|
* Real-time clock.
|
|
*/
|
|
#define CLK_PER_SEC 50
|
|
|
|
int int_enabled, dev_ready;
|
|
|
|
struct intr rtc_int = { 0, 1 };
|
|
|
|
t_stat clk_reset(DEVICE *dptr);
|
|
|
|
t_stat clk_svc(UNIT *uptr);
|
|
|
|
UNIT clk_unit = { UDATA (&clk_svc, 0, 0) };
|
|
|
|
REG clk_reg[] = {
|
|
{ FLDATA (INTENB, int_enabled, 0) },
|
|
{ FLDATA (DEVRDY, dev_ready, 0) },
|
|
{ NULL }
|
|
};
|
|
|
|
MTAB clk_mod[] = {
|
|
{ 0 }
|
|
};
|
|
|
|
DEVICE clk_dev = {
|
|
"RTC", &clk_unit, clk_reg, clk_mod,
|
|
1, 0, 0, 0, 0, 0,
|
|
NULL, NULL, &clk_reset,
|
|
NULL, NULL, NULL,
|
|
0, 0
|
|
};
|
|
|
|
int
|
|
iox_clk(int addr)
|
|
{
|
|
int rv = 0;
|
|
|
|
switch (addr & 3) {
|
|
case 0: /* return 0 in A */
|
|
regA = 0;
|
|
break;
|
|
case 1: /* Reset counter */
|
|
sim_activate_after_abs(&clk_unit, 1000000/CLK_PER_SEC);
|
|
break;
|
|
case 2: /* read status */
|
|
regA = (dev_ready << 3) | int_enabled;
|
|
break;
|
|
|
|
case 3: /* set status */
|
|
sim_activate_after_abs(&clk_unit, 1000000/CLK_PER_SEC);
|
|
int_enabled = regA & 1;
|
|
if (BIT13(regA))
|
|
dev_ready = 0;
|
|
break;
|
|
|
|
default:
|
|
rv = STOP_UNHIOX;
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
t_stat
|
|
clk_reset (DEVICE *dptr)
|
|
{
|
|
sim_rtc_init(1000000/CLK_PER_SEC);
|
|
return SCPE_OK;
|
|
}
|
|
|
|
t_stat
|
|
clk_svc(UNIT *uptr)
|
|
{
|
|
sim_rtc_calb(CLK_PER_SEC);
|
|
sim_activate_after(&clk_unit, 1000000/CLK_PER_SEC);
|
|
dev_ready = 1;
|
|
if (int_enabled)
|
|
extint(13, &rtc_int);
|
|
return SCPE_OK;
|
|
}
|