2017-01-13 02:21:35 +00:00
|
|
|
<!DOCTYPE HTML>
|
|
|
|
<!--
|
|
|
|
test.html: Test harness for the JSSpeccy Z80 core
|
2017-01-14 16:14:25 +00:00
|
|
|
|
2017-01-13 02:21:35 +00:00
|
|
|
Copyright (C) 2009 Matthew Westcott
|
2017-01-14 16:14:25 +00:00
|
|
|
|
2017-01-13 02:21:35 +00:00
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
2017-01-14 16:14:25 +00:00
|
|
|
|
2017-01-13 02:21:35 +00:00
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
2017-01-14 16:14:25 +00:00
|
|
|
|
2017-01-13 02:21:35 +00:00
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
2017-01-14 16:14:25 +00:00
|
|
|
|
2017-01-13 02:21:35 +00:00
|
|
|
Contact details: <matthew@west.co.tt>
|
|
|
|
Matthew Westcott, 14 Daisy Hill Drive, Adlington, Chorley, Lancs PR6 9NE UNITED KINGDOM
|
|
|
|
-->
|
|
|
|
<html>
|
|
|
|
<head>
|
|
|
|
<title>jsspeccy test</title>
|
|
|
|
<script>var global = {}</script>
|
2017-01-14 16:14:25 +00:00
|
|
|
<script src="../../../src/cpu/z80.js"></script>
|
2017-01-13 02:21:35 +00:00
|
|
|
<script type="text/javascript">/* <![CDATA[ */
|
|
|
|
var testInputLines;
|
|
|
|
var currentLine;
|
|
|
|
|
|
|
|
global.buildZ80({
|
|
|
|
applyContention: true
|
|
|
|
});
|
|
|
|
|
|
|
|
var Memory = function() {
|
|
|
|
var self = {};
|
|
|
|
|
|
|
|
var mem;
|
|
|
|
var initialMem;
|
|
|
|
|
|
|
|
self.clear = function() {
|
|
|
|
mem = new Uint8Array(0x10000);
|
|
|
|
for (var i = 0; i < 0x10000; i += 4) {
|
|
|
|
mem[i] = 0xde; mem[i+1] = 0xad; mem[i+2] = 0xbe; mem[i+3] = 0xef;
|
|
|
|
}
|
|
|
|
initialMem = new Uint8Array(0x10000);
|
|
|
|
for (var i = 0; i < 0x10000; i += 4) {
|
|
|
|
initialMem[i] = 0xde; initialMem[i+1] = 0xad; initialMem[i+2] = 0xbe; initialMem[i+3] = 0xef;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
self.isContended = function(addr) {
|
|
|
|
return ((addr & 0xc000) == 0x4000);
|
|
|
|
}
|
|
|
|
|
|
|
|
self.contend = function(addr, tstate) {
|
|
|
|
if (self.oncontend) self.oncontend(addr);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
self.read = function(addr) {
|
|
|
|
var val = mem[addr];
|
|
|
|
if (self.onread) self.onread(addr, val);
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
self.write = function(addr, val) {
|
|
|
|
mem[addr] = val;
|
|
|
|
if (self.onwrite) self.onwrite(addr, val);
|
|
|
|
}
|
|
|
|
self.initialWrite = function(addr, val) {
|
|
|
|
mem[addr] = val;
|
|
|
|
initialMem[addr] = val;
|
|
|
|
}
|
|
|
|
self.dump = function() {
|
|
|
|
for (i = 0; i < mem.length; i++) {
|
|
|
|
if((initialMem[i]) != (mem[i])) {
|
|
|
|
var changeReport = hexWord(i);
|
|
|
|
while ((initialMem[i]) != (mem[i]) && i < mem.length) {
|
|
|
|
changeReport += ' ' + hexByte(mem[i]);
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
dump(changeReport + ' -1');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
var IOBus = function() {
|
|
|
|
var self = {};
|
|
|
|
|
|
|
|
self.read = function(addr) {
|
|
|
|
var val = addr >> 8;
|
|
|
|
if (self.onread) self.onread(addr, val);
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
self.write = function(addr, val) {
|
|
|
|
if (self.onwrite) self.onwrite(addr, val);
|
|
|
|
}
|
|
|
|
self.isULAPort = function(addr) {
|
|
|
|
return ((addr & 0x0001) == 0x0000);
|
|
|
|
}
|
|
|
|
self.contend = function(addr) {
|
|
|
|
if (self.oncontend) self.oncontend(addr);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
memory = Memory();
|
|
|
|
ioBus = IOBus();
|
|
|
|
z80 = global.Z80({
|
|
|
|
display: {},
|
|
|
|
memory: memory,
|
|
|
|
ioBus: ioBus
|
|
|
|
});
|
|
|
|
memory.oncontend = function(addr) {
|
|
|
|
dump((' ' + z80.getTstates()).substr(-5) + ' MC ' + hexWord(addr));
|
|
|
|
}
|
|
|
|
memory.onread = function(addr, val) {
|
|
|
|
dump((' ' + z80.getTstates()).substr(-5) + ' MR ' + hexWord(addr) + ' ' + hexByte(val));
|
|
|
|
}
|
|
|
|
memory.onwrite = function(addr, val) {
|
|
|
|
dump((' ' + z80.getTstates()).substr(-5) + ' MW ' + hexWord(addr) + ' ' + hexByte(val));
|
|
|
|
}
|
|
|
|
ioBus.onread = function(addr, val) {
|
|
|
|
dump((' ' + z80.getTstates()).substr(-5) + ' PR ' + hexWord(addr) + ' ' + hexByte(val));
|
|
|
|
}
|
|
|
|
ioBus.onwrite = function(addr, val) {
|
|
|
|
dump((' ' + z80.getTstates()).substr(-5) + ' PW ' + hexWord(addr) + ' ' + hexByte(val));
|
|
|
|
}
|
|
|
|
ioBus.oncontend = function(addr) {
|
|
|
|
dump((' ' + z80.getTstates()).substr(-5) + ' PC ' + hexWord(addr));
|
|
|
|
}
|
|
|
|
|
|
|
|
function runTests() {
|
|
|
|
testInput = document.getElementById('test_in').value;
|
|
|
|
testInputLines = testInput.split(/\n/);
|
|
|
|
currentLine = 0;
|
|
|
|
document.getElementById('test_out').value = '';
|
|
|
|
while (!eof()) {
|
|
|
|
/* skip past all blank lines and consume the first non-blank line */
|
|
|
|
if ((name = readLine()) == '') continue;
|
|
|
|
dump(name);
|
|
|
|
var mainRegs = readLine().split(/\s+/); /* AF BC DE HL AF' BC' DE' HL' IX IY SP PC */
|
|
|
|
var af = parseInt(mainRegs[0], 16); z80.setAF(af);
|
|
|
|
var bc = parseInt(mainRegs[1], 16); z80.setBC(bc);
|
|
|
|
var de = parseInt(mainRegs[2], 16); z80.setDE(de);
|
|
|
|
var hl = parseInt(mainRegs[3], 16); z80.setHL(hl);
|
|
|
|
var af_ = parseInt(mainRegs[4], 16); z80.setAF_(af_);
|
|
|
|
var bc_ = parseInt(mainRegs[5], 16); z80.setBC_(bc_);
|
|
|
|
var de_ = parseInt(mainRegs[6], 16); z80.setDE_(de_);
|
|
|
|
var hl_ = parseInt(mainRegs[7], 16); z80.setHL_(hl_);
|
|
|
|
var ix = parseInt(mainRegs[8], 16); z80.setIX(ix);
|
|
|
|
var iy = parseInt(mainRegs[9], 16); z80.setIY(iy);
|
|
|
|
z80.setSP(parseInt(mainRegs[10], 16));
|
|
|
|
z80.setPC(parseInt(mainRegs[11], 16));
|
|
|
|
var otherRegs = readLine().split(/\s+/); /* I R IFF1 IFF2 IM <halted> <tstates> */
|
|
|
|
z80.setI(parseInt(otherRegs[0], 16));
|
|
|
|
z80.setR(parseInt(otherRegs[1], 16));
|
|
|
|
z80.setIFF1(parseInt(otherRegs[2], 16));
|
|
|
|
z80.setIFF2(parseInt(otherRegs[3], 16));
|
|
|
|
z80.setIM(parseInt(otherRegs[4], 16));
|
|
|
|
z80.setHalted(otherRegs[5] == '1');
|
|
|
|
var runTime = parseInt(otherRegs[6]);
|
|
|
|
|
|
|
|
memory.clear();
|
|
|
|
|
|
|
|
while ((memLine = readLine()) != '-1') {
|
|
|
|
var memWrites = memLine.split(/\s+/);
|
|
|
|
var addr = parseInt(memWrites.shift(), 16);
|
|
|
|
for (var i = 0; i < memWrites.length; i++) {
|
|
|
|
var byte = memWrites[i];
|
|
|
|
if (byte != '-1') {
|
|
|
|
memory.initialWrite(addr++, parseInt(byte, 16));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
z80.setTstates(0);
|
|
|
|
z80.runFrame(runTime);
|
|
|
|
|
|
|
|
/* AF BC DE HL AF' BC' DE' HL' IX IY SP PC */
|
|
|
|
dump(
|
|
|
|
hexWord(z80.getAF()) + ' '
|
|
|
|
+ hexWord(z80.getBC()) + ' '
|
|
|
|
+ hexWord(z80.getDE()) + ' '
|
|
|
|
+ hexWord(z80.getHL()) + ' '
|
|
|
|
+ hexWord(z80.getAF_()) + ' '
|
|
|
|
+ hexWord(z80.getBC_()) + ' '
|
|
|
|
+ hexWord(z80.getDE_()) + ' '
|
|
|
|
+ hexWord(z80.getHL_()) + ' '
|
|
|
|
+ hexWord(z80.getIX()) + ' '
|
|
|
|
+ hexWord(z80.getIY()) + ' '
|
|
|
|
+ hexWord(z80.getSP()) + ' '
|
|
|
|
+ hexWord(z80.getPC()) + ' '
|
|
|
|
);
|
|
|
|
/* I R IFF1 IFF2 IM <halted> <tstates> */
|
|
|
|
dump(
|
|
|
|
hexByte(z80.getI()) + ' ' + hexByte(z80.getR()) + ' '
|
|
|
|
+ z80.getIFF1() + ' ' + z80.getIFF2() + ' ' + z80.getIM() + ' ' + (z80.getHalted() ? '1' : '0') + ' ' + z80.getTstates()
|
|
|
|
)
|
|
|
|
/* dump memory state */
|
|
|
|
memory.dump();
|
|
|
|
dump('');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
function eof() {
|
|
|
|
return (currentLine >= testInputLines.length);
|
|
|
|
}
|
|
|
|
function readLine() {
|
|
|
|
return testInputLines[currentLine++];
|
|
|
|
}
|
|
|
|
function dump(line) {
|
|
|
|
document.getElementById('test_out').value += (line + "\n");
|
|
|
|
}
|
|
|
|
function hexByte(num) {
|
|
|
|
return ('00' + num.toString(16)).substr(-2);
|
|
|
|
}
|
|
|
|
function hexWord(num) {
|
|
|
|
return ('0000' + num.toString(16)).substr(-4);
|
|
|
|
}
|
|
|
|
|
|
|
|
window.onload = function() {
|
|
|
|
var request = new XMLHttpRequest();
|
|
|
|
request.addEventListener('load', function(e) {
|
|
|
|
data = request.response;
|
|
|
|
document.getElementById('test_in').value = data;
|
|
|
|
});
|
|
|
|
request.open('GET', 'tests.in', true);
|
|
|
|
request.send();
|
|
|
|
}
|
|
|
|
/* ]]> */</script>
|
|
|
|
</head>
|
|
|
|
<body>
|
|
|
|
<textarea rows="24" cols="80" id="test_in"></textarea>
|
|
|
|
<textarea rows="24" cols="80" id="test_out"></textarea>
|
|
|
|
<input type="button" value="run tests" onclick="runTests()" />
|
|
|
|
</body>
|
|
|
|
</html>
|