`timescale 1us/1us `include "eater_types.sv" module eater_decoder ( input clk_i, input wire [7:0] instruction_i, output CpuControlFlags flags_o ); CpuState internal_state /* verilator public_flat_rd */; CpuState next_state; CpuControlFlags internal_flags; wire [3:0] actual_instruction = instruction_i[7:4]; assign flags_o = internal_flags; initial begin internal_state = INIT; next_state = INIT; // assigned in always_comb // internal_flags = '{default: '0}; end function CpuState insdep_state; case (actual_instruction) NOP: insdep_state = PC_to_MAR; LDA: insdep_state = LDA_INS_to_MAR; ADD: insdep_state = ADD_INS_to_MAR; SUB: insdep_state = SUB_INS_to_MAR; STA: insdep_state = STA_INS_to_MAR; LDI: insdep_state = LDI_INS_to_A; JMP: insdep_state = JMP_INS_to_PC; OUT: insdep_state = OUT_A_to_OUT; HALT_op: insdep_state = HALT_st; default: insdep_state = INIT; endcase endfunction // next-state machine always @(posedge clk_i) begin next_state = INIT; case (internal_state) INIT: next_state = PC_to_MAR; PC_to_MAR: next_state = MEM_to_INS; MEM_to_INS: next_state = PC_inc; PC_inc: next_state = insdep_state(); LDA_INS_to_MAR: next_state = LDA_MEM_to_A; LDA_MEM_to_A: next_state = PC_to_MAR; ADD_INS_to_MAR: next_state = ADD_MEM_to_B; ADD_MEM_to_B: next_state = ADD_ALU_to_A; ADD_ALU_to_A: next_state = PC_to_MAR; SUB_INS_to_MAR: next_state = SUB_MEM_to_B; SUB_MEM_to_B: next_state = SUB_ALU_to_A; SUB_ALU_to_A: next_state = PC_to_MAR; STA_INS_to_MAR: next_state = STA_A_to_MEM; STA_A_to_MEM: next_state = PC_to_MAR; LDI_INS_to_A: next_state = PC_to_MAR; JMP_INS_to_PC: next_state = PC_to_MAR; JMP_NOP: next_state = PC_to_MAR; OUT_A_to_OUT: next_state = PC_to_MAR; HALT_st: next_state = HALT_st; 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 LDA_INS_to_MAR: begin internal_flags.INS_out = 1; internal_flags.MAR_in = 1; end LDA_MEM_to_A: begin internal_flags.RAM_out = 1; internal_flags.A_in = 1; end ADD_INS_to_MAR: begin internal_flags.INS_out = 1; internal_flags.MAR_in = 1; end ADD_MEM_to_B: begin internal_flags.RAM_out = 1; internal_flags.B_in = 1; end ADD_ALU_to_A: begin internal_flags.ALU_out = 1; internal_flags.A_in = 1; end SUB_INS_to_MAR: begin internal_flags.INS_out = 1; internal_flags.MAR_in = 1; end SUB_MEM_to_B: begin internal_flags.RAM_out = 1; internal_flags.B_in = 1; end SUB_ALU_to_A: begin internal_flags.ALU_out = 1; internal_flags.ALU_subtract_nadd = 1; internal_flags.A_in = 1; end STA_INS_to_MAR: begin internal_flags.INS_out = 1; internal_flags.MAR_in = 1; end STA_A_to_MEM: begin internal_flags.RAM_in = 1; internal_flags.A_out = 1; end LDI_INS_to_A: begin internal_flags.INS_out = 1; internal_flags.A_in = 1; end JMP_INS_to_PC: begin internal_flags.INS_out = 1; internal_flags.PC_in = 1; end JMP_NOP: begin end OUT_A_to_OUT: begin internal_flags.A_out = 1; internal_flags.OUT_in = 1; end HALT_st: begin internal_flags.halt = 1; end default: begin end endcase end endmodule