// Control Word `define BIT_MEM_EN 0 `define BIT_PC_INC 1 `define BIT_ACC_WR 2 `define BIT_ACC_EN 3 `define BIT_LOAD_INSTR 4 `define BIT_MAR_WR 5 `define BIT_REG_WR 6 `define BIT_ALU_EN 7 `define BIT_PC_EN 8 `define BIT_MAR_EN 9 `define BIT_MEM_WR 10 `define BIT_PC_WR 11 `define BIT_FLAGS_WR 12 `define BIT_TIMER_RST 14 `define BIT_HLT 15 // Flags `define BIT_ZERO 0 `define BIT_CARRY 1 `define MEM_EN (16'b1 << `BIT_MEM_EN) `define PC_INC (16'b1 << `BIT_PC_INC) `define ACC_WR (16'b1 << `BIT_ACC_WR) `define ACC_EN (16'b1 << `BIT_ACC_EN) `define MAR_WR (16'b1 << `BIT_MAR_WR) `define LOAD_INSTR (16'b1 << `BIT_LOAD_INSTR) `define REG_WR (16'b1 << `BIT_REG_WR) `define ALU_EN (16'b1 << `BIT_ALU_EN) `define PC_EN (16'b1 << `BIT_PC_EN) `define MAR_EN (16'b1 << `BIT_MAR_EN) `define MEM_WR (16'b1 << `BIT_MEM_WR) `define PC_WR (16'b1 << `BIT_PC_WR) `define FLAGS_WR (16'b1 << `BIT_FLAGS_WR) `define TIMER_RST (16'b1 << `BIT_TIMER_RST) `define HLT (16'b1 << `BIT_HLT) `define ZERO (4'b1 << `BIT_ZERO) `define CARRY (4'b1 << `BIT_CARRY) module ProgramCounter( inout [11:0] addr, input inc, input en, input wr, input clk, input rst ); reg [11:0] value = 0; always@ (posedge clk or posedge rst) begin if (rst) value <= 0; else if (wr && !en) value <= addr; else if (inc) value <= value + 1; end assign addr = en && !wr ? value : 12'hzzz; endmodule // ProgramCounter module Register( output reg [7:0] data_out = 0, input [7:0] data_in, input wr, input clk, input rst ); always@ (posedge clk or posedge rst) begin if (rst) data_out <= 0; else if (wr) data_out <= data_in; end endmodule // Register module Accumulator( inout [7:0] bus, output [7:0] out, input clk, input rst, input wr, input en ); reg [7:0] value = 0; always@ (posedge clk or posedge rst) begin if (rst) value <= 0; else if (wr && !en) value <= bus; end assign out = value; assign bus = (!wr && en) ? value : 8'hzz; endmodule // Accumulator module InstructionDecoder( input [3:0] timer, input [7:0] instr, input clk, output reg [`BIT_HLT:0] control_word ); wire [`BIT_HLT:0] cw_instr [15:0] [15:2]; // hlt assign cw_instr[4'b0000][4'b0010] = `HLT; // lda imm8 assign cw_instr[4'b0001][4'b0010] = `PC_EN | `MEM_EN | `ACC_WR; assign cw_instr[4'b0001][4'b0011] = `PC_INC | `TIMER_RST; // alu imm8 assign cw_instr[4'b0010][4'b0010] = `PC_EN | `MEM_EN | `REG_WR; assign cw_instr[4'b0010][4'b0011] = `PC_INC | `ALU_EN | `ACC_WR | `TIMER_RST; // rb imm12 assign cw_instr[4'b0011][4'b0010] = `PC_EN | `MEM_EN | `MAR_WR; assign cw_instr[4'b0011][4'b0011] = `PC_INC | `MAR_EN | `MEM_EN | `ACC_WR | `TIMER_RST; // wb imm12 assign cw_instr[4'b0100][4'b0010] = `PC_EN | `MEM_EN | `MAR_WR; assign cw_instr[4'b0100][4'b0011] = `PC_INC | `MAR_EN | `MEM_WR | `ACC_EN | `TIMER_RST; // jmp imm12 assign cw_instr[4'b0101][4'b0010] = `PC_EN | `MEM_EN | `MAR_WR; assign cw_instr[4'b0101][4'b0011] = `MAR_EN | `PC_WR | `TIMER_RST; always@ (negedge clk) case (timer) 4'b0000: control_word <= `PC_EN | `MEM_EN | `LOAD_INSTR; 4'b0001: control_word <= `PC_INC; default: control_word <= cw_instr[instr[7:4]][timer]; endcase endmodule // InstructionDecoder module ALU( input [7:0] in_a, input [7:0] in_b, input [3:0] funct, input [3:0] flags_in, output [7:0] out, output [3:0] flags_out, input en ); reg [8:0] result; always@ (*) begin case (funct) 4'b0000: result = in_a + in_b; 4'b0001: result = in_a - in_b; 4'b0010: result = { 1'b0, in_a & in_b }; 4'b0011: result = { 1'b0, in_a | in_b }; 4'b0100: result = { 1'b0, in_a ^ in_b }; 4'b0101: result = { 1'b0, in_a << in_b }; 4'b0110: result = { 1'b0, in_a >> in_b }; 4'b0111: result = { 1'b0, in_a >>> in_b }; default: result = 9'bx; endcase end assign flags_out[`BIT_ZERO] = result[7:0] == 0; assign flags_out[`BIT_CARRY] = result[8]; assign out = en ? result[7:0] : 8'bz; endmodule // ALU module CPU( output [11:0] addr_out, inout [7:0] bus, output [7:0] debug, output mem_wr, output mem_en, output reg hlt = 0, input clk, input rst ); wire [`BIT_HLT:0] control_word; wire [7:0] instr; wire [7:0] alu_in_a; wire [7:0] alu_in_b; wire [3:0] flags_alu; reg [3:0] timer = 0; reg [11:0] mar; reg [3:0] flags; assign debug = instr; ProgramCounter _pc( .addr(addr_out), .inc(control_word[`BIT_PC_INC]), .en(control_word[`BIT_PC_EN]), .wr(control_word[`BIT_PC_WR]), .clk(clk), .rst(rst) ); Register _ireg( .data_in(bus), .data_out(instr), .wr(control_word[`BIT_LOAD_INSTR]), .clk(clk), .rst(rst) ); InstructionDecoder _idec( .instr(instr), .clk(clk), .timer(timer), .control_word(control_word) ); Accumulator _acc( .bus(bus), .out(alu_in_a), .clk(clk), .rst(rst), .wr(control_word[`BIT_ACC_WR]), .en(control_word[`BIT_ACC_EN]) ); Register _reg( .data_in(bus), .data_out(alu_in_b), .clk(clk), .rst(rst), .wr(control_word[`BIT_REG_WR]) ); ALU _alu( .in_a(alu_in_a), .in_b(alu_in_b), .funct(instr[3:0]), .out(bus), .flags_in(flags), .flags_out(flags_alu), .en(control_word[`BIT_ALU_EN]) ); assign addr_out = control_word[`BIT_MAR_EN] ? mar : 12'hzzz; assign mem_wr = control_word[`BIT_MEM_WR]; assign mem_en = control_word[`BIT_MEM_EN]; always@ (posedge clk or posedge rst) if (rst) flags <= 0; else if (control_word[`BIT_FLAGS_WR]) flags <= flags_alu; always@ (posedge clk or posedge rst) if (rst) hlt <= 0; else if (control_word[`BIT_HLT]) hlt <= 1; always@ (posedge clk) if (control_word[`BIT_MAR_WR]) mar <= { instr[3:0], bus }; always@ (posedge clk or posedge rst) if (rst) timer <= 0; else if (control_word[`BIT_TIMER_RST]) timer <= 0; else timer <= timer + 1; endmodule // CPU