mirror of
https://github.com/simh/simh.git
synced 2026-01-25 19:56:25 +00:00
PDP11, PDP1, TX-0: Added SDL based graphics support using sim_video.
Both VT11 and VS60 properly autoconfigure on the PDP11. PDP11 now runs Lunar Lander on all SDL supported platforms. Reworked refresh logic to not require internal delays in the display library
This commit is contained in:
@@ -636,9 +636,8 @@ typedef struct pdp_dib DIB;
|
||||
#define INT_V_DCO 12
|
||||
/* VT simulation is sequential, so only
|
||||
one interrupt is posted at a time. */
|
||||
#define INT_V_VTLP 13 /* XXX - Manual says VTLP, VTST have opposite */
|
||||
#define INT_V_VTST 14 /* XXX precedence, but that breaks LUNAR! */
|
||||
/* XXX How this happens is an utter mystery. */
|
||||
#define INT_V_VTST 13
|
||||
#define INT_V_VTLP 14
|
||||
#define INT_V_VTCH 15
|
||||
#define INT_V_VTNM 16
|
||||
#define INT_V_LK 17
|
||||
@@ -784,6 +783,7 @@ typedef struct pdp_dib DIB;
|
||||
#define IREQ(dv) int_req[IPL_##dv]
|
||||
#define SET_INT(dv) int_req[IPL_##dv] = int_req[IPL_##dv] | (INT_##dv)
|
||||
#define CLR_INT(dv) int_req[IPL_##dv] = int_req[IPL_##dv] & ~(INT_##dv)
|
||||
#define INT_IS_SET(dv) (int_req[IPL_##dv] & (INT_##dv))
|
||||
|
||||
/* Massbus definitions */
|
||||
|
||||
|
||||
@@ -657,6 +657,8 @@ AUTO_CON auto_tab[] = {/*c #v am vm fxa fxv */
|
||||
{ { NULL }, 1, 2, 16, 8 }, /* DH11 */
|
||||
{ { "VT" }, 1, 4, 0, 8,
|
||||
{012000, 012010, 012020, 012030} }, /* VT11/GT40 - fx CSRs */
|
||||
{ { "VS60" }, 1, 4, 0, 8,
|
||||
{012000} }, /* VS60/GT48 - fx CSRs */
|
||||
{ { NULL }, 1, 2, 0, 8,
|
||||
{010400} }, /* LPS11 */
|
||||
{ { NULL }, 1, 2, 8, 8 }, /* DQ11 */
|
||||
|
||||
210
PDP11/pdp11_vt.c
210
PDP11/pdp11_vt.c
@@ -47,6 +47,7 @@
|
||||
|
||||
#include "display/display.h"
|
||||
#include "display/vt11.h"
|
||||
#include "sim_video.h"
|
||||
|
||||
/*
|
||||
* Timing parameters. Should allow some runtime adjustment,
|
||||
@@ -61,8 +62,9 @@
|
||||
/*
|
||||
* run a VT11/VS60 cycle every this many PDP-11 "cycle" times;
|
||||
*
|
||||
* Under the X Window System (X11), this includes polling
|
||||
* for events (mouse movement)!
|
||||
* this includes phosphor aging and polling for events (mouse movement)
|
||||
* every refresh_interval (determined internally while processing the
|
||||
* VT11/VS60 cycle).
|
||||
*/
|
||||
#define VT11_DELAY 1
|
||||
|
||||
@@ -109,43 +111,106 @@ const char *vt_description (DEVICE *dptr);
|
||||
#define IOLN_VT11 010 /* VT11 */
|
||||
#define IOLN_VS60 040 /* VS60 */
|
||||
DIB vt_dib = { IOBA_AUTO, IOLN_VT11, &vt_rd, &vt_wr,
|
||||
4, IVCL(VTST), VEC_AUTO, {NULL} };
|
||||
4, IVCL(VTST), VEC_AUTO, {NULL}, IOLN_VT11 };
|
||||
/* (VT11 uses only the first 3 interrupt vectors) */
|
||||
|
||||
UNIT vt_unit = {
|
||||
UDATA (&vt_svc, UNIT_SEQ, 0), VT11_DELAY};
|
||||
UDATA (&vt_svc, UNIT_SEQ, 0), VT11_DELAY};
|
||||
|
||||
REG vt_reg[] = {
|
||||
{ DRDATAD (CYCLE, vt_unit.wait, 24, "VT11/VS60 cycle"), REG_NZ + PV_LEFT },
|
||||
{ GRDATA (DEVADDR, vt_dib.ba, DEV_RDX, 32, 0), REG_HRO },
|
||||
{ GRDATA (DEVVEC, vt_dib.vec, DEV_RDX, 16, 0), REG_HRO },
|
||||
{ NULL } };
|
||||
|
||||
MTAB vt_mod[] = {
|
||||
{ MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "CRT", "CRT={VR14|VR17|VR48}",
|
||||
&vt_set_crt, &vt_show_crt, NULL, "CRT Type" },
|
||||
{ MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "SCALE", "SCALE={1|2|4|8}",
|
||||
&vt_set_scale, &vt_show_scale, NULL, "Pixel Scale Factor" },
|
||||
{ MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "HSPACE", "HSPACE={NARROW|NORMAL}",
|
||||
{ MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "CRT", "CRT={VR14|VR17|VR48}",
|
||||
&vt_set_crt, &vt_show_crt, NULL, "CRT Type" },
|
||||
{ MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "SCALE", "SCALE={1|2|4|8}",
|
||||
&vt_set_scale, &vt_show_scale, NULL, "Pixel Scale Factor" },
|
||||
{ MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "HSPACE", "HSPACE={NARROW|NORMAL}",
|
||||
&vt_set_hspace, &vt_show_hspace, NULL, "Horizontal Spacing" },
|
||||
{ MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "VSPACE", "VSPACE={TALL|NORMAL}",
|
||||
{ MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "VSPACE", "VSPACE={TALL|NORMAL}",
|
||||
&vt_set_vspace, &vt_show_vspace, NULL, "Vertical Spacing" },
|
||||
{ MTAB_XTD|MTAB_VDV|MTAB_VALR, 020, "ADDRESS", "ADDRESS",
|
||||
&set_addr, &show_addr, NULL, "Bus address" },
|
||||
{ MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "VECTOR", "VECTOR",
|
||||
&set_vec, &show_vec, NULL, "Interrupt vector" },
|
||||
{ MTAB_XTD|MTAB_VDV, 0, NULL, "AUTOCONFIGURE",
|
||||
&set_addr_flt, NULL, NULL, "Enable autoconfiguration of address & vector" },
|
||||
&set_addr, &show_addr, NULL, "Bus address" },
|
||||
{ MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "VECTOR", "VECTOR",
|
||||
&set_vec, &show_vec, NULL, "Interrupt vector" },
|
||||
{ MTAB_XTD|MTAB_VDV, 0, NULL, "AUTOCONFIGURE",
|
||||
&set_addr_flt, NULL, NULL, "Enable autoconfiguration of address & vector" },
|
||||
{ 0 } };
|
||||
|
||||
|
||||
static t_bool vt_stop_flag = FALSE;
|
||||
|
||||
static void vt_quit_callback (void)
|
||||
{
|
||||
vt_stop_flag = TRUE;
|
||||
}
|
||||
|
||||
/* Debug detail levels */
|
||||
|
||||
#define DEB_OPS 0001 /* transactions */
|
||||
#define DEB_RRD 0002 /* reg reads */
|
||||
#define DEB_RWR 0004 /* reg writes */
|
||||
#define DEB_TRC 0010 /* trace */
|
||||
#define DEB_STINT 0020 /* STOP interrupts */
|
||||
#define DEB_LPINT 0040 /* Light Pen interrupts */
|
||||
#define DEB_CHINT 0100 /* CHAR interrupts */
|
||||
#define DEB_NMINT 0200 /* NAME interrupts */
|
||||
#define DEB_INT 0360 /* All Interrupts */
|
||||
#define DEB_VT11 0400 /* VT11 activities */
|
||||
#define DEB_VMOU SIM_VID_DBG_MOUSE /* Video mouse */
|
||||
#define DEB_VKEY SIM_VID_DBG_KEY /* Video key */
|
||||
#define DEB_VCUR SIM_VID_DBG_CURSOR /* Video cursor */
|
||||
#define DEB_VVID SIM_VID_DBG_VIDEO /* Video */
|
||||
|
||||
DEBTAB vt_deb[] = {
|
||||
{ "OPS", DEB_OPS, "transactions" },
|
||||
{ "RRD", DEB_RRD, "register reads" },
|
||||
{ "RWR", DEB_RWR, "register writes" },
|
||||
{ "INT", DEB_INT, "All Interrupts" },
|
||||
{ "STOP", DEB_STINT, "STOP interrupts" },
|
||||
{ "LPEN", DEB_LPINT, "Light Pen interrupts" },
|
||||
{ "CHAR", DEB_CHINT, "CHAR interrupts" },
|
||||
{ "NAME", DEB_NMINT, "NAME interrupts" },
|
||||
{ "VT11", DEB_VT11, "VT11 activities" },
|
||||
{ "TRACE", DEB_TRC, "trace" },
|
||||
{ "VMOU", DEB_VMOU, "Video Mouse" },
|
||||
{ "VKEY", DEB_VKEY, "Video Key" },
|
||||
{ "VCUR", DEB_VCUR, "Video Cursor" },
|
||||
{ "VVID", DEB_VVID, "Video Video" },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
DEVICE vt_dev = {
|
||||
"VT", &vt_unit, vt_reg, vt_mod,
|
||||
1, 8, 31, 1, DEV_RDX, 16,
|
||||
NULL, NULL, &vt_reset,
|
||||
&vt_boot, NULL, NULL,
|
||||
&vt_dib, DEV_DIS | DEV_DISABLE | DEV_UBUS | DEV_Q18,
|
||||
0, 0, NULL, NULL, NULL, NULL, NULL,
|
||||
&vt_dib, DEV_DIS | DEV_DISABLE | DEV_UBUS | DEV_Q18 | DEV_DEBUG,
|
||||
0, vt_deb, NULL, NULL, NULL, NULL, NULL,
|
||||
&vt_description
|
||||
};
|
||||
|
||||
char *vt_regnam[] = {
|
||||
"DPC",
|
||||
"MPR",
|
||||
"XPR",
|
||||
"YPR",
|
||||
"RR",
|
||||
"SPR",
|
||||
"XOR",
|
||||
"YOR",
|
||||
"ANR",
|
||||
"SCR",
|
||||
"NR",
|
||||
"SDR",
|
||||
"STR",
|
||||
"SAR",
|
||||
"ZPR",
|
||||
"ZOR",
|
||||
};
|
||||
|
||||
/* VT11/VS60 routines
|
||||
|
||||
@@ -159,45 +224,67 @@ DEVICE vt_dev = {
|
||||
t_stat
|
||||
vt_rd(int32 *data, int32 PA, int32 access)
|
||||
{
|
||||
t_stat stat = SCPE_OK;
|
||||
|
||||
switch (PA & 036) {
|
||||
case 000: *data = vt11_get_dpc(); return SCPE_OK;
|
||||
case 002: *data = vt11_get_mpr(); return SCPE_OK;
|
||||
case 004: *data = vt11_get_xpr(); return SCPE_OK;
|
||||
case 006: *data = vt11_get_ypr(); return SCPE_OK;
|
||||
case 010: if (!VS60) break; *data = vt11_get_rr(); return SCPE_OK;
|
||||
case 012: if (!VS60) break; *data = vt11_get_spr(); return SCPE_OK;
|
||||
case 014: if (!VS60) break; *data = vt11_get_xor(); return SCPE_OK;
|
||||
case 016: if (!VS60) break; *data = vt11_get_yor(); return SCPE_OK;
|
||||
case 020: if (!VS60) break; *data = vt11_get_anr(); return SCPE_OK;
|
||||
case 022: if (!VS60) break; *data = vt11_get_scr(); return SCPE_OK;
|
||||
case 024: if (!VS60) break; *data = vt11_get_nr(); return SCPE_OK;
|
||||
case 026: if (!VS60) break; *data = vt11_get_sdr(); return SCPE_OK;
|
||||
case 030: if (!VS60) break; *data = vt11_get_str(); return SCPE_OK;
|
||||
case 032: if (!VS60) break; *data = vt11_get_sar(); return SCPE_OK;
|
||||
case 034: if (!VS60) break; *data = vt11_get_zpr(); return SCPE_OK;
|
||||
case 036: if (!VS60) break; *data = vt11_get_zor(); return SCPE_OK;
|
||||
case 000: *data = vt11_get_dpc(); break;
|
||||
case 002: *data = vt11_get_mpr(); break;
|
||||
case 004: *data = vt11_get_xpr(); break;
|
||||
case 006: *data = vt11_get_ypr(); break;
|
||||
case 010: if (VS60) *data = vt11_get_rr(); else stat = SCPE_NXM; break;
|
||||
case 012: if (VS60) *data = vt11_get_spr(); else stat = SCPE_NXM; break;
|
||||
case 014: if (VS60) *data = vt11_get_xor(); else stat = SCPE_NXM; break;
|
||||
case 016: if (VS60) *data = vt11_get_yor(); else stat = SCPE_NXM; break;
|
||||
case 020: if (VS60) *data = vt11_get_anr(); else stat = SCPE_NXM; break;
|
||||
case 022: if (VS60) *data = vt11_get_scr(); else stat = SCPE_NXM; break;
|
||||
case 024: if (VS60) *data = vt11_get_nr(); else stat = SCPE_NXM; break;
|
||||
case 026: if (VS60) *data = vt11_get_sdr(); else stat = SCPE_NXM; break;
|
||||
case 030: if (VS60) *data = vt11_get_str(); else stat = SCPE_NXM; break;
|
||||
case 032: if (VS60) *data = vt11_get_sar(); else stat = SCPE_NXM; break;
|
||||
case 034: if (VS60) *data = vt11_get_zpr(); else stat = SCPE_NXM; break;
|
||||
case 036: if (VS60) *data = vt11_get_zor(); else stat = SCPE_NXM; break;
|
||||
default: stat = SCPE_NXM;
|
||||
}
|
||||
return SCPE_NXM;
|
||||
sim_debug (DEB_RRD, &vt_dev, "vt_rd(%s-PA=0%o,data=0x%X(0%o),access=%d)\n", vt_regnam[(PA & 036)>>1], (int)PA, (int)*data, (int)*data, (int)access);
|
||||
return stat;
|
||||
}
|
||||
|
||||
t_stat
|
||||
vt_wr(int32 data, int32 PA, int32 access)
|
||||
{
|
||||
uint16 d = data & 0177777; /* mask just in case */
|
||||
|
||||
sim_debug (DEB_RWR, &vt_dev, "vt_wr(%s-PA=0%o,data=0x%X(0%o),access=%d)\n", vt_regnam[(PA & 036)>>1], (int)PA, (int)data, (int)data, (int)access);
|
||||
|
||||
switch (PA & 037) {
|
||||
case 000: /* DPC */
|
||||
/* set the simulator PC */
|
||||
vt11_set_dpc(d);
|
||||
|
||||
/* clear interrupt request (only one will be simulated at a time) */
|
||||
CLR_INT (VTST);
|
||||
CLR_INT (VTLP);
|
||||
CLR_INT (VTCH);
|
||||
CLR_INT (VTNM);
|
||||
/* Interrupt requests are cleared as each vector is dispatched,
|
||||
so in general, no need to clear interrupt requests here.
|
||||
However, if software is running at high IPL (diagnostics maybe)
|
||||
clearing them here does no harm */
|
||||
if (INT_IS_SET(VTST)) {
|
||||
sim_debug (DEB_STINT, &vt_dev, "CLR_INT(all)\n");
|
||||
CLR_INT (VTST);
|
||||
}
|
||||
if (INT_IS_SET(VTLP)) {
|
||||
sim_debug (DEB_LPINT, &vt_dev, "CLR_INT(all)\n");
|
||||
CLR_INT (VTLP);
|
||||
}
|
||||
if (INT_IS_SET(VTCH)) {
|
||||
sim_debug (DEB_CHINT, &vt_dev, "CLR_INT(all)\n");
|
||||
CLR_INT (VTCH);
|
||||
}
|
||||
if (INT_IS_SET(VTNM)) {
|
||||
sim_debug (DEB_NMINT, &vt_dev, "CLR_INT(all)\n");
|
||||
CLR_INT (VTNM);
|
||||
}
|
||||
|
||||
/* start the display processor by running a cycle */
|
||||
return vt_svc(&vt_unit);
|
||||
vt_svc (&vt_unit);
|
||||
return SCPE_OK;
|
||||
|
||||
case 002: vt11_set_mpr(d); return SCPE_OK;
|
||||
case 004: vt11_set_xpr(d); return SCPE_OK;
|
||||
@@ -221,15 +308,17 @@ vt_wr(int32 data, int32 PA, int32 access)
|
||||
/*
|
||||
* here to run a display processor cycle, called as a SIMH
|
||||
* "device service routine".
|
||||
*
|
||||
* Under X11 this includes polling for events, so it can't be
|
||||
* call TOO infrequently...
|
||||
*/
|
||||
t_stat
|
||||
vt_svc(UNIT *uptr)
|
||||
{
|
||||
if (vt11_cycle(CYCLE_US, 1))
|
||||
sim_activate (&vt_unit, vt_unit.wait); /* running; reschedule */
|
||||
sim_debug (DEB_TRC, &vt_dev, "vt_svc(wait=%d,DPC=0%o)\n", uptr->wait, vt11_get_dpc());
|
||||
if (vt11_cycle(uptr->wait, 0))
|
||||
sim_activate_after (uptr, uptr->wait); /* running; reschedule */
|
||||
if (vt_stop_flag) {
|
||||
vt_stop_flag = FALSE; /* reset flag after we notice it */
|
||||
return SCPE_STOP;
|
||||
}
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
@@ -237,12 +326,14 @@ t_stat
|
||||
vt_reset(DEVICE *dptr)
|
||||
{
|
||||
if (!(dptr->flags & DEV_DIS))
|
||||
vt11_reset();
|
||||
vt11_reset(dptr, DEB_VT11);
|
||||
vid_register_quit_callback (&vt_quit_callback);
|
||||
sim_debug (DEB_INT, &vt_dev, "CLR_INT(all)\n");
|
||||
CLR_INT (VTST);
|
||||
CLR_INT (VTLP);
|
||||
CLR_INT (VTCH);
|
||||
CLR_INT (VTNM);
|
||||
sim_cancel (&vt_unit); /* deactivate unit */
|
||||
sim_cancel (dptr->units); /* deactivate unit */
|
||||
return auto_config ("VT", (dptr->flags & DEV_DIS) ? 0 : 1);
|
||||
}
|
||||
|
||||
@@ -256,6 +347,7 @@ t_stat
|
||||
vt_boot(int32 unit, DEVICE *dptr)
|
||||
{
|
||||
t_stat r;
|
||||
char stability[32];
|
||||
extern int32 saved_PC;
|
||||
extern uint16 *M;
|
||||
|
||||
@@ -266,15 +358,23 @@ vt_boot(int32 unit, DEVICE *dptr)
|
||||
sim_set_memory_load_file (BOOT_CODE_ARRAY, BOOT_CODE_SIZE);
|
||||
r = load_cmd (0, BOOT_CODE_FILENAME);
|
||||
sim_set_memory_load_file (NULL, 0);
|
||||
/* Lunar Lander presumes a VT device vector of 320 */
|
||||
if (0320 != vt_dib.vec) { /* If that is not the case, then copy the 320 vector to */
|
||||
M[vt_dib.vec >> 1] = M[0320 >> 1];
|
||||
/* Lunar Lander presumes a VT device vector base of 320 */
|
||||
if (0320 != vt_dib.vec) { /* If that is not the case, then copy the 320 vectors to the right place */
|
||||
M[(vt_dib.vec >> 1) + 0] = M[(0320 >> 1) + 0];
|
||||
M[(vt_dib.vec >> 1) + 1] = M[(0320 >> 1) + 1];
|
||||
M[(vt_dib.vec >> 1) + 2] = M[(0324 >> 1) + 0];
|
||||
M[(vt_dib.vec >> 1) + 3] = M[(0324 >> 1) + 1];
|
||||
M[(vt_dib.vec >> 1) + 4] = M[(0330 >> 1) + 0];
|
||||
M[(vt_dib.vec >> 1) + 5] = M[(0330 >> 1) + 1];
|
||||
M[(vt_dib.vec >> 1) + 6] = M[(0334 >> 1) + 0];
|
||||
M[(vt_dib.vec >> 1) + 7] = M[(0334 >> 1) + 1];
|
||||
}
|
||||
M[032530>>1] = 1;
|
||||
cpu_set_boot (saved_PC);
|
||||
set_cmd (0, "VT SCALE=1");
|
||||
set_cmd (0, "VT CRT=VR14");
|
||||
sprintf (stability, "%d", SIM_IDLE_STMIN);
|
||||
sim_set_idle (NULL, 0, stability, NULL); /* force minimum calibration stability */
|
||||
sim_clr_idle (NULL, 0, stability, NULL);
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -284,6 +384,7 @@ t_stat
|
||||
vt_set_crt(UNIT *uptr, int32 val, char *cptr, void *desc)
|
||||
{
|
||||
char gbuf[CBUFSIZE];
|
||||
|
||||
if (vt11_init)
|
||||
return SCPE_ALATT; /* should be "changes locked out" */
|
||||
if (cptr == NULL)
|
||||
@@ -298,6 +399,9 @@ vt_set_crt(UNIT *uptr, int32 val, char *cptr, void *desc)
|
||||
else
|
||||
return SCPE_ARG;
|
||||
vt_dib.lnt = (VS60) ? IOLN_VS60 : IOLN_VT11;
|
||||
deassign_device (&vt_dev);
|
||||
if (VS60)
|
||||
assign_device (&vt_dev, "VS60");
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
@@ -388,24 +492,28 @@ vt_show_vspace(FILE *st, UNIT *uptr, int32 val, void *desc)
|
||||
void
|
||||
vt_stop_intr(void)
|
||||
{
|
||||
sim_debug (DEB_STINT, &vt_dev, "SET_INT (VTST)\n");
|
||||
SET_INT (VTST);
|
||||
}
|
||||
|
||||
void
|
||||
vt_lpen_intr(void)
|
||||
{
|
||||
sim_debug (DEB_LPINT, &vt_dev, "SET_INT (VTLP)\n");
|
||||
SET_INT (VTLP);
|
||||
}
|
||||
|
||||
void
|
||||
vt_char_intr(void)
|
||||
{
|
||||
sim_debug (DEB_CHINT, &vt_dev, "SET_INT (CHAR)\n");
|
||||
SET_INT (VTCH);
|
||||
}
|
||||
|
||||
void
|
||||
vt_name_intr(void)
|
||||
{
|
||||
sim_debug (DEB_NMINT, &vt_dev, "SET_INT (VTNM)\n");
|
||||
SET_INT (VTNM);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user