forked from Arlet/verilog-6502
-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathALU.v
executable file
·138 lines (120 loc) · 2.92 KB
/
ALU.v
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
/*
* parameterisable ALU for 6502 and 65Org16
*
* verilog-6502 project: verilog model of 6502 and 65Org16 CPU core
*
* (C) 2011 Arlet Ottens, <[email protected]>
* (C) 2011 Ed Spittles, <[email protected]>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation.
*
* 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, OUT, V, Z, N,
`ifdef BCD_ENABLED
BCD,
HC,
`endif
RDY );
parameter dw = 16; // data width (8 for 6502, 16 for 65Org16)
input clk;
input right;
input [3:0] op; // operation
input [dw-1:0] AI;
input [dw-1:0] BI;
input CI;
output [dw-1:0] OUT;
output CO;
output V;
output Z;
output N;
`ifdef BCD_ENABLED
input BCD; // BCD style carry
output HC;
`endif
input RDY;
reg [dw-1:0] OUT;
reg CO;
reg V;
reg Z;
reg N;
reg [dw:0] logical;
reg [dw-1:0] temp_BI;
`ifdef BCD_ENABLED
reg HC;
reg [4:0] temp_l;
reg [dw-4:0] temp_h;
wire [dw:0] temp = { temp_h, temp_l[3:0] };
`else
wire [dw:0] temp = logical + temp_BI + adder_CI;
`endif
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: logical = AI | BI;
2'b01: logical = AI & BI;
2'b10: logical = AI ^ BI;
2'b11: logical = AI;
endcase
if( right )
logical = { AI[0], CI, AI[dw-1: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 = logical[dw-1:0]; // A+A
2'b11: temp_BI = 0; // A+0
endcase
end
`ifdef BCD_ENABLED
// 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 = logical[3:0] + temp_BI[3:0] + adder_CI;
temp_h = logical[dw:4] + temp_BI[dw-1:4] + temp_HC;
end
`endif
// calculate the flags
always @(posedge clk)
if( RDY ) begin
OUT <= temp[dw-1:0];
CO <= temp[dw]
`ifdef BCD_ENABLED
| CO9
`endif
;
Z <= ~|temp[dw-1:0];
N <= temp[dw-1];
V <= AI[dw-1] ^ temp_BI[dw-1] ^ temp[dw-1] ^ temp[dw];
`ifdef BCD_ENABLED
HC <= temp_HC;
`endif
end
endmodule