1134 lines
70 KiB
C
1134 lines
70 KiB
C
#ifdef USE_DISPLAY
|
||
/* pdp11_vt.c: PDP-11 VT11/VS60 Display Processor Simulation
|
||
|
||
Copyright (c) 2003-2004, Philip L. Budne, Douglas A. Gwyn
|
||
Copyright (c) 1993-2003, Robert M Supnik
|
||
|
||
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
|
||
THE AUTHORS 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 names of the authors shall not be
|
||
used in advertising or otherwise to promote the sale, use or other dealings
|
||
in this Software without prior written authorization from the authors.
|
||
|
||
vt VT11/VS60 Display Processor
|
||
|
||
05-Feb-04 DAG Improved VT11 emulation
|
||
Added VS60 support
|
||
14-Sep-03 PLB Start from pdp11_lp.c
|
||
*/
|
||
|
||
/*
|
||
* this file is just a thin layer of glue to the simulator-
|
||
* independent XY Display simulation
|
||
*/
|
||
|
||
#if defined (VM_VAX) /* VAX version */
|
||
#include "vax_defs.h"
|
||
#elif defined(VM_PDP11) /* PDP-11 version */
|
||
#include "pdp11_defs.h"
|
||
#else
|
||
#error "VT11/VS60 is supported only on the PDP-11 and VAX"
|
||
#endif
|
||
|
||
#include "display/display.h"
|
||
#include "display/vt11.h"
|
||
#include "sim_video.h"
|
||
|
||
/*
|
||
* Timing parameters. Should allow some runtime adjustment,
|
||
* since several different configurations were shipped, including:
|
||
*
|
||
* GT40: PDP-11/05 with VT11 display processor
|
||
* GT44: PDP-11/40 with VT11 display processor
|
||
* GT46: PDP-11/34 with VT11 display processor
|
||
* GT62: PDP-11/34a with VS60 display system
|
||
*/
|
||
|
||
/*
|
||
* run a VT11/VS60 cycle every this many PDP-11 "cycle" times;
|
||
*
|
||
* 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
|
||
|
||
/*
|
||
* memory cycle time
|
||
*/
|
||
#define MEMORY_CYCLE 1 /* either .98 or 1.2 us? */
|
||
|
||
/*
|
||
* delay in microseconds between VT11/VS60 cycles:
|
||
* VT11/VS60 and PDP-11 CPU's share the same memory bus,
|
||
* and each VT11/VS60 instruction requires a memory reference;
|
||
* figure each PDP11 instruction requires two memory references
|
||
*/
|
||
#define CYCLE_US (MEMORY_CYCLE*(VT11_DELAY*2+1))
|
||
|
||
extern int32 int_vec[IPL_HLVL][32];
|
||
|
||
t_stat vt_rd(int32 *data, int32 PA, int32 access);
|
||
t_stat vt_wr(int32 data, int32 PA, int32 access);
|
||
t_stat vt_svc(UNIT *uptr);
|
||
t_stat vt_reset(DEVICE *dptr);
|
||
t_stat vt_boot(int32 unit, DEVICE *dptr);
|
||
t_stat vt_set_crt(UNIT *uptr, int32 val, CONST char *cptr, void *desc);
|
||
t_stat vt_show_crt(FILE *st, UNIT *uptr, int32 val, CONST void *desc);
|
||
t_stat vt_set_scale(UNIT *uptr, int32 val, CONST char *cptr, void *desc);
|
||
t_stat vt_show_scale(FILE *st, UNIT *uptr, int32 val, CONST void *desc);
|
||
t_stat vt_set_hspace(UNIT *uptr, int32 val, CONST char *cptr, void *desc);
|
||
t_stat vt_show_hspace(FILE *st, UNIT *uptr, int32 val, CONST void *desc);
|
||
t_stat vt_set_vspace(UNIT *uptr, int32 val, CONST char *cptr, void *desc);
|
||
t_stat vt_show_vspace(FILE *st, UNIT *uptr, int32 val, CONST void *desc);
|
||
t_stat vt_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr);
|
||
const char *vt_description (DEVICE *dptr);
|
||
|
||
/* VT11/VS60 data structures
|
||
|
||
vt_dev VT11 device descriptor
|
||
vt_unit VT11 unit descriptor
|
||
vt_reg VT11 register list
|
||
vt_mod VT11 modifier list
|
||
*/
|
||
#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}, IOLN_VT11 };
|
||
/* (VT11 uses only the first 3 interrupt vectors) */
|
||
|
||
UNIT vt_unit = {
|
||
UDATA (&vt_svc, 0, 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}",
|
||
&vt_set_hspace, &vt_show_hspace, NULL, "Horizontal Spacing" },
|
||
{ 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" },
|
||
{ 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 | DEV_DEBUG,
|
||
0, vt_deb, NULL, NULL, NULL, &vt_help, NULL,
|
||
&vt_description
|
||
};
|
||
|
||
const char *vt_regnam[] = {
|
||
"DPC",
|
||
"MPR",
|
||
"XPR",
|
||
"YPR",
|
||
"RR",
|
||
"SPR",
|
||
"XOR",
|
||
"YOR",
|
||
"ANR",
|
||
"SCR",
|
||
"NR",
|
||
"SDR",
|
||
"STR",
|
||
"SAR",
|
||
"ZPR",
|
||
"ZOR",
|
||
};
|
||
|
||
/* VT11/VS60 routines
|
||
|
||
vt_rd I/O page read
|
||
vt_wr I/O page write
|
||
vt_svc process event
|
||
vt_reset process reset
|
||
vt_boot bootstrap device
|
||
*/
|
||
|
||
t_stat
|
||
vt_rd(int32 *data, int32 PA, int32 access)
|
||
{
|
||
t_stat stat = SCPE_OK;
|
||
|
||
switch (PA & 036) {
|
||
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;
|
||
}
|
||
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);
|
||
|
||
/* 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 */
|
||
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;
|
||
case 006: vt11_set_ypr(d); return SCPE_OK;
|
||
case 010: if (!VS60) break; vt11_set_rr(d); return SCPE_OK;
|
||
case 012: if (!VS60) break; vt11_set_spr(d); return SCPE_OK;
|
||
case 014: if (!VS60) break; vt11_set_xor(d); return SCPE_OK;
|
||
case 016: if (!VS60) break; vt11_set_yor(d); return SCPE_OK;
|
||
case 020: if (!VS60) break; vt11_set_anr(d); return SCPE_OK;
|
||
case 022: if (!VS60) break; vt11_set_scr(d); return SCPE_OK;
|
||
case 024: if (!VS60) break; vt11_set_nr(d); return SCPE_OK;
|
||
case 026: if (!VS60) break; vt11_set_sdr(d); return SCPE_OK;
|
||
case 030: if (!VS60) break; vt11_set_str(d); return SCPE_OK;
|
||
case 032: if (!VS60) break; vt11_set_sar(d); return SCPE_OK;
|
||
case 034: if (!VS60) break; vt11_set_zpr(d); return SCPE_OK;
|
||
case 036: if (!VS60) break; vt11_set_zor(d); return SCPE_OK;
|
||
}
|
||
return SCPE_NXM;
|
||
}
|
||
|
||
/*
|
||
* here to run a display processor cycle, called as a SIMH
|
||
* "device service routine".
|
||
*/
|
||
t_stat
|
||
vt_svc(UNIT *uptr)
|
||
{
|
||
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;
|
||
}
|
||
|
||
t_stat
|
||
vt_reset(DEVICE *dptr)
|
||
{
|
||
DEVICE *ng_dptr;
|
||
|
||
ng_dptr = find_dev ("NG");
|
||
if (!(dptr->flags & DEV_DIS) &&
|
||
(ng_dptr != NULL) && !(ng_dptr->flags & DEV_DIS)) {
|
||
dptr->flags |= DEV_DIS;
|
||
return sim_messagef (SCPE_NOFNC, "VT and NG device can't both be enabled\n");
|
||
}
|
||
if (!(dptr->flags & DEV_DIS))
|
||
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 (dptr->units); /* deactivate unit */
|
||
return auto_config ("VT", (dptr->flags & DEV_DIS) ? 0 : 1);
|
||
}
|
||
|
||
#include "pdp11_vt_lunar_rom.h" /* Lunar Lander image */
|
||
|
||
/*
|
||
* GT4x/GT62 bootstrap (acts as remote terminal)
|
||
*
|
||
*/
|
||
|
||
t_addr vt_rom_base = 017766000;
|
||
|
||
uint16 vt_boot_rom[] = {
|
||
// ; .ASECT
|
||
//
|
||
// ;BOOTVT.S09 5/2/72
|
||
//
|
||
//
|
||
// ; VT-40 BOOTSTRAP LOADER, VERSION S09, RELEASE R01, 5/2/72
|
||
//
|
||
// ; COPYRIGHT 1972, DIGITAL EQUIPMENT CORPORATION
|
||
// ; 146 MAIN STREET
|
||
// ; MAYNARD, MASSACHUSSETTS
|
||
// ; 01754
|
||
//
|
||
//
|
||
// ; WRITTEN BY JACK BURNESS, SENIOR SYSTEMS ARCHITECT!
|
||
//
|
||
//
|
||
//
|
||
//
|
||
// ; THIS ROUTINE IS INTENDED TO BE LOADED IN THE ROM PORTION OF THE VT-40.
|
||
//
|
||
//
|
||
// ; REGISTER DEFINITIONS:
|
||
//
|
||
// 000000 R0=%0
|
||
// 000001 R1=%1
|
||
// 000002 R2=%2
|
||
// 000003 R3=%3
|
||
// 000004 R4=%4
|
||
// 000005 R5=%5
|
||
// 000006 R6=%6
|
||
// 000007 R7=%7
|
||
//
|
||
// 000006 SP=R6
|
||
// 000007 PC=R7
|
||
//
|
||
// 000000 RET1=R0 ;RETURN OF VALUE REGISTER.
|
||
// 000001 INP1=R1 ;ARGUMENT FOR CALLED FUNCTION
|
||
// 000002 INP2=R2 ;SECOND ARGUMENT.
|
||
// 000003 WORK1=R3 ;FIRST WORK REGISTER.
|
||
// 000004 WORK2=R4 ;SECOND WORKING REGISTER.
|
||
// 000005 SCR1=R5 ;SCRATCH REGISTER.
|
||
//
|
||
// 000003 L.CKSM=WORK1 ;OVERLAPPING DEFINITIONS FOR LOADER PORTION.
|
||
// 000000 L.BYT=RET1
|
||
// 000005 L.BC=SCR1
|
||
// 000001 L.ADR=INP1
|
||
//
|
||
//
|
||
//
|
||
//
|
||
// 016000 COREND=16000 ;FIRST LOCATION OF NON-CORE.
|
||
//
|
||
// ; ROMORG=037000 ;WHERE THE ROM PROGRAM SHOULD GO.
|
||
// 166000 ROMORG=166000 ;WHERE THE ROM PROGRAM SHOULD GO.
|
||
// 000000 STARTX=0 ;WHERE TO START DISPLAYING THE X POSITIONS.
|
||
// 001360 STARTY=1360 ;WHERE TO START DISPLAYING THE Y.
|
||
//
|
||
// 172000 VT40PC=172000 ;VT40 PROGRAM COUNTER.
|
||
// 177560 KBDIS=177560 ;TTY INPUT STATUS.
|
||
// 175614 P10OS=175614 ;PDP-10 OUTPUT STATUS.
|
||
// 175610 P10IS=175610 ;PDP-10 INPUT STATUS.
|
||
//
|
||
// 177562 KBDIB=KBDIS+2 ;TTY INPUT BUFFER.
|
||
// 175612 P10IB=P10IS+2 ;PDP-10 INPUT CHARACTER.
|
||
// 175616 P10OB=P10OS+2 ;PDP-10 OUTPUT BUFFER.
|
||
//
|
||
//
|
||
// 015776 P10OC=COREND-2 ;CHARACTER TO BE SENT TO THE PDP-10
|
||
// 015772 P10IC=P10OC-4 ;INPUT CHARACTER FROM 10 PLUS ONE SAVE CHARACTER
|
||
// 015770 STKSRT=P10IC-2 ;FIRST LOCATION OF STACK.
|
||
//
|
||
//
|
||
// 160000 JMPDIS=160000 ;THE VT-40 DISPLAY JUMP INSTRUCTION.
|
||
//
|
||
//
|
||
// 000024 PWRFAL=24 ;POWER FAIL RESTART LOCATION.
|
||
//
|
||
//
|
||
// 166000 .=ROMORG ;SET THE ORIGIN NOW!!!!
|
||
//
|
||
//
|
||
0012705, 0000026, // 166000 012705 000026 START: MOV #PWRFAL+2,SCR1 ;PICK UP POINTER TO P.F. STATUS.
|
||
0005015, // 166004 005015 CLR @SCR1 ;CLEAR IT OUT TO BE SURE.
|
||
0010745, // 166006 010745 MOV PC,-(SCR1) ;SET UP THE RESTART LOCATION.
|
||
//
|
||
0000005, // 166010 000005 RESET ;RESET THE BUS.
|
||
//
|
||
0012767, 0000007, 0007570, // 166012 012767 000007 007570 MOV #7,P10IS ;INITIALIZE PDP-10 INPUT
|
||
0012767, 0000001, 0011532, // 166020 012767 000001 011532 MOV #1,KBDIS ;INITIALIZE TTY INPUT.
|
||
0012767, 0000201, 0007560, // 166026 012767 000201 007560 MOV #201,P10OS ;INITIALIZE PDP-10 OUTPUT.
|
||
//
|
||
//
|
||
//
|
||
0012706, 0015770, // 166034 012706 015770 RESTRT: MOV #STKSRT,SP ;SET UP THE STACK NOW!
|
||
0005001, // 166040 005001 CLR L.ADR ;CLEAR ADDRESS POINTER.
|
||
0012702, 0160000, // 166042 012702 160000 MOV #JMPDIS,INP2 ;PLACE A DISPLAY JUMP INSTRUCTION IN A REGISTER.
|
||
//
|
||
//
|
||
0010221, // 166046 010221 MOV INP2,(L.ADR)+ ;MOVE IT TO LOCATION 0.
|
||
0012711, 0166756, // 166050 012711 166756 MOV #DISPRG,(L.ADR) ;MOVE ADDRESS POINTER INTO 2.
|
||
0012701, 0000030, // 166054 012701 000030 MOV #PWRFAL+4,L.ADR ;SET UP WHERE WE WILL STORE CHARACTERS.
|
||
0005000, // 166060 005000 CLR RET1 ;PREPARE TO INSERT A ZERO CHARACTER.
|
||
0004767, 0000022, // 166062 004767 000022 JSR PC,DOCHAR ;INSERT IT NOW.
|
||
0005067, 0003706, // 166066 005067 003706 CLR VT40PC ;CLEAR THE DISPLAY PROGRAM COUNTER AND START.
|
||
//
|
||
0004767, 0000210, // 166072 004767 000210 MAJOR: JSR PC,GETCHR ;GET A CHARACTER NOW.
|
||
0000240, // 166076 000240 NOP
|
||
0000240, // 166100 000240 NOP
|
||
0000240, // 166102 000240 NOP
|
||
0012746, 0166072, // 166104 012746 166072 MOV #MAJOR,-(SP) ;INSERT IN DISPLAY BUFFER NOW.
|
||
//
|
||
0010105, // 166110 010105 DOCHAR: MOV L.ADR,SCR1 ;GET CURRENT BUFFER POSITION NOW.
|
||
0022525, // 166112 022525 CMP (SCR1)+,(SCR1)+ ;BYPASS CURRENT DISPLAY JUMP.
|
||
0005025, // 166114 005025 CLR (SCR1)+ ;CLEAR FUTURE ADDRESS FOR JUMP.
|
||
0010225, // 166116 010225 MOV INP2,(SCR1)+ ;STICK IN TEMPORARY JUMP WHILE WE REPLACE CURREN
|
||
0005015, // 166120 005015 CLR (SCR1) ;A DISPLAY JUMP TO ZERO.
|
||
0005011, // 166122 005011 CLR (L.ADR) ;NOW REPLACE CURRENT DISPLAY JUMP BY THE CHARACT
|
||
0050021, // 166124 050021 BIS RET1,(L.ADR)+ ;IT'S DONE THIS WAY TO WASTE 2 CYCLES.
|
||
0010211, // 166126 010211 MOV INP2,(L.ADR) ;TO AVOID TIMING PROBLEMS WITH THE VT40.
|
||
0000207, // 166130 000207 RTS PC ;AND FINALLY RETURN.
|
||
//
|
||
//
|
||
0004767, 0000124, // 166132 004767 000124 GET8: JSR PC,GETSIX ;GET SIX BITS NOW.
|
||
0010046, // 166136 010046 MOV RET1,-(SP) ;SAVE THE CHARACTER NOW.
|
||
0000401, // 166140 000401 BR GETP84 ;BYPASS THE 8'ER
|
||
0005002, // 166142 005002 GET84: CLR INP2 ;RESET THE MAGIC REGISTER NOW.
|
||
0005722, // 166144 005722 GETP84: TST (INP2)+ ;INCREMENT WHERE TO GO.
|
||
0066207, 0166250, // 166146 066207 166250 ADD GET8TB(INP2),PC ;UPDATE PC NOW.
|
||
//
|
||
// 166152 GET8P=.
|
||
//
|
||
0004767, 0000104, // 166152 004767 000104 GET81: JSR PC,GETSIX ;GET A CHARACTER NOW.
|
||
0010004, // 166156 010004 MOV RET1,WORK2 ;SAVE FOR A SECOND.
|
||
0006300, // 166160 006300 ASL RET1
|
||
0006300, // 166162 006300 ASL RET1 ;SHIFT TO LEFT OF BYTE
|
||
0106300, // 166164 106300 ASLB RET1
|
||
0106116, // 166166 106116 ROLB @SP ;PACK THEM IN.
|
||
0106300, // 166170 106300 ASLB RET1
|
||
//
|
||
//
|
||
0106116, // 166172 106116 ROLB @SP ;A GOOD 8 BIT THING.
|
||
0012600, // 166174 012600 MOV (SP)+,RET1 ;POP AND RETURN NOW.
|
||
0000207, // 166176 000207 RTS PC
|
||
//
|
||
0006300, // 166200 006300 GET82: ASL RET1 ;WORST CASE, SHIFT 4
|
||
0006300, // 166202 006300 ASL RET1
|
||
0106300, // 166204 106300 ASLB RET1
|
||
0106104, // 166206 106104 ROLB WORK2
|
||
0106300, // 166210 106300 ASLB RET1
|
||
0106104, // 166212 106104 ROLB WORK2
|
||
0106300, // 166214 106300 ASLB RET1
|
||
0106104, // 166216 106104 ROLB WORK2
|
||
0106300, // 166220 106300 ASLB RET1
|
||
0106104, // 166222 106104 ROLB WORK2
|
||
0010400, // 166224 010400 MOV WORK2,RET1
|
||
0012604, // 166226 012604 MOV (SP)+,WORK2
|
||
0000207, // 166230 000207 RTS PC
|
||
//
|
||
0006100, // 166232 006100 GET83: ROL RET1
|
||
0006100, // 166234 006100 ROL RET1
|
||
0006004, // 166236 006004 ROR WORK2
|
||
0106000, // 166240 106000 RORB RET1
|
||
0006004, // 166242 006004 ROR WORK2
|
||
0106000, // 166244 106000 RORB RET1 ;FINAL CHARACTER ASSEMBLED.
|
||
0005726, // 166246 005726 TST (SP)+ ;FUDGE STACK.
|
||
0000207, // 166250 000207 RTS PC ;AND RETURN NOW.
|
||
//
|
||
// 166250 GET8TB = .-2 ;PUSH ZERO CONDITION BACK INTO NEVER-NEVER LAND.
|
||
//
|
||
0000000, // 166252 000000 .WORD GET81-GET8P
|
||
0000026, // 166254 000026 .WORD GET82-GET8P
|
||
0000060, // 166256 000060 .WORD GET83-GET8P
|
||
0177770, // 166260 177770 .WORD GET84-GET8P
|
||
//
|
||
//
|
||
0004767, 0000020, // 166262 004767 000020 GETSIX: JSR PC,GETCHR
|
||
0020027, 0000040, // 166266 020027 000040 CMP RET1,#40
|
||
0002546, // 166272 002546 BLT L.BAD
|
||
0020027, 0000137, // 166274 020027 000137 CMP RET1,#137
|
||
0003143, // 166300 003143 BGT L.BAD
|
||
0000207, // 166302 000207 RTS PC
|
||
//
|
||
//
|
||
//
|
||
0005726, // 166304 005726 GETCHP: TST (SP)+ ;UPDATE THE STACK.
|
||
//
|
||
0012700, 0015772, // 166306 012700 015772 GETCHR: MOV #P10IC,RET1 ;SET UP POINTER TO THE INPUT CHARACTER.
|
||
0004767, 0000064, // 166312 004767 000064 GETCHL: JSR PC,CHECK
|
||
0005710, // 166316 005710 TST @RET1 ;ANY CHARACTER THERE?
|
||
0001774, // 166320 001774 BEQ GETCHL
|
||
0011046, // 166322 011046 MOV @RET1,-(SP) ;PUSH THE CHAR ON THE STACK.
|
||
0005020, // 166324 005020 CLR (RET1)+ ;CLEAR THE CHAR GOT FLAG NOW.
|
||
0042716, 0177600, // 166326 042716 177600 BIC #-200,(SP) ;CLEAR AWAY PARITY NOW.
|
||
0001764, // 166332 001764 BEQ GETCHP ;IF ZERO, GET ANOTHER
|
||
//
|
||
//
|
||
0022716, 0000177, // 166334 022716 000177 CMP #177,(SP)
|
||
0001761, // 166340 001761 BEQ GETCHP ;ALSO IGNORE RUBOUTS.
|
||
0022710, 0000175, // 166342 022710 000175 CMP #175,@RET1 ;WAS IT A "175"
|
||
0001007, // 166346 001007 BNE GETNP ;NOPE.
|
||
0011610, // 166350 011610 MOV (SP),@RET1 ;YEP. RESET IN CASE OF ABORT.
|
||
0021027, 0000122, // 166352 021027 000122 CMP @RET1,#122 ;IS IT AN R
|
||
0001626, // 166356 001626 BEQ RESTRT ;YEP. RESTART
|
||
0021027, 0000114, // 166360 021027 000114 CMP @RET1,#114 ;IS IT AN L
|
||
0001455, // 166364 001455 BEQ LOAD ;YEP. LOAD.
|
||
//
|
||
0011610, // 166366 011610 GETNP: MOV (SP),@RET1 ;NOW DO THE FUDGING.
|
||
0012600, // 166370 012600 MOV (SP)+,RET1
|
||
0020027, 0000175, // 166372 020027 000175 CMP RET1,#175
|
||
0001743, // 166376 001743 BEQ GETCHR ;IF ALTMODE, LOOP
|
||
0000207, // 166400 000207 RTS PC
|
||
//
|
||
//
|
||
0005767, 0027370, // 166402 005767 027370 CHECK: TST P10OC ;DO WE WANT TO OUTPUT?
|
||
0001410, // 166406 001410 BEQ CHECK1 ;NO.
|
||
0105767, 0007200, // 166410 105767 007200 TSTB P10OS ;WE DO. IS THE 10 READY?
|
||
0100005, // 166414 100005 BPL CHECK1 ;NOT QUITE.
|
||
0016767, 0027354, 0007172, // 166416 016767 027354 007172 MOV P10OC,P10OB ;IT'S READY. SEND THE CHARACTER.
|
||
0005067, 0027346, // 166424 005067 027346 CLR P10OC ;AND THE SAVED CHARACTER.
|
||
//
|
||
0105767, 0011124, // 166430 105767 011124 CHECK1: TSTB KBDIS ;HEY, IS THE KEYBOARD READY?
|
||
0100014, // 166434 100014 BPL CHECK3 ;NOPE. NO LUCK.
|
||
0116746, 0011120, // 166436 116746 011120 MOVB KBDIB,-(SP) ;YEP. SAVE THE CHARACTER NOW.
|
||
0012767, 0000001, 0011110, // 166442 012767 000001 011110 MOV #1,KBDIS ;AND REENABLE THE COMMUNICATIONS DEVICE.
|
||
//
|
||
0004767, 0177726, // 166450 004767 177726 CHECK2: JSR PC,CHECK ;IS THE OUTPUT READY?
|
||
0005767, 0027316, // 166454 005767 027316 TST P10OC
|
||
0001373, // 166460 001373 BNE CHECK2 ;IF NOT, WAIT TILL DONE.
|
||
0012667, 0007130, // 166462 012667 007130 MOV (SP)+,P10OB ;AND THEN SEND OUT THE CHARACTER.
|
||
//
|
||
//
|
||
0105767, 0007116, // 166466 105767 007116 CHECK3: TSTB P10IS ;IS THE 10 TALKING TO ME.
|
||
0100011, // 166472 100011 BPL CHECK4 ;NOPE. EXIT.
|
||
0116767, 0007112, 0027270, // 166474 116767 007112 027270 MOVB P10IB,P10IC ;GET THE CHARACTER NOW.
|
||
0052767, 0177400, 0027262, // 166502 052767 177400 027262 BIS #-400,P10IC ;MAKE SURE IT'S NONE ZERO.
|
||
0012767, 0000007, 0007072, // 166510 012767 000007 007072 MOV #7,P10IS ;REINITIALIZE COMMUNICATION LINE.
|
||
//
|
||
0000207, // 166516 000207 CHECK4: RTS PC ;AND RETURN.
|
||
//
|
||
//
|
||
// ; THE L O A D E R
|
||
//
|
||
0005002, // 166520 005002 LOAD: CLR INP2 ;RESET TO FIRST 8 BIT CHARACTER.
|
||
0012712, 0172000, // 166522 012712 172000 MOV #172000,(INP2) ;AND ALSO CLEVERLY STOP THE VT40.
|
||
0012706, 0015770, // 166526 012706 015770 MOV #STKSRT,SP ;RESET STACK POINTER NOW.
|
||
//
|
||
0005003, // 166532 005003 L.LD2: CLR L.CKSM ;CLEAR THE CHECKSUM
|
||
0004767, 0000070, // 166534 004767 000070 JSR PC,L.PTR ;GET A BYTE NOW.
|
||
0105300, // 166540 105300 DECB L.BYT ;IS IT ONE?
|
||
0001373, // 166542 001373 BNE L.LD2 ;NOPE. WAIT AWHILE
|
||
0004767, 0000060, // 166544 004767 000060 JSR PC,L.PTR ;YEP. GET NEXT CHARACTER.
|
||
//
|
||
0004767, 0000072, // 166550 004767 000072 JSR PC,L.GWRD ;GET A WORD.
|
||
0010005, // 166554 010005 MOV L.BYT,L.BC ;GET THE COUNTER NOW.
|
||
0162705, 0000004, // 166556 162705 000004 SUB #4,L.BC ;CHOP OFF EXTRA STUFF.
|
||
0022705, 0000002, // 166562 022705 000002 CMP #2,L.BC ;NULL?
|
||
0001437, // 166566 001437 BEQ L.JMP ;YEP. MUST BE END.
|
||
0004767, 0000052, // 166570 004767 000052 JSR PC,L.GWRD ;NOPE. GET THE ADDRESS.
|
||
0010001, // 166574 010001 MOV L.BYT,L.ADR ;AND REMEMBER FOR OLD TIMES SAKE.
|
||
//
|
||
0004767, 0000026, // 166576 004767 000026 L.LD3: JSR PC,L.PTR ;GET A BYTE (DATA)
|
||
0002010, // 166602 002010 BGE L.LD4 ;ALL DONE WITH THE COUNTER?
|
||
0105703, // 166604 105703 TSTB L.CKSM ;YEP. GOOD CHECK SUM?
|
||
0001751, // 166606 001751 BEQ L.LD2 ;NOPE. LOAD ERROR.
|
||
//
|
||
0012700, // 166610 012700 L.BAD: MOV (PC)+,RET1 ;SEND OUT SOME CHARACTERS NOW.
|
||
0041175, // 166612 175
|
||
// 166613 102 .BYTE 175,102 ;"CTRL BAD"
|
||
0004767, 0000110, // 166614 004767 000110 JSR PC,SENDIT
|
||
0000167, 0177210, // 166620 000167 177210 JMP RESTRT
|
||
//
|
||
0110021, // 166624 110021 L.LD4: MOVB L.BYT,(L.ADR)+ ;PLACE THE BYTE IN CORE.
|
||
0000763, // 166626 000763 BR L.LD3 ;GET ANOTHER ONE.
|
||
//
|
||
0004767, 0177276, // 166630 004767 177276 L.PTR: JSR PC,GET8 ;GET 8 BITS NOW.
|
||
0060003, // 166634 060003 ADD L.BYT,L.CKSM ;UPDATE CHECKSUM
|
||
0042700, 0177400, // 166636 042700 177400 BIC #177400,L.BYT ;CLEAN UP THE BYTE NOW.
|
||
0005305, // 166642 005305 DEC L.BC ;UPDATE THE COUNTER.
|
||
0000207, // 166644 000207 RTS PC ;RETURN NOW.
|
||
//
|
||
0004767, 0177756, // 166646 004767 177756 L.GWRD: JSR PC,L.PTR ;GET A CHARACTER.
|
||
0010046, // 166652 010046 MOV L.BYT,-(SP) ;SAVE FOR A SECOND.
|
||
0004767, 0177750, // 166654 004767 177750 JSR PC,L.PTR ;GET ANOTHER CHARACTER.
|
||
0000300, // 166660 000300 SWAB L.BYT ;NOW ASSEMBLE THE WORD.
|
||
0052600, // 166662 052600 BIS (SP)+,L.BYT ;AND RETURN WITH A 16 BITER.
|
||
//
|
||
//
|
||
0000207, // 166664 000207 RTS PC
|
||
//
|
||
0004767, 0177754, // 166666 004767 177754 L.JMP: JSR PC,L.GWRD ;GET A WORD
|
||
0010046, // 166672 010046 MOV L.BYT,-(SP) ;SAVE ON THE STACK.
|
||
0004767, 0177730, // 166674 004767 177730 JSR PC,L.PTR ;GET A CHARACTER.
|
||
0105703, // 166700 105703 TSTB L.CKSM ;IS IT ZERO?
|
||
0001342, // 166702 001342 BNE L.BAD ;YEP. WHAT CRAP.
|
||
0032716, 0000001, // 166704 032716 000001 BIT #1,(SP) ;IS IT ODD?
|
||
0001406, // 166710 001406 BEQ L.JMP1 ;YEP. START PROGRAM GOING NOW.
|
||
0012700, // 166712 012700 MOV (PC)+,RET1 ;TELL PDP-10 WE'VE LOADED OK.
|
||
0043575, // 166714 175
|
||
// 166715 107 .BYTE 175,107
|
||
0004767, 0000006, // 166716 004767 000006 JSR PC,SENDIT
|
||
0000000, // 166722 000000 HALT
|
||
0000776, // 166724 000776 BR .-2
|
||
//
|
||
0000136, // 166726 000136 L.JMP1: JMP @(SP)+ ;AND AWAY WE GO.
|
||
//
|
||
//
|
||
0004767, 0177446, // 166730 004767 177446 SENDIT: JSR PC,CHECK ;POLL THE OUTPUT DEVICE NOW.
|
||
0005767, 0027036, // 166734 005767 027036 TST P10OC ;OUTPUT CLEAR?
|
||
0001373, // 166740 001373 BNE SENDIT ;NOPE. LOOP AWHILE LONGER.
|
||
0010067, 0006650, // 166742 010067 006650 MOV RET1,P10OB ;SEND OUT THE CHARACTER.
|
||
0105000, // 166746 105000 CLRB RET1 ;CLEAR THE BYTE.
|
||
0000300, // 166750 000300 SWAB RET1 ;AND SWAP THEM NOW.
|
||
0001366, // 166752 001366 BNE SENDIT ;IF NOT EQUAL, REPEAT.
|
||
0000207, // 166754 000207 RTS PC
|
||
0000000, // 166756 000000 //
|
||
0000000, // 166760 000000 //
|
||
0000000, // 166762 000000 //
|
||
0000000, // 166764 000000 //
|
||
0000000, // 166766 000000 //
|
||
0000000, // 166770 000000 //
|
||
0000000, // 166772 000000 //
|
||
0000000, // 166774 000000 //
|
||
0000000, // 166776 000000 //
|
||
//
|
||
// ; THIS IS THE INITIALIZING VT40 PROGRAM WHICH WILL
|
||
// ; JUMP TO THE PROGRAM AFTER THE POWER FAIL LOCATIONS
|
||
// ; WHICH WILL JUMP TO ZERO WHICH WILL JUMP BACK TO HERE.
|
||
//
|
||
//
|
||
//
|
||
0170256, // 166756 170256 DISPRG: .WORD 170256 ;LOAD STATUS REGISTER FOR NORMAL OPERATION.
|
||
0115124, // 166760 115124 .WORD 115124 ;SET POINT MODE. "NORMAL".
|
||
0000000, // 166762 000000 .WORD STARTX ;X COORDINATE
|
||
0001360, // 166764 001360 .WORD STARTY ;Y COORDINATE
|
||
0100000, // 166766 100000 .WORD 100000 ;SET CHARACTER MODE.
|
||
0160000, // 166770 160000 .WORD JMPDIS ;THEN JUMP TO THE POWERFAIL LOCATION.
|
||
0000030, // 166772 000030 .WORD PWRFAL+4 ;TO DISPLAY USERS CHARACTERS.
|
||
//
|
||
//
|
||
// 000001 .END
|
||
};
|
||
|
||
t_stat
|
||
vt_rom_rd(int32 *data, int32 PA, int32 access)
|
||
{
|
||
*data = (int32)vt_boot_rom[(((PA - vt_rom_base) & 0xFFFF) >> 1)];
|
||
return SCPE_OK;
|
||
}
|
||
|
||
DIB vt_rom_dib;
|
||
|
||
t_stat
|
||
vt_boot(int32 unit, DEVICE *dptr)
|
||
{
|
||
t_stat r;
|
||
char stability[32];
|
||
extern int32 saved_PC;
|
||
|
||
if (sim_switch_number == 40) { /* GT40 Boot? */
|
||
set_cmd (0, "CPU 11/05");
|
||
set_cmd (0, "CPU 16k");
|
||
set_cmd (0, "DLI ENABLE");
|
||
set_cmd (0, "DLI LINES=1");
|
||
set_cmd (0, "DLI ADDRESS=17775610");
|
||
set_cmd (0, "VT CRT=VR14");
|
||
set_cmd (0, "VT SCALE=1");
|
||
set_cmd (0, "VT ADDRESS=17772000");
|
||
vt_dib.next = &vt_rom_dib;
|
||
vt_rom_dib.ba = vt_rom_base;
|
||
vt_rom_dib.lnt = sizeof (vt_boot_rom);
|
||
vt_rom_dib.rd = &vt_rom_rd;
|
||
r = build_ubus_tab (&vt_dev, &vt_rom_dib);
|
||
if (r != SCPE_OK)
|
||
return r;
|
||
cpu_set_boot (vt_rom_base);
|
||
return r;
|
||
}
|
||
/* XXX should do something like vt11_set_dpc(&appropriate_ROM_image) */
|
||
|
||
/* Instead, since that won't be too useful.... */
|
||
/* Load and start Lunar Lander which has the potential to be fun! */
|
||
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 base of 320 */
|
||
if (0320 != vt_dib.vec) { /* If that is not the case, then copy the 320 vectors to the right place */
|
||
WrMemW (vt_dib.vec + 000, RdMemW (0320 + 0));
|
||
WrMemW (vt_dib.vec + 002, RdMemW (0320 + 2));
|
||
WrMemW (vt_dib.vec + 004, RdMemW (0324 + 0));
|
||
WrMemW (vt_dib.vec + 006, RdMemW (0324 + 2));
|
||
WrMemW (vt_dib.vec + 010, RdMemW (0330 + 0));
|
||
WrMemW (vt_dib.vec + 012, RdMemW (0330 + 2));
|
||
WrMemW (vt_dib.vec + 014, RdMemW (0334 + 0));
|
||
WrMemW (vt_dib.vec + 016, RdMemW (0334 + 2));
|
||
}
|
||
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;
|
||
}
|
||
|
||
/* SET/SHOW VT options: */
|
||
|
||
t_stat
|
||
vt_set_crt(UNIT *uptr, int32 val, CONST char *cptr, void *desc)
|
||
{
|
||
char gbuf[CBUFSIZE];
|
||
|
||
if (vt11_init)
|
||
return SCPE_ALATT; /* should be "changes locked out" */
|
||
if (cptr == NULL)
|
||
return SCPE_ARG;
|
||
get_glyph(cptr, gbuf, 0);
|
||
if (strcmp(gbuf, "VR14") == 0)
|
||
vt11_display = DIS_VR14;
|
||
else if (strcmp(gbuf, "VR17") == 0)
|
||
vt11_display = DIS_VR17;
|
||
else if (strcmp(gbuf, "VR48") == 0)
|
||
vt11_display = DIS_VR48;
|
||
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;
|
||
}
|
||
|
||
t_stat
|
||
vt_show_crt(FILE *st, UNIT *uptr, int32 val, CONST void *desc)
|
||
{
|
||
fprintf(st, "crt=VR%d", (int)vt11_display);
|
||
return SCPE_OK;
|
||
}
|
||
|
||
t_stat
|
||
vt_set_scale(UNIT *uptr, int32 val, CONST char *cptr, void *desc)
|
||
{
|
||
t_stat r;
|
||
t_value v;
|
||
if (vt11_init)
|
||
return SCPE_ALATT; /* should be "changes locked out" */
|
||
if (cptr == NULL)
|
||
return SCPE_ARG;
|
||
v = get_uint(cptr, 10, 8, &r);
|
||
if (r != SCPE_OK)
|
||
return r;
|
||
if (v != 1 && v != 2 && v != 4 && v != 8)
|
||
return SCPE_ARG;
|
||
vt11_scale = v;
|
||
return SCPE_OK;
|
||
}
|
||
|
||
t_stat
|
||
vt_show_scale(FILE *st, UNIT *uptr, int32 val, CONST void *desc)
|
||
{
|
||
fprintf(st, "scale=%d", (int)vt11_scale);
|
||
return SCPE_OK;
|
||
}
|
||
|
||
t_stat
|
||
vt_set_hspace(UNIT *uptr, int32 val, CONST char *cptr, void *desc)
|
||
{
|
||
char gbuf[CBUFSIZE];
|
||
if (vt11_init)
|
||
return SCPE_ALATT; /* should be "changes locked out" */
|
||
if (cptr == NULL)
|
||
return SCPE_ARG;
|
||
get_glyph(cptr, gbuf, 0);
|
||
if (strcmp(gbuf, "NARROW") == 0)
|
||
vt11_csp_w = 12;
|
||
else if (strcmp(gbuf, "NORMAL") == 0)
|
||
vt11_csp_w = 14;
|
||
else
|
||
return SCPE_ARG;
|
||
return SCPE_OK;
|
||
}
|
||
|
||
t_stat
|
||
vt_show_hspace(FILE *st, UNIT *uptr, int32 val, CONST void *desc)
|
||
{
|
||
fprintf(st, "hspace=%s", vt11_csp_w==12 ? "narrow" : "normal");
|
||
return SCPE_OK;
|
||
}
|
||
|
||
t_stat
|
||
vt_set_vspace(UNIT *uptr, int32 val, CONST char *cptr, void *desc)
|
||
{
|
||
char gbuf[CBUFSIZE];
|
||
if (vt11_init)
|
||
return SCPE_ALATT; /* should be "changes locked out" */
|
||
if (cptr == NULL)
|
||
return SCPE_ARG;
|
||
get_glyph(cptr, gbuf, 0);
|
||
if (strcmp(gbuf, "TALL") == 0)
|
||
vt11_csp_h = 26;
|
||
else if (strcmp(gbuf, "NORMAL") == 0)
|
||
vt11_csp_h = 24;
|
||
else
|
||
return SCPE_ARG;
|
||
return SCPE_OK;
|
||
}
|
||
|
||
t_stat
|
||
vt_show_vspace(FILE *st, UNIT *uptr, int32 val, CONST void *desc)
|
||
{
|
||
fprintf(st, "vspace=%s", vt11_csp_h==26 ? "tall" : "normal");
|
||
return SCPE_OK;
|
||
}
|
||
|
||
/* interface routines (called from display simulator) */
|
||
|
||
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);
|
||
}
|
||
|
||
/* fetch memory */
|
||
int
|
||
vt_fetch(uint32 addr, vt11word *wp)
|
||
{
|
||
/* On PDP-11 Unibus 22-bit systems, the VT11/VS60 behaves as
|
||
an 18-bit Unibus peripheral and must go through the I/O map. */
|
||
|
||
/* apply Unibus map, when appropriate */
|
||
|
||
/*
|
||
* The Graphics processor only has a 16 bit program counter
|
||
* (i.e. address register). If this address happens to be >= 56Kb
|
||
* then it is a reference to a graphics program running from
|
||
* ROM and in order for that to be found on an 18 bit Unibus
|
||
* we need to sign extend the the address so it resides in
|
||
* the I/O page.
|
||
*/
|
||
if (addr >= (uint32)(IOPAGEBASE & DMASK)) {
|
||
sim_debug (DEB_VT11, &vt_dev, "vt_fetch(addr=0%o) Adjusting ROM address to 0%o\n", (int)addr, (int)(addr | IOPAGEBASE));
|
||
addr |= IOPAGEBASE;
|
||
}
|
||
if (Map_ReadW(addr, 2, wp) == 0) {
|
||
sim_debug (DEB_VT11, &vt_dev, "vt_fetch(addr=0%o) - 0%o\n", (int)addr, (int)*wp);
|
||
return 0; /* no problem */
|
||
}
|
||
sim_debug (DEB_VT11, &vt_dev, "vt_fetch(addr=0%o) - failed\n", (int)addr);
|
||
/* else mapped address lies outside configured memory range */
|
||
|
||
*wp = 0164000; /* DNOP; just updates DPC if used */
|
||
/* which shouldn't happen */
|
||
return 1; /* used to set "time_out" flag */
|
||
}
|
||
|
||
const char *vt_description (DEVICE *dptr)
|
||
{
|
||
return (VS60) ? "VS60 Display processor"
|
||
: "VT11 Display processor";
|
||
}
|
||
|
||
#ifdef VM_PDP11
|
||
/* PDP-11 simulation provides this */
|
||
extern int32 SR; /* switch register */
|
||
#else
|
||
int32 SR; /* switch register */
|
||
#endif
|
||
|
||
void
|
||
cpu_set_switches(unsigned long v1, unsigned long v2)
|
||
{
|
||
SR = v1 ^ v2;
|
||
}
|
||
|
||
void
|
||
cpu_get_switches(unsigned long *p1, unsigned long *p2)
|
||
{
|
||
*p1 = SR;
|
||
*p2 = 0;
|
||
}
|
||
|
||
t_stat vt_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
|
||
{
|
||
const char helpString[] =
|
||
/* The '*'s in the next line represent the standard text width of a help line */
|
||
/****************************************************************************/
|
||
" The VT11 is a calligraphic display-file device used in the GT4x series\n"
|
||
" of workstations (PDP-11/04,34,40 based).\n\n"
|
||
" The VS60 is an improved, extended, upward-compatible version of the\n"
|
||
" VT11, used in the GT62 workstation (PDP-11/34 based). It supports\n"
|
||
" dual consoles (CRTs with light pens), multiple phosphor colors, 3D\n"
|
||
" depth cueing, and circle/arc generator as options. We do not know\n"
|
||
" whether any of these options were ever implemented or delivered.\n"
|
||
" Apparently a later option substituted a digitizing-tablet correlator\n"
|
||
" for the light pen. The VS60 has a 4-level silo (graphic data pipeline)\n"
|
||
" which for reasons of simplicity is not implemented in this simulation;\n"
|
||
" the only visible effect is that DZVSC diagnostic tests 110 & 111 will\n"
|
||
" report failure.\n\n"
|
||
" The VSV11/VS11 is a color raster display-file device (with joystick\n"
|
||
" instead of light pen) with instructions similar to the VT11's but\n"
|
||
" different enough that a separate emulation should be created by\n"
|
||
" editing a copy of this source file rather than trying to hack it into\n"
|
||
" this one. Very likely, the display (phosphor decay) simulation will\n"
|
||
" also require revision to handle multiple colors.\n\n"
|
||
" There were further models in this series, but they appear to have\n"
|
||
" little if any compatibility with the VT11.\n\n"
|
||
" Much later, DEC produced a display system it called the VS60S, but\n"
|
||
" that doesn't seem to bear any relationship to the original VS60.\n\n"
|
||
" A PDP-11 system has at most one display controller attached.\n\n"
|
||
"1 Booting\n"
|
||
" There are two booting options for the GT40.\n"
|
||
"2 Demo Mode - Lunar Lander\n"
|
||
" The most famous software for the GT40 was the MOONLANDER\n"
|
||
" game by Jack Burness, also known as LUNAR LANDER. This was\n"
|
||
" undoubtedly the inspiration for Atari's coin-operated video\n"
|
||
" game of that name. To play the demo and play the game:\n\n"
|
||
"++sim> set vt enable\n"
|
||
"++sim> boot vt\n\n"
|
||
"3 Playing Lunar Lander\n"
|
||
" The object of moonlander is to land a lunar module on the\n"
|
||
" surface of the moon.\n\n"
|
||
" When the program is loaded, it will automatically start and\n"
|
||
" display an \"introductory message\" on the screen. Future\n"
|
||
" restart of the program will not cause this message to be\n"
|
||
" displayed. All numbers, speeds, weights, etc., are actual\n"
|
||
" numbers. They are for real. To make the game more possible\n"
|
||
" for an average person to play, I have given him about 25 to\n"
|
||
" 50%% more fuel in the final stages of landing than he would\n"
|
||
" actually have.\n\n"
|
||
" What the user sees on the screen is a broad and extremely\n"
|
||
" mountainous view of the moon. On the right is a list of data\n"
|
||
" parameters which the user may examine. They are height,\n"
|
||
" altitude, angle, fuel left, thrust, weight, horizontal\n"
|
||
" velocity, vertical velocity, horizontal acceleration, vertical\n"
|
||
" acceleration, distance and seconds. At the top of the screen,\n"
|
||
" any four of the values may be displayed. To display an item,\n"
|
||
" the user points the mouse at the item he wishes to display.\n"
|
||
" The item will then start blinking, to indicate that this is\n"
|
||
" the item to be displayed. The user then points the mouse at\n"
|
||
" one of the previously displayed items at the top of the screen.\n"
|
||
" The old item disappears and is replaced by the new item.\n"
|
||
" Note that it is possible to display any item anywhere, and even\n"
|
||
" possible to display one item four times at the top. Anyway,\n"
|
||
" the parameters mean the following. Height is the height in\n"
|
||
" feet above the surface (terrain) of the moon. It is the \"radar\"\n"
|
||
" height. Altitude is the height above the \"mean\" height of the\n"
|
||
" moon ( I guess you would call it \"mare\" level). Thus altitude\n"
|
||
" is not affected by terrain. Angle is the angle of the ship in\n"
|
||
" relationship to the vertical. 10 degrees, -70 degrees, etc.\n"
|
||
" Fuel left is the amount of fuel left in pounds. Thrust is the\n"
|
||
" amount of thrust (pounds) currently being produced by the engine.\n"
|
||
" Weight is the current earth weight of the ship. As fuel is\n"
|
||
" burned off, the acceleration will increase due to a lessening of\n"
|
||
" weight. The horizontal velocity is the current horizontal speed\n"
|
||
" of the ship, in feet per second. It is necessary to land at\n"
|
||
" under 10 fps horizontal, or else the ship will tip over.\n"
|
||
" Vertical velocity is the downward speed of the ship. Try to\n"
|
||
" keep it under 30 for the first few landings, until you get\n"
|
||
" better. A perfect landing is under 8 fps. The horizontal\n"
|
||
" and vertical accelerations are just those, in f/sec/sec.\n"
|
||
" With no power, the vertical acceleration is about 5 fp/s/s\n"
|
||
" down (-5). Distance is the horizontal distance (X direction)\n"
|
||
" you are from the projected landing site. Try to stay within\n"
|
||
" 500 feet of this distance, because there are not too many\n"
|
||
" spots suitable for landing on the moon. Seconds is just the\n"
|
||
" time since you started trying to land. Thus you now know how\n"
|
||
" to display information and what they mean.\n\n"
|
||
" To control the ship, two controls are provided. The first\n"
|
||
" controls the rolling or turning of the ship. This is accom-\n"
|
||
" plished by four arrows just above the display menu. Two point\n"
|
||
" left and two point right. The two pointing left mean rotate\n"
|
||
" left and the two pointing right mean rotate right. There is\n"
|
||
" a big and a little one in each direction. The big one means\n"
|
||
" to rotate \"fast\" and the small one means to rotate \"slow\".\n"
|
||
" Thus to rotate fast left, you point the mouse at left arrow.\n"
|
||
" To rotate slow right, you point the mouse at the small arrow\n"
|
||
" pointing to the right. The arrow will get slightly brighter\n"
|
||
" to indicate you have chosen it. Above the arrow there is a\n"
|
||
" bright, solid bar. This bar is your throttle bar. To its\n"
|
||
" left there is a number in percent (say 50%%). This number\n"
|
||
" indicates the percentage of full thrust your rocket engine\n"
|
||
" is developing. The engine can develop anywhere from\n"
|
||
" 10%% to 100%% thrust - full thrust is 10,500 pounds. The\n"
|
||
" engine thrust cannot fall below 10%%. That is the way Grumman\n"
|
||
" built it (actually the subcontractor). To increase or decrease\n"
|
||
" your thrust, you merely slide the mouse up and down the bar.\n"
|
||
" The indicated percentage thrust will change accordingly.\n\n"
|
||
" Now we come to actually flying the beast. The module appears\n"
|
||
" in the upper left hand corner of the screen and is traveling\n"
|
||
" down and to the right. Your job is to land at the correct\n"
|
||
" spot (for the time being, we will say this is when the\n"
|
||
" distance and height both reach zero). The first picture you\n"
|
||
" see, with the module in the upper left hand corner, is not\n"
|
||
" drawn to scale (the module appears too big in relationship\n"
|
||
" to the mountains). Should you successfully get below around\n"
|
||
" 400 feet altitude, the view will now change to a closeup\n"
|
||
" view of the landing site, and everything will be in scale.\n"
|
||
" Remember, it is not easy to land the first few times, but\n"
|
||
" don't be disappointed, you'll do it. Be careful, the game\n"
|
||
" is extremely addictive. It is also quite dynamic.\n\n"
|
||
" Incorporated in the game are just about everything the GT40\n"
|
||
" can do. Letters, italics, light pen letters, a light bar,\n"
|
||
" dynamic motion, various line types and intensities (the moon\n"
|
||
" is not all the same brightness you know). It also shows that\n"
|
||
" the GT40 can do a lot of calculations while maintaining a\n"
|
||
" reasonable display.\n\n"
|
||
" There are three possible landing sites on the Moon:\n\n"
|
||
"+1. On the extreme left of the landscape\n\n"
|
||
"+2. A small flat area to the right of the mountains\n\n"
|
||
"+3. In the large \"flat\" area on the right\n\n"
|
||
" Good Luck!\n\n"
|
||
"2 Terminal Mode\n"
|
||
" The GT40 LSI 11/05 configuration had a boot ROM which allowed the\n"
|
||
" VR14 to be used as a very minimal dumb terminal in order to allow\n"
|
||
" the user to login to the host computer. It watches for the host\n"
|
||
" computer to send a special character sequence to initiate download\n"
|
||
" mode. In download mode it loads a series of memory areas supplied\n"
|
||
" by the host. The data sent in download mode is encoded with six bits\n"
|
||
" per character.\n\n"
|
||
" GT40 Terminal Mode is initiated by:\n\n"
|
||
"++sim> set dli enable\n"
|
||
"++sim> attach dli Line=0,Connect=ipaddr:port\n"
|
||
"++sim> set vt enable\n"
|
||
"++sim> boot -40 vt\n\n"
|
||
"1 Implementation Status\n"
|
||
" Clipping is not implemented properly for arcs.\n\n"
|
||
" This simulation passes all four MAINDEC VS60 diagnostics and the\n"
|
||
" DEC/X11 VS60 system exerciser, with the following exceptions:\n\n"
|
||
" MD-11-DZVSA-A, VS60 instruction test part I, test 161:\n"
|
||
" Failure to time-out an access to a \"nonexistent\" bus address, when the\n"
|
||
" system is configured with so much memory that the probed address\n"
|
||
" actually responds; this is a deficiency in the diagnostic itself.\n\n"
|
||
" MD-11-DZVSB-A, VS60 instruction test part II:\n"
|
||
" No exceptions.\n\n"
|
||
" MD-11-DZVSC-B, VS60 instruction test part III, tests 107,110,111:\n"
|
||
" Memory address test fails under SIMH, due to SIMH not implementing\n"
|
||
" KT11 \"maintenance mode\", in which the final destination address (only)\n"
|
||
" is relocated. When SIMH is patched to fix this, the test still fails\n"
|
||
" due to a bug in the diagnostic itself, namely a call to DPCONV1 which\n"
|
||
" tests a condition code that is supposed to pertain to R0 but which\n"
|
||
" hasn't been set up. Swapping the two instructions before the call to\n"
|
||
" DPCONV1 corrects this, and then this test passes.\n"
|
||
" Graphic silo content tests fail, since the silo pipeline is not\n"
|
||
" simulated; there are no plans to fix this, since it serves no other\n"
|
||
" purpose in this simulation and would adversely affect performance.\n\n"
|
||
" MD-11-DZVSD-B, VS60 visual display test, frame 13:\n"
|
||
" \"O\" character sizes are slightly off, due to optimization for raster\n"
|
||
" display rather than true stroking; there are no plans to change this.\n\n"
|
||
" MD-11-DZVSE-A0, XXDP VS60 visual display exerciser:\n"
|
||
" No visible exceptions. Light-pen interrupts might not be handled\n"
|
||
" right, since they're reported as errors and cause display restart.\n"
|
||
" (XXX Need to obtain source listing to check this.)\n\n"
|
||
;
|
||
return scp_help (st, dptr, uptr, flag, helpString, cptr);
|
||
}
|
||
#else /* USE_DISPLAY not defined */
|
||
char pdp11_vt_unused; /* sometimes empty object modules cause problems */
|
||
#endif /* USE_DISPLAY not defined */
|