Master the fundamental concepts of cpu design through this focused micro-challenge.
You have read the whole brief, and the concepts above stay free on every task. Writing and running the code needs a plan.
Three hints are available for this task, revealed one at a time inside the code workspace so you can struggle productively before seeing them.
Every task includes starter code, theory, and hidden tests so you can implement and verify locally in the browser.
How it worksBranch instructions compare flags or registers and overwrite the program counter when a condition is true. Without branches, programs are straight-line calculators; with them, CPUs can loop, branch on error, and implement if/else.
| Opcode | Condition | PC update |
|---|---|---|
| JMP | always | PC = target |
| JEQ | Z == 1 | PC = target if zero |
| JGT | N xor V == 0 and Z == 0 | taken if greater (signed) |
cLoading…
Branches are cheap in your sequential emulator but expensive in pipelined hardware because the fetch stage may already pull wrong-path instructions. Later tasks add predictors and flushes.
For this exercise, you will implement JMP, JEQ, and JGT using the flag bits from your ALU. You will need correct PC writes to run a counting loop that terminates when a register hits zero.
Keep the relevant datasheet, ISA manual, or architecture textbook chapter open while you implement. When your output disagrees with the reference trace on the same program, the bug is usually a mis-decoded opcode, a stale register read, or a flag bit left unchanged after arithmetic.
For this exercise, you will use those habits while implementing the requirement in the starter code. Microarchitectural product names change across CPU generations, but the control ideas (fetch, bypass, cache lines, vector lanes) stay stable enough to debug from first principles.
Add branches to the toy CPU so it can loop and decide. A two-pass assembler resolves label: names to instruction addresses. CMP sets comparison flags. JMP, JEQ and JGT load a new PC, the latter two only when their condition holds. Run the program and report its output and how many branches were taken.
Four 8-bit registers R0: R3 (start at 0, arithmetic wraps modulo 256) and two flags EQ, GT (start at 0).
| Instruction | Effect |
|---|---|
MOV Rd, imm | Rd = imm (0..255) |
ADD Rd, Rs / SUB Rd, Rs | Rd = Rd ± Rs |
CMP Ra, Rb | EQ = (Ra == Rb), GT = (Ra > Rb) (unsigned) |
JMP label | PC = label |
JEQ label | if EQ: PC = label |
JGT label | if GT: PC = label |
OUT Rd | print Rd in decimal on its own line |
HALT | stop |
Only CMP changes the flags.
One instruction per line. A line may start with label:, and may consist of only a label. Labels name the address of the next instruction. Blank lines are ignored.
The OUT lines, then one of:
cLoading…
N counts executed instructions (including HALT). JMP always counts as taken. If assembly fails, print only error line L: MESSAGE for the first failing line (L counts every input line from 1), where MESSAGE is unknown instruction WORD, bad operands, duplicate label NAME or undefined label NAME. Undefined labels are found in the second pass, so they are reported only if every line passes the first pass.
Input:
cLoading…
Output:
cLoading…
PC; the fetch step increments PC before execution.Hidden tests cover JEQ, a label on the same line as an instruction, a forward jump, a loop that sums numbers, falling off the end, and a program that jumps to an undefined label.