Skip to content

Instantly share code, notes, and snippets.

@bzikarsky
Created December 6, 2011 07:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bzikarsky/1437169 to your computer and use it in GitHub Desktop.
Save bzikarsky/1437169 to your computer and use it in GitHub Desktop.
<html>
<head>
<title>VM</title>
<style type="text/css">
body {
font-family: "Courier New";
font-size: .8em;
}
hr {
height: 1px;
background-color: #000;
color:#000;
border: 0;
}
th {
text-align: left;
}
#opcodes, #memory, .column {
float: left;
margin-left: 2em;
margin-right: 2em;
margin-bottom: 2em;
min-width: 300px;
max-height: 90%;
overflow: auto;
}
#memory table {
font-size: .8em;
}
#opcodes * {
max-height: 80%;
overflow: auto;
}
#footer {
font-size: 12px;
clear: both;
}
.value {
display: none;
}
.read {
background-color: #cfc;
}
.write {
background-color: #fcc;
}
.instr_ptr {
background-color: #ccf;
}
.instr_ptr_next {
background-color: #ffc;
}
</style>
</head>
<body>
<script type="text/javascript" src="http://code.jquery.com/jquery-1.7.1.min.js"></script>
<!-- see: https://gist.github.com/1437167 -->
<script type="text/javascript" src="vm.js"></script>
<script type="text/javascript">
var MemoryView = function(container, vm) {
var CLS_WRITE = 'write';
var CLS_READ = 'read';
var CLS_IP = 'instr_ptr';
var CLS_IP_NEXT = 'instr_ptr_next';
var VIEW_TYPES = {
HEX: function(v) {
return v.toHex();
},
ASCII: function(v) {
return String.fromCharCode(v);
}
};
var viewType = VIEW_TYPES.HEX;
var buildTable = function() {
var table = $('<table>');
var tr = $('<tr>');
tr.append('<th>mem/seg</th>');
for (var i=0; i<vm.MEM_SEGMENT_SIZE; i++) {
tr.append('<th>' + i.toHex() + '</th>');
}
for (var i=0; i<vm.mem.length; i++) {
if (i%vm.MEM_SEGMENT_SIZE == 0) {
table.append(tr);
if (i%(vm.mem.length/3) == 0 && i > 0) {
table.append('<tr><td>&nbsp;</td></tr>');
}
tr = $('<tr>');
tr.append('<th>' + (i/vm.MEM_SEGMENT_SIZE).toHex() + '</th>');
}
var td = $('<td id="mem_' + i + '">'
+ '<span class="value">' + vm.mem[i] + '</span>'
+ '<span class="display">' + viewType(vm.mem[i]) + '</span>'
+ '</td>');
tr.append(td);
}
table.append(tr);
return table;
}
var buildHeadline = function() {
return $('<h2>Memory ['
+ '<span class="' + CLS_READ + '">READ</span> '
+ '<span class="' + CLS_WRITE + '">WRITE</span> '
+ '<span class="' + CLS_IP + '">IP</span> '
+ '<span class="' + CLS_IP_NEXT + '">NEXT IP</span>'
+ ']</h2>');
}
var refresh = function(idx) {
if (idx != undefined) {
var td = container.find('#mem_' + idx);
var val = parseInt(td.find('.value').text());
td.children('.display').text(viewType(val));
return;
}
for (var i=0; i<vm.mem.length; i++) {
refresh(i);
}
};
this.setViewType = function(newViewType) {
if (VIEW_TYPES[newViewType] == undefined) {
throw new "Invalid viewType " + viewType;
}
viewType = VIEW_TYPES[newViewType];
refresh();
};
this.resetFlags = function() {
container.find('td').removeClass([CLS_WRITE, CLS_READ, CLS_IP, CLS_IP_NEXT].join(' '));
};
this.onMemRead = function(data) {
container.find('#mem_' + data.idx).addClass(CLS_READ);
};
this.onMemWrite = function(data) {
var td = container.find('#mem_' + data.idx);
td.find('.value').text(data.value);
td.addClass(CLS_WRITE);
refresh(data.idx);
}
this.onOP = function(data) {
container.find('#mem_' + data.ip)
.addClass(CLS_IP)
.removeClass(CLS_IP_NEXT);
container.find('#mem_' + data.nextip).addClass(CLS_IP_NEXT);
};
this.reset = function() {
container.find('table').remove();
container.append(buildTable());
};
container.append(buildHeadline(), buildTable(vm));
vm.addObserver('MEM_READ', $.proxy(this, "onMemRead"));
vm.addObserver('MEM_WRITE', $.proxy(this, "onMemWrite"));
vm.addObserver('OP', $.proxy(this, "onOP"));
};
var Controller = function(container, vmhost) {
this.getStepSize = function() {
return parseInt(stepSizeInput.val());
};
this.makeStep = function() {
vmhost.getMemoryView().resetFlags();
vmhost.getCPUView().resetFlags();
finished = vmhost.getVM().exec(this.getStepSize());
if (finished) {
simButton.hide();
stepButton.hide();
}
};
this.toggleSimulation = function() {
if (!simulation) {
simButton.val('stop simulation');
stepButton.hide();
simulation = true;
this.simulateStep();
} else {
simulation = false;
stepButton.show();
simButton.val('simulate');
}
};
this.simulateStep = function() {
if (!simulation || finished) {
return;
}
this.makeStep();
window.setTimeout(
$.proxy(this, 'simulateStep'),
Math.round(1000 / parseInt(simSpeedInput.val()))
);
};
this.changeMemoryDisplay = function() {
vmhost.getMemoryView().setViewType(changeMemoryDisplayInput.val());
};
this.reset = function() {
simulation = false;
finished = false;
simButton.show().val('simulate');
stepButton.show();
};
var simulation = false;
var finished = false;
var stepButton = $('<input type="button" value="step">').on('click', $.proxy(this, 'makeStep'));
var simButton = $('<input type="button" value="simulate">').on('click', $.proxy(this, 'toggleSimulation'));
var resetButton = $('<input type="button" value="reset">').on('click', $.proxy(vmhost, 'reset'));
var stepSizeInput = $('<input type="input" value="1" size="5">');
var simSpeedInput = $('<input type="input" value="1" size="5">');
var changeMemoryDisplayInput = $('<select><option>HEX</option><option>ASCII</option></select>').on('change', $.proxy(this, 'changeMemoryDisplay'));
container.append(
$('<h2>Control</h2>'),
$('<h3>Running/Simulation</h3>'),
$('<p>').append(
$('<span>Cycles per step:&nbsp;</span>'), stepSizeInput, '<br>',
$('<span>Steps per second:</span>'), simSpeedInput, '<br>',
stepButton,
simButton,
resetButton
),
$('<h3>Memory</h3>'),
$('<p>').append(
$('<span>Show memory as: </span>'),
changeMemoryDisplayInput
)
);
};
var OpCodeView = function(container, vm) {
var log = $('<div>').css('white-space', 'pre');
this.reset = function() {
log.text('');
};
this.onOP = function(data) {
log.prepend(
'[' + data.cycle.toString().lpad(5) + '] ' + data.message + '<br>'
);
}
vm.addObserver('OP', $.proxy(this, 'onOP'));
container.append(
'<h2>Opcode-Log</h2>',
log
);
};
var CPUView = function(container, vm) {
var CLS_WRITE = 'write';
var CLS_READ = 'read';
this.onOP = function(data) {
container.find('td.cycle').text(data.cycle);
};
this.onInterrupt = function(data) {
container.find('td.interrupt').text(data.interrupt);
};
this.onRegRead = function(data) {
container.find('#cpu_' + data.register)
.text(data.value.toHex())
.addClass(CLS_READ);
};
this.onRegWrite = function(data) {
container.find('#cpu_' + data.register)
.text(data.value.toHex())
.addClass(CLS_WRITE);
};
this.onRegRead = function(data) {
container.find('#cpu_' + data.register)
.addClass(CLS_READ);
};
this.resetFlags = function() {
container.find('td').removeClass([CLS_READ, CLS_WRITE].join(' '));
};
this.reset = function() {
container.find('div').replaceWith(buildTables());
};
function buildTables() {
var tr = $('<tr>');
var tr2 = $('<tr>');
var table = $('<table>');
for (key in vm.cpu) {
if (key == 'firmware') continue;
tr.append('<th>' + key + '</th>');
tr2.append('<td id="cpu_' + key + '">' + vm.cpu[key].toHex() + '</td>');
}
table.append(tr, tr2);
return $('<div>').append(
'<table>'
+ '<tr><th>Cycle:</th><td class="cycle">0</td></tr>'
+ '<tr><th>Interrupt:</th><td class="interrupt">None</td></tr>'
+ '</table>',
'<br>',
table
);
};
vm.addObserver('OP', $.proxy(this, 'onOP'));
vm.addObserver('INTERRUPT', $.proxy(this, 'onInterrupt'));
vm.addObserver('REG_WRITE', $.proxy(this, 'onRegWrite'));
vm.addObserver('REG_READ', $.proxy(this, 'onRegRead'));
container.append(
'<h2>CPU</h2>',
buildTables()
);
}
var VMHost = function(vm, container) {
var MEM_ID = 'memory';
var CTRL_ID = 'control';
var OPC_ID = 'opcodes';
var CPU_ID = 'cpu';
this.getMemoryView = function() {
return memoryView;
};
this.getOpcodeView = function() {
return opCodeView;
};
this.getCPUView = function() {
return cpuView;
};
this.getVM = function() {
return vm;
};
this.reset = function() {
vm.init(VM_CPU, VM_MEM);
controlView.reset();
memoryView.reset();
opCodeView.reset();
cpuView.reset();
}
var container = container || $('body');
// create control view
var controlViewContainer = $('<div>').attr('id', CTRL_ID);
var controlView = new Controller(controlViewContainer, this);
// create memory view
var memoryViewContainer = $('<div>').attr('id', MEM_ID);
var memoryView = new MemoryView(memoryViewContainer, vm);
var opCodeContainer = $('<div>').attr('id', OPC_ID);
var opCodeView = new OpCodeView(opCodeContainer, vm);
var cpuContainer = $('<div>').attr('id', CPU_ID);
var cpuView = new CPUView(cpuContainer, vm);
container.append(
opCodeContainer,
memoryViewContainer,
$('<div class="column">').append(
cpuContainer,
'<hr>',
controlViewContainer
)
);
};
$(document).ready(function() {
VM.init(VM_CPU, VM_MEM);
controller = new VMHost(VM, $('#solution'));
});
</script>
<div id="solution"></div>
<div id="footer">
<hr />
<p>solution to <a href="http://www.canyoucrackit.co.uk/15b436de1f9107f3778aad525e5d0b20.js">canyoucrackit.co.uk#2</a><br>
contact <a href="http://benjamin-zikarsky.de">benjamin-zikarsky.de</a><br />
tested in chrome, ff</p>
</div>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment