mirror of
https://github.com/trebonian/visual6502.git
synced 2025-02-06 22:30:02 +00:00
272 lines
8.4 KiB
JavaScript
272 lines
8.4 KiB
JavaScript
// chip-specific support functions
|
|
//
|
|
// may override function definitions made previously
|
|
|
|
chipname='z80';
|
|
|
|
// DMB: Update this
|
|
grChipSize=7000;
|
|
|
|
ngnd = nodenames['vss'];
|
|
npwr = nodenames['vcc'];
|
|
|
|
nodenamereset = '_reset';
|
|
|
|
presetLogLists=[
|
|
['cycle',],
|
|
['ab','db','_m1','_rd','_wr','_mreq','_iorq','pc'],
|
|
['af', 'bc', 'de', 'hl', 'ix', 'iy', 'sp', 'wz', 'ir'],
|
|
['State'],
|
|
['_int','_nmi',nodenamereset],
|
|
];
|
|
|
|
function setupTransistors(){
|
|
for(i in transdefs){
|
|
var tdef = transdefs[i];
|
|
var name = tdef[0];
|
|
var gate = tdef[1];
|
|
var c1 = tdef[2];
|
|
var c2 = tdef[3];
|
|
var bb = tdef[4];
|
|
if(tdef[6])
|
|
// just ignore all the 'weak' transistors for now
|
|
continue;
|
|
if(c1==ngnd) {c1=c2;c2=ngnd;}
|
|
if(c1==npwr) {c1=c2;c2=npwr;}
|
|
var trans = {name: name, on: false, gate: gate, c1: c1, c2: c2, bb: bb};
|
|
nodes[gate].gates.push(trans);
|
|
nodes[c1].c1c2s.push(trans);
|
|
nodes[c2].c1c2s.push(trans);
|
|
transistors[name] = trans;
|
|
}
|
|
}
|
|
|
|
// simulate a single clock phase with no update to graphics or trace
|
|
function halfStep(){
|
|
var clk = isNodeHigh(nodenames['clk']);
|
|
eval(clockTriggers[cycle]);
|
|
if (clk) {setLow('clk'); }
|
|
else {setHigh('clk'); }
|
|
// DMB: It's almost certainly wrong to execute the on both clock edges
|
|
handleBusRead();
|
|
handleBusWrite;
|
|
}
|
|
|
|
function goUntilSyncOrWrite(){
|
|
halfStep();
|
|
cycle++;
|
|
while(
|
|
!isNodeHigh(nodenames['clk']) ||
|
|
( isNodeHigh(nodenames['_m1']) && isNodeHigh(nodenames['_wr']) )
|
|
) {
|
|
halfStep();
|
|
cycle++;
|
|
}
|
|
chipStatus();
|
|
}
|
|
|
|
function initChip(){
|
|
var start = now();
|
|
for(var nn in nodes) {
|
|
nodes[nn].state = false;
|
|
nodes[nn].float = true;
|
|
}
|
|
|
|
nodes[ngnd].state = false;
|
|
nodes[ngnd].float = false;
|
|
nodes[npwr].state = true;
|
|
nodes[npwr].float = false;
|
|
for(var tn in transistors) transistors[tn].on = false;
|
|
setLow(nodenamereset);
|
|
setLow('clk');
|
|
setHigh('_busrq');
|
|
setHigh('_int');
|
|
setHigh('_nmi');
|
|
setHigh('_wait');
|
|
recalcNodeList(allNodes());
|
|
// DMB: Not sure why the 6800 sim did something like this
|
|
//for(var i=0;i<8;i++){
|
|
// setHigh('clk');
|
|
// setLow('clk');
|
|
//}
|
|
for(var i=0;i<31;i++){halfStep();} // avoid updating graphics and trace buffer before user code
|
|
setHigh(nodenamereset);
|
|
refresh();
|
|
cycle = 0;
|
|
trace = Array();
|
|
if(typeof expertMode != "undefined")
|
|
updateLogList();
|
|
chipStatus();
|
|
if(ctrace)console.log('initChip done after', now()-start);
|
|
}
|
|
|
|
function handleBusRead(){
|
|
if(!isNodeHigh(nodenames['_rd'])){
|
|
var a = readAddressBus();
|
|
var d = eval(readTriggers[a]);
|
|
if(d == undefined)
|
|
d = mRead(readAddressBus());
|
|
if(!isNodeHigh(nodenames['_m1']))
|
|
eval(fetchTriggers[d]);
|
|
writeDataBus(d);
|
|
}
|
|
}
|
|
|
|
|
|
function handleBusWrite(){
|
|
if(!isNodeHigh(nodenames['_wr'])){
|
|
var a = readAddressBus();
|
|
var d = readDataBus();
|
|
eval(writeTriggers[a]);
|
|
mWrite(a,d);
|
|
if(a<0x200) setCellValue(a,d);
|
|
}
|
|
}
|
|
|
|
function readA(){return 0xFF ^ readBits('reg_a', 8);}
|
|
function readF(){return 0xFF ^ readBits('reg_f', 8);}
|
|
function readB(){return 0xFF ^ readBits('reg_b', 8);}
|
|
function readC(){return 0xFF ^ readBits('reg_c', 8);}
|
|
function readD(){return 0xFF ^ readBits('reg_d', 8);}
|
|
function readE(){return 0xFF ^ readBits('reg_e', 8);}
|
|
function readH(){return 0xFF ^ readBits('reg_h', 8);}
|
|
function readL(){return 0xFF ^ readBits('reg_l', 8);}
|
|
function readI(){return 0xFF ^ readBits('reg_i', 8);}
|
|
function readR(){return 0xFF ^ readBits('reg_r', 8);}
|
|
function readW(){return 0xFF ^ readBits('reg_w', 8);}
|
|
function readZ(){return 0xFF ^ readBits('reg_z', 8);}
|
|
|
|
function readIX(){return 0xFFFF ^ ((readBits('reg_ixh', 8)<<8) + readBits('reg_ixl', 8));}
|
|
function readIY(){return 0xFFFF ^ ((readBits('reg_iyh', 8)<<8) + readBits('reg_iyl', 8));}
|
|
function readSP(){return 0xFFFF ^ ((readBits('reg_sph', 8)<<8) + readBits('reg_spl', 8));}
|
|
function readPC(){return 0xFFFF ^ ((readBits('reg_pch', 8)<<8) + readBits('reg_pcl', 8));}
|
|
function readPCL(){return 0xFF ^ readBits('reg_pcl', 8);}
|
|
function readPCH(){return 0xFF ^ readBits('reg_pch', 8);}
|
|
|
|
// The 6800 state control is something like a branching shift register
|
|
// ... but not quite like that
|
|
TCStates=[
|
|
"m1", "m2", "m3", "m4", "m5",
|
|
"t1", "t2", "t3", "t4", "t5", "t6",
|
|
];
|
|
|
|
function listActiveTCStates() {
|
|
var s=[];
|
|
for(var i=0;i<TCStates.length;i++){
|
|
var t=TCStates[i];
|
|
if (isNodeHigh(nodenames[t])) s.push(t.slice(0,3));
|
|
}
|
|
return s.join(" ");
|
|
}
|
|
|
|
function busToHexInv(busname){
|
|
var value=busToHex(busname)
|
|
if (typeof value != "undefined")
|
|
return value.replace(/./g,function(x){return (15-parseInt(x,16)).toString(16)});
|
|
else
|
|
return undefined;;
|
|
}
|
|
|
|
function busToString(busname){
|
|
// takes a signal name or prefix
|
|
// returns an appropriate string representation
|
|
// some 'signal names' are CPU-specific aliases to user-friendly string output
|
|
if(busname=='cycle')
|
|
return cycle>>1;
|
|
if(busname=='af')
|
|
return busToHexInv('reg_a') + busToHexInv('reg_f');
|
|
if(busname=='bc')
|
|
return busToHexInv('reg_b') + busToHexInv('reg_c');
|
|
if(busname=='de')
|
|
return busToHexInv('reg_d') + busToHexInv('reg_e');
|
|
if(busname=='hl')
|
|
return busToHexInv('reg_h') + busToHexInv('reg_l');
|
|
if(busname=='ir')
|
|
return busToHexInv('reg_i') + busToHexInv('reg_r');
|
|
if(busname=='wz')
|
|
return busToHexInv('reg_w') + busToHexInv('reg_z');
|
|
if(busname=='pc')
|
|
return busToHexInv('reg_pch') + busToHexInv('reg_pcl');
|
|
if(busname=='sp')
|
|
return busToHexInv('reg_sph') + busToHexInv('reg_spl');
|
|
if(busname=='ix')
|
|
return busToHexInv('reg_ixh') + busToHexInv('reg_ixl');
|
|
if(busname=='iy')
|
|
return busToHexInv('reg_iyh') + busToHexInv('reg_iyl');
|
|
if(busname=='State')
|
|
return listActiveTCStates();
|
|
// DMB: TODO
|
|
// if(busname=='Execute')
|
|
// return disassemblytoHTML(readBits('ir',8));
|
|
// if(busname=='Fetch')
|
|
// return !isNodeHigh(nodenames['_m1'])?disassemblytoHTML(readDataBus()):"";
|
|
// if(busname=='plaOutputs')
|
|
// // PLA outputs are mostly ^op- but some have a prefix too
|
|
// // - we'll allow the x and xx prefix but ignore the #
|
|
// return listActiveSignals('^([x]?x-)?op-');
|
|
// if(busname=='DPControl')
|
|
// return listActiveSignals('^dpc[0-9]+_');
|
|
if(busname[0]=="-"){
|
|
// invert the value of the bus for display
|
|
var value=busToHex(busname.slice(1))
|
|
if(typeof value != "undefined")
|
|
return value.replace(/./g,function(x){return (15-parseInt(x,16)).toString(16)});
|
|
else
|
|
return undefined;;
|
|
} else {
|
|
return busToHex(busname);
|
|
}
|
|
}
|
|
|
|
function chipStatus(){
|
|
var ab = readAddressBus();
|
|
var machine1 =
|
|
' halfcyc:' + cycle +
|
|
' clk:' + readBit('clk') +
|
|
' AB:' + hexWord(ab) +
|
|
' D:' + hexByte(readDataBus()) +
|
|
' M1:' + readBit('_m1') +
|
|
' RD:' + readBit('_rd') +
|
|
' WR:' + readBit('_wr') +
|
|
' MREQ:' + readBit('_mreq') +
|
|
' IORQ:' + readBit('_iorq');
|
|
var machine2 =
|
|
' PC:' + hexWord(readPC()) +
|
|
' A:' + hexByte(readA()) +
|
|
' F:' + hexByte(readF()) +
|
|
' B:' + hexByte(readB()) +
|
|
' C:' + hexByte(readC()) +
|
|
' D:' + hexByte(readD()) +
|
|
' E:' + hexByte(readE()) +
|
|
' H:' + hexByte(readH()) +
|
|
' L:' + hexByte(readL()) +
|
|
' I:' + hexByte(readI()) +
|
|
' R:' + hexByte(readR()) +
|
|
' W:' + hexByte(readW()) +
|
|
' Z:' + hexByte(readZ()) +
|
|
' IX:' + hexWord(readIX()) +
|
|
' IY:' + hexWord(readIY()) +
|
|
' SP:' + hexWord(readSP());
|
|
var machine3 =
|
|
'State: ' + busToString('State') +
|
|
'Hz: ' + estimatedHz().toFixed(1);
|
|
if(typeof expertMode != "undefined") {
|
|
machine3 += ' Exec: ' + busToString('Execute'); // no T-state info for 6800 yet
|
|
if(!isNodeHigh(nodenames['_m1']))
|
|
machine3 += ' (Fetch: ' + busToString('Fetch') + ')';
|
|
if(goldenChecksum != undefined)
|
|
machine3 += " Chk:" + traceChecksum + ((traceChecksum==goldenChecksum)?" OK":" no match");
|
|
}
|
|
|
|
setStatus(machine1, machine2, machine3);
|
|
if (logThese.length>1) {
|
|
updateLogbox(logThese);
|
|
}
|
|
selectCell(ab);
|
|
}
|
|
|
|
// DMB: TODO
|
|
var disassembly={
|
|
0x00: "nop",
|
|
};
|