mirror of
https://github.com/sxpert/hp-saturn
synced 2024-11-16 19:50:19 +01:00
start implementing the ALU
This commit is contained in:
parent
aa1d8efd85
commit
713e9b967b
4 changed files with 287 additions and 42 deletions
210
saturn-alu.v
210
saturn-alu.v
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
1
testrom-2.hex
Normal file
|
@ -0,0 +1 @@
|
|||
2 3
|
Loading…
Reference in a new issue