Added Debugger "int" command to manually request interrupts
This commit is contained in:
parent
65ecb282ad
commit
276c36334e
11 changed files with 1328 additions and 44 deletions
|
|
@ -5,7 +5,6 @@ permalink: /devices/pc8080/machine/invaders/
|
||||||
machines:
|
machines:
|
||||||
- type: pc8080
|
- type: pc8080
|
||||||
id: invaders
|
id: invaders
|
||||||
debugger: true
|
|
||||||
---
|
---
|
||||||
|
|
||||||
Space Invaders (1978)
|
Space Invaders (1978)
|
||||||
|
|
|
||||||
27
devices/pc8080/machine/invaders/debugger/README.md
Normal file
27
devices/pc8080/machine/invaders/debugger/README.md
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
---
|
||||||
|
layout: page
|
||||||
|
title: Space Invaders (1978) with Debugger
|
||||||
|
permalink: /devices/pc8080/machine/invaders/debugger/
|
||||||
|
machines:
|
||||||
|
- type: pc8080
|
||||||
|
id: invaders
|
||||||
|
debugger: true
|
||||||
|
---
|
||||||
|
|
||||||
|
Space Invaders (1978) with Debugger
|
||||||
|
-----------------------------------
|
||||||
|
|
||||||
|
The [PC8080](/modules/pc8080/) machine below is configured to run [Space Invaders](/devices/pc8080/machine/invaders/)
|
||||||
|
with a Control Panel and Debugger. It is currently playable only in desktop browsers and uses the following hard-coded
|
||||||
|
key mappings:
|
||||||
|
|
||||||
|
- 1: One Player
|
||||||
|
- 2: Two Player
|
||||||
|
- 3: Insert Coin
|
||||||
|
- A: Move Left
|
||||||
|
- D: Move Right
|
||||||
|
- L: Fire Missile
|
||||||
|
|
||||||
|
Click the "Run" button when you're ready to start the simulation.
|
||||||
|
|
||||||
|
{% include machine.html id="invaders" %}
|
||||||
24
devices/pc8080/machine/invaders/debugger/machine.xml
Normal file
24
devices/pc8080/machine/invaders/debugger/machine.xml
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<?xml-stylesheet type="text/xsl" href="/versions/pc8080/1.23.3/machine.xsl"?>
|
||||||
|
<machine id="invaders" class="pc8080" border="1" pos="center" background="#FAEBD7">
|
||||||
|
<name pos="center">Space Invaders</name>
|
||||||
|
<computer id="computer" busWidth="16"/>
|
||||||
|
<cpu id="cpu8080" model="8080" cycles="2000000" autoStart="true"/>
|
||||||
|
<rom id="romH" addr="0x0000" size="0x0800" file="/devices/pc8080/rom/invaders/INVADERS-H.json"/>
|
||||||
|
<rom id="romG" addr="0x0800" size="0x0800" file="/devices/pc8080/rom/invaders/INVADERS-G.json"/>
|
||||||
|
<rom id="romF" addr="0x1000" size="0x0800" file="/devices/pc8080/rom/invaders/INVADERS-F.json"/>
|
||||||
|
<rom id="romE" addr="0x1800" size="0x0800" file="/devices/pc8080/rom/invaders/INVADERS-E.json"/>
|
||||||
|
<ram id="ram" addr="0x2000" size="0x0400"/>
|
||||||
|
<video id="video" screenWidth="896" screenHeight="1024" bufferRotate="-90" smoothing="false" bufferAddr="0x2400" bufferCols="256" bufferRows="224" bufferBits="1" bufferLeft="0" interruptRate="120" width="40%" pos="left" padding="8px">
|
||||||
|
<menu>
|
||||||
|
<title>224x256 Screen (Rotated)</title>
|
||||||
|
<control type="container" pos="right">
|
||||||
|
<control type="button" binding="fullScreen" padleft="8px;line-height:1em">Full Screen</control>
|
||||||
|
</control>
|
||||||
|
</menu>
|
||||||
|
</video>
|
||||||
|
<chipset id="chipset" model="SI1978"/>
|
||||||
|
<keyboard id="keyboard"/>
|
||||||
|
<panel ref="/devices/pc8080/panel/left.xml"/>
|
||||||
|
<debugger id="debugger" commands="s 8086"/>
|
||||||
|
</machine>
|
||||||
|
|
@ -9,7 +9,7 @@
|
||||||
<rom id="romF" addr="0x1000" size="0x0800" file="/devices/pc8080/rom/invaders/INVADERS-F.json"/>
|
<rom id="romF" addr="0x1000" size="0x0800" file="/devices/pc8080/rom/invaders/INVADERS-F.json"/>
|
||||||
<rom id="romE" addr="0x1800" size="0x0800" file="/devices/pc8080/rom/invaders/INVADERS-E.json"/>
|
<rom id="romE" addr="0x1800" size="0x0800" file="/devices/pc8080/rom/invaders/INVADERS-E.json"/>
|
||||||
<ram id="ram" addr="0x2000" size="0x0400"/>
|
<ram id="ram" addr="0x2000" size="0x0400"/>
|
||||||
<video id="video" screenWidth="896" screenHeight="1024" bufferRotate="-90" smoothing="false" bufferAddr="0x2400" bufferCols="256" bufferRows="224" bufferBits="1" bufferLeft="0" interruptRate="120" width="40%" pos="left" padding="8px">
|
<video id="video" screenWidth="896" screenHeight="1024" bufferRotate="-90" smoothing="false" bufferAddr="0x2400" bufferCols="256" bufferRows="224" bufferBits="1" bufferLeft="0" interruptRate="120" padding="8px">
|
||||||
<menu>
|
<menu>
|
||||||
<title>224x256 Screen (Rotated)</title>
|
<title>224x256 Screen (Rotated)</title>
|
||||||
<control type="container" pos="right">
|
<control type="container" pos="right">
|
||||||
|
|
@ -19,6 +19,4 @@
|
||||||
</video>
|
</video>
|
||||||
<chipset id="chipset" model="SI1978"/>
|
<chipset id="chipset" model="SI1978"/>
|
||||||
<keyboard id="keyboard"/>
|
<keyboard id="keyboard"/>
|
||||||
<panel ref="/devices/pc8080/panel/left.xml"/>
|
|
||||||
<debugger id="debugger" commands="s 8086"/>
|
|
||||||
</machine>
|
</machine>
|
||||||
|
|
|
||||||
|
|
@ -26,5 +26,5 @@
|
||||||
<chipset id="chipset" model="VT100"/>
|
<chipset id="chipset" model="VT100"/>
|
||||||
<keyboard id="keyboard"/>
|
<keyboard id="keyboard"/>
|
||||||
<panel ref="/devices/pc8080/panel/wide.xml"/>
|
<panel ref="/devices/pc8080/panel/wide.xml"/>
|
||||||
<debugger id="debugger" messages="port|mem" commands="s 8086"/>
|
<debugger id="debugger" messages="chipset|mem" commands="s 8086"/>
|
||||||
</machine>
|
</machine>
|
||||||
|
|
|
||||||
|
|
@ -64,6 +64,8 @@ and passed on to the PC8080 Debugger. Here are the rebuild steps:
|
||||||
grep -E "[0-9]+ [0-9A-D]+.*;;" VT100.lst | sed -E "s/ *[0-9]+ ([0-9A-F]+).*;(;.*)/ \1 . \2/" > VT100.map
|
grep -E "[0-9]+ [0-9A-D]+.*;;" VT100.lst | sed -E "s/ *[0-9]+ ([0-9A-F]+).*;(;.*)/ \1 . \2/" > VT100.map
|
||||||
filedump --file=VT100.bin --format=bytes --output=VT100.json --comments --overwrite
|
filedump --file=VT100.bin --format=bytes --output=VT100.json --comments --overwrite
|
||||||
|
|
||||||
|
You can omit `--comments` to reduce the size of the [VT100.json](VT100.json) file.
|
||||||
|
|
||||||
Some [VT100.asm](VT100.asm) clean-up remains, because there are still chunks of data that were incorrectly disassembled as code.
|
Some [VT100.asm](VT100.asm) clean-up remains, because there are still chunks of data that were incorrectly disassembled as code.
|
||||||
From a reassembly standpoint, it doesn't matter too much, because such instructions get reassembled into the same original binary
|
From a reassembly standpoint, it doesn't matter too much, because such instructions get reassembled into the same original binary
|
||||||
patterns, but from a readability standpoint, it's a nuisance.
|
patterns, but from a readability standpoint, it's a nuisance.
|
||||||
|
|
|
||||||
|
|
@ -3703,8 +3703,8 @@ X18d7: in 42h
|
||||||
jnz X18d7
|
jnz X18d7
|
||||||
mvi a,2fh ;; Write 0x2fh (standby) to nvr latch
|
mvi a,2fh ;; Write 0x2fh (standby) to nvr latch
|
||||||
out 62h
|
out 62h
|
||||||
lxi h,X21d3 ;; HL=X21d3
|
lxi h,X21d3 ;; HL = X21d3
|
||||||
mvi b,0eh ;; B= 14 -- we're reading 14 bits
|
mvi b,0eh ;; B = 14 -- we're reading 14 bits
|
||||||
X18e6: in 42h
|
X18e6: in 42h
|
||||||
ana c
|
ana c
|
||||||
jz X18e6
|
jz X18e6
|
||||||
|
|
@ -3726,7 +3726,7 @@ X1900: in 42h
|
||||||
jnz X18f6 ;; read next bit
|
jnz X18f6 ;; read next bit
|
||||||
mvi a,2fh ;; send standby
|
mvi a,2fh ;; send standby
|
||||||
out 62h
|
out 62h
|
||||||
lxi d,X21d3 ;; DE=0x21d3
|
lxi d,X21d3 ;; DE = 0x21d3
|
||||||
mvi b,0eh ;; B = 14
|
mvi b,0eh ;; B = 14
|
||||||
lxi h,X0000 ;; HL = 0
|
lxi h,X0000 ;; HL = 0
|
||||||
X1916: dad h ;;
|
X1916: dad h ;;
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -631,7 +631,7 @@ FileDump.prototype.loadMap = function(sMapFile, done)
|
||||||
done(new Error("unrecognized line (" + s + ") in MAP file: " + sMapName), null);
|
done(new Error("unrecognized line (" + s + ") in MAP file: " + sMapName), null);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
sMapData = JSON.stringify(aSymbols);
|
sMapData = obj.fJSONComments? JSON.stringify(aSymbols, null, 2) : JSON.stringify(aSymbols);
|
||||||
if (sMapData) {
|
if (sMapData) {
|
||||||
obj.json = '{' + obj.json + ',"symbols":' + sMapData + '}';
|
obj.json = '{' + obj.json + ',"symbols":' + sMapData + '}';
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -205,7 +205,8 @@ ChipSet.VT100 = {
|
||||||
ERASE: 0x5,
|
ERASE: 0x5,
|
||||||
READ: 0x6,
|
READ: 0x6,
|
||||||
STANDBY: 0x7
|
STANDBY: 0x7
|
||||||
}
|
},
|
||||||
|
WORDMASK: 0x3fff // NVR words are 14-bit
|
||||||
},
|
},
|
||||||
DC012: { // generates scan counts for the Video Processor
|
DC012: { // generates scan counts for the Video Processor
|
||||||
PORT: 0xA2, // write-only
|
PORT: 0xA2, // write-only
|
||||||
|
|
@ -678,11 +679,11 @@ ChipSet.prototype.getNVRAddr = function()
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* advanceNVR()
|
* doNVRCommand()
|
||||||
*/
|
*/
|
||||||
ChipSet.prototype.advanceNVR = function()
|
ChipSet.prototype.doNVRCommand = function()
|
||||||
{
|
{
|
||||||
var addr;
|
var addr, data;
|
||||||
var bit = this.bNVRLatch & 0x1;
|
var bit = this.bNVRLatch & 0x1;
|
||||||
var bCmd = (this.bNVRLatch >> 1) & 0x7;
|
var bCmd = (this.bNVRLatch >> 1) & 0x7;
|
||||||
|
|
||||||
|
|
@ -696,7 +697,8 @@ ChipSet.prototype.advanceNVR = function()
|
||||||
|
|
||||||
case ChipSet.VT100.NVR.CMD.ERASE:
|
case ChipSet.VT100.NVR.CMD.ERASE:
|
||||||
addr = this.getNVRAddr();
|
addr = this.getNVRAddr();
|
||||||
this.aNVRWords[addr] = 0x3fff;
|
this.aNVRWords[addr] = ChipSet.VT100.NVR.WORDMASK;
|
||||||
|
this.printMessage("doNVRCommand(): erase data at addr " + str.toHexWord(addr));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ChipSet.VT100.NVR.CMD.ACCEPT_DATA:
|
case ChipSet.VT100.NVR.CMD.ACCEPT_DATA:
|
||||||
|
|
@ -705,17 +707,32 @@ ChipSet.prototype.advanceNVR = function()
|
||||||
|
|
||||||
case ChipSet.VT100.NVR.CMD.WRITE:
|
case ChipSet.VT100.NVR.CMD.WRITE:
|
||||||
addr = this.getNVRAddr();
|
addr = this.getNVRAddr();
|
||||||
this.aNVRWords[addr] = this.wNVRData & 0x3fff;
|
data = this.wNVRData & ChipSet.VT100.NVR.WORDMASK;
|
||||||
|
this.aNVRWords[addr] = data;
|
||||||
|
this.printMessage("doNVRCommand(): write data " + str.toHexWord(data) + " to addr " + str.toHexWord(addr));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ChipSet.VT100.NVR.CMD.READ:
|
case ChipSet.VT100.NVR.CMD.READ:
|
||||||
addr = this.getNVRAddr();
|
addr = this.getNVRAddr();
|
||||||
this.wNVRData = this.aNVRWords[addr];
|
data = this.aNVRWords[addr];
|
||||||
|
/*
|
||||||
|
* Since we don't explicitly initialize aNVRWords[], we pretend any uninitialized words contains WORDMASK.
|
||||||
|
*/
|
||||||
|
if (data == null) data = ChipSet.VT100.NVR.WORDMASK;
|
||||||
|
this.wNVRData = data;
|
||||||
|
this.printMessage("doNVRCommand(): read data " + str.toHexWord(data) + " from addr " + str.toHexWord(addr));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ChipSet.VT100.NVR.CMD.SHIFT_OUT:
|
case ChipSet.VT100.NVR.CMD.SHIFT_OUT:
|
||||||
this.bNVROut = this.wNVRData & 0x2000;
|
|
||||||
this.wNVRData <<= 1;
|
this.wNVRData <<= 1;
|
||||||
|
/*
|
||||||
|
* Since WORDMASK is 0x3fff, this will mask the shifted data with 0x4000, which is the bit we want to isolate.
|
||||||
|
*/
|
||||||
|
this.bNVROut = this.wNVRData & (ChipSet.VT100.NVR.WORDMASK + 1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
this.printMessage("doNVRCommand(): unrecognized command " + str.toHexByte(bCmd));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -738,7 +755,7 @@ ChipSet.prototype.inVT100FlagsBuffer = function(port, addrFrom)
|
||||||
if (this.getVT100LBA(7)) {
|
if (this.getVT100LBA(7)) {
|
||||||
b |= ChipSet.VT100.FLAGS_BUFFER.NVR_CLK;
|
b |= ChipSet.VT100.FLAGS_BUFFER.NVR_CLK;
|
||||||
if (b != this.bFlagsBuffer) {
|
if (b != this.bFlagsBuffer) {
|
||||||
this.advanceNVR();
|
this.doNVRCommand();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
b &= ~ChipSet.VT100.FLAGS_BUFFER.NVR_DATA;
|
b &= ~ChipSet.VT100.FLAGS_BUFFER.NVR_DATA;
|
||||||
|
|
|
||||||
|
|
@ -230,30 +230,31 @@ if (DEBUGGER) {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Debugger.COMMANDS = {
|
Debugger.COMMANDS = {
|
||||||
'?': "help/print",
|
'?': "help/print",
|
||||||
'a [#]': "assemble", // TODO: Implement this command someday
|
'a [#]': "assemble", // TODO: Implement this command someday
|
||||||
'b [#]': "breakpoint", // multiple variations (use b? to list them)
|
'b [#]': "breakpoint", // multiple variations (use b? to list them)
|
||||||
'c': "clear output",
|
'c': "clear output",
|
||||||
'd [#]': "dump memory", // additional syntax: d [#] [l#], where l# is a number of bytes to dump
|
'd [#]': "dump memory", // additional syntax: d [#] [l#], where l# is a number of bytes to dump
|
||||||
'e [#]': "edit memory",
|
'e [#]': "edit memory",
|
||||||
'f': "frequencies",
|
'f': "frequencies",
|
||||||
'g [#]': "go [to #]",
|
'g [#]': "go [to #]",
|
||||||
'h': "halt",
|
'h': "halt",
|
||||||
'i [#]': "input port #",
|
'i [#]': "input port #",
|
||||||
'if': "eval expression",
|
'if': "eval expression",
|
||||||
'k': "stack trace",
|
'int [#]': "request interrupt",
|
||||||
"ln": "list nearest symbol(s)",
|
'k': "stack trace",
|
||||||
'm': "messages",
|
"ln": "list nearest symbol(s)",
|
||||||
'o [#]': "output port #",
|
'm': "messages",
|
||||||
'p': "step over", // other variations: pr (step and dump registers)
|
'o [#]': "output port #",
|
||||||
'print': "print expression",
|
'p': "step over", // other variations: pr (step and dump registers)
|
||||||
'r': "dump/set registers",
|
'print': "print expression",
|
||||||
'reset': "reset machine",
|
'r': "dump/set registers",
|
||||||
's': "set options",
|
'reset': "reset machine",
|
||||||
't [#]': "trace", // other variations: tr (trace and dump registers)
|
's': "set options",
|
||||||
'u [#]': "unassemble",
|
't [#]': "trace", // other variations: tr (trace and dump registers)
|
||||||
'v': "print version",
|
'u [#]': "unassemble",
|
||||||
'var': "assign variable"
|
'v': "print version",
|
||||||
|
'var': "assign variable"
|
||||||
};
|
};
|
||||||
|
|
||||||
Debugger.STYLE_8080 = 8080;
|
Debugger.STYLE_8080 = 8080;
|
||||||
|
|
@ -3288,7 +3289,7 @@ if (DEBUGGER) {
|
||||||
{
|
{
|
||||||
var s = "commands:";
|
var s = "commands:";
|
||||||
for (var sCommand in Debugger.COMMANDS) {
|
for (var sCommand in Debugger.COMMANDS) {
|
||||||
s += '\n' + str.pad(sCommand, 7) + Debugger.COMMANDS[sCommand];
|
s += '\n' + str.pad(sCommand, 9) + Debugger.COMMANDS[sCommand];
|
||||||
}
|
}
|
||||||
if (!this.checksEnabled()) s += "\nnote: frequency/history disabled if no exec breakpoints";
|
if (!this.checksEnabled()) s += "\nnote: frequency/history disabled if no exec breakpoints";
|
||||||
this.println(s);
|
this.println(s);
|
||||||
|
|
@ -3799,6 +3800,26 @@ if (DEBUGGER) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* doInt(sLevel)
|
||||||
|
*
|
||||||
|
* @this {Debugger}
|
||||||
|
* @param {string} sLevel
|
||||||
|
* @return {boolean} true if success, false if error
|
||||||
|
*/
|
||||||
|
Debugger.prototype.doInt = function(sLevel)
|
||||||
|
{
|
||||||
|
if (!this.cpu.getIF()) {
|
||||||
|
this.println("interrupts disabled (use rif=1 to enable)");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
var nLevel = this.parseExpression(sLevel);
|
||||||
|
if (nLevel == null) return false;
|
||||||
|
this.println("requesting interrupt level " + nLevel);
|
||||||
|
this.cpu.requestINTR(nLevel);
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* doVar(sCmd)
|
* doVar(sCmd)
|
||||||
*
|
*
|
||||||
|
|
@ -4686,6 +4707,12 @@ if (DEBUGGER) {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (asArgs[0] == "int") {
|
||||||
|
if (!this.doInt(asArgs[1])) {
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
this.doInput(asArgs[1]);
|
this.doInput(asArgs[1]);
|
||||||
break;
|
break;
|
||||||
case 'k':
|
case 'k':
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue