mirror of
https://github.com/alangarf/apple-one.git
synced 2024-08-29 20:29:32 +00:00
109 lines
2.2 KiB
Coq
109 lines
2.2 KiB
Coq
|
/*
|
||
|
* ALU.
|
||
|
*
|
||
|
* AI and BI are 8 bit inputs. Result in OUT.
|
||
|
* CI is Carry In.
|
||
|
* CO is Carry Out.
|
||
|
*
|
||
|
* op[3:0] is defined as follows:
|
||
|
*
|
||
|
* 0011 AI + BI
|
||
|
* 0111 AI - BI
|
||
|
* 1011 AI + AI
|
||
|
* 1100 AI | BI
|
||
|
* 1101 AI & BI
|
||
|
* 1110 AI ^ BI
|
||
|
* 1111 AI
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
module ALU( clk, op, right, AI, BI, CI, CO, BCD, OUT, V, Z, N, HC, RDY );
|
||
|
input clk;
|
||
|
input right;
|
||
|
input [3:0] op; // operation
|
||
|
input [7:0] AI;
|
||
|
input [7:0] BI;
|
||
|
input CI;
|
||
|
input BCD; // BCD style carry
|
||
|
output [7:0] OUT;
|
||
|
output CO;
|
||
|
output V;
|
||
|
output Z;
|
||
|
output N;
|
||
|
output HC;
|
||
|
input RDY;
|
||
|
|
||
|
reg [7:0] OUT;
|
||
|
reg CO;
|
||
|
wire V;
|
||
|
wire Z;
|
||
|
reg N;
|
||
|
reg HC;
|
||
|
|
||
|
reg AI7;
|
||
|
reg BI7;
|
||
|
reg [8:0] temp_logic;
|
||
|
reg [7:0] temp_BI;
|
||
|
reg [4:0] temp_l;
|
||
|
reg [4:0] temp_h;
|
||
|
wire [8:0] temp = { temp_h, temp_l[3:0] };
|
||
|
wire adder_CI = (right | (op[3:2] == 2'b11)) ? 0 : CI;
|
||
|
|
||
|
// calculate the logic operations. The 'case' can be done in 1 LUT per
|
||
|
// bit. The 'right' shift is a simple mux that can be implemented by
|
||
|
// F5MUX.
|
||
|
always @* begin
|
||
|
case( op[1:0] )
|
||
|
2'b00: temp_logic = AI | BI;
|
||
|
2'b01: temp_logic = AI & BI;
|
||
|
2'b10: temp_logic = AI ^ BI;
|
||
|
2'b11: temp_logic = AI;
|
||
|
endcase
|
||
|
|
||
|
if( right )
|
||
|
temp_logic = { AI[0], CI, AI[7:1] };
|
||
|
end
|
||
|
|
||
|
// Add logic result to BI input. This only makes sense when logic = AI.
|
||
|
// This stage can be done in 1 LUT per bit, using carry chain logic.
|
||
|
always @* begin
|
||
|
case( op[3:2] )
|
||
|
2'b00: temp_BI = BI; // A+B
|
||
|
2'b01: temp_BI = ~BI; // A-B
|
||
|
2'b10: temp_BI = temp_logic; // A+A
|
||
|
2'b11: temp_BI = 0; // A+0
|
||
|
endcase
|
||
|
end
|
||
|
|
||
|
// HC9 is the half carry bit when doing BCD add
|
||
|
wire HC9 = BCD & (temp_l[3:1] >= 3'd5);
|
||
|
|
||
|
// CO9 is the carry-out bit when doing BCD add
|
||
|
wire CO9 = BCD & (temp_h[3:1] >= 3'd5);
|
||
|
|
||
|
// combined half carry bit
|
||
|
wire temp_HC = temp_l[4] | HC9;
|
||
|
|
||
|
// perform the addition as 2 separate nibble, so we get
|
||
|
// access to the half carry flag
|
||
|
always @* begin
|
||
|
temp_l = temp_logic[3:0] + temp_BI[3:0] + adder_CI;
|
||
|
temp_h = temp_logic[8:4] + temp_BI[7:4] + temp_HC;
|
||
|
end
|
||
|
|
||
|
// calculate the flags
|
||
|
always @(posedge clk)
|
||
|
if( RDY ) begin
|
||
|
AI7 <= AI[7];
|
||
|
BI7 <= temp_BI[7];
|
||
|
OUT <= temp[7:0];
|
||
|
CO <= temp[8] | CO9;
|
||
|
N <= temp[7];
|
||
|
HC <= temp_HC;
|
||
|
end
|
||
|
|
||
|
assign V = AI7 ^ BI7 ^ CO ^ N;
|
||
|
assign Z = ~|OUT;
|
||
|
|
||
|
endmodule
|