1
0
mirror of https://github.com/simh/simh.git synced 2026-04-15 16:11:13 +00:00

Beta Simulators (PDQ-3 and SAGE) from Holger Veit

This commit is contained in:
Mark Pizzolato
2014-09-17 17:31:40 -07:00
parent 7087f1e1c6
commit e2524e7feb
69 changed files with 24440 additions and 4 deletions

BIN
PDQ-3/hdt/CPU_C5.bin Normal file

Binary file not shown.

BIN
PDQ-3/master.imd Normal file

Binary file not shown.

174
PDQ-3/names.sim Normal file
View File

@@ -0,0 +1,174 @@
name CSP:proc53 initdriver
name CSP:proc52 ExtractSegno
name CSP:proc51 getsib
name CSP:proc50 myselfer
name CSP:proc49 S_IOR_Set
name CSP:proc48 S_Read_Seg
name CSP:proc47 S_Chuck_G_Dir
name CSP:proc46 S_Finish_CU
name CSP:proc45 S_Execute_CU
name CSP:proc44 S_Geq_U
name CSP:proc43 S_Blow_Up
name CSP:proc42 S_Bump_Heap
name CSP:proc41 S_R_Mem_Avail
name CSP:proc40 S_Mem_Avail
name CSP:proc39 S_Halt
name CSP:proc38 S_Unit_Clear
name CSP:proc37 S_Unit_Wait
name CSP:proc36 S_Pwr_of_Ten
name CSP:proc35 S_Unit_Busy
name CSP:proc34 S_Io_Result
name CSP:proc33 S_Release
name CSP:proc32 S_Mark
name CSP:proc31 X_Sqrt
name CSP:proc30 X_Exp
name CSP:proc29 X_Ln
name CSP:proc28 S_Unload_Seg
name CSP:proc27 S_Load_Seg
name CSP:proc26 S_Unit_Status
name CSP:proc25 X_Sin
name CSP:proc24 S_Blk_Exit
name CSP:proc23 S_Attach
name CSP:proc22 S_Rel_Seg
name CSP:proc21 S_Get_Seg
name CSP:proc20 S_Stop_P
name CSP:proc19 S_Start_P
name CSP:proc18 S_Check
name CSP:proc17 S_Assign
name CSP:proc16 S_Geq_S
name CSP:proc15 S_Leq_S
name CSP:proc14 S_Equ_S
name CSP:proc13 S_New
name CSP:proc12 S_IO_Check
name CSP:proc11 S_Scan
name CSP:proc10 S_Fill_Char
name CSP:proc9 S_Time
name CSP:proc8 S_Tree_Search
name CSP:proc17 S_Id_Search
name CSP:proc6 S_Unit_Write
name CSP:proc5 S_Unit_Read
name CSP:proc4 S_Exit
name CSP:proc3 S_Move_Right
name CSP:proc2 S_Move_Left
name CSP:proc1 csp_initunit
name GOTOXYU:proc1 gotoxyu_initunit
name GOTOXYU:proc2 Z19_XY
name PASCALIO:proc1 pascalio_initunit
name PASCALIO:proc2 F_Read_Real
name PASCALIO:proc3 F_Write_Real
name PASCALIO:proc4 F_Seek
name LONGINT:proc1 longint_initunit
name LONGINT:proc2 F_Read_Dec
name LONGINT:proc3 F_Write_Dec
name LONGINT:proc4 Decops
name TRANSCEN:proc1 transcen_initunit
name TRANSCEN:proc2 S_Sin
name TRANSCEN:proc3 S_Cos
name TRANSCEN:proc4 S_Log10
name TRANSCEN:proc5 S_Arctan
name TRANSCEN:proc6 S_Ln
name TRANSCEN:proc7 S_Exp
name TRANSCEN:proc8 S_Sqrt
name HEAPOPS:proc1 heapops_initunit
name HEAPOPS:proc2 H_Mark
name HEAPOPS:proc3 H_Release
name HEAPOPS:proc4 H_New
name HEAPOPS:proc5 H_Dispose
name HEAPOPS:proc6 H_Mem_Lock
name HEAPOPS:proc7 H_Mem_Swap
name HEAPOPS:proc8 H_Var_New
name HEAPOPS:proc9 H_Var_Dispose
name HEAPOPS:proc10 H_Var_Avail
name HEAPOPS:proc11 H_Unlock_Seg
name HEAPOPS:proc12 H_Clean_Up
name EXCEPTIO:proc1 exceptio_initunit
name EXCEPTIO:proc2 Handle_Exception
name EXCEPTIN:proc1 exceptin_initunit
name EXCEPTIN:proc2 Ex_Stats
name HALTUNIT:proc1 haltunit_initunit
name HALTUNIT:proc2 Do_Halt
name CLOCKDRI:proc1 clockdri_initunit
name CLOCKDRI:proc2 Clk_Init
name CLOCKDRI:proc3 Clk_Read
name CLOCKDRI:proc4 Clk_Write
name CLOCKDRI:proc5 Clk_Clear
name CLOCKDRI:proc6 Clk_Power
name CLOCKDRI:proc7 Clk_Status
name CLOCKDRI:proc8 Clk_Term
name DTCDRIVE:proc1 dtcdrive_initunit
name DTCDRIVE:proc2 Dtc_Init
name DTCDRIVE:proc3 Dtc_Read
name DTCDRIVE:proc4 Dtc_Write
name DTCDRIVE:proc5 Dtc_Clear
name DTCDRIVE:proc6 Dtc_Power
name DTCDRIVE:proc7 Dtc_Status
name DTCDRIVE:proc8 Dtc_Term
name DZ11DRIV:proc1 dz11driv_initunit
name DZ11DRIV:proc2 DZ_Init
name DZ11DRIV:proc3 DZ_Read
name DZ11DRIV:proc4 DZ_Write
name DZ11DRIV:proc5 DZ_Clear
name DZ11DRIV:proc6 DZ_Power
name DZ11DRIV:proc7 DZ_Status
name DZ11DRIV:proc8 DZ_Term
name FLOPPYDR:proc1 floppydr_initunit
name FLOPPYDR:proc2 Fl_Init
name FLOPPYDR:proc3 Fl_Read
name FLOPPYDR:proc4 Fl_Write
name FLOPPYDR:proc5 Fl_Clear
name FLOPPYDR:proc6 Fl_Power
name FLOPPYDR:proc7 Fl_Status
name FLOPPYDR:proc8 Fl_Term
name PRIAMDRI:proc1 priamdri_initunit
name PRIAMDRI:proc2 Prm_Init
name PRIAMDRI:proc3 Prm_Read
name PRIAMDRI:proc4 Prm_Write
name PRIAMDRI:proc5 Prm_Clear
name PRIAMDRI:proc6 Prm_Power
name PRIAMDRI:proc7 Prm_Status
name PRIAMDRI:proc8 Prm_Term
name RL02DRIV:proc1 rl02driv_initunit
name RL02DRIV:proc2 RL_Init
name RL02DRIV:proc3 RL_Read
name RL02DRIV:proc4 RL_Write
name RL02DRIV:proc5 RL_Clear
name RL02DRIV:proc6 RL_Power
name RL02DRIV:proc7 RL_Status
name RL02DRIV:proc8 RL_Term
name SERDRIVE:proc1 serdrive_initunit
name SERDRIVE:proc2 Ser_Init
name SERDRIVE:proc3 Ser_Read
name SERDRIVE:proc4 Ser_Write
name SERDRIVE:proc5 Ser_Clear
name SERDRIVE:proc6 Ser_Power
name SERDRIVE:proc7 Ser_Status
name SERDRIVE:proc8 Ser_Term
name STANDRIV:proc1 standriv_initunit
name STANDRIV:proc2 Stan_Init
name STANDRIV:proc3 Stan_Read
name STANDRIV:proc4 Stan_Write
name STANDRIV:proc5 Stan_Clear
name STANDRIV:proc6 Stan_Power
name STANDRIV:proc7 Stan_Status
name STANDRIV:proc8 Stan_Term
name SYSDRIVE:proc1 sysdrive_initunit
name SYSDRIVE:proc2 Intr_Init
name SYSDRIVE:proc3 Intr_Enable
name SYSDRIVE:proc4 Enter_HDT
name TM11DRIV:proc1 standriv_initunit
name TM11DRIV:proc2 TM_Init
name TM11DRIV:proc3 TM_Read
name TM11DRIV:proc4 TM_Write
name TM11DRIV:proc5 TM_Clear
name TM11DRIV:proc6 TM_Power
name TM11DRIV:proc7 TM_Status
name TM11DRIV:proc8 TM_Term
name SPOOLUNI:proc1 spooluni_initunit
name SPOOLUNI:proc2 Spool_Status
name SPOOLUNI:proc3 Spool_Restart
name SPOOLUNI:proc4 Spool_Stop
name SPOOLUNI:proc5 Spool_File
name SHELL:proc1 SHELL_initunit
name GETCMD:proc1 GETCMD_initunit
name SERDRIVE:proc9 SER_EnDis_RCVXMIT
name SERDRIVE:proc16 SER_RawEmit

232
PDQ-3/opcode.dbg Normal file
View File

@@ -0,0 +1,232 @@
0 0 ;SLDC0
1 0 ;SLDC1
2 0 ;SLDC2
3 0 ;SLDC3
4 0 ;SLDC4
5 0 ;SLDC5
6 0 ;SLDC6
7 0 ;SLDC7
8 0 ;SLDC8
9 0 ;SLDC9
a 0 ;SLDC10
b 0 ;SLDC11
c 0 ;SLDC12
d 0 ;SLDC13
e 0 ;SLDC14
f 0 ;SLDC15
10 0 ;SLDC16
11 0 ;SLDC17
12 0 ;SLDC18
13 0 ;SLDC19
14 0 ;SLDC20
15 0 ;SLDC21
16 0 ;SLDC22
17 0 ;SLDC23
18 0 ;SLDC24
19 0 ;SLDC25
1a 0 ;SLDC26
1b 0 ;SLDC27
1c 0 ;SLDC28
1d 0 ;SLDC29
1e 0 ;SLDC30
1f 0 ;SLDC31
20 0 ;SLDL1
21 0 ;SLDL2
22 0 ;SLDL3
23 0 ;SLDL4
24 0 ;SLDL5
25 0 ;SLDL6
26 0 ;SLDL7
27 0 ;SLDL8
28 0 ;SLDL9
29 0 ;SLDL10
2a 0 ;SLDL11
2b 0 ;SLDL12
2c 0 ;SLDL13
2d 0 ;SLDL14
2e 0 ;SLDL15
2f 0 ;SLDL16
30 0 ;SLDO1
31 0 ;SLDO2
32 0 ;SLDO3
33 0 ;SLDO4
34 0 ;SLDO5
35 0 ;SLDO6
36 0 ;SLDO7
37 0 ;SLDO8
38 0 ;SLDO9
39 0 ;SLDO10
3a 0 ;SLDO11
3b 0 ;SLDO12
3c 0 ;SLDO13
3d 0 ;SLDO14
3e 0 ;SLDO15
3f 0 ;SLDO16
40 3 ;
41 3 ;
42 3 ;
43 3 ;
44 3 ;
45 3 ;
46 3 ;
47 3 ;
48 3 ;
49 3 ;
4a 3 ;
4b 3 ;
4c 3 ;
4d 3 ;
4e 3 ;
4f 3 ;
50 3 ;
51 3 ;
52 3 ;
53 3 ;
54 3 ;
55 3 ;
56 3 ;
57 3 ;
58 3 ;
59 3 ;
5a 3 ;
5b 3 ;
5c 3 ;
5d 3 ;
5e 3 ;
5f 3 ;
60 3 ;
61 3 ;
62 3 ;
63 3 ;
64 3 ;
65 3 ;
66 3 ;
67 3 ;
68 3 ;
69 3 ;
6a 3 ;
6b 3 ;
6c 3 ;
6d 3 ;
6e 3 ;
6f 3 ;
70 3 ;
71 3 ;
72 3 ;
73 3 ;
74 3 ;
75 3 ;
76 3 ;
77 3 ;
78 0 ;SIND0
79 0 ;SIND1
7a 0 ;SIND2
7b 0 ;SIND3
7c 0 ;SIND4
7d 0 ;SIND5
7e 0 ;SIND6
7f 0 ;SIND7
80 0 ;LDCB
81 0 ;LDCI
82 0 ;LCA
83 0 ;LDC
84 0 ;LLA
85 3 ;LDO
86 0 ;LAO
87 0 ;LDL
88 0 ;LDA
89 0 ;LOD
8a 0 ;UJP
8b 0 ;UJPL
8c 0 ;MPI
8d 0 ;DVI
8e 0 ;STM
8f 0 ;MODI
90 0 ;CPL
91 0 ;CPG
92 0 ;CPI
93 0 ;CXL
94 0 ;CXG
95 0 ;CXI
96 0 ;RPU
97 0 ;CPF
98 0 ;LDCN
99 0 ;LSL
9a 3 ;LDE
9b 3 ;LAE
9c 0 ;NOP
9d 0 ;LPR
9e 3 ;BPT
9f 0 ;BNOT
a0 0 ;LOR
a1 0 ;LAND
a2 0 ;ADI
a3 0 ;SBI
a4 0 ;STL
a5 0 ;SRO
a6 0 ;STR
a7 0 ;LDB
a8 3 ;
a9 3 ;
aa 3 ;
ab 3 ;
ac 3 ;
ad 3 ;
ae 3 ;
af 3 ;
b0 0 ;EQUI
b1 0 ;NEQI
b2 0 ;LEQI
b3 0 ;GEQI
b4 0 ;LEUSW
b5 0 ;GEUSW
b6 0 ;EQUPWR
b7 0 ;LEQPWR
b8 0 ;GEQPWR
b9 0 ;EQUBYT
ba 3 ;LEQBYT
bb 3 ;GEQBYT
bc 0 ;SRS
bd 3 ;SWAP
be 3 ;TNC
bf 3 ;RND
c0 3 ;ADR
c1 3 ;SBR
c2 3 ;MPR
c3 0 ;DVR
c4 0 ;STO
c5 0 ;MOV
c6 3 ;DUP2
c7 0 ;ADJ
c8 0 ;STB
c9 0 ;LDP
ca 0 ;STP
cb 0 ;CHK
cc 0 ;FLT
cd 0 ;EQUREAL
ce 0 ;LEQREAL
cf 3 ;GEQREAL
d0 0 ;LDM
d1 0 ;SPR
d2 3 ;EFJ
d3 3 ;NFJ
d4 0 ;FJP
d5 0 ;FJPL
d6 0 ;XJP
d7 0 ;IXA
d8 0 ;IXP
d9 3 ;STE
da 0 ;INN
db 0 ;UNI
dc 0 ;INT
dd 0 ;DIF
de 0 ;SIGNAL
df 0 ;WAIT
e0 3 ;ABI
e1 0 ;NGI
e2 0 ;DUP1
e3 3 ;ABR
e4 3 ;NGR
e5 0 ;LNOT
e6 0 ;IND
e7 0 ;INC

1733
PDQ-3/pdq3_cpu.c Normal file

File diff suppressed because it is too large Load Diff

441
PDQ-3/pdq3_debug.c Normal file
View File

@@ -0,0 +1,441 @@
/* pdq3_debug.c: PDQ3 debug helper
Work derived from Copyright (c) 2004-2012, Robert M. Supnik
Copyright (c) 2013 Holger Veit
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
ROBERT M SUPNIK 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 Robert M Supnik and Holger Veit
shall not be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik and Holger Veit.
20130421 hv initial version
20130928 hv fix problem with callstack when S_Start_P patches MSCW
20131012 hv view calltree returned incorrect segment of caller
*/
#include "pdq3_defs.h"
static uint8 *opdebug = NULL;
static void dbg_opdbgcreate() {
int i;
FILE *fd = fopen(DEBUG_OPDBGFILE, "w");
if (fd==NULL) {
fprintf(stderr,"Cannot create %s\n", DEBUG_OPDBGFILE);
exit(1);
}
for (i=DEBUG_MINOPCODE; i<DEBUG_MAXOPCODE; i++) {
if (DEBUG_VALIDOP(i)) {
fprintf(fd,"%x %d ;%s\n",
i, DEBUG_PRE|DEBUG_POST, optable[i].name);
} else {
fprintf(fd,"%x %d ;invalid\n",
i, DEBUG_PRE|DEBUG_POST);
}
}
fclose(fd);
fprintf(stderr,"%s created. Adapt file manually and restart simh\n", DEBUG_OPDBGFILE);
exit(2);
}
static void dbg_opdbginit() {
char line[100];
int i, f;
FILE* fd = fopen(DEBUG_OPDBGFILE,"r");
if (fd == NULL)
dbg_opdbgcreate(); /* will not return */
if (opdebug == NULL)
opdebug = (uint8*)calloc(DEBUG_MAXOPCODE-DEBUG_MINOPCODE,sizeof(uint8));
for (i=DEBUG_MINOPCODE; i<DEBUG_MAXOPCODE; i++)
opdebug[i-DEBUG_MINOPCODE] = DEBUG_PRE|DEBUG_POST;
while (!feof(fd)) {
fgets(line,100,fd);
sscanf(line,"%x %d", &i, &f);
opdebug[i-DEBUG_MINOPCODE] = f;
}
fclose(fd);
}
t_stat dbg_check(t_value op, uint8 flag) {
if (opdebug[op-DEBUG_MINOPCODE] & flag) {
if (flag & DEBUG_PRE) {
opdebug[op-DEBUG_MINOPCODE] &= ~DEBUG_PRE;
return STOP_DBGPRE;
} else
return STOP_DBGPOST;
}
return SCPE_OK;
}
t_stat dbg_dump_tib(FILE *fd, uint16 base) {
t_stat rc;
uint16 data;
fprintf(fd, "TIB at $%04x (CTP=$%04x, RQ=$%04x)\n",base, reg_ctp, reg_rq);
if ((rc=ReadEx(base, OFF_WAITQ, &data)) != SCPE_OK) return rc;
fprintf(fd, " WAITQ: $%04x\n",data);
if ((rc=ReadBEx(base+OFFB_PRIOR, 0, &data)) != SCPE_OK) return rc;
fprintf(fd, " PRIOR: %02x\n",data);
if ((rc=ReadEx(base, OFF_SPLOW, &data)) != SCPE_OK) return rc;
fprintf(fd, " SPLOW: $%04x\n",data);
if ((rc=ReadEx(base, OFF_SPUPR, &data)) != SCPE_OK) return rc;
fprintf(fd, " SPUPR: $%04x\n",data);
if ((rc=ReadEx(base, OFF_SP, &data)) != SCPE_OK) return rc;
fprintf(fd, " SP: $%04x\n",data);
if ((rc=ReadEx(base, OFF_MP, &data)) != SCPE_OK) return rc;
fprintf(fd, " MP: $%04x\n",data);
if ((rc=ReadEx(base, OFF_BP, &data)) != SCPE_OK) return rc;
fprintf(fd, " BP: $%04x\n",data);
if ((rc=ReadEx(base, OFF_IPC, &data)) != SCPE_OK) return rc;
fprintf(fd, " IPC: #%04x\n",data);
if ((rc=ReadEx(base, OFF_SEGB, &data)) != SCPE_OK) return rc;
fprintf(fd, " SEGB: $%04x\n",data);
if ((rc=ReadEx(base, OFF_HANGP, &data)) != SCPE_OK) return rc;
fprintf(fd, " HANGP: $%04x\n",data);
if ((rc=ReadEx(base, OFF_IORSLT, &data)) != SCPE_OK) return rc;
fprintf(fd, " IORSLT: %04x\n",data);
if ((rc=ReadEx(base, OFF_SIBS, &data)) != SCPE_OK) return rc;
fprintf(fd, " SIBS: $%04x\n",data);
return SCPE_OK;
}
t_stat dbg_dump_queue(FILE* fd, const char* qname, uint16 q) {
t_stat rc;
fprintf(fd, "dump queue %s: address=$%04x\n ",qname, q);
while (q != NIL) {
fprintf(fd, "$%04x->",q);
if ((rc=ReadEx(q, OFF_WAITQ, &q)) != SCPE_OK) return rc;
}
fprintf(fd, "NIL\n");
return SCPE_OK;
}
t_stat dbg_dump_mscw(FILE* fd, uint16 base) {
t_stat rc;
uint16 data;
fprintf(fd, "MSCW at $%04x\n",base);
if ((rc=ReadEx(base, OFF_MSSTAT, &data)) != SCPE_OK) return rc;
fprintf(fd, " MSSTAT: $%04x\n", data);
if ((rc=ReadEx(base, OFF_MSDYNL, &data)) != SCPE_OK) return rc;
fprintf(fd, " MSDYNL: $%04x\n", data);
if ((rc=ReadEx(base, OFF_MSIPC, &data)) != SCPE_OK) return rc;
fprintf(fd, " MSIPC: $%04x\n", data);
if ((rc=ReadBEx(base+OFFB_MSSEG, 0, &data)) != SCPE_OK) return rc;
fprintf(fd, " MSSEG: %02x\n", data);
return SCPE_OK;
}
void dbg_enable() {
cpu_dev.dctrl |= (DBG_CPU_READ|DBG_CPU_WRITE|DBG_CPU_STACK);
}
/******************************************************************************
* Segment Tracking support
*****************************************************************************/
static char* pdq3_segname(uint16 nameptr) {
static char name[10];
uint16 data;
int i;
for (i=0; i<8; i++) {
ReadBEx(nameptr,i,&data);
name[i] = data != ' ' ? data : 0;
}
name[8] = 0;
return name;
}
t_stat dbg_dump_seg(FILE* fd, uint16 segptr) {
t_stat rc;
uint16 data;
if ((rc=ReadEx(segptr, OFF_SEGBASE, &data)) != SCPE_OK) return rc;
fprintf(fd, " BASE: $%04x\n",data);
if ((rc=ReadEx(segptr, OFF_SEGLENG, &data)) != SCPE_OK) return rc;
fprintf(fd, " LENGTH: $%04x\n",data);
if ((rc=ReadEx(segptr, OFF_SEGREFS, &data)) != SCPE_OK) return rc;
fprintf(fd, " REFS: $%04x\n",data);
if ((rc=ReadEx(segptr, OFF_SEGADDR, &data)) != SCPE_OK) return rc;
fprintf(fd, " ADDR: $%04x\n",data);
if ((rc=ReadEx(segptr, OFF_SEGUNIT, &data)) != SCPE_OK) return rc;
fprintf(fd, " UNIT: $%04x\n",data);
if ((rc=ReadEx(segptr, OFF_PREVSP, &data)) != SCPE_OK) return rc;
fprintf(fd, " PREVSP: $%04x\n",data);
fprintf(fd, " NAME: %s\n", pdq3_segname(segptr+OFF_SEGNAME));
if ((rc=ReadEx(segptr, OFF_SEGLINK, &data)) != SCPE_OK) return rc;
fprintf(fd, " LINK: $%04x\n",data);
if ((rc=ReadEx(segptr, OFF_SEGGLOBAL, &data)) != SCPE_OK) return rc;
fprintf(fd, " GLOBAL: $%04x\n",data);
if ((rc=ReadEx(segptr, OFF_SEGINIT, &data)) != SCPE_OK) return rc;
fprintf(fd, " INIT: $%04x\n",data);
if ((rc=ReadEx(segptr, OFF_SEG13, &data)) != SCPE_OK) return rc;
fprintf(fd, " entry13: $%04x\n",data);
if ((rc=ReadEx(segptr, OFF_SEGBACK, &data)) != SCPE_OK) return rc;
fprintf(fd, " SELF: $%04x\n",data);
return SCPE_OK;
}
t_stat dbg_dump_segtbl(FILE* fd) {
int i;
uint16 segptr, nsegs;
t_stat rc;
if (reg_ssv < 0x2030 || reg_ssv > 0xf000) {
printf("Cannot list segments in bootloader: incomplete tables\n");
return SCPE_NXM;
}
if ((rc=Read(reg_ssv, -1, &nsegs, 0)) != SCPE_OK) return rc;
fprintf(fd, "Segment table: ssv=$%04x size=%d\n",reg_ssv, nsegs);
for (i=0; i<=nsegs; i++) {
if ((rc=ReadEx(reg_ssv, i, &segptr)) != SCPE_OK) return rc;
fprintf(fd, " %02x %04x %s\n",i,segptr, pdq3_segname(segptr + OFF_SEGNAME));
}
return SCPE_OK;
}
/* segment tracking */
typedef struct _seginfo {
uint16 base; /* base load address */
struct _seginfo* next;
uint16 idx; /* index into SSV table */
char name[10]; /* segment name */
uint16 size;
uint16 nproc;
uint16 segno;
} SEGINFO;
#define SEGHASHSIZE 97
SEGINFO* seghash[SEGHASHSIZE];
#define SEGHASHFUNC(i) (i % SEGHASHSIZE)
void dbg_segtrackinit() {
int i;
for (i=0; i<SEGHASHSIZE; i++)
seghash[i] = NULL;
}
static SEGINFO* new_seginfo(SEGINFO* next, uint16 base) {
SEGINFO* s = (SEGINFO*)malloc(sizeof(SEGINFO));
s->next = next;
s->base = base;
return s;
}
static SEGINFO* find_seginfo(uint16 base, int* idx) {
SEGINFO* s;
*idx = SEGHASHFUNC(base);
s = seghash[*idx];
while (s && s->base != base) s = s->next;
return s;
}
t_stat dbg_segtrack(uint16 segbase) {
t_stat rc;
int idx;
SEGINFO* s = find_seginfo(segbase, &idx);
if (!s) {
s = seghash[idx] = new_seginfo(seghash[idx], segbase);
if ((rc=ReadEx(segbase, 0, &s->size)) != SCPE_OK) return rc;
strcpy(s->name, segbase==0xf418 ? "HDT" : pdq3_segname(segbase+2));
if ((rc=ReadBEx(segbase+s->size, 0, &s->segno)) != SCPE_OK) return rc;
if ((rc=ReadBEx(segbase+s->size, 1, &s->nproc)) != SCPE_OK) return rc;
// printf("Entered at %04x: %s sz=%x seg=%x np=%x\n",segbase, s->name, s->size, s->segno, s->nproc);
}
return SCPE_OK;
}
/******************************************************************************
* Name Alias Handling
*****************************************************************************/
typedef struct _aliases {
char* key;
char* alias;
struct _aliases* next;
} ALIASES;
#define ALIASHASHSIZE 97
static ALIASES* aliases[ALIASHASHSIZE];
static void dbg_initaliases() {
int i;
for (i=0; i<ALIASHASHSIZE; i++)
aliases[i] = NULL;
}
static int aliashash(const char* key) {
int i, h=0;
int len = strlen(key);
for (i=0; i<len; i++)
h += key[i];
return h % ALIASHASHSIZE;
}
static ALIASES* find_alias(const char* key, int* idx) {
ALIASES* a;
char gbuf[CBUFSIZE], gbuf2[CBUFSIZE];
get_glyph(key, gbuf, 0);
*idx = aliashash(key);
a = aliases[*idx];
if (a) get_glyph(a->key, gbuf2, 0);
while (a && strcmp(gbuf2,gbuf)) {
a = a->next;
if (a) get_glyph(a->key, gbuf2, 0);
}
return a;
}
t_stat dbg_enteralias(const char* key, const char* value) {
int idx;
ALIASES* a = find_alias(key, &idx);
if (!a) {
a = (ALIASES*)malloc(sizeof(ALIASES));
a->key = strdup(key);
a->alias = strdup(value);
a->next = aliases[idx];
aliases[idx] = a;
}
return SCPE_OK;
}
t_stat dbg_listalias(FILE* fd) {
int i;
ALIASES* a;
fprintf(fd, "Name table:\n");
for (i=0; i<ALIASHASHSIZE; i++) {
a = aliases[i];
while (a) {
fprintf(fd, " Name %s = %s\n", a->key, a->alias);
a = a->next;
}
}
return SCPE_OK;
}
/******************************************************************************
* Procedure tracking support
*****************************************************************************/
typedef struct _procinfo {
struct _procinfo *next;
uint16 procno;
SEGINFO* seg;
uint16 localsz;
uint16 freesz;
uint16 mscw;
uint16 segb;
uint16 instipc;
uint16 ipc;
} PROCINFO;
const char* find_procname(PROCINFO* p) {
ALIASES* a;
int dummy;
static char buf[100];
sprintf(buf,"%s:proc%d", p->seg->name, p->procno);
a = find_alias(buf, &dummy);
if (a) return a->alias;
return buf;
}
static PROCINFO* procroot = NULL;
static PROCINFO* new_procinfo(uint16 segbase, uint16 procno, uint16 mscw, uint16 osegb) {
int dummy;
uint16 procbase, procaddr;
uint16 exitic, sz1, sz2;
PROCINFO* p = (PROCINFO*)malloc(sizeof(PROCINFO));
p->procno = procno;
p->mscw = mscw;
p->seg = find_seginfo(segbase, &dummy);
p->segb = osegb;
p->instipc = ADDR_OFF(PCX);
ReadEx(mscw,OFF_MSIPC, &p->ipc);
ReadEx(segbase, 0, &procbase);
ReadEx(segbase+procbase-procno, 0, &procaddr);
ReadEx(segbase+procaddr, 0, &p->localsz);
ReadEx(segbase+procaddr-1, 0, &exitic);
ReadBEx(segbase, exitic, &sz1);
if (sz1==0x96) {
ReadBEx(segbase, exitic+1, &sz1);
if (sz1 & 0x80) {
ReadBEx(segbase, exitic+2, &sz2);
sz1 = ((sz1 & 0x7f)<<8) | sz2;
}
p->freesz = sz1;
}
return p;
}
t_stat dbg_procenter(uint16 segbase, uint16 procno, uint16 mscw, uint16 osegb) {
PROCINFO* p = new_procinfo(segbase, procno, mscw, osegb);
p->next = procroot;
procroot = p;
return SCPE_OK;
}
t_stat dbg_procleave() {
t_stat rc;
PROCINFO* p = procroot;
uint16 ipc,pipc;
while (p) {
pipc = p->ipc;
if ((rc=ReadEx(p->mscw,OFF_MSIPC, &ipc)) != SCPE_OK) return rc;
procroot = p->next;
free(p);
if (pipc == ipc) break;
p = procroot;
}
return SCPE_OK;
}
t_stat dbg_calltree(FILE* fd) {
PROCINFO* p = procroot, *lastp;
if (!p) {
fprintf(fd,"Callstack is empty\n");
return SCPE_OK;
}
fprintf(fd,"Calltree:\nCurrently in %s at %04x:%04x\n",
find_procname(p), reg_segb, reg_ipc);
lastp = p;
p = p->next;
while (p) {
fprintf(fd," at %04x:%04x called by %s (%04x:%04x)\n",
lastp->segb, lastp->instipc, find_procname(p), p->segb, p->instipc);
lastp = p;
p = p->next;
}
return SCPE_OK;
}
/******************************************************************************
* Initialization
*****************************************************************************/
t_stat dbg_init() {
dbg_opdbginit();
dbg_segtrackinit();
return SCPE_OK;
}

415
PDQ-3/pdq3_defs.h Normal file
View File

@@ -0,0 +1,415 @@
/* pdq3_defs.h: PDQ3 simulator definitions
Work derived from Copyright (c) 2004-2012, Robert M. Supnik
Copyright (c) 2013 Holger Veit
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
ROBERT M SUPNIK 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 Robert M Supnik and Holger Veit
shall not be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik and Holger Veit.
20131103 hv INT_CONR/CONT assignments incorrect in docs, must be swapped
*/
#ifndef _PDQ3_DEFS_H_
#define _PDQ3_DEFS_H_ 0
#include "sim_defs.h" /* simulator defns */
#include "sim_sock.h"
#include "sim_tmxr.h"
/* constants */
#define NIL 0xfc00 /* Pascal Microengine NIL value */
#define MSCW_SZ 4 /* size of MSCW */
#define REAL_SZ 2 /* size of real number (REAL*4) */
#define BSET_SZ 4080 /* usable size of set in bits */
#define ISET_SZ 255 /* size of set in words */
#define WORD_SZ 16 /* size of machine word in bits */
#define OFF_SEGBASE 0 /* offsets into SIB entry */
#define OFF_SEGLENG 1
#define OFF_SEGREFS 2
#define OFF_SEGADDR 3
#define OFF_SEGUNIT 4
#define OFF_PREVSP 5
#define OFF_SEGNAME 6
#define OFF_SEGLINK 10
#define OFF_SEGGLOBAL 11
#define OFF_SEGINIT 12
#define OFF_SEG13 13
#define OFF_SEGBACK 14
#define OFF_MSSTAT 0 /* offsets into MSCW */
#define OFF_MSDYNL 1
#define OFF_MSIPC 2
#define OFFB_MSSEG 3
#define OFFB_MSFLAG 3
#define OFF_WAITQ 0 /* offset into TIB */
#define OFF_QLINK 0
#define OFFB_PRIOR 1
#define OFFB_FLAGS 1
#define OFF_SPLOW 2
#define OFF_SPUPR 3
#define OFF_SP 4
#define OFF_MP 5
#define OFF_BP 6
#define OFF_IPC 7
#define OFF_SEGB 8
#define OFF_HANGP 9
#define OFF_IORSLT 10
#define OFF_SIBS 11
#define OFF_SEMCOUNT 0 /* offset into SEMA variable */
#define OFF_SEMWAITQ 1
#define SSR_BERR 0x01 /* bits of system status register */
#define SSR_TICK 0x02
#define SSR_INTVL 0x04
#define SSR_BIT3 0x08
#define SSR_PWRF 0x10
#define SSR_PRNT 0x20
#define SSR_INTEN 0x40
#define SSR_INIT 0x80
/* fixed interrupts */
#define INT_BERR 0 /* interrupt levels */
#define INT_PWRF 1
#define INT_DMAFD 2
#define INT_CONR 3 /* Appendix B.0.1 has CONT and CONR swapped, see Errata */
#define INT_CONT 4
#define INT_PRNT 5
#define INT_TICK 6
#define INT_INTVL 7
/* assignable QBUS interrupts, daisy-chained - highest prio = 8, lowest = 31 */
#define INT_QBUS8 8
#define INT_QBUS9 9
#define INT_QBUS10 10
#define INT_QBUS11 11
#define INT_QBUS12 12
#define INT_QBUS13 13
#define INT_QBUS14 14
#define INT_QBUS15 15
#define INT_QBUS16 16
#define INT_QBUS17 17
#define INT_QBUS18 18
#define INT_QBUS19 19
#define INT_QBUS20 20
#define INT_QBUS21 21
#define INT_QBUS22 22
#define INT_QBUS23 23
#define INT_QBUS24 24
#define INT_QBUS25 25
#define INT_QBUS26 26
#define INT_QBUS27 27
#define INT_QBUS28 28
#define INT_QBUS29 29
#define INT_QBUS30 30
#define INT_QBUS31 31
/* common unit user-defined attributes */
#define u_unitno u3
/* Memory */
#define MEMSIZE 65536 /* memory size in bytes */
#define MAXMEMSIZE (65535 * 2) /* maximum memory size in bytes */
#define memorysize uptr->capac
/* CPU Unit flags */
#define UNIT_V_PDQ3 (UNIT_V_UF + 0)
#define UNIT_V_MSIZE (UNIT_V_UF + 1)
#define UNIT_V_PASEXC (UNIT_V_UF + 2)
#define UNIT_PDQ3 (1u << UNIT_V_PDQ3)
#define UNIT_MSIZE (1u << UNIT_V_MSIZE)
#define UNIT_PASEXC (1u << UNIT_V_PASEXC)
#define Q_PDQ3 (cpu_unit.flags & UNIT_PDQ3)
#define Q_MSIZE (cpu_unit.flags & UNIT_MSIZE)
#define Q_PASEXC (cpu_unit.flags & UNIT_PASEXC)
#define setbit(reg,val) reg |= (val)
#define clrbit(reg,val) reg &= ~(val)
#define isbitset(reg, val) (reg & (val))
#define isbitclr(reg, val) ((reg & (val)) == 0)
/* debug flags */
#define DBG_NONE 0x0000
#define DBG_FD_CMD 0x0001
#define DBG_FD_READ 0x0002
#define DBG_FD_WRITE 0x0004
#define DBG_FD_SVC 0x0008
#define DBG_FD_IMD 0x0010
#define DBG_FD_IMD2 0x0020 /* deep inspection */
#define DBG_FD_DMA 0x0040
#define DBG_FD_DMA2 0x0080 /* deep inspection */
//define DBG_CPU_TRACE 0x0001 unused
#define DBG_CPU_INT 0x0001
#define DBG_CPU_INT2 0x0002 /* deep inspection */
#define DBG_CPU_READ 0x0004
#define DBG_CPU_WRITE 0x0008
#define DBG_CPU_FETCH 0x0010
#define DBG_CPU_PUSH 0x0020
#define DBG_CPU_POP 0x0040
#define DBG_CPU_PICK 0x0080
#define DBG_CPU_STACK (DBG_CPU_PUSH|DBG_CPU_POP|DBG_CPU_PICK)
#define DBG_CPU_CONC 0x0100
#define DBG_CPU_CONC2 0x0200 /* deep inspection */
#define DBG_CPU_CONC3 0x0400 /* even deeper inspection */
#define DBG_CON_READ 0x0001
#define DBG_CON_WRITE 0x0002
#define DBG_CON_SVC 0x0004
#define DBG_TIM_READ 0x0001
#define DBG_TIM_WRITE 0x0002
#define DBG_TIM_SVC 0x0004
#define DBG_PCFORMAT0 "[%04x:%04x] "
#define DBG_PCFORMAT1 " [%04x:%04x] "
#define DBG_PCFORMAT2 " [%04x:%04x] "
#define DBG_PC reg_segb,ADDR_OFF(PCX)
#define DBG_PC2 reg_segb,reg_ipc
/* calibration timers */
#define TMR_CONPOLL 0
/* console sio data rates */
#define CON_POLLUNIT 0
#define CON_TERMUNIT 1
#define CON_POLLFIRST 1 /* immediate */
#define CON_POLLRATE 100
#define CON_POLLWAIT 12500
//#define CON_TERMRATE 1300
#define CON_TERMRATE 300
/* floppy size */
#define FDC_MAX_TRACKS 77
/* IMD anachronism */
#ifndef MAX_COMMENT_LEN
#define MAX_COMMENT_LEN 256
#endif
/* XXX @TODO Pascal error codes (Raise()) */
#define PASERROR_SYSTEM 0
#define PASERROR_VALRANGE 1
#define PASERROR_NOSEG 2
#define PASERROR_PROCERR 3
#define PASERROR_STKOVFL 4
#define PASERROR_INTOVFL 5
#define PASERROR_DIVZERO 6
#define PASERROR_MEMERR 7
#define PASERROR_USERBRK 8
#define PASERROR_SYSIO 9
#define PASERROR_USERIO 10
#define PASERROR_UNIMPL 11
#define PASERROR_FPERR 12
#define PASERROR_STRINGOVFL 13
#define PASERROR_HALT 14
/* simh error codes */
#define STOP_IBKPT 1
#define STOP_MEM 2
#define STOP_ERROP 3
#define STOP_ERRADR 4
#define STOP_ERRIO 5
#define STOP_IMPL 6
#define STOP_BPT 7
#define STOP_DBGPRE 8
#define STOP_DBGPOST 9
#define STOP_PASEXC 10
/* IO addresses and vectors */
#define CON_IOBASE 0xfc10
#define CON_RCV_VEC 0x0012
#define CON_XMT_VEC 0x000e
#define CON_PRT_VEC 0x0016
#define SES_IOBASE 0xfc18
#define SES_BERR_VEC 0x0002
#define SES_PWRF_VEC 0x0006
#define SSR_IOBASE 0xfc24
#define TIM_IOBASE 0xfc20
#define TIM_TICK_VEC 0x001a
#define TIM_INTVL_VEC 0x001e
#define FDC_IOBASE 0xfc30
#define FDC_VEC 0x000a
#define CPU_SERIALNO 0xf5ff /* is part of ROM */
#define ROM_BASE 0xfc68
#define ROM 0xf400
#define ROM_SIZE 0x01ff /* excluding serial number */
/* address calculations */
#define ADDRMASK_SEG 0xffff0000
#define ADDRMASK_OFF 0x0000ffff
#define ADDR_16bit(a) ((a) & 0x0000ffff)
#define ADDR_SEG(a) (((a)>>16) & ADDRMASK_OFF)
#define ADDR_OFF(a) ((a) & ADDRMASK_OFF)
#define MAKE_BADDR(s,o) ((ADDR_16bit(s)<<16) | ADDR_16bit(o))
#define MAKE_WADDR(a) MAKE_BADDR(NIL,ADDR_OFF(a))
#define ADDR_ISWORD(a) (ADDR_SEG(a) == NIL)
/* opcode table */
#define OP_ERROR -1
#define OP_NULL 0
#define OP_UB 1
#define OP_W 2
#define OP_B 3
#define OP_DBB 4
#define OP_UBB 5
#define OP_BUB 6
#define OP_SB 7
#define OP_DBUB 8
#define OP_UBUB 9
#define OP_UBDBUB 10
#define OP_DB 11
#define OP_SW 12
#define OP_AB 13
typedef struct _optable {
char* name;
int16 flags;
} OPTABLE;
extern OPTABLE optable[];
/* debug support */
#define DEBUG_OPDBGFILE "opcode.dbg"
#define DEBUG_MINOPCODE 0
#define DEBUG_MAXOPCODE 0xe8
#define DEBUG_VALIDOP(op) (optable[op].flags >= 0)
#define DEBUG_PRE 0x01
#define DEBUG_POST 0x02
extern t_stat dbg_init();
extern t_stat dbg_check(t_value data,uint8 prepost);
extern t_stat dbg_dump_tib(FILE* fd, uint16 base);
extern t_stat dbg_dump_queue(FILE* fd, const char* qname, uint16 q);
extern t_stat dbg_dump_mscw(FILE* fd, uint16 base);
extern t_stat dbg_dump_seg(FILE* fd, uint16 segptr);
extern t_stat dbg_dump_segtbl(FILE* fd);
extern t_stat dbg_segtrack(uint16 segbase);
extern t_stat dbg_procenter(uint16 segbase, uint16 procno, uint16 mscw, uint16 osegb);
extern t_stat dbg_procleave();
extern void dbg_enable();
extern t_stat dbg_calltree(FILE* fd);
extern t_stat dbg_enteralias(const char* key, const char* value);
extern t_stat dbg_listalias(FILE*);
/* floating point */
typedef union flcvt {
float f;
uint16 i[2];
} T_FLCVT;
/* wrapper structure for terminal multiplexer,
pointer to pointer stored in device->ctxt */
typedef struct {
int pfirst, prate; /* pollrate first time, later */
TMLN ldsc;
TMXR desc;
UNIT* term;
UNIT* poll;
} SERMUX;
extern t_stat mux_attach(UNIT*, char*, SERMUX*);
extern t_stat mux_detach(UNIT*, SERMUX*);
/* externals */
extern DEVICE cpu_dev;
extern UNIT cpu_unit;
extern DEVICE con_dev;
extern UNIT con_unit[];
extern DEVICE fdc_dev;
extern UNIT fdc_unit[];
extern DEVICE timer_dev;
extern UNIT timer_unit[];
extern t_addr PCX; /* PC at the begin of execution */
extern uint16 reg_segb;
extern uint32 reg_dmabase;
extern uint16 reg_mp;
extern uint16 reg_bp;
extern uint16 reg_sp;
extern uint16 reg_splow;
extern uint16 reg_spupr;
extern uint16 reg_ctp;
extern uint16 reg_rq;
extern uint16 reg_ipc;
extern uint16 reg_fc68;
extern uint16 reg_romsize;
extern uint16 reg_ssv;
extern uint16 reg_ssr;
extern uint16 reg_cpuserial;
extern uint32 reg_intpending;
extern t_stat Read(t_addr base, t_addr woffset, uint16 *data, uint32 dctrl);
extern t_stat Write(t_addr base, t_addr boffset, uint16 data, uint32 dctrl);
extern t_stat ReadB(t_addr base, t_addr boffset, uint16 *data, uint32 dctrl);
extern t_stat WriteB(t_addr base, t_addr boffset, uint16 data, uint32 dctrl);
extern t_stat ReadEx(t_addr base, t_addr woffset, uint16 *data);
extern t_stat ReadBEx(t_addr base, t_addr boffset, uint16 *data);
extern t_stat rom_read(t_addr base, uint16 *data);
extern t_stat rom_write(t_addr base, uint16 data);
extern t_stat fprint_sym_m (FILE *of, t_addr addr, t_value *val, UNIT *uptr, int32 sw);
extern t_stat con_read(t_addr ioaddr, uint16 *data);
extern t_stat con_write(t_addr ioaddr, uint16 data);
extern t_stat con_binit();
extern t_stat fdc_read(t_addr ioaddr, uint16 *data);
extern t_stat fdc_write(t_addr ioaddr, uint16 data);
extern t_stat fdc_autoload();
extern t_stat fdc_binit();
extern t_stat tim_read(t_addr ioaddr, uint16 *data);
extern t_stat tim_write(t_addr ioaddr, uint16 data);
extern void cpu_assertInt(int level, t_bool tf);
extern t_stat cpu_raiseInt(int level);
extern t_stat cpu_setIntVec(uint16 vector,int level);
extern void cpu_setRegs(uint16 ctp, uint16 ssv, uint16 rq);
extern void cpu_finishAutoload();
extern t_stat cpu_buserror();
typedef t_stat (*IOREAD)(t_addr ioaddr, uint16 *data);
typedef t_stat (*IOWRITE)(t_addr ioaddr, uint16 data);
typedef struct _ioinfo {
struct _ioinfo* next;
uint16 iobase;
uint16 iosize;
uint16 qvector;
uint16 qprio;
IOREAD read;
IOWRITE write;
} IOINFO;
typedef struct _devctxt {
IOINFO* ioi;
} DEVCTXT;
extern t_stat pdq3_ioinit();
extern t_stat add_ioh(IOINFO* ioi);
extern t_stat del_ioh(IOINFO* ioi);
extern t_stat set_iobase(UNIT *uptr, int32 val, char *cptr, void *desc);
extern t_stat show_iobase(FILE *st, UNIT *uptr, int32 val, void *desc);
extern t_stat set_iovec(UNIT *uptr, int32 val, char *cptr, void *desc);
extern t_stat show_iovec(FILE *st, UNIT *uptr, int value, void *desc);
extern t_stat set_ioprio(UNIT *uptr, int32 val, char *cptr, void *desc);
extern t_stat show_ioprio(FILE *st, UNIT *uptr, int value, void *desc);
#endif

1176
PDQ-3/pdq3_fdc.c Normal file

File diff suppressed because it is too large Load Diff

355
PDQ-3/pdq3_mem.c Normal file
View File

@@ -0,0 +1,355 @@
/*
Work derived from Copyright (c) 2004-2012, Robert M. Supnik
Copyright (c) 2013 Holger Veit
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
ROBERT M SUPNIK 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 Robert M Supnik and Holger Veit
shall not be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik and Holger Veit.
20130920 hv initial version, moved some code from pdq3_cpu.c
*/
#include "pdq3_defs.h"
/* the memory */
uint16 M[MAXMEMSIZE];
/******************************************************************************
* IO dispatcher
*****************************************************************************/
static t_bool initio = FALSE;
#define IOSIZE 4096
#define IOPAGEMASK 0x0fff
IOREAD ioreaders[IOSIZE];
IOWRITE iowriters[IOSIZE];
/* I/O devices are implemented this way:
* a unit will register its own I/O addresses together with its handler
* in a hash which allows simple lookup of memory mapped I/O addresses
*/
t_stat pdq3_ioinit() {
int i;
if (!initio) {
for (i=0; i < IOSIZE; i++) {
ioreaders[i] = NULL;
iowriters[i] = NULL;
}
for (i=8; i < 32; i++)
cpu_setIntVec(NIL, i);
initio = TRUE;
}
return SCPE_OK;
}
t_stat add_ioh(IOINFO* ioi) {
while (ioi) {
int i;
for (i=0; i<ioi->iosize; i++) {
int idx = (ioi->iobase + i) & IOPAGEMASK;
ioreaders[idx] = ioi->read;
iowriters[idx] = ioi->write;
}
ioi = ioi->next;
}
return SCPE_OK;
}
t_stat del_ioh(IOINFO* ioi) {
while (ioi) {
int i;
for (i=0; i<ioi->iosize; i++) {
int idx = (ioi->iobase + i) & IOPAGEMASK;
ioreaders[idx] = NULL;
iowriters[idx] = NULL;
}
ioi = ioi->next;
}
return SCPE_OK;
}
/******************************************************************************
* configuration
*****************************************************************************/
t_stat show_iobase(FILE *st, UNIT *uptr, int32 val, void *desc) {
DEVICE* dptr;
DEVCTXT* ctxt;
IOINFO* ioi;
t_bool first = TRUE;
if (!uptr) return SCPE_IERR;
if ((dptr = find_dev_from_unit(uptr)) == 0) return SCPE_IERR;
ctxt = (DEVCTXT*)dptr->ctxt;
ioi = ctxt->ioi;
while (ioi) {
if (ioi->iobase) {
if (ioi->iobase > 0xfc00) {
fprintf(st, first ? "IOBASE=$%04x":",$%04x", ioi->iobase);
first = FALSE;
}
}
ioi = ioi->next;
}
return SCPE_OK;
}
t_stat set_iobase(UNIT *uptr, int32 val, char *cptr, void *desc) {
t_stat rc;
DEVICE* dptr;
DEVCTXT* ctxt;
IOINFO* ioi;
t_bool first = TRUE;
if (!cptr) return SCPE_ARG;
if (!uptr) return SCPE_IERR;
if ((dptr = find_dev_from_unit(uptr)) == 0) return SCPE_IERR;
ctxt = (DEVCTXT*)dptr->ctxt;
ioi = ctxt->ioi;
if (ioi->next)
return SCPE_ARG; /* note: fixed devices on mainboard cannot be changed */
ioi->iobase = get_uint(cptr, 16, 0xffff, &rc);
return rc;
}
t_stat set_iovec(UNIT *uptr, int32 val, char *cptr, void *desc) {
t_stat rc;
DEVICE* dptr;
DEVCTXT* ctxt;
IOINFO* ioi;
t_bool first = TRUE;
if (!cptr) return SCPE_ARG;
if (!uptr) return SCPE_IERR;
if ((dptr = find_dev_from_unit(uptr)) == 0) return SCPE_IERR;
ctxt = (DEVCTXT*)dptr->ctxt;
ioi = ctxt->ioi;
if (ioi->next)
return SCPE_ARG; /* note: fixed devices on mainboard cannot be changed */
ioi->qvector = get_uint(cptr, 16, 0xff, &rc);
return rc;
}
t_stat show_iovec(FILE *st, UNIT *uptr, int value, void *desc) {
DEVICE* dptr;
DEVCTXT* ctxt;
IOINFO* ioi;
t_bool first = TRUE;
if (!uptr) return SCPE_IERR;
if ((dptr = find_dev_from_unit(uptr)) == 0) return SCPE_IERR;
ctxt = (DEVCTXT*)dptr->ctxt;
ioi = ctxt->ioi;
while (ioi) {
if (ioi->qprio < 32) {
fprintf(st, first ? "VECTOR=$%04x":",$%04x", ioi->qvector);
first = FALSE;
}
ioi = ioi->next;
}
return SCPE_OK;
}
t_stat set_ioprio(UNIT *uptr, int32 val, char *cptr, void *desc) {
t_stat rc;
DEVICE* dptr;
DEVCTXT* ctxt;
IOINFO* ioi;
t_bool first = TRUE;
if (!cptr) return SCPE_ARG;
if (!uptr) return SCPE_IERR;
if ((dptr = find_dev_from_unit(uptr)) == 0) return SCPE_IERR;
ctxt = (DEVCTXT*)dptr->ctxt;
ioi = ctxt->ioi;
if (ioi->next)
return SCPE_ARG; /* note: fixed devices on mainboard cannot be changed */
ioi->qprio = get_uint(cptr, 16, 31, &rc);
return rc;
}
t_stat show_ioprio(FILE *st, UNIT *uptr, int value, void *desc) {
DEVICE* dptr;
DEVCTXT* ctxt;
IOINFO* ioi;
t_bool first = TRUE;
if (!uptr) return SCPE_IERR;
if ((dptr = find_dev_from_unit(uptr)) == 0) return SCPE_IERR;
ctxt = (DEVCTXT*)dptr->ctxt;
ioi = ctxt->ioi;
while (ioi) {
if (ioi->qprio < 32) {
fprintf(st, first ? "PRIO=%d":",%d", ioi->qprio);
first = FALSE;
}
ioi = ioi->next;
}
return SCPE_OK;
}
/******************************************************************************
* central memory handling
*****************************************************************************/
t_stat Read(t_addr base, t_addr woffset, uint16 *data, uint32 dctrl) {
t_stat rc;
uint16 ea = base + woffset;
/* Note: the PRIAM driver attempts to read the ready bit from FF25 (bit 9) which should be 1.
* As long as we don't have a HDP device, the invalid value should be 0x0000 */
*data = 0x0000; /* preload invalid data value */
if (ea < 0xf000 || (ea == 0xfffe && cpu_unit.capac > 65535)) {
*data = M[ea]; /* normal memory */
rc = SCPE_OK;
} else {
IOREAD reader = ioreaders[ea & IOPAGEMASK];
rc = reader ? (*reader)(ea, data) : SCPE_NXM;
}
if (rc != SCPE_OK) {
cpu_buserror();
sim_debug(DBG_CPU_READ, &cpu_dev, DBG_PCFORMAT1 "Invalid Mem read from $%04x\n", DBG_PC, ea);
printf("read buserror: ea=$%04x at $%x:#%x\n",ea,reg_segb,reg_ipc);
return rc;
}
if (dctrl & DBG_CPU_PICK) {
sim_debug(DBG_CPU_PICK, &cpu_dev, DBG_PCFORMAT1 "Pick %04x at SP=$%04x\n", DBG_PC, *data, ea);
} else if (dctrl & DBG_CPU_POP) {
sim_debug(DBG_CPU_POP, &cpu_dev, DBG_PCFORMAT2 "Pop %04x from SP=$%04x\n", DBG_PC, *data, ea);
} else {
sim_debug(dctrl, &cpu_dev, DBG_PCFORMAT2 "Word read %04x from $%04x\n", DBG_PC, *data, ea);
}
return rc;
}
/* read routine that does not generate bus errors, for SIMH Examine
* will read 0x0000 for unknown memory */
t_stat ReadEx(t_addr base, t_addr woffset, uint16 *data) {
t_stat rc;
uint16 ea = base + woffset;
*data = 0x0000; /* preload invalid data value */
if (ea < 0xf000) {
*data = M[ea]; /* normal memory */
rc = SCPE_OK;
} else {
IOREAD reader = ioreaders[ea & IOPAGEMASK];
rc = reader ? (*reader)(ea, data) : SCPE_NXM;
}
return rc;
}
t_stat Write(t_addr base, t_addr woffset, uint16 data, uint32 dctrl) {
t_stat rc;
uint16 ea = base + woffset;
if (ea < 0xf000) {
M[ea] = data;
rc = SCPE_OK;
} else {
IOWRITE write = iowriters[ea & IOPAGEMASK];
rc = write ? (*write)(ea, data) : SCPE_NXM;
}
if (rc != SCPE_OK) {
cpu_buserror();
sim_debug(DBG_CPU_WRITE, &cpu_dev, DBG_PCFORMAT0 "Invalid Mem write to $%04x\n", DBG_PC, ea);
printf("write buserror %x at %x:%x\n",ea,reg_segb,reg_ipc);
//exit(1);
return rc;
}
if (dctrl & DBG_CPU_STACK)
sim_debug(DBG_CPU_PUSH, &cpu_dev, DBG_PCFORMAT1 "Push %04x to SP=$%04x\n", DBG_PC, data, ea);
else
sim_debug(dctrl, &cpu_dev, DBG_PCFORMAT2 "Word write %04x to $%04x\n", DBG_PC, data, ea);
return rc;
}
t_stat ReadB(t_addr base, t_addr boffset, uint16 *data, uint32 dctrl)
{
t_stat rc;
t_addr ea = base + boffset/2;
if ((rc=Read(ea, 0, data, DBG_NONE)) != SCPE_OK) return rc;
if (boffset & 1)
*data >>= 8;
*data &= 0xff;
if (dctrl & DBG_CPU_FETCH)
sim_debug(DBG_CPU_FETCH, &cpu_dev, DBG_PCFORMAT0 "Fetch %02x from SEGB:%04x\n",
DBG_PC, *data, reg_ipc);
else
sim_debug(dctrl, &cpu_dev, DBG_PCFORMAT2 "Byte[%d] read %02x from $%04x\n",
DBG_PC, boffset & 1, *data, ea);
return SCPE_OK;
}
t_stat ReadBEx(t_addr base, t_addr boffset, uint16 *data)
{
t_stat rc;
t_addr ea = base + boffset/2;
if ((rc=ReadEx(ea, 0, data)) != SCPE_OK) return rc;
if (boffset & 1)
*data >>= 8;
*data &= 0xff;
return SCPE_OK;
}
t_stat WriteB(t_addr base, t_addr boffset, uint16 data, uint32 dctrl)
{
uint16 wdata;
t_addr ea = base + boffset/2;
if (ea < 0xfc00) {
sim_debug(dctrl, &cpu_dev, DBG_PCFORMAT2 "Byte[%d] write %02x to $%04x\n",
DBG_PC, boffset & 1, data, ea);
wdata = M[ea];
} else {
printf(DBG_PCFORMAT0 "Invalid byte[%d] write %02x to I/O addr $%04x\n", DBG_PC, boffset & 1, data, ea);
return STOP_ERRIO;
}
if (boffset & 1) {
wdata = (wdata & 0xff) | (data<<8);
} else {
wdata = (wdata & 0xff00) | (data & 0xff);
}
return Write(ea, 0, wdata, 0);
}
t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc)
{
int32 mc;
t_addr i;
if (val < 0 || val > 1)
return SCPE_ARG;
val = val ? 65536 : 32768;
for (mc = 0, i = val; i < memorysize; i++)
mc = mc | M[i];
if (mc && !get_yn ("Really truncate memory [N]?", FALSE))
return SCPE_OK;
memorysize = val;
for (i = memorysize; i < MAXMEMSIZE; i++)
M[i] = 0;
return SCPE_OK;
}
t_stat rom_read(t_addr ea, uint16 *data)
{
*data = M[ea];
return SCPE_OK;
}
t_stat rom_write(t_addr ea, uint16 data) {
M[ea] = data;
return SCPE_OK;
}

641
PDQ-3/pdq3_stddev.c Normal file
View File

@@ -0,0 +1,641 @@
/* PDQ3_stddev.c: PDQ3 simulator standard devices
Work derived from Copyright (c) 2004-2012, Robert M. Supnik
Copyright (c) 2013 Holger Veit
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
ROBERT M SUPNIK 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 Robert M Supnik and Holger Veit
shall not be used in advertising or otherwise to promote the sale, use or
other dealings in this Software without prior written authorization from
Robert M Supnik and Holger Veit.
20130902 hv added telnet multiplexer code
20131020 hv fixed CON interrupt handling
20131103 hv connect CON_ATTACH logic with DSR, so that DSR is set if tcp connect
*/
#include "pdq3_defs.h"
#include <ctype.h>
extern UNIT cpu_unit;
extern int32 sim_switches;
extern UNIT con_unit[];
static t_stat con_termsvc(UNIT *uptr);
static t_stat con_pollsvc(UNIT *uptr);
static t_stat con_attach(UNIT*, char*);
static t_stat con_detach(UNIT*);
static t_stat con_reset(DEVICE* dptr);
static t_stat tim_reset(DEVICE *dptr);
static t_stat tim0_svc(UNIT* uptr);
static t_stat tim1_svc(UNIT* uptr);
static t_stat tim2_svc(UNIT* uptr);
/* CON USART registers */
/* This is described as positive logic, and represents the
* content of the corresponding registers.
* However, the USART is connected to inverted DAL lines
* and needs to be written to with the inverted value
* This is done in CPU Read/Write */
#define CONC1_LOOP 0x80 /* 0=loopmode diagnostic, 1=normal full duplex */
#define CONC1_BRK 0x40 /* 1=send break */
#define CONC1_MISC 0x20 /* 1=one stop bit, 0=two */
#define CONC1_ECHO 0x10 /* 1=echo received data */
#define CONC1_PE 0x08 /* 1=check parity */
#define CONC1_RE 0x04 /* 1=enable receiver */
#define CONC1_RTS 0x02 /* 1=enable transmitter if CTS */
#define CONC1_DTR 0x01 /* 1=enable CD, DSR,RI interrupts */
static uint8 con_ctrl1;
#define CONC2_CLENMASK 0xc0 /* number of bits */
#define CONC2_CLEN8 0x00
#define CONC2_CLEN7 0x40
#define CONC2_CLEN6 0x80
#define CONC2_CLEN5 0xc0
#define CONC2_MODE 0x20 /* not used set to 0 (async mode) */
#define CONC2_ODDEVN 0x10 /* 0=even parity */
#define CONC2_RXCLK 0x08 /* not used, set to 1 */
#define CONC2_CLKMASK 0x07 /* clock selector */
#define CONC2_CLK110 0x06 /* must be set to 001 (rate 1 clock) */
static uint8 con_ctrl2;
#define CONS_DSC 0x80 /* set to 1 after status read, cleared by DSR/DCD/RI */
#define CONS_DSR 0x40 /* DSR input */
#define CONS_CD 0x20 /* DCD input */
#define CONS_FE 0x10 /* 1=framing error */
#define CONS_PE 0x08 /* 1=parity error */
#define CONS_OE 0x04 /* 1= overrun error */
#define CONS_DR 0x02 /* set to 1 if data received, 0 if data read */
#define CONS_THRE 0x01 /* set to 1 if data xmit buffer empty */
static uint8 con_status;
static uint8 con_xmit;
static uint8 con_rcv;
/************************************************************************************************
* Utilities
***********************************************************************************************/
t_stat mux_attach(UNIT* uptr, char* cptr, SERMUX* mux) {
t_stat rc;
mux->desc.ldsc = &mux->ldsc;
if ((rc = tmxr_attach(&mux->desc, uptr, cptr)) == SCPE_OK) {
mux->poll->wait = mux->pfirst;
sim_activate(mux->poll, mux->poll->wait);
}
return rc;
}
t_stat mux_detach(UNIT* uptr, SERMUX* mux) {
t_stat rc = tmxr_detach(&mux->desc, uptr);
mux->ldsc.rcve = 0;
sim_cancel(mux->poll);
sim_cancel(mux->term);
return rc;
}
/************************************************************************************************
* Onboard Console
***********************************************************************************************/
/* con data structures
con_dev con device descriptor
con_unit con unit descriptor
con_mod con modifier list
con_reg con register list
*/
IOINFO con_ioinfo1 = { NULL, CON_IOBASE, 4, CON_RCV_VEC, 4, con_read, con_write };
IOINFO con_ioinfo2 = { &con_ioinfo1, 0, 0, CON_XMT_VEC, 3, con_read, con_write };
DEVCTXT con_ctxt = { &con_ioinfo2 };
UNIT con_unit[] = {
{ UDATA (&con_pollsvc, UNIT_ATTABLE, 0), CON_POLLRATE, },
{ UDATA (&con_termsvc, UNIT_IDLE, 0), CON_TERMRATE, }
};
REG con_reg[] = {
{ HRDATA (CTRL1, con_ctrl1, 8) },
{ HRDATA (CTRL2, con_ctrl2, 8) },
{ HRDATA (STAT, con_status, 8) },
{ HRDATA (XMIT, con_xmit, 8) },
{ HRDATA (RCV, con_rcv, 8) },
{ NULL }
};
MTAB con_mod[] = {
{ MTAB_XTD|MTAB_VDV, 0, "IOBASE", "IOBASE", NULL, &show_iobase },
{ MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR", NULL, &show_iovec },
{ MTAB_XTD|MTAB_VDV, 0, "PRIO", "PRIO", NULL, &show_ioprio },
{ 0 }
};
DEBTAB con_dflags[] = {
{ "WRITE", DBG_CON_WRITE },
{ "READ", DBG_CON_READ },
{ "SVC", DBG_CON_SVC },
{ 0, 0 }
};
SERMUX con_mux[1] = {
{ CON_POLLFIRST, /*pfirst*/
CON_POLLRATE, /*prate*/
{ 0 }, /*ldsc*/
{ 1,0,0,0 }, /*desc*/
&con_unit[1], /*term*/
&con_unit[0] /*poll*/
}
};
DEVICE con_dev = {
"CON", /*name*/
con_unit, /*units*/
con_reg, /*registers*/
con_mod, /*modifiers*/
2, /*numunits*/
16, /*aradix*/
16, /*awidth*/
1, /*aincr*/
8, /*dradix*/
8, /*dwidth*/
NULL, /*examine*/
NULL, /*deposit*/
&con_reset, /*reset*/
NULL, /*boot*/
con_attach, /*attach*/
con_detach, /*detach*/
&con_ctxt, /*ctxt*/
DEV_DEBUG|DEV_DISABLE, /*flags*/
0, /*dctrl*/
con_dflags, /*debflags*/
NULL, /*msize*/
NULL /*lname*/
};
/* bus reset handler */
t_stat con_binit() {
SERMUX *mux = &con_mux[0];
con_status = CONS_THRE;
if (mux->ldsc.conn) setbit(con_status, CONS_DSR);
con_ctrl1 = 0; /* no echo, receiver disabled, transmitter disabled */
con_ctrl2 = 0; /* ASYNC mode, 8bits, Clock 1X */
con_xmit = 0;
con_rcv = 0;
return SCPE_OK;
}
/* common handlers */
static t_stat con_reset(DEVICE* dptr)
{
int32 wait;
SERMUX * mux = &con_mux[0];
UNIT *term = mux->term;
UNIT *poll = mux->poll;
DEVCTXT* ctxt = (DEVCTXT*)dptr->ctxt;
wait = poll->wait = CON_POLLWAIT;
sim_rtcn_init (wait, TMR_CONPOLL); /* init poll timer */
sim_cancel(term);
/* register/deregister I/O handlers */
if (dptr->flags & DEV_DIS) {
del_ioh(ctxt->ioi);
} else {
add_ioh(ctxt->ioi);
poll->buf = 0;
sim_activate (poll, wait);
}
return con_binit();
}
t_stat con_attach(UNIT* uptr, char* cptr) {
setbit(con_status, CONS_DSR|CONS_DSC);
return mux_attach(uptr, cptr, &con_mux[0]);
}
t_stat con_detach(UNIT* uptr) {
clrbit(con_status, CONS_DSR);
setbit(con_status, CONS_DSC);
return mux_detach(uptr, &con_mux[0]);
}
#define XMITENABLED() (isbitset(con_ctrl1,CONC1_RTS))
#define XMITENABLE() setbit(con_ctrl1,CONC1_RTS)
#define XMITDISABLE() clrbit(con_ctrl1,CONC1_RTS)
#define XMITEMPTY() (isbitset(con_status, CONS_THRE))
#define RCVENABLED() (isbitset(con_ctrl1,CONC1_RE))
#define RCVFULL() (isbitset(con_status, CONS_DR))
#define RCVENABLE() setbit(con_ctrl1,CONC1_RE)
#define RCVDISABLE() clrbit(con_ctrl1,CONC1_RE)
#define DSRACTIVE() (isbitset(con_ctrl1,CONC1_DTR) && isbitset(con_status,CONS_DSR))
/* The transmit interrupt is raised continuously,
* as long as the transmit holding reg is empty and the transmitter is enabled.
* It will be deasserted when the tranmit reg is full or tranmitter disabled.
*/
#define XMITINTR() cpu_assertInt(INT_CONT, XMITEMPTY())
/* The receive interrupt is raised continuously,
* when the receiver holding register is full and the receiver is enabled.
* it will be deasserted when the receiver reg is read or the receiver disabled.
*/
#define RCVINTR() cpu_assertInt(INT_CONR, RCVFULL())
/* The DSR interrupt is raised when DSC is set to 1 (pos logic)
* and DTR is active, cleared if status is read */
#define DSRINTR() cpu_assertInt(INT_PRNT, DSRACTIVE())
/* Terminal output service */
t_stat con_termsvc (UNIT *uptr) {
SERMUX *mux = &con_mux[0];
t_bool isnetwork = (mux->poll->flags & UNIT_ATT);
t_stat rc;
int ch = uptr->buf & 0xff;
// sim_debug(DBG_CON_SVC, &con_dev, "termsvc: isnetwork=%d\n",isnetwork);
/* TODO? sim_tt_outcvt */
if (XMITENABLED()) { /* tranmitter enabled */
/* attached to a telnet port? */
// printf("*** Emit: %02x ***\n",uptr->buf & 0xff);
if (isnetwork) {
if ((rc=tmxr_putc_ln(&mux->ldsc, ch)) != SCPE_OK) {
sim_activate(uptr, uptr->wait);
return SCPE_OK;
} else
tmxr_poll_tx(&mux->desc);
} else {
if ((rc=sim_putchar_s(ch)) != SCPE_OK) {
sim_activate(uptr, uptr->wait);
return rc==SCPE_STALL ? SCPE_OK : rc;
}
}
setbit(con_status,CONS_THRE); /* set transmitter holding reg empty */
cpu_assertInt(INT_CONT, TRUE); /* generate an interrupt because of DRQO */
}
return SCPE_OK;
}
/* Terminal input service */
t_stat con_pollsvc(UNIT *uptr) {
int32 c, kbdc;
SERMUX *mux = &con_mux[0];
t_bool isnetwork = (mux->poll->flags & UNIT_ATT);
uptr->wait = sim_rtcn_calb(mux->prate, TMR_CONPOLL); /* calibrate timer */
sim_activate (uptr, uptr->wait); /* restart polling */
kbdc = sim_poll_kbd(); /* check keyboard */
if (kbdc == SCPE_STOP) return kbdc; /* handle CTRL-E */
/* network-redirected input? */
if (isnetwork) {
if (tmxr_poll_conn(&mux->desc) >= 0) /* incoming connection */
mux->ldsc.rcve = 1;
tmxr_poll_rx(&mux->desc); /* poll for input */
if (!tmxr_rqln(&mux->ldsc)) return SCPE_OK;
/* input ready */
c = tmxr_getc_ln(&mux->ldsc);
if ((c & TMXR_VALID) == 0) return SCPE_OK;
} else {
c = kbdc; /* use char polled from keyboard */
if (c < SCPE_KFLAG) return c; /* ignore data if not valid */
}
c = sim_tt_inpcvt(c, TT_GET_MODE(uptr->flags));
uptr->buf = c & 0xff;
uptr->pos = uptr->pos + 1;
if (RCVENABLED()) { /* receiver enabled? */
if (RCVFULL()) /* handle data overrun */
setbit(con_status,CONS_OE);
con_rcv = c & 0xff; /* put in receiver register */
setbit(con_status,CONS_DR); /* notify: data received */
cpu_assertInt(INT_CONR, TRUE); /* generate interrupt because of DRQI */
if (isbitset(con_ctrl1, CONC1_ECHO)) { /* echo? XXX handle in telnet handler? */
/* XXX use direct send here, not sending via con_termsvc */
if (isnetwork)
tmxr_putc_ln(&mux->ldsc, c);
else
sim_putchar_s(c);
}
}
return SCPE_OK;
}
static int set_parity(int c, int odd)
{
int i, p = 0;
for (i=0; i<8; i++)
if (c & (1<<i)) p ^= 1;
c |= p ? 0 : 0x80;
if (!odd) c ^= 0x80;
return c;
}
static int get_parity(int c, int even)
{
int i, p = 0;
for (i=0; i<8; i++)
if (c & (1<<i)) p ^= 1;
if (even) p ^= 1;
return p;
}
// functions from memory handler to read and write a char
// note: the usart is connected to inverted data lines,
// this is fixed by negating input and output
//
// The logic in here uses the positive logic conventions as
// described in the WD1931 data sheet, not the ones in the PDQ-3_Hardware_Users_Manual
t_stat con_write(t_addr ioaddr, uint16 data) {
SERMUX * mux = &con_mux[0];
UNIT *term = mux->term;
UNIT *poll = mux->poll;
/* note usart has inverted bus, so all data is inverted */
data = (~data) & 0xff;
switch (ioaddr & 0x0003) {
case 0: /* CTRL1 */
con_ctrl1 = data;
if (!RCVENABLED()) { /* disable receiver */
clrbit(con_status,CONS_FE|CONS_PE|CONS_OE|CONS_DR);
sim_cancel(poll);
} else {
sim_activate(poll, poll->wait); /* start poll service, will raise interrupt if buffer full */
}
if (!XMITENABLED()) { /* disable transmitter */
/* will drain current pending xmit service. RTS output is assumed to become inactive
* (it is not necessary to emulate it) */
} else {
if (XMITEMPTY()) {
} else {
/* some char in THR, start service to emit */
sim_activate(term, term->wait);
}
}
break;
case 1:
con_ctrl2 = data;
break;
case 2:
// ignore this here - DLE register
break;
case 3:
switch (con_ctrl2 & CONC2_CLENMASK) {
case CONC2_CLEN5: data &= 0x1f; break;
case CONC2_CLEN6: data &= 0x3f; break;
case CONC2_CLEN7: data &= 0x7f;
if (isbitset(con_ctrl1,CONC1_PE))
data = set_parity(data, con_ctrl2 & CONC2_ODDEVN);
break;
case CONC2_CLEN8: data &= 0xff; break;
}
con_xmit = data;
term->buf = data;
clrbit(con_status,CONS_THRE);
if (XMITENABLED())
sim_activate(term,term->wait);
}
// RCVINTR();
XMITINTR();
DSRINTR();
sim_debug(DBG_CON_WRITE, &con_dev, DBG_PCFORMAT0 "Byte write %02x (pos logic) to $%04x\n", DBG_PC, data & 0xff, ioaddr);
return SCPE_OK;
}
t_stat con_read(t_addr ioaddr, uint16 *data) {
SERMUX *mux = &con_mux[0];
switch (ioaddr & 0x0003) {
case 0: /* CTRL1 */
*data = con_ctrl1;
break;
case 1:
*data = con_ctrl2;
break;
case 2:
if (mux->ldsc.conn) setbit(con_status, CONS_DSR);
else clrbit(con_status, CONS_DSR);
*data = con_status;
clrbit(con_status,CONS_DSC); /* acknowledge change in DSR/DCD */
break;
case 3:
*data = con_rcv;
clrbit(con_status,CONS_DR);
cpu_assertInt(INT_CONR, FALSE);
}
sim_debug(DBG_CON_READ, &con_dev, DBG_PCFORMAT1 "Byte read %02x (pos logic) from $%04x\n", DBG_PC, *data & 0xff, ioaddr);
/* note usart has inverted bus, so returned data must be negated */
*data = ~(*data);
return SCPE_OK;
}
/************************************************************************************************
* Onboard 8253 timer
***********************************************************************************************/
struct i8253 {
uint16 cnt;
uint16 preset;
uint16 mode;
t_bool hilo; /* which half of 16 bit cnt is to be set */
};
struct i8253 tim[3];
IOINFO tim_ioinfo1 = { NULL, TIM_IOBASE, 4, TIM_TICK_VEC, 6, tim_read, tim_write };
IOINFO tim_ioinfo2 = { &tim_ioinfo1, 0, 0, TIM_INTVL_VEC, 7, tim_read, tim_write };
DEVCTXT tim_ctxt = { &tim_ioinfo2 };
UNIT tim_unit[] = {
{ UDATA (&tim0_svc, 0, 0), CON_POLLRATE, },
{ UDATA (&tim1_svc, 0, 0), CON_POLLRATE, },
{ UDATA (&tim2_svc, 0, 0), CON_POLLRATE, }
};
REG tim_reg[] = {
{ HRDATA (CNT0, tim[0].cnt, 16) },
{ HRDATA (CNT1, tim[1].cnt, 16) },
{ HRDATA (CNT2, tim[2].cnt, 16) },
{ HRDATA (MODE0, tim[0].mode, 8) },
{ HRDATA (MODE1, tim[1].mode, 8) },
{ HRDATA (MODE2, tim[2].mode, 8) },
{ NULL }
};
MTAB tim_mod[] = {
{ MTAB_XTD|MTAB_VDV, 0, "IOBASE", "IOBASE", NULL, &show_iobase },
{ MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR", NULL, &show_iovec },
{ MTAB_XTD|MTAB_VDV, 0, "PRIO", "PRIO", NULL, &show_ioprio },
{ 0 }
};
DEBTAB tim_dflags[] = {
{ "WRITE", DBG_TIM_WRITE },
{ "READ", DBG_TIM_READ },
{ "SVC", DBG_TIM_SVC },
{ 0, 0 }
};
DEVICE tim_dev = {
"TIM", /*name*/
tim_unit, /*units*/
tim_reg, /*registers*/
tim_mod, /*modifiers*/
3, /*numunits*/
16, /*aradix*/
16, /*awidth*/
1, /*aincr*/
8, /*dradix*/
8, /*dwidth*/
NULL, /*examine*/
NULL, /*deposit*/
&tim_reset, /*reset*/
NULL, /*boot*/
NULL, /*attach*/
NULL, /*detach*/
&tim_ctxt, /*ctxt*/
DEV_DEBUG, /*flags*/
0, /*dctrl*/
tim_dflags, /*debflags*/
NULL, /*msize*/
NULL /*lname*/
};
t_stat tim_reset(DEVICE *dptr)
{
DEVCTXT* ctxt = (DEVCTXT*)dptr->ctxt;
if (dptr->flags & DEV_DIS) {
del_ioh(ctxt->ioi);
sim_cancel(&tim_unit[0]);
sim_cancel(&tim_unit[1]);
sim_cancel(&tim_unit[2]);
} else {
add_ioh(ctxt->ioi);
}
return SCPE_OK;
}
t_stat tim_read(t_addr ioaddr, uint16 *data)
{
int n = ioaddr & 0x0003;
if (n == 3)
*data = 0xff;
else {
*data = (tim[n].hilo ? tim[n].cnt : (tim[n].cnt >> 8)) & 0xff;
sim_debug(DBG_TIM_READ, &tim_dev, DBG_PCFORMAT1 "Read %s timer%d: %02x\n",
DBG_PC, tim[n].hilo ? "high" : "low", n, *data);
tim[n].hilo = ! tim[n].hilo;
}
return SCPE_OK;
}
static uint16 sethi(uint16 val, uint16 data) {
val &= 0xff;
val |= (data << 8);
return val;
}
static uint16 setlo(uint16 val, uint16 data) {
val &= 0xff00;
val |= data;
return val;
}
t_stat tim_write(t_addr ioaddr, uint16 data)
{
int n = ioaddr & 0x0003;
data &= 0xff;
if (n == 3) {
n = (data & 0xc0) >> 6;
sim_debug(DBG_TIM_WRITE, &tim_dev, DBG_PCFORMAT0 "Timer%d: mode=%d\n",
DBG_PC, n, (data >> 1) & 7);
if (n == 3) {
printf("Unimplemented: Mode=0xc0\n");
return STOP_IMPL;
}
if (data & 0x01) {
printf("Unimplemented: BCD mode: timer=%d\n",n);
return STOP_IMPL;
}
if (!( (data & 0x0e)==0x00 || (data & 0x0e)==0x04)) {
printf("Unimplemented: Mode not 0 or 2: timer=%d\n",n);
return STOP_IMPL;
}
if ((data & 0x30) != 0x30) {
printf("Unimplemented: not 16 bit load: timer=%d\n",n);
return STOP_IMPL;
}
tim[n].mode = data;
} else {
if (tim[n].hilo) {
tim[n].preset = sethi(tim[n].preset, data);
tim[n].cnt = sethi(tim[n].cnt, data);
if (n < 2) { /* timer 2 is triggered by timer 1 */
int32 time = 1250000 / tim[n].cnt;
sim_cancel(&tim_unit[n]);
sim_activate(&tim_unit[n], time);
}
} else {
tim[n].preset = setlo(tim[n].preset, data);
tim[n].cnt = setlo(tim[n].cnt, data);
}
sim_debug(DBG_TIM_WRITE, &tim_dev, DBG_PCFORMAT0 "Timer%d: %s cnt=%02x\n",
DBG_PC, n, tim[n].hilo ? "high":"low", data);
tim[n].hilo = !tim[n].hilo;
}
return SCPE_OK;
}
/* baud rate timer 0 is programmed in mode 2 - actually, this is ignored */
static t_stat tim0_svc(UNIT* uptr)
{
int32 time = 1250000 / tim[0].preset;
sim_activate(uptr, time);
sim_debug(DBG_TIM_SVC, &tim_dev, DBG_PCFORMAT2 "Timer0: SVC call\n", DBG_PC);
return SCPE_OK;
}
/* system timer 1 is programmed in mode 2, causes interrupt each time it is 0 */
static t_stat tim1_svc(UNIT* uptr)
{
int32 time = 1250000 / tim[0].preset;
sim_debug(DBG_TIM_SVC, &tim_dev, DBG_PCFORMAT2 "Timer1: SVC call\n", DBG_PC);
sim_activate(uptr, time);
cpu_raiseInt(INT_TICK);
reg_ssr |= SSR_TICK; /* notify TICK timer int occurred */
/* handle interval timer */
if (tim[2].cnt > 0) tim[2].cnt--;
if (tim[2].cnt == 0) {
cpu_raiseInt(INT_INTVL);
reg_ssr |= SSR_INTVL; /* notify INTVL timer int occurred */
if ((tim[2].mode & 0x0e) == 0x04) {
tim[2].cnt = tim[2].preset; /* restart timer */
} /* otherwise single shot */
}
return SCPE_OK;
}
/* interval timer 2 is programmed in mode 0 (single shot) or 2 (rate generator)
* this is triggered by timer1 - svc is ignored here */
static t_stat tim2_svc(UNIT* uptr)
{
sim_debug(DBG_TIM_SVC, &tim_dev, DBG_PCFORMAT2 "Timer2: SVC call - should not occur\n", DBG_PC);
return SCPE_OK;
}

621
PDQ-3/pdq3_sys.c Normal file
View File

@@ -0,0 +1,621 @@
/* pdq3_sys.c: PDQ3 simulator interface
Work derived from Copyright (c) 2004-2012, Robert M. Supnik
Copyright (c) 2013 Holger Veit
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
ROBERT M SUPNIK 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 Robert M Supnik and Holger Veit
shall not be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik and Holger Veit.
2013xxxx hv initial version (written up to the leval to test against bootloader)
20130907 hv added VIEWSEG command
20130925 hv added CALL and NAME command
20130927 hv wrong disassembly of LDC instr
*/
#include "pdq3_defs.h"
#include <ctype.h>
static int disass(t_addr addr);
t_stat parse_sym_m (char *cptr, t_value *val, int32 sw);
void pdq3_vm_init (void);
static t_stat pdq3_cmd_exstack(int32 arg, char *buf);
static t_stat pdq3_cmd_exmscw(int32 arg, char *buf);
static t_stat pdq3_cmd_extib(int32 arg, char *buf);
static t_stat pdq3_cmd_exseg(int32 arg, char *buf);
static t_stat pdq3_cmd_calcea(int32 arg, char *buf);
static t_stat pdq3_cmd_calltree(int32 arg, char *buf);
static t_stat pdq3_cmd_namealias(int32 arg, char *buf);
extern DEVICE cpu_dev;
extern UNIT cpu_unit;
extern DEVICE tty_dev;
extern DEVICE fdc_dev;
extern DEVICE tim_dev;
extern REG cpu_reg[];
extern uint16 M[];
extern uint16 reg_pc;
/* SCP data structures and interface routines
sim_name simulator name string
sim_PC pointer to saved PC register descriptor
sim_emax maximum number of words for examine/deposit
sim_devices array of pointers to simulated devices
sim_stop_messages array of pointers to stop messages
sim_load binary loader
*/
char sim_name[] = "PDQ3";
REG *sim_PC = &cpu_reg[0]; /* note this is the artifical register PCX */
int32 sim_emax = 6;
DEVICE *sim_devices[] = {
&cpu_dev,
&con_dev,
&fdc_dev,
&tim_dev,
NULL
};
const char *sim_stop_messages[] = {
"---",
"PC Breakpoint",
"MEM Breakpoint",
"Invalid Opcode",
"Invalid MEM Access",
"Invalid I/O Access",
"Not yet implemented",
"BPT instruction",
"DEBUG PRE exec stop",
"DEBUG POST exec stop",
"HALT on Pascal Exception",
};
CTAB pdq3_cmds[] = {
{ "VSTACK", &pdq3_cmd_exstack, 0, "Display last N elements of stack. Top is where SP points to" },
{ "VMSCW", &pdq3_cmd_exmscw, 0, "Display current MSCW" },
{ "VTIB", &pdq3_cmd_extib, 0, "Display current TIB" },
{ "VSEG", &pdq3_cmd_exseg, 0, "Display a segment table entry" },
{ "VCALL", &pdq3_cmd_calltree, 0, "Display the call tree" },
{ "NAME", &pdq3_cmd_namealias, 0, "Define a name" },
{ NULL, NULL, 0, NULL }
};
void (*sim_vm_init)(void) = &pdq3_vm_init;
/* Loader proper */
t_stat sim_load (FILE *fi, char *cptr, char *fnam, int flag)
{
int rombase;
int c1, c2, i;
if (flag == 1) /* don't dump */
return SCPE_ARG;
/* this assumes a HDT style ROM, where the first 2 bytes refer to the
* actual word start of the ROM, e.g. with PDQ-3 the HDT ROM has 0xf401
* as the first word, so it will load at word address 0xf400, and 0xfc68
* will be preset to 0xf401
*/
c1 = fgetc(fi);
c2 = fgetc(fi);
rombase = c1 + c2 * 256;
rom_write(rombase & 0xfffe, rombase);
reg_fc68 = rombase;
i = 0;
while (!feof(fi) && i<0x1ff) {
c1 = fgetc(fi);
c2 = fgetc(fi);
rom_write(rombase+i, (uint16)(c1 + c2*256));
i++;
}
reg_romsize = i;
/* preset the cpu_serial number from ROM, may be overwritten manually for special purposes */
rom_read(rombase+i-1, &reg_cpuserial);
return SCPE_OK;
}
/* Note: this simh handles ABSOLUTE word addresses and segmented byte addresses.
* A word address addresses a single cell in memory (up to 65536 cells).
* A byte address only occurs in IPC context, it is relative to the content of
* the reg_segb register.
* Convention:
* $xxxx = word address
* xxxx:yyyy = byte address yyyy relative to segment xxxx
* #yyyy = byte address relative to current reg_segb
* The t_addr type must be 32 bit, the upper half contains the segment, the lower
* half contains the offset. If the upper half is NIL, it is a word address
*/
void pdq3_fprint_addr (FILE *st, DEVICE *dptr, t_addr addr)
{
if (ADDR_ISWORD(addr))
fprintf(st,"$");
else if (ADDR_SEG(addr) == reg_segb)
fprintf(st,"#");
else {
fprint_val (st, ADDR_SEG(addr), dptr->dradix, dptr->dwidth, PV_LEFT);
fprintf(st,":");
}
fprint_val (st, ADDR_OFF(addr), dptr->dradix, dptr->dwidth, PV_LEFT);
return;
}
t_addr pdq3_parse_addr (DEVICE *dptr, char *cptr, char **tptr)
{
t_addr seg, off;
if (cptr[0] == '#') {
off = strtotv(cptr+1, tptr, dptr->aradix);
return MAKE_BADDR(reg_segb,off);
} else if (cptr[0] == '$') {
off = strtotv(cptr+1, tptr, dptr->aradix);
return MAKE_WADDR(off);
} else {
char gbuf[CBUFSIZE];
get_glyph (cptr, gbuf, 0);
if (!strncmp(gbuf,"SEGB",4)) {
seg = reg_segb; *tptr = cptr+4;
} else
seg = strtotv(cptr, tptr, dptr->aradix);
if (*tptr[0] == ':') {
cptr = *tptr + 1;
off = strtotv(cptr, tptr, dptr->aradix);
return MAKE_BADDR(seg,off);
} else
return MAKE_WADDR(seg);
}
}
void pdq3_vm_init (void)
{
sim_vm_fprint_addr = &pdq3_fprint_addr;
sim_vm_parse_addr = &pdq3_parse_addr;
sim_vm_cmd = pdq3_cmds;
return;
}
static t_stat pdq3_cmd_exstack(int32 arg, char *buf)
{
t_stat rc;
uint16 data;
int i;
int n = buf[0] ? atol(buf) : 0;
if (n < 0) n = 0;
printf("SP: $%04x LOW: $%04x UPR: $%04x\n",
reg_sp, reg_splow, reg_spupr);
for (i=n; i>=0; i--) {
if ((rc=Read(reg_sp+i, 0, &data, 0)) != SCPE_OK) continue;
if (i==0) printf(" TOS: "); else printf(" %3d: ",i);
printf("%04x ($%04x)\n", data, reg_sp+i);
}
return SCPE_OK;
}
static t_stat pdq3_cmd_exmscw(int32 arg, char *buf)
{
char* next;
return dbg_dump_mscw(stdout, buf[0] ? pdq3_parse_addr(&cpu_dev, buf, &next) : reg_mp);
}
static t_stat pdq3_cmd_extib(int32 arg, char *buf)
{
char* next;
return dbg_dump_tib(stdout, buf[0] ? pdq3_parse_addr(&cpu_dev, buf, &next) : reg_ctp);
}
static t_stat pdq3_cmd_exseg(int32 arg, char *buf)
{
t_stat rc;
uint16 nsegs;
uint16 segnum, segptr;
char* next;
FILE* fd = stdout; /* XXX */
if (reg_ssv < 0x2030 || reg_ssv > 0xf000) {
fprintf(fd, "Cannot list segments in bootloader: incomplete tables\n");
return SCPE_NXM;
}
if ((rc=Read(reg_ssv, -1, &nsegs, 0)) != SCPE_OK) return rc;
if (buf[0]) {
segnum = pdq3_parse_addr(&cpu_dev, buf, &next);
fprintf(fd, "Segment $%02x\n", segnum);
if (segnum > nsegs) {
fprintf(fd, "Too high: maxsegs=$%02x\n",nsegs);
return SCPE_ARG;
}
if ((rc=Read(reg_ssv, segnum, &segptr, 0)) != SCPE_OK) return rc;
rc = dbg_dump_seg(fd, segptr);
} else
rc = dbg_dump_segtbl(fd);
return rc;
}
static t_stat pdq3_cmd_calltree(int32 arg, char *buf) {
return dbg_calltree(stdout);
}
static t_stat pdq3_cmd_namealias(int32 arg, char *buf) {
char* name, *alias;
if (buf[0]==0)
return dbg_listalias(stdout);
name = strtok(buf, " \t");
alias = strtok(NULL, " \t\n");
return dbg_enteralias(name,alias);
}
/**************************************************************************************
* PDQ utility functions
*************************************************************************************/
OPTABLE optable[] = {
/*00*/ { "SLDC0", OP_NULL }, { "SLDC1", OP_NULL },
/*02*/ { "SLDC2", OP_NULL }, { "SLDC3", OP_NULL },
/*04*/ { "SLDC4", OP_NULL }, { "SLDC5", OP_NULL },
/*06*/ { "SLDC6", OP_NULL }, { "SLDC7", OP_NULL },
/*08*/ { "SLDC8", OP_NULL }, { "SLDC9", OP_NULL },
/*0a*/ { "SLDC10", OP_NULL }, { "SLDC11", OP_NULL },
/*0c*/ { "SLDC12", OP_NULL }, { "SLDC13", OP_NULL },
/*0e*/ { "SLDC14", OP_NULL }, { "SLDC15", OP_NULL },
/*10*/ { "SLDC16", OP_NULL }, { "SLDC17", OP_NULL },
/*12*/ { "SLDC18", OP_NULL }, { "SLDC19", OP_NULL },
/*14*/ { "SLDC20", OP_NULL }, { "SLDC21", OP_NULL },
/*16*/ { "SLDC22", OP_NULL }, { "SLDC23", OP_NULL },
/*18*/ { "SLDC24", OP_NULL }, { "SLDC25", OP_NULL },
/*1a*/ { "SLDC26", OP_NULL }, { "SLDC27", OP_NULL },
/*1c*/ { "SLDC28", OP_NULL }, { "SLDC29", OP_NULL },
/*1e*/ { "SLDC30", OP_NULL }, { "SLDC31", OP_NULL },
/*20*/ { "SLDL1", OP_NULL }, { "SLDL2", OP_NULL },
/*22*/ { "SLDL3", OP_NULL }, { "SLDL4", OP_NULL },
/*24*/ { "SLDL5", OP_NULL }, { "SLDL6", OP_NULL },
/*26*/ { "SLDL7", OP_NULL }, { "SLDL8", OP_NULL },
/*28*/ { "SLDL9", OP_NULL }, { "SLDL10", OP_NULL },
/*2a*/ { "SLDL11", OP_NULL }, { "SLDL12", OP_NULL },
/*2c*/ { "SLDL13", OP_NULL }, { "SLDL14", OP_NULL },
/*2e*/ { "SLDL15", OP_NULL }, { "SLDL16", OP_NULL },
/*30*/ { "SLDO1", OP_NULL }, { "SLDO2", OP_NULL },
/*32*/ { "SLDO3", OP_NULL }, { "SLDO4", OP_NULL },
/*34*/ { "SLDO5", OP_NULL }, { "SLDO6", OP_NULL },
/*36*/ { "SLDO7", OP_NULL }, { "SLDO8", OP_NULL },
/*38*/ { "SLDO9", OP_NULL }, { "SLDO10", OP_NULL },
/*3a*/ { "SLDO11", OP_NULL }, { "SLDO12", OP_NULL },
/*3c*/ { "SLDO13", OP_NULL }, { "SLDO14", OP_NULL },
/*3e*/ { "SLDO15", OP_NULL }, { "SLDO16", OP_NULL },
/*40*/ { "", OP_ERROR }, { "", OP_ERROR },
/*42*/ { "", OP_ERROR }, { "", OP_ERROR },
/*44*/ { "", OP_ERROR }, { "", OP_ERROR },
/*46*/ { "", OP_ERROR }, { "", OP_ERROR },
/*48*/ { "", OP_ERROR }, { "", OP_ERROR },
/*4a*/ { "", OP_ERROR }, { "", OP_ERROR },
/*4c*/ { "", OP_ERROR }, { "", OP_ERROR },
/*4e*/ { "", OP_ERROR }, { "", OP_ERROR },
/*50*/ { "", OP_ERROR }, { "", OP_ERROR },
/*52*/ { "", OP_ERROR }, { "", OP_ERROR },
/*54*/ { "", OP_ERROR }, { "", OP_ERROR },
/*56*/ { "", OP_ERROR }, { "", OP_ERROR },
/*58*/ { "", OP_ERROR }, { "", OP_ERROR },
/*5a*/ { "", OP_ERROR }, { "", OP_ERROR },
/*5c*/ { "", OP_ERROR }, { "", OP_ERROR },
/*5e*/ { "", OP_ERROR }, { "", OP_ERROR },
/*60*/ { "", OP_ERROR }, { "", OP_ERROR },
/*62*/ { "", OP_ERROR }, { "", OP_ERROR },
/*64*/ { "", OP_ERROR }, { "", OP_ERROR },
/*66*/ { "", OP_ERROR }, { "", OP_ERROR },
/*68*/ { "", OP_ERROR }, { "", OP_ERROR },
/*6a*/ { "", OP_ERROR }, { "", OP_ERROR },
/*6c*/ { "", OP_ERROR }, { "", OP_ERROR },
/*6e*/ { "", OP_ERROR }, { "", OP_ERROR },
/*70*/ { "", OP_ERROR }, { "", OP_ERROR },
/*72*/ { "", OP_ERROR }, { "", OP_ERROR },
/*74*/ { "", OP_ERROR }, { "", OP_ERROR },
/*76*/ { "", OP_ERROR }, { "", OP_ERROR },
/*78*/ { "SIND0", OP_NULL }, { "SIND1", OP_NULL },
/*7a*/ { "SIND2", OP_NULL }, { "SIND3", OP_NULL },
/*7c*/ { "SIND4", OP_NULL }, { "SIND5", OP_NULL },
/*7e*/ { "SIND6", OP_NULL }, { "SIND7", OP_NULL },
/*80*/ { "LDCB", OP_UB }, { "LDCI", OP_W },
/*82*/ { "LCA", OP_AB }, { "LDC", OP_BUB },
/*84*/ { "LLA", OP_B }, { "LDO", OP_B },
/*86*/ { "LAO", OP_B }, { "LDL", OP_B },
/*88*/ { "LDA", OP_DBB }, { "LOD", OP_DBB },
/*8a*/ { "UJP", OP_SB }, { "UJPL", OP_SW },
/*8c*/ { "MPI", OP_NULL }, { "DVI", OP_NULL },
/*8e*/ { "STM", OP_UB }, { "MODI", OP_NULL },
/*90*/ { "CPL", OP_UB }, { "CPG", OP_UB },
/*92*/ { "CPI", OP_DBUB }, { "CXL", OP_UBUB },
/*94*/ { "CXG", OP_UBUB }, { "CXI", OP_UBDBUB },
/*96*/ { "RPU", OP_B }, { "CPF", OP_NULL },
/*98*/ { "LDCN", OP_NULL }, { "LSL", OP_DB },
/*9a*/ { "LDE", OP_UBB }, { "LAE", OP_UBB },
/*9c*/ { "NOP", OP_NULL }, { "LPR", OP_NULL },
/*9e*/ { "BPT", OP_NULL }, { "BNOT", OP_NULL },
/*a0*/ { "LOR", OP_NULL }, { "LAND", OP_NULL },
/*a2*/ { "ADI", OP_NULL }, { "SBI", OP_NULL },
/*a4*/ { "STL", OP_B }, { "SRO", OP_B },
/*a6*/ { "STR", OP_DBB }, { "LDB", OP_NULL },
/*a8*/ { "LHO", OP_NULL }, { "LVO", OP_NULL },
/*aa*/ { "", OP_ERROR }, { "", OP_ERROR },
/*ac*/ { "", OP_ERROR }, { "", OP_ERROR },
/*ae*/ { "", OP_ERROR }, { "", OP_ERROR },
/*b0*/ { "EQUI", OP_NULL }, { "NEQI", OP_NULL },
/*b2*/ { "LEQI", OP_NULL }, { "GEQI", OP_NULL },
/*b4*/ { "LEUSW", OP_NULL }, { "GEUSW", OP_NULL },
/*b6*/ { "EQUPWR", OP_NULL }, { "LEQPWR", OP_NULL },
/*b8*/ { "GEQPWR", OP_NULL }, { "EQUBYT", OP_B },
/*ba*/ { "LEQBYT", OP_B }, { "GEQBYT", OP_B },
/*bc*/ { "SRS", OP_NULL }, { "SWAP", OP_NULL },
/*be*/ { "TNC", OP_NULL }, { "RND", OP_NULL },
/*c0*/ { "ADR", OP_NULL }, { "SBR", OP_NULL },
/*c2*/ { "MPR", OP_NULL }, { "DVR", OP_NULL },
/*c4*/ { "STO", OP_NULL }, { "MOV", OP_B },
/*c6*/ { "DUP2", OP_NULL }, { "ADJ", OP_UB },
/*c8*/ { "STB", OP_NULL }, { "LDP", OP_NULL },
/*ca*/ { "STP", OP_NULL }, { "CHK", OP_NULL },
/*cc*/ { "FLT", OP_NULL }, { "EQUREAL",OP_NULL },
/*ce*/ { "LEQREAL",OP_NULL }, { "GEQREAL",OP_NULL },
/*d0*/ { "LDM", OP_UB }, { "SPR", OP_NULL },
/*d2*/ { "EFJ", OP_SB }, { "NFJ", OP_SB },
/*d4*/ { "FJP", OP_SB }, { "FJPL", OP_SW },
/*d6*/ { "XJP", OP_B }, { "IXA", OP_B },
/*d8*/ { "IXP", OP_UBUB }, { "STE", OP_UBB },
/*da*/ { "INN", OP_NULL }, { "UNI", OP_NULL },
/*dc*/ { "INT", OP_NULL }, { "DIF", OP_NULL },
/*de*/ { "SIGNAL", OP_NULL }, { "WAIT", OP_NULL },
/*e0*/ { "ABI", OP_NULL }, { "NGI", OP_NULL },
/*e2*/ { "DUP1", OP_NULL }, { "ABR", OP_NULL },
/*e4*/ { "NGR", OP_NULL }, { "LNOT", OP_NULL },
/*e6*/ { "IND", OP_B }, { "INC", OP_B },
};
static uint16 UB(t_value arg)
{
return arg & 0xff;
}
static uint16 DB(t_value arg)
{
return UB(arg);
}
static int16 W(t_value arg1, t_value arg2)
{
uint16 wl = arg1 & 0xff;
uint16 wh = arg2 & 0xff;
return wl | ((wh << 8) & 0xff00);
}
static int16 SW(t_value arg1, t_value arg2)
{
return W(arg1,arg2);
}
static int16 SB(t_value arg)
{
int16 w = arg & 0xff;
if (w & 0x80) w |= 0xff00;
return w;
}
static uint16 B(t_value arg1, t_value arg2, int* sz) {
uint16 wh = arg1 & 0xff;
uint16 wl;
if (wh & 0x80) {
wl = arg2 & 0xff;
wl |= ((wh & 0x7f) << 8);
*sz = 2;
return wl;
} else {
*sz = 1;
return wh;
}
}
t_stat print_hd(FILE *of, t_value val, t_bool hexdec, t_bool isbyte)
{
uint16 data = isbyte ? (val & 0xff) : (val & 0xffff);
if (hexdec)
fprintf(of,"%0xh",data);
else
fprintf(of,"%d",data);
return SCPE_OK;
}
t_stat fprint_sym_m (FILE *of, t_addr addr, t_value *val,
UNIT *uptr, int32 sw)
{
uint16 op, arg1, arg2, arg3;
int16 sarg;
t_stat size = 0;
int optype, sz;
t_bool hexdec = (sw & SWMASK('H')) ? TRUE : FALSE;
addr = ADDR_OFF(addr);
op = val[0];
if (op > 0xe7) return SCPE_ARG;
optype = optable[op].flags;
if (optype > OP_ERROR) {
fprintf(of,"%-8s", optable[op].name);
switch (optype) {
case OP_NULL:
break;
case OP_UB:
size = 1; arg1 = UB(val[1]);
print_hd(of, arg1, hexdec, FALSE);
break;
case OP_W:
size = 2; sarg = W(val[1],val[2]);
print_hd(of, sarg, hexdec, FALSE);
break;
case OP_AB:
arg1 = B(val[1],val[2], &sz); size = sz;
fprintf(of,"#%x", arg1*2);
break;
case OP_B:
arg1 = B(val[1],val[2], &sz); size = sz;
print_hd(of, arg1, hexdec, FALSE);
break;
case OP_DBB:
arg1 = DB(val[1]);
arg2 = B(val[2],val[3], &sz); size = sz+1;
print_hd(of, arg1, hexdec, TRUE); fputc(',',of);
print_hd(of, arg2, hexdec, FALSE);
break;
case OP_UBB:
arg1 = UB(val[1]);
arg2 = B(val[2],val[3], &sz); size = sz+1;
print_hd(of, arg1, hexdec, TRUE); fputc(',',of);
print_hd(of, arg2, hexdec, FALSE);
break;
case OP_BUB:
arg1 = B(val[1],val[2], &sz); size = sz+1;
arg2 = UB(val[sz+1]);
print_hd(of, arg1, hexdec, FALSE); fputc(',',of);
print_hd(of, arg2, hexdec, TRUE);
break;
case OP_SB:
size = 1; sarg = SB(val[1]);
fprintf(of,"#%x", addr+sarg+2);
break;
case OP_SW:
size = 2; sarg = SW(val[1],val[2]);
fprintf(of,"#%x", addr+sarg+3);
break;
case OP_DBUB:
size = 2; arg1 = DB(val[1]);
arg2 = UB(val[2]);
print_hd(of, arg1, hexdec, TRUE); fputc(',',of);
print_hd(of, arg2, hexdec, TRUE);
break;
case OP_UBUB:
size = 2; arg1 = UB(val[1]);
arg2 = UB(val[2]);
print_hd(of, arg1, hexdec, TRUE); fputc(',',of);
print_hd(of, arg2, hexdec, TRUE);
break;
case OP_UBDBUB:
size = 3; arg1 = UB(val[1]);
arg2 = DB(val[2]);
arg3 = UB(val[3]);
print_hd(of, arg1, hexdec, TRUE); fputc(',',of);
print_hd(of, arg2, hexdec, TRUE); fputc(',',of);
print_hd(of, arg3, hexdec, TRUE);
break;
case OP_DB:
size = 1; arg1 = DB(val[1]);
print_hd(of, arg1, hexdec, TRUE);
break;
}
return -size;
} else {
fprintf(of,"%-8s","DB"); print_hd(of, op, hexdec, TRUE);
return SCPE_OK;
}
}
/* Symbolic decode
Inputs:
*of = output stream
addr = current PC
*val = pointer to data
*uptr = pointer to unit
sw = switches
Outputs:
return = status code
*/
t_stat fprint_sym (FILE *of, t_addr addr, t_value *val,
UNIT *uptr, int32 sw)
{
t_addr off;
T_FLCVT t;
int ch;
t_bool hexdec = (sw & SWMASK('H')) ? TRUE : FALSE;
if (sw & SWMASK('M') && !ADDR_ISWORD(addr)) {
return fprint_sym_m(of, addr, val, uptr, sw);
}
if (sw & SWMASK('B')) { /* as BYTE */
if (ADDR_ISWORD(addr)) {
fprint_val(of, (val[0]>>8) & 0xff, cpu_dev.dradix, 8, PV_RZRO);
fprintf(of, ",");
fprint_val(of, val[0] & 0xff, cpu_dev.dradix, 8, PV_RZRO);
} else
fprint_val(of, val[0], cpu_dev.dradix, 8, PV_RZRO);
return SCPE_OK;
}
if (sw & SWMASK('C')) { /* as CHAR */
if (ADDR_ISWORD(addr)) {
ch = val[0] & 0xff;
fprintf(of, isprint(ch) ? "%c," : "%02x,", ch);
ch = val[0]>>8;
fprintf(of, isprint(ch) ? "%c" : "%02x", ch);
} else {
ch = val[0] & 0xff;
fprintf(of, isprint(ch) ? "%c" : "%02x", ch);
}
return SCPE_OK;
}
if (sw & SWMASK('W')) { /* as WORD */
if (ADDR_ISWORD(addr)) {
fprint_val(of, val[0], cpu_dev.dradix, 16, PV_RZRO);
off = ADDR_OFF(addr);
if (off > (reg_bp+MSCW_SZ-1))
fprintf(of," (GLOBAL+%d)", off - reg_bp - MSCW_SZ + 1);
else if (off >= reg_mp && off <= (reg_mp+OFFB_MSSEG))
fprintf(of," (MP+%d)", off - reg_mp);
else if (off > (reg_mp+MSCW_SZ-1))
fprintf(of," (LOCAL+%d)", off - reg_mp - MSCW_SZ + 1);
else if (off >= reg_sp && off < reg_spupr)
fprintf(of," (SP+%d)", off - reg_sp);
} else {
fprint_val(of, val[0], cpu_dev.dradix, 8, PV_RZRO);
fprint_val(of, val[1], cpu_dev.dradix, 8, PV_RZRO);
}
return SCPE_OK;
}
if (sw & SWMASK('F')) { /* as FLOAT */
t.i[0] = val[1];
t.i[1] = val[0];
fprintf(of, "%12.6e", t.f);
return -1;
}
if (sw & SWMASK('S')) { /* as semaphore */
fprintf(of, "SEM(count=%d, waitq=$%04x)", val[0], val[1]);
return -1;
}
if (sw & SWMASK('M')) { /* as MSCW */
dbg_dump_mscw(of, val[0]);
return SCPE_OK;
}
if (sw & SWMASK('T')) { /* as TIB */
dbg_dump_tib(of, addr);
return SCPE_OK;
}
return SCPE_ARG;
}
/* Symbolic input
Inputs:
*cptr = pointer to input string
addr = current PC
*uptr = pointer to unit
*val = pointer to output values
sw = switches
Outputs:
status = error status
*/
t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw)
{
return SCPE_ARG;
}

2
PDQ-3/run.cmd Normal file
View File

@@ -0,0 +1,2 @@
@echo off
pdq3.exe testhdt.sim

125
PDQ-3/testhdt.sim Normal file
View File

@@ -0,0 +1,125 @@
;set debug debug.log
set debug stdout
;set fdc debug=read
;set fdc debug=write
;set fdc debug=verbose
;set fdc debug=svc
;set fdc debug=imd
;set fdc debug=dma
;set fdc debug=dmavb
;set fdc debug=cmd
;set cpu exc
;set cpu debug=int
;set cpu debug=trace
;set cpu debug=write
;set cpu debug=read
;set cpu debug=fetch
;set cpu debug=stack
;set cpu debug=conc
;set con debug=svc
;set con debug=read
;set con debug=write
;set tim debug=read
;set tim debug=write
;set tim debug=svc
att con 8000
att fdc0 master.imd
set fdc0 wrtlck
set fdc1 disable
; HDT boot
;break f418:368
;break f418:36a
;break f418:218
; HDT:bootfd
;break f418:e0
; HDT CHK instruction: will fail if CPU serial is > 0x7fff
;break 2018:067d
;break 2018:070f
; entering PASCALSY
;break eb1e:10
; problem main loop in syscode1
;break dc26:1d0a
;break d488:b1b
;break d488:b55
; bug in SPR(4), does not save SP in TIB?
;break d488:bb8
;break d488:bc7
; problem with wait?
;break d488:0917
; interrupt debugging
;break d078:4f
;break d488:919
;break d488:ebe
;break dc26:ec3
;break d1bd:79
;break b80d:715
;break dc26:1d35
;break d488:806
;break d488:915
;break dc26:1d36
; SHELL handling
;break badf:98
;break badf:51
;break bbd2:1ba
;break bbd2:1be
;break bbd2:32a
; Ser_RawEmit
;break c964:5f2
;break d488:d80
;break c964:6be
; ticker interrrupts
;break d078:4f
;break d1bd:6e
; Start/Stop Process
;break d488:7f0
;break d488:92e
;break d488:934
;break d488:958
;break d488:0dd9
;break c964:756
;break c964:a6
;break c964:cf4
; waiting for DSR sem
;break c964:624
; Ser_Read
;break c964:466
;break c964:4f9
;break c964:4fa
;break c964:327
;break c964:59e
;break c964:323
;break d078:4c
;break d078:4f
;break d1bd:6a
;break d1bd:6d
;break d488:ed0
load hdt/CPU_C5.BIN
dep _ssr 80
dep _ses 80
do names.sim
boot cpu
set debug stdout