summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoruvok2026-01-19 15:51:28 +0100
committeruvok2026-01-19 15:51:28 +0100
commitbde4ea4d677ca2e39450f972c3e692893f1e52b3 (patch)
tree68a1beb334cec09a53821105e6a16684b1483764
parentb99a9872b2d6cb5a0abedfdb33125dc6274f1c1d (diff)
Add instruction decoder with FSM
-rw-r--r--eater_cpu/Makefile4
-rw-r--r--eater_cpu/eater_computer.sv7
-rw-r--r--eater_cpu/eater_decoder.sv92
3 files changed, 101 insertions, 2 deletions
diff --git a/eater_cpu/Makefile b/eater_cpu/Makefile
index 9145135..ab0e7b1 100644
--- a/eater_cpu/Makefile
+++ b/eater_cpu/Makefile
@@ -1,4 +1,4 @@
-cpu: eater_computer_tb.sv eater_computer.sv zbuffer.sv eater_register.v eater_alu.sv ../playground/my_mem.v ../nandgame/counter.sv
+cpu: eater_computer_tb.sv eater_computer.sv zbuffer.sv eater_register.v eater_alu.sv eater_decoder.sv ../playground/my_mem.v ../nandgame/counter.sv
iverilog -o $@ -g2012 -DIVERILOG $^
HARDWARE_SUFFIX := .sv
@@ -10,7 +10,7 @@ include ../common.mk
.PHONY: simpc
simpc: simpc/Vcomputer
-simpc/Vcomputer: eater_computer.sv zbuffer.sv eater_register.v eater_alu.sv ../playground/my_mem.v ../nandgame/counter.sv
+simpc/Vcomputer: eater_computer.sv zbuffer.sv eater_register.v eater_alu.sv eater_decoder.sv ../playground/my_mem.v ../nandgame/counter.sv
#computer.sv cpp/Vcomputer__main.cpp cpp/disas.cpp cpp/simpc_ui.cpp
# -CFLAGS "-I${PWD}/cpp"
verilator \
diff --git a/eater_cpu/eater_computer.sv b/eater_cpu/eater_computer.sv
index f7f0952..f9104af 100644
--- a/eater_cpu/eater_computer.sv
+++ b/eater_cpu/eater_computer.sv
@@ -165,4 +165,11 @@ eater_register OUT (
.always_out(OUT_out)
);
+eater_decoder decoder (
+ .clk_i(clk_in),
+ .instruction_i(INS_out),
+ .enable_control_i(0),
+ .flags_o()
+);
+
endmodule
diff --git a/eater_cpu/eater_decoder.sv b/eater_cpu/eater_decoder.sv
new file mode 100644
index 0000000..d6b6c4c
--- /dev/null
+++ b/eater_cpu/eater_decoder.sv
@@ -0,0 +1,92 @@
+`timescale 1us/1us
+
+`include "eater_types.sv"
+
+module eater_decoder (
+ input clk_i,
+ input wire enable_control_i,
+ input wire [7:0] instruction_i,
+ output CpuControlFlags flags_o
+);
+
+CpuState internal_state;
+CpuState next_state;
+CpuControlFlags internal_flags;
+
+always_comb begin
+ if (enable_control_i) begin
+ flags_o = internal_flags;
+ end else begin
+`ifdef IVERILOG
+ flags_o = 'bz;
+`else
+ flags_o = '{default: 'z};
+`endif
+ end
+end
+
+initial begin
+ internal_state = INIT;
+ next_state = INIT;
+ // assigned in always_comb
+ // internal_flags = '{default: '0};
+end
+
+// next-state machine
+always @(posedge clk_i) begin
+ next_state = INIT;
+
+ case (internal_state)
+ INIT: begin
+ next_state = PC_to_MAR;
+ end
+ PC_to_MAR: begin
+ next_state = MEM_to_INS;
+ end
+
+ MEM_to_INS: begin
+ next_state = PC_inc;
+ end
+
+ PC_inc: begin
+ next_state = PC_to_MAR;
+ end
+
+ default: begin
+ next_state = INIT;
+ end
+
+ endcase
+ internal_state <= next_state;
+end
+
+// current-state-to-flags machine
+// TODO: This is kinda weird, I *can* set "all flags" to zero "in the beginning",
+// and then only set the required flags "later".
+// how does that work combinatorically???
+always_comb begin
+`ifdef IVERILOG
+ internal_flags = 'b0;
+`else
+ internal_flags = '{default: '0};
+`endif
+
+ case (internal_state)
+ // INIT: // left out
+ PC_to_MAR: begin
+ internal_flags.PC_out = 1;
+ internal_flags.MAR_in = 1;
+ end
+ MEM_to_INS: begin
+ internal_flags.RAM_out = 1;
+ internal_flags.INS_in = 1;
+ end
+ PC_inc: begin
+ internal_flags.PC_count = 1;
+ end
+ default: begin
+ end
+ endcase
+end
+
+endmodule