1/*
2 Режимы работы АЛУ
3 ---------------------------------------------------------------------
4 0 LDI    9  EOR      11 LSR      19 MULSU
5 1 CPC    A  OR       12 ROR
6 2 SBC    B  <SREG>   13 DEC
7 3 ADD    C  COM      14 ADIW
8 5 CP     D  NEG      15 SBIW
9 6 SUB    E  SWAP     16 BLD
10 7 ADC    F  INC      17 MUL
11 8 AND    10 ASR      18 MULS
12 ---------------------------------------------------------------------
13*/
14
15module avralu
16(
17    // Входные данные на обработку
18    input      [ 4:0] mode,         // режим
19    input      [ 7:0] dst,          // dst
20    input      [ 7:0] src,          // src
21    input      [15:0] src16,        // src (16 бит)
22    input      [ 7:0] si,           // sreg
23
24    // Результат
25    output reg [ 7:0] so,           // Исходящие флаги
26    output reg [ 7:0] resb,         // Результат 8 бит
27    output reg [15:0] resw          // Результат 16 бит
28);
29
30// Вычисления
31wire [7:0] sub  = dst - src;            // Вычитание
32wire [7:0] add  = dst + src;            // Сложение
33wire [8:0] sbc  = dst - src - si[0];    // Вычитание с заемом
34wire [7:0] adc  = dst + src + si[0];    // Сложение с заемом
35wire [7:0] lsr  = {  1'b0, dst[7:1]};   // Логический сдвиг вправо
36wire [7:0] ror  = { si[0], dst[7:1]};   // Сдвиг вправо с заемом
37wire [7:0] asr  = {dst[7], dst[7:1]};   // Арифметический сдвиг вправо
38wire [7:0] neg  = -dst;                 // Отрицательное значение
39wire [7:0] inc  = dst + 1;              // Инкремент
40wire [7:0] dec  = dst - 1;              // Декремент
41wire [7:0] com  = dst ^ 8'hFF;          // Комплементация
42wire [7:0] swap = {dst[3:0], dst[7:4]}; // Обмен нибблами
43reg        carry;
44
45// 16 битные вычисления
46wire [15:0] adiw  = src16 + src;
47wire [15:0] sbiw  = src16 - src;
48wire [15:0] mul   = dst[7:0] * src[7:0];
49wire [15:0] mulsu = {{8{dst[7]}}, dst[7:0]} * src[7:0];
50wire [15:0] muls  = {{8{dst[7]}}, dst[7:0]} * {{8{src[7]}}, src[7:0]};
51
52// Флаги переполнения после сложения и вычитания
53wire add_flag_v = (dst[7] &  src[7] & !resb[7]) | (!dst[7] & !src[7] & resb[7]);
54wire sub_flag_v = (dst[7] & !src[7] & !resb[7]) | (!dst[7] &  src[7] & resb[7]);
55wire neg_flag_v = (resb == 8'h80);
56
57// Флаги половинного переполнения после сложения и вычитания
58wire add_flag_h = ( dst[3] & src[3]) | (src[3] & !resb[3]) | (!resb[3] &  dst[3]);
59wire sub_flag_h = (!dst[3] & src[3]) | (src[3] &  resb[3]) | ( resb[3] & !dst[3]);
60wire neg_flag_h = dst[3] | (dst[3] & resb[3]) | resb[3];
61
62// Флаги ADIW, SBIW
63wire adiw_v = !src16[15] & resw [15];
64wire adiw_c = !resw [15] & src16[15];
65
66// Логические флаги
67wire [7:0] set_logic_flag = {
68
69    /* i */ si[7],
70    /* t */ si[6],
71    /* h */ si[5],
72    /* s */ resb[7],
73    /* v */ 1'b0,
74    /* n */ resb[7],
75    /* z */ resb[7:0] == 0,
76    /* c */ si[0]
77};
78
79// Флаги после вычитания с переносом
80wire [7:0] set_subcarry_flag = {
81
82    /* i */ si[7],
83    /* t */ si[6],
84    /* h */ sub_flag_h,
85    /* s */ sub_flag_v ^ resb[7],
86    /* v */ sub_flag_v,
87    /* n */ resb[7],
88    /* z */ (resb[7:0] == 0) & si[1],
89    /* c */ sbc[8]
90};
91
92// Флаги после вычитания
93wire [7:0] set_subtract_flag = {
94
95    /* i */ si[7],
96    /* t */ si[6],
97    /* h */ sub_flag_h,
98    /* s */ sub_flag_v ^ resb[7],
99    /* v */ sub_flag_v,
100    /* n */ resb[7],
101    /* z */ (resb[7:0] == 0),
102    /* c */ dst < src
103};
104
105// Флаги после COM
106wire [7:0] set_com_flag = {
107
108    /* i */ si[7],
109    /* t */ si[6],
110    /* h */ si[5],
111    /* s */ resb[7],
112    /* v */ 1'b0,
113    /* n */ resb[7],
114    /* z */ (resb[7:0] == 0),
115    /* c */ 1'b1
116};
117
118// Флаги после NEG
119wire [7:0] set_neg_flag = {
120
121    /* i */ si[7],
122    /* t */ si[6],
123    /* h */ neg_flag_h,
124    /* s */ neg_flag_v ^ resb[7],
125    /* v */ neg_flag_v,
126    /* n */ resb[7],
127    /* z */ (resb[7:0] == 0),
128    /* c */ dst != 0
129};
130
131// Флаги после сложения с переносом
132wire [7:0] set_add_flag = {
133
134    /* i */ si[7],
135    /* t */ si[6],
136    /* h */ add_flag_h,
137    /* s */ add_flag_v ^ resb[7],
138    /* v */ add_flag_v,
139    /* n */ resb[7],
140    /* z */ (resb[7:0] == 0),
141    /* c */ dst + src + carry >= 9'h100
142};
143
144// Флаги после логической операции сдвига вправо
145wire [7:0] set_lsr_flag = {
146
147    /* i */ si[7],
148    /* t */ si[6],
149    /* h */ si[5],
150    /* s */ dst[0],
151    /* v */ resb[7] ^ dst[0],
152    /* n */ resb[7],
153    /* z */ (resb[7:0] == 0),
154    /* c */ dst[0]
155};
156
157// Флаги после INC
158wire [7:0] set_inc_flag = {
159
160    /* i */ si[7],
161    /* t */ si[6],
162    /* h */ si[5],
163    /* s */ (resb == 8'h80) ^ resb[7],
164    /* v */ (resb == 8'h80),
165    /* n */ resb[7],
166    /* z */ (resb[7:0] == 0),
167    /* c */ si[0]
168};
169
170// Флаги после DEC
171wire [7:0] set_dec_flag = {
172
173    /* i */ si[7],
174    /* t */ si[6],
175    /* h */ si[5],
176    /* s */ (resb == 8'h7F) ^ resb[7],
177    /* v */ (resb == 8'h7F),
178    /* n */ resb[7],
179    /* z */ (resb[7:0] == 0),
180    /* c */ si[0]
181};
182
183// Флаги после ADIW
184wire [7:0] set_adiw_flag = {
185
186    /* i */ si[7],
187    /* t */ si[6],
188    /* h */ si[5],
189    /* s */ adiw_v ^ resw[15],
190    /* v */ adiw_v,
191    /* n */ resw[15],
192    /* z */ (resw[15:0] == 0),
193    /* c */ adiw_c
194};
195
196// Флаги после SBIW
197wire [7:0] set_sbiw_flag = {
198
199    /* i */ si[7],
200    /* t */ si[6],
201    /* h */ si[5],
202    /* s */ adiw_v ^ resw[15],
203    /* v */ adiw_v,
204    /* n */ resw[15],
205    /* z */ (resw[15:0] == 0),
206    /* c */ adiw_v
207};
208
209// Флаги после MUL
210wire [7:0] set_mul_flag = {
211
212    /* i */ si[7],
213    /* t */ si[6],
214    /* h */ si[5],
215    /* s */ si[7],
216    /* v */ si[7],
217    /* n */ si[7],
218    /* z */ (mul[15:0] == 0),
219    /* c */ mul[15]
220};
221
222always @(*) begin
223
224    so    = si;
225    carry = 0;
226
227    case (mode)
228
229        /* LDI   */ 0:  begin resb = src; end
230        /* CPC   */ 1:  begin resb = sbc[7:0];   so = set_subcarry_flag; end
231        /* SBC   */ 2:  begin resb = sbc[7:0];   so = set_subcarry_flag; end
232        /* ADD   */ 3:  begin resb = add;        so = set_add_flag;      carry = 0; end
233        /* CP    */ 5:  begin resb = sub;        so = set_subtract_flag; end
234        /* SUB   */ 6:  begin resb = sub;        so = set_subtract_flag; end
235        /* ADC   */ 7:  begin resb = adc;        so = set_add_flag;      carry = si[0]; end
236        /* AND   */ 8:  begin resb = dst & src;  so = set_logic_flag;   end
237        /* EOR   */ 9:  begin resb = dst ^ src;  so = set_logic_flag;   end
238        /* OR    */ 10: begin resb = dst | src;  so = set_logic_flag;   end
239        /* SREG  */ 11: begin                    so = src;              end
240        /* COM   */ 12: begin resb = com;        so = set_com_flag;     end
241        /* NEG   */ 13: begin resb = neg;        so = set_neg_flag;     end
242        /* SWAP  */ 14: begin resb = swap;       end
243        /* INC   */ 15: begin resb = inc;        so = set_inc_flag;     end
244        /* ASR   */ 16: begin resb = asr;        so = set_lsr_flag;     end
245        /* LSR   */ 17: begin resb = lsr;        so = set_lsr_flag;     end
246        /* ROR   */ 18: begin resb = ror;        so = set_lsr_flag;     end
247        /* DEC   */ 19: begin resb = dec;        so = set_dec_flag;     end
248        /* ADIW  */ 20: begin resw = adiw;       so = set_adiw_flag;    end
249        /* SBIW  */ 21: begin resw = sbiw;       so = set_sbiw_flag;    end
250        /* BLD   */ 22: case (src[2:0])
251
252            0: resb = {dst[7:1], si[6]};
253            1: resb = {dst[7:2], si[6], dst[  0]};
254            2: resb = {dst[7:3], si[6], dst[1:0]};
255            3: resb = {dst[7:4], si[6], dst[2:0]};
256            4: resb = {dst[7:5], si[6], dst[3:0]};
257            5: resb = {dst[7:6], si[6], dst[4:0]};
258            6: resb = {dst[  7], si[6], dst[5:0]};
259            7: resb = {          si[6], dst[6:0]};
260
261        endcase
262        /* MUL   */ 23: begin resw = mul;   so = set_mul_flag; end
263        /* MULS  */ 24: begin resw = muls;  so = set_mul_flag; end
264        /* MULSU */ 25: begin resw = mulsu; so = set_mul_flag; end
265
266        default: resb = 8'hFF;
267
268    endcase
269
270end
271
272endmodule