Practice
Coating Booth Recipe Core
A PCB coating booth at Bexley Circuits follows compact spray-and-cure recipes. A tiny custom processor reads each program and controls the steps that protect every panel.
The chip died, and nobody sells it now. Its 32-byte recipe programs survive in a yellow service binder, beside a manual for eight instructions.
The manual also specifies one accumulator and two clocks per instruction.
The booth's spare FPGA gets the rebuild. If the core runs those programs exactly, the booth sprays again. If one opcode drifts, panels leave the blue rack tacky.
Your task: build recipe_core, the executing core. The booth's bench supplies the recipe ROM and data memory. The programs are the judge.
Interface
| Port | Direction | Type | Description |
|---|---|---|---|
| clk | in | 1 bit | Clock |
| rst | in | 1 bit | Synchronous reset, active high |
| fetch | out | 1 bit | High during the fetch phase |
| imem_addr | out | 5-bit vector | Program counter presented to the recipe ROM |
| imem_data | in | 8-bit vector | Instruction word returned by the recipe ROM |
| dmem_addr | out | 5-bit vector | Operand during execute, zero during fetch |
| dmem_rdata | in | 8-bit vector | Data memory read value |
| dmem_wdata | out | 8-bit vector | Store data, carrying acc while STA executes |
| dmem_we | out | 1 bit | High only while a store executes |
| acc | out | 8-bit vector | Accumulator, visible for the waveform |
Behavior
- The core alternates fetch and execute, completing one instruction every two clocks
- During fetch, fetch is high, imem_addr presents the current PC, dmem_addr is zero, and dmem_we is low
- At the rising edge ending fetch, imem_data is captured into the instruction register
- PC and acc hold across that fetch edge, then the core enters execute
- During execute, fetch is low, and the captured instruction's bits 4..0 drive dmem_addr
- At the rising edge ending execute, the operation completes, PC updates, and the core returns to fetch
- The instruction word uses bits 7..5 for the opcode and bits 4..0 for operand k or address a
- 000 LDI: acc becomes k, zero-extended from five bits to eight
- 001 LDA: acc becomes dmem_rdata from address a
- 010 STA: data at address a becomes acc; acc itself does not change
- During an STA execute phase, dmem_we is high and dmem_wdata carries acc
- The store commits on the rising edge ending that execute phase
- 011 ADD: acc becomes acc plus dmem_rdata from address a, modulo 256
- 100 SUB: acc becomes acc minus dmem_rdata from address a, modulo 256
- 101 XOR: acc becomes acc xor dmem_rdata from address a
- 110 JZ: if acc is zero, PC becomes a; otherwise PC steps
- JZ tests the acc value from before its own execute edge and does not change acc
- 111 JMP: PC becomes a, regardless of acc, and acc does not change
- A taken JZ and every JMP load address a into PC
- After every other instruction, PC increments by one, wrapping modulo 32
- There is no halt instruction; a finished recipe parks on a JMP to its own address
- rst high at a rising edge sets PC and acc to zero, makes the next phase fetch, and forces dmem_we low
- A reset edge performs no instruction or store, and no prior state carries over
What the bench checks
- The bench checks reset state, fetch startup, and cancellation during either phase
- It checks the exact fetch and execute sequence, including PC and acc holding during fetch
- It runs all eight opcodes against external recipe ROM and data memory models
- It checks zero extension, modulo arithmetic, and accumulator preservation for stores and branches
- It checks sequential PC steps, modulo-32 wrapping, taken branches, and untaken JZ instructions
- It changes acc around JZ cases to confirm the branch uses its pre-edge value
- It checks store address, data, edge timing, and that dmem_we never appears outside STA execute
Constraints
everything is synchronous to clk. Outputs are registers or direct decodes of registers. dmem_we must never glitch high outside a store's execute phase.
the recipe ROM and data memory live outside recipe_core. The booth's bench supplies both memories; this challenge covers only the executing core.
Do not add ports.
Click Run to execute your code. Output will appear here.