implement the ALU as it should be

This commit is contained in:
Raphael Jacquot 2019-03-14 21:47:05 +01:00
parent 137d9b3b5a
commit b2ae484450
4 changed files with 162 additions and 31 deletions

2
run.sh
View file

@ -15,7 +15,7 @@ iverilog -v -Wall -DSIM -o z_saturn_test.iv -s saturn_top \
saturn_bus.v saturn_hp48gx_rom.v \ saturn_bus.v saturn_hp48gx_rom.v \
saturn_bus_controller.v saturn_debugger.v \ saturn_bus_controller.v saturn_debugger.v \
saturn_control_unit.v saturn_inst_decoder.v\ saturn_control_unit.v saturn_inst_decoder.v\
saturn_regs_pc_rstk.v saturn_alu_module.v saturn_regs_pc_rstk.v #saturn_alu_module.v
IVERILOG_STATUS=$? IVERILOG_STATUS=$?
#./mask_gen_tb #./mask_gen_tb
echo "--------------------------------------------------------------------" echo "--------------------------------------------------------------------"

View file

@ -171,7 +171,7 @@ always @(posedge i_clk) begin
end end
`ifdef SIM `ifdef SIM
if (cycle_ctr == 136) begin if (cycle_ctr == 138) begin
bus_halt <= 1'b1; bus_halt <= 1'b1;
$display("BUS %0d: [%d] enough cycles for now", phase, cycle_ctr); $display("BUS %0d: [%d] enough cycles for now", phase, cycle_ctr);
end end

View file

@ -309,30 +309,30 @@ wire [19:0] reg_PC;
* *
*************************************************************************************************/ *************************************************************************************************/
saturn_alu_module alu_module ( // saturn_alu_module alu_module (
.i_clk (i_clk), // .i_clk (i_clk),
.i_clk_en (i_clk_en), // .i_clk_en (i_clk_en),
.i_reset (i_reset), // .i_reset (i_reset),
.i_phases (i_phases), // .i_phases (i_phases),
.i_phase (i_phase), // .i_phase (i_phase),
.i_cycle_ctr (i_cycle_ctr), // .i_cycle_ctr (i_cycle_ctr),
.i_opcode (alu_opcode), // .i_opcode (alu_opcode),
.i_ptr_begin (alu_ptr_begin), // .i_ptr_begin (alu_ptr_begin),
.i_ptr_end (alu_ptr_end), // .i_ptr_end (alu_ptr_end),
.i_run (alu_run), // .i_run (alu_run),
.i_done (alu_done), // .i_done (alu_done),
.i_prep_src_1_val (alu_prep_src_1_val), // .i_prep_src_1_val (alu_prep_src_1_val),
.i_prep_src_2_val (alu_prep_src_2_val), // .i_prep_src_2_val (alu_prep_src_2_val),
.i_prep_carry (alu_prep_carry), // .i_prep_carry (alu_prep_carry),
.i_calc_pos (alu_calc_pos), // .i_calc_pos (alu_calc_pos),
.o_calc_res_1_val (alu_calc_res_1_val), // .o_calc_res_1_val (alu_calc_res_1_val),
.o_calc_res_2_val (alu_calc_res_2_val), // .o_calc_res_2_val (alu_calc_res_2_val),
.o_calc_carry (alu_calc_carry) // .o_calc_carry (alu_calc_carry)
); // );
/* /*
* ALU control variable * ALU control variable
@ -357,9 +357,9 @@ reg [0:0] alu_prep_done;
reg [0:0] alu_calc_run; reg [0:0] alu_calc_run;
reg [3:0] alu_calc_pos; reg [3:0] alu_calc_pos;
wire [3:0] alu_calc_res_1_val; reg [3:0] alu_calc_res_1_val;
wire [3:0] alu_calc_res_2_val; reg [3:0] alu_calc_res_2_val;
wire [0:0] alu_calc_carry; reg [0:0] alu_calc_carry;
reg [0:0] alu_calc_done; reg [0:0] alu_calc_done;
reg [0:0] alu_save_run; reg [0:0] alu_save_run;
@ -550,7 +550,11 @@ always @(posedge i_clk) begin
alu_calc_done <= 1'b0; alu_calc_done <= 1'b0;
alu_save_done <= 1'b0; alu_save_done <= 1'b0;
if (aluop_zero) alu_save_run <= 1'b1; if (aluop_zero)
begin
alu_calc_res_1_val <= 4'h0;
alu_save_run <= 1'b1;
end
else alu_prep_run <= 1'b1; else alu_prep_run <= 1'b1;
end end
end end
@ -681,41 +685,114 @@ always @(posedge i_clk) begin
/****************************************************************************************** /******************************************************************************************
* *
* ALU control * ALU pipeline
* *
*****************************************************************************************/ *****************************************************************************************/
if (i_clk_en && control_unit_ready) begin if (i_clk_en && control_unit_ready) begin
/**********
*
* ALU prepare source values
*
*/
if (alu_start && alu_prep_run && !alu_prep_done) begin if (alu_start && alu_prep_run && !alu_prep_done) begin
$display("ALU_PREP %0d: [%d] b %h | p %h | e %h", i_phase, i_cycle_ctr, alu_ptr_begin, alu_prep_pos, alu_ptr_end); $display("ALU_PREP %0d: [%d] b %h | p %h | e %h", i_phase, i_cycle_ctr, alu_ptr_begin, alu_prep_pos, alu_ptr_end);
case (dec_alu_reg_src_1)
`ALU_REG_A: alu_prep_src_1_val <= reg_A[alu_prep_pos];
`ALU_REG_B: alu_prep_src_1_val <= reg_B[alu_prep_pos];
`ALU_REG_C: alu_prep_src_1_val <= reg_C[alu_prep_pos];
`ALU_REG_D: alu_prep_src_1_val <= reg_D[alu_prep_pos];
default: $display("ALU_PREP %0d: [%d] unhandled src1 register %0d", i_phase, i_cycle_ctr, dec_alu_reg_src_1);
endcase
case (dec_alu_reg_src_2)
`ALU_REG_A: alu_prep_src_2_val <= reg_A[alu_prep_pos];
`ALU_REG_B: alu_prep_src_2_val <= reg_B[alu_prep_pos];
`ALU_REG_C: alu_prep_src_2_val <= reg_C[alu_prep_pos];
`ALU_REG_D: alu_prep_src_2_val <= reg_D[alu_prep_pos];
`ALU_REG_NONE: begin end
default: $display("ALU_PREP %0d: [%d] unhandled src2 register %0d", i_phase, i_cycle_ctr, dec_alu_reg_src_2);
endcase
/* need to prepare the carry here */
if (alu_prep_pos == alu_ptr_end) begin if (alu_prep_pos == alu_ptr_end) begin
alu_prep_done <= 1'b1; alu_prep_done <= 1'b1;
alu_prep_run <= 1'b0; alu_prep_run <= 1'b0;
end end
alu_prep_pos <= alu_prep_pos + 4'h1; alu_prep_pos <= alu_prep_pos + 4'h1;
/* start the calc thread */
alu_calc_run <= 1'b1;
end end
/**********
*
* ALU calculations
*
*/
if (alu_start && alu_calc_run && !alu_calc_done) begin if (alu_start && alu_calc_run && !alu_calc_done) begin
$display("ALU_CALC %0d: [%d] b %h | p %h | e %h", i_phase, i_cycle_ctr, alu_ptr_begin, alu_calc_pos, alu_ptr_end); $display("ALU_CALC %0d: [%d] b %h | p %h | e %h | s1 %h | s2 %h | c %b",
i_phase, i_cycle_ctr, alu_ptr_begin, alu_calc_pos, alu_ptr_end,
alu_prep_src_1_val, alu_prep_src_2_val, alu_prep_carry);
case (alu_opcode)
`ALU_OP_ZERO: begin end // this doesn't run, handled directly by the save below
`ALU_OP_COPY: alu_calc_res_1_val <= alu_prep_src_1_val;
`ALU_OP_EXCH:
begin
alu_calc_res_1_val <= alu_prep_src_2_val;
alu_calc_res_2_val <= alu_prep_src_1_val;
end
default: $display("ALU_CALC %0d: [%d] unhandled opcode %0d", i_phase, i_cycle_ctr, alu_opcode);
endcase
if (alu_calc_pos == alu_ptr_end) begin if (alu_calc_pos == alu_ptr_end) begin
alu_calc_done <= 1'b1; alu_calc_done <= 1'b1;
alu_calc_run <= 1'b0; alu_calc_run <= 1'b0;
end end
alu_calc_pos <= alu_calc_pos + 4'h1; alu_calc_pos <= alu_calc_pos + 4'h1;
/* start the save thread */
alu_save_run <= 1'b1;
end end
/**********
*
* ALU save results to registers
*
*/
if (alu_start && alu_save_run && !alu_save_done) begin if (alu_start && alu_save_run && !alu_save_done) begin
$display("ALU_SAVE %0d: [%d] b %h | p %h | e %h | r1 %h | r2 %h | c %b", $display("ALU_SAVE %0d: [%d] b %h | p %h | e %h | r1 %h | r2 %h | c %b | rs1 %d | rs2 %d | d %d",
i_phase, i_cycle_ctr, i_phase, i_cycle_ctr,
alu_ptr_begin, alu_save_pos, alu_ptr_end, alu_ptr_begin, alu_save_pos, alu_ptr_end,
alu_calc_res_1_val, alu_calc_res_2_val, alu_calc_carry); alu_calc_res_1_val, alu_calc_res_2_val, alu_calc_carry,
alu_reg_src_1, alu_reg_src_2, alu_reg_dest);
case (alu_reg_dest) case (alu_reg_dest)
`ALU_REG_C: reg_C[alu_save_pos] <= alu_calc_res_1_val; `ALU_REG_A: reg_A[alu_save_pos] <= alu_calc_res_1_val;
`ALU_REG_B: reg_B[alu_save_pos] <= alu_calc_res_1_val;
`ALU_REG_C: reg_C[alu_save_pos] <= alu_calc_res_1_val;
`ALU_REG_D: reg_D[alu_save_pos] <= alu_calc_res_1_val;
`ALU_REG_D0: reg_D0[alu_save_pos[2:0]] <= alu_calc_res_1_val;
`ALU_REG_D1: reg_D1[alu_save_pos[2:0]] <= alu_calc_res_1_val;
default: $display("ALU_SAVE %0d: [%d] dest register %0d not supported", i_phase, i_cycle_ctr, alu_reg_dest); default: $display("ALU_SAVE %0d: [%d] dest register %0d not supported", i_phase, i_cycle_ctr, alu_reg_dest);
endcase endcase
if (alu_opcode == `ALU_OP_EXCH)
case (alu_reg_src_2)
`ALU_REG_A: reg_A[alu_save_pos] <= alu_calc_res_2_val;
`ALU_REG_B: reg_B[alu_save_pos] <= alu_calc_res_2_val;
`ALU_REG_C: reg_C[alu_save_pos] <= alu_calc_res_2_val;
`ALU_REG_D: reg_D[alu_save_pos] <= alu_calc_res_2_val;
`ALU_REG_D0: reg_D0[alu_save_pos[2:0]] <= alu_calc_res_2_val;
`ALU_REG_D1: reg_D1[alu_save_pos[2:0]] <= alu_calc_res_2_val;
default: $display("ALU_SAVE %0d: [%d] exch: src_2 register %0d not supported", i_phase, i_cycle_ctr, alu_reg_src_2);
endcase
if (alu_save_pos == alu_ptr_end) begin if (alu_save_pos == alu_ptr_end) begin
alu_save_done <= 1'b1; alu_save_done <= 1'b1;
alu_save_run <= 1'b0; alu_save_run <= 1'b0;
@ -723,6 +800,13 @@ always @(posedge i_clk) begin
alu_save_pos <= alu_save_pos + 4'h1; alu_save_pos <= alu_save_pos + 4'h1;
end end
/**********
*
* ALU end of operations
*
*/
if (i_phases[2] && alu_start && alu_save_done) begin if (i_phases[2] && alu_start && alu_save_done) begin
$display("CTRL %0d: [%d] end of ALU operation", i_phase, i_cycle_ctr); $display("CTRL %0d: [%d] end of ALU operation", i_phase, i_cycle_ctr);
alu_start <= 1'b0; alu_start <= 1'b0;

View file

@ -144,6 +144,7 @@ reg [0:0] block_84x_85x;
reg [0:0] block_Ax; reg [0:0] block_Ax;
reg [0:0] block_Aax; reg [0:0] block_Aax;
reg [0:0] block_Abx; reg [0:0] block_Abx;
reg [0:0] block_Dx;
reg [0:0] block_JUMP; reg [0:0] block_JUMP;
reg [0:0] block_LOAD; reg [0:0] block_LOAD;
@ -195,6 +196,7 @@ initial begin
block_Ax = 1'b0; block_Ax = 1'b0;
block_Aax = 1'b0; block_Aax = 1'b0;
block_Abx = 1'b0; block_Abx = 1'b0;
block_Dx = 1'b0;
block_JUMP = 1'b0; block_JUMP = 1'b0;
block_LOAD = 1'b0; block_LOAD = 1'b0;
@ -217,6 +219,9 @@ end
*/ */
wire [4:0] regs_ABCD = { 3'b000, i_nibble[1:0] }; wire [4:0] regs_ABCD = { 3'b000, i_nibble[1:0] };
wire [4:0] regs_BCAC = { 3'b000, i_nibble[0], !(i_nibble[1] | i_nibble[0]) };
wire [4:0] regs_ABAC = { 3'b000, i_nibble[1] & i_nibble[0], !i_nibble[1] & i_nibble[0] };
wire [4:0] regs_BCCD = { 3'b000, i_nibble[1] | i_nibble[0], !i_nibble[1] ^ i_nibble[0] };
/**************************** /****************************
* *
@ -271,6 +276,7 @@ always @(posedge i_clk) begin
block_FIELDS <= 1'b1; block_FIELDS <= 1'b1;
fields_table <= `FT_A_B; fields_table <= `FT_A_B;
end end
4'hD: block_Dx <= 1'b1;
default: default:
begin begin
$display("invalid instruction"); $display("invalid instruction");
@ -497,6 +503,46 @@ always @(posedge i_clk) begin
block_Abx <= 1'b0; block_Abx <= 1'b0;
end end
if (block_Dx) begin
$display("DECODER %0d: [%d] block_Dx %h", i_phase, i_cycle_ctr, i_nibble);
o_instr_type <= `INSTR_TYPE_ALU;
o_alu_field <= `FT_FIELD_A;
o_alu_ptr_begin <= 4'h0;
o_alu_ptr_end <= 4'h4;
o_alu_reg_src_2 <= `ALU_REG_NONE;
case ({i_nibble[3], i_nibble[2]})
2'b00:
begin
o_alu_opcode <= `ALU_OP_ZERO;
o_alu_reg_dest <= regs_ABCD;
o_alu_reg_src_1 <= `ALU_REG_NONE;
end
2'b01:
begin
o_alu_opcode <= `ALU_OP_COPY;
o_alu_reg_dest <= regs_ABCD;
o_alu_reg_src_1 <= regs_BCAC;
end
2'b10:
begin
o_alu_opcode <= `ALU_OP_COPY;
o_alu_reg_dest <= regs_BCAC;
o_alu_reg_src_1 <= regs_ABCD;
end
2'b11:
begin
o_alu_opcode <= `ALU_OP_EXCH;
o_alu_reg_dest <= regs_ABAC;
o_alu_reg_src_1 <= regs_ABAC;
o_alu_reg_src_2 <= regs_BCCD;
end
endcase
o_instr_decoded <= 1'b1;
o_instr_execute <= 1'b1;
decode_started <= 1'b0;
block_Dx <= 1'b0;
end
/* special cases */ /* special cases */
if (block_JUMP) begin if (block_JUMP) begin
@ -649,6 +695,7 @@ always @(posedge i_clk) begin
block_Ax <= 1'b0; block_Ax <= 1'b0;
block_Aax <= 1'b0; block_Aax <= 1'b0;
block_Abx <= 1'b0; block_Abx <= 1'b0;
block_Dx <= 1'b0;
block_JUMP <= 1'b0; block_JUMP <= 1'b0;
block_LOAD <= 1'b0; block_LOAD <= 1'b0;