Fixed the memory clear "toggle-in", by returning the correct amount of installed RAM, and passing properly masked addresses to all the I/O handlers
This commit is contained in:
parent
a7a44a8288
commit
0cf11c0b01
8 changed files with 605 additions and 511 deletions
|
|
@ -94,7 +94,7 @@ function BusPDP11(parmsBus, cpu, dbg)
|
|||
* as a result, our IOController functions assume that all incoming offsets are within a single 8Kb block.
|
||||
*/
|
||||
this.addrTotal = 1 << this.nBusWidth;
|
||||
this.nBusLimit = this.nBusMask = (this.addrTotal - 1);
|
||||
this.nBusMask = (this.addrTotal - 1);
|
||||
this.nBlockSize = BusPDP11.IOPAGE_LENGTH;
|
||||
this.nBlockShift = Math.log2(this.nBlockSize); // ES6 ALERT (alternatively: Math.log(this.nBlockSize) / Math.LN2)
|
||||
this.nBlockLen = this.nBlockSize >> 2;
|
||||
|
|
@ -135,6 +135,7 @@ function BusPDP11(parmsBus, cpu, dbg)
|
|||
this.fIOBreakAll = false;
|
||||
this.nDisableFaults = 0;
|
||||
this.fFault = false;
|
||||
this.cbRAM = 0;
|
||||
|
||||
/*
|
||||
* Array of RESET notification handlers registered by Device components.
|
||||
|
|
@ -242,21 +243,28 @@ BusPDP11.IOController = {
|
|||
var b = -1;
|
||||
var bus = this.controller;
|
||||
var afn = bus.aIOHandlers[off];
|
||||
|
||||
/*
|
||||
* Since addr is primarily used to advise an I/O handler of the target IOPAGE address, and since we don't want
|
||||
* our handlers to worry about the current IOPAGE location, we truncate addr to 16 bits (the IOPAGE's lowest location).
|
||||
*/
|
||||
var addrMasked = addr & 0xffff;
|
||||
|
||||
if (afn) {
|
||||
if (afn[BusPDP11.IOHANDLER.READ_BYTE]) {
|
||||
b = afn[BusPDP11.IOHANDLER.READ_BYTE](addr);
|
||||
b = afn[BusPDP11.IOHANDLER.READ_BYTE](addrMasked);
|
||||
} else if (afn[BusPDP11.IOHANDLER.READ_WORD]) {
|
||||
if (!(addr & 0x1)) {
|
||||
b = afn[BusPDP11.IOHANDLER.READ_WORD](addr) & 0xff;
|
||||
if (!(addrMasked & 0x1)) {
|
||||
b = afn[BusPDP11.IOHANDLER.READ_WORD](addrMasked) & 0xff;
|
||||
} else {
|
||||
b = afn[BusPDP11.IOHANDLER.READ_WORD](addr & ~0x1) >> 8;
|
||||
b = afn[BusPDP11.IOHANDLER.READ_WORD](addrMasked & ~0x1) >> 8;
|
||||
}
|
||||
}
|
||||
} else if (addr & 0x1) {
|
||||
} else if (addrMasked & 0x1) {
|
||||
afn = bus.aIOHandlers[off & ~0x1];
|
||||
if (afn) {
|
||||
if (afn[BusPDP11.IOHANDLER.READ_WORD]) {
|
||||
b = afn[BusPDP11.IOHANDLER.READ_WORD](addr & ~0x1) >> 8;
|
||||
b = afn[BusPDP11.IOHANDLER.READ_WORD](addrMasked & ~0x1) >> 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -288,12 +296,19 @@ BusPDP11.IOController = {
|
|||
var fWrite = false;
|
||||
var bus = this.controller;
|
||||
var afn = bus.aIOHandlers[off];
|
||||
|
||||
/*
|
||||
* Since addr is primarily used to advise an I/O handler of the target IOPAGE address, and since we don't want
|
||||
* our handlers to worry about the current IOPAGE location, we truncate addr to 16 bits (the IOPAGE's lowest location).
|
||||
*/
|
||||
var addrMasked = addr & 0xffff;
|
||||
|
||||
if (afn) {
|
||||
/*
|
||||
* If a writeByte() handler exists, call it; we're done.
|
||||
*/
|
||||
if (afn[BusPDP11.IOHANDLER.WRITE_BYTE]) {
|
||||
afn[BusPDP11.IOHANDLER.WRITE_BYTE](b, addr);
|
||||
afn[BusPDP11.IOHANDLER.WRITE_BYTE](b, addrMasked);
|
||||
fWrite = true;
|
||||
}
|
||||
/*
|
||||
|
|
@ -306,15 +321,15 @@ BusPDP11.IOController = {
|
|||
*/
|
||||
else if (afn[BusPDP11.IOHANDLER.WRITE_WORD]) {
|
||||
w = afn[BusPDP11.IOHANDLER.READ_WORD]? afn[BusPDP11.IOHANDLER.READ_WORD](0) : 0;
|
||||
if (!(addr & 0x1)) {
|
||||
afn[BusPDP11.IOHANDLER.WRITE_WORD]((w & ~0xff) | b, addr);
|
||||
if (!(addrMasked & 0x1)) {
|
||||
afn[BusPDP11.IOHANDLER.WRITE_WORD]((w & ~0xff) | b, addrMasked);
|
||||
fWrite = true;
|
||||
} else {
|
||||
afn[BusPDP11.IOHANDLER.WRITE_WORD]((w & 0xff) | (b << 8), addr & ~0x1);
|
||||
afn[BusPDP11.IOHANDLER.WRITE_WORD]((w & 0xff) | (b << 8), addrMasked & ~0x1);
|
||||
fWrite = true;
|
||||
}
|
||||
}
|
||||
} else if (addr & 0x1) {
|
||||
} else if (addrMasked & 0x1) {
|
||||
/*
|
||||
* If no handler existed, and this address was odd, then perhaps a handler exists for the even address;
|
||||
* if so, call the readWord() handler first to get the original data, then call writeWord() with the new
|
||||
|
|
@ -327,9 +342,9 @@ BusPDP11.IOController = {
|
|||
afn = bus.aIOHandlers[off & ~0x1];
|
||||
if (afn) {
|
||||
if (afn[BusPDP11.IOHANDLER.WRITE_WORD]) {
|
||||
addr &= ~0x1;
|
||||
addrMasked &= ~0x1;
|
||||
w = afn[BusPDP11.IOHANDLER.READ_WORD]? afn[BusPDP11.IOHANDLER.READ_WORD](0) : 0;
|
||||
afn[BusPDP11.IOHANDLER.WRITE_WORD]((w & 0xff) | (b << 8), addr);
|
||||
afn[BusPDP11.IOHANDLER.WRITE_WORD]((w & 0xff) | (b << 8), addrMasked);
|
||||
fWrite = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -359,11 +374,18 @@ BusPDP11.IOController = {
|
|||
var w = -1;
|
||||
var bus = this.controller;
|
||||
var afn = bus.aIOHandlers[off];
|
||||
|
||||
/*
|
||||
* Since addr is primarily used to advise an I/O handler of the target IOPAGE address, and since we don't want
|
||||
* our handlers to worry about the current IOPAGE location, we truncate addr to 16 bits (the IOPAGE's lowest location).
|
||||
*/
|
||||
var addrMasked = addr & 0xffff;
|
||||
|
||||
if (afn) {
|
||||
if (afn[BusPDP11.IOHANDLER.READ_WORD]) {
|
||||
w = afn[BusPDP11.IOHANDLER.READ_WORD](addr);
|
||||
w = afn[BusPDP11.IOHANDLER.READ_WORD](addrMasked);
|
||||
} else if (afn[BusPDP11.IOHANDLER.READ_BYTE]) {
|
||||
w = afn[BusPDP11.IOHANDLER.READ_BYTE](addr) | (afn[BusPDP11.IOHANDLER.READ_BYTE](addr + 1) << 8);
|
||||
w = afn[BusPDP11.IOHANDLER.READ_BYTE](addrMasked) | (afn[BusPDP11.IOHANDLER.READ_BYTE](addrMasked + 1) << 8);
|
||||
}
|
||||
}
|
||||
if (w >= 0) {
|
||||
|
|
@ -393,13 +415,20 @@ BusPDP11.IOController = {
|
|||
var fWrite = false;
|
||||
var bus = this.controller;
|
||||
var afn = bus.aIOHandlers[off];
|
||||
|
||||
/*
|
||||
* Since addr is primarily used to advise an I/O handler of the target IOPAGE address, and since we don't want
|
||||
* our handlers to worry about the current IOPAGE location, we truncate addr to 16 bits (the IOPAGE's lowest location).
|
||||
*/
|
||||
var addrMasked = addr & 0xffff;
|
||||
|
||||
if (afn) {
|
||||
if (afn[BusPDP11.IOHANDLER.WRITE_WORD]) {
|
||||
afn[BusPDP11.IOHANDLER.WRITE_WORD](w, addr);
|
||||
afn[BusPDP11.IOHANDLER.WRITE_WORD](w, addrMasked);
|
||||
fWrite = true;
|
||||
} else if (afn[BusPDP11.IOHANDLER.WRITE_BYTE]) {
|
||||
afn[BusPDP11.IOHANDLER.WRITE_BYTE](w & 0xff, addr);
|
||||
afn[BusPDP11.IOHANDLER.WRITE_BYTE](w >> 8, addr + 1);
|
||||
afn[BusPDP11.IOHANDLER.WRITE_BYTE](w & 0xff, addrMasked);
|
||||
afn[BusPDP11.IOHANDLER.WRITE_BYTE](w >> 8, addrMasked + 1);
|
||||
fWrite = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -458,7 +487,7 @@ BusPDP11.prototype.setIOPageRange = function(nRange)
|
|||
if (nRange) {
|
||||
this.nIOPageRange = nRange;
|
||||
addr = (1 << nRange);
|
||||
this.nBusLimit = this.nBusMask = (addr - 1);
|
||||
this.nBusMask = (addr - 1);
|
||||
addr -= BusPDP11.IOPAGE_LENGTH;
|
||||
this.aIOPrevBlocks = this.getMemoryBlocks(addr, BusPDP11.IOPAGE_LENGTH);
|
||||
if (this.aIOPageBlocks) {
|
||||
|
|
@ -633,6 +662,9 @@ BusPDP11.prototype.addMemory = function(addr, size, type, controller)
|
|||
}
|
||||
|
||||
if (sizeLeft <= 0) {
|
||||
if (type == MemoryPDP11.TYPE.RAM && !this.cbRAM) {
|
||||
this.cbRAM += size;
|
||||
}
|
||||
this.status(str.toDec(size / 1024) + "Kb " + MemoryPDP11.TYPE_NAMES[type] + " at " + str.toOct(addr));
|
||||
return true;
|
||||
}
|
||||
|
|
@ -1203,6 +1235,27 @@ BusPDP11.prototype.restoreMemory = function(a)
|
|||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* getMemorySize(type)
|
||||
*
|
||||
* NOTE: The original pdp11.js defined MAX_MEMORY as IOBASE_UNIBUS - 16384, where IOBASE_UNIBUS
|
||||
* is 4Mb less 256Kb, and then subtracted another 16Kb so that BSD 2.9 could boot.
|
||||
*
|
||||
* @this {BusPDP11}
|
||||
* @param {number} type is one of the MemoryPDP11.TYPE constants (only RAM is currently supported)
|
||||
* @return {number} (size of initial allocation, in bytes)
|
||||
*/
|
||||
BusPDP11.prototype.getMemorySize = function(type)
|
||||
{
|
||||
var cb = 0;
|
||||
switch(type) {
|
||||
case MemoryPDP11.TYPE.RAM:
|
||||
cb = this.cbRAM;
|
||||
break;
|
||||
}
|
||||
return cb;
|
||||
};
|
||||
|
||||
/**
|
||||
* addIOHandlers(start, end, fnReadByte, fnWriteByte, fnReadWord, fnWriteWord, sName)
|
||||
*
|
||||
|
|
@ -1331,7 +1384,7 @@ BusPDP11.prototype.fault = function(addr, err, access)
|
|||
* @this {BusPDP11}
|
||||
* @return {boolean}
|
||||
*/
|
||||
BusPDP11.prototype.checkFault= function()
|
||||
BusPDP11.prototype.checkFault = function()
|
||||
{
|
||||
var f = this.fFault;
|
||||
this.fFault = false;
|
||||
|
|
|
|||
|
|
@ -278,6 +278,9 @@ CPUStatePDP11.prototype.setMemoryAccess = function()
|
|||
/**
|
||||
* getMMR0()
|
||||
*
|
||||
* 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 MMR0
|
||||
* nonr leng read trap unus unus ena mnt cmp -mode- i/d --page-- enable
|
||||
*
|
||||
* @this {CPUStatePDP11}
|
||||
* @return {number}
|
||||
*/
|
||||
|
|
@ -1257,6 +1260,11 @@ CPUStatePDP11.prototype.getTrapStatus = function()
|
|||
* address are added to 22 bits of the selected mapping register to produce the 22-bit physical address. The lowest
|
||||
* order bit of all mapping registers is always a zero, since relocation is always on word boundaries.
|
||||
*
|
||||
* Sadly, because these mappings occur at a word-granular level, we can't implement the mappings by simply shuffling
|
||||
* the underlying block around in the Bus component; it would be much more efficient if we could. That's EXACTLY how
|
||||
* we move the IOPAGE in response to addressing changes. If it turns out that block-granular addresses are commonly
|
||||
* stored in the unibusMap registers, we could add code to detect that and perform block remapping in those cases.
|
||||
*
|
||||
* @this {CPUStatePDP11}
|
||||
* @param {number} addr
|
||||
* @return {number}
|
||||
|
|
@ -1295,15 +1303,33 @@ CPUStatePDP11.prototype.mapUnibus = function(addr)
|
|||
* it again if all worked. If however something happens to cause a trap then no restore is
|
||||
* done as setPSW() will have been invoked as part of the trap, which will resynchronize mmuMode.
|
||||
*
|
||||
* A PDP 11/70 is different to other PDP 11's in that the highest 18 bit space (017000000 & above)
|
||||
* A PDP-11/70 is different from other PDP-11s in that the highest 18 bit space (017000000 & above)
|
||||
* maps directly to UNIBUS space - including low memory. This doesn't appear to be particularly
|
||||
* useful as it restricts maximum system memory - although it does appear to allow software
|
||||
* testing of the unibus map. This feature also appears to confuse some OSes which test consecutive
|
||||
* memory locations to find maximum memory -- and on a full memory system find themselves accessing
|
||||
* low memory again at high addresses.
|
||||
*
|
||||
* 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 MMR0
|
||||
* nonr leng read trap unus unus ena mnt cmp -mode- i/d --page-- enable
|
||||
* Construction of a Physical Address
|
||||
* ----------------------------------
|
||||
*
|
||||
* Virtual Addr (VA) 12 11 10 9 8 7 6 5 4 3 2 1 0
|
||||
* Page Addr Field (PAF) 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
|
||||
* + -----------------------------------------------------------------
|
||||
* Physical Addr (PA) 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
|
||||
*
|
||||
* The Page Address Field (PAF) comes from a Page Address Register (PAR) that is selected by Virtual Address (VA)
|
||||
* bits 15-13. You can see from the above alignments that the VA contributes to the low 13 bits, providing an 8Kb
|
||||
* range.
|
||||
*
|
||||
* VA bits 0-5 pass directly through to the PA; those are also called the DIB (Displacement in Block) bits.
|
||||
* VA bits 6-12 are added to the low 7 bits of the PAF and are also called the BN (Block Number) bits.
|
||||
*
|
||||
* You can also think of the entire PAF as a block number, where each block is 64 bytes. This is consistent with
|
||||
* the LSIZE register at 177760, which is supposed to contain the number of 64-byte blocks of memory installed.
|
||||
*
|
||||
* Note that if a PAR is initialized to zero, successively adding 0200 (0x80) to the PAR will advance the base
|
||||
* physical address to the next 8Kb page.
|
||||
*
|
||||
* @this {CPUStatePDP11}
|
||||
* @param {number} virtualAddress
|
||||
|
|
|
|||
|
|
@ -770,7 +770,7 @@ if (DEBUGGER) {
|
|||
* done later, by getAddr(), which returns PDP11.ADDR_INVALID for invalid segments, out-of-range offsets,
|
||||
* etc. The Debugger's low-level get/set memory functions verify all getAddr() results, but even if an
|
||||
* invalid address is passed through to the Bus memory interfaces, the address will simply be masked with
|
||||
* BusPDP11.nBusLimit; in the case of PDP11.ADDR_INVALID, that will generally refer to the top of the physical
|
||||
* bus.nBusMask; in the case of PDP11.ADDR_INVALID, that will generally refer to the top of the physical
|
||||
* address space.
|
||||
*
|
||||
* @this {DebuggerPDP11}
|
||||
|
|
@ -2013,64 +2013,59 @@ if (DEBUGGER) {
|
|||
if (fTemporary && !dbgAddrBreak.fTemporary) continue;
|
||||
|
||||
/*
|
||||
* We used to calculate the linear address of the breakpoint at the time the
|
||||
* breakpoint was added, so that a breakpoint set in one mode (eg, in real-mode)
|
||||
* would still work as intended if the mode changed later (eg, to protected-mode).
|
||||
*
|
||||
* However, that created difficulties setting protected-mode breakpoints in segments
|
||||
* that might not be defined yet, or that could move in physical memory.
|
||||
*
|
||||
* If you want to create a real-mode breakpoint that will break regardless of mode,
|
||||
* use the physical address of the real-mode memory location instead.
|
||||
* Since we're checking an execution address, which is always virtual, and virtual
|
||||
* addresses are always restricted to 16 bits, let's mask the breakpoint address to match
|
||||
* (the user should know better, but we'll be nice).
|
||||
*/
|
||||
var addrBreak = this.getAddr(dbgAddrBreak);
|
||||
var addrBreak = this.getAddr(dbgAddrBreak) & 0xffff;
|
||||
for (var n = 0; n < nb; n++) {
|
||||
if (addr + n == addrBreak) {
|
||||
var a;
|
||||
fBreak = true;
|
||||
if (dbgAddrBreak.fTemporary) {
|
||||
this.findBreakpoint(aBreak, dbgAddrBreak, true, true);
|
||||
fTemporary = true;
|
||||
}
|
||||
if (a = dbgAddrBreak.aCmds) {
|
||||
/*
|
||||
* When one or more commands are attached to a breakpoint, we don't halt by default.
|
||||
* Instead, we set fBreak to true only if, at the completion of all the commands, the
|
||||
* CPU is halted; in other words, you should include "h" as one of the breakpoint commands
|
||||
* if you want the breakpoint to stop execution.
|
||||
*
|
||||
* Another useful command is "if", which will return false if the expression is false,
|
||||
* at which point we'll jump ahead to the next "else" command, and if there isn't an "else",
|
||||
* we abort.
|
||||
*/
|
||||
fBreak = false;
|
||||
for (var j = 0; j < a.length; j++) {
|
||||
if (!this.doCommand(a[j], true)) {
|
||||
if (a[j].indexOf("if")) {
|
||||
fBreak = true; // the failed command wasn't "if", so abort
|
||||
break;
|
||||
}
|
||||
var k = j + 1;
|
||||
for (; k < a.length; k++) {
|
||||
if (!a[k].indexOf("else")) break;
|
||||
j++;
|
||||
}
|
||||
if (k == a.length) { // couldn't find an "else" after the "if", so abort
|
||||
fBreak = true;
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* If we're still here, we'll execute the "else" command (which is just a no-op),
|
||||
* followed by any remaining commands.
|
||||
*/
|
||||
|
||||
if ((addr + n) != addrBreak) continue;
|
||||
|
||||
var a;
|
||||
fBreak = true;
|
||||
if (dbgAddrBreak.fTemporary) {
|
||||
this.findBreakpoint(aBreak, dbgAddrBreak, true, true);
|
||||
fTemporary = true;
|
||||
}
|
||||
if (a = dbgAddrBreak.aCmds) {
|
||||
/*
|
||||
* When one or more commands are attached to a breakpoint, we don't halt by default.
|
||||
* Instead, we set fBreak to true only if, at the completion of all the commands, the
|
||||
* CPU is halted; in other words, you should include "h" as one of the breakpoint commands
|
||||
* if you want the breakpoint to stop execution.
|
||||
*
|
||||
* Another useful command is "if", which will return false if the expression is false,
|
||||
* at which point we'll jump ahead to the next "else" command, and if there isn't an "else",
|
||||
* we abort.
|
||||
*/
|
||||
fBreak = false;
|
||||
for (var j = 0; j < a.length; j++) {
|
||||
if (!this.doCommand(a[j], true)) {
|
||||
if (a[j].indexOf("if")) {
|
||||
fBreak = true; // the failed command wasn't "if", so abort
|
||||
break;
|
||||
}
|
||||
var k = j + 1;
|
||||
for (; k < a.length; k++) {
|
||||
if (!a[k].indexOf("else")) break;
|
||||
j++;
|
||||
}
|
||||
if (k == a.length) { // couldn't find an "else" after the "if", so abort
|
||||
fBreak = true;
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* If we're still here, we'll execute the "else" command (which is just a no-op),
|
||||
* followed by any remaining commands.
|
||||
*/
|
||||
}
|
||||
if (!this.cpu.isRunning()) fBreak = true;
|
||||
}
|
||||
if (fBreak) {
|
||||
if (!fTemporary) this.printBreakpoint(aBreak, i, "hit");
|
||||
break;
|
||||
}
|
||||
if (!this.cpu.isRunning()) fBreak = true;
|
||||
}
|
||||
if (fBreak) {
|
||||
if (!fTemporary) this.printBreakpoint(aBreak, i, "hit");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -518,7 +518,7 @@ var PDP11 = {
|
|||
UNDEF1: 0o177754,
|
||||
UNDEF2: 0o177756,
|
||||
|
||||
LSIZE: 0o177760, // Lower Size Register (last 32-word block) (11/70 only)
|
||||
LSIZE: 0o177760, // Lower Size Register (last 64-byte block #) (11/70 only)
|
||||
HSIZE: 0o177762, // Upper Size Register (always zero) (11/70 only)
|
||||
SYSID: 0o177764, // System ID Register (11/70 only)
|
||||
CPUERR: 0o177766, // CPU error (11/70 only)
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ if (NODE) {
|
|||
var Component = require("../../shared/lib/component");
|
||||
var State = require("../../shared/lib/state");
|
||||
var BusPDP11 = require("./bus");
|
||||
var MemoryPDP11 = require("./memory");
|
||||
var MessagesPDP11 = require("./messages");
|
||||
var PC11 = require("./pc11");
|
||||
var RL11 = require("./rl11");
|
||||
|
|
@ -854,13 +855,24 @@ DevicePDP11.prototype.writeCTRL = function(data, addr)
|
|||
/**
|
||||
* readSIZE(addr)
|
||||
*
|
||||
* We're adhering to DEC's documentation, which says:
|
||||
*
|
||||
* This read-only register specifies the memory size of the system. It is defined to indicate the
|
||||
* last addressable block of 32 words in memory (bit 0 is equivalent to bit 6 of the Physical Address).
|
||||
*
|
||||
* Looking at the Memory Clear "toggle-in" code in /devices/pdp11/machine/1170/panel/debugger/README.md, the
|
||||
* memory loop gives up when the block number stored in KIPAR0 is >= LSIZE, suggesting that LSIZE is actually
|
||||
* the total number of 64-byte blocks, rather than the block number of the last block. But that code is
|
||||
* not conclusive, since it writes 8192 bytes at a time rather than 64, so it doesn't really matter if LSIZE
|
||||
* is off by one.
|
||||
*
|
||||
* @this {DevicePDP11}
|
||||
* @param {number} addr (eg, PDP11.UNIBUS.LSIZE--HSIZE or 177760--177762)
|
||||
* @return {number}
|
||||
*/
|
||||
DevicePDP11.prototype.readSIZE = function(addr)
|
||||
{
|
||||
return addr == PDP11.UNIBUS.LSIZE? ((BusPDP11.MAX_MEMORY >> 6) - 1) : 0;
|
||||
return addr == PDP11.UNIBUS.LSIZE? ((this.bus.getMemorySize(MemoryPDP11.TYPE.RAM) >> 6) - 1) : 0;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
Loading…
Reference in a new issue