§ Код ядра

Описание пинов:
  • clock — тактовая частота, срабатывает на позитивном и негативном фронте, который записывает результаты в регистры
  • reset_n — при 0, сброс процессора
  • pc — указатель Program Counter
  • ir — данные 16 битные из rom[pc]
  • address — указатель в оперативную память, до 64К
  • data_i — входящие в процессор данные
  • data_o — данные на запись
  • intr — прерывание, срабатывает на перемене состояния
  • vect — номер прерывания от 0 до 7
  • we — сигнал записи, длительность сигнала — 1 такт на 1 инструкцию
  • read — сигнал, что данные были именно прочитаны из памяти (тоже 1 такт на 1 инструкцию)
Ревизия обновлена: 14 янв 2024.

§ Код ядра

Ниже представлен готовый код ядра процессора.
1/* verilator lint_off WIDTH */
2/* verilator lint_off CASEX */
3/* verilator lint_off CASEINCOMPLETE */
4/* verilator lint_off UNOPTFLAT */
5module avr
6(
7    input               clock,
8    input               reset_n,
9    // Программная память
10    output reg  [15:0]  pc,         // Программный счетчик
11    input       [15:0]  ir,         // Инструкция из памяти
12    // Оперативная память
13    output reg  [15:0]  address,    // Указатель на память RAM (sram)
14    input       [ 7:0]  data_i,     // = memory[ address ]
15    output reg  [ 7:0]  data_o,     // Запись в память по address
16    output reg          we,         // =1 Запись в память
17    output reg          read,       // =1 Запрос чтения из памяти
18    // Внешнее прерывание #0..7
19    input               intr,
20    input       [ 2:0]  vect
21);
22initial begin
23    address = 1'b0;
24    pc      = 1'b0;
25    we      = 1'b0;
26    data_o  = 1'b0;
27    read    = 1'b0;
28    // Регистры 0-15
29    r[0] = 8'h00; r[4] = 8'h00; r[8]  = 8'h00; r[12] = 8'h01;
30    r[1] = 8'h00; r[5] = 8'h00; r[9]  = 8'h00; r[13] = 8'h00;
31    r[2] = 8'h00; r[6] = 8'h00; r[10] = 8'h00; r[14] = 8'h00;
32    r[3] = 8'h00; r[7] = 8'h00; r[11] = 8'h00; r[15] = 8'h00;
33    // Регистры 16-31
34    r[16] = 8'h00; r[20] = 8'h00; r[24] = 8'h00; r[28] = 8'h00;
35    r[17] = 8'h00; r[21] = 8'h00; r[25] = 8'h00; r[29] = 8'h00;
36    r[18] = 8'h00; r[22] = 8'h00; r[26] = 8'h00; r[30] = 8'h05;
37    r[19] = 8'h00; r[23] = 8'h00; r[27] = 8'h00; r[31] = 8'hFA;
38end
39localparam
40    SPDEC = 1,
41    SPINC = 2;
42// ---------------------------------------------------------------------
43// Проксирование памяти
44// ---------------------------------------------------------------------
45reg [7:0] din;
46always @* begin
47    casex (address)
48        // Регистры
49        16'b0000_0000_000x_xxxx: din = r[ address[4:0] ];
50        // Процессор
51        16'h005B: din = rampz;
52        16'h005D: din = sp[ 7:0];
53        16'h005E: din = sp[15:8];
54        16'h005F: din = sreg;
55        // Память
56        default:  din = data_i;
57    endcase
58end
59// ---------------------------------------------------------------------
60// Регистры процессора, в том числе системные
61// ---------------------------------------------------------------------
62// Регистры
63reg [ 7:0]  r[32];                      // Регистры
64reg [ 1:0]  tstate  = 0;                // Машинное состояние
65reg [15:0]  latch   = 0;                // Записанный опкод
66reg [15:0]  pclatch = 0;                // Для LPM / SPM
67reg [15:0]  sp      = 16'h1FFF;         // Stack Pointer 8k
68reg [ 7:0]  sreg    = 8'b0000_0000;     // Status Register
69reg [ 4:0]  alu     = 0;                // Режим работы АЛУ
70// Команды на обратном фронте
71reg         reg_w   = 0;                // Писать в регистр
72reg         sreg_w  = 0;                // Писать в SREG из АЛУ
73reg [ 4:0]  reg_id  = 0;                // В какой регистр писать
74reg [ 1:0]  sp_mth  = 0;                // Увеличение или уменьшение стека
75// 16 битные регистры
76reg         reg_ww  = 1'b0;             // Писать в X,Y,Z
77reg         reg_ws  = 1'b0;             // =1 Источник АЛУ; =0 Источник регистр `wb2`
78reg         reg_wm  = 1'b0;             // Запись в 1:0
79reg [ 1:0]  reg_idw = 1'b0;             // Номер 16-битного регистра
80reg [15:0]  wb2     = 1'b0;             // Данные для записи в X,Y,Z
81reg [ 7:0]  rampz   = 1'b0;             // Верхняя память для E-функции
82// Провода
83wire [15:0] opcode = tstate ? latch : ir;
84wire [15:0] X   = {r[27], r[26]};
85wire [15:0] Y   = {r[29], r[28]};
86wire [15:0] Z   = {r[31], r[30]};
87wire [15:0] Xm  = X - 1'b1;
88wire [15:0] Xp  = X + 1'b1;
89wire [15:0] Ym  = Y - 1'b1;
90wire [15:0] Yp  = Y + 1'b1;
91wire [15:0] Zm  = Z - 1'b1;
92wire [15:0] Zp  = Z + 1'b1;
93wire [ 5:0] q   = {opcode[13], opcode[11:10], opcode[2:0]};
94wire [ 4:0] rd  =  opcode[8:4];
95wire [ 4:0] rr  = {opcode[9], opcode[3:0]};
96wire [ 4:0] rdi = {1'b1, opcode[7:4]};
97wire [ 4:0] rri = {1'b1, opcode[3:0]};
98wire [ 7:0] K   = {opcode[11:8], opcode[3:0]};
99// Управление счетчиком
100reg         skip_instr  = 1'b0;
101wire [15:0] pcnext      = pc + 1'h1;
102wire [15:0] pcnext2     = pc + 2'h2;
103wire        is_call     = {opcode[14], opcode[3:1]} == 4'b0111;
104// ---------------------------------------------------------------------
105// Арифметико-логическое устройство
106// ---------------------------------------------------------------------
107reg  [ 7:0] op1, op2, alu_res, alu_sreg;
108reg  [15:0] op1w, resw;
109
110// Таймер прерываний
111reg        intr_trigger = 1'b0;
112reg        intr_prev    = 1'b0;
113reg [2:0]  intr_vect    = 1'b0;
114// ---------------------------------------------------------------------
115// Главное исполнительное устройство
116// ---------------------------------------------------------------------
117always @(posedge clock)
118// Сброс процессора
119if (reset_n == 1'b0) begin
120    pc      <= 1'b0;
121    tstate  <= 1'b0;
122end
123// Рабочее состояние
124else begin
125    we     <= 1'b0;
126    read   <= 1'b0; // Чтение из памяти
127    reg_w  <= 1'b0;
128    sreg_w <= 1'b0;
129    sp_mth <= 1'b0; // Ничего не делать с SP
130    reg_ww <= 1'b0; // Ничего не делать с X,Y,Z
131    reg_ws <= 1'b0; // Источник регистр wb2
132    reg_wm <= 1'b0; // Источник регистр resw
133    if (tstate == 0) latch <= ir;
134    // Код пропуска инструкции (JMP, CALL, LDS, STS)
135    if (skip_instr) begin
136        casex (opcode)
137            16'b1001_010x_xxxx_11xx, // CALL | JMP
138            16'b1001_00xx_xxxx_0000: // LDS  | STS
139                pc <= pcnext + 1;
140            default:
141                pc <= pcnext;
142        endcase
143        skip_instr <= 0;
144    end
145    // Вызов прерывания таймера
146    // -----------------------------------------------------------------
147    else if (intr_trigger) begin
148        case (tstate)
149            // Запись PCL
150            0: begin
151                tstate  <= 1;
152                address <= sp;
153                data_o  <= pc[7:0];
154                we      <= 1'b1;
155                sp_mth  <= SPDEC;
156            end
157            // Запись PCH
158            1: begin
159                tstate  <= 0;
160                address <= sp;
161                data_o  <= pc[15:8];
162                we      <= 1'b1;
163                sp_mth  <= SPDEC;
164                pc      <= {intr_vect, 1'b0};  // ISR(INTx_vect)
165                intr_trigger <= 0;             // Переход к обычному исполнению
166                // Сброс флага I->0 (sreg)
167                alu     <= 11;
168                op2     <= {1'b0, sreg[6:0]};
169                sreg_w  <= 1'b1;
170            end
171        endcase
172    end
173    // Вызов прерывания IRQ#x срабатывает на переключении intr
174    // -----------------------------------------------------------------
175    else if (sreg[7] && tstate == 0 && intr ^ intr_prev) begin
176        intr_vect    <= vect + 1;   // Вектор 0..7
177        intr_prev    <= intr;       // Сохранить предыдущее состояние
178        intr_trigger <= 1'b1;       // Вызов прерывания
179    end
180    // Исполнение опкодов
181    // -----------------------------------------------------------------
182    else casex (opcode)
183        // NOP, BREAK
184        16'b0000_0000_0000_0000: pc <= pcnext;
185        16'b1001_0101_1001_1000: pc <= pcnext;
186        // [1T] LDI Rd, K
187        16'b1110_xxxx_xxxx_xxxx: begin
188            pc      <= pcnext;
189            alu     <= 0;       // Инструкция LDI
190            op2     <= K;
191            reg_w   <= 1'b1;
192            reg_id  <= rdi;
193        end
194        // [1T] RJMP k | IJMP | EIJMP
195        16'b1100_xxxx_xxxx_xxxx: pc <= pcnext + {{4{opcode[11]}}, opcode[11:0]};
196        16'b1001_0100_000x_1001: pc <= Z;
197        // [2T] JMP k
198        16'b1001_010x_xxxx_110x:
199        case (tstate)
200            0: begin tstate <= 1; pc <= pcnext; end
201            1: begin tstate <= 0; pc <= ir; end
202        endcase
203        // [1T] <ALU> Rd, Rr
204        16'b000x_01xx_xxxx_xxxx, // 1 CPC, 5 CP
205        16'b000x_1xxx_xxxx_xxxx, // 2 SBC, 3 ADD, 6 SUB, 7 ADC
206        16'b0010_0xxx_xxxx_xxxx, // 8 AND, 9 EOR
207        16'b0010_10xx_xxxx_xxxx: // A OR
208        begin
209            pc      <= pcnext;
210            alu     <= opcode[13:10];
211            op1     <= r[rd];
212            op2     <= r[rr];
213            reg_id  <= rd;
214            // CP, CPС не писать
215            reg_w   <= (opcode[13:10] != 4'b0001 && opcode[13:10] != 4'b0101);
216            sreg_w  <= 1'b1;
217        end
218        // [1T] BRB[C/S] k
219        16'b1111_0xxx_xxxx_xxxx:
220        begin
221            if (sreg[ opcode[2:0] ] ^ opcode[10])
222                pc <= pcnext + {{9{opcode[9]}}, opcode[9:3]};
223            else
224                pc <= pcnext;
225        end
226        // [1T] АЛУ с непосредственным операндом
227        16'b0011_xxxx_xxxx_xxxx, // CPI
228        16'b0100_xxxx_xxxx_xxxx, // SBCI
229        16'b0101_xxxx_xxxx_xxxx, // SUBI
230        16'b0110_xxxx_xxxx_xxxx, // ORI
231        16'b0111_xxxx_xxxx_xxxx: // ANDI
232        begin
233            pc      <= pcnext;
234            op1     <= r[rdi];
235            op2     <= K;
236            reg_id  <= rdi;
237            reg_w   <= (opcode[15:12] != 4'b0011); // CPI не писать
238            sreg_w  <= 1'b1;
239            case (opcode[15:12])
240                4'b0011: alu <= 5;  // CPI
241                4'b0100: alu <= 2;  // SBCI
242                4'b0101: alu <= 6;  // SUBI
243                4'b0110: alu <= 10; // ORI
244                4'b0111: alu <= 8;  // ANDI
245            endcase
246        end
247        // [1T] MOV Rd, Rr
248        16'b0010_11xx_xxxx_xxxx:
249        begin
250            pc      <= pcnext;
251            alu     <= 0;
252            op2     <= r[rr];
253            reg_id  <= rd;
254            reg_w   <= 1'b1;
255        end
256        // [2T] RCALL k | ICALL | EICALL | CALL
257        16'b1101_xxxx_xxxx_xxxx,
258        16'b1001_0101_000x_1001,
259        16'b1001_010x_xxxx_111x:
260        case (tstate)
261            // Запись PCL
262            0: begin
263                tstate  <= 1;
264                address <= sp;
265                data_o  <= is_call ? pcnext2[7:0] : pcnext[7:0];
266                we      <= 1'b1;
267                sp_mth  <= SPDEC;
268                pc      <= pcnext;
269            end
270            // Запись PCH
271            1: begin
272                tstate  <= 0;
273                address <= sp;
274                data_o  <= is_call ? pcnext[15:8] : pc[15:8];
275                we      <= 1'b1;
276                sp_mth  <= SPDEC;
277                // Метод вызова
278                /* CALL */       if (is_call)    pc <= ir;
279                /* RCALL */ else if (opcode[14]) pc <= (pc + {{4{opcode[11]}}, opcode[11:0]});
280                /* ICALL */ else                 pc <= Z;
281            end
282        endcase
283        // [3T] 9508 RET | 9518 RETI
284        16'b1001_0101_000x_1000:
285        case (tstate)
286            // Указатель адреса
287            0: begin
288                tstate   <= 1;
289                read     <= 1;
290                address  <= sp + 1;
291                sp_mth   <= SPINC;
292            end
293            // Чтение PCH
294            1: begin
295                tstate   <= 2;
296                read     <= 1;
297                pc[15:8] <= din;
298                address  <= sp + 1;
299                sp_mth   <= SPINC;
300            end
301            // Чтение PCL
302            2: begin
303                tstate   <= 0;
304                pc[ 7:0] <= din;
305                alu      <= 11;
306                op2      <= {sreg[7] | opcode[4], sreg[6:0]};
307                sreg_w   <= 1;
308            end
309        endcase
310        // [2T] LD Rd, (X|Y|Z)+
311        // [1T] ST Rd, (X|Y|Z)+
312        16'b1001_00xx_xxxx_1100, // X
313        16'b1001_00xx_xxxx_1101, // X+
314        16'b1001_00xx_xxxx_1110, // -X
315        16'b1001_00xx_xxxx_1001, // Y+
316        16'b1001_00xx_xxxx_1010, // -Y
317        16'b1001_00xx_xxxx_0001, // Z+
318        16'b1001_00xx_xxxx_0010: // -Z
319        case (tstate)
320            // Установка указателя на память
321            0: begin
322                tstate <= opcode[9] ? 0 : 1;
323                pc     <= pcnext;
324                data_o <= r[rd];
325                we     <=  opcode[9];
326                read   <= !opcode[9];
327                // Выбор адреса
328                case (opcode[3:0])
329                    4'b11_00: begin address <= X;  end
330                    4'b11_01: begin address <= X;  wb2 <= Xp; reg_idw <= 2'b01; reg_ww <= 1; end
331                    4'b11_10: begin address <= Xm; wb2 <= Xm; reg_idw <= 2'b01; reg_ww <= 1; end
332                    4'b10_01: begin address <= Y;  wb2 <= Yp; reg_idw <= 2'b10; reg_ww <= 1; end
333                    4'b10_10: begin address <= Ym; wb2 <= Ym; reg_idw <= 2'b10; reg_ww <= 1; end
334                    4'b00_01: begin address <= Z;  wb2 <= Zp; reg_idw <= 2'b11; reg_ww <= 1; end
335                    4'b00_10: begin address <= Zm; wb2 <= Zm; reg_idw <= 2'b11; reg_ww <= 1; end
336                endcase
337            end
338            // Запись в регистр Rd (LD)
339            1: begin
340                tstate  <= 0;
341                alu     <= 0;
342                op2     <= din;
343                reg_w   <= 1;
344                reg_id  <= rd;
345            end
346        endcase
347        // [2T] LDD Y+q, Z+q
348        // [1T] STD Y+q, Z+q
349        16'b10x0_xxxx_xxxx_xxxx: // Y,Z
350        case (tstate)
351            // Установка указателя на память
352            0: begin
353                tstate  <= opcode[9] ? 0 : 1;
354                pc      <= pcnext;
355                address <= (opcode[3] ? Y : Z) + q;
356                data_o  <= r[rd];
357                we      <=  opcode[9];
358                read    <= !opcode[9];
359            end
360            // Запись в регистр Rd
361            1: begin
362                tstate  <= 0;
363                alu     <= 0;
364                op2     <= din;
365                reg_w   <= 1;
366                reg_id  <= rd;
367            end
368        endcase
369        // [1T] 0=COM, 1=NEG, 2=SWAP, 3=INC, 5=ASR, 6=LSR, 7=ROR, 10=DEC
370        16'b1001_010x_xxxx_00xx,
371        16'b1001_010x_xxxx_011x,
372        16'b1001_010x_xxxx_0101,
373        16'b1001_010x_xxxx_1010: begin
374            pc      <= pcnext;
375            op1     <= r[rd];   // Rd
376            reg_w   <= 1;
377            sreg_w  <= 1;
378            reg_id  <= rd;
379            case (opcode[3:0])
380                4'b0000: alu <= 5'h0C; // COM
381                4'b0001: alu <= 5'h0D; // NEG
382                4'b0010: alu <= 5'h0E; // SWAP
383                4'b0011: alu <= 5'h0F; // INC
384                4'b0101: alu <= 5'h10; // ASR
385                4'b0110: alu <= 5'h11; // LSR
386                4'b0111: alu <= 5'h12; // ROR
387                4'b1010: alu <= 5'h13; // DEC
388            endcase
389        end
390        // [2T] MOVW Rd, Rr
391        16'b0000_0001_xxxx_xxxx:
392        case (tstate)
393            // LO регистр
394            0: begin
395                tstate  <= 1;
396                pc      <= pcnext;
397                alu     <= 0;
398                op2     <= r[ {opcode[3:0], 1'b0} ];
399                reg_id  <=    {opcode[7:4], 1'b0};
400                reg_w   <= 1;
401            end
402            // HI регистр
403            1: begin
404                tstate  <= 0;
405                alu     <= 0;
406                op2     <= r[ {opcode[3:0], 1'b1} ];
407                reg_id  <=    {opcode[7:4], 1'b1};
408                reg_w   <= 1;
409            end
410        endcase
411        // [1T] <ADIW|SBIW> Rd, K
412        16'b1001_0110_xxxx_xxxx, // ADIW
413        16'b1001_0111_xxxx_xxxx: // SBIW
414        begin
415            pc      <= pcnext;
416            alu     <= opcode[8] ? 5'h15 : 5'h14;
417            case (opcode[5:4])
418                0: op1w <= {r[25], r[24]};
419                1: op1w <= {r[27], r[26]};
420                2: op1w <= {r[29], r[28]};
421                3: op1w <= {r[31], r[30]};
422            endcase
423            op2     <= {opcode[7:6], opcode[3:0]};
424            reg_idw <= opcode[5:4];
425            reg_ww  <= 1;
426            reg_ws  <= 1;
427            sreg_w  <= 1;
428        end
429        // [2T] LPM Rd, Z
430        16'b1001_0101_110x_1000, // LPM R0, Z  | ELPM R0, Z
431        16'b1001_000x_xxxx_01x0, // LPM Rd, Z  | ELPM Rd, Z
432        16'b1001_000x_xxxx_01x1: // LPM Rd, Z+ | ELPM Rd, Z+
433        case (tstate)
434            // Считывание байта
435            0: begin
436                tstate  <= 1;
437                pclatch <= pcnext;
438                // Если ELPM, то записать в старший бит rampz[0]
439                if (opcode[1] || (opcode[10] && opcode[4]))
440                     pc <= {rampz[0], Z[15:1]}; // ELPM
441                else pc <= Z[15:1];             // LPM
442            end
443            // Запись
444            1: begin
445                tstate  <= 0;
446                pc      <= pclatch;
447                alu     <= 0;       // LDI
448                reg_idw <= 2'b11;   // Z
449                reg_ww  <= (!opcode[10] & opcode[0]); // Z+
450                wb2     <= Zp;
451                reg_w   <= 1;
452                reg_id  <= opcode[10] ? 0 : rd;         // R0, Rd
453                op2     <= Z[0] ? ir[15:8] : ir[7:0];   // Hi, Lo
454            end
455        endcase
456        // [2T] IN  Rd, A
457        // [1T] OUT A, Rd
458        16'b1011_xxxx_xxxx_xxxx:
459        case (tstate)
460            // Установка адреса
461            0: begin
462                tstate  <= opcode[11] ? 0 : 1;
463                pc      <= pcnext;
464                data_o  <= r[rd];
465                we      <=  opcode[11];
466                read    <= !opcode[11];
467                address <= {opcode[10:9], opcode[3:0]} + 16'h20;
468            end
469            // Запись регистра
470            1: begin
471                tstate  <= 0;
472                alu     <= 0;
473                op2     <= din;
474                reg_id  <= rd;
475                reg_w   <= 1;
476            end
477        endcase
478        // [1T] SBR[C,S] Rd, b
479        // [1T] SBRS Rd, b
480        16'b1111_11xx_xxxx_0xxx: begin
481            pc <= pcnext;
482            if (r[rd][ opcode[2:0] ] == opcode[9])
483                skip_instr <= 1;
484        end
485        // [2T] SBI[C,S] A, b
486        // [2T] SBIS A, b
487        16'b1001_10x1_xxxx_xxxx: // C=0,S=1
488        casex (tstate)
489            // Запрос чтения
490            0: begin
491                tstate  <= 1;
492                read    <= 1;
493                address <= opcode[7:3] + 16'h20;
494            end
495            // Вычисление бита
496            1: begin
497                tstate  <= 0;
498                pc      <= pcnext;
499                if (din[ opcode[2:0] ] == opcode[9])
500                    skip_instr <= 1;
501            end
502        endcase
503        // [1T] CPSE Rd, Rr
504        16'b0001_00xx_xxxx_xxxx: begin
505            if (r[rd] == r[rr]) skip_instr <= 1;
506            pc <= pcnext;
507        end
508        // [3T] LDS Rd, Mem
509        // [2T] STS Mem, Rd
510        16'b1001_00xx_xxxx_0000: // 0=lds, 1=sts
511        case (tstate)
512            // К следующему коду
513            0: begin
514                tstate  <= 1;
515                pc      <= pcnext;
516            end
517            // Запись в память или выбор регистра
518            1: begin
519                tstate  <= opcode[9] ? 0 : 2; // 1=STS, 0=LDS
520                pc      <= pcnext;
521                reg_id  <= rd;
522                address <= ir;
523                data_o  <= r[rd];
524                we      <=  opcode[9];
525                read    <= !opcode[9];
526            end
527            // Запись в регистр
528            2: begin
529                tstate <= 0;
530                alu    <= 0;
531                reg_w  <= 1;
532                op2    <= din;
533            end
534        endcase
535        // [1T] BCLR, BSET
536        16'b1001_0100_xxxx_1000: begin
537            case (opcode[6:4])
538                0: op2 <= {sreg[7:1], !opcode[7]};
539                1: op2 <= {sreg[7:2], !opcode[7], sreg[0]};
540                2: op2 <= {sreg[7:3], !opcode[7], sreg[1:0]};
541                3: op2 <= {sreg[7:4], !opcode[7], sreg[2:0]};
542                4: op2 <= {sreg[7:5], !opcode[7], sreg[3:0]};
543                5: op2 <= {sreg[7:6], !opcode[7], sreg[4:0]};
544                6: op2 <= {sreg[7],   !opcode[7], sreg[5:0]};
545                7: op2 <= {!opcode[7],            sreg[6:0]};
546            endcase
547            alu     <= 11;
548            sreg_w  <= 1;
549            pc      <= pcnext;
550        end
551        // [1T] PUSH Rd
552        16'b1001_001x_xxxx_1111: begin
553            pc      <= pcnext;
554            data_o  <= r[rd];
555            we      <= 1'b1;
556            address <= sp;
557            sp_mth  <= SPDEC;
558        end
559        // [2T] POP Rd
560        16'b1001_000x_xxxx_1111:
561        case (tstate)
562            // Указатель адреса
563            0: begin
564                tstate  <= 1;
565                pc      <= pcnext;
566                address <= sp + 1;
567                sp_mth  <= SPINC;
568                read    <= 1;
569            end
570            // Запись в регистр
571            1: begin
572                tstate  <= 0;
573                alu     <= 0;
574                op2     <= din;
575                reg_id  <= rd;
576                reg_w   <= 1;
577            end
578        endcase
579        // [1T] BST Rd, b
580        16'b1111_101x_xxxx_0xxx: begin
581            pc      <= pcnext;
582            alu     <= 11;
583            op2     <= {sreg[7], r[rd][ opcode[2:0] ], sreg[5:0]};
584            sreg_w  <= 1;
585        end
586        // [1T] BLD Rd, b
587        16'b1111_100x_xxxx_0xxx: begin
588            pc      <= pcnext;
589            alu     <= 22;  // BLD
590            op1     <= r[rd];
591            op2     <= opcode[2:0];
592            reg_id  <= rd;
593            reg_w   <= 1;
594        end
595        // [2T] CBI / SBI A, b
596        16'b1001_10x0_xxxx_xxxx:
597        case (tstate)
598            // Чтение из порта
599            0: begin
600                tstate  <= 1;
601                read    <= 1;
602                pc      <= pcnext;
603                address <= opcode[7:3] + 16'h20;
604            end
605            // Запись в порт
606            1: begin
607                tstate <= 1'b0;
608                we     <= 1'b1;
609                case (opcode[2:0])
610                    0: data_o <= {din[7:1], opcode[9]};
611                    1: data_o <= {din[7:2], opcode[9], din[0]};
612                    2: data_o <= {din[7:3], opcode[9], din[1:0]};
613                    3: data_o <= {din[7:4], opcode[9], din[2:0]};
614                    4: data_o <= {din[7:5], opcode[9], din[3:0]};
615                    5: data_o <= {din[7:6], opcode[9], din[4:0]};
616                    6: data_o <= {din[  7], opcode[9], din[5:0]};
617                    7: data_o <= {          opcode[9], din[6:0]};
618                endcase
619            end
620        endcase
621        // MUL
622        16'b1001_11xx_xxxx_xxxx: begin
623            pc      <= pcnext;
624            alu     <= 23;
625            op1     <= r[rd];
626            op2     <= r[rr];
627            reg_wm  <= 1;
628        end
629        // MULS d16..31, r16..31
630        16'b0000_0010_xxxx_xxxx: begin
631            pc      <= pcnext;
632            alu     <= 24;
633            op1     <= r[ {1'b1, opcode[7:4]} ];
634            op2     <= r[ {1'b1, opcode[3:0]} ];
635            reg_wm  <= 1;
636        end
637        // MULSU d16..23, r16..23
638        16'b0000_0011_0xxx_0xxx: begin
639            pc      <= pcnext;
640            alu     <= 25;
641            op1     <= r[ {2'b10, opcode[6:4]} ];
642            op2     <= r[ {2'b10, opcode[2:0]} ];
643            reg_wm  <= 1;
644        end
645    endcase
646end
647// Запись в регистры
648always @(negedge clock)
649begin
650    // Запись в регистр
651    if (reg_w) r[ reg_id ] <= alu_res;
652    // Запись в SREG
653    if (sreg_w) sreg <= alu_sreg;
654    // Инкремент или декремент
655    case (sp_mth)
656        SPDEC: sp <= sp - 1'b1;
657        SPINC: sp <= sp + 1'b1;
658    endcase
659    // Автоинкремент или декремент X,Y,Z
660    if (reg_ww) begin
661        case (reg_idw)
662            0: {r[25], r[24]} <= reg_ws ? resw : wb2; // W
663            1: {r[27], r[26]} <= reg_ws ? resw : wb2; // X
664            2: {r[29], r[28]} <= reg_ws ? resw : wb2; // Y
665            3: {r[31], r[30]} <= reg_ws ? resw : wb2; // Z
666        endcase
667    end
668    // Инструкции MUL
669    if (reg_wm) {r[1], r[0]} <= resw;
670    // Запись в порты или регистры
671    if (we) begin
672        case (address)
673            // Системные регистры
674            16'h005B: rampz         <= data_o; // Верхняя память ROM
675            16'h005D: sp[ 7:0]      <= data_o; // SPL
676            16'h005E: sp[15:8]      <= data_o; // SPH
677            16'h005F: sreg          <= data_o; // SREG
678            // Запись в регистры как в память
679            default:  if (address < 16'h20) r[ address[4:0] ] <= data_o;
680        endcase
681    end
682end
683
684// Режим работы АЛУ
685// ---------------------------------------------------------------------
686// 0 LDI    9  EOR      11 LSR      19 MULSU
687// 1 CPC    A  OR       12 ROR
688// 2 SBC    B  <SREG>   13 DEC
689// 3 ADD    C  COM      14 ADIW
690// 5 CP     D  NEG      15 SBIW
691// 6 SUB    E  SWAP     16 BLD
692// 7 ADC    F  INC      17 MUL
693// 8 AND    10 ASR      18 MULS
694// ---------------------------------------------------------------------
695// Вычисления
696wire [7:0] sub      = op1 - op2;
697wire [7:0] add      = op1 + op2;
698wire [8:0] sbc      = op1 - op2 - sreg[0];
699wire [7:0] adc      = op1 + op2 + sreg[0];
700wire [7:0] lsr      = {1'b0,    op1[7:1]};
701wire [7:0] ror      = {sreg[0], op1[7:1]};
702wire [7:0] asr      = {op1[7],  op1[7:1]};
703wire [7:0] neg      = -op1;
704wire [7:0] inc      = op1 + 1;
705wire [7:0] dec      = op1 - 1;
706wire [7:0] com      = ~op1;
707wire [7:0] swap     = {op1[3:0], op1[7:4]};
708// 16 битные вычисления
709wire [15:0] adiw    = op1w + op2;
710wire [15:0] sbiw    = op1w - op2;
711wire [15:0] mul     = op1[7:0] * op2[7:0];
712wire [15:0] mulsu   = {{8{op1[7]}}, op1[7:0]} * op2[7:0];
713wire [15:0] muls    = {{8{op1[7]}}, op1[7:0]} * {{8{op2[7]}}, op2[7:0]};
714// Флаги переполнения после сложения и вычитания
715wire add_flag_v     = (op1[7] &  op2[7] & !alu_res[7]) | (!op1[7] & !op2[7] & alu_res[7]);
716wire sub_flag_v     = (op1[7] & !op2[7] & !alu_res[7]) | (!op1[7] &  op2[7] & alu_res[7]);
717wire neg_flag_v     =  alu_res == 8'h80;
718// Флаги половинного переполнения после сложения и вычитания
719wire add_flag_h     = ( op1[3] & op2[3]) | (op2[3] & !alu_res[3]) | (!alu_res[3] &  op1[3]);
720wire sub_flag_h     = (!op1[3] & op2[3]) | (op2[3] &  alu_res[3]) | ( alu_res[3] & !op1[3]);
721wire neg_flag_h     =   op1[3] | (op1[3] & alu_res[3]) | alu_res[3];
722// Флаги ADIW, SBIW
723wire adiw_c =  op1w[15] & !resw[15];
724wire adiw_v = !op1w[15] &  resw[15];
725// Логические флаги
726wire [7:0] set_logic_flag = {
727    /* i */ sreg[7],
728    /* t */ sreg[6],
729    /* h */ sreg[5],
730    /* s */ alu_res[7],
731    /* v */ 1'b0,
732    /* n */ alu_res[7],
733    /* z */ alu_res[7:0] == 0,
734    /* c */ sreg[0]
735};
736// Флаги после вычитания с переносом
737wire [7:0] set_subcarry_flag = {
738    /* i */ sreg[7],
739    /* t */ sreg[6],
740    /* h */ sub_flag_h,
741    /* s */ sub_flag_v ^ alu_res[7],
742    /* v */ sub_flag_v,
743    /* n */ alu_res[7],
744    /* z */ (alu_res[7:0] == 0) & sreg[1],
745    /* c */ sbc[8]
746};
747// Флаги после вычитания
748wire [7:0] set_subtract_flag = {
749    /* i */ sreg[7],
750    /* t */ sreg[6],
751    /* h */ sub_flag_h,
752    /* s */ sub_flag_v ^ alu_res[7],
753    /* v */ sub_flag_v,
754    /* n */ alu_res[7],
755    /* z */ (alu_res[7:0] == 0),
756    /* c */ op1 < op2
757};
758// Флаги после COM
759wire [7:0] set_com_flag = {
760    /* i */ sreg[7],
761    /* t */ sreg[6],
762    /* h */ sreg[5],
763    /* s */ alu_res[7],
764    /* v */ 1'b0,
765    /* n */ alu_res[7],
766    /* z */ (alu_res[7:0] == 0),
767    /* c */ 1'b1
768};
769// Флаги после NEG
770wire [7:0] set_neg_flag = {
771    /* i */ sreg[7],
772    /* t */ sreg[6],
773    /* h */ neg_flag_h,
774    /* s */ neg_flag_v ^ alu_res[7],
775    /* v */ neg_flag_v,
776    /* n */ alu_res[7],
777    /* z */ (alu_res[7:0] == 0),
778    /* c */ op1 != 0
779};
780// Флаги после сложения
781wire [7:0] set_add_flag = {
782    /* i */ sreg[7],
783    /* t */ sreg[6],
784    /* h */ add_flag_h,
785    /* s */ add_flag_v ^ alu_res[7],
786    /* v */ add_flag_v,
787    /* n */ alu_res[7],
788    /* z */ (alu_res[7:0] == 0),
789    /* c */ op1 + op2 >= 9'h100
790};
791// Флаги после сложения с переносом
792wire [7:0] set_adc_flag = {
793    /* i */ sreg[7],
794    /* t */ sreg[6],
795    /* h */ add_flag_h,
796    /* s */ add_flag_v ^ alu_res[7],
797    /* v */ add_flag_v,
798    /* n */ alu_res[7],
799    /* z */ (alu_res[7:0] == 0),
800    /* c */ op1 + op2 + sreg[0] >= 9'h100
801};
802// Флаги после логической операции сдвига вправо
803wire [7:0] set_lsr_flag = {
804    /* i */ sreg[7],
805    /* t */ sreg[6],
806    /* h */ sreg[5],
807    /* s */ op1[0],
808    /* v */ alu_res[7] ^ op1[0],
809    /* n */ alu_res[7],
810    /* z */ (alu_res[7:0] == 0),
811    /* c */ op1[0]
812};
813// Флаги после INC
814wire [7:0] set_inc_flag = {
815    /* i */ sreg[7],
816    /* t */ sreg[6],
817    /* h */ sreg[5],
818    /* s */ (alu_res == 8'h80) ^ alu_res[7],
819    /* v */ (alu_res == 8'h80),
820    /* n */ alu_res[7],
821    /* z */ (alu_res[7:0] == 0),
822    /* c */ sreg[0]
823};
824// Флаги после DEC
825wire [7:0] set_dec_flag = {
826    /* i */ sreg[7],
827    /* t */ sreg[6],
828    /* h */ sreg[5],
829    /* s */ (alu_res == 8'h7F) ^ alu_res[7],
830    /* v */ (alu_res == 8'h7F),
831    /* n */ alu_res[7],
832    /* z */ (alu_res[7:0] == 0),
833    /* c */ sreg[0]
834};
835// Флаги после ADIW
836wire [7:0] set_adiw_flag = {
837    /* i */ sreg[7],
838    /* t */ sreg[6],
839    /* h */ sreg[5],
840    /* s */ adiw_v ^ resw[15],
841    /* v */ adiw_v,
842    /* n */ resw[15],
843    /* z */ (resw[15:0] == 0),
844    /* c */ adiw_c
845};
846// Флаги после SBIW
847wire [7:0] set_sbiw_flag = {
848    /* i */ sreg[7],
849    /* t */ sreg[6],
850    /* h */ sreg[5],
851    /* s */ adiw_c ^ resw[15],
852    /* v */ adiw_c,
853    /* n */ resw[15],
854    /* z */ (resw[15:0] == 0),
855    /* c */ adiw_v
856};
857// Флаги после MUL, MULS, MULSU
858wire [7:0] set_mul_flag   = {sreg[7:2], /* z */ (mul  [15:0] == 0), /* c */ mul  [15]};
859wire [7:0] set_muls_flag  = {sreg[7:2], /* z */ (muls [15:0] == 0), /* c */ muls [15]};
860wire [7:0] set_mulsu_flag = {sreg[7:2], /* z */ (mulsu[15:0] == 0), /* c */ mulsu[15]};
861
862always @(*)
863begin
864
865    alu_sreg = sreg;
866    case (alu)
867        /* LDI   */ 0:  begin alu_res = op2; end
868        /* CPC   */ 1:  begin alu_res = sbc[7:0];   alu_sreg = set_subcarry_flag; end
869        /* SBC   */ 2:  begin alu_res = sbc[7:0];   alu_sreg = set_subcarry_flag; end
870        /* ADD   */ 3:  begin alu_res = add;        alu_sreg = set_add_flag;      end
871        /* CP    */ 5:  begin alu_res = sub;        alu_sreg = set_subtract_flag; end
872        /* SUB   */ 6:  begin alu_res = sub;        alu_sreg = set_subtract_flag; end
873        /* ADC   */ 7:  begin alu_res = adc;        alu_sreg = set_adc_flag;      end
874        /* AND   */ 8:  begin alu_res = op1 & op2;  alu_sreg = set_logic_flag; end
875        /* EOR   */ 9:  begin alu_res = op1 ^ op2;  alu_sreg = set_logic_flag; end
876        /* OR    */ 10: begin alu_res = op1 | op2;  alu_sreg = set_logic_flag; end
877        /* SREG  */ 11: begin                       alu_sreg = op2; end
878        /* COM   */ 12: begin alu_res = com;        alu_sreg = set_com_flag; end
879        /* NEG   */ 13: begin alu_res = neg;        alu_sreg = set_neg_flag; end
880        /* SWAP  */ 14: begin alu_res = swap;       end
881        /* INC   */ 15: begin alu_res = inc;        alu_sreg = set_inc_flag; end
882        /* ASR   */ 16: begin alu_res = asr;        alu_sreg = set_lsr_flag; end
883        /* LSR   */ 17: begin alu_res = lsr;        alu_sreg = set_lsr_flag; end
884        /* ROR   */ 18: begin alu_res = ror;        alu_sreg = set_lsr_flag; end
885        /* DEC   */ 19: begin alu_res = dec;        alu_sreg = set_dec_flag; end
886        /* ADIW  */ 20: begin resw    = adiw;       alu_sreg = set_adiw_flag; end
887        /* SBIW  */ 21: begin resw    = sbiw;       alu_sreg = set_sbiw_flag; end
888        /* BLD   */ 22: begin
889        case (op2[2:0])
890            0: alu_res = {op1[7:1], sreg[6]};
891            1: alu_res = {op1[7:2], sreg[6], op1[0]};
892            2: alu_res = {op1[7:3], sreg[6], op1[1:0]};
893            3: alu_res = {op1[7:4], sreg[6], op1[2:0]};
894            4: alu_res = {op1[7:5], sreg[6], op1[3:0]};
895            5: alu_res = {op1[7:6], sreg[6], op1[4:0]};
896            6: alu_res = {op1[  7], sreg[6], op1[5:0]};
897            7: alu_res = {          sreg[6], op1[6:0]};
898        endcase
899        end
900        /* MUL   */ 23: begin resw = mul;   alu_sreg = set_mul_flag; end
901        /* MULS  */ 24: begin resw = muls;  alu_sreg = set_muls_flag; end
902        /* MULSU */ 25: begin resw = mulsu; alu_sreg = set_mulsu_flag; end
903        default: alu_res = 8'hFF;
904    endcase
905end
906endmodule