2010-09-18 17:12:28 +00:00
|
|
|
/*
|
2010-11-22 12:22:36 +00:00
|
|
|
Copyright (c) 2010 Brian Silverman, Barry Silverman, Ed Spittles, Achim Breidenbach
|
2010-09-18 17:12:28 +00:00
|
|
|
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
of this software and associated documentation files (the "Software"), to deal
|
|
|
|
in the Software without restriction, including without limitation the rights
|
|
|
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
|
|
copies of the Software, and to permit persons to whom the Software is
|
|
|
|
furnished to do so, subject to the following conditions:
|
|
|
|
|
|
|
|
The above copyright notice and this permission notice shall be included in
|
|
|
|
all copies or substantial portions of the Software.
|
|
|
|
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
|
|
THE SOFTWARE.
|
|
|
|
*/
|
|
|
|
|
|
|
|
var memory = Array();
|
|
|
|
var cycle = 0;
|
|
|
|
var trace = Array();
|
2010-09-25 21:32:29 +00:00
|
|
|
var logstream = Array();
|
2010-09-18 17:12:28 +00:00
|
|
|
var running = false;
|
2010-11-01 19:36:52 +00:00
|
|
|
var logThese=[];
|
2011-04-01 11:17:34 +00:00
|
|
|
var chipname='6502';
|
|
|
|
var nodenamereset='res';
|
2010-11-01 19:36:52 +00:00
|
|
|
var presetLogLists=[
|
|
|
|
['cycle'],
|
2010-11-22 13:27:26 +00:00
|
|
|
['ab','db','rw','Fetch','pc','a','x','y','s','p'],
|
|
|
|
['Execute','State'],
|
2010-11-19 21:49:16 +00:00
|
|
|
['ir','tcstate','-pd'],
|
2010-11-01 19:36:52 +00:00
|
|
|
['adl','adh','sb','alu'],
|
|
|
|
['alucin','alua','alub','alucout','aluvout','dasb'],
|
2010-11-22 13:27:26 +00:00
|
|
|
['plaOutputs','DPControl'],
|
2010-11-01 19:36:52 +00:00
|
|
|
['idb','dor'],
|
2011-04-01 11:17:34 +00:00
|
|
|
['irq','nmi',nodenamereset],
|
2010-11-01 19:36:52 +00:00
|
|
|
];
|
2010-09-18 17:12:28 +00:00
|
|
|
|
2010-10-01 18:39:33 +00:00
|
|
|
function loadProgram(){
|
2010-10-06 19:51:57 +00:00
|
|
|
// a moderate size of static testprogram might be loaded
|
|
|
|
if(testprogram.length!=0 && testprogramAddress != undefined)
|
|
|
|
for(var i=0;testprogram[i]!=undefined;i++){
|
|
|
|
var a=testprogramAddress+i;
|
|
|
|
mWrite(a, testprogram[i]);
|
|
|
|
if(a<0x200)
|
|
|
|
setCellValue(a, testprogram[i]);
|
|
|
|
}
|
|
|
|
// a small test program or patch might be passed in the URL
|
2010-10-01 18:39:33 +00:00
|
|
|
if(userCode.length!=0)
|
2010-10-06 19:51:57 +00:00
|
|
|
for(var i=0;i<userCode.length;i++){
|
|
|
|
if(userCode[i] != undefined){
|
|
|
|
mWrite(i, userCode[i]);
|
|
|
|
if(i<0x200)
|
|
|
|
setCellValue(i, userCode[i]);
|
|
|
|
}
|
|
|
|
}
|
2010-10-01 18:39:33 +00:00
|
|
|
// default reset vector will be 0x0000 because undefined memory reads as zero
|
|
|
|
if(userResetLow!=undefined)
|
|
|
|
mWrite(0xfffc, userResetLow);
|
|
|
|
if(userResetHigh!=undefined)
|
|
|
|
mWrite(0xfffd, userResetHigh);
|
2010-09-18 17:12:28 +00:00
|
|
|
}
|
|
|
|
|
2010-10-01 18:39:33 +00:00
|
|
|
function go(){
|
2010-10-30 18:05:29 +00:00
|
|
|
if(typeof userSteps != "undefined"){
|
2010-10-30 16:16:54 +00:00
|
|
|
if(--userSteps==0){
|
|
|
|
running=false;
|
|
|
|
userSteps=undefined;
|
|
|
|
}
|
|
|
|
}
|
2010-09-18 17:46:24 +00:00
|
|
|
if(running) {
|
|
|
|
step();
|
2010-10-01 18:39:33 +00:00
|
|
|
setTimeout(go, 0); // schedule the next poll
|
2010-09-18 17:46:24 +00:00
|
|
|
}
|
2010-09-18 17:12:28 +00:00
|
|
|
}
|
|
|
|
|
2010-10-06 20:59:43 +00:00
|
|
|
function goUntilSync(){
|
|
|
|
halfStep();
|
|
|
|
while(!isNodeHigh(nodenames['sync']) || isNodeHigh(nodenames['clk0']))
|
|
|
|
halfStep();
|
|
|
|
}
|
|
|
|
|
|
|
|
function goUntilSyncOrWrite(){
|
|
|
|
halfStep();
|
2010-11-01 18:02:52 +00:00
|
|
|
cycle++;
|
2010-10-06 20:59:43 +00:00
|
|
|
while(
|
2010-11-01 18:02:52 +00:00
|
|
|
!isNodeHigh(nodenames['clk0']) ||
|
|
|
|
( !isNodeHigh(nodenames['sync']) && isNodeHigh(nodenames['rw']) )
|
|
|
|
) {
|
2010-10-06 20:59:43 +00:00
|
|
|
halfStep();
|
2010-11-01 18:02:52 +00:00
|
|
|
cycle++;
|
|
|
|
}
|
|
|
|
chipStatus();
|
2010-10-06 20:59:43 +00:00
|
|
|
}
|
|
|
|
|
2010-09-18 17:46:24 +00:00
|
|
|
function testNMI(n){
|
|
|
|
initChip();
|
|
|
|
|
|
|
|
mWrite(0x0000, 0x38); // set carry
|
|
|
|
mWrite(0x0001, 0x4c); // jump to test code
|
|
|
|
mWrite(0x0002, 0x06);
|
|
|
|
mWrite(0x0003, 0x23);
|
|
|
|
|
|
|
|
mWrite(0x22ff, 0x38); // set carry
|
|
|
|
mWrite(0x2300, 0xea);
|
|
|
|
mWrite(0x2301, 0xea);
|
|
|
|
mWrite(0x2302, 0xea);
|
|
|
|
mWrite(0x2303, 0xea);
|
|
|
|
mWrite(0x2304, 0xb0); // branch carry set to self
|
|
|
|
mWrite(0x2305, 0xfe);
|
|
|
|
|
|
|
|
mWrite(0x2306, 0xb0); // branch carry set to self
|
|
|
|
mWrite(0x2307, 0x01);
|
|
|
|
mWrite(0x2308, 0x00); // brk should be skipped
|
|
|
|
mWrite(0x2309, 0xa9); // anything
|
|
|
|
mWrite(0x230a, 0xde); // anything
|
|
|
|
mWrite(0x230b, 0xb0); // branch back with page crossing
|
|
|
|
mWrite(0x230c, 0xf2);
|
|
|
|
|
|
|
|
mWrite(0xc018, 0x40); // nmi handler
|
|
|
|
|
|
|
|
mWrite(0xfffa, 0x18); // nmi vector
|
|
|
|
mWrite(0xfffb, 0xc0);
|
|
|
|
mWrite(0xfffc, 0x00); // reset vector
|
|
|
|
mWrite(0xfffd, 0x00);
|
|
|
|
|
|
|
|
for(var i=0;i<n;i++){step();}
|
|
|
|
setLow('nmi');
|
|
|
|
chipStatus();
|
|
|
|
for(var i=0;i<8;i++){step();}
|
|
|
|
setHigh('nmi');
|
|
|
|
chipStatus();
|
|
|
|
for(var i=0;i<16;i++){step();}
|
|
|
|
}
|
|
|
|
|
2010-09-18 17:12:28 +00:00
|
|
|
function initChip(){
|
2010-09-18 17:46:24 +00:00
|
|
|
var start = now();
|
2010-10-13 21:53:40 +00:00
|
|
|
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;
|
2010-09-18 17:12:28 +00:00
|
|
|
for(var tn in transistors) transistors[tn].on = false;
|
2011-04-01 11:17:34 +00:00
|
|
|
setLow(nodenamereset);
|
2010-09-18 17:12:28 +00:00
|
|
|
setLow('clk0');
|
|
|
|
setHigh('rdy'); setLow('so');
|
|
|
|
setHigh('irq'); setHigh('nmi');
|
|
|
|
recalcNodeList(allNodes());
|
|
|
|
for(var i=0;i<8;i++){setHigh('clk0'), setLow('clk0');}
|
2011-04-01 11:17:34 +00:00
|
|
|
setHigh(nodenamereset);
|
2010-10-01 18:39:33 +00:00
|
|
|
for(var i=0;i<18;i++){halfStep();} // avoid updating graphics and trace buffer before user code
|
2010-09-18 17:12:28 +00:00
|
|
|
refresh();
|
|
|
|
cycle = 0;
|
|
|
|
trace = Array();
|
2010-11-08 09:03:13 +00:00
|
|
|
if(typeof expertMode != "undefined")
|
|
|
|
updateLogList();
|
2010-09-18 17:12:28 +00:00
|
|
|
chipStatus();
|
2010-09-19 07:02:26 +00:00
|
|
|
if(ctrace)console.log('initChip done after', now()-start);
|
2010-09-18 17:12:28 +00:00
|
|
|
}
|
|
|
|
|
2010-09-27 17:25:14 +00:00
|
|
|
function signalSet(n){
|
|
|
|
var signals=[];
|
2010-11-01 19:36:52 +00:00
|
|
|
for (var i=0; (i<=n)&&(i<presetLogLists.length) ; i++){
|
|
|
|
for (var j=0; j<presetLogLists[i].length; j++){
|
|
|
|
signals.push(presetLogLists[i][j]);
|
2010-09-27 17:25:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return signals;
|
|
|
|
}
|
2010-09-25 21:32:29 +00:00
|
|
|
|
2010-11-06 17:55:36 +00:00
|
|
|
function updateLogList(names){
|
2010-11-01 19:36:52 +00:00
|
|
|
// user supplied a list of signals, which we append to the set defined by loglevel
|
|
|
|
logThese = signalSet(loglevel);
|
2010-11-06 17:55:36 +00:00
|
|
|
if(typeof names == "undefined")
|
|
|
|
// this is a UI call - read the text input
|
|
|
|
names = document.getElementById('LogThese').value;
|
|
|
|
else
|
|
|
|
// this is an URL call - update the text input box
|
|
|
|
document.getElementById('LogThese').value = names;
|
|
|
|
names = names.split(/[\s,]+/);
|
|
|
|
for(var i=0;i<names.length;i++){
|
2010-11-05 19:02:41 +00:00
|
|
|
// could be a signal name, a node number, or a special name
|
2010-11-06 17:55:36 +00:00
|
|
|
if(typeof busToString(names[i]) != "undefined")
|
|
|
|
logThese.push(names[i]);
|
2010-11-01 19:36:52 +00:00
|
|
|
}
|
|
|
|
initLogbox(logThese);
|
|
|
|
}
|
|
|
|
|
2010-10-05 19:14:08 +00:00
|
|
|
var traceChecksum='';
|
|
|
|
var goldenChecksum;
|
|
|
|
|
2010-09-27 17:25:14 +00:00
|
|
|
// simulate a single clock phase, updating trace and highlighting layout
|
2010-09-18 17:12:28 +00:00
|
|
|
function step(){
|
2010-10-05 19:14:08 +00:00
|
|
|
var s=stateString();
|
|
|
|
var m=getMem();
|
|
|
|
trace[cycle]= {chip: s, mem: m};
|
|
|
|
if(goldenChecksum != undefined)
|
|
|
|
traceChecksum=adler32(traceChecksum+s+m.slice(0,511).toString(16));
|
2010-09-18 17:12:28 +00:00
|
|
|
halfStep();
|
2010-10-01 13:02:03 +00:00
|
|
|
if(animateChipLayout)
|
|
|
|
refresh();
|
2010-09-18 17:12:28 +00:00
|
|
|
cycle++;
|
|
|
|
chipStatus();
|
|
|
|
}
|
|
|
|
|
2010-11-06 17:21:50 +00:00
|
|
|
// triggers for breakpoints, watchpoints, input pin events
|
2010-11-08 22:03:47 +00:00
|
|
|
// almost always are undefined when tested, so minimal impact on performance
|
2010-11-06 17:21:50 +00:00
|
|
|
clockTriggers={};
|
2010-11-08 22:03:47 +00:00
|
|
|
writeTriggers={};
|
|
|
|
readTriggers={};
|
|
|
|
fetchTriggers={};
|
|
|
|
|
|
|
|
// example instruction tracing triggers
|
|
|
|
// fetchTriggers[0x20]="console.log('0x'+readAddressBus().toString(16)+': JSR');";
|
|
|
|
// fetchTriggers[0x60]="console.log('0x'+readAddressBus().toString(16)+': RTS');";
|
|
|
|
// fetchTriggers[0x4c]="console.log('0x'+readAddressBus().toString(16)+': JMP');";
|
2010-11-06 17:21:50 +00:00
|
|
|
|
2010-09-27 17:25:14 +00:00
|
|
|
// simulate a single clock phase with no update to graphics or trace
|
2010-09-18 17:12:28 +00:00
|
|
|
function halfStep(){
|
|
|
|
var clk = isNodeHigh(nodenames['clk0']);
|
|
|
|
if (clk) {setLow('clk0'); handleBusRead(); }
|
|
|
|
else {setHigh('clk0'); handleBusWrite();}
|
2013-06-25 20:31:53 +00:00
|
|
|
eval(clockTriggers[cycle+1]); // pre-apply next tick's inputs now, so the updates are displayed
|
|
|
|
|
2010-09-18 17:12:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function handleBusRead(){
|
2010-11-08 22:03:47 +00:00
|
|
|
if(isNodeHigh(nodenames['rw'])){
|
|
|
|
var a = readAddressBus();
|
|
|
|
var d = eval(readTriggers[a]);
|
|
|
|
if(d == undefined)
|
|
|
|
d = mRead(readAddressBus());
|
|
|
|
if(isNodeHigh(nodenames['sync']))
|
|
|
|
eval(fetchTriggers[d]);
|
|
|
|
writeDataBus(d);
|
|
|
|
}
|
2010-09-18 17:12:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function handleBusWrite(){
|
|
|
|
if(!isNodeHigh(nodenames['rw'])){
|
|
|
|
var a = readAddressBus();
|
|
|
|
var d = readDataBus();
|
2010-11-08 22:03:47 +00:00
|
|
|
eval(writeTriggers[a]);
|
2010-09-18 17:12:28 +00:00
|
|
|
mWrite(a,d);
|
|
|
|
if(a<0x200) setCellValue(a,d);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function readAddressBus(){return readBits('ab', 16);}
|
|
|
|
function readDataBus(){return readBits('db', 8);}
|
|
|
|
function readA(){return readBits('a', 8);}
|
|
|
|
function readY(){return readBits('y', 8);}
|
|
|
|
function readX(){return readBits('x', 8);}
|
|
|
|
function readP(){return readBits('p', 8);}
|
2010-09-18 17:46:24 +00:00
|
|
|
function readPstring(){
|
|
|
|
var result;
|
|
|
|
result = (isNodeHigh(nodenames['p7'])?'N':'n') +
|
|
|
|
(isNodeHigh(nodenames['p6'])?'V':'v') +
|
2010-10-05 18:12:44 +00:00
|
|
|
'‑' + // non-breaking hyphen
|
2011-04-01 11:59:22 +00:00
|
|
|
(isNodeHigh(nodenames['p4'])?'B':'b') +
|
2010-09-18 17:46:24 +00:00
|
|
|
(isNodeHigh(nodenames['p3'])?'D':'d') +
|
|
|
|
(isNodeHigh(nodenames['p2'])?'I':'i') +
|
|
|
|
(isNodeHigh(nodenames['p1'])?'Z':'z') +
|
|
|
|
(isNodeHigh(nodenames['p0'])?'C':'c');
|
|
|
|
return result;
|
|
|
|
}
|
2010-09-18 17:12:28 +00:00
|
|
|
function readSP(){return readBits('s', 8);}
|
2010-09-18 17:46:24 +00:00
|
|
|
function readPC(){return (readBits('pch', 8)<<8) + readBits('pcl', 8);}
|
|
|
|
function readPCL(){return readBits('pcl', 8);}
|
|
|
|
function readPCH(){return readBits('pch', 8);}
|
2010-09-18 17:12:28 +00:00
|
|
|
|
2010-11-19 22:42:26 +00:00
|
|
|
// for one-hot or few-hot signal collections we want to list the active ones
|
|
|
|
// and for brevity we remove the common prefix
|
|
|
|
function listActiveSignals(pattern){
|
|
|
|
var r=new RegExp(pattern);
|
|
|
|
var list=[];
|
2010-11-01 17:42:18 +00:00
|
|
|
for(var i in nodenamelist){
|
|
|
|
if(r.test(nodenamelist[i])) {
|
|
|
|
if(isNodeHigh(nodenames[nodenamelist[i]]))
|
2010-11-19 22:42:26 +00:00
|
|
|
// also map hyphen to a non-breaking version
|
|
|
|
list.push(nodenamelist[i].replace(r,'').replace(/-/g,'‑'));
|
2010-11-01 17:42:18 +00:00
|
|
|
}
|
|
|
|
}
|
2010-11-19 22:42:26 +00:00
|
|
|
return list;
|
2010-11-01 17:42:18 +00:00
|
|
|
}
|
|
|
|
|
2010-11-22 12:23:20 +00:00
|
|
|
// The 6502 TCState is almost but not quite an inverted one-hot shift register
|
|
|
|
function listActiveTCStates() {
|
|
|
|
var s=[];
|
|
|
|
if(!isNodeHigh(nodenames['clock1'])) s.push("T0");
|
|
|
|
if(!isNodeHigh(nodenames['clock2'])) s.push("T1");
|
|
|
|
if(!isNodeHigh(nodenames['t2'])) s.push("T2");
|
|
|
|
if(!isNodeHigh(nodenames['t3'])) s.push("T3");
|
|
|
|
if(!isNodeHigh(nodenames['t4'])) s.push("T4");
|
|
|
|
if(!isNodeHigh(nodenames['t5'])) s.push("T5");
|
|
|
|
return s.join("+");
|
|
|
|
}
|
|
|
|
|
2017-09-20 00:01:47 +00:00
|
|
|
// Show all time code node states (active and inactive) in fixed format,
|
Corrected and expanded the time state readout (the "TState" pseudobus).
The occurrences of T6 and T1 have been corrected. T6 now only occurs when a BRK
instruction is executing, it is a synonym for when the VEC1 node is logic high.
T1 now occurs when node 862 is logic high, which drives the SYNC pin, among
other control effects.
Formerly, T1 and T6 were displayed only when all the nodes that affect the PLA
were inactive. Node 1357's state was used in that case to choose between
displaying T1 (1357 high) or T6 (1357 low). That turned out to be incorrect
pair of inferences. The result was that T1 was absent when it should have been
present (when T+ was present without T0), and T6 was present when it should
have been absent (for instructions other than BRK). Among the corrective
changes, node 1357 is no longer consulted.
Expansion of state display adds V0, SD1, and SD2 indications. The last two are
in their own field (an eighth field). V0 is in the seventh field (square
bracketed, the same field occupied by T1 and T6). It is a two-character
representation of node VEC0 being at logic high. VEC0 high causes VEC1 to be
high one cycle later, which is T6. V0 is, like T6, activated only by execution
of a BRK instruction.
SD1 and SD2 are nodes 440 and 1258 respectively, which lie in the RCL block
outside of the timing generation (clock) block. They serve the needs of the
RMW (Read-Modify-Write) instructions for their addressing modes that use
external memory instead of the accumulator.
All of the corrected and new features has increased the total number of
displayed states to 24 from 10. Hopefully, this is the ultimate, final,
most fully comprehensive clock display possible, but we'll see.
2017-12-15 18:47:24 +00:00
|
|
|
// with non-PLA-controlling internal state indication in square
|
|
|
|
// brackets, followed by RCL-resident timing state indication.
|
|
|
|
// ".." for a PLA-controlling node indicates inactive state, "T"* for a
|
|
|
|
// PLA-controlling node indicates active state.
|
|
|
|
// Bracketed codes are one of T1/V0/T6/..
|
|
|
|
// V0 indicates the VEC0 node, T6 is a synonym for the VEC1 node.
|
|
|
|
// The RCL codes are one of SD1/SD2/...
|
2017-10-30 18:08:57 +00:00
|
|
|
// For discussion of this reconstruction, see:
|
|
|
|
// http://visual6502.org/wiki/index.php?title=6502_Timing_States
|
2017-10-28 12:49:46 +00:00
|
|
|
function allTCStates( useHTML )
|
2017-09-20 00:01:47 +00:00
|
|
|
{
|
|
|
|
var s = "";
|
2017-10-09 21:49:53 +00:00
|
|
|
var _spc;
|
2017-10-30 04:49:17 +00:00
|
|
|
useHTML = (typeof useHTML === 'undefined') ? false : useHTML;
|
2017-10-09 21:49:53 +00:00
|
|
|
// Use Non-Breaking Space for presentation in an HTML (browser)
|
|
|
|
// context, else use ASCII space for logging context
|
2017-10-28 12:49:46 +00:00
|
|
|
_spc = useHTML ? ' ' : ' ';
|
Corrected and expanded the time state readout (the "TState" pseudobus).
The occurrences of T6 and T1 have been corrected. T6 now only occurs when a BRK
instruction is executing, it is a synonym for when the VEC1 node is logic high.
T1 now occurs when node 862 is logic high, which drives the SYNC pin, among
other control effects.
Formerly, T1 and T6 were displayed only when all the nodes that affect the PLA
were inactive. Node 1357's state was used in that case to choose between
displaying T1 (1357 high) or T6 (1357 low). That turned out to be incorrect
pair of inferences. The result was that T1 was absent when it should have been
present (when T+ was present without T0), and T6 was present when it should
have been absent (for instructions other than BRK). Among the corrective
changes, node 1357 is no longer consulted.
Expansion of state display adds V0, SD1, and SD2 indications. The last two are
in their own field (an eighth field). V0 is in the seventh field (square
bracketed, the same field occupied by T1 and T6). It is a two-character
representation of node VEC0 being at logic high. VEC0 high causes VEC1 to be
high one cycle later, which is T6. V0 is, like T6, activated only by execution
of a BRK instruction.
SD1 and SD2 are nodes 440 and 1258 respectively, which lie in the RCL block
outside of the timing generation (clock) block. They serve the needs of the
RMW (Read-Modify-Write) instructions for their addressing modes that use
external memory instead of the accumulator.
All of the corrected and new features has increased the total number of
displayed states to 24 from 10. Hopefully, this is the ultimate, final,
most fully comprehensive clock display possible, but we'll see.
2017-12-15 18:47:24 +00:00
|
|
|
if ( !isNodeHigh( nodenames[ 'clock1' ] ) ) s += "T0"; else s += "..";
|
2017-10-09 21:49:53 +00:00
|
|
|
s += _spc;
|
2017-09-20 00:01:47 +00:00
|
|
|
// T+ in visual6502 is called T1x in
|
|
|
|
// http://www.weihenstephan.org/~michaste/pagetable/6502/6502.jpg
|
|
|
|
// Notated as T+ for compatibility with PLA node names
|
Corrected and expanded the time state readout (the "TState" pseudobus).
The occurrences of T6 and T1 have been corrected. T6 now only occurs when a BRK
instruction is executing, it is a synonym for when the VEC1 node is logic high.
T1 now occurs when node 862 is logic high, which drives the SYNC pin, among
other control effects.
Formerly, T1 and T6 were displayed only when all the nodes that affect the PLA
were inactive. Node 1357's state was used in that case to choose between
displaying T1 (1357 high) or T6 (1357 low). That turned out to be incorrect
pair of inferences. The result was that T1 was absent when it should have been
present (when T+ was present without T0), and T6 was present when it should
have been absent (for instructions other than BRK). Among the corrective
changes, node 1357 is no longer consulted.
Expansion of state display adds V0, SD1, and SD2 indications. The last two are
in their own field (an eighth field). V0 is in the seventh field (square
bracketed, the same field occupied by T1 and T6). It is a two-character
representation of node VEC0 being at logic high. VEC0 high causes VEC1 to be
high one cycle later, which is T6. V0 is, like T6, activated only by execution
of a BRK instruction.
SD1 and SD2 are nodes 440 and 1258 respectively, which lie in the RCL block
outside of the timing generation (clock) block. They serve the needs of the
RMW (Read-Modify-Write) instructions for their addressing modes that use
external memory instead of the accumulator.
All of the corrected and new features has increased the total number of
displayed states to 24 from 10. Hopefully, this is the ultimate, final,
most fully comprehensive clock display possible, but we'll see.
2017-12-15 18:47:24 +00:00
|
|
|
if ( !isNodeHigh( nodenames[ 'clock2' ] ) ) s += "T+"; else s += "..";
|
2017-10-09 21:49:53 +00:00
|
|
|
s += _spc;
|
Corrected and expanded the time state readout (the "TState" pseudobus).
The occurrences of T6 and T1 have been corrected. T6 now only occurs when a BRK
instruction is executing, it is a synonym for when the VEC1 node is logic high.
T1 now occurs when node 862 is logic high, which drives the SYNC pin, among
other control effects.
Formerly, T1 and T6 were displayed only when all the nodes that affect the PLA
were inactive. Node 1357's state was used in that case to choose between
displaying T1 (1357 high) or T6 (1357 low). That turned out to be incorrect
pair of inferences. The result was that T1 was absent when it should have been
present (when T+ was present without T0), and T6 was present when it should
have been absent (for instructions other than BRK). Among the corrective
changes, node 1357 is no longer consulted.
Expansion of state display adds V0, SD1, and SD2 indications. The last two are
in their own field (an eighth field). V0 is in the seventh field (square
bracketed, the same field occupied by T1 and T6). It is a two-character
representation of node VEC0 being at logic high. VEC0 high causes VEC1 to be
high one cycle later, which is T6. V0 is, like T6, activated only by execution
of a BRK instruction.
SD1 and SD2 are nodes 440 and 1258 respectively, which lie in the RCL block
outside of the timing generation (clock) block. They serve the needs of the
RMW (Read-Modify-Write) instructions for their addressing modes that use
external memory instead of the accumulator.
All of the corrected and new features has increased the total number of
displayed states to 24 from 10. Hopefully, this is the ultimate, final,
most fully comprehensive clock display possible, but we'll see.
2017-12-15 18:47:24 +00:00
|
|
|
if ( !isNodeHigh( nodenames[ 't2' ] ) ) s += "T2"; else s += "..";
|
2017-10-09 21:49:53 +00:00
|
|
|
s += _spc;
|
Corrected and expanded the time state readout (the "TState" pseudobus).
The occurrences of T6 and T1 have been corrected. T6 now only occurs when a BRK
instruction is executing, it is a synonym for when the VEC1 node is logic high.
T1 now occurs when node 862 is logic high, which drives the SYNC pin, among
other control effects.
Formerly, T1 and T6 were displayed only when all the nodes that affect the PLA
were inactive. Node 1357's state was used in that case to choose between
displaying T1 (1357 high) or T6 (1357 low). That turned out to be incorrect
pair of inferences. The result was that T1 was absent when it should have been
present (when T+ was present without T0), and T6 was present when it should
have been absent (for instructions other than BRK). Among the corrective
changes, node 1357 is no longer consulted.
Expansion of state display adds V0, SD1, and SD2 indications. The last two are
in their own field (an eighth field). V0 is in the seventh field (square
bracketed, the same field occupied by T1 and T6). It is a two-character
representation of node VEC0 being at logic high. VEC0 high causes VEC1 to be
high one cycle later, which is T6. V0 is, like T6, activated only by execution
of a BRK instruction.
SD1 and SD2 are nodes 440 and 1258 respectively, which lie in the RCL block
outside of the timing generation (clock) block. They serve the needs of the
RMW (Read-Modify-Write) instructions for their addressing modes that use
external memory instead of the accumulator.
All of the corrected and new features has increased the total number of
displayed states to 24 from 10. Hopefully, this is the ultimate, final,
most fully comprehensive clock display possible, but we'll see.
2017-12-15 18:47:24 +00:00
|
|
|
if ( !isNodeHigh( nodenames[ 't3' ] ) ) s += "T3"; else s += "..";
|
2017-10-09 21:49:53 +00:00
|
|
|
s += _spc;
|
Corrected and expanded the time state readout (the "TState" pseudobus).
The occurrences of T6 and T1 have been corrected. T6 now only occurs when a BRK
instruction is executing, it is a synonym for when the VEC1 node is logic high.
T1 now occurs when node 862 is logic high, which drives the SYNC pin, among
other control effects.
Formerly, T1 and T6 were displayed only when all the nodes that affect the PLA
were inactive. Node 1357's state was used in that case to choose between
displaying T1 (1357 high) or T6 (1357 low). That turned out to be incorrect
pair of inferences. The result was that T1 was absent when it should have been
present (when T+ was present without T0), and T6 was present when it should
have been absent (for instructions other than BRK). Among the corrective
changes, node 1357 is no longer consulted.
Expansion of state display adds V0, SD1, and SD2 indications. The last two are
in their own field (an eighth field). V0 is in the seventh field (square
bracketed, the same field occupied by T1 and T6). It is a two-character
representation of node VEC0 being at logic high. VEC0 high causes VEC1 to be
high one cycle later, which is T6. V0 is, like T6, activated only by execution
of a BRK instruction.
SD1 and SD2 are nodes 440 and 1258 respectively, which lie in the RCL block
outside of the timing generation (clock) block. They serve the needs of the
RMW (Read-Modify-Write) instructions for their addressing modes that use
external memory instead of the accumulator.
All of the corrected and new features has increased the total number of
displayed states to 24 from 10. Hopefully, this is the ultimate, final,
most fully comprehensive clock display possible, but we'll see.
2017-12-15 18:47:24 +00:00
|
|
|
if ( !isNodeHigh( nodenames[ 't4' ] ) ) s += "T4"; else s += "..";
|
2017-10-09 21:49:53 +00:00
|
|
|
s += _spc;
|
Corrected and expanded the time state readout (the "TState" pseudobus).
The occurrences of T6 and T1 have been corrected. T6 now only occurs when a BRK
instruction is executing, it is a synonym for when the VEC1 node is logic high.
T1 now occurs when node 862 is logic high, which drives the SYNC pin, among
other control effects.
Formerly, T1 and T6 were displayed only when all the nodes that affect the PLA
were inactive. Node 1357's state was used in that case to choose between
displaying T1 (1357 high) or T6 (1357 low). That turned out to be incorrect
pair of inferences. The result was that T1 was absent when it should have been
present (when T+ was present without T0), and T6 was present when it should
have been absent (for instructions other than BRK). Among the corrective
changes, node 1357 is no longer consulted.
Expansion of state display adds V0, SD1, and SD2 indications. The last two are
in their own field (an eighth field). V0 is in the seventh field (square
bracketed, the same field occupied by T1 and T6). It is a two-character
representation of node VEC0 being at logic high. VEC0 high causes VEC1 to be
high one cycle later, which is T6. V0 is, like T6, activated only by execution
of a BRK instruction.
SD1 and SD2 are nodes 440 and 1258 respectively, which lie in the RCL block
outside of the timing generation (clock) block. They serve the needs of the
RMW (Read-Modify-Write) instructions for their addressing modes that use
external memory instead of the accumulator.
All of the corrected and new features has increased the total number of
displayed states to 24 from 10. Hopefully, this is the ultimate, final,
most fully comprehensive clock display possible, but we'll see.
2017-12-15 18:47:24 +00:00
|
|
|
if ( !isNodeHigh( nodenames[ 't5' ] ) ) s += "T5"; else s += "..";
|
2017-10-09 21:49:53 +00:00
|
|
|
s += _spc + "[";
|
Corrected and expanded the time state readout (the "TState" pseudobus).
The occurrences of T6 and T1 have been corrected. T6 now only occurs when a BRK
instruction is executing, it is a synonym for when the VEC1 node is logic high.
T1 now occurs when node 862 is logic high, which drives the SYNC pin, among
other control effects.
Formerly, T1 and T6 were displayed only when all the nodes that affect the PLA
were inactive. Node 1357's state was used in that case to choose between
displaying T1 (1357 high) or T6 (1357 low). That turned out to be incorrect
pair of inferences. The result was that T1 was absent when it should have been
present (when T+ was present without T0), and T6 was present when it should
have been absent (for instructions other than BRK). Among the corrective
changes, node 1357 is no longer consulted.
Expansion of state display adds V0, SD1, and SD2 indications. The last two are
in their own field (an eighth field). V0 is in the seventh field (square
bracketed, the same field occupied by T1 and T6). It is a two-character
representation of node VEC0 being at logic high. VEC0 high causes VEC1 to be
high one cycle later, which is T6. V0 is, like T6, activated only by execution
of a BRK instruction.
SD1 and SD2 are nodes 440 and 1258 respectively, which lie in the RCL block
outside of the timing generation (clock) block. They serve the needs of the
RMW (Read-Modify-Write) instructions for their addressing modes that use
external memory instead of the accumulator.
All of the corrected and new features has increased the total number of
displayed states to 24 from 10. Hopefully, this is the ultimate, final,
most fully comprehensive clock display possible, but we'll see.
2017-12-15 18:47:24 +00:00
|
|
|
// Check three confirmed exclusive states (three nodes)
|
|
|
|
if ( isNodeHigh( 862 ) ) {
|
|
|
|
s += "T1";
|
|
|
|
// ...else if VEC0 is on...
|
|
|
|
} else if ( isNodeHigh( nodenames[ 'VEC0' ] ) ) {
|
|
|
|
// ...then tell the outside world
|
|
|
|
s += "V0";
|
|
|
|
// ...else if VEC1 is on...
|
|
|
|
} else if ( isNodeHigh( nodenames[ 'VEC1' ] ) ) {
|
|
|
|
// ...then this is the canonical T6. It is a synonym for VEC1
|
|
|
|
s += "T6";
|
2017-09-20 00:01:47 +00:00
|
|
|
} else {
|
Corrected and expanded the time state readout (the "TState" pseudobus).
The occurrences of T6 and T1 have been corrected. T6 now only occurs when a BRK
instruction is executing, it is a synonym for when the VEC1 node is logic high.
T1 now occurs when node 862 is logic high, which drives the SYNC pin, among
other control effects.
Formerly, T1 and T6 were displayed only when all the nodes that affect the PLA
were inactive. Node 1357's state was used in that case to choose between
displaying T1 (1357 high) or T6 (1357 low). That turned out to be incorrect
pair of inferences. The result was that T1 was absent when it should have been
present (when T+ was present without T0), and T6 was present when it should
have been absent (for instructions other than BRK). Among the corrective
changes, node 1357 is no longer consulted.
Expansion of state display adds V0, SD1, and SD2 indications. The last two are
in their own field (an eighth field). V0 is in the seventh field (square
bracketed, the same field occupied by T1 and T6). It is a two-character
representation of node VEC0 being at logic high. VEC0 high causes VEC1 to be
high one cycle later, which is T6. V0 is, like T6, activated only by execution
of a BRK instruction.
SD1 and SD2 are nodes 440 and 1258 respectively, which lie in the RCL block
outside of the timing generation (clock) block. They serve the needs of the
RMW (Read-Modify-Write) instructions for their addressing modes that use
external memory instead of the accumulator.
All of the corrected and new features has increased the total number of
displayed states to 24 from 10. Hopefully, this is the ultimate, final,
most fully comprehensive clock display possible, but we'll see.
2017-12-15 18:47:24 +00:00
|
|
|
// ...else none of the "hidden" bits in the clock state is active
|
2017-09-20 00:01:47 +00:00
|
|
|
s += "..";
|
|
|
|
}
|
Corrected and expanded the time state readout (the "TState" pseudobus).
The occurrences of T6 and T1 have been corrected. T6 now only occurs when a BRK
instruction is executing, it is a synonym for when the VEC1 node is logic high.
T1 now occurs when node 862 is logic high, which drives the SYNC pin, among
other control effects.
Formerly, T1 and T6 were displayed only when all the nodes that affect the PLA
were inactive. Node 1357's state was used in that case to choose between
displaying T1 (1357 high) or T6 (1357 low). That turned out to be incorrect
pair of inferences. The result was that T1 was absent when it should have been
present (when T+ was present without T0), and T6 was present when it should
have been absent (for instructions other than BRK). Among the corrective
changes, node 1357 is no longer consulted.
Expansion of state display adds V0, SD1, and SD2 indications. The last two are
in their own field (an eighth field). V0 is in the seventh field (square
bracketed, the same field occupied by T1 and T6). It is a two-character
representation of node VEC0 being at logic high. VEC0 high causes VEC1 to be
high one cycle later, which is T6. V0 is, like T6, activated only by execution
of a BRK instruction.
SD1 and SD2 are nodes 440 and 1258 respectively, which lie in the RCL block
outside of the timing generation (clock) block. They serve the needs of the
RMW (Read-Modify-Write) instructions for their addressing modes that use
external memory instead of the accumulator.
All of the corrected and new features has increased the total number of
displayed states to 24 from 10. Hopefully, this is the ultimate, final,
most fully comprehensive clock display possible, but we'll see.
2017-12-15 18:47:24 +00:00
|
|
|
s += "]" + _spc;
|
|
|
|
// Check the RCL's two confirmed exclusive states (two nodes)
|
|
|
|
// If this node is grounding ~WR...
|
|
|
|
if ( isNodeHigh( 440 ) ) {
|
|
|
|
// ...then we can regard this state as Store Data 1
|
|
|
|
s += "SD1";
|
|
|
|
// ...else if this node is grounding ~WR...
|
|
|
|
} else if ( isNodeHigh( 1258 ) ) {
|
|
|
|
// ...then we can regard this state as Store Data 2
|
|
|
|
s += "SD2";
|
|
|
|
} else {
|
|
|
|
// ...else none of the RCL-resident timing bits is active
|
|
|
|
s += "...";
|
|
|
|
}
|
2017-09-20 00:01:47 +00:00
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
2010-09-18 17:46:24 +00:00
|
|
|
function readBit(name){
|
|
|
|
return isNodeHigh(nodenames[name])?1:0;
|
|
|
|
}
|
2010-09-18 17:12:28 +00:00
|
|
|
function readBits(name, n){
|
|
|
|
var res = 0;
|
|
|
|
for(var i=0;i<n;i++){
|
|
|
|
var nn = nodenames[name+i];
|
|
|
|
res+=((isNodeHigh(nn))?1:0)<<i;
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2010-09-27 13:16:59 +00:00
|
|
|
function busToString(busname){
|
|
|
|
// takes a signal name or prefix
|
|
|
|
// returns an appropriate string representation
|
2010-11-22 13:27:26 +00:00
|
|
|
// some 'signal names' are CPU-specific aliases to user-friendly string output
|
2010-09-27 17:25:14 +00:00
|
|
|
if(busname=='cycle')
|
|
|
|
return cycle>>1;
|
2010-09-25 21:32:29 +00:00
|
|
|
if(busname=='pc')
|
2010-09-27 13:16:59 +00:00
|
|
|
return busToHex('pch') + busToHex('pcl');
|
|
|
|
if(busname=='p')
|
|
|
|
return readPstring();
|
2010-09-27 17:25:14 +00:00
|
|
|
if(busname=='tcstate')
|
2010-10-05 18:12:44 +00:00
|
|
|
return ['clock1','clock2','t2','t3','t4','t5'].map(busToHex).join("");
|
2010-11-22 13:27:26 +00:00
|
|
|
if(busname=='State')
|
|
|
|
return listActiveTCStates();
|
2017-10-09 21:49:53 +00:00
|
|
|
if(busname=='TState')
|
|
|
|
return allTCStates( true );
|
2017-10-30 04:49:17 +00:00
|
|
|
if(busname=='Phi')
|
|
|
|
// Pretty-printed phase indication based on the state of cp1,
|
|
|
|
// the internal Phase 1 node
|
|
|
|
return 'Φ' +
|
|
|
|
(isNodeHigh( nodenames[ 'cp1' ] ) ? '1' : '2');
|
2010-11-22 13:27:26 +00:00
|
|
|
if(busname=='Execute')
|
2011-04-01 16:05:41 +00:00
|
|
|
return disassemblytoHTML(readBits('ir',8));
|
2010-11-22 13:27:26 +00:00
|
|
|
if(busname=='Fetch')
|
2011-04-01 16:05:41 +00:00
|
|
|
return isNodeHigh(nodenames['sync'])?disassemblytoHTML(readDataBus()):"";
|
2010-11-01 17:42:18 +00:00
|
|
|
if(busname=='plaOutputs')
|
2010-11-19 22:42:26 +00:00
|
|
|
// 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')
|
2018-05-29 09:51:02 +00:00
|
|
|
return listActiveSignals('^dpc[-]?[0-9]+_');
|
2010-11-19 21:49:16 +00:00
|
|
|
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);
|
|
|
|
}
|
2010-09-27 13:16:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function busToHex(busname){
|
2010-09-27 17:25:14 +00:00
|
|
|
// may be passed a bus or a signal, so allow multiple signals
|
2010-09-25 21:32:29 +00:00
|
|
|
var width=0;
|
2010-11-19 21:49:16 +00:00
|
|
|
var r=new RegExp('^' + busname + '[0-9]+$');
|
2010-09-25 21:32:29 +00:00
|
|
|
for(var i in nodenamelist){
|
2010-09-27 17:25:14 +00:00
|
|
|
if(r.test(nodenamelist[i])) {
|
2010-09-25 21:32:29 +00:00
|
|
|
width++;
|
2010-09-27 17:25:14 +00:00
|
|
|
}
|
2010-09-25 21:32:29 +00:00
|
|
|
}
|
2010-11-05 19:02:41 +00:00
|
|
|
if(width==0) {
|
|
|
|
// not a bus, so could be a signal, a nodenumber or a mistake
|
|
|
|
if(typeof nodenames[busname] != "undefined")
|
|
|
|
return isNodeHigh(nodenames[busname])?"1":"0";
|
|
|
|
if((parseInt(busname)!=NaN) && (typeof nodes[busname] != "undefined"))
|
|
|
|
return isNodeHigh(busname)?"1":"0";
|
|
|
|
return undefined;
|
|
|
|
}
|
2010-09-25 21:32:29 +00:00
|
|
|
if(width>16)
|
2010-11-05 19:02:41 +00:00
|
|
|
return undefined;
|
2010-09-27 17:25:14 +00:00
|
|
|
// finally, convert from logic values to hex
|
2010-10-30 18:05:29 +00:00
|
|
|
return (0x10000+readBits(busname,width)).toString(16).slice(-(width-1)/4-1);
|
2010-09-25 21:32:29 +00:00
|
|
|
}
|
|
|
|
|
2010-09-18 17:12:28 +00:00
|
|
|
function writeDataBus(x){
|
|
|
|
var recalcs = Array();
|
|
|
|
for(var i=0;i<8;i++){
|
|
|
|
var nn = nodenames['db'+i];
|
|
|
|
var n = nodes[nn];
|
|
|
|
if((x%2)==0) {n.pulldown=true; n.pullup=false;}
|
|
|
|
else {n.pulldown=false; n.pullup=true;}
|
|
|
|
recalcs.push(nn);
|
|
|
|
x>>=1;
|
|
|
|
}
|
|
|
|
recalcNodeList(recalcs);
|
|
|
|
}
|
|
|
|
|
|
|
|
function mRead(a){
|
|
|
|
if(memory[a]==undefined) return 0;
|
|
|
|
else return memory[a];
|
|
|
|
}
|
|
|
|
|
|
|
|
function mWrite(a, d){memory[a]=d;}
|
|
|
|
|
|
|
|
function clkNodes(){
|
|
|
|
var res = Array();
|
|
|
|
res.push(943);
|
|
|
|
for(var i in nodes[943].gates){
|
2010-10-15 00:16:43 +00:00
|
|
|
var t = nodes[943].gates[i];
|
2010-09-18 17:12:28 +00:00
|
|
|
if(t.c1==npwr) res.push(t.c2);
|
|
|
|
if(t.c2==npwr) res.push(t.c1);
|
|
|
|
}
|
|
|
|
hiliteNode(res);
|
|
|
|
}
|
|
|
|
|
|
|
|
function runChip(){
|
|
|
|
var start = document.getElementById('start');
|
|
|
|
var stop = document.getElementById('stop');
|
|
|
|
start.style.visibility = 'hidden';
|
|
|
|
stop.style.visibility = 'visible';
|
2010-10-30 18:24:00 +00:00
|
|
|
if(typeof running == "undefined")
|
|
|
|
initChip();
|
2010-09-18 17:12:28 +00:00
|
|
|
running = true;
|
2010-10-01 18:39:33 +00:00
|
|
|
go();
|
2010-09-18 17:12:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function stopChip(){
|
|
|
|
var start = document.getElementById('start');
|
|
|
|
var stop = document.getElementById('stop');
|
|
|
|
start.style.visibility = 'visible';
|
|
|
|
stop.style.visibility = 'hidden';
|
|
|
|
running = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
function resetChip(){
|
|
|
|
stopChip();
|
2011-04-01 11:17:34 +00:00
|
|
|
setStatus('resetting ' + chipname + '...');
|
2010-09-18 17:46:24 +00:00
|
|
|
setTimeout(initChip,0);
|
2010-09-18 17:12:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function stepForward(){
|
2010-11-05 21:39:01 +00:00
|
|
|
if(typeof running == "undefined")
|
|
|
|
initChip();
|
2010-09-18 17:12:28 +00:00
|
|
|
stopChip();
|
|
|
|
step();
|
|
|
|
}
|
|
|
|
|
|
|
|
function stepBack(){
|
|
|
|
if(cycle==0) return;
|
|
|
|
showState(trace[--cycle].chip);
|
|
|
|
setMem(trace[cycle].mem);
|
|
|
|
var clk = isNodeHigh(nodenames['clk0']);
|
|
|
|
if(!clk) writeDataBus(mRead(readAddressBus()));
|
|
|
|
chipStatus();
|
|
|
|
}
|
|
|
|
|
|
|
|
function chipStatus(){
|
2010-09-18 17:46:24 +00:00
|
|
|
var ab = readAddressBus();
|
|
|
|
var machine1 =
|
|
|
|
' halfcyc:' + cycle +
|
|
|
|
' phi0:' + readBit('clk0') +
|
|
|
|
' AB:' + hexWord(ab) +
|
|
|
|
' D:' + hexByte(readDataBus()) +
|
|
|
|
' RnW:' + readBit('rw');
|
|
|
|
var machine2 =
|
|
|
|
' PC:' + hexWord(readPC()) +
|
|
|
|
' A:' + hexByte(readA()) +
|
|
|
|
' X:' + hexByte(readX()) +
|
|
|
|
' Y:' + hexByte(readY()) +
|
|
|
|
' SP:' + hexByte(readSP()) +
|
|
|
|
' ' + readPstring();
|
2010-11-22 13:27:26 +00:00
|
|
|
var machine3 =
|
2011-04-01 11:59:22 +00:00
|
|
|
'Hz: ' + estimatedHz().toFixed(1);
|
|
|
|
if(typeof expertMode != "undefined") {
|
|
|
|
machine3 += ' Exec: ' + busToString('Execute') + '(' + busToString('State') + ')';
|
|
|
|
if(isNodeHigh(nodenames['sync']))
|
|
|
|
machine3 += ' (Fetch: ' + busToString('Fetch') + ')';
|
|
|
|
if(goldenChecksum != undefined)
|
|
|
|
machine3 += " Chk:" + traceChecksum + ((traceChecksum==goldenChecksum)?" OK":" no match");
|
|
|
|
}
|
2010-11-22 13:27:26 +00:00
|
|
|
setStatus(machine1, machine2, machine3);
|
2011-04-06 18:13:04 +00:00
|
|
|
if (logThese.length>1) {
|
2010-11-01 19:36:52 +00:00
|
|
|
updateLogbox(logThese);
|
2010-09-25 21:32:29 +00:00
|
|
|
}
|
|
|
|
selectCell(ab);
|
|
|
|
}
|
|
|
|
|
2010-11-15 17:29:50 +00:00
|
|
|
// run for an extended number of cycles, with low overhead, for interactive programs or for benchmarking
|
|
|
|
// note: to run an interactive program, use an URL like
|
|
|
|
// http://visual6502.org/JSSim/expert.html?graphics=f&loglevel=-1&headlesssteps=-500
|
2010-10-15 02:48:25 +00:00
|
|
|
function goFor(){
|
2010-11-15 17:29:50 +00:00
|
|
|
var n = headlessSteps; // a negative value is a request to free-run
|
|
|
|
if(headlessSteps<0)
|
|
|
|
n=-n;
|
|
|
|
var start = document.getElementById('start');
|
|
|
|
var stop = document.getElementById('stop');
|
|
|
|
start.style.visibility = 'hidden';
|
|
|
|
stop.style.visibility = 'visible';
|
|
|
|
if(typeof running == "undefined") {
|
|
|
|
initChip();
|
|
|
|
}
|
|
|
|
running = true;
|
|
|
|
setTimeout("instantaneousHz(); goForN("+n+")",0);
|
|
|
|
}
|
|
|
|
|
|
|
|
// helper function: allows us to poll 'running' without resetting it when we're re-scheduled
|
|
|
|
function goForN(n){
|
|
|
|
var n2=n; // save our parameter so we can re-submit ourselves
|
2010-11-01 18:19:46 +00:00
|
|
|
while(n--){
|
2010-10-15 02:48:25 +00:00
|
|
|
halfStep();
|
|
|
|
cycle++;
|
|
|
|
}
|
2010-11-15 17:29:50 +00:00
|
|
|
instantaneousHz();
|
2010-10-15 02:48:25 +00:00
|
|
|
chipStatus();
|
2010-11-15 17:29:50 +00:00
|
|
|
if((headlessSteps<0) && running){
|
|
|
|
setTimeout("goForN("+n2+")",0); // re-submit ourselves if we are meant to free-run
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
running = false;
|
2011-04-05 18:29:49 +00:00
|
|
|
var start = document.getElementById('start');
|
|
|
|
var stop = document.getElementById('stop');
|
2010-11-15 17:29:50 +00:00
|
|
|
start.style.visibility = 'visible';
|
|
|
|
stop.style.visibility = 'hidden';
|
2010-10-15 02:48:25 +00:00
|
|
|
}
|
|
|
|
|
2010-10-02 11:51:33 +00:00
|
|
|
var prevHzTimeStamp=0;
|
|
|
|
var prevHzCycleCount=0;
|
|
|
|
var prevHzEstimate1=1;
|
|
|
|
var prevHzEstimate2=1;
|
|
|
|
var HzSamplingRate=10;
|
2010-10-15 02:48:25 +00:00
|
|
|
|
2010-11-15 17:29:50 +00:00
|
|
|
// return an averaged speed: called periodically during normal running
|
2010-10-02 11:51:33 +00:00
|
|
|
function estimatedHz(){
|
|
|
|
if(cycle%HzSamplingRate!=3)
|
|
|
|
return prevHzEstimate1;
|
|
|
|
var HzTimeStamp = now();
|
|
|
|
var HzEstimate = (cycle-prevHzCycleCount+.01)/(HzTimeStamp-prevHzTimeStamp+.01);
|
|
|
|
HzEstimate=HzEstimate*1000/2; // convert from phases per millisecond to Hz
|
|
|
|
if(HzEstimate<5)
|
|
|
|
HzSamplingRate=5; // quicker
|
|
|
|
if(HzEstimate>10)
|
|
|
|
HzSamplingRate=10; // smoother
|
|
|
|
prevHzEstimate2=prevHzEstimate1;
|
|
|
|
prevHzEstimate1=(HzEstimate+prevHzEstimate1+prevHzEstimate2)/3; // wrong way to average speeds
|
|
|
|
prevHzTimeStamp=HzTimeStamp;
|
|
|
|
prevHzCycleCount=cycle;
|
|
|
|
return prevHzEstimate1
|
|
|
|
}
|
|
|
|
|
2010-11-15 17:29:50 +00:00
|
|
|
// return instantaneous speed: called twice, before and after a timed run using goFor()
|
|
|
|
function instantaneousHz(){
|
|
|
|
var HzTimeStamp = now();
|
|
|
|
var HzEstimate = (cycle-prevHzCycleCount+.01)/(HzTimeStamp-prevHzTimeStamp+.01);
|
|
|
|
HzEstimate=HzEstimate*1000/2; // convert from phases per millisecond to Hz
|
|
|
|
prevHzEstimate1=HzEstimate;
|
|
|
|
prevHzEstimate2=prevHzEstimate1;
|
|
|
|
prevHzTimeStamp=HzTimeStamp;
|
|
|
|
prevHzCycleCount=cycle;
|
|
|
|
return prevHzEstimate1
|
|
|
|
}
|
|
|
|
|
2010-11-08 22:03:47 +00:00
|
|
|
var logbox;
|
2010-09-25 21:32:29 +00:00
|
|
|
function initLogbox(names){
|
2010-11-08 22:03:47 +00:00
|
|
|
logbox=document.getElementById('logstream');
|
2010-10-07 16:21:06 +00:00
|
|
|
if(logbox==null)return;
|
|
|
|
|
2010-11-19 21:49:16 +00:00
|
|
|
names=names.map(function(x){return x.replace(/^-/,'')});
|
2010-09-25 21:32:29 +00:00
|
|
|
logStream = [];
|
2011-04-01 11:59:22 +00:00
|
|
|
logStream.push("<td class=header>" + names.join("</td><td class=header>") + "</td>");
|
2010-09-27 17:25:14 +00:00
|
|
|
logbox.innerHTML = "<tr>"+logStream.join("</tr><tr>")+"</tr>";
|
2010-09-25 21:32:29 +00:00
|
|
|
}
|
|
|
|
|
2010-11-05 19:53:22 +00:00
|
|
|
var logboxAppend=true;
|
|
|
|
|
|
|
|
// can append or prepend new states to the log table
|
|
|
|
// when we reverse direction we need to reorder the log stream
|
|
|
|
function updateLogDirection(){
|
|
|
|
var loglines=[];
|
2010-11-08 22:03:47 +00:00
|
|
|
logboxAppend=!logboxAppend;
|
2010-11-05 19:53:22 +00:00
|
|
|
// the first element is the header so we can't reverse()
|
|
|
|
for (var i=1;i<logStream.length;i++) {
|
|
|
|
loglines.unshift(logStream[i]);
|
|
|
|
}
|
|
|
|
loglines.unshift(logStream[0]);
|
|
|
|
logStream=loglines;
|
|
|
|
logbox.innerHTML = "<tr>"+logStream.join("</tr><tr>")+"</tr>";
|
|
|
|
}
|
|
|
|
|
|
|
|
// update the table of signal values, by prepending or appending
|
2010-09-25 21:32:29 +00:00
|
|
|
function updateLogbox(names){
|
|
|
|
var signals=[];
|
2011-04-01 11:59:22 +00:00
|
|
|
var odd=true;
|
|
|
|
var bg;
|
|
|
|
var row;
|
|
|
|
|
|
|
|
for(var i in names){
|
|
|
|
if(cycle % 4 < 2){
|
|
|
|
bg = odd ? " class=oddcol":"";
|
|
|
|
} else {
|
|
|
|
bg = odd ? " class=oddrow":" class=oddrowcol";
|
|
|
|
}
|
|
|
|
signals.push("<td" + bg + ">" + busToString(names[i]) + "</td>");
|
|
|
|
odd =! odd;
|
2010-09-25 21:32:29 +00:00
|
|
|
}
|
2011-04-01 11:59:22 +00:00
|
|
|
row = "<tr>" + signals.join("") + "</tr>";
|
2010-11-05 19:53:22 +00:00
|
|
|
if(logboxAppend)
|
2011-04-01 11:59:22 +00:00
|
|
|
logStream.push(row);
|
2010-11-05 19:53:22 +00:00
|
|
|
else
|
2011-04-01 11:59:22 +00:00
|
|
|
logStream.splice(1,0,row);
|
2010-09-25 21:32:29 +00:00
|
|
|
|
2011-04-01 11:59:22 +00:00
|
|
|
logbox.innerHTML = logStream.join("");
|
2010-09-18 17:12:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function getMem(){
|
|
|
|
var res = Array();
|
|
|
|
for(var i=0;i<0x200;i++) res.push(mRead(i));
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
function setMem(arr){
|
|
|
|
for(var i=0;i<0x200;i++){mWrite(i, arr[i]); setCellValue(i, arr[i]);}
|
|
|
|
}
|
|
|
|
|
|
|
|
function hexWord(n){return (0x10000+n).toString(16).substring(1)}
|
|
|
|
function hexByte(n){return (0x100+n).toString(16).substring(1)}
|
2010-10-05 19:14:08 +00:00
|
|
|
|
|
|
|
function adler32(x){
|
|
|
|
var a=1;
|
|
|
|
var b=0;
|
|
|
|
for(var i=0;i<x.length;i++){
|
|
|
|
a=(a+x.charCodeAt(i))%65521;
|
|
|
|
b=(b+a)%65521;
|
|
|
|
}
|
|
|
|
return (0x100000000+(b<<16)+a).toString(16).slice(-8);
|
|
|
|
}
|
2010-11-22 12:22:36 +00:00
|
|
|
|
2011-04-01 11:59:22 +00:00
|
|
|
// sanitised opcode for HTML output
|
2011-04-01 16:05:41 +00:00
|
|
|
function disassemblytoHTML(byte){
|
|
|
|
var opcode=disassembly[byte];
|
2011-04-01 11:59:22 +00:00
|
|
|
if(typeof opcode == "undefined")
|
|
|
|
return "unknown"
|
|
|
|
return opcode.replace(/ /,' ');
|
|
|
|
}
|
|
|
|
|
2010-11-22 12:22:36 +00:00
|
|
|
// opcode lookup for 6502 - not quite a disassembly
|
|
|
|
// javascript derived from Debugger.java by Achim Breidenbach
|
2011-04-01 16:05:41 +00:00
|
|
|
var disassembly={
|
2010-11-22 12:22:36 +00:00
|
|
|
0x00:"BRK",
|
|
|
|
0x01:"ORA (zp,X)",
|
|
|
|
0x05:"ORA zp",
|
|
|
|
0x06:"ASL zp",
|
|
|
|
0x08:"PHP",
|
|
|
|
0x09:"ORA #",
|
|
|
|
0x0A:"ASL ",
|
|
|
|
0x0D:"ORA Abs",
|
|
|
|
0x0E:"ASL Abs",
|
|
|
|
0x10:"BPL ",
|
|
|
|
0x11:"ORA (zp),Y",
|
|
|
|
0x15:"ORA zp,X",
|
|
|
|
0x16:"ASL zp,X",
|
|
|
|
0x18:"CLC",
|
|
|
|
0x19:"ORA Abs,Y",
|
|
|
|
0x1D:"ORA Abs,X",
|
|
|
|
0x1E:"ASL Abs,X",
|
|
|
|
0x20:"JSR Abs",
|
|
|
|
0x21:"AND (zp,X)",
|
|
|
|
0x24:"BIT zp",
|
|
|
|
0x25:"AND zp",
|
|
|
|
0x26:"ROL zp",
|
|
|
|
0x28:"PLP",
|
|
|
|
0x29:"AND #",
|
|
|
|
0x2A:"ROL ",
|
|
|
|
0x2C:"BIT Abs",
|
|
|
|
0x2D:"AND Abs",
|
|
|
|
0x2E:"ROL Abs",
|
|
|
|
0x30:"BMI ",
|
|
|
|
0x31:"AND (zp),Y",
|
|
|
|
0x35:"AND zp,X",
|
|
|
|
0x36:"ROL zp,X",
|
|
|
|
0x38:"SEC",
|
|
|
|
0x39:"AND Abs,Y",
|
|
|
|
0x3D:"AND Abs,X",
|
|
|
|
0x3E:"ROL Abs,X",
|
|
|
|
0x40:"RTI",
|
|
|
|
0x41:"EOR (zp,X)",
|
|
|
|
0x45:"EOR zp",
|
|
|
|
0x46:"LSR zp",
|
|
|
|
0x48:"PHA",
|
|
|
|
0x49:"EOR #",
|
|
|
|
0x4A:"LSR ",
|
|
|
|
0x4C:"JMP Abs",
|
|
|
|
0x4D:"EOR Abs",
|
|
|
|
0x4E:"LSR Abs",
|
|
|
|
0x50:"BVC ",
|
|
|
|
0x51:"EOR (zp),Y",
|
|
|
|
0x55:"EOR zp,X",
|
|
|
|
0x56:"LSR zp,X",
|
|
|
|
0x58:"CLI",
|
|
|
|
0x59:"EOR Abs,Y",
|
|
|
|
0x5D:"EOR Abs,X",
|
|
|
|
0x5E:"LSR Abs,X",
|
|
|
|
0x60:"RTS",
|
|
|
|
0x61:"ADC (zp,X)",
|
|
|
|
0x65:"ADC zp",
|
|
|
|
0x66:"ROR zp",
|
|
|
|
0x68:"PLA",
|
|
|
|
0x69:"ADC #",
|
|
|
|
0x6A:"ROR ",
|
2017-03-11 04:09:20 +00:00
|
|
|
0x6C:"JMP (Abs)",
|
2010-11-22 12:22:36 +00:00
|
|
|
0x6D:"ADC Abs",
|
|
|
|
0x6E:"ROR Abs",
|
|
|
|
0x70:"BVS ",
|
|
|
|
0x71:"ADC (zp),Y",
|
|
|
|
0x75:"ADC zp,X",
|
|
|
|
0x76:"ROR zp,X",
|
|
|
|
0x78:"SEI",
|
|
|
|
0x79:"ADC Abs,Y",
|
|
|
|
0x7D:"ADC Abs,X",
|
|
|
|
0x7E:"ROR Abs,X",
|
|
|
|
0x81:"STA (zp,X)",
|
|
|
|
0x84:"STY zp",
|
|
|
|
0x85:"STA zp",
|
|
|
|
0x86:"STX zp",
|
|
|
|
0x88:"DEY",
|
|
|
|
0x8A:"TXA",
|
|
|
|
0x8C:"STY Abs",
|
|
|
|
0x8D:"STA Abs",
|
|
|
|
0x8E:"STX Abs",
|
|
|
|
0x90:"BCC ",
|
|
|
|
0x91:"STA (zp),Y",
|
|
|
|
0x94:"STY zp,X",
|
|
|
|
0x95:"STA zp,X",
|
|
|
|
0x96:"STX zp,Y",
|
|
|
|
0x98:"TYA",
|
|
|
|
0x99:"STA Abs,Y",
|
|
|
|
0x9A:"TXS",
|
|
|
|
0x9D:"STA Abs,X",
|
|
|
|
0xA0:"LDY #",
|
|
|
|
0xA1:"LDA (zp,X)",
|
|
|
|
0xA2:"LDX #",
|
|
|
|
0xA4:"LDY zp",
|
|
|
|
0xA5:"LDA zp",
|
|
|
|
0xA6:"LDX zp",
|
|
|
|
0xA8:"TAY",
|
|
|
|
0xA9:"LDA #",
|
|
|
|
0xAA:"TAX",
|
|
|
|
0xAC:"LDY Abs",
|
|
|
|
0xAD:"LDA Abs",
|
|
|
|
0xAE:"LDX Abs",
|
|
|
|
0xB0:"BCS ",
|
|
|
|
0xB1:"LDA (zp),Y",
|
|
|
|
0xB4:"LDY zp,X",
|
|
|
|
0xB5:"LDA zp,X",
|
|
|
|
0xB6:"LDX zp,Y",
|
|
|
|
0xB8:"CLV",
|
|
|
|
0xB9:"LDA Abs,Y",
|
|
|
|
0xBA:"TSX",
|
|
|
|
0xBC:"LDY Abs,X",
|
|
|
|
0xBD:"LDA Abs,X",
|
|
|
|
0xBE:"LDX Abs,Y",
|
|
|
|
0xC0:"CPY #",
|
|
|
|
0xC1:"CMP (zp,X)",
|
|
|
|
0xC4:"CPY zp",
|
|
|
|
0xC5:"CMP zp",
|
|
|
|
0xC6:"DEC zp",
|
|
|
|
0xC8:"INY",
|
|
|
|
0xC9:"CMP #",
|
|
|
|
0xCA:"DEX",
|
|
|
|
0xCC:"CPY Abs",
|
|
|
|
0xCD:"CMP Abs",
|
|
|
|
0xCE:"DEC Abs",
|
|
|
|
0xD0:"BNE ",
|
|
|
|
0xD1:"CMP (zp),Y",
|
|
|
|
0xD5:"CMP zp,X",
|
|
|
|
0xD6:"DEC zp,X",
|
|
|
|
0xD8:"CLD",
|
|
|
|
0xD9:"CMP Abs,Y",
|
|
|
|
0xDD:"CMP Abs,X",
|
|
|
|
0xDE:"DEC Abs,X",
|
|
|
|
0xE0:"CPX #",
|
|
|
|
0xE1:"SBC (zp,X)",
|
|
|
|
0xE4:"CPX zp",
|
|
|
|
0xE5:"SBC zp",
|
|
|
|
0xE6:"INC zp",
|
|
|
|
0xE8:"INX",
|
|
|
|
0xE9:"SBC #",
|
|
|
|
0xEA:"NOP",
|
|
|
|
0xEC:"CPX Abs",
|
|
|
|
0xED:"SBC Abs",
|
|
|
|
0xEE:"INC Abs",
|
|
|
|
0xF0:"BEQ ",
|
|
|
|
0xF1:"SBC (zp),Y",
|
|
|
|
0xF5:"SBC zp,X",
|
|
|
|
0xF6:"INC zp,X",
|
|
|
|
0xF8:"SED",
|
|
|
|
0xF9:"SBC Abs,Y",
|
|
|
|
0xFD:"SBC Abs,X",
|
|
|
|
0xFE:"INC Abs,X",
|
|
|
|
};
|