3 / 24 · Lab
Lab: an eight-bit ALU reference model
Check ADD, SUB, AND, XOR, carry, and borrow in a standalone executable.
Lessons are free to read. Enroll to save your learning progress.
Make the numeric contract executable
This lab models a combinational ALU using JavaScript integers. Operands range from 0 to 255, with operations 0 through 3. Output y always fits eight bits. The flag means ADD carry or SUB borrow and is zero for logical operations. In this interface, borrow is one when a is smaller than b. Other architectures may define subtraction flags differently; our contract is explicit.
Create a local folder, or manually create a blank project and add alu-model.mjs in Digital Design Studio. Save the following file. In a terminal with Node.js installed, enter the folder and run node alu-model.mjs. Editing a file in DDS and executing JavaScript are separate actions. No package installation or automatic import feature is required.
import assert from 'node:assert/strict';
function alu(a, b, op) {
if (op === 0) {
const wide = a + b;
return { y: wide & 255, flag: Number(wide > 255) };
}
if (op === 1) return { y: (a - b) & 255, flag: Number(a < b) };
if (op === 2) return { y: a & b, flag: 0 };
if (op === 3) return { y: a ^ b, flag: 0 };
throw new RangeError('operation');
}
assert.deepEqual(alu(250, 10, 0), { y: 4, flag: 1 });
assert.deepEqual(alu(3, 5, 1), { y: 254, flag: 1 });
assert.deepEqual(alu(170, 204, 2), { y: 136, flag: 0 });
assert.deepEqual(alu(170, 204, 3), { y: 102, flag: 0 });
let checks = 0;
for (let a = 0; a < 256; a++) {
for (let b = 0; b < 256; b++) {
const add = alu(a, b, 0), sub = alu(a, b, 1);
assert.equal(add.y + 256 * add.flag, a + b);
assert.equal(sub.y - 256 * sub.flag, a - b);
assert.equal(alu(a, b, 2).y | alu(a, b, 3).y, a | b);
checks += 3;
}
}
console.log(`ALU PASS: ${checks} identities`);For 250+10, y=4 and carry=1 reconstruct 260. For 3-5, y=254 and borrow=1 reconstruct -2. Binary 170 is 10101010 and 204 is 11001100: AND gives 136 and XOR gives 102. The loop visits all 65536 operand pairs and checks three identities per pair. A successful run reports 196608 checks.
Use a different method in the reference model than in the RTL. If hardware extracts carry from a nine-bit adder, this model checks the mathematical range. That reduces shared implementation mistakes. These checks do not evaluate HDL X/Z values, propagation timing, or clock behavior. Reuse the vectors in a simulator when implementing the RTL. Always compare flags as well as data; correct wrapping bits can hide an incorrect boundary flag.
Try it yourself
If SUB always returns flag=0, which numeric identity fails? Check a=0, b=1 by hand and restore the implementation.
Read the explanation
y is 255. With flag=0, y-256×flag is 255 instead of -1, so the subtraction reconstruction fails. With borrow=1, 255-256=-1. Checking y alone would miss this error.