summaryrefslogtreecommitdiff
path: root/eater_cpu/eater_decoder.sv
diff options
context:
space:
mode:
authoruvok2026-01-19 15:51:28 +0100
committeruvok2026-01-19 15:51:28 +0100
commitbde4ea4d677ca2e39450f972c3e692893f1e52b3 (patch)
tree68a1beb334cec09a53821105e6a16684b1483764 /eater_cpu/eater_decoder.sv
parentb99a9872b2d6cb5a0abedfdb33125dc6274f1c1d (diff)
Add instruction decoder with FSM
Diffstat (limited to 'eater_cpu/eater_decoder.sv')
-rw-r--r--eater_cpu/eater_decoder.sv92
1 files changed, 92 insertions, 0 deletions
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