More 8080 improvements, including some initial "Fake CP/M" support

This commit is contained in:
Jeff Parsons 2016-04-27 08:28:52 -07:00
commit 5b6f6756a2
25 changed files with 1051 additions and 842 deletions

View file

@ -78,7 +78,7 @@ function Bus(parmsBus, cpu, dbg)
this.cpu = cpu;
this.dbg = dbg;
this.nBusWidth = parmsBus['buswidth'] || 16;
this.nBusWidth = parmsBus['busWidth'] || 16;
/*
* Compute all Bus memory block parameters, based on the width of the bus.
@ -108,6 +108,7 @@ function Bus(parmsBus, cpu, dbg)
*
* Bus Width Block Shift Block Size
* --------- ----------- ----------
* 16 bits (64Kb address space): 10 1Kb (64 maximum blocks)
* 20 bits (1Mb address space): 12 4Kb (256 maximum blocks)
* 24 bits (16Mb address space): 14 16Kb (1K maximum blocks)
* 32 bits (4Gb address space); 15 32Kb (128K maximum blocks)
@ -119,7 +120,7 @@ function Bus(parmsBus, cpu, dbg)
*/
this.addrTotal = Math.pow(2, this.nBusWidth);
this.nBusLimit = this.nBusMask = (this.addrTotal - 1) | 0;
this.nBlockShift = (this.nBusWidth <= 20)? 12 : (this.nBusWidth <= 24? 14 : 15);
this.nBlockShift = (this.nBusWidth <= 16)? 10 : ((this.nBusWidth <= 20)? 12 : (this.nBusWidth <= 24? 14 : 15));
this.nBlockSize = 1 << this.nBlockShift;
this.nBlockLen = this.nBlockSize >> 2;
this.nBlockLimit = this.nBlockSize - 1;
@ -268,16 +269,15 @@ Bus.prototype.powerUp = function(data, fRepower)
* allocations, etc.
*
* We've relaxed some of the original requirements (ie, that addresses must start at a
* block-granular address, or that sizes must be equal to exactly one or more blocks), because
* machines with large block sizes can make it impossible to load certain ROMs at at their
* required addresses.
* block-granular address, or that sizes must be equal to exactly one or more blocks),
* because machines with large block sizes can make it impossible to load certain ROMs at
* their required addresses. Every allocation still allocates a whole number of blocks.
*
* Even so, Bus memory management does NOT provide a general-purpose heap. Most memory
* allocations occur during machine initialization and never change. The only notable
* exception is the Video frame buffer, which ranges from 4Kb (MDA) to 16Kb (CGA) to
* 32Kb/64Kb/128Kb (EGA), and only the EGA changes its buffer address post-initialization.
* allocations occur during machine initialization and never change. In particular, there
* is NO support for removing partial-block allocations.
*
* Each Memory block keeps track of a single address (addr) and length (used), indicating
* Each Memory block keeps track of a start address (addr) and length (used), indicating
* the used space within the block; any free space that precedes or follows that used space
* can be allocated later, by simply extending the beginning or ending of the previously used
* space. However, any holes that might have existed between the original allocation and an
@ -293,17 +293,18 @@ Bus.prototype.addMemory = function(addr, size, type)
{
var iBlock = addr >>> this.nBlockShift;
while (size > 0 && iBlock < this.aMemBlocks.length) {
var block = this.aMemBlocks[iBlock];
var addrBlock = iBlock * this.nBlockSize;
var sizeBlock = size > this.nBlockSize? this.nBlockSize : size;
var sizeBlock = this.nBlockSize - (addr - addrBlock);
if (sizeBlock > size) sizeBlock = size;
if (block && block.size) {
if (block.type == type) {
/*
* Where there is already a block with a non-zero size, we can allow the allocation only if:
* Where there is already a similar block with a non-zero size, we allow the allocation only if:
*
* 1) addr + size <= block.addr (the request precedes the used portion of the current block)
* or:
* 1) addr + size <= block.addr (the request precedes the used portion of the current block), or
* 2) addr >= block.addr + block.used (the request follows the used portion of the current block)
*/
if (addr + size <= block.addr) {
@ -315,23 +316,27 @@ Bus.prototype.addMemory = function(addr, size, type)
var sizeAvail = block.size - (addr - addrBlock);
if (sizeAvail > size) sizeAvail = size;
block.used = addr - block.addr + sizeAvail;
size -= sizeAvail;
addr = addrBlock + this.nBlockSize;
size -= sizeAvail;
iBlock++;
continue;
}
}
return this.reportError(Bus.ERROR.ADD_MEM_INUSE, addr, size);
}
var blockOld = this.aMemBlocks[iBlock];
var blockNew = new Memory(addr, sizeBlock, this.nBlockSize, type);
blockNew.copyBreakpoints(this.dbg, blockOld);
blockNew.copyBreakpoints(this.dbg, block);
this.aMemBlocks[iBlock++] = blockNew;
addr = addrBlock + this.nBlockSize;
size -= sizeBlock;
}
if (size <= 0) {
return true;
}
return this.reportError(Bus.ERROR.ADD_MEM_BADRANGE, addr, size);
};

View file

@ -166,7 +166,7 @@ function Computer(parmsComputer, parmsMachine, fSuspended) {
/*
* Initialize the Bus component
*/
this.bus = new Bus({'id': this.idMachine + '.bus', 'buswidth': this.nBusWidth}, this.cpu, this.dbg);
this.bus = new Bus({'id': this.idMachine + '.bus', 'busWidth': this.nBusWidth}, this.cpu, this.dbg);
/*
* Iterate through all the components and connect them to the Control Panel, if any

View file

@ -104,6 +104,7 @@ var CPUDef = {
* Opcode definitions
*/
OPCODE: {
HLT: 0x76,
ACI: 0xCE, // PS.ALL
CALL: 0xCD,
RST0: 0xC7

View file

@ -1299,23 +1299,37 @@ CPUDef.opHLT = function()
* we are signalling to stepCPU() that it's free to end the current burst AND that it should not
* execute any more instructions until checkINTR() indicates a hardware interrupt is requested.
*/
var addr = this.getPC() - 1;
/*
* If any HLT check functions are installed, call them, and if any of them return true, then
* immediately stop HLT processing.
*/
if (this.afnHalt.length) {
for (var i = 0; i < this.afnHalt.length; i++) {
if (this.afnHalt[i](addr)) return;
}
}
this.intFlags |= CPUDef.INTFLAG.HALT;
this.nStepCycles -= 7;
/*
* If a Debugger is present and the HALT message category is enabled, then we REALLY halt the CPU,
* on the theory that whoever's using the Debugger would like to see HLTs.
*/
if (DEBUGGER && this.dbg && this.messageEnabled(Messages.HALT)) {
this.setPC(this.getPC() - 1); // this is purely for the Debugger's benefit, to show the HLT
this.setPC(addr); // this is purely for the Debugger's benefit, to show the HLT
this.dbg.stopCPU();
return;
}
/*
* We also REALLY halt the machine if interrupts have been disabled, since that means it's dead
* in the water (we have no NMI generation mechanism at the moment).
*/
if (!this.getIF()) {
if (DEBUGGER && this.dbg) this.setPC(this.getPC() - 1);
if (DEBUGGER && this.dbg) this.setPC(addr);
this.stopCPU();
}
};

View file

@ -100,6 +100,12 @@ function CPUSim(parmsCPU)
this.nBusMask = 0;
this.nBlockShift = this.nBlockSize = this.nBlockLimit = this.nBlockTotal = this.nBlockMask = 0;
/*
* Array of halt handlers, if any (see addHaltCheck)
*/
this.afnHalt = [];
this.addrReset = 0x0000;
/*
* This initial resetRegs() call is important to create all the registers, so that if/when we call restore(),
* it will have something to fill in.
@ -130,14 +136,22 @@ CPUSim.prototype.initMemory = function(aBusBlocks, nBlockShift, nBusMask)
this.nBusMask = nBusMask;
};
/**
* addHaltCheck(fn)
*
* Records a function that will be called during HLT opcode processing.
*
* @this {CPUSim}
* @param {function(number)} fn
*/
CPUSim.prototype.addHaltCheck = function(fn)
{
this.afnHalt.push(fn);
};
/**
* addMemBreak(addr, fWrite)
*
* NOTE: addMemBreak() could be merged with addMemCheck(), but the new merged interface would
* have to provide one additional parameter indicating whether the Debugger or the CPU is the client.
*
* For now, this is simply a DEBUGGER-only interface.
*
* @this {CPUSim}
* @param {number} addr
* @param {boolean} fWrite is true for a memory write breakpoint, false for a memory read breakpoint
@ -153,11 +167,6 @@ CPUSim.prototype.addMemBreak = function(addr, fWrite)
/**
* removeMemBreak(addr, fWrite)
*
* NOTE: removeMemBreak() could be merged with removeMemCheck(), but the new merged interface would
* have to provide one additional parameter indicating whether the Debugger or the CPU is the client.
*
* For now, this is simply a DEBUGGER-only interface.
*
* @this {CPUSim}
* @param {number} addr
* @param {boolean} fWrite is true for a memory write breakpoint, false for a memory read breakpoint
@ -170,41 +179,6 @@ CPUSim.prototype.removeMemBreak = function(addr, fWrite)
}
};
/**
* addMemCheck(addr, fWrite)
*
* These functions provide Debug register functionality to the CPU by leveraging the same Memory block-based
* breakpoint support originally created for our built-in Debugger. Only minimal changes were required to the
* Memory component, by adding additional checkMemoryException() call-outs from the "checked" Memory access
* functions.
*
* Note that those call-outs occur only AFTER our own Debugger (if present) has checked the address and has
* passed on it, because we want our own Debugger's breakpoints to take precedence over any breakpoints that
* the emulated machine may have enabled.
*
* @this {CPUSim}
* @param {number} addr
* @param {boolean} fWrite is true for a memory write check, false for a memory read check
*/
CPUSim.prototype.addMemCheck = function(addr, fWrite)
{
var iBlock = addr >>> this.nBlockShift;
this.aBusBlocks[iBlock].addBreakpoint(addr & this.nBlockLimit, fWrite, this);
};
/**
* removeMemCheck(addr, fWrite)
*
* @this {CPUSim}
* @param {number} addr
* @param {boolean} fWrite is true for a memory write check, false for a memory read check
*/
CPUSim.prototype.removeMemCheck = function(addr, fWrite)
{
var iBlock = addr >>> this.nBlockShift;
this.aBusBlocks[iBlock].removeBreakpoint(addr & this.nBlockLimit, fWrite);
};
/**
* initProcessor()
*
@ -244,7 +218,7 @@ CPUSim.prototype.resetRegs = function()
this.regH = 0;
this.regL = 0;
this.setSP(0);
this.setPC(0);
this.setPC(this.addrReset);
/*
* This resets the Processor Status flags (regPS), along with all the internal "result registers";
@ -260,6 +234,18 @@ CPUSim.prototype.resetRegs = function()
this.intFlags = CPUDef.INTFLAG.NONE;
};
/**
* setReset(addr)
*
* @this {CPUSim}
* @param {number} addr
*/
CPUSim.prototype.setReset = function(addr)
{
this.addrReset = addr;
this.setPC(addr);
};
/**
* getChecksum()
*
@ -336,13 +322,16 @@ CPUSim.prototype.setBinding = function(sHTMLType, sBinding, control, sValue)
case "A":
case "B":
case "C":
case "BC":
case "D":
case "E":
case "DE":
case "H":
case "L":
case "HL":
case "SP":
case "PC":
case "F":
case "PS":
case "SF":
case "ZF":
case "AF":
@ -1047,14 +1036,17 @@ CPUSim.prototype.updateStatus = function(fForce)
this.updateReg("A", this.regA);
this.updateReg("B", this.regB);
this.updateReg("C", this.regC);
this.updateReg("BC", this.getBC(), 4);
this.updateReg("D", this.regD);
this.updateReg("E", this.regE);
this.updateReg("DE", this.getDE(), 4);
this.updateReg("H", this.regH);
this.updateReg("L", this.regL);
this.updateReg("HL", this.getHL(), 4);
this.updateReg("SP", this.getSP(), 4);
this.updateReg("PC", this.getPC(), 4);
var regPS = this.getPS();
this.updateReg("F", regPS, 2);
this.updateReg("PS", regPS, 4);
this.updateReg("SF", (regPS & CPUDef.PS.SF), 1);
this.updateReg("ZF", (regPS & CPUDef.PS.ZF), 1);
this.updateReg("AF", (regPS & CPUDef.PS.AF), 1);

View file

@ -87,7 +87,7 @@ function Debugger(parmsDbg)
Component.call(this, "Debugger", parmsDbg, Debugger);
this.style = Debugger.STYLE_8086;
this.style = Debugger.STYLE_8080;
/*
* These keep track of instruction activity, but only when tracing or when Debugger checks
@ -300,7 +300,7 @@ if (DEBUGGER) {
"CALLC", "CALLS", "CALLNC", "CALLNZ", "CALLNS", "CALLP", "CALLNP", "CALLZ",
"NOT", "CMC", "CMP", "CMP", "DAA", "ADD", "DEC", "DEC",
"CLI", "STI", "HLT", "IN", "INC", "INC", "JMP", "JC",
"JS", "JNC", "JNZ", "JNS", "JP", "JNP", "JZ", "LDA",
"JS", "JNC", "JNZ", "JNS", "JP", "JNP", "JZ", "MOV",
"MOV", "MOV", "MOV", "MOV", "MOV", "NOP", "OR", "OR",
"OUT", "JMP", "POP", "PUSH", "RCL", "RCR", "RET", "RETC",
"RETS", "RETNC", "RETNZ", "RETNS", "RETP", "RETNP", "RETZ", "ROL",
@ -321,7 +321,7 @@ if (DEBUGGER) {
Debugger.REG_HL = 0x0A;
Debugger.REG_SP = 0x0B;
Debugger.REG_PC = 0x0C;
Debugger.REG_PS = 0x0D; // aka PSW (aka AF if Z80-style)
Debugger.REG_PS = 0x0D; // aka PSW (aka AF if Z80-style mnemonics)
Debugger.REGS = [
"B", "C", "D", "E", "H", "L", "M", "A", "BC", "DE", "HL", "SP", "PC", "PSW"
@ -403,15 +403,15 @@ if (DEBUGGER) {
Debugger.aaOpDescs = [
/* 0x00 */ [Debugger.INS.NOP],
/* 0x01 */ [Debugger.INS.LXI, Debugger.TYPE_BC, Debugger.TYPE_IMM],
/* 0x02 */ [Debugger.INS.STAX, Debugger.TYPE_BC | Debugger.TYPE_MEM, Debugger.TYPE_A | Debugger.TYPE_OPT],
/* 0x02 */ [Debugger.INS.STAX, Debugger.TYPE_BC | Debugger.TYPE_MEM, Debugger.TYPE_A | Debugger.TYPE_OPT],
/* 0x03 */ [Debugger.INS.INX, Debugger.TYPE_BC],
/* 0x04 */ [Debugger.INS.INR, Debugger.TYPE_B],
/* 0x05 */ [Debugger.INS.DCR, Debugger.TYPE_B],
/* 0x06 */ [Debugger.INS.MVI, Debugger.TYPE_B, Debugger.TYPE_IMM],
/* 0x07 */ [Debugger.INS.RLC],
/* 0x08 */ [Debugger.INS.NOP, Debugger.TYPE_UNDOC],
/* 0x09 */ [Debugger.INS.DAD, Debugger.TYPE_HL, Debugger.TYPE_BC], // let's be more explicit about the operands
/* 0x0A */ [Debugger.INS.LDAX, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_BC | Debugger.TYPE_MEM],
/* 0x09 */ [Debugger.INS.DAD, Debugger.TYPE_HL | Debugger.TYPE_OPT, Debugger.TYPE_BC],
/* 0x0A */ [Debugger.INS.LDAX, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_BC | Debugger.TYPE_MEM],
/* 0x0B */ [Debugger.INS.DCX, Debugger.TYPE_BC],
/* 0x0C */ [Debugger.INS.INR, Debugger.TYPE_C],
/* 0x0D */ [Debugger.INS.DCR, Debugger.TYPE_C],
@ -419,15 +419,15 @@ if (DEBUGGER) {
/* 0x0F */ [Debugger.INS.RRC],
/* 0x10 */ [Debugger.INS.NOP, Debugger.TYPE_UNDOC],
/* 0x11 */ [Debugger.INS.LXI, Debugger.TYPE_DE, Debugger.TYPE_IMM],
/* 0x12 */ [Debugger.INS.STAX, Debugger.TYPE_DE | Debugger.TYPE_MEM, Debugger.TYPE_A | Debugger.TYPE_OPT],
/* 0x12 */ [Debugger.INS.STAX, Debugger.TYPE_DE | Debugger.TYPE_MEM, Debugger.TYPE_A | Debugger.TYPE_OPT],
/* 0x13 */ [Debugger.INS.INX, Debugger.TYPE_DE],
/* 0x14 */ [Debugger.INS.INR, Debugger.TYPE_D],
/* 0x15 */ [Debugger.INS.DCR, Debugger.TYPE_D],
/* 0x16 */ [Debugger.INS.MVI, Debugger.TYPE_D, Debugger.TYPE_IMM],
/* 0x17 */ [Debugger.INS.RAL],
/* 0x18 */ [Debugger.INS.NOP, Debugger.TYPE_UNDOC],
/* 0x19 */ [Debugger.INS.DAD, Debugger.TYPE_HL, Debugger.TYPE_DE], // let's be more explicit about the operands
/* 0x1A */ [Debugger.INS.LDAX, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_DE | Debugger.TYPE_MEM],
/* 0x19 */ [Debugger.INS.DAD, Debugger.TYPE_HL | Debugger.TYPE_OPT, Debugger.TYPE_DE],
/* 0x1A */ [Debugger.INS.LDAX, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_DE | Debugger.TYPE_MEM],
/* 0x1B */ [Debugger.INS.DCX, Debugger.TYPE_DE],
/* 0x1C */ [Debugger.INS.INR, Debugger.TYPE_E],
/* 0x1D */ [Debugger.INS.DCR, Debugger.TYPE_E],
@ -435,14 +435,14 @@ if (DEBUGGER) {
/* 0x1F */ [Debugger.INS.RAR],
/* 0x20 */ [Debugger.INS.NOP, Debugger.TYPE_UNDOC],
/* 0x21 */ [Debugger.INS.LXI, Debugger.TYPE_HL, Debugger.TYPE_IMM],
/* 0x22 */ [Debugger.INS.SHLD, Debugger.TYPE_ADDR | Debugger.TYPE_MEM, Debugger.TYPE_HL | Debugger.TYPE_OPT],
/* 0x22 */ [Debugger.INS.SHLD, Debugger.TYPE_ADDR | Debugger.TYPE_MEM, Debugger.TYPE_HL | Debugger.TYPE_OPT],
/* 0x23 */ [Debugger.INS.INX, Debugger.TYPE_HL],
/* 0x24 */ [Debugger.INS.INR, Debugger.TYPE_H],
/* 0x25 */ [Debugger.INS.DCR, Debugger.TYPE_H],
/* 0x26 */ [Debugger.INS.MVI, Debugger.TYPE_H, Debugger.TYPE_IMM],
/* 0x27 */ [Debugger.INS.DAA],
/* 0x28 */ [Debugger.INS.NOP, Debugger.TYPE_UNDOC],
/* 0x29 */ [Debugger.INS.DAD, Debugger.TYPE_HL, Debugger.TYPE_HL], // let's be more explicit about the operands
/* 0x29 */ [Debugger.INS.DAD, Debugger.TYPE_HL | Debugger.TYPE_OPT, Debugger.TYPE_HL],
/* 0x2A */ [Debugger.INS.LHLD, Debugger.TYPE_HL | Debugger.TYPE_OPT, Debugger.TYPE_ADDR | Debugger.TYPE_MEM],
/* 0x2B */ [Debugger.INS.DCX, Debugger.TYPE_HL],
/* 0x2C */ [Debugger.INS.INR, Debugger.TYPE_L],
@ -451,14 +451,14 @@ if (DEBUGGER) {
/* 0x2F */ [Debugger.INS.CMA, Debugger.TYPE_A | Debugger.TYPE_OPT],
/* 0x30 */ [Debugger.INS.NOP, Debugger.TYPE_UNDOC],
/* 0x31 */ [Debugger.INS.LXI, Debugger.TYPE_SP, Debugger.TYPE_IMM],
/* 0x32 */ [Debugger.INS.STA, Debugger.TYPE_ADDR | Debugger.TYPE_MEM, Debugger.TYPE_A | Debugger.TYPE_OPT],
/* 0x32 */ [Debugger.INS.STA, Debugger.TYPE_ADDR | Debugger.TYPE_MEM, Debugger.TYPE_A | Debugger.TYPE_OPT],
/* 0x33 */ [Debugger.INS.INX, Debugger.TYPE_SP],
/* 0x34 */ [Debugger.INS.INR, Debugger.TYPE_M],
/* 0x35 */ [Debugger.INS.DCR, Debugger.TYPE_M],
/* 0x36 */ [Debugger.INS.MVI, Debugger.TYPE_M, Debugger.TYPE_IMM],
/* 0x37 */ [Debugger.INS.STC],
/* 0x38 */ [Debugger.INS.NOP, Debugger.TYPE_UNDOC],
/* 0x39 */ [Debugger.INS.DAD, Debugger.TYPE_HL, Debugger.TYPE_SP], // let's be more explicit about the operands
/* 0x39 */ [Debugger.INS.DAD, Debugger.TYPE_HL | Debugger.TYPE_OPT, Debugger.TYPE_SP],
/* 0x3A */ [Debugger.INS.LDA, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_ADDR | Debugger.TYPE_MEM],
/* 0x3B */ [Debugger.INS.DCX, Debugger.TYPE_SP],
/* 0x3C */ [Debugger.INS.INR, Debugger.TYPE_A],
@ -519,7 +519,7 @@ if (DEBUGGER) {
/* 0x73 */ [Debugger.INS.MOV, Debugger.TYPE_M, Debugger.TYPE_E],
/* 0x74 */ [Debugger.INS.MOV, Debugger.TYPE_M, Debugger.TYPE_H],
/* 0x75 */ [Debugger.INS.MOV, Debugger.TYPE_M, Debugger.TYPE_L],
/* 0x76 */ [Debugger.INS.MOV, Debugger.TYPE_M, Debugger.TYPE_M],
/* 0x76 */ [Debugger.INS.HLT],
/* 0x77 */ [Debugger.INS.MOV, Debugger.TYPE_M, Debugger.TYPE_A],
/* 0x78 */ [Debugger.INS.MOV, Debugger.TYPE_A, Debugger.TYPE_B],
/* 0x79 */ [Debugger.INS.MOV, Debugger.TYPE_A, Debugger.TYPE_C],
@ -529,77 +529,77 @@ if (DEBUGGER) {
/* 0x7D */ [Debugger.INS.MOV, Debugger.TYPE_A, Debugger.TYPE_L],
/* 0x7E */ [Debugger.INS.MOV, Debugger.TYPE_A, Debugger.TYPE_M],
/* 0x7F */ [Debugger.INS.MOV, Debugger.TYPE_A, Debugger.TYPE_A],
/* 0x80 */ [Debugger.INS.ADD, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_B],
/* 0x81 */ [Debugger.INS.ADD, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_C],
/* 0x82 */ [Debugger.INS.ADD, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_D],
/* 0x83 */ [Debugger.INS.ADD, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_E],
/* 0x84 */ [Debugger.INS.ADD, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_H],
/* 0x85 */ [Debugger.INS.ADD, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_L],
/* 0x86 */ [Debugger.INS.ADD, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_M],
/* 0x87 */ [Debugger.INS.ADD, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_A],
/* 0x88 */ [Debugger.INS.ADC, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_B],
/* 0x89 */ [Debugger.INS.ADC, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_C],
/* 0x8A */ [Debugger.INS.ADC, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_D],
/* 0x8B */ [Debugger.INS.ADC, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_E],
/* 0x8C */ [Debugger.INS.ADC, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_H],
/* 0x8D */ [Debugger.INS.ADC, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_L],
/* 0x8E */ [Debugger.INS.ADC, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_M],
/* 0x8F */ [Debugger.INS.ADC, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_A],
/* 0x90 */ [Debugger.INS.SUB, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_B],
/* 0x91 */ [Debugger.INS.SUB, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_C],
/* 0x92 */ [Debugger.INS.SUB, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_D],
/* 0x93 */ [Debugger.INS.SUB, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_E],
/* 0x94 */ [Debugger.INS.SUB, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_H],
/* 0x95 */ [Debugger.INS.SUB, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_L],
/* 0x96 */ [Debugger.INS.SUB, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_M],
/* 0x97 */ [Debugger.INS.SUB, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_A],
/* 0x98 */ [Debugger.INS.SBB, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_B],
/* 0x99 */ [Debugger.INS.SBB, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_C],
/* 0x9A */ [Debugger.INS.SBB, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_D],
/* 0x9B */ [Debugger.INS.SBB, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_E],
/* 0x9C */ [Debugger.INS.SBB, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_H],
/* 0x9D */ [Debugger.INS.SBB, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_L],
/* 0x9E */ [Debugger.INS.SBB, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_M],
/* 0x9F */ [Debugger.INS.SBB, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_A],
/* 0xA0 */ [Debugger.INS.ANA, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_B],
/* 0xA1 */ [Debugger.INS.ANA, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_C],
/* 0xA2 */ [Debugger.INS.ANA, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_D],
/* 0xA3 */ [Debugger.INS.ANA, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_E],
/* 0xA4 */ [Debugger.INS.ANA, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_H],
/* 0xA5 */ [Debugger.INS.ANA, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_L],
/* 0xA6 */ [Debugger.INS.ANA, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_M],
/* 0xA7 */ [Debugger.INS.ANA, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_A],
/* 0xA8 */ [Debugger.INS.XRA, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_B],
/* 0xA9 */ [Debugger.INS.XRA, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_C],
/* 0xAA */ [Debugger.INS.XRA, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_D],
/* 0xAB */ [Debugger.INS.XRA, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_E],
/* 0xAC */ [Debugger.INS.XRA, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_H],
/* 0xAD */ [Debugger.INS.XRA, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_L],
/* 0xAE */ [Debugger.INS.XRA, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_M],
/* 0xAF */ [Debugger.INS.XRA, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_A],
/* 0xB0 */ [Debugger.INS.ORA, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_B],
/* 0xB1 */ [Debugger.INS.ORA, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_C],
/* 0xB2 */ [Debugger.INS.ORA, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_D],
/* 0xB3 */ [Debugger.INS.ORA, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_E],
/* 0xB4 */ [Debugger.INS.ORA, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_H],
/* 0xB5 */ [Debugger.INS.ORA, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_L],
/* 0xB6 */ [Debugger.INS.ORA, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_M],
/* 0xB7 */ [Debugger.INS.ORA, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_A],
/* 0xB8 */ [Debugger.INS.CMP, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_B],
/* 0xB9 */ [Debugger.INS.CMP, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_C],
/* 0xBA */ [Debugger.INS.CMP, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_D],
/* 0xBB */ [Debugger.INS.CMP, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_E],
/* 0xBC */ [Debugger.INS.CMP, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_H],
/* 0xBD */ [Debugger.INS.CMP, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_L],
/* 0xBE */ [Debugger.INS.CMP, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_M],
/* 0xBF */ [Debugger.INS.CMP, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_A],
/* 0x80 */ [Debugger.INS.ADD, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_B],
/* 0x81 */ [Debugger.INS.ADD, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_C],
/* 0x82 */ [Debugger.INS.ADD, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_D],
/* 0x83 */ [Debugger.INS.ADD, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_E],
/* 0x84 */ [Debugger.INS.ADD, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_H],
/* 0x85 */ [Debugger.INS.ADD, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_L],
/* 0x86 */ [Debugger.INS.ADD, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_M],
/* 0x87 */ [Debugger.INS.ADD, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_A],
/* 0x88 */ [Debugger.INS.ADC, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_B],
/* 0x89 */ [Debugger.INS.ADC, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_C],
/* 0x8A */ [Debugger.INS.ADC, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_D],
/* 0x8B */ [Debugger.INS.ADC, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_E],
/* 0x8C */ [Debugger.INS.ADC, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_H],
/* 0x8D */ [Debugger.INS.ADC, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_L],
/* 0x8E */ [Debugger.INS.ADC, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_M],
/* 0x8F */ [Debugger.INS.ADC, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_A],
/* 0x90 */ [Debugger.INS.SUB, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_B],
/* 0x91 */ [Debugger.INS.SUB, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_C],
/* 0x92 */ [Debugger.INS.SUB, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_D],
/* 0x93 */ [Debugger.INS.SUB, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_E],
/* 0x94 */ [Debugger.INS.SUB, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_H],
/* 0x95 */ [Debugger.INS.SUB, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_L],
/* 0x96 */ [Debugger.INS.SUB, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_M],
/* 0x97 */ [Debugger.INS.SUB, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_A],
/* 0x98 */ [Debugger.INS.SBB, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_B],
/* 0x99 */ [Debugger.INS.SBB, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_C],
/* 0x9A */ [Debugger.INS.SBB, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_D],
/* 0x9B */ [Debugger.INS.SBB, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_E],
/* 0x9C */ [Debugger.INS.SBB, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_H],
/* 0x9D */ [Debugger.INS.SBB, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_L],
/* 0x9E */ [Debugger.INS.SBB, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_M],
/* 0x9F */ [Debugger.INS.SBB, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_A],
/* 0xA0 */ [Debugger.INS.ANA, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_B],
/* 0xA1 */ [Debugger.INS.ANA, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_C],
/* 0xA2 */ [Debugger.INS.ANA, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_D],
/* 0xA3 */ [Debugger.INS.ANA, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_E],
/* 0xA4 */ [Debugger.INS.ANA, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_H],
/* 0xA5 */ [Debugger.INS.ANA, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_L],
/* 0xA6 */ [Debugger.INS.ANA, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_M],
/* 0xA7 */ [Debugger.INS.ANA, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_A],
/* 0xA8 */ [Debugger.INS.XRA, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_B],
/* 0xA9 */ [Debugger.INS.XRA, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_C],
/* 0xAA */ [Debugger.INS.XRA, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_D],
/* 0xAB */ [Debugger.INS.XRA, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_E],
/* 0xAC */ [Debugger.INS.XRA, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_H],
/* 0xAD */ [Debugger.INS.XRA, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_L],
/* 0xAE */ [Debugger.INS.XRA, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_M],
/* 0xAF */ [Debugger.INS.XRA, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_A],
/* 0xB0 */ [Debugger.INS.ORA, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_B],
/* 0xB1 */ [Debugger.INS.ORA, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_C],
/* 0xB2 */ [Debugger.INS.ORA, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_D],
/* 0xB3 */ [Debugger.INS.ORA, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_E],
/* 0xB4 */ [Debugger.INS.ORA, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_H],
/* 0xB5 */ [Debugger.INS.ORA, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_L],
/* 0xB6 */ [Debugger.INS.ORA, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_M],
/* 0xB7 */ [Debugger.INS.ORA, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_A],
/* 0xB8 */ [Debugger.INS.CMP, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_B],
/* 0xB9 */ [Debugger.INS.CMP, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_C],
/* 0xBA */ [Debugger.INS.CMP, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_D],
/* 0xBB */ [Debugger.INS.CMP, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_E],
/* 0xBC */ [Debugger.INS.CMP, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_H],
/* 0xBD */ [Debugger.INS.CMP, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_L],
/* 0xBE */ [Debugger.INS.CMP, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_M],
/* 0xBF */ [Debugger.INS.CMP, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_A],
/* 0xC0 */ [Debugger.INS.RNZ],
/* 0xC1 */ [Debugger.INS.POP, Debugger.TYPE_BC],
/* 0xC2 */ [Debugger.INS.JNZ, Debugger.TYPE_ADDR],
/* 0xC3 */ [Debugger.INS.JMP, Debugger.TYPE_ADDR],
/* 0xC4 */ [Debugger.INS.CNZ, Debugger.TYPE_ADDR],
/* 0xC5 */ [Debugger.INS.PUSH, Debugger.TYPE_BC],
/* 0xC6 */ [Debugger.INS.ADI, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_IMM | Debugger.TYPE_BYTE],
/* 0xC6 */ [Debugger.INS.ADI, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_IMM | Debugger.TYPE_BYTE],
/* 0xC7 */ [Debugger.INS.RST, Debugger.TYPE_INT],
/* 0xC8 */ [Debugger.INS.RZ],
/* 0xC9 */ [Debugger.INS.RET],
@ -607,39 +607,39 @@ if (DEBUGGER) {
/* 0xCB */ [Debugger.INS.JMP, Debugger.TYPE_ADDR | Debugger.TYPE_UNDOC],
/* 0xCC */ [Debugger.INS.CZ, Debugger.TYPE_ADDR],
/* 0xCD */ [Debugger.INS.CALL, Debugger.TYPE_ADDR],
/* 0xCE */ [Debugger.INS.ACI, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_IMM | Debugger.TYPE_BYTE],
/* 0xCE */ [Debugger.INS.ACI, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_IMM | Debugger.TYPE_BYTE],
/* 0xCF */ [Debugger.INS.RST, Debugger.TYPE_INT],
/* 0xD0 */ [Debugger.INS.RNC],
/* 0xD1 */ [Debugger.INS.POP, Debugger.TYPE_DE],
/* 0xD2 */ [Debugger.INS.JNC, Debugger.TYPE_ADDR],
/* 0xD3 */ [Debugger.INS.OUT, Debugger.TYPE_IMM | Debugger.TYPE_BYTE, Debugger.TYPE_A | Debugger.TYPE_OPT],
/* 0xD3 */ [Debugger.INS.OUT, Debugger.TYPE_IMM | Debugger.TYPE_BYTE,Debugger.TYPE_A | Debugger.TYPE_OPT],
/* 0xD4 */ [Debugger.INS.CNC, Debugger.TYPE_ADDR],
/* 0xD5 */ [Debugger.INS.PUSH, Debugger.TYPE_DE],
/* 0xD6 */ [Debugger.INS.SUI, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_IMM | Debugger.TYPE_BYTE],
/* 0xD6 */ [Debugger.INS.SUI, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_IMM | Debugger.TYPE_BYTE],
/* 0xD7 */ [Debugger.INS.RST, Debugger.TYPE_INT],
/* 0xD8 */ [Debugger.INS.RC],
/* 0xD9 */ [Debugger.INS.RET, Debugger.TYPE_UNDOC],
/* 0xDA */ [Debugger.INS.JC, Debugger.TYPE_ADDR],
/* 0xDB */ [Debugger.INS.IN, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_IMM | Debugger.TYPE_BYTE],
/* 0xDB */ [Debugger.INS.IN, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_IMM | Debugger.TYPE_BYTE],
/* 0xDC */ [Debugger.INS.CC, Debugger.TYPE_ADDR],
/* 0xDD */ [Debugger.INS.CALL, Debugger.TYPE_ADDR | Debugger.TYPE_UNDOC],
/* 0xDE */ [Debugger.INS.SBI, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_IMM | Debugger.TYPE_BYTE],
/* 0xDE */ [Debugger.INS.SBI, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_IMM | Debugger.TYPE_BYTE],
/* 0xDF */ [Debugger.INS.RST, Debugger.TYPE_INT],
/* 0xE0 */ [Debugger.INS.RPO],
/* 0xE1 */ [Debugger.INS.POP, Debugger.TYPE_HL],
/* 0xE2 */ [Debugger.INS.JPO, Debugger.TYPE_ADDR],
/* 0xE3 */ [Debugger.INS.XTHL, Debugger.TYPE_SP | Debugger.TYPE_MEM, Debugger.TYPE_HL],// let's be more explicit about the operands
/* 0xE3 */ [Debugger.INS.XTHL, Debugger.TYPE_SP | Debugger.TYPE_MEM| Debugger.TYPE_OPT, Debugger.TYPE_HL | Debugger.TYPE_OPT],
/* 0xE4 */ [Debugger.INS.CPO, Debugger.TYPE_ADDR],
/* 0xE5 */ [Debugger.INS.PUSH, Debugger.TYPE_HL],
/* 0xE6 */ [Debugger.INS.ANI, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_IMM | Debugger.TYPE_BYTE],
/* 0xE6 */ [Debugger.INS.ANI, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_IMM | Debugger.TYPE_BYTE],
/* 0xE7 */ [Debugger.INS.RST, Debugger.TYPE_INT],
/* 0xE8 */ [Debugger.INS.RPE],
/* 0xE9 */ [Debugger.INS.PCHL, Debugger.TYPE_HL],
/* 0xEA */ [Debugger.INS.JPE, Debugger.TYPE_ADDR],
/* 0xEB */ [Debugger.INS.XCHG, Debugger.TYPE_HL, Debugger.TYPE_DE], // let's be more explicit about the operands
/* 0xEB */ [Debugger.INS.XCHG, Debugger.TYPE_HL | Debugger.TYPE_OPT, Debugger.TYPE_DE | Debugger.TYPE_OPT],
/* 0xEC */ [Debugger.INS.CPE, Debugger.TYPE_ADDR],
/* 0xED */ [Debugger.INS.CALL, Debugger.TYPE_ADDR | Debugger.TYPE_UNDOC],
/* 0xEE */ [Debugger.INS.XRI, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_IMM | Debugger.TYPE_BYTE],
/* 0xEE */ [Debugger.INS.XRI, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_IMM | Debugger.TYPE_BYTE],
/* 0xEF */ [Debugger.INS.RST, Debugger.TYPE_INT],
/* 0xF0 */ [Debugger.INS.RP],
/* 0xF1 */ [Debugger.INS.POP, Debugger.TYPE_PS],
@ -647,15 +647,15 @@ if (DEBUGGER) {
/* 0xF3 */ [Debugger.INS.DI],
/* 0xF4 */ [Debugger.INS.CP, Debugger.TYPE_ADDR],
/* 0xF5 */ [Debugger.INS.PUSH, Debugger.TYPE_PS],
/* 0xF6 */ [Debugger.INS.ORI, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_IMM | Debugger.TYPE_BYTE],
/* 0xF6 */ [Debugger.INS.ORI, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_IMM | Debugger.TYPE_BYTE],
/* 0xF7 */ [Debugger.INS.RST, Debugger.TYPE_INT],
/* 0xF8 */ [Debugger.INS.RM],
/* 0xF9 */ [Debugger.INS.SPHL, Debugger.TYPE_SP, Debugger.TYPE_HL], // let's be more explicit about the operands
/* 0xF9 */ [Debugger.INS.SPHL, Debugger.TYPE_SP | Debugger.TYPE_OPT, Debugger.TYPE_HL | Debugger.TYPE_OPT],
/* 0xFA */ [Debugger.INS.JM, Debugger.TYPE_ADDR],
/* 0xFB */ [Debugger.INS.EI],
/* 0xFC */ [Debugger.INS.CM, Debugger.TYPE_ADDR],
/* 0xFD */ [Debugger.INS.CALL, Debugger.TYPE_ADDR | Debugger.TYPE_UNDOC],
/* 0xFE */ [Debugger.INS.CPI, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_IMM | Debugger.TYPE_BYTE],
/* 0xFE */ [Debugger.INS.CPI, Debugger.TYPE_A | Debugger.TYPE_OPT, Debugger.TYPE_IMM | Debugger.TYPE_BYTE],
/* 0xFF */ [Debugger.INS.RST, Debugger.TYPE_INT]
];
@ -2651,7 +2651,6 @@ if (DEBUGGER) {
this.getRegOutput(Debugger.REG_DE) +
this.getRegOutput(Debugger.REG_HL) +
this.getRegOutput(Debugger.REG_SP) +
this.getRegOutput(Debugger.REG_PS) +
this.getFlagOutput('I') + this.getFlagOutput('S') + this.getFlagOutput('Z') +
this.getFlagOutput('A') + this.getFlagOutput('P') + this.getFlagOutput('C');
return s;

View file

@ -38,6 +38,7 @@ if (NODE) {
var DumpAPI = require("../../shared/lib/dumpapi");
var Component = require("../../shared/lib/component");
var Memory = require("./memory");
var CPUDef = require("./cpudef");
}
/**
@ -49,7 +50,7 @@ if (NODE) {
* size: amount of ROM, in bytes
* alias: physical alias address (null if none)
* file: name of ROM data file
* notify: ID of a component to notify once the ROM is in place (optional)
* writable: true to make ROM writable (default is false)
*
* NOTE: The ROM data will not be copied into place until the Bus is ready (see initBus()) AND the
* ROM data file has finished loading (see doneLoad()).
@ -57,6 +58,10 @@ if (NODE) {
* Also, while the size parameter may seem redundant, I consider it useful to confirm that the ROM you received
* is the ROM you expected.
*
* Finally, while making ROM "writable" may seem a contradiction in terms, I want to be able to load selected
* CP/M binary files into memory purely for testing purposes, and the RAM component has no "file" option, so the
* simplest solution was to add the option to load binary files into memory as "writable ROMs".
*
* @constructor
* @extends Component
* @param {Object} parmsROM
@ -68,6 +73,7 @@ function ROM(parmsROM)
this.abROM = null;
this.addrROM = parmsROM['addr'];
this.sizeROM = parmsROM['size'];
this.fWritable = parmsROM['writable'];
/*
* The new 'alias' property can now be EITHER a single physical address (like 'addr') OR an array of
@ -106,6 +112,8 @@ function ROM(parmsROM)
Component.subclass(ROM);
ROM.FAKECPM_VECTORS = [0x0000, 0x0005];
/*
* NOTE: There's currently no need for this component to have a reset() function, since
* once the ROM data is loaded, it can't be changed, so there's nothing to reinitialize.
@ -268,6 +276,12 @@ ROM.prototype.copyROM = function()
this.setReady();
}
else if (this.abROM && this.bus) {
/*
* If no explicit size was specified, then use whatever the actual size is.
*/
if (!this.sizeROM) {
this.sizeROM = this.abROM.length;
}
if (this.abROM.length != this.sizeROM) {
/*
* Note that setError() sets the component's fError flag, which in turn prevents setReady() from
@ -314,11 +328,28 @@ ROM.prototype.copyROM = function()
*/
ROM.prototype.addROM = function(addr)
{
if (this.bus.addMemory(addr, this.sizeROM, Memory.TYPE.ROM)) {
if (this.bus.addMemory(addr, this.sizeROM, this.fWritable? Memory.TYPE.RAM : Memory.TYPE.ROM)) {
if (DEBUG) this.log("addROM(): copying ROM to " + str.toHexLong(addr) + " (" + str.toHexLong(this.abROM.length) + " bytes)");
var bto = null;
for (var off = 0; off < this.abROM.length; off++) {
this.bus.setByteDirect(addr + off, this.abROM[off]);
var i;
for (i = 0; i < this.abROM.length; i++) {
this.bus.setByteDirect(addr + i, this.abROM[i]);
}
if (this.fWritable && addr == 0x100) {
/*
* Here's where we enable our "Fake CP/M" support, triggered by the user loading a "writable ROM" image
* at offset 0x100. Fake CP/M support works by installing HLT opcodes at well-known hard-coded CP/M offsets
* (namely, 0x0000, which is the CP/M reset vector, and 0x0005, which is the CP/M system call vector) and
* then telling the CPU to call us whenever a HLT occurs, so we can check PC for one of these vectors.
*/
for (i = 0; i < ROM.FAKECPM_VECTORS.length; i++) {
this.bus.setByteDirect(ROM.FAKECPM_VECTORS[i], CPUDef.OPCODE.HLT);
}
this.cpu.addHaltCheck(function(rom) {
return function(addr) {rom.checkHalt(addr)};
}(this));
this.cpu.setReset(addr);
}
return true;
}
@ -328,6 +359,24 @@ ROM.prototype.addROM = function(addr)
return false;
};
/**
* checkHalt(addr)
*
* @this {ROM}
* @param {number} addr (of the HLT opcode)
* @return {boolean} true if special processing performed, false if not
*/
ROM.prototype.checkHalt = function(addr)
{
if (this.dbg) {
this.println("CP/M vector " + str.toHexWord(addr));
this.cpu.setPC(addr); // this is purely for the Debugger's benefit, to show the HLT
this.dbg.stopCPU();
return true;
}
return false;
};
/**
* cloneROM(addr)
*

View file

@ -78,7 +78,7 @@ function Bus(parmsBus, cpu, dbg)
this.cpu = cpu;
this.dbg = dbg;
this.nBusWidth = parmsBus['buswidth'] || 20;
this.nBusWidth = parmsBus['busWidth'] || 20;
/*
* Compute all Bus memory block parameters, based on the width of the bus.
@ -93,8 +93,8 @@ function Bus(parmsBus, cpu, dbg)
*
* iBlock & this.nBlockMask
*
* Similarly, we mask addresses with busMask to enforce "A20 wrap" on 20-bit busses.
* For larger busses, A20 wrap can be simulated by either clearing bit 20 of busMask or by
* Similarly, we mask addresses with busMask to enforce "A20 wrap" on 20-bit buses.
* For larger buses, A20 wrap can be simulated by either clearing bit 20 of busMask or by
* changing all the block entries for the 2nd megabyte to match those in the 1st megabyte.
*
* Bus Property Old hard-coded values (when nBusWidth was always 20)
@ -354,16 +354,16 @@ Bus.prototype.powerUp = function(data, fRepower)
* allocations, etc.
*
* We've relaxed some of the original requirements (ie, that addresses must start at a
* block-granular address, or that sizes must be equal to exactly one or more blocks), because
* machines with large block sizes can make it impossible to load certain ROMs at at their
* required addresses.
* block-granular address, or that sizes must be equal to exactly one or more blocks),
* because machines with large block sizes can make it impossible to load certain ROMs at
* their required addresses. Every allocation still allocates a whole number of blocks.
*
* Even so, Bus memory management does NOT provide a general-purpose heap. Most memory
* allocations occur during machine initialization and never change. The only notable
* exception is the Video frame buffer, which ranges from 4Kb (MDA) to 16Kb (CGA) to
* 32Kb/64Kb/128Kb (EGA), and only the EGA changes its buffer address post-initialization.
* allocations occur during machine initialization and never change. In particular, there
* is NO support for removing partial-block allocations. Typically, the only region that
* changes post-initialization is the Video buffer, and only in the EGA/VGA implementation.
*
* Each Memory block keeps track of a single address (addr) and length (used), indicating
* Each Memory block keeps track of a start address (addr) and length (used), indicating
* the used space within the block; any free space that precedes or follows that used space
* can be allocated later, by simply extending the beginning or ending of the previously used
* space. However, any holes that might have existed between the original allocation and an
@ -380,17 +380,18 @@ Bus.prototype.addMemory = function(addr, size, type, controller)
{
var iBlock = addr >>> this.nBlockShift;
while (size > 0 && iBlock < this.aMemBlocks.length) {
var block = this.aMemBlocks[iBlock];
var addrBlock = iBlock * this.nBlockSize;
var sizeBlock = size > this.nBlockSize? this.nBlockSize : size;
var sizeBlock = this.nBlockSize - (addr - addrBlock);
if (sizeBlock > size) sizeBlock = size;
if (block && block.size) {
if (block.type == type && block.controller == controller) {
/*
* Where there is already a block with a non-zero size, we can allow the allocation only if:
* Where there is already a similar block with a non-zero size, we allow the allocation only if:
*
* 1) addr + size <= block.addr (the request precedes the used portion of the current block)
* or:
* 1) addr + size <= block.addr (the request precedes the used portion of the current block), or
* 2) addr >= block.addr + block.used (the request follows the used portion of the current block)
*/
if (addr + size <= block.addr) {
@ -402,17 +403,19 @@ Bus.prototype.addMemory = function(addr, size, type, controller)
var sizeAvail = block.size - (addr - addrBlock);
if (sizeAvail > size) sizeAvail = size;
block.used = addr - block.addr + sizeAvail;
size -= sizeAvail;
addr = addrBlock + this.nBlockSize;
size -= sizeAvail;
iBlock++;
continue;
}
}
return this.reportError(Bus.ERROR.ADD_MEM_INUSE, addr, size);
}
var blockOld = this.aMemBlocks[iBlock];
var blockNew = new Memory(addr, sizeBlock, this.nBlockSize, type, controller);
blockNew.copyBreakpoints(this.dbg, blockOld);
blockNew.copyBreakpoints(this.dbg, block);
this.aMemBlocks[iBlock++] = blockNew;
addr = addrBlock + this.nBlockSize;
size -= sizeBlock;
}

View file

@ -195,7 +195,7 @@ function Computer(parmsComputer, parmsMachine, fSuspended) {
/*
* Initialize the Bus component
*/
this.bus = new Bus({'id': this.idMachine + '.bus', 'buswidth': this.nBusWidth}, this.cpu, this.dbg);
this.bus = new Bus({'id': this.idMachine + '.bus', 'busWidth': this.nBusWidth}, this.cpu, this.dbg);
/*
* Iterate through all the components and connect them to the Control Panel, if any

View file

@ -305,6 +305,12 @@ ROM.prototype.copyROM = function()
this.setReady();
}
else if (this.abROM && this.bus) {
/*
* If no explicit size was specified, then use whatever the actual size is.
*/
if (!this.sizeROM) {
this.sizeROM = this.abROM.length;
}
if (this.abROM.length != this.sizeROM) {
/*
* Note that setError() sets the component's fError flag, which in turn prevents setReady() from

View file

@ -903,10 +903,16 @@
<xsl:otherwise/>
</xsl:choose>
</xsl:variable>
<xsl:variable name="writable">
<xsl:choose>
<xsl:when test="@writable"><xsl:value-of select="@writable"/></xsl:when>
<xsl:otherwise>false</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:call-template name="component">
<xsl:with-param name="machine" select="$machine"/>
<xsl:with-param name="class">rom</xsl:with-param>
<xsl:with-param name="parms">,addr:<xsl:value-of select="$addr"/>,size:<xsl:value-of select="$size"/>,alias:<xsl:value-of select="$alias"/>,file:'<xsl:value-of select="$file"/>',notify:'<xsl:value-of select="$notify"/>'</xsl:with-param>
<xsl:with-param name="parms">,addr:<xsl:value-of select="$addr"/>,size:<xsl:value-of select="$size"/>,alias:<xsl:value-of select="$alias"/>,file:'<xsl:value-of select="$file"/>',notify:'<xsl:value-of select="$notify"/>',writable:<xsl:value-of select="$writable"/></xsl:with-param>
</xsl:call-template>
</xsl:template>
@ -1141,7 +1147,7 @@
<xsl:choose>
<xsl:when test="@buswidth"><xsl:value-of select="@buswidth"/></xsl:when>
<xsl:when test="@busWidth"><xsl:value-of select="@busWidth"/></xsl:when>
<xsl:otherwise>20</xsl:otherwise>
<xsl:otherwise>0</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:variable name="resume">