Published
Edited
Aug 10, 2022
8 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
disassemble = (t) => {
const program = [];
const bytes = d3
.pairs(t.split(""))
.filter((d, i) => i % 2 === 0)
.map((p) => p.join(""));

let inst,
acc = 0,
bb,
j;
for (let i = 0; i < bytes.length; i++) {
const b = bytes[i];
if (acc === 0) {
j = i;
[inst, acc] = CPU8080.disasm(parseInt(b, 16));
bb = "";
} else bb = `${b}${bb}`;

if (--acc === 0)
program.push([
("0000" + j.toString(16).toUpperCase()).slice(-4),
b,
inst.replace(/[$]00+/, bb)
]);
}

return md`| byte | code | instruction
|-:|:-:|:-
${program.map((d) => `| ${d.join(" | ")}`).join("\n")}`;
}
Insert cell
show = () => {
// slightly adapted from https://www.quaxio.com/kaleidoscope_part1/
const size = Math.floor(width / 64);
const ctx = DOM.context2d(64 * size, 64 * size, 1);

// clear canvas
ctx.fillStyle = "#000000";
ctx.fillRect(0, 0, 64 * size, 64 * size);

// memory is simply an array
let memory = [];

// videoOffset gets set when portTo is called with addr 14
let videoOffset = -1;

// copy code into memory
for (let i = 0; i < kaleidoscope.length; i += 2) {
let byte = parseInt(kaleidoscope.substr(i, 2), 16);
memory[i / 2] = byte;
}

// callback used by 8080.js to write to memory.
function memoryTo(addr, value) {
memory[addr] = value;

if (addr >= videoOffset) {
// convert addr to two pixels and draw them. First find the quadrant
let memOffset = addr - videoOffset;
let quad = (memOffset / 512) | 0;
let i = (quad % 2) * 32;
let j = ((quad / 2) | 0) * 32;
memOffset = memOffset % 512;

// convert memOffset to offset within quadrant
i += (memOffset % 16) * 2;
j += (memOffset / 16) | 0;

// draw the two pixels defined by the value
drawPixel(i, j, value);
drawPixel(i + 1, j, value >> 4);
}
}

function drawPixel(i, j, data) {
// the lower four bits encode the following information:
// | 3 | 2 | 1 | 0 |
// | hi/lo | blue | green | red |
let style = "#";
let intensity = data & 0x8 ? "ff" : "7f";
style += data & 0x1 ? intensity : "00";
style += data & 0x2 ? intensity : "00";
style += data & 0x4 ? intensity : "00";
ctx.fillStyle = style;
ctx.fillRect(i * size + 2, j * size + 2, size - 4, size - 4);
}

// callback used by 8080.js to read from memory.
function memoryAt(addr) {
return memory[addr];
}

// unused
function ticker(T) {}

// callback used to write to a peripheral
function portTo(addr, value) {
switch (addr) {
case 14:
videoOffset = (value & 0x7f) << 9;
break;
case 15:
// we only support one mode (64x64 color), so we don't need to
// do anything.
break;
default:
throw new Error("unexpected portTo");
}
}

// callback used to read from a peripheral
function portAt(addr) {
throw new Error("unexpected portAt");
}

// initialize 8080 simulator
CPU8080.init(memoryTo, memoryAt, ticker, portTo, portAt);

// run at 33333 steps per animationFrame, which translates to roughly 2Mhz,
// which was to the best of my knowledge, the clock speed of the Altair 8800.
let frame;
function go() {
CPU8080.steps((viewof clockSpeed.value * 1e6) / 60);
return (frame = window.requestAnimationFrame(go));
}
go();
invalidation.then(() => cancelAnimationFrame(frame));

return ctx.canvas;
}
Insert cell
CPU8080 = {
let exports = {};
await fetch("https://raw.githubusercontent.com/maly/8080js/master/8080.js")
.then((d) => d.text())
.then((t) =>
eval(`
let T; // fixes a missing declaration in maly’s code
${t}
`)
);
return exports;
}
Insert cell
bytes = (t) => {
const view = d3
.pairs(t.split(""))
.filter((d, i) => i % 2 === 0)
.map((d) => d.join(""))
.join(" ");
return Object.assign(
html`<p style="font-family: monospace; font-size:small;">${view}`,
{ value: t }
);
}
Insert cell

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more