§ Описание

Здесь лишь только часть процессора, то есть, только его ядро: core88.
Основные пины
  • clock — 25 мгц
  • resetn — если 0, то процессор сбрасывается
  • locked — если 1, процессор работает
  • address — адрес
  • bus — входящие данные
  • data — исходящие данные
  • wreq — сигнал записи
Порты
  • port_clk - тактовый импульс для защелкивания
  • port - номер порта
  • port_i - входящие данные из порта
  • port_o - исходящие данные
  • port_w - сигнал записи в порт
Прерывания
  • intr - Запрос прерывания
  • irq - Номер прерывания
  • intr_latch - Защелка что прерывание обработано
Модуль АЛУ описан ранее.

§ Ядро процессора на Verilog

Ревизия процессора: 09/05/22
1// verilator lint_off CASEX
2// verilator lint_off CASEOVERLAP
3
4module core88
5(
6    input   wire        clock,
7    input   wire        reset_n,
8    input   wire        locked,
9
10    // Данные
11    output  wire [19:0] address,
12    input   wire [ 7:0] bus,
13    output  reg  [ 7:0] data,
14    output  reg         wreq,
15
16    // Порты
17    output  reg         port_clk,
18    output  reg  [15:0] port,
19    input   wire [ 7:0] port_i,
20    output  reg  [ 7:0] port_o,
21    output  reg         port_w,
22
23    // Прерывания
24    input   wire        intr,       // Запрос прерывания
25    input   wire [ 7:0] irq,        // Номер прерывания
26    output  reg         intr_latch, // ACCEPT прерывания
27
28    // Отладочные LED
29    output  wire [ 3:0]  iload
30);
31
32assign iload = mode;
33
34// ---------------------------------------------------------------------
35// ОБЪЯВЛЕНИЕ РЕГИСТРОВ
36// ---------------------------------------------------------------------
37
38// Сегментные регистры
39reg [15:0]  seg_cs = 16'hF000;
40reg [15:0]  seg_ss = 16'h0000;
41reg [15:0]  seg_es = 16'h0000;
42reg [15:0]  seg_ds = 16'h0000;
43reg [15:0]  seg_fs = 16'h0000;
44reg [15:0]  seg_gs = 16'h0000;
45
46// Регистры
47reg [31:0]  eax = 32'h4321_e21B;
48reg [31:0]  ebx = 32'hefd0_0001;
49reg [31:0]  ecx = 32'ha1ac_0005;
50reg [31:0]  edx = 32'h0b21_8001;
51reg [31:0]  esp = 32'haaa3_5432;
52reg [31:0]  ebp = 32'ha940_5678;
53reg [31:0]  esi = 32'ha580_0002;
54reg [31:0]  edi = 32'ha670_0004;
55
56// Системные
57reg [15:0]  ip      = 16'h0000;
58reg [15:0]  ipstart = 16'h0000;
59reg [15:0]  seg_ea  = 16'h0000;
60reg [31:0]  ea      = 32'h0000_0000;
61
62//                        ODIT SZ A P C
63reg [11:0]  flags   = 12'b0000_00000010;
64
65// ---------------------------------------------------------------------
66// Состояние процессора
67// ---------------------------------------------------------------------
68
69// Выбранная шина адреса (sel=1) seg:ea (sel=0) cs:ip
70reg [3:0]   mode    = 1'b0;
71reg         sel     = 1'b0;
72reg         sel_seg = 1'b0;
73reg [1:0]   sel_rep = 1'b0;
74reg [3:0]   tstate  = 1'b0;
75reg [4:0]   estate  = 1'b0;
76reg [8:0]   opcode  = 1'b0;
77reg [7:0]   modrm   = 1'b0;
78reg         skip_op = 1'b0;    // Не считывать операнды
79reg         stack32 = 1'b0;    // 16/32
80reg         isize   = 1'b0;    // 8/16
81reg         opsize  = 1'b0;    // 16/32
82reg         opsizet = 1'b0;
83reg         adsize  = 1'b0;    // 16/32
84reg         idir    = 1'b0;    // rm,r | r,rm
85reg [ 2:0]  regn    = 1'b0;    // regv = register[regn]
86reg [ 2:0]  alumode = 1'b0;
87reg [31:0]  op1     = 1'b0;
88reg [31:0]  op2     = 1'b0;
89reg [31:0]  wb      = 1'b0;    // Для записи в reg/rm
90reg [15:0]  tmp16   = 1'b0;
91reg         is_intr = 1'b0;
92reg [63:0]  rdtsc   = 1'b0;
93
94// Модуль деления op1 / op2 -> divres | divrem
95reg [63:0]  diva    = 1'b0;
96reg [63:0]  divb    = 1'b0;
97reg [ 6:0]  divcnt  = 1'b0;
98reg [63:0]  divrem  = 1'b0;
99reg [63:0]  divres  = 1'b0;
100reg         signa   = 1'b0;
101reg         signb   = 1'b0;
102
103// ---------------------------------------------------------------------
104// Константы и initial
105// ---------------------------------------------------------------------
106
107localparam
108    CF = 0, PF = 2, AF = 4,  ZF = 6, SF = 7,
109    TF = 8, IF = 9, DF = 10, OF = 11;
110
111localparam
112
113    PREPARE     = 0,    // Эта подготовки инструкции к исполнению
114    MAIN        = 1,    // Обработка микрокода
115    FETCHEA     = 2,    // Считывание ModRM/EA
116    SETEA       = 3,    // Запись в память или регистр
117    PUSH        = 4,    // Запись в стек
118    POP         = 5,    // Извлечь из стека
119    INTERRUPT   = 6,    // Вызов прерывания
120    LOADSEG     = 7,    // Загрузка сегмента
121    IMMEDIATE   = 8,    // Непосредственное значение
122    SHIFT       = 9,    // Сдвиги
123    DIVIDE      = 10,   // Деление 8/16/32 битного
124    EXTENDED0   = 11,
125    EXTENDED    = 12;   // Расширенный опкод
126
127initial begin
128
129    data        = 8'hFF;
130    wreq        = 0;
131    port_w      = 0;
132    port_o      = 0;
133    port_clk    = 0;
134    port        = 0;
135    intr_latch  = 0;
136
137end
138
139// ---------------------------------------------------------------------
140// Предвычисления
141// ---------------------------------------------------------------------
142
143// Выбор регистра
144wire [31:0] regv =
145    regn == 0 ? (isize ? (opsize ? eax : eax[15:0]) : eax[ 7:0]) :
146    regn == 1 ? (isize ? (opsize ? ecx : ecx[15:0]) : ecx[ 7:0]) :
147    regn == 2 ? (isize ? (opsize ? edx : edx[15:0]) : edx[ 7:0]) :
148    regn == 3 ? (isize ? (opsize ? ebx : ebx[15:0]) : ebx[ 7:0]) :
149    regn == 4 ? (isize ? (opsize ? esp : esp[15:0]) : eax[15:8]) :
150    regn == 5 ? (isize ? (opsize ? ebp : ebp[15:0]) : ecx[15:8]) :
151    regn == 6 ? (isize ? (opsize ? esi : esi[15:0]) : edx[15:8]) :
152                (isize ? (opsize ? edi : edi[15:0]) : ebx[15:8]);
153
154// Вычисление условий
155wire [7:0] branches = {
156
157    (flags[SF] ^ flags[OF]) | flags[ZF], // 7: (ZF=1) OR (SF!=OF)
158    (flags[SF] ^ flags[OF]),             // 6: SF!=OF
159     flags[PF],                          // 5: PF
160     flags[SF],                          // 4: SF
161     flags[CF] | flags[ZF],              // 3: CF or ZF
162     flags[ZF],                          // 2: ZF
163     flags[CF],                          // 1: CF
164     flags[OF]                           // 0: OF
165};
166
167// Модуль умножения
168wire [63:0] mult  = op1 * op2;
169wire        signd = signa ^ signb;
170
171// Выбор источника памяти
172assign address = sel ? {seg_ea, 4'h0} + ea : {seg_cs, 4'h0} + ip;
173
174// =====================================================================
175// Основная работа процессорного микрокода, так сказать
176// =====================================================================
177
178// Считать такты процессора
179always @(posedge clock) rdtsc <= rdtsc + 1;
180
181always @(posedge clock)
182// Сброс
183if (reset_n == 0) begin seg_cs <= 16'hF000; ip <= 0; mode <= PREPARE; end
184// Исполнение
185else if (locked) case (mode)
186
187    // Считывание опкода, сброс, прерывания
188    PREPARE: begin
189
190        opcode  <= bus;
191        idir    <= 0;
192        isize   <= 0;
193        modrm   <= 0;
194        opsize  <= 0;
195        adsize  <= 0;
196        sel_seg <= 0;
197        sel_rep <= 0;
198        stack32 <= 0;
199        skip_op <= 0;
200        seg_ea  <= seg_ds;
201        tstate  <= 0;
202        estate  <= 0;
203        ipstart <= ip;
204
205        // Есть наличие IRQ из контроллера прерываний
206        if (flags[IF] & (intr ^ intr_latch)) begin
207
208            is_intr <= 1;
209            mode    <= INTERRUPT;
210            wb      <= irq;
211            intr_latch <= intr;
212
213            // Разблокировка HLT
214            if (bus == 8'hF4) ip <= ip + 1;
215
216        end
217        else begin
218
219            is_intr <= 0;
220            ip      <= ip + 1;
221            mode    <= MAIN;
222
223        end
224
225    end
226
227    // Исполнение инструкции
228    MAIN: casex (opcode)
229
230        // Сегментные префиксы
231        8'h26: begin opcode <= bus; ip <= ip + 1; sel_seg <= 1; seg_ea <= seg_es; end
232        8'h2E: begin opcode <= bus; ip <= ip + 1; sel_seg <= 1; seg_ea <= seg_cs; end
233        8'h36: begin opcode <= bus; ip <= ip + 1; sel_seg <= 1; seg_ea <= seg_ss; end
234        8'h3E: begin opcode <= bus; ip <= ip + 1; sel_seg <= 1; seg_ea <= seg_ds; end
235        8'h64: begin opcode <= bus; ip <= ip + 1; sel_seg <= 1; seg_ea <= seg_fs; end
236        8'h65: begin opcode <= bus; ip <= ip + 1; sel_seg <= 1; seg_ea <= seg_gs; end
237        // Расширения операнда и адреса
238        8'h66: begin opcode <= bus; ip <= ip + 1; opsize  <= ~opsize; end
239        8'h67: begin opcode <= bus; ip <= ip + 1; adsize  <= ~adsize; end
240        // REP:
241        8'hF2: begin opcode <= bus; ip <= ip + 1; sel_rep <= 2'b10; end // REPNZ
242        8'hF3: begin opcode <= bus; ip <= ip + 1; sel_rep <= 2'b11; end // REPZ
243        // Расширение опкода
244        8'h0F: begin opcode <= {1'b1, bus}; ip <= ip + 1; end
245        // Неиспользуемые коды операции LOCK: FWAIT
246        8'hF0, 8'h9B: begin opcode <= bus; ip <= ip + 1; end
247
248        // ==== Групповые инструкции должны идти первыми ====
249
250        // Групповые инструкции F6/F7
251        8'b1111_011x: case (tstate)
252
253            0: begin tstate <= 1; {idir, isize} <= opcode[0]; mode <= FETCHEA; end
254            1: begin tstate <= 2; case (modrm[5:3])
255
256                // TEST
257                0, 1: begin sel <= 0;    mode <= IMMEDIATE; end
258                // NOT
259                2:    begin wb  <= ~op1; mode <= SETEA; end
260                // NEG
261                3:    begin op1 <= 0; op2 <= op1; alumode <= 5; end
262                // MUL
263                4:    begin op2 <= isize ? (opsize ? eax : eax[15:0]) : eax[7:0]; end
264                // IMUL
265                5:    begin
266
267                    op1 <= isize ? (opsize ? op1 : {{16{op1[15]}},op1[15:0]}) : {{24{op1[7]}},op1[7:0]};
268                    op2 <= isize ? (opsize ? eax : {{16{eax[15]}},eax[15:0]}) : {{24{eax[7]}},eax[7:0]};
269
270                end
271                // DIV, IDIV
272                6, 7: begin
273
274                    divcnt <= isize ? (opsize ? 64 : 32) : 16;
275                    diva   <= isize ? (opsize ? {edx, eax} : {edx[15:0],eax[15:0],32'h0}) : {eax[15:0],48'h0};
276                    divb   <= isize ? (opsize ? op1 : op1[15:0]) : op1[7:0];
277                    divrem <= 0;
278                    divres <= 0;
279                    signa  <= 0;
280                    signb  <= 0;
281
282                    // Переход к IDIV вместо DIV
283                    if (modrm[3]) tstate <= 4; else mode <= DIVIDE;
284
285                end
286
287            endcase end
288            2: begin tstate <= 3; case (modrm[5:3])
289
290                0, 1: begin op2 <= wb; alumode <= 4; end
291                2:    begin sel <= 0; mode <= PREPARE; end
292                3:    begin wb <= result; flags <= flags_o; mode <= SETEA; end
293                4, 5: begin
294
295                    sel  <= 0;
296                    mode <= PREPARE;
297
298                    // CF,OF устанавливаются при переполнении
299                    // ZF при нулевом результате
300                    if (opsize && isize) begin // 32 bit
301
302                        eax <= mult[31:0];
303                        edx <= mult[63:32];
304                        flags[ZF] <= mult[63:0] == 0;
305                        flags[CF] <= edx != 0;
306                        flags[OF] <= edx != 0;
307
308                    end else if (isize) begin // 16 bit
309
310                        eax[15:0] <= mult[15:0];
311                        edx[15:0] <= mult[31:16];
312                        flags[ZF] <= mult[31:0] == 0;
313                        flags[CF] <= edx[15:0]  != 0;
314                        flags[OF] <= edx[15:0]  != 0;
315
316                    end else begin // 8 bit
317
318                        eax[15:0] <= mult[15:0];
319                        flags[ZF] <= mult[15:0] == 0;
320                        flags[CF] <= eax[15:8]  != 0;
321                        flags[OF] <= eax[15:8]  != 0;
322
323                    end
324
325                end
326                6, 7: begin
327
328                    sel  <= 0;
329                    wb   <= 0;
330                    mode <= PREPARE;
331
332                    if (isize && opsize) begin
333
334                        eax <= signd ? -divres[31:0] : divres[31:0];
335                        edx <= divrem[31:0];
336
337                        if (|divres[63:32] || divb[31:0] == 0) mode <= INTERRUPT;
338
339                    end else if (isize) begin
340
341                        eax[15:0] <= signd ? -divres[15:0] : divres[15:0];
342                        edx[15:0] <= divrem[15:0];
343
344                        if (|divres[31:16] || divb[15:0] == 0) mode <= INTERRUPT;
345
346                    end else begin
347
348                        eax[ 7:0] <= signd ? -divres[7:0] : divres[7:0];
349                        eax[15:8] <= divrem[7:0];
350
351                        if (|divres[15:8] || divb[7:0] == 0) mode <= INTERRUPT;
352
353                    end
354
355                end
356
357            endcase end
358            3: case (modrm[5:3])
359
360                0, 1: begin flags <= flags_o; mode <= PREPARE; end
361                3, 6: begin sel <= 0; mode <= PREPARE; end
362
363            endcase
364
365            // Коррекция IDIV
366            4: begin
367
368                signa <= diva[63];
369
370                // Определение знака A
371                if (diva[63]) begin
372
373                    if (isize && opsize) diva        <= -diva;
374                    else if (isize)      diva[63:32] <= -diva[63:32];
375                    else                 diva[63:48] <= -diva[63:48];
376
377                end
378
379                // Определение знака A
380                if (isize && opsize && divb[31]) begin signb <= 1; divb[31:0] <= -divb[31:0]; end
381                else if (isize && divb[15])      begin signb <= 1; divb[15:0] <= -divb[15:0]; end
382                else if (divb[7])                begin signb <= 1; divb[ 7:0] <= -divb[ 7:0]; end
383
384                tstate <= 2;
385                mode   <= DIVIDE;
386
387            end
388
389        endcase
390
391        // Групповые инструкции #2 INC/DEC r8
392        8'b1111_1110: case (tstate)
393
394            0: begin tstate <= 1; mode <= FETCHEA; {idir, isize} <= 2'b00; end
395            1: begin tstate <= 2; op2 <= 1; alumode <= modrm[3] ? 5 : 0; end
396            2: begin tstate <= 3; wb <= result; flags <= {flags_o[11:1], 1'b0}; mode <= SETEA; end
397            3: begin sel <= 0; mode <= PREPARE; end
398
399        endcase
400
401        // Групповые инструкции #3 Word/DWord
402        8'b1111_1111: case (tstate)
403
404            0: begin tstate <= 1; {idir, isize} <= 2'b01; mode <= FETCHEA; end
405            1: begin tstate <= 2; case (modrm[5:3])
406
407                // INC|DEC
408                0, 1: begin op2 <= 1; alumode <= modrm[3] ? 5 : 0; end
409                // CALL rm16
410                2: begin wb <= ip; ip <= op1; mode <= PUSH; end
411                // CALL far: Запись CS
412                3: begin wb <= seg_cs; mode <= PUSH; op2 <= ea; tmp16 <= seg_ea; end
413                // JMP rm16
414                4: begin ip <= op1; sel <= 0; mode <= PREPARE; end
415                // JMP far
416                5: begin ip <= op1; ea <= ea + (opsize ? 4 : 2); sel <= 1; end
417                // PUSH rm16
418                6: begin wb <= op1; mode <= PUSH; end
419
420            endcase end
421            2: begin tstate <= 3; case (modrm[5:3])
422
423                // INC|DEC
424                0, 1: begin mode <= SETEA; wb <= result; flags <= {flags_o[11:1], 1'b0}; {idir, isize} <= 2'b01; end
425                // CALL far: запись IP
426                3: begin wb <= ip; ip <= op1; mode <= PUSH; end
427                // JMP far
428                5: begin wb <= bus; ea <= ea + 1; end
429                2, 6: mode <= PREPARE;
430
431            endcase end
432            3: begin tstate <= 4; case (modrm[5:3])
433
434                // INC|DEC
435                0, 1: begin sel <= 0; mode <= PREPARE; end
436                // CALL far
437                3: begin sel <= 1; seg_ea <= op2; ea <= tmp16 + (opsize ? 4 : 2); end
438                // JMP far
439                5: begin wb[15:8] <= bus; mode <= LOADSEG; regn <= 1; end
440
441            endcase end
442            4: begin tstate <= 5; case (modrm[5:3])
443
444                3: begin wb <= bus; ea <= ea + 1; end
445                5: begin sel <= 0; mode <= PREPARE; end
446
447            endcase end
448            5: begin tstate <= 6; case (modrm[5:3])
449
450                3: begin wb[15:8] <= bus; mode <= LOADSEG; regn <= 1; end
451
452            endcase end
453            5: case (modrm[5:3])
454
455                3: begin sel <= 0; mode <= PREPARE; end
456
457            endcase
458
459        endcase
460
461        // Arithmetic Grp
462        8'b1000_00xx: case (tstate)
463
464            // Прочесть байт modrm, найти ссылку на память
465            0: begin tstate <= 1; mode <= FETCHEA; isize <= opcode[0]; idir <= 0; end
466
467            // Запрос на получение второго операнда
468            1: begin tstate <= 2; mode <= IMMEDIATE;
469
470                alumode <= modrm[5:3];
471                sel     <= 0;
472                if (opcode[1:0] == 2'b11) isize <= 0;
473
474            end
475            // Распознание второго операнда
476            2: begin
477
478                tstate <= 3;
479                op2    <= opcode[1:0] == 2'b11 ? (opsize ? {{24{wb[7]}},wb[7:0]} : {{8{wb[7]}},wb[7:0]}) : wb;
480                isize  <= opcode[0];
481
482            end
483            // Запись результата
484            3: begin
485
486                tstate <= 4;
487                mode  <= alumode == 7 ? PREPARE : SETEA;
488                sel   <= alumode == 7 ? 0 : 1;
489                wb    <= result;
490                flags <= flags_o;
491                if (alumode == 7) sel <= 0;
492
493            end
494            4: begin sel <= 0; mode <= PREPARE; end
495
496        endcase
497
498        // ALU modrm
499        8'b00_xxx_0xx: case (tstate)
500
501            0: begin tstate <= 1; mode  <= FETCHEA; {idir, isize} <= opcode[1:0]; alumode <= opcode[5:3]; end
502            1: begin tstate <= 2; flags <= flags_o; if (alumode < 7) begin mode <= SETEA; wb <= result; end end
503            2: begin mode <= PREPARE; sel <= 0; end
504
505        endcase
506
507        // ALU ac, #
508        8'b00_xxx_10x: case (tstate)
509
510            0: begin
511
512                tstate  <= 1;
513                mode    <= IMMEDIATE;
514                alumode <= opcode[5:3];
515                isize   <= opcode[0];
516                op1     <= opcode[0] ? (opsize ? eax : eax[15:0]) : eax[7:0];
517
518            end
519            1: begin tstate <= 2; op2 <= wb; end
520            2: begin tstate <= 3; flags <= flags_o;
521
522                idir <= 1;
523                mode <= alumode == 7 ? PREPARE : SETEA;
524                wb   <= result;
525                modrm[5:3] <= 0;
526
527            end
528            3: mode <= PREPARE;
529
530        endcase
531
532        // IMUL r16, rm, i16/i8
533        8'b0110_10x1: case (tstate)
534
535            0: begin tstate <= 1; mode <= FETCHEA; {idir, isize} <= 2'b11; end
536            1: begin tstate <= 2; mode <= IMMEDIATE; isize <= ~opcode[1]; op1 <= op2; sel <= 0; end
537            2: begin tstate <= 3;
538
539                isize <= 1'b1;
540                op1 <= opsize ? op2 : {{16{op2[15]}}, op2[15:0]};
541                op2 <= isize ? (opsize ? wb : {{16{wb[15]}}, wb[15:0]}) : {{24{wb[7]}}, wb[7:0]};
542
543            end
544            3: begin tstate <= 4;
545
546                if (opsize) begin
547
548                    wb <= mult[31:0];
549                    flags[CF] <= mult[63:32] ? 1 : 0;
550                    flags[OF] <= mult[63:32] ? 1 : 0;
551
552                end
553                else begin
554
555                    wb <= mult[15:0];
556                    flags[CF] <= mult[31:16] ? 1 : 0;
557                    flags[OF] <= mult[31:16] ? 1 : 0;
558
559                end
560
561                mode <= SETEA;
562
563            end
564            4: begin mode <= PREPARE; sel <= 0; end
565
566        endcase
567
568        // PUSH i16/i8
569        8'b0110_10x0: case (tstate)
570
571            0: begin tstate <= 1; isize <= !opcode[1]; mode <= IMMEDIATE; end
572            1: begin tstate <= 2; isize <= 1; mode <= PUSH; if (isize == 0) wb <= {{24{wb[7]}}, wb[7:0]}; end
573            2: begin mode <= PREPARE; sel <= 0; end
574
575        endcase
576
577        // ==== Строковые инструкции ====
578
579        // MOVSx
580        8'b1010_010x: case (tstate)
581
582            0: begin // Читать
583
584                tstate  <= 1;
585                isize   <= opcode[0];
586                ea      <= esi[15:0];
587                op1     <= 0;
588                op2     <= opcode[0] ? (opsize ? 4 : 2) : 1;
589
590                // Если REP и CX=0, то пропуск инструкции
591                if (sel_rep && ecx[15:0] == 0) begin sel <= 0; mode <= PREPARE; end
592                else begin sel <= 1; estate <= 4; mode <= FETCHEA; end
593
594            end
595            1: begin // Писать
596
597                tstate  <= 2;
598                estate  <= 0;
599                seg_ea  <= seg_es;
600                ea      <= edi[15:0];
601                wb      <= op1;
602                mode    <= SETEA;
603
604            end
605            2: begin // Инкременты
606
607                sel  <= 0;
608                mode <= PREPARE;
609
610                esi[15:0] <= flags[DF] ? esi[15:0] - op2 : esi[15:0] + op2;
611                edi[15:0] <= flags[DF] ? edi[15:0] - op2 : edi[15:0] + op2;
612
613                if (sel_rep) begin ecx[15:0] <= ecx[15:0] - 1; ip <= ipstart; end
614
615            end
616
617        endcase
618
619        // CMPSx
620        8'b1010_011x: case (tstate)
621
622            0: begin // Читать DS:SI
623
624                tstate  <= 1;
625                isize   <= opcode[0];
626                ea      <= esi[15:0];
627                op1     <= 0;
628                tmp16   <= opcode[0] ? (opsize ? 4 : 2) : 1;
629                alumode <= 7; // alu=CMP
630
631                // Если REP и CX=0, то пропуск инструкции
632                if (sel_rep && ecx[15:0] == 0)
633                     begin sel <= 0; mode <= PREPARE; end
634                else begin sel <= 1; mode <= FETCHEA; estate <= 4; end
635
636            end
637            1: begin // Читать ES:DI
638
639                tstate  <= 2;
640                estate  <= 4;
641                idir    <= 1;
642                seg_ea  <= seg_es;
643                ea      <= edi[15:0];
644                mode    <= FETCHEA;
645
646            end
647            2: begin // Инкременты
648
649                sel   <= 0;
650                mode  <= PREPARE;
651                flags <= flags_o;
652
653                esi[15:0] <= flags[DF] ? esi[15:0] - tmp16 : esi[15:0] + tmp16;
654                edi[15:0] <= flags[DF] ? edi[15:0] - tmp16 : edi[15:0] + tmp16;
655
656                // При CMPSx всегда проверяется REPZ/REPNZ
657                // При любом REP должен быть декрементирован CX
658                if (sel_rep) ecx[15:0] <= ecx[15:0] - 1;
659                if (sel_rep && sel_rep[0] == flags_o[ZF]) ip <= ipstart;
660
661            end
662
663        endcase
664
665        // STOSx
666        8'b1010_101x: case (tstate)
667
668            0: begin
669
670                tstate  <= 1;
671                isize   <= opcode[0];
672                seg_ea  <= seg_es;
673                ea      <= edi[15:0];
674                wb      <= eax;
675                op2     <= opcode[0] ? (opsize ? 4 : 2) : 1;
676
677                // Если REP и CX=0, то пропуск инструкции
678                if (sel_rep && ecx[15:0] == 0) mode <= PREPARE;
679                else begin sel <= 1; mode <= SETEA; end
680
681            end
682            1: begin
683
684                sel  <= 0;
685                mode <= PREPARE;
686
687                // Увеличить/Уменьшить DI
688                edi[15:0] <= flags[DF] ? edi[15:0] - op2 : edi[15:0] + op2;
689
690                // Если есть префикс REP: то повторить инструкцию
691                if (sel_rep) begin ecx[15:0] <= ecx[15:0] - 1; ip <= ipstart; end
692
693            end
694
695        endcase
696
697        // LODSx
698        8'b1010_110x: case (tstate)
699
700            0: begin
701
702                tstate  <= 1;
703                estate  <= 4;
704                isize   <= opcode[0];
705                ea      <= esi[15:0];
706                op1     <= 0;
707                op2     <= opcode[0] ? (opsize ? 4 : 2) : 1;
708
709                // Если REP и CX=0, то пропуск инструкции
710                if (sel_rep && ecx[15:0] == 0) mode <= PREPARE;
711                else begin sel <= 1; mode <= FETCHEA; end
712
713            end
714            1: begin
715
716                sel  <= 0;
717                mode <= PREPARE;
718
719                // Загрузка в Acc
720                if (isize && opsize) eax <= op1;
721                else if (isize) eax[15:0] <= op1[15:0];
722                else eax[7:0] <= op1[7:0];
723
724                esi[15:0] <= flags[DF] ? esi[15:0] - op2 : esi[15:0] + op2;
725                if (sel_rep) begin ecx[15:0] <= ecx[15:0] - 1; ip <= ipstart; end
726
727            end
728
729        endcase
730
731        // SCASx
732        8'b1010_111x: case (tstate)
733
734            0: begin // Читать ES:DI
735
736                tstate  <= 1;
737                idir    <= 1;
738                isize   <= opcode[0];
739                seg_ea  <= seg_es;
740                ea      <= edi[15:0];
741                op1     <= eax;
742                tmp16   <= opcode[0] ? (opsize ? 4 : 2) : 1;
743                alumode <= 7; // alu=CMP
744
745                // Если REP и CX=0, то пропуск инструкции
746                if (sel_rep && ecx[15:0] == 0)
747                     begin sel <= 0; mode <= PREPARE; end
748                else begin sel <= 1; mode <= FETCHEA; estate <= 4; end
749
750            end
751            1: begin // Инкременты
752
753                sel   <= 0;
754                mode  <= PREPARE;
755                flags <= flags_o;
756
757                edi[15:0] <= flags[DF] ? edi[15:0] - tmp16 : edi[15:0] + tmp16;
758
759                // Учет префикса REP:
760                if (sel_rep) ecx[15:0] <= ecx[15:0] - 1;
761                if (sel_rep && sel_rep[0] == flags_o[ZF]) ip <= ipstart;
762
763            end
764
765        endcase
766
767        // ==== Все инструкции ====
768
769        // PUSH sr
770        8'b00_0xx_110: case (tstate)
771
772            0: begin tstate <= 1;
773
774                mode <= PUSH;
775                case (opcode[4:3])
776                    2'b00: wb <= seg_es;
777                    2'b01: wb <= seg_cs;
778                    2'b10: wb <= seg_ss;
779                    2'b11: wb <= seg_ds;
780                endcase
781
782            end
783
784            1: mode <= PREPARE;
785
786        endcase
787
788        // POP sr
789        8'b00_0xx_111: case (tstate)
790
791            0: begin tstate <= 1; mode <= POP; end
792            1: begin tstate <= 2; mode <= LOADSEG; regn <= opcode[4:3]; end
793            2: mode <= PREPARE;
794
795        endcase
796
797        // DAA|DAS|AAA|AAS
798        8'b00_1xx_111: case (tstate)
799
800            0: begin tstate <= 1; op1 <= eax[15:0]; alumode <= opcode[4:3]; end
801            1: begin mode <= PREPARE;
802
803                flags <= flags_d;
804                if (opcode[4])
805                     eax[15:0] <= daa_r;
806                else eax[ 7:0] <= daa_r[7:0];
807
808            end
809
810        endcase
811
812        // INC|DEC r
813        8'b01_00x_xxx: case (tstate)
814
815            0: begin tstate <= 1; op2 <= 1;    regn <= opcode[2:0]; isize <= 1'b1; end
816            1: begin tstate <= 2; op1 <= regv; alumode <= opcode[3] ? /*SUB*/ 5 : /*ADD*/ 0; end
817            2: begin tstate <= 3;
818
819                mode    <= SETEA;
820                idir    <= 1'b1;
821                wb      <= result;
822                flags   <= {flags_o[11:1], flags[0]};
823                modrm[5:3] <= regn;
824
825            end
826            3: mode <= PREPARE;
827
828        endcase
829
830        // PUSH r
831        8'b01_010_xxx: case (tstate)
832
833            0: begin tstate <= 1; regn <= opcode[2:0]; isize <= 1'b1; end
834            1: begin tstate <= 2; wb   <= regv; mode <= PUSH; end
835            2: mode <= PREPARE;
836
837        endcase
838
839        // POP r
840        8'b01_011_xxx: case (tstate)
841
842            0: begin tstate <= 1; mode <= POP;   {idir, isize} <= 2'b11; end
843            1: begin tstate <= 2; mode <= SETEA; modrm[5:3] <= opcode[2:0]; end
844            2: begin mode <= PREPARE; end
845
846        endcase
847
848        // Jccc b8
849        8'b0111_xxxx: begin
850
851            // Проверка на выполнение условия в branches
852            if (branches[ opcode[3:1] ] ^ opcode[0])
853                ip <= ip + 1 + {{8{bus[7]}}, bus[7:0]};
854            else
855                ip <= ip + 1;
856
857            mode <= PREPARE;
858
859        end
860
861        // TEST rm, r
862        8'b1000_010x: case (tstate)
863
864            0: begin tstate <= 1; {idir, isize} <= opcode[1:0]; mode <= FETCHEA; alumode <= 4; end
865            1: begin flags <= flags_o; sel <= 0; mode <= PREPARE; end
866
867        endcase
868
869        // XCHG rm, r
870        8'b1000_011x: case (tstate)
871
872            0: begin tstate <= 1; {idir, isize} <= opcode[1:0]; mode <= FETCHEA; alumode <= 4; end
873            1: begin tstate <= 2; wb <= op2; mode <= SETEA; end
874            2: begin tstate <= 3; wb <= op1; mode <= SETEA; idir <= 0; end
875            3: begin sel <= 0; mode <= PREPARE; end
876
877        endcase
878
879        // MOV rmr
880        8'b1000_10xx: case (tstate)
881
882            0: begin tstate <= 1; {idir, isize} <= opcode[1:0]; mode <= FETCHEA; end
883            1: begin tstate <= 2; wb <= op2; mode <= SETEA; end
884            2: begin sel <= 0; mode <= PREPARE; end
885
886        endcase
887
888        // LEA r16, ea
889        8'b1000_1101: case (tstate)
890
891            0: begin tstate <= 1; {idir, isize} <= 2'b11; mode <= FETCHEA; skip_op <= 1; end
892            1: begin tstate <= 2; wb <= ea; mode <= SETEA; end
893            2: begin sel <= 0; mode <= PREPARE; end
894
895        endcase
896
897        // MOV sreg|rm
898        8'b1000_11x0: case (tstate)
899
900            0: begin tstate <= 1; {isize, idir} <= opcode[2:1]; skip_op <= ~opcode[1]; mode <= FETCHEA; end
901            1: begin
902
903                tstate <= 2;
904
905                // MOV sr, r16
906                if (opcode[1]) begin
907
908                    mode <= LOADSEG;
909                    regn <= modrm[5:3];
910                    wb   <= op2;
911
912                end
913                // MOV rm, sr
914                else begin
915
916                    mode <= SETEA;
917                    case (modrm[5:3])
918                        0: wb <= seg_es;
919                        1: wb <= seg_cs;
920                        2: wb <= seg_ss;
921                        3: wb <= seg_ds;
922                        4: wb <= seg_fs;
923                        5: wb <= seg_gs;
924                    endcase
925
926                end
927
928            end
929            2: begin sel <= 0; mode <= PREPARE; end
930
931        endcase
932
933        // POP rm
934        8'b1000_1111: case (tstate)
935
936            0: begin tstate <= 1; mode <= POP; {idir, isize} <= 2'b01; op1 <= seg_ea; end
937            1: begin tstate <= 2; mode <= FETCHEA; skip_op <= 1;       seg_ea <= op1; end
938            2: begin tstate <= 3; mode <= SETEA; end
939            3: begin sel    <= 0; mode <= PREPARE; end
940
941        endcase
942
943        // XCHG ax, r
944        8'b1001_0000: mode <= PREPARE;
945        8'b1001_0xxx: case (tstate)
946
947            0: begin tstate <= 1; regn <= opcode[2:0]; modrm[5:3] <= opcode[2:0]; {isize, idir} <= 2'b11; end
948            1: begin tstate <= 2; mode <= SETEA; wb <= eax; if (opsize) eax <= regv; else eax[15:0] <= regv; end
949            2: begin sel <= 0; mode <= PREPARE; end
950
951        endcase
952
953        // CBW, CWDE
954        8'b1001_1000: begin
955
956            if (opsize) eax[31:16] <= {16{eax[15]}};
957            else        eax[15:8]  <= {8{eax[7]}};
958
959            mode <= PREPARE;
960
961        end
962
963        // CWD, CDQ
964        8'b1001_1001: begin
965
966            if (opsize) edx       <= {32{eax[31]}};
967            else        edx[15:0] <= {16{eax[15]}};
968
969            mode <= PREPARE;
970
971        end
972
973        // CALL far
974        8'b1001_1010: case (tstate)
975
976            0: begin tstate <= 1; isize  <= 1; mode <= IMMEDIATE; end
977            1: begin tstate <= 2; opsize <= 0; mode <= IMMEDIATE; op1 <= wb; end
978            2: begin tstate <= 3; mode <= PUSH; wb <= seg_cs;     op2 <= wb;  end
979            3: begin tstate <= 4; mode <= PUSH; wb <= ip; end
980            4: begin tstate <= 5; mode <= LOADSEG; wb <= op2; regn <= 1; ip <= op1; end
981            5: begin mode <= PREPARE; end
982
983        endcase
984
985        // PUSHF
986        8'b1001_1100: case (tstate)
987
988            0: begin tstate <= 1; mode <= PUSH; wb <= {flags[11:6],1'b0,flags[4],1'b0,flags[2],1'b1,flags[0]};  end
989            1: begin sel <= 0; mode <= PREPARE; end
990
991        endcase
992
993        // POPF
994        8'b1001_1101: case (tstate)
995
996            0: begin tstate <= 1; mode <= POP; end
997            1: begin flags <= wb[11:0]; sel <= 0; mode <= PREPARE; end
998
999        endcase
1000
1001        // SAHF, LAHF
1002        8'b1001_1110: begin flags[7:0] <= eax[15:8]; mode <= PREPARE; end
1003        8'b1001_1111: begin eax[15:8] <= flags[7:0]; mode <= PREPARE; end
1004
1005        // MOV r,#
1006        8'b1011_xxxx: case (tstate)
1007
1008            0: begin
1009
1010                tstate  <= 1;
1011                idir    <= 1;
1012                isize   <= opcode[3];
1013                modrm[5:3] <= opcode[2:0];
1014                mode    <= IMMEDIATE;
1015
1016            end
1017            1: begin tstate <= 2; mode <= SETEA; end
1018            2: mode <= PREPARE;
1019
1020        endcase
1021
1022        // MOV ac, [m16]
1023        8'b1010_00xx: case (tstate)
1024
1025            0: begin // Чтение imm8/16/32
1026
1027                tstate  <= 1;
1028                opsizet <= opsize;
1029                opsize  <= adsize;
1030                isize   <= 1;
1031                mode    <= IMMEDIATE;
1032
1033            end
1034            1: begin // Запрос на чтение из памяти или запись в память
1035
1036                tstate <= 2;
1037                sel    <= 1;
1038                modrm  <= 0;
1039                idir   <= 0;
1040                isize  <= opcode[0];
1041                opsize <= opsizet;
1042                ea     <= wb;
1043
1044                // acc -> mem
1045                if (opcode[1]) begin mode <= SETEA; wb <= eax; end else
1046                // mem -> acc
1047                begin mode <= FETCHEA; sel <= 1; estate <= 4; end
1048
1049            end
1050            2: begin // Запись в регистр ACC или выход
1051
1052                sel  <= 0;
1053                mode <= PREPARE;
1054
1055                // Запись в регистр AL, AX, EAX
1056                if (opcode[1] == 0) begin
1057
1058                    if (isize && opsize) eax <= op1;
1059                    else if (isize)      eax[15:0] <= op1[15:0];
1060                    else eax[7:0] <= op1[7:0];
1061
1062                end
1063
1064            end
1065
1066        endcase
1067
1068        // TEST eax, #
1069        8'b1010_100x: case (tstate)
1070
1071            0: begin tstate <= 1; isize <= opcode[0]; mode <= IMMEDIATE; end
1072            1: begin tstate <= 2; alumode <= 4; op1 <= eax; op2 <= wb; end
1073            2: begin flags <= flags_o; sel <= 0; mode <= PREPARE; end
1074
1075        endcase
1076
1077        // RET [i16]
1078        8'b1100_001x: case (tstate)
1079
1080            // Если opcode[0]=0, imm16
1081            0: begin tstate <= 1; isize <= 1; mode <= POP; end
1082            1: begin tstate <= 2; op1 <= wb; if (opcode[0] == 0) mode <= IMMEDIATE; end
1083            2: begin
1084
1085                ip   <= op1;
1086                sel  <= 0;
1087                mode <= PREPARE;
1088
1089                // Если RET imm, то добавить к стеку
1090                if (opcode[0] == 0) begin
1091                if (stack32) esp <= esp + wb; else esp[15:0] <= esp[15:0] + wb;
1092                end
1093
1094            end
1095
1096        endcase
1097
1098        // LES|LDS r16, [m]
1099        8'b1100_010x: case (tstate)
1100
1101            0: begin tstate <= 1; {idir, isize} <= 2'b11; mode <= FETCHEA; end
1102            1: begin tstate <= 2; mode <= SETEA; wb <= op2; end
1103            2: begin tstate <= 3; ea   <= ea + opsize ? 4 : 2; end
1104            3: begin tstate <= 4; wb[7:0]  <= bus; ea   <= ea + 1; end
1105            4: begin tstate <= 5; wb[15:8] <= bus; regn <= opcode[0] ? 3 : 0; mode <= LOADSEG; sel <= 0; end
1106            5: begin mode <= PREPARE; end
1107
1108        endcase
1109
1110        // MOV rm, #
1111        8'b1100_011x: case (tstate)
1112
1113            0: begin tstate <= 1; {idir, isize} <= {1'b0, opcode[0]}; skip_op <= 1; mode <= FETCHEA; end
1114            1: begin tstate <= 2; sel <= 0; mode <= IMMEDIATE; end
1115            2: begin tstate <= 3; sel <= 1; mode <= SETEA; end
1116            3: begin sel <= 0; mode <= PREPARE; end
1117
1118        endcase
1119
1120        // RETF
1121        8'b1100_101x: case (tstate)
1122
1123            0: begin tstate <= 1; isize <= 1; mode <= POP; end
1124            1: begin tstate <= 2; op1 <= wb;  mode <= POP; end
1125            2: begin tstate <= 3; op2 <= wb;  if (opcode[0] == 0) mode <= IMMEDIATE; end
1126            3: begin tstate <= 4;
1127
1128                ip   <= op1;
1129                wb   <= op2;
1130                regn <= 1;
1131                sel  <= 0;
1132                mode <= LOADSEG;
1133
1134                if (opcode[0] == 0) begin
1135                if (stack32) esp <= esp + wb; else esp[15:0] <= esp[15:0] + wb;
1136                end
1137
1138            end
1139            4: mode <= PREPARE;
1140
1141        endcase
1142
1143        // INT 1/3
1144        8'b1111_0001,
1145        8'b1100_1100: case (tstate)
1146
1147            0: begin tstate <= 1; wb <= opcode[0] ? 1 : 3; mode <= INTERRUPT; end
1148            1: begin mode <= PREPARE; end
1149
1150        endcase
1151
1152        // INT i8
1153        8'b1100_1101: case (tstate)
1154
1155            0: begin tstate <= 1; isize <= 0; mode <= IMMEDIATE; end
1156            1: begin tstate <= 2; mode <= INTERRUPT; end
1157            2: begin mode <= PREPARE; end
1158
1159        endcase
1160
1161        // INTO: Вызов INT4 если OF=1
1162        8'b1100_1110: case (tstate)
1163
1164            0: begin
1165
1166                tstate <= 1;
1167                wb     <= 4;
1168                mode   <= flags[OF] ? INTERRUPT : PREPARE;
1169
1170            end
1171            1: mode <= PREPARE;
1172
1173        endcase
1174
1175        // IRET
1176        8'b1100_1111: case (tstate)
1177
1178            0: begin tstate <= 1; mode <= POP; end
1179            1: begin tstate <= 2; mode <= POP; op1 <= wb; end
1180            2: begin tstate <= 3; mode <= POP; op2 <= wb; end
1181            3: begin tstate <= 4; mode <= LOADSEG; regn <= 1; ip <= op1; wb <= op2; flags <= wb; end
1182            4: mode <= PREPARE;
1183
1184        endcase
1185
1186        // Сдвиговые инструкции (IMM)
1187        8'b1100_000x: case (tstate)
1188
1189            0: begin tstate <= 1; mode <= FETCHEA; {idir, isize} <= opcode[1:0]; end
1190            1: begin tstate <= 2; mode <= IMMEDIATE; sel <= 0; isize <= 0; opsizet <= isize; end
1191            2: begin tstate <= 3; mode <= SHIFT; alumode <= modrm[5:3]; op2 <= wb; isize <= opsizet; end
1192            3: begin tstate <= 4; mode <= SETEA; sel <= 1; wb <= op1; end
1193            4: begin sel    <= 0; mode <= PREPARE;  end
1194
1195        endcase
1196
1197        // Сдвиговые инструкции (CL,N)
1198        8'b1101_00xx: case (tstate)
1199
1200            0: begin tstate <= 1; mode <= FETCHEA; {idir, isize} <= {1'b0, opcode[0]}; end
1201            1: begin tstate <= 2; mode <= SHIFT; alumode <= modrm[5:3]; op2 <= opcode[1] ? ecx[4:0] : 1; end
1202            2: begin tstate <= 3; mode <= SETEA; wb <= op1; end
1203            3: begin sel    <= 0; mode <= PREPARE;  end
1204
1205        endcase
1206
1207        // AAM
1208        8'b1101_0100: case (tstate)
1209
1210            0: begin tstate <= 1;
1211
1212                divcnt  <= 8;
1213                diva    <= {eax[7:0], 56'b0};
1214                divb    <= bus;
1215                wb      <= 0;
1216                mode    <= bus ? DIVIDE : INTERRUPT;
1217                ip      <= ip + 1;
1218
1219            end
1220            1: begin
1221
1222                sel <= 0;
1223                mode <= PREPARE;
1224
1225                if (divb) begin
1226
1227                    eax[15:0] <= {divres[7:0], divrem[7:0]};
1228                    flags[ZF] <= eax[15:0] == 0;
1229                    flags[SF] <= eax[15];
1230                    flags[PF] <= ~^eax[15];
1231
1232                end
1233
1234            end
1235
1236        endcase
1237
1238        // AAD
1239        8'b1101_0101: case (tstate)
1240
1241            0: begin tstate <= 1; eax[15:0] <= eax[15:8]*bus + eax[7:0]; ip <= ip + 1; end
1242            1: begin mode <= PREPARE;
1243
1244                flags[ZF] <= eax[15:0] == 0;
1245                flags[SF] <= eax[15];
1246                flags[PF] <= ~^eax[15];
1247
1248            end
1249
1250        endcase
1251
1252        // SALC
1253        8'b1101_0110: begin eax[7:0] <= {8{flags[CF]}}; mode <= PREPARE; end
1254
1255        // XLATB
1256        8'b1101_0111: case (tstate)
1257
1258            0: begin sel <= 1; tstate <= 1; ea <= ebx[15:0] + eax[7:0]; end
1259            1: begin sel <= 0; eax[7:0] <= bus; mode <= PREPARE; end
1260
1261        endcase
1262
1263        // JCXZ
1264        8'b1110_0011: begin
1265
1266            mode <= PREPARE;
1267            if ((opsize && ecx == 0) || (!adsize && ecx[15:0] == 0))
1268                ip <= ip + 1 + {{24{bus[7]}}, bus[7:0]};
1269            else
1270                ip <= ip + 1;
1271
1272        end
1273
1274        // LOOPNZ, LOOPZ, LOOP
1275        8'b1110_00xx: begin
1276
1277            if (adsize) ecx       <= ecx - 1;
1278            else        ecx[15:0] <= ecx[15:0] - 1;
1279
1280            // ZF=0/1 и CX != 0 (после декремента)
1281            if (((flags[ZF] == opcode[0]) || opcode[1]) && (adsize ? ecx : ecx[15:0]) != 1)
1282                ip <= ip + 1 + {{24{bus[7]}}, bus[7:0]};
1283            else
1284                ip <= ip + 1;
1285
1286            mode <= PREPARE;
1287
1288        end
1289
1290        // IN eAX, dx/i8
1291        8'b1110_x10x: case (tstate)
1292
1293            0: begin tstate <= 1;
1294
1295                if (opcode[3] == 0) ip <= ip + 1;
1296                port <= opcode[3] ? edx[15:0] : bus;
1297                op1  <= opcode[0] ? (opsize ? 3 : 1) : 0;
1298                op2  <= 0;
1299
1300            end
1301            1: begin tstate <= 2; port_clk <= 1; end
1302            2: begin tstate <= 3; port_clk <= 0; end
1303            3: begin tstate <= 1;
1304
1305                case (op2[1:0])
1306
1307                    0: eax[7:0]   <= port_i;
1308                    1: eax[15:8]  <= port_i;
1309                    2: eax[23:16] <= port_i;
1310                    3: eax[31:24] <= port_i;
1311
1312                endcase
1313
1314                port     <= port + 1;
1315                op2[1:0] <= op2[1:0] + 1;
1316
1317                if (op1[1:0] == op2[1:0]) mode <= PREPARE;
1318
1319            end
1320
1321        endcase
1322
1323        // OUT dx/i8, eAX
1324        8'b1110_x11x: case (tstate)
1325
1326            0: begin tstate <= 1;
1327
1328                if (opcode[3] == 0) ip <= ip + 1;
1329                port <= opcode[3] ? edx[15:0] : bus;
1330                op1  <= opcode[0] ? (opsize ? 3 : 1) : 0;
1331                op2  <= 0;
1332
1333            end
1334            1: begin tstate <= 2;
1335
1336                case (op2[1:0])
1337
1338                    0: port_o <= eax[7:0];
1339                    1: port_o <= eax[15:8];
1340                    2: port_o <= eax[23:16];
1341                    3: port_o <= eax[31:24];
1342
1343                endcase
1344
1345                port_w   <= 1;
1346                port_clk <= 1;
1347
1348            end
1349            2: begin tstate <= 3; port_w <= 0; port_clk <= 0; end
1350            3: begin tstate <= 1;
1351
1352                port     <= port + 1;
1353                op2[1:0] <= op2[1:0] + 1;
1354
1355                if (op1[1:0] == op2[1:0]) mode <= PREPARE;
1356
1357            end
1358
1359        endcase
1360
1361        // CALL b16
1362        8'b1110_1000: case (tstate)
1363
1364            0: begin tstate <= 1; isize <= 1; mode <= IMMEDIATE; end
1365            1: begin tstate <= 2; wb <= ip; ip <= ip + wb; mode <= PUSH; end
1366            2: begin mode <= PREPARE; end
1367
1368        endcase
1369
1370        // JMP b16
1371        8'b1110_1001: case (tstate)
1372
1373            0: begin tstate <= 1; isize <= 1; mode <= IMMEDIATE; end
1374            1: begin mode <= PREPARE; ip <= ip + wb; end
1375
1376        endcase
1377
1378        // JMP b16:c16
1379        8'b1110_1010: case (tstate)
1380
1381            0: begin tstate <= 1; isize <= 1; mode <= IMMEDIATE; end
1382            1: begin tstate <= 2; op1 <= wb; opsize <= 0; mode <= IMMEDIATE; end
1383            2: begin tstate <= 3; mode <= LOADSEG; regn <= 1; ip <= op1; end
1384            3: begin mode <= PREPARE; end
1385
1386        endcase
1387
1388        // JMP b8
1389        8'b1110_1011: begin ip <= ip + 1 + {{8{bus[7]}}, bus[7:0]}; mode <= PREPARE; end
1390
1391        // HLT
1392        8'b1111_0100: begin ip <= ip - 1; mode <= PREPARE; end
1393
1394        // CMC, CLC, STC, CLI, STI, CLD, STD
1395        8'b1111_0101: begin flags[CF] <= ~flags[CF]; mode <= PREPARE; end
1396        8'b1111_100x: begin flags[CF] <= opcode[0];  mode <= PREPARE; end
1397        8'b1111_101x: begin flags[IF] <= opcode[0];  mode <= PREPARE; end
1398        8'b1111_110x: begin flags[DF] <= opcode[0];  mode <= PREPARE; end
1399
1400        // Коды расширенных инструкции
1401        // =============================================================
1402
1403        // Jccc NEAR b16
1404        9'b1_1000_xxxx: case (tstate)
1405
1406            0: begin tstate <= 1; wb <= bus; ip <= ip + 1; end
1407            1: begin
1408
1409                if (branches[opcode[3:1]] ^ opcode[0])
1410                    ip <= ip + (adsize ? 3 : 1) + {bus, wb[7:0]};
1411                else
1412                    ip <= ip + (adsize ? 3 : 1);
1413
1414                mode <= PREPARE;
1415
1416            end
1417
1418        endcase
1419
1420        // RDTSC
1421        9'b1_0011_0001: begin eax <= rdtsc[31:0]; edx <= rdtsc[63:32]; mode <= PREPARE; end
1422
1423    endcase
1424
1425    // Считывание эффективного адреса и регистров
1426    FETCHEA: case (estate)
1427
1428        0: begin
1429
1430            modrm <= bus;
1431            ip    <= ip + 1;
1432
1433            // Операнд 1
1434            case (idir ? bus[5:3] : bus[2:0])
1435
1436                0: op1 <= isize ? (opsize ? eax : eax[15:0]) : eax[ 7:0];
1437                1: op1 <= isize ? (opsize ? ecx : ecx[15:0]) : ecx[ 7:0];
1438                2: op1 <= isize ? (opsize ? edx : edx[15:0]) : edx[ 7:0];
1439                3: op1 <= isize ? (opsize ? ebx : ebx[15:0]) : ebx[ 7:0];
1440                4: op1 <= isize ? (opsize ? esp : esp[15:0]) : eax[15:8];
1441                5: op1 <= isize ? (opsize ? ebp : ebp[15:0]) : ecx[15:8];
1442                6: op1 <= isize ? (opsize ? esi : esi[15:0]) : edx[15:8];
1443                7: op1 <= isize ? (opsize ? edi : edi[15:0]) : ebx[15:8];
1444
1445            endcase
1446
1447            // Операнд 2
1448            case (idir ? bus[2:0] : bus[5:3])
1449
1450                0: op2 <= isize ? (opsize ? eax : eax[15:0]) : eax[ 7:0];
1451                1: op2 <= isize ? (opsize ? ecx : ecx[15:0]) : ecx[ 7:0];
1452                2: op2 <= isize ? (opsize ? edx : edx[15:0]) : edx[ 7:0];
1453                3: op2 <= isize ? (opsize ? ebx : ebx[15:0]) : ebx[ 7:0];
1454                4: op2 <= isize ? (opsize ? esp : esp[15:0]) : eax[15:8];
1455                5: op2 <= isize ? (opsize ? ebp : ebp[15:0]) : ecx[15:8];
1456                6: op2 <= isize ? (opsize ? esi : esi[15:0]) : edx[15:8];
1457                7: op2 <= isize ? (opsize ? edi : edi[15:0]) : ebx[15:8];
1458
1459            endcase
1460
1461            // Вычисление эффективного адреса 32 bit
1462            if (adsize)
1463            case (bus[2:0])
1464                0: ea <= eax;
1465                1: ea <= ecx;
1466                2: ea <= edx;
1467                3: ea <= ebx;
1468                // 4: SIB
1469                5: ea <= ebp;
1470                6: ea <= esi;
1471                7: ea <= edi;
1472            endcase
1473            else
1474            // Вычисление эффективного адреса 16 bit
1475            case (bus[2:0])
1476
1477                0: ea[15:0] <= ebx[15:0] + esi[15:0];
1478                1: ea[15:0] <= ebx[15:0] + edi[15:0];
1479                2: ea[15:0] <= ebp[15:0] + esi[15:0];
1480                3: ea[15:0] <= ebp[15:0] + edi[15:0];
1481                4: ea[15:0] <= esi[15:0];
1482                5: ea[15:0] <= edi[15:0];
1483                6: ea[15:0] <= ebp[15:0];
1484                7: ea[15:0] <= ebx[15:0];
1485
1486            endcase
1487
1488            // Выбор SS: по умолчанию
1489            if (!sel_seg) begin
1490
1491                // 32 bit
1492                if (adsize) begin if (bus[2:0] == 5 && ^bus[7:6]) seg_ea <= seg_ss; end
1493                // 16 bit
1494                else if ((bus[2:0] == 3'h6 && ^bus[7:6]) || (bus[2:1] == 2'b01))
1495                    seg_ea <= seg_ss;
1496            end
1497
1498            // 32 bit
1499            if (adsize)
1500            casex (bus)
1501
1502                8'b11_xxx_xxx: begin estate <= 0; mode <= MAIN; end // reg
1503                8'b00_xxx_101: begin estate <= 8; ea <= 0; end      // disp32
1504                8'bxx_xxx_100: begin estate <= 12; end              // sib
1505                8'b00_xxx_xxx: begin estate <= 4; sel <= 1; end     // без disp
1506                8'b01_xxx_xxx: begin estate <= 3; end               // disp8
1507                8'b10_xxx_xxx: begin estate <= 8; end               // disp32
1508
1509            endcase
1510            // 16 bit
1511            else casex (bus)
1512
1513                8'b00_xxx_110: begin estate <= 1; ea  <= 0; end // disp16
1514                8'b00_xxx_xxx: begin estate <= 4; sel <= 1; end // без disp
1515                8'b01_xxx_xxx: begin estate <= 3; end           // disp8
1516                8'b10_xxx_xxx: begin estate <= 1; end           // disp16
1517                8'b11_xxx_xxx: begin estate <= 0; mode <= MAIN; end
1518
1519            endcase
1520
1521        end
1522
1523        // Считывание 16-бит displacement
1524        1: begin estate <= 2; ip <= ip + 1; ea <= ea + bus; end
1525        2: begin estate <= 4; ip <= ip + 1; ea[15:8] <= ea[15:8] + bus; ea[31:16] <= 0; sel <= 1; end
1526
1527        // Считывание 8-бит displacement
1528        3: begin estate <= 4;
1529
1530            ip  <= ip + 1;
1531            sel <= 1;
1532
1533            if (adsize)
1534                 ea <= ea + {{24{bus[7]}}, bus[7:0]};
1535            else ea[15:0] <= ea[15:0] + {{8{bus[7]}}, bus[7:0]};
1536
1537        end
1538
1539        // Чтение операнда 8bit из памяти
1540        4: begin
1541
1542            if (skip_op) begin estate <= 0; mode <= MAIN; end
1543            else begin
1544
1545                if (idir) op2 <= bus; else op1 <= bus;
1546                if (isize) begin estate <= 5; ea <= ea + 1; end
1547                else       begin estate <= 0; mode <= MAIN; end
1548            end
1549
1550        end
1551
1552        // Чтение операнда 16 бит (память)
1553        5: begin
1554
1555            if (idir) op2[15:8] <= bus; else op1[15:8] <= bus;
1556            if (opsize) begin estate <= 6; ea <= ea + 1; end
1557            else        begin estate <= 0; ea <= ea - 1; mode <= MAIN; end
1558
1559        end
1560
1561        // Чтение операнда 32 бит (память)
1562        6: begin estate <= 7; if (idir) op2[23:16] <= bus; else op1[23:16] <= bus; ea <= ea + 1; end
1563        7: begin estate <= 0; if (idir) op2[31:24] <= bus; else op1[31:24] <= bus; ea <= ea - 3; mode <= MAIN; end
1564
1565        // Чтение +disp32 и переход к чтение операнда из памяти
1566        8:  begin tstate <= 9;  ip <= ip + 1; ea        <= ea        + bus; end
1567        9:  begin tstate <= 10; ip <= ip + 1; ea[31:8]  <= ea[31:8]  + bus; end
1568        10: begin tstate <= 11; ip <= ip + 1; ea[31:16] <= ea[31:16] + bus; end
1569        11: begin tstate <= 4;  ip <= ip + 1; ea[31:24] <= ea[31:24] + bus; sel <= 1; end
1570
1571        // Разбор байта SIB: Считывание SS*INDEX
1572        12: begin
1573
1574            estate <= 13;
1575
1576            casex (bus)
1577
1578                8'bxx_000_xxx: ea <= eax << bus[7:6];
1579                8'bxx_001_xxx: ea <= ecx << bus[7:6];
1580                8'bxx_010_xxx: ea <= edx << bus[7:6];
1581                8'bxx_011_xxx: ea <= ebx << bus[7:6];
1582                8'bxx_100_xxx: ea <= 0;
1583                8'bxx_101_xxx: ea <= ebp << bus[7:6];
1584                8'bxx_110_xxx: ea <= esi << bus[7:6];
1585                8'bxx_111_xxx: ea <= edi << bus[7:6];
1586
1587            endcase
1588
1589            // Выбор сегмента SS: по умолчанию
1590            if (!sel_seg && bus[5:3] == 5) seg_ea <= seg_ss;
1591
1592        end
1593
1594        // Считывание BASE
1595        13: begin
1596
1597            estate <= 4;
1598            sel    <= 1;
1599            ip     <= ip + 1;
1600
1601            case (bus[2:0])
1602
1603                // disp32
1604                3'b000: ea <= ea + eax;
1605                3'b001: ea <= ea + ecx;
1606                3'b010: ea <= ea + edx;
1607                3'b011: ea <= ea + ebx;
1608                3'b100: ea <= ea + esp;
1609                3'b101:
1610                if (^modrm[7:6]) begin
1611                    ea <= ea + ebp;
1612                    if (!sel_seg) seg_ea <= seg_ss;
1613                end
1614                3'b110: ea <= ea + esi;
1615                3'b111: ea <= ea + edi;
1616
1617            endcase
1618
1619            // +disp8/32
1620            if (modrm[7:6] == 2'b00 && bus[2:0] == 5) begin sel <= 0; estate <= 8; end
1621            else if (modrm[7:6] == 2'b01) begin sel <= 0; estate <= 3; end
1622            else if (modrm[7:6] == 2'b10) begin sel <= 0; estate <= 8; end
1623
1624        end
1625
1626    endcase
1627
1628    // Запись обратно в память или регистр [idir, isize, modrm, wb]
1629    // * idir  (1 запись `wb` в регистр modrm[5:3])
1630    //         (0 запись в память ea)
1631    // * isize (0/1)
1632    // * wb    (8/16)
1633    SETEA: case (estate)
1634
1635        0: begin
1636
1637            // Запись результата в регистр
1638            if (idir || (modrm[7:6] == 2'b11)) begin
1639
1640                case (idir ? modrm[5:3] : modrm[2:0])
1641
1642                    0: if (isize && opsize) eax <= wb; else if (isize) eax[15:0] <= wb; else eax[ 7:0] <= wb[7:0];
1643                    1: if (isize && opsize) ecx <= wb; else if (isize) ecx[15:0] <= wb; else ecx[ 7:0] <= wb[7:0];
1644                    2: if (isize && opsize) edx <= wb; else if (isize) edx[15:0] <= wb; else edx[ 7:0] <= wb[7:0];
1645                    3: if (isize && opsize) ebx <= wb; else if (isize) ebx[15:0] <= wb; else ebx[ 7:0] <= wb[7:0];
1646                    4: if (isize && opsize) esp <= wb; else if (isize) esp[15:0] <= wb; else eax[15:8] <= wb[7:0];
1647                    5: if (isize && opsize) ebp <= wb; else if (isize) ebp[15:0] <= wb; else ecx[15:8] <= wb[7:0];
1648                    6: if (isize && opsize) esi <= wb; else if (isize) esi[15:0] <= wb; else edx[15:8] <= wb[7:0];
1649                    7: if (isize && opsize) edi <= wb; else if (isize) edi[15:0] <= wb; else ebx[15:8] <= wb[7:0];
1650
1651                endcase
1652
1653                mode <= MAIN;
1654
1655            end
1656            // Запись [7:0] в память
1657            else begin
1658
1659                estate <= 1;
1660                wreq   <= 1;
1661                data   <= wb[7:0];
1662
1663            end
1664
1665        end
1666
1667        // Запись [15:8] или завершение
1668        1: begin
1669
1670            if (isize)
1671                 begin estate <= 2; data <= wb[15:8]; ea <= ea + 1; end
1672            else begin estate <= 0; wreq <= 0; mode <= MAIN; end
1673
1674        end
1675
1676        // Завершение записи 16 bit
1677        2: begin
1678
1679            if (opsize) begin estate <= 3; data <= wb[23:16]; ea <= ea + 1; end
1680            else        begin estate <= 0; wreq <= 0; mode <= MAIN; ea <= ea - 1; end
1681
1682        end
1683
1684        // Завершение записи 32 bit
1685        3: begin estate <= 4; data <= wb[31:24]; ea <= ea + 1; end
1686        4: begin estate <= 0; wreq <= 0; mode <= MAIN; ea <= ea - 3; end
1687
1688    endcase
1689
1690    // Получение imm8/16/32 [isize]
1691    IMMEDIATE: case (estate)
1692
1693        0: begin ip <= ip + 1; wb        <= bus; if (isize == 0) mode <= MAIN; else begin estate <= 1; end end
1694        1: begin ip <= ip + 1; wb[ 15:8] <= bus; if (opsize) estate <= 2; else begin estate <= 0; mode <= MAIN; end end
1695        2: begin ip <= ip + 1; wb[23:16] <= bus; estate <= 3; end
1696        3: begin ip <= ip + 1; wb[31:24] <= bus; estate <= 0; mode <= MAIN; end
1697
1698    endcase
1699
1700    // Сохранение данных в стек [wb]
1701    // Если стек 32-х разрядный, используются 4 байта
1702    PUSH: case (estate)
1703
1704        0: begin
1705
1706            estate  <= 1;
1707            sel     <= 1;
1708            wreq    <= 1;
1709            seg_ea  <= seg_ss;
1710            data    <= wb[7:0];
1711
1712            if (stack32) begin
1713                ea  <= esp - 4;
1714                esp <= esp - 4;
1715            end
1716            else begin
1717                ea        <= esp[15:0] - (opsize ? 4 : 2);
1718                esp[15:0] <= esp[15:0] - (opsize ? 4 : 2);
1719            end
1720
1721        end
1722        1: begin estate <= 2; ea <= ea + 1; data <= wb[15:8]; end
1723        2: begin
1724
1725            if (opsize) begin ea <= ea + 1; data <= wb[23:16]; estate <= 3; end
1726            else begin
1727
1728                estate <= 0;
1729                sel    <= 0;
1730                wreq   <= 0;
1731                mode   <= MAIN;
1732
1733            end
1734
1735        end
1736        3: begin estate <= 4; ea <= ea + 1; data <= wb[31:24];  end
1737        4: begin estate <= 0; sel <= 0; wreq <= 0; mode <= MAIN; end
1738
1739    endcase
1740
1741    // Извлечение данных из стека -> wb
1742    POP: case (estate)
1743
1744        0: begin
1745
1746            estate  <= 1;
1747            sel     <= 1;
1748            seg_ea  <= seg_ss;
1749
1750            if (stack32) begin
1751                ea  <= esp;
1752                esp <= esp - 4;
1753            end
1754            else begin
1755                ea        <= esp[15:0];
1756                esp[15:0] <= esp[15:0] + (opsize ? 4 : 2);
1757            end
1758
1759        end
1760        1: begin estate <= 2; wb <= bus; ea <= ea + 1; end
1761        2: begin
1762
1763            wb[15:8] <= bus;
1764
1765            if (opsize) begin estate <= 3; ea <= ea + 1; end
1766            else        begin estate <= 0; sel <= 0; mode <= MAIN; end
1767
1768        end
1769        3: begin estate <= 4; wb[23:16] <= bus; ea <= ea + 1; end
1770        4: begin estate <= 0; wb[31:24] <= bus; sel <= 0; mode <= MAIN; end
1771
1772    endcase
1773
1774    // Загрузка и проверка нового сегментного регистра [regn, wb]
1775    LOADSEG: case (estate)
1776
1777        0: begin
1778
1779            // Если это было прерывание
1780            if (is_intr) begin mode <= PREPARE; end
1781            else mode <= MAIN;
1782
1783            case (regn)
1784
1785                3'b000: seg_es <= wb;
1786                3'b001: seg_cs <= wb;
1787                3'b010: seg_ss <= wb;
1788                3'b011: seg_ds <= wb;
1789                3'b100: seg_fs <= wb;
1790                3'b101: seg_gs <= wb;
1791
1792            endcase
1793
1794        end
1795
1796    endcase
1797
1798    // Вызов прерывания [wb]
1799    INTERRUPT: case (estate)
1800
1801        // Запись в стек CS:IP:FLAGS
1802        0: begin
1803
1804            estate  <= 1;
1805            sel     <= 1;
1806            wreq    <= 1;
1807            seg_ea  <= seg_ss;
1808            data    <= ip[7:0];
1809
1810            if (stack32) begin
1811                ea  <= esp - 4*3;
1812                esp <= esp - 4*3;
1813            end
1814            else begin
1815                ea        <= esp[15:0] - 2*3;
1816                esp[15:0] <= esp[15:0] - 2*3;
1817            end
1818
1819        end
1820        1: begin data <= ip[15:8]; estate <= stack32 ? 2 : 4; ea <= ea + 1; end
1821        // 2, 3
1822        4: begin data <= seg_cs[ 7:0]; estate <= 5; ea <= ea + 1; end
1823        5: begin data <= seg_cs[15:8]; estate <= stack32 ? 6 : 8; ea <= ea + 1; end
1824        // 6, 7
1825        8: begin data <= flags[7:0]; estate <= 9; ea <= ea + 1; end
1826        9: begin data <= flags[11:8]; estate <= stack32 ? 10 : 12; ea <= ea + 1; end
1827        // 10, 11
1828        12: begin estate <= 13;
1829
1830            wreq      <= 0;
1831            flags[IF] <= 1'b0;
1832            flags[TF] <= 1'b0;
1833            seg_ea    <= 0;
1834            ea        <= {wb, 2'b00};
1835
1836        end
1837        // Загрузка нового CS:IP из IVT
1838        13: begin estate <= 14; ip[7:0]  <= bus; ea <= ea + 1; end
1839        14: begin estate <= 15; ip[15:8] <= bus; ea <= ea + 1; end
1840        15: begin estate <= 16; wb[7:0]  <= bus; ea <= ea + 1; end
1841        16: begin estate <= 0;  wb[15:8] <= bus; sel <= 0; regn <= 1; mode <= LOADSEG; end
1842
1843        // 32-х битный
1844        default: begin estate <= estate + 1; data <= 0; ea <= ea + 1; end
1845
1846    endcase
1847
1848    // Сдвиги:
1849    // * alumode=операция
1850    // * isize, opsize
1851    // * op1
1852    // * op2
1853    SHIFT: case (estate)
1854
1855        // Вычисление ограничения количества сдвигов
1856        // Если сдвиг не задан (0), то не срабатывает
1857        0: begin
1858
1859            estate <= 1;
1860
1861            if (isize && opsize)
1862                begin wb <= 31; op2 <= op2[4:0]; if (op2[4:0] == 0) begin estate <= 0; mode <= MAIN; end end
1863            else if (isize)
1864                // DosBox так обрабатывает (4:0)
1865                begin wb <= 15; op2 <= op2[4:0]; if (op2[4:0] == 0) begin estate <= 0; mode <= MAIN; end end
1866            else
1867                begin wb <= 7;  op2 <= op2[2:0]; if (op2[2:0] == 0) begin estate <= 0; mode <= MAIN; end end
1868
1869        end
1870
1871        // Вычисление
1872        1: begin
1873
1874            // Сдвиги
1875            if (op2) begin
1876
1877                op2 <= op2 - 1;
1878                case (alumode)
1879
1880                    /* ROL */ 0:
1881                    begin op1 <= isize ? (opsize ? {op1[30:0],op1[31]} : {op1[14:0],op1[15]}) : {op1[6:0],op1[7]}; end
1882
1883                    /* ROR */ 1:
1884                    begin op1 <= isize ? (opsize ? {op1[0],op1[31:1]} : {op1[0],op1[15:1]}) : {op1[0],op1[7:1]}; end
1885
1886                    /* RCL */ 2:
1887                    begin
1888
1889                        op1 <= isize ? (opsize ? {op1[30:0],flags[CF]} : {op1[14:0],flags[CF]}) : {op1[6:0],flags[CF]};
1890                        flags[CF] <= op1[wb];
1891
1892                    end
1893
1894                    /* RCR */ 3:
1895                    begin
1896
1897                        op1 <= isize ? (opsize ? {flags[CF],op1[31:1]} : {flags[CF],op1[15:1]}) : {flags[CF],op1[7:1]};
1898                        flags[CF] <= op1[0];
1899
1900                    end
1901
1902                    /* SHL */ 4, 6:
1903                    begin
1904
1905                        flags[CF] <= op1[wb-op2+1];
1906                        op1 <= op1 << op2;
1907                        op2 <= 0;
1908
1909                    end
1910
1911                    /* SHR */ 5:
1912                    begin
1913
1914                        flags[CF] <= op1[op2-1];
1915                        op1 <= op1 >> op2;
1916                        op2 <= 0;
1917
1918                    end
1919
1920                    /* SAR */ 7:
1921                    begin
1922                        op1 <= isize ? (opsize ? {op1[31],op1[31:1]} : {op1[15],op1[15:1]}) : {op1[7],op1[7:1]};
1923                        flags[CF] <= op1[0];
1924                    end
1925
1926                endcase
1927
1928            end
1929            // Расчет флагов
1930            else begin
1931
1932                estate <= 0;
1933                mode   <= MAIN;
1934
1935                case (alumode)
1936
1937                    0: begin flags[CF] <= op1[0];  flags[OF] <= op1[0]  ^ op1[wb];   end
1938                    1: begin flags[CF] <= op1[wb]; flags[OF] <= op1[wb] ^ op1[wb-1]; end
1939                    2: begin flags[OF] <= flags[CF] ^ op1[wb]; end
1940                    3: begin flags[OF] <= op1[wb] ^ op1[wb-1]; end
1941                    default: begin
1942
1943                        flags[ZF] <= !op1;
1944                        flags[SF] <= op1[wb];
1945                        flags[PF] <= ~^op1[7:0];
1946                        flags[AF] <= 1;
1947
1948                    end
1949
1950                endcase
1951
1952            end
1953        end
1954
1955    endcase
1956
1957    // Процедура деления [diva, divb, divcnt]
1958    DIVIDE: begin
1959
1960        if (divcnt) begin
1961
1962            divrem <= {divrem,diva[63]} >= divb ? {divrem,diva[63]} - divb : {divrem,diva[63]};
1963            divres <= {divres[62:0], {divrem,diva[63]} >= divb};
1964            diva   <= {diva[62:0], 1'b0};
1965            divcnt <= divcnt - 1;
1966
1967        end
1968        else mode <= MAIN;
1969
1970    end
1971
1972endcase
1973
1974// ---------------------------------------------------------------------
1975// АРИФМЕТИКО-ЛОГИКА
1976// ---------------------------------------------------------------------
1977
1978wire [31:0] result = isize ? (opsize ? res[31:0] : res[15:0]) : res[7:0];
1979reg  [15:0] daa_r;
1980reg  [11:0] flags_o;
1981reg  [11:0] flags_d;
1982reg  [32:0] res;
1983
1984// Десятичная коррекция
1985reg         daa_a;
1986reg         daa_c;
1987reg         daa_x;
1988reg [8:0]   daa_i;
1989reg [7:0]   daa_h;
1990
1991// Верхний бит 7, 15 или 31
1992wire [3:0]  signx = isize ? (opsize ? 31 : 15) : 7;
1993
1994wire parity  = ~^res[7:0];
1995wire zerof   = isize ? (opsize ? ~|res : ~|res[15:0]) : ~|res[7:0];
1996wire carryf  = res[signx + 1];
1997wire signf   = res[signx];
1998wire auxf    = op1[4]^op2[4]^res[4];
1999
2000// Самая хитрая логика из всего тут
2001wire add_o   = (op1[isize] ^ op2[isize] ^ 1) & (op1[isize] ^ res[isize]);
2002wire sub_o   = (op1[isize] ^ op2[isize] ^ 0) & (op1[isize] ^ res[isize]);
2003
2004// Общие АЛУ
2005always @* begin
2006
2007    case (alumode)
2008
2009        /* ADD */ 0: res = op1 + op2;
2010        /* OR  */ 1: res = op1 | op2;
2011        /* ADC */ 2: res = op1 + op2 + flags[0];
2012        /* SBB */ 3: res = op1 - op2 - flags[0];
2013        /* AND */ 4: res = op1 & op2;
2014        /* SUB */ 5,
2015        /* CMP */ 7: res = op1 - op2;
2016        /* XOR */ 6: res = op1 ^ op2;
2017
2018    endcase
2019
2020    case (alumode)
2021
2022        // ADD | ADC
2023        0, 2: flags_o = {
2024
2025            /* O */ add_o,
2026            /* D */ flags[10],
2027            /* I */ flags[9],
2028            /* T */ flags[8],
2029            /* S */ signf,
2030            /* Z */ zerof,
2031            /* 0 */ 1'b0,
2032            /* A */ auxf,
2033            /* 0 */ 1'b0,
2034            /* P */ parity,
2035            /* 1 */ 1'b1,
2036            /* C */ carryf
2037        };
2038
2039        // SBB | SUB | CMP
2040        3, 5, 7: flags_o = {
2041
2042            /* O */ sub_o,
2043            /* D */ flags[10],
2044            /* I */ flags[9],
2045            /* T */ flags[8],
2046            /* S */ signf,
2047            /* Z */ zerof,
2048            /* 0 */ 1'b0,
2049            /* A */ auxf,
2050            /* 0 */ 1'b0,
2051            /* P */ parity,
2052            /* 1 */ 1'b1,
2053            /* C */ carryf
2054        };
2055
2056        // OR, AND, XOR одинаковые флаги
2057        1, 4, 6: flags_o = {
2058
2059            /* O */ 1'b0,
2060            /* D */ flags[10],
2061            /* I */ flags[9],
2062            /* T */ flags[8],
2063            /* S */ signf,
2064            /* Z */ zerof,
2065            /* 0 */ 1'b0,
2066            /* A */ 1'b0,
2067            /* 0 */ 1'b0,
2068            /* P */ parity,
2069            /* 1 */ 1'b1,
2070            /* C */ 1'b0
2071        };
2072
2073    endcase
2074
2075end
2076
2077// Десятичная коррекция
2078always @* begin
2079
2080    daa_r   = op1[7:0];
2081    flags_d = flags;
2082
2083    case (alumode)
2084
2085        // DAA, DAS
2086        0, 1: begin
2087
2088            daa_c = flags[0];
2089            daa_a = flags[4];
2090            daa_i = op1[7:0];
2091
2092            // Младший ниббл
2093            if (op1[3:0] > 9 || flags[4]) begin
2094                daa_i = alumode[0] ? op1[7:0]-6 : op1[7:0]+6;
2095                daa_c = daa_i[8];
2096                daa_a = 1;
2097            end
2098
2099            daa_r = daa_i[7:0];
2100            daa_x = daa_c;
2101
2102            // Старший ниббл
2103            if (daa_c || daa_i[7:0] > 8'h9F) begin
2104                daa_r = alumode[0] ? daa_i[7:0]-8'h60 : daa_i[7:0]+8'h60;
2105                daa_x = 1;
2106            end
2107
2108            flags_d[7] =   daa_r[7];        // S
2109            flags_d[6] = ~|daa_r[7:0];      // Z
2110            flags_d[4] =   daa_a;           // A
2111            flags_d[2] = ~^daa_r[7:0];      // P
2112            flags_d[0] =   daa_x;           // C
2113
2114        end
2115
2116        // AAA, AAS
2117        2, 3: begin
2118
2119            daa_i = op1[ 7:0];
2120            daa_r = op1[15:0];
2121
2122            if (flags[4] || op1[3:0] > 9) begin
2123
2124                daa_i = alumode[0] ? op1[ 7:0] - 6 : op1[ 7:0] + 6;
2125                daa_h = alumode[0] ? op1[15:8] - 1 : op1[15:8] + 1;
2126                daa_r = {daa_h, 4'h0, daa_i[3:0]};
2127
2128                flags_d[4] = 1; // AF=1
2129                flags_d[0] = 1; // CF=1
2130
2131            end
2132            else begin flags_d[4] = 0; flags_d[0] = 0; end
2133
2134        end
2135
2136    endcase
2137
2138end
2139
2140endmodule