mirror of
https://github.com/sxpert/hp-saturn
synced 2024-12-31 10:23:35 +01:00
44ca0f4a15
implement exch in ALU fix jump base calculations correct some things in debugger fix fields and registers for some instructions
696 lines
No EOL
19 KiB
Verilog
696 lines
No EOL
19 KiB
Verilog
|
||
`ifndef _SATURN_ALU
|
||
`define _SATURN_ALU
|
||
|
||
`include "def-alu.v"
|
||
|
||
`ifdef SIM
|
||
// `define ALU_DEBUG_DBG
|
||
`endif
|
||
|
||
`define ALU_DEBUG 1'b0
|
||
`define ALU_DEBUG_DUMP 1'b1
|
||
`define ALU_DEBUG_JUMP 1'b0
|
||
`define ALU_DEBUG_PC 1'b0
|
||
|
||
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,
|
||
|
||
i_push,
|
||
i_pop,
|
||
i_alu_debug,
|
||
|
||
o_alu_stall_dec,
|
||
i_ins_decoded,
|
||
|
||
i_field_start,
|
||
i_field_last,
|
||
i_imm_value,
|
||
|
||
i_alu_op,
|
||
i_alu_no_stall,
|
||
i_reg_dest,
|
||
i_reg_src1,
|
||
i_reg_src2,
|
||
|
||
i_ins_alu_op,
|
||
i_ins_set_mode,
|
||
i_ins_rtn,
|
||
|
||
i_mode_dec,
|
||
i_set_xm,
|
||
i_set_carry,
|
||
i_carry_val,
|
||
|
||
o_reg_p,
|
||
o_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;
|
||
|
||
input wire [0:0] i_push;
|
||
input wire [0:0] i_pop;
|
||
input wire [0:0] i_alu_debug;
|
||
|
||
wire alu_debug;
|
||
wire alu_debug_dump;
|
||
wire alu_debug_jump;
|
||
wire alu_debug_pc;
|
||
assign alu_debug = `ALU_DEBUG || i_alu_debug;
|
||
assign alu_debug_dump = `ALU_DEBUG_DUMP || i_alu_debug;
|
||
assign alu_debug_jump = `ALU_DEBUG_JUMP || i_alu_debug;
|
||
assign alu_debug_pc = `ALU_DEBUG_PC || i_alu_debug;
|
||
|
||
output wire [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 [0:0] i_alu_no_stall;
|
||
input wire [4:0] i_reg_dest;
|
||
input wire [4:0] i_reg_src1;
|
||
input wire [4:0] i_reg_src2;
|
||
|
||
input wire [0:0] i_ins_alu_op;
|
||
input wire [0:0] i_ins_set_mode;
|
||
input wire [0:0] i_ins_rtn;
|
||
|
||
input wire [0:0] i_mode_dec;
|
||
input wire [0:0] i_set_xm;
|
||
input wire [0:0] i_set_carry;
|
||
input wire [0:0] i_carry_val;
|
||
|
||
output wire [3:0] o_reg_p;
|
||
output wire [19:0] o_pc;
|
||
|
||
assign o_reg_p = P;
|
||
assign o_pc = PC;
|
||
|
||
/* internal registers */
|
||
|
||
/* copy of arguments */
|
||
reg [4:0] alu_op;
|
||
reg [4:0] reg_dest;
|
||
reg [4:0] reg_src1;
|
||
reg [4:0] reg_src2;
|
||
reg [3:0] f_first;
|
||
reg [3:0] f_cur;
|
||
reg [3:0] f_last;
|
||
|
||
/* internal pointers */
|
||
|
||
reg [3:0] p_src1;
|
||
reg [3:0] p_src2;
|
||
reg [0:0] p_carry;
|
||
reg [3:0] c_res1;
|
||
reg [3:0] c_res2;
|
||
reg [0:0] c_carry;
|
||
reg [0:0] is_zero;
|
||
|
||
/* alu status */
|
||
|
||
reg alu_run;
|
||
reg alu_done;
|
||
|
||
/*
|
||
* next PC in case of jump
|
||
*/
|
||
reg [19:0] jump_bse;
|
||
reg [19:0] jump_off;
|
||
wire [19:0] jump_pc;
|
||
assign jump_pc = (alu_op == `ALU_OP_JMP_ABS5)?jump_off:(jump_bse + jump_off);
|
||
|
||
reg [2:0] rstk_ptr;
|
||
|
||
/* public registers */
|
||
|
||
reg [19:0] PC;
|
||
|
||
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 [19:0] RSTK[0:7];
|
||
|
||
|
||
initial begin
|
||
// alu internal control bits
|
||
alu_op = 0;
|
||
reg_dest = 0;
|
||
reg_src1 = 0;
|
||
reg_src2 = 0;
|
||
f_first = 0;
|
||
f_cur = 0;
|
||
f_last = 0;
|
||
|
||
alu_run = 0;
|
||
alu_done = 0;
|
||
|
||
p_src1 = 0;
|
||
p_src2 = 0;
|
||
p_carry = 0;
|
||
c_res1 = 0;
|
||
c_res2 = 0;
|
||
c_carry = 0;
|
||
is_zero = 0;
|
||
// o_alu_stall_dec = 0;
|
||
// processor registers
|
||
PC = 0;
|
||
|
||
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
|
||
|
||
`ifdef SIM
|
||
wire do_reg_dump;
|
||
wire do_alu_shpc;
|
||
assign do_reg_dump = (!i_reset) && i_en_alu_dump && i_ins_decoded && !o_alu_stall_dec;
|
||
assign do_alu_shpc = (!i_reset) && i_en_alu_dump;
|
||
`endif
|
||
|
||
wire do_alu_init;
|
||
wire do_alu_prep;
|
||
wire do_alu_calc;
|
||
wire do_alu_save;
|
||
wire do_alu_pc;
|
||
wire do_alu_mode;
|
||
|
||
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 && alu_run;
|
||
assign do_alu_calc = !i_reset && i_en_alu_calc && alu_run;
|
||
assign do_alu_save = !i_reset && i_en_alu_save && alu_run;
|
||
assign do_alu_pc = !i_reset && i_en_alu_save;
|
||
assign do_alu_mode = !i_reset && i_en_alu_save && i_ins_set_mode;
|
||
|
||
// the decoder may request the ALU to not stall it
|
||
|
||
assign o_alu_stall_dec = alu_run && (!i_alu_no_stall || alu_finish);
|
||
|
||
wire alu_start;
|
||
wire alu_finish;
|
||
wire [3:0] f_next;
|
||
|
||
assign alu_start = f_cur == f_first;
|
||
assign alu_finish = f_cur == f_last;
|
||
assign f_next = (f_cur + 1) & 4'hF;
|
||
|
||
/*
|
||
* test things on alu_op
|
||
*/
|
||
|
||
wire is_alu_op_jump;
|
||
assign is_alu_op_jump = ((alu_op == `ALU_OP_JMP_REL3) ||
|
||
(alu_op == `ALU_OP_JMP_REL4) ||
|
||
(alu_op == `ALU_OP_JMP_ABS5) ||
|
||
i_ins_rtn);
|
||
|
||
/*****************************************************************************
|
||
*
|
||
* Dump all registers at the end of each instruction's execution cycle
|
||
*
|
||
****************************************************************************/
|
||
|
||
always @(posedge i_clk) begin
|
||
`ifdef ALU_DEBUG_DBG
|
||
$display("iad %b | AD %b | ad %b | ADD %b | add %b | ADJ %b | adj %b | ADP %b | adp %b",
|
||
i_alu_debug,
|
||
`ALU_DEBUG, i_alu_debug,
|
||
`ALU_DEBUG_DUMP, alu_debug_dump,
|
||
`ALU_DEBUG_JUMP, alu_debug_jump,
|
||
`ALU_DEBUG_PC, alu_debug_pc );
|
||
`endif
|
||
|
||
`ifdef SIM
|
||
if (do_reg_dump && alu_debug_dump) begin
|
||
|
||
$display("ALU_DUMP 0: run %b | done %b", alu_run, alu_done);
|
||
// 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]);
|
||
end
|
||
`endif
|
||
end
|
||
|
||
/*****************************************************************************
|
||
*
|
||
* Initialize the ALU, to prepare it to execute the instruction
|
||
*
|
||
****************************************************************************/
|
||
|
||
wire [0:0] is_mem_read;
|
||
wire [0:0] is_mem_write;
|
||
wire [0:0] is_mem_xfer;
|
||
wire [4:0] mem_reg;
|
||
assign is_mem_read = (i_reg_src1 == `ALU_REG_DAT0) || (i_reg_src1 == `ALU_REG_DAT1);
|
||
assign is_mem_write = (i_reg_dest == `ALU_REG_DAT0) || (i_reg_dest == `ALU_REG_DAT1);
|
||
assign is_mem_xfer = is_mem_read || is_mem_write;
|
||
assign mem_reg = is_mem_read?i_reg_src1:i_reg_dest;
|
||
|
||
always @(posedge i_clk) begin
|
||
// this happens in phase 3, right after the instruction decoder (in phase 2) is finished
|
||
if (do_alu_init) begin
|
||
|
||
`ifdef SIM
|
||
if (alu_debug)
|
||
$display({"ALU_INIT 3: run %b | done %b | stall %b | op %d | s %h | l %h ",
|
||
"| ialu %b | dest %d | src1 %d | src2 %d | imm %h"},
|
||
alu_run, alu_done, o_alu_stall_dec, i_alu_op,i_field_start, i_field_last,
|
||
i_ins_alu_op, i_reg_dest, i_reg_src1, i_reg_src2, i_imm_value);
|
||
`endif
|
||
|
||
alu_op <= i_alu_op;
|
||
reg_dest <= i_reg_dest;
|
||
reg_src1 <= i_reg_src1;
|
||
reg_src2 <= i_reg_src2;
|
||
f_last <= i_field_last;
|
||
|
||
if (is_mem_xfer) begin
|
||
`ifdef SIM
|
||
$display("ALU_XFER 3: read %b | write %b | mem_reg DAT%b",
|
||
is_mem_read, is_mem_write, mem_reg[0]);
|
||
$display(".------------------------------------.");
|
||
$display("| SHOULD TELL THE BUS CONTROLLER TO |");
|
||
$display("| LOAD D0 OR D1 INTO MODULES' DP REG |");
|
||
$display("`------------------------------------´");
|
||
`endif
|
||
// DO SOMETHING TO GET THE BUS CONTROLLER TO SEND OUT
|
||
// THE CONTENTS OF D0 OR D1 AS THE DP
|
||
end
|
||
end
|
||
end
|
||
|
||
/*
|
||
* handles f_start, alu_run and alu_done
|
||
*/
|
||
|
||
always @(posedge i_clk) begin
|
||
|
||
if (do_alu_init) begin
|
||
alu_run <= 1;
|
||
f_first <= i_field_start;
|
||
f_cur <= i_field_start;
|
||
end
|
||
|
||
if (do_alu_prep) begin
|
||
// $display("ALU_TEST 1: tf %b | nxt %h", test_finish, f_next);
|
||
alu_done <= 0;
|
||
end
|
||
|
||
if (do_alu_calc) begin
|
||
// $display("ALU_TEST 2: tf %b | nxt %h", test_finish, f_next);
|
||
alu_done <= alu_finish;
|
||
// f_next <= (f_start + 1) & 4'hF;
|
||
end
|
||
|
||
if (do_alu_save) begin
|
||
// $display("ALU_TEST 3: tf %b | nxt %h", test_finish, f_next);
|
||
f_cur <= f_next;
|
||
end
|
||
|
||
if (do_alu_save && alu_done) begin
|
||
alu_run <= 0;
|
||
alu_done <= 0;
|
||
end
|
||
end
|
||
|
||
|
||
|
||
always @(posedge i_clk) begin
|
||
if (do_alu_prep) begin
|
||
if (alu_debug) begin
|
||
`ifdef SIM
|
||
$display("ALU_PREP 1: run %b | done %b | stall %b | op %d | f %h | c %h | l %h",
|
||
alu_run, alu_done, o_alu_stall_dec, alu_op, f_first, f_cur, f_last);
|
||
`endif
|
||
end
|
||
|
||
case (alu_op)
|
||
`ALU_OP_ZERO: begin end // no source required
|
||
`ALU_OP_COPY,
|
||
`ALU_OP_EXCH,
|
||
`ALU_OP_RST_BIT,
|
||
`ALU_OP_SET_BIT,
|
||
`ALU_OP_2CMPL,
|
||
`ALU_OP_JMP_REL3,
|
||
`ALU_OP_JMP_REL4,
|
||
`ALU_OP_JMP_ABS5,
|
||
`ALU_OP_CLR_MASK:
|
||
case (reg_src1)
|
||
`ALU_REG_A: p_src1 <= A [f_cur*4+:4];
|
||
`ALU_REG_B: p_src1 <= B [f_cur*4+:4];
|
||
`ALU_REG_C: p_src1 <= C [f_cur*4+:4];
|
||
`ALU_REG_D: p_src1 <= D [f_cur*4+:4];
|
||
`ALU_REG_D0: p_src1 <= D0[f_cur*4+:4];
|
||
`ALU_REG_D1: p_src1 <= D1[f_cur*4+:4];
|
||
`ALU_REG_P: p_src1 <= P;
|
||
`ALU_REG_HST: p_src1 <= HST;
|
||
`ALU_REG_IMM: p_src1 <= i_imm_value;
|
||
`ALU_REG_ZERO: p_src1 <= 0;
|
||
default: $display("#### SRC_1 UNHANDLED REGISTER %0d", reg_src1);
|
||
endcase
|
||
default: $display("#### SRC_1 UNHANDLED OPERATION %0d", alu_op);
|
||
endcase
|
||
|
||
case (alu_op)
|
||
`ALU_OP_ZERO,
|
||
`ALU_OP_COPY,
|
||
`ALU_OP_RST_BIT,
|
||
`ALU_OP_SET_BIT,
|
||
`ALU_OP_2CMPL,
|
||
`ALU_OP_JMP_REL3,
|
||
`ALU_OP_JMP_REL4,
|
||
`ALU_OP_JMP_ABS5: begin end // no need for a 2nd operand
|
||
`ALU_OP_EXCH,
|
||
`ALU_OP_CLR_MASK: begin
|
||
case (reg_src2)
|
||
`ALU_REG_A: p_src2 <= A [f_cur*4+:4];
|
||
`ALU_REG_B: p_src2 <= B [f_cur*4+:4];
|
||
`ALU_REG_C: p_src2 <= C [f_cur*4+:4];
|
||
`ALU_REG_D: p_src2 <= D [f_cur*4+:4];
|
||
`ALU_REG_D0: p_src2 <= D0[f_cur*4+:4];
|
||
`ALU_REG_D1: p_src2 <= D1[f_cur*4+:4];
|
||
`ALU_REG_P: p_src2 <= P;
|
||
`ALU_REG_HST: p_src2 <= HST;
|
||
`ALU_REG_IMM: p_src2 <= i_imm_value;
|
||
`ALU_REG_ZERO: p_src2 <= 0;
|
||
default: $display("#### SRC_2 UNHANDLED REGISTER %0d", reg_src2);
|
||
endcase
|
||
end
|
||
default: $display("#### SRC_2 UNHANDLED OPERATION %0d", alu_op);
|
||
endcase
|
||
|
||
// setup p_carry
|
||
// $display("fs %h | fs=0 %b | cc %b | npc %b", f_start, (f_start == 0), c_carry, (f_start == 0)?1'b1:c_carry);
|
||
case (alu_op)
|
||
`ALU_OP_2CMPL: p_carry <= (alu_start)?1'b1:c_carry;
|
||
endcase
|
||
|
||
// prepare jump base
|
||
case (alu_op)
|
||
`ALU_OP_JMP_REL3,
|
||
`ALU_OP_JMP_REL4:
|
||
begin
|
||
// the address of the first digit of the offset
|
||
if (!i_push && alu_start)
|
||
jump_bse <= PC - 1;
|
||
// doc says address of the next instruction, but appears to be off by 1
|
||
if (i_push)
|
||
jump_bse <= PC;
|
||
end
|
||
endcase
|
||
|
||
end
|
||
end
|
||
|
||
always @(posedge i_clk) begin
|
||
if (do_alu_calc) begin
|
||
`ifdef SIM
|
||
if (alu_debug)
|
||
$display("ALU_CALC 2: run %b | done %b | stall %b | op %d | f %h | c %h | l %h | dest %d | src1 %h | src2 %h | p_carry %b",
|
||
alu_run, alu_done, o_alu_stall_dec, alu_op, f_first, f_cur, f_last, reg_dest, p_src1, p_src2, p_carry);
|
||
if (alu_debug_jump)
|
||
$display("ALU_JUMP 2: run %b | done %b | stall %b | op %d | f %h | c %h | l %h | jbs %5h | jof %5h | jpc %5h | fin %b",
|
||
alu_run, alu_done, o_alu_stall_dec, alu_op, f_first, f_cur, f_last, jump_bse, jump_off, jump_pc, alu_finish);
|
||
`endif
|
||
|
||
case (alu_op)
|
||
`ALU_OP_JMP_REL3,
|
||
`ALU_OP_JMP_REL4,
|
||
`ALU_OP_JMP_ABS5:
|
||
if (alu_start)
|
||
jump_off <= { 16'b0, p_src1 };
|
||
endcase
|
||
|
||
// main case
|
||
case (alu_op)
|
||
`ALU_OP_ZERO: c_res1 <= 0;
|
||
`ALU_OP_EXCH:
|
||
begin
|
||
c_res1 <= p_src2;
|
||
c_res2 <= p_src1;
|
||
end
|
||
`ALU_OP_COPY,
|
||
`ALU_OP_RST_BIT,
|
||
`ALU_OP_SET_BIT: c_res1 <= p_src1;
|
||
`ALU_OP_2CMPL:
|
||
begin
|
||
c_carry <= (~p_src1 == 4'hf) && p_carry ;
|
||
c_res1 <= ~p_src1 + p_carry;
|
||
is_zero <= ((~p_src1 + p_carry) == 0) && alu_start?1:is_zero;
|
||
end
|
||
`ALU_OP_JMP_REL3,
|
||
`ALU_OP_JMP_REL4,
|
||
`ALU_OP_JMP_ABS5: jump_off[f_cur*4+:4] <= p_src1;
|
||
`ALU_OP_CLR_MASK: c_res1 <= p_src1 & ~p_src2;
|
||
default: $display("#### CALC 2 UNHANDLED OPERATION %0d", alu_op);
|
||
endcase
|
||
|
||
case (alu_op)
|
||
`ALU_OP_JMP_REL3: if (alu_finish)
|
||
jump_off <= { {8{p_src1[3]}}, p_src1, jump_off[7:0] };
|
||
`ALU_OP_JMP_REL4: if (alu_finish)
|
||
jump_off <= { {4{p_src1[3]}}, p_src1, jump_off[11:0] };
|
||
endcase
|
||
|
||
// $display("-------C- SRC1 %b %h | ~SRC1 %b %h | PC %b | RES1 %b %h | CC %b",
|
||
// p_src1, p_src1, ~p_src1, ~p_src1, p_carry,
|
||
// (~p_src1) + p_carry, (~p_src1) + p_carry,
|
||
// (~p_src1) == 4'hf );
|
||
end
|
||
end
|
||
|
||
always @(posedge i_clk) begin
|
||
|
||
if (do_alu_save) begin
|
||
`ifdef ALU_DEBUG
|
||
if (alu_debug)
|
||
$display({"ALU_SAVE 3: run %b | done %b | stall %b | op %d | f %h | c %h | l %h |",
|
||
" dest %d | cres1 %h | cres2 %h | psrc1 %h | psrc2 %h | c_carry %b"},
|
||
alu_run, alu_done, o_alu_stall_dec, alu_op,
|
||
f_first, f_cur, f_last, reg_dest, c_res1, c_res2, p_src1, p_src2, c_carry);
|
||
if (alu_debug_jump)
|
||
$display( "ALU_JUMP 3: run %b | done %b | stall %b | op %d | f %h | c %h | l %h | bse %5h | jof %5h | jpc %5h | fin %b",
|
||
alu_run, alu_done, o_alu_stall_dec, alu_op, f_first, f_cur, f_last, jump_bse, jump_off, jump_pc, alu_finish);
|
||
`endif
|
||
|
||
// $display("-------S- SRC1 %b %h | ~SRC1 %b %h | PC %b | RES1 %b %h | CC %b",
|
||
// p_src1, p_src1, ~p_src1, ~p_src1, p_carry,
|
||
// (~p_src1) + p_carry, (~p_src1) + p_carry,
|
||
// (~p_src1) == 4'hf );
|
||
|
||
case (alu_op)
|
||
`ALU_OP_ZERO,
|
||
`ALU_OP_COPY,
|
||
`ALU_OP_EXCH, // does the first assign
|
||
`ALU_OP_2CMPL,
|
||
`ALU_OP_CLR_MASK:
|
||
case (reg_dest)
|
||
`ALU_REG_A: A[f_cur*4+:4] <= c_res1;
|
||
`ALU_REG_B: B[f_cur*4+:4] <= c_res1;
|
||
`ALU_REG_C: C[f_cur*4+:4] <= c_res1;
|
||
`ALU_REG_D: D[f_cur*4+:4] <= c_res1;
|
||
`ALU_REG_D0: D0[f_cur*4+:4] <= c_res1;
|
||
`ALU_REG_D1: D1[f_cur*4+:4] <= c_res1;
|
||
`ALU_REG_ST: ST[f_cur*4+:4] <= c_res1;
|
||
`ALU_REG_P: P <= c_res1;
|
||
`ALU_REG_HST: HST <= c_res1;
|
||
endcase
|
||
`ALU_OP_RST_BIT,
|
||
`ALU_OP_SET_BIT:
|
||
case (reg_dest)
|
||
`ALU_REG_ST: ST[c_res1] <= alu_op==`ALU_OP_SET_BIT?1:0;
|
||
default: $display("#### ALU_SAVE invalid register %0d for op %0d", reg_dest, alu_op);
|
||
endcase
|
||
`ALU_OP_JMP_REL3,
|
||
`ALU_OP_JMP_REL4,
|
||
`ALU_OP_JMP_ABS5: begin end // nothing to save, handled by PC management below
|
||
default: $display("#### ALU_SAVE UNHANDLED OP %0d", alu_op);
|
||
endcase
|
||
|
||
case (alu_op)
|
||
`ALU_OP_EXCH: // 2nd assign, with src2
|
||
case (reg_src2)
|
||
`ALU_REG_A: A[f_cur*4+:4] <= c_res2;
|
||
`ALU_REG_B: B[f_cur*4+:4] <= c_res2;
|
||
`ALU_REG_C: C[f_cur*4+:4] <= c_res2;
|
||
`ALU_REG_D: D[f_cur*4+:4] <= c_res2;
|
||
// `ALU_REG_D0: D0[f_start*4+:4] <= c_res2;
|
||
// `ALU_REG_D1: D1[f_start*4+:4] <= c_res2;
|
||
// `ALU_REG_ST: ST[f_start*4+:4] <= c_res2;
|
||
// `ALU_REG_P: P <= c_res2;
|
||
// `ALU_REG_HST: HST <= c_res2;
|
||
endcase
|
||
endcase
|
||
|
||
end
|
||
|
||
|
||
|
||
if (do_alu_save) begin
|
||
case (alu_op)
|
||
`ALU_OP_2CMPL: CARRY <= !is_zero;
|
||
endcase
|
||
end
|
||
|
||
// do whatever is requested by the RTN instruction
|
||
if (i_ins_rtn) begin
|
||
|
||
if (i_set_xm)
|
||
HST[`ALU_HST_XM] <= 1;
|
||
|
||
if (i_set_carry)
|
||
CARRY <= i_carry_val;
|
||
|
||
end
|
||
|
||
end
|
||
|
||
/*****************************************************************************
|
||
*
|
||
* Handles all changes to PC
|
||
*
|
||
****************************************************************************/
|
||
|
||
wire [19:0] next_pc;
|
||
wire [0:0] update_pc;
|
||
wire [0:0] push_pc;
|
||
|
||
assign next_pc = (is_alu_op_jump && alu_finish)?jump_pc:PC + 1;
|
||
assign update_pc = !o_alu_stall_dec || is_alu_op_jump;
|
||
assign push_pc = update_pc && i_push && alu_finish;
|
||
|
||
always @(posedge i_clk) begin
|
||
if (i_reset)
|
||
PC <= ~0;
|
||
|
||
/*
|
||
* some debug information
|
||
*/
|
||
|
||
`ifdef SIM
|
||
if (do_alu_shpc && alu_debug_pc) begin
|
||
if (!o_alu_stall_dec)
|
||
$display("ALU_SHPC 0: pc %5h", PC);
|
||
if (o_alu_stall_dec)
|
||
$display("ALU_SHPC 0: STALL");
|
||
end
|
||
`endif
|
||
|
||
/*
|
||
* updates the PC
|
||
*/
|
||
if (do_alu_pc) begin
|
||
`ifdef SIM
|
||
if (alu_debug_pc)
|
||
$display("ALU_PC 3: !stl %b | nx %5h | done %b | fin %b | jmp %b | ins_rtn %b | push %b",
|
||
!o_alu_stall_dec, next_pc, alu_done, alu_finish, is_alu_op_jump, i_ins_rtn, i_push);
|
||
if (is_alu_op_jump && alu_done) begin
|
||
$display(".---------------------------------.");
|
||
$display("| SHOULD TELL THE BUS CONTROLLER |");
|
||
$display("| TO LOAD PC INTO MODULES' PC REG |");
|
||
$display("`---------------------------------´");
|
||
end
|
||
`endif
|
||
// this may do wierd things with C=RSTK...
|
||
if (update_pc) begin
|
||
PC <= i_pop ? RSTK[rstk_ptr-1] : next_pc;
|
||
end
|
||
|
||
if (i_pop) begin
|
||
RSTK[rstk_ptr - 1] <= 0;
|
||
rstk_ptr <= rstk_ptr - 1;
|
||
end
|
||
|
||
if (push_pc) begin
|
||
$display("PUSH PC %5h to RSTK[%0d]", PC, rstk_ptr);
|
||
RSTK[rstk_ptr] <= PC;
|
||
rstk_ptr <= rstk_ptr + 1;
|
||
end
|
||
end
|
||
end
|
||
|
||
/*****************************************************************************
|
||
*
|
||
* execute SETHEX and SETDEC
|
||
*
|
||
****************************************************************************/
|
||
|
||
always @(posedge i_clk)
|
||
// changing calculation modes
|
||
if (do_alu_mode) begin
|
||
$display("SETTING MODE TO %s", i_mode_dec?"DEC":"HEX");
|
||
DEC <= i_mode_dec;
|
||
end
|
||
|
||
|
||
endmodule
|
||
|
||
`endif |