174 lines
3.1 KiB
Verilog
174 lines
3.1 KiB
Verilog
module alu(
|
|
input clk,
|
|
input rst,
|
|
input cs,
|
|
input flags_we,
|
|
input a_we,
|
|
input a_store,
|
|
input a_restore,
|
|
input tmp_we,
|
|
input[4:0] op,
|
|
input[7:0] bus,
|
|
output[7:0] flags,
|
|
output[7:0] out
|
|
);
|
|
|
|
reg carry;
|
|
|
|
wire flg_c;
|
|
wire flg_z;
|
|
wire flg_p;
|
|
wire flg_s;
|
|
|
|
reg[7:0] acc;
|
|
reg[7:0] flg;
|
|
reg[7:0] act; // Internal
|
|
reg[7:0] tmp; // Internal
|
|
|
|
localparam FLG_Z = 0;
|
|
localparam FLG_C = 1;
|
|
localparam FLG_P = 2;
|
|
localparam FLG_S = 3;
|
|
|
|
localparam OP_ADD = 5'b00000;
|
|
localparam OP_ADC = 5'b00001;
|
|
localparam OP_SUB = 5'b00010;
|
|
localparam OP_SBB = 5'b00011;
|
|
localparam OP_ANA = 5'b00100;
|
|
localparam OP_XRA = 5'b00101;
|
|
localparam OP_ORA = 5'b00110;
|
|
localparam OP_CMP = 5'b00111;
|
|
localparam OP_RLC = 5'b01000;
|
|
localparam OP_RRC = 5'b01001;
|
|
localparam OP_RAL = 5'b01010;
|
|
localparam OP_RAR = 5'b01011;
|
|
localparam OP_DAA = 5'b01100; // Unsupported
|
|
localparam OP_CMA = 5'b01101;
|
|
localparam OP_STC = 5'b01110;
|
|
localparam OP_CMC = 5'b01111;
|
|
localparam OP_INR = 5'b10000;
|
|
localparam OP_DCR = 5'b10001;
|
|
|
|
assign flg_c = (carry == 1'b1);
|
|
assign flg_z = (acc[7:0] == 8'b0);
|
|
assign flg_s = acc[7];
|
|
assign flg_p = ~^acc[7:0];
|
|
|
|
always @(posedge clk, posedge rst) begin
|
|
if (rst) begin
|
|
acc <= 8'b0;
|
|
act <= 8'b0;
|
|
tmp <= 8'b0;
|
|
carry <= 1'b0;
|
|
end else begin
|
|
if (a_we) begin
|
|
acc <= bus;
|
|
end else if (a_restore) begin
|
|
acc <= act;
|
|
end else if (cs) begin
|
|
case (op)
|
|
OP_ADD: begin
|
|
{carry, acc} <= acc + tmp;
|
|
end
|
|
OP_ADC: begin
|
|
{carry, acc} <= acc + tmp + flg[FLG_C];
|
|
end
|
|
OP_SUB: begin
|
|
{carry, acc} <= acc - tmp;
|
|
end
|
|
OP_SBB: begin
|
|
{carry, acc} <= acc - tmp - flg[FLG_C];
|
|
end
|
|
OP_ANA: begin
|
|
{carry, acc} <= acc & tmp;
|
|
end
|
|
OP_XRA: begin
|
|
{carry, acc} <= acc ^ tmp;
|
|
end
|
|
OP_ORA: begin
|
|
{carry, acc} <= acc | tmp;
|
|
end
|
|
OP_CMP: begin
|
|
act <= acc - tmp;
|
|
end
|
|
OP_RLC: begin
|
|
carry <= acc[7];
|
|
acc <= acc << 1;
|
|
end
|
|
OP_RRC: begin
|
|
carry <= acc[0];
|
|
acc <= acc >> 1;
|
|
end
|
|
OP_RAL: begin
|
|
carry <= acc[7];
|
|
acc <= (acc << 1 | {7'b0, flg[FLG_C]});
|
|
end
|
|
OP_RAR: begin
|
|
carry <= acc[0];
|
|
acc <= (acc >> 1 | {flg[FLG_C], 7'b0});
|
|
end
|
|
OP_CMA: begin
|
|
acc <= ~acc;
|
|
end
|
|
OP_STC: begin
|
|
carry <= 1'b1;
|
|
end
|
|
OP_CMC: begin
|
|
carry <= ~flg[FLG_C];
|
|
end
|
|
OP_INR: begin
|
|
acc <= acc + 1;
|
|
end
|
|
OP_DCR: begin
|
|
acc <= acc - 1;
|
|
end
|
|
endcase
|
|
end
|
|
|
|
if (a_store)
|
|
act <= acc;
|
|
|
|
if (tmp_we)
|
|
tmp <= bus;
|
|
end
|
|
end
|
|
|
|
always @(negedge clk, posedge rst) begin
|
|
if (rst) begin
|
|
flg <= 8'b0;
|
|
end else if (flags_we) begin
|
|
flg <= bus;
|
|
end else begin
|
|
if (cs) begin
|
|
case (op)
|
|
OP_ADD, OP_ADC, OP_SUB, OP_SBB, OP_ANA, OP_XRA, OP_ORA: begin
|
|
flg[FLG_C] <= flg_c;
|
|
flg[FLG_Z] <= flg_z;
|
|
flg[FLG_S] <= flg_s;
|
|
flg[FLG_P] <= flg_p;
|
|
end
|
|
|
|
OP_CMP: begin
|
|
flg[FLG_Z] <= (act == 8'b0);
|
|
end
|
|
|
|
OP_INR, OP_DCR: begin
|
|
flg[FLG_Z] <= flg_z;
|
|
flg[FLG_S] <= flg_s;
|
|
flg[FLG_P] <= flg_p;
|
|
end
|
|
|
|
OP_RLC, OP_RRC, OP_RAL, OP_RAR, OP_STC, OP_CMC: begin
|
|
flg[FLG_C] <= flg_c;
|
|
end
|
|
endcase
|
|
end
|
|
end
|
|
end
|
|
|
|
assign flags = flg;
|
|
assign out = acc;
|
|
|
|
endmodule
|
|
|