svgb/rtl/cpu/alu.sv
Koray Yanik fda176d3b5 Complete rewrite from scratch, bootstrap WIP
Rewrite to use several bus multiplexers, resulting into a less messy
microarchitecture (hopefully). Some more room for cleanup though...

Supports every instruction from the bootstrap rom, more or less.
LY hacked at 0x90 to progress through vsync instantly.
No cartridge is present yet, so we will always fail checksum test and lock up.
2023-10-01 23:00:56 +01:00

170 lines
4.9 KiB
Systemverilog

`include "cpu_pkg.svh"
import cpu_pkg::*;
module alu (
input logic clk,
input logic nreset,
input alu_ctrl_t alu_ctrl_i,
input logic [ 7:0] operand_in_i,
output logic [ 7:0] operand_out_o,
output logic [ 7:0] reg_a_o,
output logic [ 7:0] reg_f_o
);
logic nop_valid;
logic a_we;
logic [ 7:0] a_r;
logic [ 7:0] a_next;
logic f_we;
logic [ 7:0] f_r;
logic [ 7:0] f_next;
always_ff @(posedge clk or negedge nreset) begin
if (!nreset)
a_r <= '0;
else if (a_we)
a_r <= a_next;
end
always_ff @(posedge clk or negedge nreset) begin
if (!nreset)
f_r <= '0;
else if (f_we)
f_r <= f_next;
end
assign a_we = alu_ctrl_i.update_a;
assign f_we = alu_ctrl_i.update_f;
assign reg_a_o = a_r;
assign reg_f_o = f_r;
logic [ 7:0] alu_a;
logic [ 7:0] alu_f;
logic [ 7:0] shift_a;
logic [ 7:0] shift_f;
logic [ 7:0] bsr_a;
logic [ 7:0] bsr_f;
logic [ 7:0] incdec_a;
logic [ 7:0] incdec_f;
assign nop_valid = ~alu_ctrl_i.alu_op_valid &
~alu_ctrl_i.shift_op_valid &
~alu_ctrl_i.bsr_op_valid &
~alu_ctrl_i.incdec_op_valid;
assign a_next = ({8{alu_ctrl_i.alu_op_valid }} & alu_a) |
({8{alu_ctrl_i.shift_op_valid }} & shift_a) |
({8{alu_ctrl_i.bsr_op_valid }} & bsr_a) |
({8{alu_ctrl_i.incdec_op_valid}} & incdec_a) |
({8{nop_valid }} & operand_in_i);
assign f_next = ({8{alu_ctrl_i.alu_op_valid }} & alu_f) |
({8{alu_ctrl_i.shift_op_valid }} & shift_f) |
({8{alu_ctrl_i.bsr_op_valid }} & bsr_f) |
({8{alu_ctrl_i.incdec_op_valid}} & incdec_f) |
({8{nop_valid }} & operand_in_i);
logic [ 8:0] add_a;
logic [ 7:0] add_f;
logic [ 8:0] sub_a;
logic [ 7:0] sub_f;
logic [ 7:0] xor_a;
logic [ 7:0] xor_f;
logic [ 7:0] cp_a;
logic [ 7:0] cp_f;
assign alu_a = ({8{alu_ctrl_i.alu_op == ALU_OP_ADD}} & add_a) |
({8{alu_ctrl_i.alu_op == ALU_OP_SUB}} & sub_a) |
({8{alu_ctrl_i.alu_op == ALU_OP_XOR}} & xor_a) |
({8{alu_ctrl_i.alu_op == ALU_OP_CP }} & cp_a);
assign alu_f = ({8{alu_ctrl_i.alu_op == ALU_OP_ADD}} & add_f) |
({8{alu_ctrl_i.alu_op == ALU_OP_SUB}} & sub_f) |
({8{alu_ctrl_i.alu_op == ALU_OP_XOR}} & xor_f) |
({8{alu_ctrl_i.alu_op == ALU_OP_CP }} & cp_f);
assign add_a = {1'b0, a_r} + {1'b0, operand_in_i};
assign add_f = {~(|sub_a[7:0]), 1'b0, 1'b0, sub_a[8], f_r[3:0]}; // TODO: implement H
assign sub_a = {1'b0, a_r} - {1'b0, operand_in_i};
assign sub_f = {~(|sub_a[7:0]), 1'b1, 1'b0, sub_a[8], f_r[3:0]}; // TODO: implement H
assign xor_a = a_r ^ operand_in_i;
assign xor_f = {~(|xor_a), 3'b0, f_r[3:0]};
assign cp_a = a_r;
assign cp_f = sub_f;
logic [ 7:0] bit_a;
logic [ 7:0] bit_f;
assign bsr_a = ({8{alu_ctrl_i.bsr_op.b}} & bit_a);
assign bsr_f = ({8{alu_ctrl_i.bsr_op.b}} & bit_f);
assign bit_a = {7'b0, ~operand_in_i[alu_ctrl_i.bsr_op.operand]};
assign bit_f = {bit_a[0], 2'b10, f_r[4:0]};
logic [ 7:0] rl_a;
logic [ 7:0] rl_f;
assign shift_a = ({8{alu_ctrl_i.shift_op == SHIFT_OP_RL}} & rl_a);
assign shift_f = ({8{alu_ctrl_i.shift_op == SHIFT_OP_RL}} & rl_f);
assign rl_a = {operand_in_i[6:0], f_r[4]};
assign rl_f = {~(|rl_a), 2'b0, operand_in_i[7], f_r[3:0]};
logic [ 7:0] incdec_input;
logic [ 7:0] inc_a;
logic [ 7:0] inc_f;
logic [ 7:0] dec_a;
logic [ 7:0] dec_f;
assign incdec_input = alu_ctrl_i.incdec_op.dst_a ? a_r :
operand_in_i;
assign incdec_a = ({8{alu_ctrl_i.incdec_op.inc}} & inc_a) |
({8{alu_ctrl_i.incdec_op.dec}} & dec_a);
assign incdec_f = ({8{alu_ctrl_i.incdec_op.inc}} & inc_f) |
({8{alu_ctrl_i.incdec_op.dec}} & dec_f);
assign inc_a = incdec_input + 8'h01;
assign inc_f = {~(|inc_a), 1'b0, inc_a[4], f_r[4], f_r[3:0]};
assign dec_a = incdec_input - 8'h01;
assign dec_f = {~(|dec_a), 1'b1, dec_a[4], f_r[4], f_r[3:0]};
assign operand_out_o = ({8{alu_ctrl_i.shift_op_valid }} & shift_a) |
({8{alu_ctrl_i.incdec_op_valid}} & incdec_a);
`include "sva_common.svh"
`SVA_DEF_CLK(clk);
`SVA_DEF_NRESET(nreset);
`SVA_ASSERT_PROP_FATAL(undefined_alu_op,
tb_top.gb_inst.cpu_inst.instr_valid & alu_ctrl_i.alu_op_valid |-> alu_ctrl_i.alu_op inside {ALU_OP_ADD, ALU_OP_SUB, ALU_OP_XOR, ALU_OP_CP},
$sformatf("Undefined alu operation pushed: 0x%X", alu_ctrl_i.alu_op)
);
`SVA_ASSERT_PROP_FATAL(undefined_shift_op,
tb_top.gb_inst.cpu_inst.instr_valid & alu_ctrl_i.shift_op_valid |-> alu_ctrl_i.shift_op inside {SHIFT_OP_RL},
$sformatf("Undefined shift operation pushed: 0x%X", alu_ctrl_i.shift_op)
);
`SVA_ASSERT_PROP_FATAL(undefined_bsr_op,
tb_top.gb_inst.cpu_inst.instr_valid & alu_ctrl_i.bsr_op_valid |-> alu_ctrl_i.bsr_op.b,
$sformatf("Undefined bsr operation pushed: 0x%X", alu_ctrl_i.bsr_op)
);
endmodule : alu