mirror of
https://github.com/pkimpel/retro-b5500.git
synced 2026-02-12 03:07:30 +00:00
Commit DCMCP transcription as of 2012-06-03; commit initial emulator
module constructors.
This commit is contained in:
@@ -2338,3 +2338,236 @@ ARRAY MAINTBUFFER[*]; 04121950
|
||||
END 04134950
|
||||
ELSE GO TO DC; 04134955
|
||||
END ELSE GO TO X; 04134960
|
||||
END; 04134990
|
||||
IF E = 0 THEN 04135000
|
||||
BEGIN % RECOVERED MASS STORAGE % 04137000
|
||||
MAINTBUFFER[NXDISK:=NXDISK+4 AND 15] 04137100
|
||||
:= -0 & U[2:46:2] & LOCATQUE[S][4:3:5] & 04137110
|
||||
(LOIGENTRY:=LOGENTRY+1)[CTF] & 04137120
|
||||
RDCTABLE[U]{18:1:2]; 04137130
|
||||
IF FINALQUE[S] GTR 0 THEN 04137140
|
||||
BEGIN 04137150
|
||||
MAINTBUFFER[XNDISK]:=(*P(DUP)) & 04137160
|
||||
((M[M[S1:=LOCATQUE[S] INX NOT 2] INX 4]04137170
|
||||
.[13:11] DIV ETRLNG)+1)[9:39:9]; 04137180
|
||||
M[S1].[7:1] := 1; 04137190
|
||||
END; 04137200
|
||||
P(MAINTBUFFER[NXDISK+2]:=IOQUE[S]); 04137202
|
||||
$ SET OMIT = NOT(AUXMEM) 04137203
|
||||
P(NFLAG(M[P])); 04137212
|
||||
P(P&V[1:44:4],[MAINTBUFFER[NXDISK+1]],STD); 04137215
|
||||
MAINTBUFFER[NXDISK+3]:=MAINTBUFFER[U]; 04137220
|
||||
IF (LOGHOLDER INX 0) = 0 THEN 04137230
|
||||
BEGIN 04137240
|
||||
LOGHOLDER.[CF]:=[MAINTBUFFER[NXDISK]]; 04137250
|
||||
INDEPENDENTRUNNER(P(.MAINTLOGGER),0,100); 04137260
|
||||
END ELSE M[LOGHOLDER.[FF]].[CF]:= 04137270
|
||||
[MAINTBUFFER[NXDISK]]; 04137275
|
||||
LOGHOLDER.[FF]:=[MAINTBUFFER[NXDISK]]; 04137280
|
||||
NUMAINTMESS:= NUMAINTMESS+1; 04137290
|
||||
T.[5:8] ~ 0; 04142000
|
||||
GO TO SW; 04142500
|
||||
END;% 04143000
|
||||
IF V = 0 THEN% 04144000
|
||||
$ SET OMIT = NOT(SHAREDISK) 04144099
|
||||
BEGIN % ORIGINAL ERROR ON MASS STORAGE% 04145000
|
||||
TINU[U].[18:2] ~ P(DUP).[18:12]+1;% 04146000
|
||||
MAINTBUFFER[U]:=R&TWO(C)[18:43:4]; 04146100
|
||||
RDCTABLE[U]:=(*P(DUP))&(C-1)[1:46:2]; 04146200
|
||||
V:=129; 04147000
|
||||
$ SET OMIT = NOT(SHAREDISK) 04147399
|
||||
END% 04148000
|
||||
ELSE BEGIN % RECURRENT ERROR ON MASS STORAGE% 04149000
|
||||
P(MAINTBUFFER[U]:=P(DUP,LOD) OR 04150100
|
||||
R&TWO(C)[18:43:4]); 04150200
|
||||
IF (V ~ V+1) > 137 THEN% 04151000
|
||||
BEGIN R:=P; 04151200
|
||||
IF LOCATQUE[S].[9:1] THEN % OLAY I/O 04151220
|
||||
M[LOCATQUE[S]:=R OR IOMASK; 04151230
|
||||
$ SET OMIT = NOT(AUXMEM) 04151235
|
||||
DISKERR: 04151300
|
||||
$ SET OMIT = NOT(DFX) 04151399
|
||||
T.[5:10]:=0; 04151400
|
||||
GO TO DX; 04152600
|
||||
END; 04152800
|
||||
P(DEL); 04152900
|
||||
END;% 04153000
|
||||
UNIT[U] ~ T&V[5:40:8];% 04154000
|
||||
DS:% 04155000
|
||||
CHANNEL[P(TIO)] ~ U;% 04156000
|
||||
P([IOQUE[S]],IIO);% 04157000
|
||||
GO TO EXTERNAL ;% 04158000
|
||||
X: STOP ~ (V!0)|2+1;% 04159000
|
||||
T.[5:13] ~ 32|E+8;% 04160000
|
||||
GO TO TEST; 04161000
|
||||
END; 04161500
|
||||
SW:: GO TO TYPE[T.[1:4]];% 04162000
|
||||
LP: 04163000
|
||||
IF STOP := (T := T&0[16:16:1]).[17:1] THEN 04164000
|
||||
TEST: IF FIRSTWAIT = NEXTWAIT THEN GO TO INCR ELSE% 04165000
|
||||
GO TO NEW ELSE GO TO NOWAIT;% 04166000
|
||||
DK: 04167900
|
||||
IF NOT (I:=IOQUE[S]).[24:1] THEN 04168000
|
||||
IF FINALQUE[S].[24:1] THEN% 04169000
|
||||
$ SET OMIT = DFX 04169090
|
||||
BEGIN 04169100
|
||||
$ SET OMIT = NOT DKBNODFX OR OMIT 04169190
|
||||
$ SET OMIT = DKBNODFX OR OMIT 04170750
|
||||
M[IOQUE[S]:=I&1[24:47:1]]:=*(P(DUP) INX P(0,LNG,XCH)); 04170800
|
||||
$ POP OMIT 04170900
|
||||
GO TO DS; 04171000
|
||||
END ELSE GO TO OK ELSE GO TO OK; 04171200
|
||||
$ POP OMIT 04171250
|
||||
$ SET OMIT = NOT DFX 04171350
|
||||
DC: 04174000
|
||||
$ SET OMIT = NOT(DATACOM ) 04174999
|
||||
04176000
|
||||
$ SET OMIT = DFX 04176899
|
||||
DX: DX1: 04176900
|
||||
$ POP OMIT 04176901
|
||||
OK: IF FIRSTWAIT = NEXTWAIT THEN 04177000
|
||||
NOWAIT: IF (S1 := LOCATQUE[S].[18:15]) LSS @1777 THEN 04178000
|
||||
INITIATEIO(IOQUE[S1],LOCATQUE[S1].[3:5],U)% 04180000
|
||||
ELSE 04181000
|
||||
PROC: T := T&0[16:16:2] 04182000
|
||||
ELSE 04183000
|
||||
BEGIN% 04187000
|
||||
NEW: NEWIO;% 04188000
|
||||
IF STOP THEN GO TO INCR;% 04189000
|
||||
QUP: IF LOCATQUE[S].[FF] GTR @1777 THEN GO TO PROC; 04190000
|
||||
QUEUEUP(U);% 04191000
|
||||
T ~ T&4[13:43:5];% 04192000
|
||||
END;% 04193000
|
||||
INCR: 04194000
|
||||
IF (TIM~CLOCK+P(RTR)-TIM) LSS THEN THEN TIM~0; 04194050
|
||||
IOD:=IOQUE[S]; 04194100
|
||||
IF (U OR 1 )=19 THEN 04194200
|
||||
BEGIN 04194300
|
||||
IF (JUNK:=M[IOD].[5:7])>9 THEN 04194400
|
||||
JUNK:=NEUP.[CF]+(JUNK AND @17); 04194500
|
||||
IF JUNK<NEUP.[FF] THEN 04194550
|
||||
PEUIO[JUNK]:=P(DUP,LOD)+CLOCK+P(RTR)-EUIO[C]; 04194600
|
||||
END; 04194650
|
||||
I~(S1~LOCATQUE[S]).[3:5]; % FIND MIX INDEX 04194700
|
||||
$ SET OMIT = NOT(NEWLOGGING) 04194799
|
||||
IOTIME[I]~(*P(DUP))+TIM; 04195000
|
||||
IF P(.S1,LOD).[10:1] THEN FORGETSPACE(IOD); % NO MEM MESSAGE 04195100
|
||||
IF F!0 THEN 04196200
|
||||
IF STOP THEN 04196400
|
||||
P(T) 04196600
|
||||
ELSE GO TO L1 04196800
|
||||
ELSE BEGIN 04197000
|
||||
RETURNIOSPACE(S); 04199000
|
||||
L1: P(T&P(.L1,LOD)[FTF]); 04201000
|
||||
END; 04202000
|
||||
P([UNIT[U]],STD); 04203000
|
||||
FIN ~ FINALQUE[S] AND NOT MEMORY;% 04205000
|
||||
IF (U OR 1) NEQ 17 THEN 04205012
|
||||
IF IOD.[24:1] THEN% 04206000
|
||||
BEGIN V ~ ABS(IOD.[33:15]-R.[33:15]);% 04207000
|
||||
IF IOD.[8:10] < V THEN% 04208000
|
||||
IF IOD.[23:1] THEN% 04209000
|
||||
V ~ IOD.[8:10];% 04210000
|
||||
IF U < 16 THEN% 04211000
|
||||
IF IOD.[21:2] = 0 THEN% 04212000
|
||||
BEGIN; STREAM(A!0:B~M[S1.[33:15]+V-1]);% 04213000
|
||||
BEGIN SI ~ LOC B;% 04214000
|
||||
IF SC = "~" THEN TALLY ~ 1;% 04215000
|
||||
A ~ TALLTY;% 04216000
|
||||
END;% 04217000
|
||||
V ~ -P+V;% 04218000
|
||||
END;% 04219000
|
||||
IF U ! 30 THEN % NOT DCA 04219100
|
||||
FINISHOFFIO(U);% 04220000
|
||||
END;% 04221000
|
||||
IF E ! 0 THEN% 04222000
|
||||
$ SET OMIT = NOT(SHAREDISK) 04222499
|
||||
BEGIN IF STOP LEQ 1 THEN 04223000
|
||||
BEGIN 04223500
|
||||
INDEPENDENTRUNNER( 04224000
|
||||
P(.DISKORAUXERROR)+((U AND @774) NEQ 16), 04224010
|
||||
R&S[3:43:5],240); 04224100
|
||||
LOCATQUE[S].[11:1]:=1; 04224500
|
||||
END 04224750
|
||||
ELSE IF FIN < 0 THEN P(LOCATQUE[S],R,XCH,~);% 04225000
|
||||
END% 04226000
|
||||
$ SET OMIT = NOT(SHAREDISK) 04226499
|
||||
ELSE BEGIN% 04227000
|
||||
IF FIN < 0 THEN P(R OR IOMASK,LOCATQUE[S],~)% 04228000
|
||||
ELSE 04229000
|
||||
$ SET OMIT = NOT (DATACOM OR DFX OR DKBNODFX) 04229099
|
||||
BEGIN 04229200
|
||||
LOCN ~ [M[LOCATQUE[S]]];% 04230000
|
||||
IOD ~ IOD.[33:15];% 04231000
|
||||
WHILE LOCN[0].[33:15] ! IOD DO% 04232000
|
||||
LOCN ~ 1 INX LOCN;% 04233000
|
||||
LOCN[0] ~ M OR FIN;% 04234000
|
||||
END END;% 04235000
|
||||
IF P1MIX = 0 THEN GO TO NOTHINGTODO;% 04236000
|
||||
IF I = P1MIX THEN GO TO RETURN;% 04237000
|
||||
GO TO INITIATE;% 04238000
|
||||
END IOCOMPLETE;% 04239000
|
||||
SAVE REAL PROCEDURE WAITIO(IOD,MASK,U);% 04240000
|
||||
VALUE MASK,U,IOD;% 04241000
|
||||
REAL MASK,U,IOD;% 04242000
|
||||
BEGIN% 04243000
|
||||
REAL T; 04243100
|
||||
DEFINE OCTADE= DS~3 RESET;3(IF SB THEN DS!SET ELSE 04243200
|
||||
DS~RESET;SKIP SB)#; 04243300
|
||||
IOD ~ NFLAG(P(.IOD,LOC))&TINU[U][3:3:5];% 04244000
|
||||
MASK ~ NOT MASK;% 04245000
|
||||
IOREQUEST(NABS(IOD)&MASK[25:40:8],IOD, 04246000
|
||||
[IOD]&U[12:42:6]);% 04247000
|
||||
IOD ~ IOD&0[25:25:8]&0[19:19:1];% 04248000
|
||||
SLEEP([IOD],IOMASK);% 04249000
|
||||
IF ((WAITIO~IOD.[26:7]) AND MASK AND MAKS.[18:15])!0 THEN 04250000
|
||||
BEGIN 04251000
|
||||
T~SPACE(12); 04251100
|
||||
STREAM(IOD~IOD.[26:7],MASK~(NOT MASK).[41:7], 04251200
|
||||
Z~[TINU[U]],T~T); 04251300
|
||||
BEGIN DS~20 LIT" UNEXP I-O ERROR ON ";SI~Z; 04251400
|
||||
SI~SI+5;DS~3 CHR;DS~8 LIT":RESULT="; 04251500
|
||||
SI~LOC IOD;SI~SI+6;SKIP 3 SB;3(OCTADE); 04251600
|
||||
DS~6 LIT",MASK=" ;SI~SI+6;SKIP 3 SB; 04251700
|
||||
3(OCTADE);DS~2 LIT".~"; 04251800
|
||||
END; 04251900
|
||||
IF P1MIX = 0 THEN BEGIN P(T); PUNT(0) END; 04252000
|
||||
IF NOTERMSET(P1MIX) THEN 04252100
|
||||
BEGIN 04252200
|
||||
TERMINATE(P1MIX&19[18:33:15]); 04252300
|
||||
IF JAR[P1MIX,9].SYSJOBF THEN %SYSTEM JOB 04252500
|
||||
BEGIN 04252600
|
||||
SPOUT(T); 04252700
|
||||
BLASTQ(U); 04252800
|
||||
END ELSE 04252900
|
||||
TERMINALMESSAGE(-T); 04253000
|
||||
END; 04253100
|
||||
END; 04253200
|
||||
END; 04253300
|
||||
REAL PROCEDURE TAPEPARITYRETRY(R,U,KEY);% 04254000
|
||||
VALUE R,U,KEY; REAL R,U,KEY; FORWARD; 04255000
|
||||
REAL PROCEDURE WRITEPARITYREELSWITCH(OIOD,RC); 04255100
|
||||
VALUE OIOD,REC; REAL OIOD,RC; FORWARD; 04255200
|
||||
PROCEDURE DISKORAUXERROR(R); VALUE R; REAL R; 04256000
|
||||
04256200
|
||||
BEGIN 04256400
|
||||
REAL MSCW = -2, 04256600
|
||||
U = +1, 04256800
|
||||
S = +2, 04257000
|
||||
E = +3, 04257200
|
||||
T = +4, 04257400
|
||||
MK = +5, CELL = MK, 04257600
|
||||
IOD = +6, 04257800
|
||||
MIX = +7, 04258000
|
||||
FIN = +8, PARITY= FIN, 04258200
|
||||
KEY1 = +9, 04258400
|
||||
KEY2 = +10, 04258600
|
||||
DISC = +11, 04258800
|
||||
MASK = +12, 04259000
|
||||
AREA = +13, U1 = AREA, 04259200
|
||||
RLST = +14, MSG = RSLT, 04259400
|
||||
PRTMAX = +15, T1 = PRTMAX, 04259600
|
||||
DISKCELL= +16, T2 = DISKCELL, 04259800
|
||||
TERMNATE = +17, 04260000
|
||||
OLAYIO = +18, 04260200
|
||||
DSKADRS = +19; 04260400
|
||||
|
||||
114
emulator/B5500CentralControl.js
Normal file
114
emulator/B5500CentralControl.js
Normal file
@@ -0,0 +1,114 @@
|
||||
/***********************************************************************
|
||||
* retro-b5500/emulator B5500CentralControl.js
|
||||
************************************************************************
|
||||
* Copyright (c) 2012, Nigel Williams and Paul Kimpel.
|
||||
* Licensed under the MIT License, see http://www.opensource.org/licenses/mit-license.php
|
||||
************************************************************************
|
||||
* JavaScript object definition for the B5500 Central Control module.
|
||||
************************************************************************
|
||||
* 2012-06-03 P.Kimpel
|
||||
* Original version, from thin air.
|
||||
***********************************************************************/
|
||||
|
||||
/**************************************/
|
||||
function B5500CentralControl() {
|
||||
/* Constructor for the Central Control module object */
|
||||
|
||||
this.IAR = 0; // Interrupt address register
|
||||
this.TM = 0; // Real-time clock (6 bits, 60 ticks per second)
|
||||
|
||||
this.CCI03F = 0; // Time interval interrupt
|
||||
this.CCI04F = 0; // I/O busy interrupt
|
||||
this.CCI05F = 0; // Keyboard request interrupt
|
||||
this.CCI06F = 0; // Printer 1 finished interrupt
|
||||
this.CCI07F = 0; // Printer 2 finished interrupt
|
||||
this.CCI08F = 0; // I/O unit 1 finished interrupt (RD in @14)
|
||||
this.CCI09F = 0; // I/O unit 2 finished interrupt (RD in @15)
|
||||
this.CCI10F = 0; // I/O unit 3 finished interrupt (RD in @16)
|
||||
this.CCI11F = 0; // I/O unit 4 finished interrupt (RD in @17)
|
||||
this.CCI12F = 0; // P2 busy interrupt
|
||||
this.CCI13F = 0; // Remote inquiry request interrupt
|
||||
this.CCI14F = 0; // Special interrupt #1 (not used)
|
||||
this.CCI15F = 0; // Disk file #1 read check finished
|
||||
this.CCI16F = 0; // Disk file #2 read check finished
|
||||
|
||||
this.AD1F = 0; // I/O unit 1 busy
|
||||
this.AD2F = 0; // I/O unit 2 busy
|
||||
this.AD3F = 0; // I/O unit 3 busy
|
||||
this.AD4F = 0; // I/O unit 4 busy
|
||||
|
||||
this.LOFF = 0; // Load button pressed on console
|
||||
this.CTMF = 0; // Commence timing FF
|
||||
this.P2BF = 0; // Processor 2 busy FF
|
||||
this.HP2F = 0; // Halt processor 2 FF
|
||||
this.PB1L = 0; // 0=> PA is P1, 1=> PB is P1
|
||||
|
||||
|
||||
this.rtcTick = 1000/60; // Real-time clock period, milliseconds
|
||||
this.nextTimeStamp = 0; // Next actual Date.getTime() expected
|
||||
}
|
||||
|
||||
/**************************************/
|
||||
B5500CentralControl.prototype.fetch(addr) {
|
||||
/* Called by all modules to fetch a word from memory. /*
|
||||
|
||||
// TO BE PROVIDED
|
||||
}
|
||||
|
||||
/**************************************/
|
||||
B5500CentralControl.prototype.store(addr, word) {
|
||||
/* Called by all modules to fetch a word from memory. /*
|
||||
|
||||
// TO BE PROVIDED
|
||||
}
|
||||
|
||||
/**************************************/
|
||||
B5500CentralControl.prototype.signalInterrupt() {
|
||||
/* Called by all modules to signal that an interrupt has occurred and
|
||||
to invoke the interrupt prioritization mechanism. This will result in
|
||||
an updated vector address in the IAR. /*
|
||||
|
||||
// TO BE PROVIDED
|
||||
}
|
||||
|
||||
/**************************************/
|
||||
B5500CentralControl.prototype.clear() {
|
||||
/* Initializes the system and starts the real-time clock */
|
||||
|
||||
this.nextTimeStamp = new Date().getTime() + this.rtcTick;
|
||||
setTimeout(this.tock, this.rtcTick);
|
||||
}
|
||||
|
||||
/**************************************/
|
||||
B5500CentralControl.prototype.tock() {
|
||||
/* Handles the 1/60th second real-time clock increment */
|
||||
var thisTime = new Date().getTime();
|
||||
|
||||
if (this.TM < 63) {
|
||||
this.TM++;
|
||||
} else {
|
||||
this.TM = 0;
|
||||
this.CCI03F = 1; // set timer interrupt
|
||||
this.signalInterrupt();
|
||||
}
|
||||
this.nextTimeStamp += this.rtcTick;
|
||||
if (this.nextTimeStamp < thisTime) {
|
||||
setTimeout(this.tock, 1); // try to catch up
|
||||
} else {
|
||||
setTimeout(this.tock, this.nextTimeStamp-thisTime);
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************/
|
||||
B5500CentralControl.prototype.halt() {
|
||||
/* Halts the system */
|
||||
|
||||
// TO BE PROVIDED
|
||||
}
|
||||
|
||||
/**************************************/
|
||||
B5500CentralControl.prototype.load() {
|
||||
/* Initiates a Load operation to start the system */
|
||||
|
||||
// TO BE PROVIDED
|
||||
}
|
||||
374
emulator/B5500Processor.js
Normal file
374
emulator/B5500Processor.js
Normal file
@@ -0,0 +1,374 @@
|
||||
/***********************************************************************
|
||||
* retro-b5500/emulator B5500Processor.js
|
||||
************************************************************************
|
||||
* Copyright (c) 2012, Nigel Williams and Paul Kimpel.
|
||||
* Licensed under the MIT License, see http://www.opensource.org/licenses/mit-license.php
|
||||
************************************************************************
|
||||
* JavaScript object definition for the B5500 Processor (CPU) module.
|
||||
************************************************************************
|
||||
* 2012-06-03 P.Kimpel
|
||||
* Original version, from thin air.
|
||||
***********************************************************************/
|
||||
|
||||
/**************************************/
|
||||
function B5500Processor() {
|
||||
/* Constructor for the Processor module object */
|
||||
|
||||
this.A = 0; // Top-of-stack register 1
|
||||
this.AROF = 0; // A contents valid
|
||||
this.B = 0; // Top-of-stack register 2
|
||||
this.BROF = 0; // B contents valid
|
||||
this.C = 0; // Current program instruction word address
|
||||
this.CCCF = 0; // Clock-count control FF (maintenance only)
|
||||
this.CWMF = 0; // Character/word mode FF (1=CM)
|
||||
this.E = 0; // Memory access control register
|
||||
this.EIHF = 0; // ??
|
||||
this.F = 0; // Top MSCW/RCW stack address
|
||||
this.G = 0; // Character index register for A
|
||||
this.H = 0; // Bit index register for G (in A)
|
||||
this.HLTF = 0; // Processor halt FF
|
||||
this.I = 0; // Processor interrupt register
|
||||
this.K = 0; // Character index register for B
|
||||
this.L = 0; // Instruction syllable index in P
|
||||
this.M = 0; // Memory address register (SI.w in CM)
|
||||
this.MRAF = 0; // Memory read access FF
|
||||
this.MROF = 0; // Memory read obtained FF
|
||||
this.MSFF = 0; // Mark-stack FF (word mode: MSCW is pending RCW, physically also TFFF & Q12F)
|
||||
this.MWOF = 0; // Memory write obtained FF
|
||||
this.N = 0; // Octal shift counter for B
|
||||
this.NCSF = 0; // Normal/control state FF (1=normal)
|
||||
this.P = 0; // Current program instruction word register
|
||||
this.PROF = 0; // P contents valid
|
||||
this.Q = 0; // Misc. FFs (bits 1-9 only: Q07F=hardware-induced interrupt, Q09F=enable parallel adder for R-relative addressing)
|
||||
this.R = 0; // PRT base address (high-order 9 bits only)
|
||||
this.S = 0; // Top-of-stack memory address (DI.w in CM)
|
||||
this.SALF = 0; // Program/subroutine state FF (1=subroutine)
|
||||
this.T = 0; // Current program syllable register
|
||||
this.TALLY = 0; // CM TALLY register (physically, low-order 6 bits of R)
|
||||
this.TM = 0; // Temporary maintenance storage register
|
||||
this.TROF = 0; // T contents valid
|
||||
this.V = 0; // Bit index register for K (in B)
|
||||
this.VARF = 0; // Variant-mode FF (enables full PRT indexing)
|
||||
this.X = 0; // Mantissa extension for B (loop control in CM)
|
||||
this.Y = 0; // Serial character register for A
|
||||
this.Z = 0; // Serial character register for B
|
||||
|
||||
this.cycleLimit = 0; // Count-down cycle limit for this.run()
|
||||
this.isP1 = true; // Control processor flag
|
||||
}
|
||||
|
||||
/**************************************/
|
||||
B5500Processor.prototype.access(eValue) {
|
||||
/* Access memory based on the E register */
|
||||
var addr;
|
||||
|
||||
/****************************************************************
|
||||
HOW TO HANDLE INVALID ADDRESS INTERRUPTS DETECTED BY CENTRAL CONTROL?
|
||||
****************************************************************/
|
||||
|
||||
this.E = eValue;
|
||||
switch (eValue) {
|
||||
case 0x02: // A = [S]
|
||||
this.A = cc.fetch(this.S);
|
||||
this.AROF = 1;
|
||||
break;
|
||||
case 0x03: // B = [S]
|
||||
this.B = cc.fetch(this.S);
|
||||
this.BROF = 1;
|
||||
break;
|
||||
case 0x04: // A = [M]
|
||||
this.A = cc.fetch(this.M);
|
||||
this.AROF = 1;
|
||||
break;
|
||||
case 0x05: // B = [M]
|
||||
this.B = cc.fetch(this.M);
|
||||
this.BROF = 1;
|
||||
break;
|
||||
case 0x06: // M = [M].[18:15]
|
||||
this.M = (cc.fetch(this.M) >>> 15) & 0x7FFF;
|
||||
break;
|
||||
case 0x0A: // [S] = A
|
||||
cc.store(this.S, this.A);
|
||||
break;
|
||||
case 0x0B: // [S] = B
|
||||
cc.store(this.S, this.B);
|
||||
break;
|
||||
case 0x0C: // [M] = A
|
||||
cc.store(this.M, this.A);
|
||||
break;
|
||||
case 0x0D: // [M] = B
|
||||
cc.store(this.M, this.B);
|
||||
case 0x30: // P = [C]
|
||||
this.P = cc.fetch(this.C);
|
||||
this.PROF = 1;
|
||||
break;
|
||||
default:
|
||||
throw "Invalid E register value: " + eReg.toString(2);
|
||||
break;
|
||||
}
|
||||
this.cycleLimit -= 6; // assume 6 us memory cycle time
|
||||
|
||||
if (addr < 0x0200 && this.NCSF) { // normal-state cannot address @000-@777 [?? first 512 or 1024 words ??]
|
||||
this.I |= 0x0500; // set I02F & I04F
|
||||
cc.signalInterrupt();
|
||||
} else {
|
||||
cc.store(addr, word);
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************/
|
||||
B5500Processor.prototype.adjustAEmpty() {
|
||||
/* Adjusts the A register so that it is empty pushing the prior
|
||||
contents of A into B and B into memory, as necessary. */
|
||||
|
||||
if (this.AROF} {
|
||||
if (this.BROF) {
|
||||
this.S++;
|
||||
this.access(0x0B); // [S] = B
|
||||
}
|
||||
this.B = this.A;
|
||||
this.AROF = 0;
|
||||
this.BROF = 1;
|
||||
// else we're done -- A is already empty
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************/
|
||||
B5500Processor.prototype.adjustAFull() {
|
||||
/* Adjusts the A register so that it is full, popping the contents of
|
||||
B or [S] into A, as necessary. */
|
||||
|
||||
if (!this.AROF) {
|
||||
if (this.BROF) {
|
||||
this.A = this.B;
|
||||
this.AROF = 1;
|
||||
this.BROF = 0;
|
||||
} else {
|
||||
this.access(0x02); // A = [S]
|
||||
this.S--;
|
||||
}
|
||||
// else we're done -- A is already full
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************/
|
||||
B5500Processor.prototype.adjustBEmpty() {
|
||||
/* Adjusts the B register so that it is empty pushing the prior
|
||||
contents of B into memory, as necessary. */
|
||||
|
||||
if (this.BROF) {
|
||||
this.S++;
|
||||
this.access(0x0B); // [S] = B
|
||||
// else we're done -- B is already empty
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************/
|
||||
B5500Processor.prototype.adjustBFull() {
|
||||
/* Adjusts the B register so that it is full popping the contents of
|
||||
[S] into B, as necessary. */
|
||||
|
||||
if (!this.BROF) {
|
||||
this.access(0x03); // B = [S]
|
||||
this.S--;
|
||||
// else we're done -- B is already full
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************/
|
||||
B5500Processor.storeForInterrupt() {
|
||||
/* Implements the 3011=SFI operator */
|
||||
|
||||
if (this.CWMF) {
|
||||
if (this.BROF) {
|
||||
this.access(0x0B); // [S] = B, save B if valid
|
||||
}
|
||||
if (this.AROF) {
|
||||
this.access(0x0A); // [S] = A, save A if valid
|
||||
}
|
||||
this.B = ((((0x30*512 +
|
||||
(this.R >>> 6))*4 +
|
||||
this.MSFF)*2 +
|
||||
this.SALF)*32768 +
|
||||
this.N)*16 +
|
||||
this.M;
|
||||
this.S++;
|
||||
this.access(0x0B);
|
||||
} else
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************/
|
||||
B5500Processor.prototype.run() {
|
||||
/* Instruction execution driver for the B5500 processor. This function is
|
||||
an artifact of the emulator design and does not represent any physical
|
||||
process or state of the processor. This routine assumes the registers are
|
||||
set up, and in particular a syllable is in T with TROF set. */
|
||||
var opcode;
|
||||
|
||||
/* HOW TO ENTER, EXIT, AND RESUME CHARACTER MODE? */
|
||||
|
||||
this.cycleLimit = 5000; // max CPU cycles to run
|
||||
do {
|
||||
opcode = this.T;
|
||||
switch (opcode & 3) {
|
||||
case 0: // LITC: Literal Call
|
||||
this.adjustAEmpty();
|
||||
this.A = opcode >>> 2;
|
||||
this.AROF = 1;
|
||||
break;
|
||||
|
||||
case 2: // OPDC: Operand Call
|
||||
this.adjustAEmpty();
|
||||
// TO BE PROVIDED
|
||||
break;
|
||||
|
||||
case 3: // DESC: Descriptor (name) Call
|
||||
this.adjustAEmpty();
|
||||
// TO BE PROVIDED
|
||||
break;
|
||||
|
||||
case 1: // all other word-mode operators
|
||||
switch (opcode & 0x3F) {
|
||||
case 0x01: // XX01: single-precision numerics
|
||||
break;
|
||||
|
||||
case 0x05: // XX05: double-precision numerics
|
||||
break;
|
||||
|
||||
case 0x09: // XX11: control state and communication ops
|
||||
switch (opcode >>> 6) {
|
||||
case 0x01: // 0111: PRL=Program Release
|
||||
break;
|
||||
|
||||
case 0x10: // 1011: COM=Communicate
|
||||
this.adjustAFull();
|
||||
this.M = 0x09; // address @11
|
||||
this.access(0x0C); // [M] = A
|
||||
this.AROF = 0;
|
||||
break;
|
||||
|
||||
case 0x02: // 0211: ITI=Interrogate Interrupt
|
||||
break;
|
||||
|
||||
case 0x04: // 0411: RTR=Read Timer
|
||||
adjustAEmpty();
|
||||
this.A = cc.CCI03F << 6 | cc.TM;
|
||||
break;
|
||||
|
||||
case 0x11: // 2111: IOR=I/O Release
|
||||
break;
|
||||
|
||||
case 0x12: // 2211: HP2=Halt Processor 2
|
||||
break;
|
||||
|
||||
case 0x14: // 2411: ZPI=Conditional Halt
|
||||
break;
|
||||
|
||||
case 0x18: // 3011: SFI=Store for Interrupt
|
||||
this.storeForInterrupt();
|
||||
break;
|
||||
|
||||
case 0x1C: // 3411: SFT=Store for Test
|
||||
break;
|
||||
|
||||
case 0x21: // 4111: IP1=Initiate Processor 1
|
||||
break;
|
||||
|
||||
case 0x22: // 4211: IP2=Initiate Processor 2
|
||||
break;
|
||||
|
||||
case 0x24: // 4411: IIO=Initiate I/O
|
||||
break;
|
||||
|
||||
case 0x29: // 5111: IFT=Initiate For Test
|
||||
break;
|
||||
|
||||
default:
|
||||
break; // Anything else is a no-op
|
||||
} / end switch for XX11 ops
|
||||
break;
|
||||
|
||||
case 0x0D: // XX15: logical (bitmask) ops
|
||||
break;
|
||||
|
||||
case 0x11: // XX21: load & store ops
|
||||
break;
|
||||
|
||||
case 0x15: // XX25: comparison & misc. stack ops
|
||||
break;
|
||||
|
||||
case 0x19: // XX31: branch, sign-bit, interrogate ops
|
||||
break;
|
||||
|
||||
case 0x1D: // XX35: exit & return ops
|
||||
break;
|
||||
|
||||
case 0x21: // XX41: index, mark stack, etc.
|
||||
break;
|
||||
|
||||
case 0x25: // XX45: ISO=Variable Field Isolate op
|
||||
break;
|
||||
|
||||
case 0x29: // XX51: delete & conditional branch ops
|
||||
break;
|
||||
|
||||
case 0x2D: // XX55: NOOP & DIA=Dial A ops
|
||||
if (opcode & 0xFC0) {
|
||||
this.G = opcode >>> 9;
|
||||
this.H = (opcode >>> 6) & 7;
|
||||
// else 0055=NOOP
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x31: // XX61: XRT & DIB=Dial B ops
|
||||
if (opcode & 0xFC0) {
|
||||
this.K = opcode >>> 9;
|
||||
this.V = (opcode >>> 6) & 7;
|
||||
} else { // 0061=XRT: temporarily set full PRT addressing mode
|
||||
this.VARF = this.SALF;
|
||||
this.SALF = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x35: // XX65: TRB=Transfer Bits op
|
||||
break;
|
||||
|
||||
case 0x39: // XX71: FCL=Compare Field Low op
|
||||
break;
|
||||
|
||||
case 0x3D: // XX75: FCE=Compare Field Equal op
|
||||
break;
|
||||
|
||||
default:
|
||||
break; // should never get here, but in any case it'd be a no-op
|
||||
} // end switch for word-mode operators
|
||||
break;
|
||||
} // end switch for main opcode dispatch
|
||||
|
||||
// SECL: Syllable Execution Complete Level
|
||||
this.Q = 0;
|
||||
this.Y = 0;
|
||||
this.Z = 0;
|
||||
if (this.CWMF) {
|
||||
this.M = 0;
|
||||
this.N = 0;
|
||||
this.X = 0;
|
||||
}
|
||||
if (cc.IAR && this.NCSF) { // there's an interrupt and we're in normal state
|
||||
this.T = 0x0609; // inject 3011=SFI into T
|
||||
this.Q |= 0x40 // set Q07F=hardware-induced SFI
|
||||
this.Q &= ~(0x100); // reset Q09F=adder mode for R-relative addressing
|
||||
} else {
|
||||
if (this.L < 3) {
|
||||
this.T = (this.P >>> (36-this.L*12)) & 0x0FFF;
|
||||
this.L++;
|
||||
} else {
|
||||
this.T = this.P & 0x0FFF;
|
||||
this.L = 0;
|
||||
this.C++;
|
||||
this.access(0x30); // P = [C]
|
||||
}
|
||||
}
|
||||
} while (--this.Limit > 0);
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
* retro-b5500/emulator Register.js
|
||||
************************************************************************
|
||||
* Copyright (c) 2012, Nigel Williams and Paul Kimpel.
|
||||
* Licensed under the MIT Licensed, see http://www.opensource.org/licenses/mit-license.php
|
||||
* Licensed under the MIT License, see http://www.opensource.org/licenses/mit-license.php
|
||||
************************************************************************
|
||||
* JavaScript object definition for the generalized Register prototype.
|
||||
* Maximum register width is 52 bits, since Javascript stores numbers
|
||||
|
||||
Reference in New Issue
Block a user