commit 0f8a33c12038f8491d6d3b4875c6422740111767
parent 071a08bb2b8bfdd304142613b37e5d6664df99b3
Author: Brian Swetland <swetland@frotz.net>
Date: Thu, 9 Feb 2012 20:43:44 -0800
cpu/control: start tidying up
Diffstat:
2 files changed, 93 insertions(+), 35 deletions(-)
diff --git a/verilog/control.v b/verilog/control.v
@@ -1,3 +1,15 @@
+// Copyright 2012, Brian Swetland. Use at your own risk.
+
+`define PC_SRC_NEXT 2'b00 // normal
+`define PC_SRC_B_IMM 2'b01 // on immediate branches
+`define PC_SRC_B_REG 2'b10 // on indirect branches
+`define PC_SRC_X 2'b11 // unspecified
+
+`define W_SRC_ALU 2'b00 // normal
+`define W_SRC_RAM 2'b01 // on ram read ops
+`define W_SRC_PC_NEXT 2'b10 // on branch link ops
+`define W_SRC_X 2'b11 // unspecified
+
module control (
input [3:0] opcode,
input [3:0] opfunc,
@@ -6,35 +18,80 @@ module control (
output ctl_ram_we,
output ctl_ram_rd,
output ctl_d_or_b,
- output ctl_branch,
- output ctl_branch_ind,
output ctl_imm16,
+ output reg [1:0] ctl_pc_src,
+ output reg [1:0] ctl_wdata_src,
output [3:0] ctl_alu_func
);
+reg ctl_branch;
+
+wire ctl_branch_op;
+wire ctl_branch_ind;
wire ctl_ram_op;
+wire ctl_regs_we_;
+
+reg [7:0] control;
+
+always @ (*)
+ case (opcode)
+ 4'b0000: control = 8'b01000000; // ALU Rd, Ra, Rb
+ 4'b0001: control = 8'b01001100; // ALU Rd, Ra, #I
+ 4'b0010: control = 8'b01101100; // LW Rd, [Ra, #]
+ 4'b0011: control = 8'b00010100; // SW Rd, [Ra, #]
+ 4'b0100: control = 8'b10001100; // B* rel16
+ 4'b0101: control = 8'b10000100; // B* Rb
+ 4'b0110: control = 8'b00000000;
+ 4'b0111: control = 8'b00000000;
+ 4'b1000: control = 8'b00000000;
+ 4'b1001: control = 8'b00000000;
+ 4'b1010: control = 8'b00000000;
+ 4'b1011: control = 8'b00000000;
+ 4'b1100: control = 8'b00000000;
+ 4'b1101: control = 8'b00000000;
+ 4'b1110: control = 8'b00000000;
+ 4'b1111: control = 8'b00000000;
+ endcase
+
+assign { ctl_branch_op, ctl_regs_we_, ctl_ram_rd, ctl_ram_we, ctl_d_or_b, ctl_imm16 } = control[7:2];
+
+wire ctl_cond_z;
+wire ctl_cond_nz;
wire ctl_link_bit;
-// cheesy decoder -- TODO: write for real
-assign ctl_regs_we =
- (opcode[3:1] == 3'h0) ||
- (opcode == 4'h2) ||
- (ctl_branch && ctl_link_bit) ||
- (ctl_branch_ind && ctl_link_bit);
-assign ctl_d_or_b = ((opcode == 4'h1) || (opcode == 4'h2) || (opcode == 4'h4));
-assign ctl_ram_rd = (opcode == 4'h2);
-assign ctl_ram_we = (opcode == 4'h3);
-assign ctl_ram_op = ((opcode == 4'h2) || (opcode == 4'h3));
-assign ctl_alu_func = ctl_ram_op ? 4'b0010 : opfunc;
-assign ctl_imm16 = (opcode != 4'h0);
+assign ctl_cond_z = opfunc[0];
+assign ctl_cond_nz = opfunc[1];
assign ctl_link_bit = opfunc[3];
+assign ctl_branch_ind = opcode[0];
+
+always @ (*)
+ case ( { ctl_branch_op, ctl_cond_z, ctl_cond_nz, ctl_adata_zero } )
+ 4'b1110: ctl_branch = 1'b1;
+ 4'b1111: ctl_branch = 1'b1;
+ 4'b1101: ctl_branch = 1'b1;
+ 4'b1010: ctl_branch = 1'b1;
+ default: ctl_branch = 1'b0;
+ endcase
+
+always @ (*)
+ case ( { ctl_branch, ctl_branch_ind } )
+ 2'b00: ctl_pc_src = `PC_SRC_NEXT;
+ 2'b01: ctl_pc_src = `PC_SRC_NEXT;
+ 2'b10: ctl_pc_src = `PC_SRC_B_IMM;
+ 2'b11: ctl_pc_src = `PC_SRC_B_REG;
+ endcase
+
+always @ (*)
+ case ( { ctl_branch, ctl_ram_rd } )
+ 2'b00: ctl_wdata_src = `W_SRC_ALU;
+ 2'b01: ctl_wdata_src = `W_SRC_RAM;
+ 2'b10: ctl_wdata_src = `W_SRC_PC_NEXT;
+ 2'b11: ctl_wdata_src = `W_SRC_PC_NEXT;
+ endcase
+
+assign ctl_alu_func = (ctl_ram_rd | ctl_ram_we) ? 4'b0010 : opfunc;
-// branch if it is a branch opcode and the condition is met
-// unconditional branches set both condition bits
-assign ctl_branch = (opcode == 4'h4) &
- ((opfunc[0] & ctl_adata_zero) || (opfunc[1] & (!ctl_adata_zero)));
-assign ctl_branch_ind = (opcode == 4'h5) &
- ((opfunc[0] & ctl_adata_zero) || (opfunc[1] & (!ctl_adata_zero)));
+assign ctl_regs_we = ctl_regs_we_ | (ctl_branch & ctl_link_bit);
endmodule
diff --git a/verilog/cpu32.v b/verilog/cpu32.v
@@ -32,21 +32,22 @@ assign opimm16 = ir[15:0];
wire ctl_regs_we; // 1 = write back to register file
wire ctl_d_or_b; // 0 = write to R[opseld], 1 = R[opselb]
-wire ctl_branch; // 1 = direct branch
-wire ctl_branch_ind; // 1 = indirect branch
wire ctl_imm16; // 0 = bdata, 1 = imm16 -> alu right
wire [3:0] ctl_alu_func;
wire ctl_ram_we;
wire ctl_ram_rd;
+wire [1:0] ctl_wdata_src;
+wire [1:0] ctl_pc_src;
+
control control(
.opcode(opcode),
.opfunc(opfunc),
.ctl_adata_zero(ctl_adata_zero),
.ctl_regs_we(ctl_regs_we),
.ctl_d_or_b(ctl_d_or_b),
- .ctl_branch(ctl_branch),
- .ctl_branch_ind(ctl_branch_ind),
+ .ctl_pc_src(ctl_pc_src),
+ .ctl_wdata_src(ctl_wdata_src),
.ctl_imm16(ctl_imm16),
.ctl_ram_we(ctl_ram_we),
.ctl_ram_rd(ctl_ram_rd),
@@ -73,11 +74,11 @@ regfile #(32,4) REGS (
);
mux4 #(32) wdata_mux(
- .sel({ctl_branch,ctl_ram_rd}),
+ .sel(ctl_wdata_src),
.in0(result),
.in1(d_data_r),
.in2(pc_plus_4),
- .in3(pc_plus_4),
+ .in3(32'b0),
.out(wdata)
);
@@ -87,7 +88,7 @@ wire S;
assign S = opimm16[15];
mux4 #(32) pc_source(
- .sel({ctl_branch_ind,ctl_branch}),
+ .sel(ctl_pc_src),
.in0(pc_plus_4),
.in1(pc + {S,S,S,S,S,S,S,S,S,S,S,S,S,S,opimm16,2'h0} ),
.in2(bdata),
@@ -101,17 +102,17 @@ assign ir = i_data;
wire [31:0] binput;
mux2 #(32) alu_right_mux(
- .sel(ctl_imm16),
- .in0(bdata),
- .in1({ 16'h0, opimm16 }),
- .out(binput)
+ .sel(ctl_imm16),
+ .in0(bdata),
+ .in1({ 16'h0, opimm16 }),
+ .out(binput)
);
mux2 #(4) alu_wsel_mux(
- .sel(ctl_d_or_b),
- .in0(opseld),
- .in1(opselb),
- .out(alu_wsel)
+ .sel(ctl_d_or_b),
+ .in0(opseld),
+ .in1(opselb),
+ .out(alu_wsel)
);
alu alu(