start implementing the ALU

This commit is contained in:
Raphael Jacquot 2019-02-13 22:43:04 +01:00
parent aa1d8efd85
commit 713e9b967b
4 changed files with 287 additions and 42 deletions

View file

@ -6,49 +6,239 @@
module saturn_alu (
i_clk,
i_reset,
i_en_alu_dump,
i_en_alu_prep,
i_en_alu_calc,
i_en_alu_init,
i_en_alu_save,
o_alu_stall_dec,
i_ins_decoded,
i_field_start,
i_field_last,
i_imm_value,
i_alu_op,
i_reg_dest,
i_reg_src1,
i_reg_src2,
o_reg_p
i_ins_alu_op,
o_reg_p,
i_pc
);
input wire [0:0] i_clk;
input wire [0:0] i_reset;
input wire [0:0] i_en_alu_dump;
input wire [0:0] i_en_alu_prep;
input wire [0:0] i_en_alu_calc;
input wire [0:0] i_en_alu_init;
input wire [0:0] i_en_alu_save;
output reg [0:0] o_alu_stall_dec;
input wire [0:0] i_ins_decoded;
input wire [3:0] i_field_start;
input wire [3:0] i_field_last;
input wire [3:0] i_imm_value;
input wire [4:0] i_alu_op;
input wire [4:0] i_reg_dest;
input wire [4:0] i_reg_src1;
input wire [4:0] i_reg_src2;
input wire i_ins_alu_op;
output wire [3:0] o_reg_p;
input wire [19:0] i_pc;
assign o_reg_p = P;
wire [19:0] PC;
assign PC = i_pc + 1;
reg [19:0] D0;
reg [19:0] D1;
reg [63:0] A;
reg [63:0] B;
reg [63:0] C;
reg [63:0] D;
reg [63:0] R0;
reg [63:0] R1;
reg [63:0] R2;
reg [63:0] R3;
reg [63:0] R4;
reg [0:0] CARRY;
reg [0:0] DEC;
reg [3:0] P;
reg [3:0] HST;
reg [15:0] ST;
reg [2:0] rstk_ptr;
reg [19:0] RSTK[0:7];
reg [3:0] P;
initial begin
P = 3;
// alu internal control bits
alu_run = 0;
o_alu_stall_dec = 0;
// processor registers
D0 = 0;
D1 = 0;
A = 0;
B = 0;
C = 0;
D = 0;
R0 = 0;
R1 = 0;
R2 = 0;
R3 = 0;
R4 = 0;
CARRY = 0;
DEC = 0;
P = 0;
HST = 0;
ST = 0;
rstk_ptr = 0;
RSTK[0] = 0;
RSTK[1] = 0;
RSTK[2] = 0;
RSTK[3] = 0;
RSTK[4] = 0;
RSTK[5] = 0;
RSTK[6] = 0;
RSTK[7] = 0;
end
wire do_reg_dump;
wire do_alu_init;
wire do_alu_prep;
wire do_alu_calc;
wire do_alu_save;
assign do_reg_dump = (!i_reset) && i_en_alu_dump && i_ins_decoded && !o_alu_stall_dec;
assign do_alu_init = (!i_reset) && i_en_alu_init && i_ins_alu_op && !alu_run;
assign do_alu_prep = (!i_reset) && i_en_alu_prep;
assign do_alu_calc = (!i_reset) && i_en_alu_calc;
assign do_alu_save = (!i_reset) && i_en_alu_save;
reg alu_run;
reg [4:0] alu_op;
reg [4:0] reg_dest;
reg [4:0] reg_src1;
reg [4:0] reg_src2;
reg [3:0] f_start;
reg [3:0] f_last;
reg [3:0] p_src1;
reg [3:0] p_src2;
reg p_carry;
reg [3:0] c_res1;
reg [3:0] c_res2;
reg c_carry;
always @(posedge i_clk) begin
if (!i_reset) begin
if (i_en_alu_prep) begin
`ifdef SIM
// $display("ALU_PREP: alu_op %h | f_start %h | f_last %h", i_alu_op, i_field_start, i_field_last);
`endif
end
// if (!i_reset) begin
// $display("alu_clk");
// end
if (do_reg_dump) begin
$display("ALU_DUMP 0:");
`ifdef SIM
// display registers
$display("PC: %05h Carry: %b h: %s rp: %h RSTK7: %05h",
PC, CARRY, DEC?"DEC":"HEX", rstk_ptr, RSTK[7]);
$display("P: %h HST: %b ST: %b RSTK6: %5h",
P, HST, ST, RSTK[6]);
$display("A: %h R0: %h RSTK5: %5h", A, R0, RSTK[5]);
$display("B: %h R1: %h RSTK4: %5h", B, R1, RSTK[4]);
$display("C: %h R2: %h RSTK3: %5h", C, R2, RSTK[3]);
$display("D: %h R3: %h RSTK2: %5h", D, R3, RSTK[2]);
$display("D0: %h D1: %h R4: %h RSTK1: %5h",
D0, D1, R4, RSTK[1]);
$display(" RSTK0: %5h",
RSTK[0]);
`endif
end
// this happens in phase 3, right after the instruction decoder (in phase 2) is finished
if (do_alu_init) begin
$display("ALU_INIT 3: run %b | i_alu %b | op %d | dest %d | src1 %d | src2 %d | start %h | end %h",
alu_run, i_ins_alu_op, i_alu_op, i_reg_dest, i_reg_src1, i_reg_src2, i_field_start, i_field_last);
alu_run <= 1;
alu_op <= i_alu_op;
reg_dest <= i_reg_dest;
reg_src1 <= i_reg_src1;
reg_src2 <= i_reg_src2;
f_start <= i_field_start;
f_last <= i_field_last;
// stall the decoder
o_alu_stall_dec <= 1;
end
if (do_alu_prep && alu_run) begin
`ifdef SIM
$display("ALU_PREP 1: run %b | stall %b | op %b | alu_op %h | f_start %h | f_last %h",
alu_run, o_alu_stall_dec, alu_op, i_alu_op, f_start, f_last);
`endif
// setup value for src1
case (alu_op)
`ALU_OP_ZERO: begin end // no source required
`ALU_OP_COPY:
case (reg_src1)
`ALU_REG_P: p_src1 <= P;
`ALU_REG_IMM: p_src1 <= i_imm_value;
endcase
endcase
// setup p_carry
end
if (do_alu_calc) begin
$display("ALU_CALC 2: run %b | op %d | src1 %h | src2 %h | p_carry %b",
alu_run, alu_op, p_src1, p_src2, p_carry);
case (alu_op)
`ALU_OP_ZERO: c_res1 <= 0;
`ALU_OP_COPY: c_res1 <= p_src1;
endcase
end
if (do_alu_save) begin
$display("ALU_SAVE 3: run %b | stall %b | op %b | res1 %h | res2 %h | c_carry %b",
alu_run, o_alu_stall_dec, alu_op, c_res1, c_res2, c_carry);
case (alu_op)
`ALU_OP_ZERO,
`ALU_OP_COPY:
case (reg_dest)
`ALU_REG_P: P <= c_res1;
endcase
endcase
// find if we're finished
if (f_start == f_last) begin
$display("ALU_SAVE 3: unstall decoder");
o_alu_stall_dec <= 0;
end
end
end
endmodule

View file

@ -44,12 +44,14 @@ assign reset = btn[1];
// clocks
reg [1:0] clk_phase;
reg en_reset;
reg en_alu_dump; // phase 0
reg en_debugger; // phase 0
reg en_bus_send; // phase 0
reg en_bus_recv; // phase 1
reg en_alu_prep; // phase 1
reg en_alu_calc; // phase 2
reg en_inst_dec; // phase 2
reg en_alu_init; // phase 3
reg en_alu_save; // phase 3
reg en_inst_exec; // phase 3
reg clock_end;
@ -92,8 +94,12 @@ saturn_decoder m_decoder (
.o_field (field),
.o_field_start (field_start),
.o_field_last (field_last),
.o_imm_value (imm_value),
.o_alu_op (alu_op),
.o_reg_dest (reg_dest),
.o_reg_src1 (reg_src1),
.o_reg_src2 (reg_src2),
.o_direction (direction),
.o_ins_rtn (ins_rtn),
@ -101,7 +107,8 @@ saturn_decoder m_decoder (
.o_set_carry (set_carry),
.o_carry_val (carry_val),
.o_ins_set_mode (ins_set_mode),
.o_mode_dec (mode_dec)
.o_mode_dec (mode_dec),
.o_ins_alu_op (ins_alu_op)
);
wire inc_pc;
@ -114,8 +121,12 @@ wire [1:0] fields_table;
wire [3:0] field;
wire [3:0] field_start;
wire [3:0] field_last;
wire [3:0] imm_value;
wire [4:0] alu_op;
wire [4:0] reg_dest;
wire [4:0] reg_src1;
wire [4:0] reg_src2;
wire direction;
wire ins_rtn;
@ -124,37 +135,60 @@ wire set_carry;
wire carry_val;
wire ins_set_mode;
wire mode_dec;
wire ins_alu_op;
saturn_alu m_alu (
.i_clk (clk),
.i_reset (reset),
.i_en_alu_prep (en_alu_prep),
.i_en_alu_calc (en_alu_calc),
.i_en_alu_save (en_alu_save),
.i_clk (clk),
.i_reset (reset),
.i_en_alu_dump (en_alu_dump),
.i_en_alu_prep (en_alu_prep),
.i_en_alu_calc (en_alu_calc),
.i_en_alu_init (en_alu_init),
.i_en_alu_save (en_alu_save),
.i_field_start (field_start),
.i_field_last (field_last),
.o_alu_stall_dec (alu_stall),
.i_ins_decoded (ins_decoded),
.i_alu_op (alu_op),
.i_field_start (field_start),
.i_field_last (field_last),
.i_imm_value (imm_value),
.o_reg_p (reg_p)
.i_alu_op (alu_op),
.i_reg_dest (reg_dest),
.i_reg_src1 (reg_src1),
.i_reg_src2 (reg_src2),
.i_ins_alu_op (ins_alu_op),
.o_reg_p (reg_p),
.i_pc (reg_pc)
);
// interconnections
wire [0:0] alu_stall;
wire [3:0] reg_p;
/*
* test rom...
*/
reg [3:0] rom [0:1024];
`ifdef SIM
reg [3:0] rom [0:2**20];
`else
reg [3:0] rom [0:2**20];
`endif
initial
begin
$readmemh( "testrom.hex", rom);
`ifndef SIM
$readmemh("rom-gx-r.hex", rom);
`else
$readmemh( "testrom-2.hex", rom);
`endif
clk_phase = 0;
en_debugger = 0; // phase 0
en_bus_send = 0; // phase 0
@ -162,6 +196,7 @@ initial
en_alu_prep = 0; // phase 1
en_alu_calc = 0; // phase 2
en_inst_dec = 0; // phase 2
en_alu_init = 0; // phase 0
en_alu_save = 0; // phase 3
en_inst_exec = 0; // phase 3
clock_end = 0;
@ -187,12 +222,14 @@ initial
always @(posedge clk) begin
if (!reset) begin
clk_phase <= clk_phase + 1;
en_alu_dump <= clk_phase[1:0] == 0;
en_debugger <= clk_phase[1:0] == 0;
en_bus_send <= clk_phase[1:0] == 0;
en_bus_recv <= clk_phase[1:0] == 1;
en_alu_prep <= clk_phase[1:0] == 1;
en_alu_calc <= clk_phase[1:0] == 2;
en_inst_dec <= clk_phase[1:0] == 2;
en_alu_init <= clk_phase[1:0] == 3;
en_alu_save <= clk_phase[1:0] == 3;
en_inst_exec <= clk_phase[1:0] == 3;
cycle_ctr <= cycle_ctr + (clk_phase[1:0] == 0);
@ -201,19 +238,21 @@ always @(posedge clk) begin
clock_end <= 1;
end else begin
clk_phase <= ~0;
en_alu_dump <= 0;
en_debugger <= 0;
en_bus_send <= 0;
en_bus_recv <= 0;
en_alu_prep <= 0;
en_alu_calc <= 0;
en_inst_dec <= 0;
en_alu_init <= 0;
en_alu_save <= 0;
en_inst_exec <= 0;
clock_end <= 0;
cycle_ctr <= ~0;
max_cycle <= 1024;
clock_end <= 0;
cycle_ctr <= ~0;
max_cycle <= 4;
`ifndef SIM
led[7:0] <= reg_pc[7:0];
led[7:0] <= reg_pc[7:0];
`endif
end
end
@ -226,12 +265,13 @@ end
reg [3:0] nibble_in;
reg [19:0] reg_pc;
reg stalled;
wire stalled;
assign stalled = alu_stall;
always @(posedge clk)
if (reset) begin
reg_pc <= ~0;
stalled <= 0;
// stalled <= 0;
end else begin
if (en_bus_send) begin
if (inc_pc & !stalled)
@ -246,10 +286,10 @@ always @(posedge clk)
nibble_in <= rom[reg_pc];
end
end
if (en_inst_exec) begin
if (cycle_ctr == 5) stalled <= 1;
if (cycle_ctr == 10) stalled <= 0;
end
// if (en_inst_exec) begin
// if (cycle_ctr == 5) stalled <= 1;
// if (cycle_ctr == 10) stalled <= 0;
// end
end
assign halt = clock_end || inv_opcode;
@ -300,7 +340,4 @@ end
endmodule
`else
`endif
`endif

View file

@ -123,6 +123,7 @@ output reg [3:0] o_mem_pos;
reg [31:0] instr_ctr;
reg [0:0] next_nibble;
reg [4:0] inst_cycles;
reg inval_opcode_regs;
@ -180,6 +181,7 @@ always @(posedge i_clk) begin
*/
`ifdef SIM
if (o_ins_decoded) begin
$write("DBG 0: ");
$write("%5h ", o_ins_addr);
// $write("[%2d] ", o_dbg_nb_nbls);
@ -342,7 +344,7 @@ always @(posedge i_clk) begin
else if (!p_is_dest)
$write("[%h:%h]", o_field_start, o_field_last);
end
$display("");
$display("\t(%d cycles)", inst_cycles);
end
end
// $display("new [%5h]--------------------------------------------------------------------", new_pc);
@ -377,12 +379,16 @@ reg go_fields_table;
/* lots'o-wires to decode common states
*/
wire count_cycles;
wire decoder_active;
wire decoder_stalled;
wire do_on_first_nibble;
wire do_on_other_nibbles;
assign decoder_active = !i_reset && i_en_dec && !i_stalled;
assign do_on_first_nibble = decoder_active && !next_nibble;
assign count_cycles = !i_reset && i_en_dec && (next_nibble || i_stalled);
assign decoder_active = !i_reset && i_en_dec && !i_stalled;
assign decoder_stalled = !i_reset && i_en_dec && i_stalled;
assign do_on_first_nibble = decoder_active && !next_nibble;
assign do_on_other_nibbles = decoder_active && next_nibble;
wire do_block_0x;
@ -437,7 +443,8 @@ assign dbg_write_pos = (!next_nibble?0:o_dbg_nb_nbls);
always @(posedge i_clk) begin
if (i_reset) begin
next_nibble <= 0;
inst_cycles <= 0;
next_nibble <= 0;
use_fields_tbl <= 0;
o_inc_pc <= 1;
o_dec_error <= 0;
@ -449,15 +456,25 @@ always @(posedge i_clk) begin
/*
* stuff that is always done
*/
$display("DEC_RUN 2: nibble %h", i_nibble);
o_inc_pc <= 1; // may be set to 0 later
o_dbg_nibbles[dbg_write_pos*4+:4] <= i_nibble;
o_dbg_nb_nbls <= o_dbg_nb_nbls + 1;
end
if (decoder_stalled) begin
$display("DEC_STAL 2:");
end
if (count_cycles) begin
inst_cycles <= inst_cycles + 1;
end
/*
* cleanup
*/
if (do_on_first_nibble) begin
inst_cycles <= 1;
next_nibble <= 1;
use_fields_tbl <= 0;
@ -520,7 +537,7 @@ always @(posedge i_clk) begin
4'h3: block_load_c_hex <= 1;
default: begin
`ifdef SIM
$display("new_instruction: nibble %h not handled", i_nibble);
$display("DEC_INIT 2: nibble %h not handled", i_nibble);
`endif
o_dec_error <= 1;
end

1
testrom-2.hex Normal file
View file

@ -0,0 +1 @@
2 3