§ Описание портов

Пины
  • clock — 25 мгц
  • reset_n — если 0, то процессор сбрасывается
  • locked — если 1, процессор работает
  • address — адрес
  • in — входящие данные
  • out — исходящие данные
  • we — сигнал записи
Порты
  • port_clk — тактовый импульс для защелкивания
  • port — номер порта
  • port_i — входящие данные из порта
  • port_o — исходящие данные
  • port_w — сигнал записи в порт
Прерывания
  • irq — Номер прерывания
  • intr — Запрос прерывания
  • intl — Защелка что прерывание обработано

§ Код ядра

1// verilator lint_off WIDTH
2// verilator lint_off CASEX
3// verilator lint_off CASEOVERLAP
4// verilator lint_off CASEINCOMPLETE
5module core
6(
7    // Тактовый генератор
8    input               clock,
9    input               reset_n,
10    input               locked,
11    // Магистраль данных 8 битная
12    output      [31:0]  address,
13    input       [ 7:0]  in,
14    output reg  [ 7:0]  out,
15    output reg          we,
16    // Порты
17    output  reg [15:0]  port,
18    output  reg         port_clk,
19    input       [ 7:0]  port_i,
20    output  reg [ 7:0]  port_o,
21    output  reg         port_w,
22    // Прерывания
23    input       [ 7:0]  irq,
24    input               intr,
25    output  reg         intl,
26    // Отладка
27    output      [ 3:0]  instr
28);
29// Отладочные
30assign instr = t; wire m0 = (t == 1'b0 && clock == 1'b0);
31always @(posedge clock)
32if (locked) begin
33if (reset_n == 1'b0) begin
34    t           <= fetch;
35    cs          <= 16'h000;
36    ds          <= 16'h000;
37    es          <= 16'h000;
38    ss          <= 16'h000;
39    esp         <= 20'h00800;
40    eip         <= 20'hF8000;
41    eflags      <= 2'h2;
42    adsize      <= defsize;
43    __adsize    <= defsize;
44    __opsize    <= defsize;
45    __segment   <= 16'h0000;
46    __override  <= 1'b0;
47    __rep       <= 1'b0;
48    __opext     <= 1'b0;
49    src         <= 1'b0;
50    prot        <= 1'b0;
51    psize       <= 1'b0;
52    trace_ff    <= 1'b0;
53end
54else case (t)
55    // Считывание опкода или префикса
56    fetch: begin
57        eip      <= eip_next;
58        opcode   <= in;
59        size     <= in[0];
60        dir      <= in[1];
61        alu      <= in[5:3];
62        regn     <= in[2:0];
63        fn       <= 1'b0;
64        fn2      <= 1'b0;
65        ignoreo  <= 1'b0;
66        t_next   <= fetch;
67        src_next <= 1'b1;
68        case (in)
69            // Сегментные префиксы
70            8'h26: begin psize <= psize + 1'b1; __segment <= es; __override <= 1'b1; end
71            8'h2E: begin psize <= psize + 1'b1; __segment <= cs; __override <= 1'b1; end
72            8'h36: begin psize <= psize + 1'b1; __segment <= ss; __override <= 1'b1; end
73            8'h3E: begin psize <= psize + 1'b1; __segment <= ds; __override <= 1'b1; end
74            8'h64: begin psize <= psize + 1'b1; __segment <= fs; __override <= 1'b1; end
75            8'h65: begin psize <= psize + 1'b1; __segment <= gs; __override <= 1'b1; end
76            // Префиксы расширения адреса
77            8'h66: begin psize <= psize + 1'b1; __opsize  <= ~__opsize; end
78            8'h67: begin psize <= psize + 1'b1; __adsize  <= ~__adsize; end
79            // ...
80            8'h0F: begin psize <= psize + 1'b1; __opext   <= 1'b1; end
81            // LOCK, REP
82            8'hF0: begin psize <= psize + 1'b1; end // LOCK:
83            8'hF2, 8'hF3: begin psize <= psize + 1'b1; __rep <= in[1:0]; end
84            // Исполнение опкода
85            default: begin
86                t       <= exec;
87                eip_rep <= eip-psize;
88                psize   <= 0;
89                // Защелкивание префиксов
90                rep         <= __rep;       __rep       <= 2'b00;
91                override    <= __override;  __override  <= 1'b0;
92                opsize      <= __opsize;    __opsize    <= defsize;
93                adsize      <= __adsize;    __adsize    <= defsize;
94                segment     <= __segment;   __segment   <= ds;
95                opcode[8]   <= __opext;     __opext     <= 1'b0;
96                // Вызвать прерывание, если разрешено
97                if (eflags[IF] && intr ^ intl) begin
98                    t       <= interrupt;
99                    intl    <= intr;
100                    eip     <= eip - psize;
101                    wb      <= irq;
102                end
103                // Trace Flag=1
104                else if (eflags[TF] && trace_ff) begin
105                    t        <= interrupt;
106                    trace_ff <= ~trace_ff;
107                    eip      <= eip - psize;
108                    wb       <= 1;
109                end
110                // На первом такте также можно исполнять некоторые опкоды
111                else casex ({__opext, in})
112                    // FWAIT, NOP
113                    8'h9B, 8'h90: begin t <= fetch; end
114                    // <ALU> modrm; XCHG modrm; ESC
115                    8'b00xx_x0xx,
116                    8'b1000_011x,
117                    8'b1101_1xxx: begin t <= fetch_modrm; end
118                    8'b00xx_x101, // <ALU> a, imm
119                    8'b1001_1010, // JMP|CALL far seg:off
120                    8'b1110_1010: begin t <= fetch_imm16; end
121                    // RET/RETF imm
122                    8'b1100_x010: begin t <= fetch_imm16; t_next <= exec; size <= 1'b1; end
123                    // POP
124                    8'b000x_x111, // POP sreg
125                    8'b0101_1xxx, // POP r16
126                    8'b1000_1111, // POPF
127                    8'b1001_1101, // POP rm
128                    8'b1100_1111, // IRET; RET; RETF
129                    8'b1100_x011: begin t <= pop; t_next <= exec; op1 <= 0; fn <= 1; end
130                    // DAA, DAS
131                    8'b0010_x111: begin t <= fetch; eflags <= eflags_d; eax[7:0] <= daa_r[ 7:0]; end
132                    // Jccc short|near
133                    9'b0_0111_xxxx,
134                    9'b1_1000_xxxx: begin
135                        size <= 1'b1;
136                        // Если условие не сработало, переход к +2
137                        if (branches[ in[3:1] ] == in[0]) begin
138                            t   <= fetch;
139                            eip <= __opext ? (__opsize ? eip_next5 : eip_next3) : eip_next2;
140                        end
141                        // В near-варианте считывается 16/32 бита
142                        else if (__opext) begin size <= 1'b1; t <= fetch_imm16; end
143                    end
144                    // AAA, AAS
145                    8'b0011_x111: begin t <= fetch; eflags <= eflags_d; eax[15:0] <= daa_r[15:0]; end
146                    // PUSH sreg
147                    8'b000x_x110: begin
148                        t       <= push;
149                        opsize  <= 1'b0;
150                        case (in[4:3])
151                        2'b00: wb <= es[15:0];
152                        2'b01: wb <= cs[15:0];
153                        2'b10: wb <= ss[15:0];
154                        2'b11: wb <= ds[15:0];
155                        endcase
156                    end
157                    // PUSH imm16
158                    8'b0110_1000: begin t <= fetch_imm16; size <= 1'b1; t_next <= exec; end
159                    // INC|DEC r16; PUSH r16; XCHG a,r16
160                    8'b0100_xxxx,
161                    8'b0101_0xxx,
162                    8'b1001_0xxx: begin size <= 1'b1; end
163                    // PUSHA
164                    8'b0110_0000: begin frametemp <= esp; t_next <= exec; size <= 1'b1; regn <= 0; end
165                    // POPA
166                    8'b0110_0001: begin t_next <= exec; regn <= 7; t <= pop; end
167                    // IMUL r,m,i8
168                    8'b0110_10x1: begin t <= fetch_modrm; {size, dir} <= 2'b11; src_next <= 1'b0; end
169                    // *SHIFT* C0-C1,D0-D3
170                    // *ALU* 80-83
171                    8'b1000_00xx,
172                    8'b1100_000x,
173                    8'b1101_00xx: begin
174                        t           <= fetch_modrm;
175                        dir         <= 1'b0;
176                        src_next    <= 1'b0;
177                    end
178                    // PUSHF
179                    8'b1001_1100: begin
180                        t   <= push;
181                        wb  <= {eflags[17:6], 1'b0, eflags[4], 1'b0, eflags[2], 1'b1, eflags[0]};
182                    end
183                    // MOV [m],a; MOV a,[m]
184                    8'b1010_00xx: begin
185                        t       <= fetch_imm16;
186                        size    <= 1'b1;
187                        opsize  <= __adsize;
188                        adsize  <= __opsize;
189                    end
190                    // MOVSx | LODSx
191                    8'b1010_x10x: if (__rep[1] == 1'b0 || str_zcx) begin
192                        t       <= fetch_modrm;
193                        t_next  <= exec;
194                        fn2     <= 4;
195                        src     <= 1'b1;
196                        ea      <= defsize ? esi : esi[15:0];
197                    end else t <= fetch;
198                    // STOSx
199                    8'b1010_101x: if (__rep[1] == 1'b0 || str_zcx) begin
200                        t       <= modrm_wb;
201                        segment <= es;
202                        ea      <= defsize ? edi : edi[15:0];
203                        wb      <= eax;
204                        edi     <= str_edi;
205                        dir     <= 1'b0;
206                        src     <= 1'b1;
207                        modrm   <= 1'b0;
208                        // При REP: уменьшать CX и переход к возвратной точке
209                        if (__rep[1]) begin ecx <= str_ecx; eip <= eip-psize; end
210                    end else t <= fetch;
211                    // CMPSx
212                    8'b1010_011x: if (__rep[1] == 1'b0 || str_zcx) begin
213                        t       <= fetch_modrm;
214                        t_next  <= exec;
215                        fn2     <= 4;
216                        dir     <= 1'b0;
217                        src     <= 1'b1;
218                        ea      <= defsize ? esi : esi[15:0];
219                        op1     <= 0;
220                        alu     <= alu_cmp;
221                    end else t <= fetch;
222                    // SCASx
223                    8'b1010_111x: if (__rep[1] == 1'b0 || str_zcx) begin
224                        t       <= fetch_modrm;
225                        t_next  <= exec;
226                        fn2     <= 4;
227                        src     <= 1'b1;
228                        ea      <= defsize ? edi : edi[15:0];
229                        segment <= es;
230                        op1     <= eax;
231                        alu     <= alu_cmp;
232                    end else t <= fetch;
233                    // TEST modrm
234                    8'b1000_010x: begin t <= fetch_modrm; alu <= alu_and; end
235                    // MOV rm, sreg
236                    8'b1000_1100: begin t <= fetch_modrm; {size, dir, ignoreo} <= 3'b101; end
237                    // LEA r16, [ea]
238                    8'b1000_1101: begin t <= fetch_modrm; {size, dir, ignoreo} <= 3'b111; end
239                    // LES|LDS r,[m]
240                    // MOV sreg, rm
241                    8'b1100_010x,
242                    8'b1000_1110: begin t <= fetch_modrm; {size, dir} <= 2'b11; end
243                    // MOV modrm
244                    8'b1000_10xx: begin t <= fetch_modrm; ignoreo <= ~in[1]; end
245                    // MOV r,imm
246                    8'b1011_1xxx: begin t <= fetch_imm16; end
247                    // SAHF
248                    8'b1001_1110: begin eflags[7:0] <= eax[15:8];   t <= fetch; end
249                    // LAHF
250                    8'b1001_1111: begin eax[15:8]   <= eflags[7:0]; t <= fetch; end
251                    // CBW, CWDE
252                    8'b1001_1000: begin
253                        t <= fetch;
254                        if (__opsize)
255                             eax[31:16] <= {16{eax[15]}};
256                        else eax[15:8]  <= { 8{eax[7]}};
257                    end
258                    // CWD, CDQ
259                    8'b1001_1001: begin
260                        t <= fetch;
261                        if (__opsize)
262                             edx[31:0] <= {32{eax[31]}};
263                        else edx[15:0] <= {16{eax[15]}};
264                    end
265                    // TEST a, imm16
266                    8'b1010_1001: begin t <= fetch_imm16; end
267                    // MOV modrm,imm
268                    8'b1100_011x: begin t <= fetch_modrm; {dir, ignoreo} <= 2'b01; end
269                    // ENTER i16, i8
270                    8'b1100_1000: begin t <= fetch_imm16; t_next <= exec; size <= 1'b1; end
271                    // LEAVE
272                    8'b1100_1001: begin esp <= ebp; t <= pop; t_next <= exec; end
273                    // SALC
274                    8'b1101_0110: begin t <= fetch; eax[7:0] <= {8{eflags[CF]}}; end
275                    // XLATB
276                    8'b1101_0111: begin t <= exec; ea <= ebx[15:0] + eax[7:0]; src <= 1'b1; end
277                    // JCXZ
278                    8'b1110_0011: begin
279                        t <= fetch;
280                        if ((__opsize && ecx == 0) || (!__opsize && ecx[15:0] == 0))
281                            t <= exec;
282                        else
283                            eip <= eip_next2;
284                    end
285                    // LOOP, LOOPNZ, LOOPZ
286                    8'b1110_000x,
287                    8'b1110_0010: begin
288                        t <= fetch;
289                        // В зависимости от выбранного режима адресации либо ECX, либо CX
290                        if (__adsize) ecx <= ecx - 1'b1; else ecx[15:0] <= ecx[15:0] - 1'b1;
291                        // ZF=0/1 и CX != 0 (после декремента)
292                        if (((eflags[ZF] == in[0]) || in[1]) && (__adsize ? ecx : ecx[15:0]) != 1'b1)
293                            t <= exec;
294                        else
295                            eip <= eip_next2;
296                    end
297                    // IN|OUT
298                    8'b1110_x1xx: begin
299                        fn       <= in[3] ? 1 : 0;
300                        op1      <= in[0] ? (__opsize ? 3 : 1) : 0;
301                        op2      <= 0;
302                        port     <= edx[15:0];
303                        port_clk <= 1'b0;
304                    end
305                    // CALL|JMP near
306                    8'b1110_100x: begin t <= fetch_imm16; size <= 1'b1; end
307                    // INT 3; INT 1
308                    8'b1100_1100: begin t <= interrupt; wb <= 3; end
309                    8'b1111_0001: begin t <= interrupt; wb <= 1; end
310                    // INTO
311                    8'b1100_1110: begin if (eflags[OF]) begin t <= interrupt; wb <= 4; end else t <= fetch; end
312                    // HLT
313                    8'b1111_0100: begin t <= fetch; eip <= eip; end
314                    // CMC; CLC,STC; CLI,STI; CLD,STD
315                    8'b1111_0101: begin t <= fetch; eflags[CF] <= ~eflags[CF]; end
316                    8'b1111_100x: begin t <= fetch; eflags[CF] <= in[0]; end
317                    8'b1111_101x: begin t <= fetch; eflags[IF] <= in[0]; end
318                    8'b1111_110x: begin t <= fetch; eflags[DF] <= in[0]; end
319                    // Групповые инструкции
320                    8'b1111_x11x: begin t <= fetch_modrm; t_next <= exec; dir <= 1'b0; end
321                    // CMOV<cc> r,rm
322                    // MOV[Z|S]X r16/32, rm8/16
323                    9'b1_0100_xxxx,
324                    9'b1_1011_x11x: begin t <= fetch_modrm; dir <= 1'b1; size <= 1'b1; end
325                    // SET<cc> rm8
326                    9'b1_1001_xxxx: begin t <= fetch_modrm; dir <= 1'b0; size <= 1'b0; ignoreo <= 1'b1; end
327                    // Все оставшиеся
328                    default: t <= exec;
329                endcase
330            end
331        endcase
332    end
333    // Прочитать байт modrm+sib
334    fetch_modrm: case (fn2)
335        // Считывание регистров
336        0: begin
337            modrm   <= in;
338            eip     <= eip_next;
339            ea      <= 1'b0;
340            // Левый операнд
341            case (dir ? in[5:3] : in[2:0])
342            0: op1 <= size ? (opsize ? eax : eax[15:0]) : eax[ 7:0];
343            1: op1 <= size ? (opsize ? ecx : ecx[15:0]) : ecx[ 7:0];
344            2: op1 <= size ? (opsize ? edx : edx[15:0]) : edx[ 7:0];
345            3: op1 <= size ? (opsize ? ebx : ebx[15:0]) : ebx[ 7:0];
346            4: op1 <= size ? (opsize ? esp : esp[15:0]) : eax[15:8];
347            5: op1 <= size ? (opsize ? ebp : ebp[15:0]) : ecx[15:8];
348            6: op1 <= size ? (opsize ? esi : esi[15:0]) : edx[15:8];
349            7: op1 <= size ? (opsize ? edi : edi[15:0]) : ebx[15:8];
350            endcase
351            // Правый операнд
352            case (dir ? in[2:0] : in[5:3])
353            0: op2 <= size ? (opsize ? eax : eax[15:0]) : eax[ 7:0];
354            1: op2 <= size ? (opsize ? ecx : ecx[15:0]) : ecx[ 7:0];
355            2: op2 <= size ? (opsize ? edx : edx[15:0]) : edx[ 7:0];
356            3: op2 <= size ? (opsize ? ebx : ebx[15:0]) : ebx[ 7:0];
357            4: op2 <= size ? (opsize ? esp : esp[15:0]) : eax[15:8];
358            5: op2 <= size ? (opsize ? ebp : ebp[15:0]) : ecx[15:8];
359            6: op2 <= size ? (opsize ? esi : esi[15:0]) : edx[15:8];
360            7: op2 <= size ? (opsize ? edi : edi[15:0]) : ebx[15:8];
361            endcase
362            // 32-bit MODRM
363            if (adsize) begin
364                case (in[2:0])
365                3'b000: ea <= eax;
366                3'b001: ea <= ecx;
367                3'b010: ea <= edx;
368                3'b011: ea <= ebx;
369                3'b100: ea <= 0;
370                3'b101: ea <= ^in[7:6] ? ebp : 0;
371                3'b110: ea <= esi;
372                3'b111: ea <= edi;
373                endcase
374                // Выбор решения
375                case (in[7:6])
376                2'b00: begin
377                    if      (in[2:0] == 3'b101) fn2 <= 1;  // DISP32
378                    else if (in[2:0] == 3'b100) fn2 <= 10; // SIB
379                    else begin
380                        fn2 <= 4;
381                        src <= 1'b1;
382                        if (ignoreo) begin t <= exec; fn2 <= 0; end
383                    end
384                end
385                2'b01: fn2 <= in[2:0] == 3'b100 ? 10 : 3; // 8     bit | SIB
386                2'b10: fn2 <= in[2:0] == 3'b100 ? 10 : 1; // 16/32 bit | SIB
387                2'b11: begin fn2 <= 0; t <= exec; end
388                endcase
389                // Выбор сегмента по умолчанию
390                if (!override && (^in[7:6] && in[2:0] == 3'b101))
391                    segment <= ss;
392            end
393            // 16-bit MODRM
394            else begin
395                case (in[2:0])
396                3'b000: ea[15:0] <= ebx + esi;
397                3'b001: ea[15:0] <= ebx + edi;
398                3'b010: ea[15:0] <= ebp + esi;
399                3'b011: ea[15:0] <= ebp + edi;
400                3'b100: ea[15:0] <= esi;
401                3'b101: ea[15:0] <= edi;
402                3'b110: ea[15:0] <= ^in[7:6] ? ebp : 1'b0;
403                3'b111: ea[15:0] <= ebx;
404                endcase
405                // Выбор сегмента по умолчанию
406                if (!override && (in[2:1] == 2'b01 || (^in[7:6] && in[2:0] == 3'b110)))
407                    segment <= ss;
408                // Выбор решения
409                case (in[7:6])
410                2'b00: begin
411                    // Читать +disp16
412                    if (in[2:0] == 3'b110) fn2 <= 1;
413                    // Сразу читать операнды из памяти
414                    else begin
415                        fn2 <= 4;
416                        src <= 1'b1;
417                        if (ignoreo) begin t <= exec; fn2 <= 0; end
418                    end
419                end
420                2'b01: fn2 <= 3; // 8 bit
421                2'b10: fn2 <= 1; // 16 bit
422                2'b11: begin fn2 <= 0; t <= exec; end
423                endcase
424            end
425        end
426        // DISP16/32
427        1: begin fn2 <= 2; ea <= ea + in; eip <= eip_next; end
428        2: begin
429            fn2      <=  adsize ? 8 : 4;
430            src      <= !adsize;
431            ea[31:8] <= ea[31:8] + in;
432            eip      <= eip_next;
433            if (ignoreo && !adsize) begin t <= exec; fn2 <= 0; end
434        end
435        // DISP8
436        3: begin
437            fn2 <= 4;
438            ea  <= ea + {{24{in[7]}}, in};
439            src <= 1'b1;
440            eip <= eip_next;
441            if (ignoreo) begin t <= exec; fn2 <= 0; end
442        end
443        // OPERAND-7:0
444        4: begin
445            if (dir) op2 <= in; else op1 <= in;
446            if (size) begin fn2 <= 5; ea <= ea + 1; end
447            else      begin fn2 <= 0; t  <= exec; src <= src_next; end
448        end
449        // OPERAND-15:8
450        5: begin
451            if (dir) op2[15:8] <= in; else op1[15:8] <= in;
452            if (opsize) begin fn2 <= 6; ea <= ea + 1; end
453            else        begin fn2 <= 0; ea <= ea - 1; t <= exec; src <= src_next; end
454        end
455        // OPERAND-23:16
456        6: begin
457            fn2 <= 7; ea <= ea + 1;
458            if (dir) op2[23:16] <= in; else op1[23:16] <= in;
459        end
460        // OPERAND-31:24
461        7: begin
462            t   <= exec;
463            fn2 <= 0;
464            ea  <= ea - 3;
465            src <= src_next;
466            if (dir) op2[31:24] <= in; else op1[31:24] <= in;
467        end
468        // DISP32
469        8: begin fn2 <= 9; ea[31:16] <= ea[31:16] + in; eip <= eip_next; end
470        9: begin
471            fn2         <= 4;
472            ea[31:24]   <= ea[31:24] + in;
473            src         <= 1'b1;
474            eip         <= eip_next;
475            if (ignoreo) begin t <= exec; fn2 <= 0; end
476        end
477        // SIB
478        10: begin
479            eip <= eip_next;
480            // SCALE*INDEX
481            case (in[5:3])
482            3'b000: ea <= sib_base + (eax << in[7:6]);
483            3'b001: ea <= sib_base + (ecx << in[7:6]);
484            3'b010: ea <= sib_base + (edx << in[7:6]);
485            3'b011: ea <= sib_base + (ebx << in[7:6]);
486            3'b100: ea <= sib_base;
487            3'b101: ea <= sib_base + (ebp << in[7:6]);
488            3'b110: ea <= sib_base + (esi << in[7:6]);
489            3'b111: ea <= sib_base + (edi << in[7:6]);
490            endcase
491            // disp32 или чтение операнда
492            case (modrm[7:6])
493            2'b00: if (in[2:0] == 3'b101)
494                   begin fn2 <= 1; end // disp32
495            else   begin fn2 <= 4; src <= 1'b1; end // operand
496            2'b01: begin fn2 <= 3; end // disp8
497            2'b10: begin fn2 <= 1; end // disp32
498            2'b11: begin fn2 <= 0; t <= exec; end
499            endcase
500            // Выбор сегмента по умолчанию (ebp)
501            if (!override && ((^modrm[7:6] && in[2:0] == 3'b101) || (in[5:3] == 3'b101)))
502                segment <= ss;
503            // Если необходимо игнорировать чтение операнда, то выход сразу к исполнению
504            if (ignoreo && modrm[7:6] == 2'b00 && in[2:0] != 3'b101) begin t <= exec; fn2 <= 0; end
505        end
506    endcase
507    // Запись результата в память или регистры
508    modrm_wb: case (fn2)
509        0: begin
510            // Проверка на запись в регистр
511            if (dir || modrm[7:6] == 2'b11) begin
512                case (dir ? modrm[5:3] : modrm[2:0])
513                3'b000: if (size && opsize) eax <= wb; else if (size) eax[15:0] <= wb[15:0]; else eax[ 7:0] <= wb[7:0];
514                3'b001: if (size && opsize) ecx <= wb; else if (size) ecx[15:0] <= wb[15:0]; else ecx[ 7:0] <= wb[7:0];
515                3'b010: if (size && opsize) edx <= wb; else if (size) edx[15:0] <= wb[15:0]; else edx[ 7:0] <= wb[7:0];
516                3'b011: if (size && opsize) ebx <= wb; else if (size) ebx[15:0] <= wb[15:0]; else ebx[ 7:0] <= wb[7:0];
517                3'b100: if (size && opsize) esp <= wb; else if (size) esp[15:0] <= wb[15:0]; else eax[15:8] <= wb[7:0];
518                3'b101: if (size && opsize) ebp <= wb; else if (size) ebp[15:0] <= wb[15:0]; else ecx[15:8] <= wb[7:0];
519                3'b110: if (size && opsize) esi <= wb; else if (size) esi[15:0] <= wb[15:0]; else edx[15:8] <= wb[7:0];
520                3'b111: if (size && opsize) edi <= wb; else if (size) edi[15:0] <= wb[15:0]; else ebx[15:8] <= wb[7:0];
521                endcase
522                t   <= t_next;
523                src <= 1'b0;
524            end
525            // LO-BYTE
526            else begin
527                out <= wb[7:0];
528                we  <= 1'b1;
529                src <= 1'b1;
530                fn2 <= 1;
531            end
532        end
533        // HI-BYTE
534        1: begin
535            if (size) begin out <= wb[15:8]; ea <= ea + 1; fn2 <= 2; end
536            else      begin fn2 <= 0; t <= t_next; {src, we} <= 2'b00;  end
537        end
538        // BYTE-3
539        2: begin
540            if (opsize) begin out <= wb[23:16]; ea <= ea + 1; fn2 <= 3; end
541            else        begin fn2 <= 0; t <= t_next; {src, we} <= 2'b00; end
542        end
543        // BYTE-4
544        3: begin out <= wb[31:24]; ea <= ea + 1; fn2 <= 4; end
545        4: begin fn2 <= 0; t <= t_next; {src, we} <= 2'b00; end
546    endcase
547    // Считать 16 или 32 бита
548    fetch_imm16: case (fn2)
549        0: begin eip <= eip_next; wb        <= in; fn2 <= 1; end
550        1: begin eip <= eip_next; wb[15:8]  <= in; fn2 <= opsize ? 2 : 0; if (!opsize) t <= exec; end
551        2: begin eip <= eip_next; wb[23:16] <= in; fn2 <= 3; end
552        3: begin eip <= eip_next; wb[31:24] <= in; fn2 <= 0; t <= exec; end
553    endcase
554    // Загрузка сегмента из wb
555    loadseg: case (fn2)
556        // Пока что загрузка идет только в REALMODE
557        0: begin
558            t   <= t_next;
559            src <= 1'b0;
560            // Обновить сегмент | селектор
561            case (regn)
562            3'b000: begin es[15:0] <= wb; end
563            3'b001: begin cs[15:0] <= wb; end
564            3'b010: begin ss[15:0] <= wb; end
565            // Заместить "скрытый" сегмент
566            3'b011: begin ds[15:0] <= wb; __segment[15:0] <= wb; end
567            3'b100: begin fs[15:0] <= wb; end
568            3'b101: begin gs[15:0] <= wb; end
569            default: t <= exception;
570            endcase
571        end
572    endcase
573    // Запись в стек
574    push: case (fn2)
575        // BYTE-1
576        0: begin
577            fn2     <= 1;
578            segment <= ss;
579            ea      <= esp_dec;
580            esp     <= esp_dec;
581            src     <= 1'b1;
582            we      <= 1'b1;
583            out     <= wb[7:0];
584        end
585        // Запись байтов 2/3/4/FIN
586        1: begin ea <= ea + 1; out <= wb[ 15:8]; fn2 <= stacksize | opsize ? 2 : 4; end
587        2: begin ea <= ea + 1; out <= wb[24:16]; fn2 <= 3; end
588        3: begin ea <= ea + 1; out <= wb[31:24]; fn2 <= 4; end
589        4: begin {we, src} <= 2'b00; fn2 <= 0; t <= t_next; end
590    endcase
591    // Извлечь из стека
592    pop: case (fn2)
593        // Установка адреса
594        0: begin
595            fn2     <= 1;
596            segment <= ss;
597            ea      <= esp;
598            esp     <= esp_inc;
599            src     <= 1'b1;
600        end
601        // 16bit
602        1: begin fn2 <= 2; wb <= in; ea <= ea + 1; end
603        2: begin
604            wb[15:8] <= in;
605            fn2 <= stacksize | opsize ? 3 : 0;
606            ea  <= ea + 1;
607            if (opsize == 0) begin src <= 1'b0; t <= t_next; end
608        end
609        // 32bit
610        3: begin wb[23:16] <= in; fn2 <= 4; ea <= ea + 1; end
611        4: begin wb[31:24] <= in; fn2 <= 0; src <= 1'b0; t <= t_next; end
612    endcase
613    // Сдвиги
614    // alu
615    // size, opsize
616    // op1, op2
617    shift: case (fn2)
618        // Вычисление ограничения количества сдвигов
619        // Если сдвиг не задан (0), то сдвиг не срабатывает
620        0: begin
621            fn2 <= 1;
622            // 32 bit
623            if (size && opsize) begin
624                wb  <= 31;
625                op2 <= op2[4:0];
626                if (op2[4:0] == 0) begin fn2 <= 0; src <= 1'b0; t <= fetch; end
627            end
628            // 16 bit
629            else if (size) begin
630                // DosBox так обрабатывает (4:0)
631                wb  <= 15;
632                op2 <= op2[4:0];
633                if (op2[4:0] == 0) begin fn2 <= 0; src <= 1'b0; t <= fetch; end
634            end
635            // 8 bit
636            else begin
637                wb  <= 7;
638                op2 <= op2[2:0];
639                if (op2[2:0] == 0) begin fn2 <= 0; src <= 1'b0; t <= fetch; end
640            end
641        end
642        // Вычисление
643        1: begin
644            // Сдвиги
645            if (op2) begin
646                op2 <= op2 - 1;
647                case (alu)
648                    0: // ROL
649                    begin op1 <= size ? (opsize ? {op1[30:0],op1[31]} : {op1[14:0],op1[15]}) : {op1[6:0],op1[7]}; end
650                    1: // ROR
651                    begin op1 <= size ? (opsize ? {op1[0],op1[31:1]} : {op1[0],op1[15:1]}) : {op1[0],op1[7:1]}; end
652                    2: // RCL
653                    begin
654                        op1 <= size ? (opsize ? {op1[30:0],eflags[CF]} : {op1[14:0],eflags[CF]}) : {op1[6:0],eflags[CF]};
655                        eflags[CF] <= op1[wb];
656                    end
657                    3: // RCR
658                    begin
659                        op1 <= size ? (opsize ? {eflags[CF],op1[31:1]} : {eflags[CF],op1[15:1]}) : {eflags[CF],op1[7:1]};
660                        eflags[CF] <= op1[0];
661                    end
662                    4, 6: // SHL
663                    begin
664                        eflags[CF] <= op1[wb-op2+1];
665                        op1 <= op1 << op2;
666                        op2 <= 0;
667                    end
668                    5: // SHR
669                    begin
670                        eflags[CF] <= op1[op2-1];
671                        op1 <= op1 >> op2;
672                        op2 <= 0;
673                    end
674                    7: // SAR
675                    begin
676                        op1 <= size ? (opsize ? {op1[31],op1[31:1]} : {op1[15],op1[15:1]}) : {op1[7],op1[7:1]};
677                        eflags[CF] <= op1[0];
678                    end
679                endcase
680            end
681            // Расчет флагов
682            else begin
683                fn2 <= 0;
684                t   <= modrm_wb;
685                wb  <= op1;
686                case (alu)
687                    0: begin eflags[CF] <= op1[0];  eflags[OF] <= op1[0]  ^ op1[wb];   end
688                    1: begin eflags[CF] <= op1[wb]; eflags[OF] <= op1[wb] ^ op1[wb-1]; end
689                    2: begin eflags[OF] <= eflags[CF] ^ op1[wb]; end
690                    3: begin eflags[OF] <= op1[wb] ^ op1[wb-1]; end
691                    default: begin
692                        eflags[ZF] <= !op1;
693                        eflags[SF] <= op1[wb];
694                        eflags[PF] <= ~^op1[7:0];
695                        eflags[AF] <= 1'b1;
696                    end
697                endcase
698            end
699        end
700    endcase
701    // Процедура деления [diva, divb, divcnt]
702    divide: begin
703        if (divcnt) begin
704            // Следующий остаток
705            divrem <= _divr >= divb ? _divr - divb : _divr;
706            // Вдвиг нового бита результата
707            divres <= {divres[62:0], _divr >= divb};
708            // Сдвиг влево делимого
709            diva   <= {diva[62:0], 1'b0};
710            // Уменьшение счетчика
711            divcnt <= divcnt - 1'b1;
712        end
713        else t <= t_next;
714    end
715    // portin: begin end
716    // portout: begin end
717    // Вызов прерывания wb
718    interrupt: case (fn)
719        // Запись в стек eflags|cs|ip
720        0: begin
721            fn          <= 1;
722            t           <= push;
723            t_next      <= interrupt;
724            wb          <= eflags;
725            eflags[IF]  <= 1'b0;
726            eflags[TF]  <= 1'b0;
727            op1         <= wb;
728        end
729        1: begin fn <= 2; t <= push; wb <=  cs[15:0]; end
730        2: begin fn <= 3; t <= push; wb <= eip[15:0]; end
731        // Загрузка данных из IDTR
732        3: begin fn <= 4; ea <= {op1[7:0], 2'b00}; src <= 1'b1; segment[15:0] <= 16'h0000; end
733        4: begin fn <= 5; eip[ 7:0] <= in; ea <= ea + 1; end
734        5: begin fn <= 6; eip[15:8] <= in; ea <= ea + 1; end
735        6: begin fn <= 7; wb [ 7:0] <= in; ea <= ea + 1; end
736        7: begin
737            t           <= loadseg;
738            t_next      <= fetch;
739            fn          <= 0;
740            fn2         <= 0;
741            wb[15:8]    <= in;
742            regn        <= 1;
743        end
744    endcase
745    exec: casex (opcode)
746        // E9      JMP near
747        // 180-18C J<ccc> near
748        9'b0_1110_1001,
749        9'b1_1000_xxxx: begin
750            t <= fetch;
751            if (opsize) eip       <= eip       + wb;
752            else        eip[15:0] <= eip[15:0] + wb[15:0];
753        end
754        // CMOV<cc> r, rm
755        9'b1_0100_xxxx: begin
756            if (branches[ opcode[3:1] ] != opcode[0]) begin
757                t  <= modrm_wb;
758                wb <= op2;
759            end else begin src <= 0; t <= fetch; end
760        end
761        // SET<cc> rm8
762        9'b1_1001_xxxx: begin
763            t  <= modrm_wb;
764            wb <= branches[ opcode[3:1] ] != opcode[0] ? 1'b1 : 1'b0;
765        end
766        // MOV[ZS]X reg, rm
767        9'b1_1011_x11x: begin
768            t <= modrm_wb;
769            if (opcode[2])
770                 wb <= opcode[0] ? {{16{op2[15]}}, op2[15:0]} : {{24{op2[7]}}, op2[7:0]}; // SX
771            else wb <= opcode[0] ?                 op2[15:0]  :                op2[7:0];  // ZX
772        end
773        // 00 <ALU> modrm
774        8'b00xx_x0xx: begin
775            t       <= modrm_wb;
776            wb      <= alu_r;
777            eflags  <= alu_f;
778            if (alu == alu_cmp) begin t <= fetch; src <= 1'b0; end
779        end
780        // 04 <ALU> a, imm
781        8'b00xx_x10x: case (fn)
782            // Выставить операнды на вычисление
783            0: begin
784                fn  <= 1;
785                op1 <= size ? (opsize ? eax : eax[15:0]) : eax[7:0];
786                op2 <= size ? (opsize ? wb  : wb[15:0]) : in;
787                if (size == 0) eip <= eip_next;
788            end
789            // Записать результаты в AL|AX|EAX
790            1: begin
791                t       <= fetch;
792                eflags  <= alu_f;
793                if (alu != alu_cmp) begin
794                    if (opsize && size) eax       <= alu_r;
795                    else if (size)      eax[15:0] <= alu_r[15:0];
796                    else                eax[7:0]  <= alu_r[7:0];
797                end
798            end
799        endcase
800        // 07 POP sreg
801        8'b000x_x111: begin
802            t       <= loadseg;
803            t_next  <= fetch;
804            regn    <= opcode[4:3];
805        end
806        // 40 INC|DEC r16
807        8'b0100_xxxx: case (fn)
808            // Загрузка
809            0: begin
810                fn  <= 1;
811                op1 <= reg32;
812                op2 <= 1;
813                alu <= opcode[3] ? alu_sub : alu_add;
814            end
815            // Вычисление
816            1: begin
817                t           <= modrm_wb;
818                wb          <= alu_r;
819                eflags      <= {alu_f[17:1], eflags[CF]};
820                dir         <= 1'b1;
821                modrm[5:3]  <= opcode[2:0];
822            end
823        endcase
824        // 50 PUSH r16
825        8'b0101_0xxx: begin
826            t  <= push;
827            wb <= reg32;
828        end
829        // 58 POP r16
830        8'b0101_1xxx: begin
831            t           <= modrm_wb;
832            t_next      <= fetch;
833            size        <= 1'b1;
834            dir         <= 1'b1;
835            modrm[5:3]  <= opcode[2:0];
836        end
837        // 60 PUSHA
838        8'b0110_0000: begin
839            if (regn == 7) t_next <= fetch;
840            wb   <= regn == 4 ? frametemp : reg32;
841            t    <= push;
842            regn <= regn + 1;
843        end
844        // 60 POPA
845        8'b0110_0001: begin
846            t    <= regn == 0 ? fetch : pop;
847            regn <= regn - 1;
848            case (regn)
849                0: if (opsize) eax <= wb; else eax[15:0] <= wb[15:0];
850                1: if (opsize) ecx <= wb; else ecx[15:0] <= wb[15:0];
851                2: if (opsize) edx <= wb; else edx[15:0] <= wb[15:0];
852                3: if (opsize) ebx <= wb; else ebx[15:0] <= wb[15:0];
853                // esp skip
854                5: if (opsize) ebp <= wb; else ebp[15:0] <= wb[15:0];
855                6: if (opsize) esi <= wb; else esi[15:0] <= wb[15:0];
856                7: if (opsize) edi <= wb; else edi[15:0] <= wb[15:0];
857            endcase
858        end
859        // 68 PUSH i16
860        8'b0110_10x0: begin
861            t       <= push;
862            t_next  <= fetch;
863            if (opcode[1]) begin wb <= {{24{in[7]}}, in}; eip <= eip_next; end
864        end
865        // 69 IMUL r16, rm, i16/i8
866        8'b0110_10x1: case (fn)
867            0: begin
868                fn      <= 1;
869                t       <= opcode[1] ? exec : fetch_imm16;
870                t_next  <= exec;
871                op1     <= op2;
872                wb      <= in;
873                if (opcode[1]) eip <= eip_next;
874            end
875            1: begin
876                fn      <= 2;
877                op1     <= opsize ? op2 : {{16{op2[15]}}, op2[15:0]};
878                op2     <= opcode[1] ? {{24{wb[7]}}, wb[7:0]} : (opsize ? wb : {{16{wb[15]}}, wb[15:0]});
879            end
880            2: begin
881                if (opsize) begin
882                    wb <= mult[31:0];
883                    eflags[CF] <= mult[63:32] ? 1 : 0;
884                    eflags[OF] <= mult[63:32] ? 1 : 0;
885                end
886                else begin
887                    wb <= mult[15:0];
888                    eflags[CF] <= mult[31:16] ? 1 : 0;
889                    eflags[OF] <= mult[31:16] ? 1 : 0;
890                end
891                t       <= modrm_wb;
892                t_next  <= fetch;
893            end
894        endcase
895        // 80 <ALU> rm, i8/16
896        8'b1000_00xx: case (fn)
897            // Считывние 8 бит или дочитывание 16/32
898            0: begin
899                fn  <= 2;
900                alu <= modrm[5:3];
901                case (opcode[1:0])
902                /*I8 */ 0, 2: begin eip <= eip_next;    op2 <= in; end
903                /*I16*/ 1:    begin t   <= fetch_imm16; fn  <= 1; end
904                /*S8 */ 3:    begin eip <= eip_next;    op2 <= opsize ? {{24{in[7]}}, in} : {{8{in[7]}}, in}; end
905                endcase
906            end
907            // Данные из Imm16/32
908            1: begin fn <= 2; op2 <= wb; end
909            // Запись результата
910            2: begin
911                t       <= modrm_wb;
912                wb      <= alu_r;
913                eflags  <= alu_f;
914                src     <= 1'b1;
915                if (alu == alu_cmp) begin t <= fetch; src <= 1'b0; end
916            end
917        endcase
918        // 84 TEST modrm
919        8'b1000_010x: begin
920            eflags  <= alu_f;
921            fn      <= 1'b0;
922            t       <= fetch;
923            src     <= 1'b0;
924        end
925        // 86 XCHG rm,r
926        8'b1000_011x: case (fn)
927            0: begin t <= modrm_wb; wb <= op2; t_next <= exec;  fn  <= 1; end
928            1: begin t <= modrm_wb; wb <= op1; t_next <= fetch; dir <= 0; end
929        endcase
930        // 88 MOV modrm
931        // 8D LEA
932        8'b1000_10xx,
933        8'b1000_1101: begin
934            t   <= modrm_wb;
935            wb  <= opcode[2] ? ea : op2;
936        end
937        // 8C MOV r, sreg
938        8'b1000_110x: begin
939            t <= modrm_wb;
940            case (modrm[5:3])
941            3'h0: wb <= es[15:0];
942            3'h1: wb <= cs[15:0];
943            3'h2: wb <= ss[15:0];
944            3'h3: wb <= ds[15:0];
945            3'h4: wb <= fs[15:0];
946            3'h5: wb <= gs[15:0];
947            default: t <= exception;
948            endcase
949        end
950        // 8E MOV sreg, rm
951        8'b1000_1110: begin
952            wb   <= op2;
953            t    <= modrm[5:3] == 3'b001 ? exception : loadseg;
954            regn <= modrm[5:3];
955        end
956        // 8F POP rm
957        8'b1000_1111: case (fn)
958            1: begin t <= fetch_modrm; fn <= 2; {dir, ignoreo} <= 2'b01; end
959            2: begin t <= modrm_wb; t_next <= fetch; end
960        endcase
961        // 90 XCHG ax, r16
962        8'b1001_0xxx: begin
963            t           <= modrm_wb;
964            wb          <= eax;
965            dir         <= 1'b1;
966            modrm[5:3]  <= regn;
967            if (opsize) eax <= reg32; else eax[15:0] <= reg32[15:0];
968        end
969        // 9A JMP|CALL FAR
970        8'b1001_1010,
971        8'b1110_1010: case (fn)
972            0: begin fn <= 1; opsize <= 1'b0; op1 <= wb; t <= fetch_imm16; end
973            1: begin
974                fn      <= 2;
975                t       <= loadseg;
976                t_next  <= opcode[4] ? exec : fetch; // CALL | JMP
977                regn    <= 3'h1; // CS:
978                if (opsize) eip <= op1; else eip[15:0] <= op1;
979                // Для CALL
980                op1 <= eip;
981                op2 <= cs[15:0];
982            end
983            2: begin fn <= 3; t <= push; wb <= op2; end
984            3: begin fn <= 0; t <= push; wb <= op1; t_next <= fetch; end
985        endcase
986        // 9D POPF
987        8'b1001_1101: begin
988            t <= fetch;
989            if (opsize)
990                eflags[17:0] <= {wb[17:6], 1'b0, wb[4], 1'b0, wb[2], 1'b1, wb[0]};
991            else
992                eflags[15:0] <= {wb[15:6], 1'b0, wb[4], 1'b0, wb[2], 1'b1, wb[0]};
993        end
994        // A0 MOV a,[m] || mov [m],a
995        8'b1010_00xx: case (fn)
996            // Либо запись в память, либо чтение
997            0: begin
998                fn      <= 1;
999                src     <= 1'b1;
1000                ea      <= wb;
1001                adsize  <= opsize;
1002                opsize  <= adsize;
1003                size    <= opcode[0];
1004                if (opcode[1]) begin
1005                    t       <= modrm_wb;
1006                    wb      <= eax;
1007                    dir     <= 1'b0;
1008                    modrm   <= 1'b0;
1009                end
1010            end
1011            // AL, [mem]
1012            1: begin
1013                fn <= 2;
1014                ea <= ea + 1;
1015                eax[7:0] <= in;
1016                if (opcode[0] == 1'b0) begin fn <= 0; src <= 1'b0; t <= fetch; end
1017            end
1018            2: begin
1019                fn <= 3;
1020                ea <= ea + 1;
1021                eax[15:8] <= in;
1022                if (opsize == 1'b0) begin fn <= 0; src <= 1'b0; t <= fetch; end
1023            end
1024            3: begin eax[23:16] <= in; fn <= 4; ea <= ea + 1; end
1025            4: begin eax[31:24] <= in; t <= fetch; src <= 1'b0; end
1026        endcase
1027        // A4 MOVSx
1028        8'b1010_010x: begin
1029            t       <= modrm_wb;
1030            t_next  <= fetch;
1031            segment <= es;
1032            ea      <= defsize ? edi : edi[15:0];
1033            wb      <= op1;
1034            modrm   <= 1'b0;
1035            esi     <= str_esi;
1036            edi     <= str_edi;
1037            if (rep[1]) begin ecx <= str_ecx; eip <= eip_rep; end
1038        end
1039        // A6 CMPSx
1040        8'b1010_011x: case (fn)
1041            0: begin // Читать ES:eDI
1042                fn      <= 1;
1043                fn2     <= 4;
1044                dir     <= 1'b1;
1045                segment <= es;
1046                ea      <= defsize ? edi : edi[15:0];
1047                t       <= fetch_modrm;
1048            end
1049            1: begin // Инкременты, запись в eflags
1050                t       <= fetch;
1051                src     <= 1'b0;
1052                eflags  <= alu_f;
1053                esi     <= str_esi;
1054                edi     <= str_edi;
1055                if (rep[1]) ecx <= str_ecx;
1056                if (rep[1] && rep[0] == alu_f[ZF]) eip <= eip_rep;
1057            end
1058        endcase
1059        // A8 TEST a,imm
1060        8'b1010_100x: case (fn)
1061            0: begin
1062                fn  <= 1;
1063                op1 <= eax;
1064                op2 <= opcode[0] ? wb : in;
1065                alu <= alu_and;
1066                if (opcode[0] == 1'b0) eip <= eip_next;
1067            end
1068            1: begin eflags <= alu_f; fn <= 1'b0; t <= fetch; end
1069        endcase
1070        // AC LODSx
1071        8'b1010_110x: begin
1072            t   <= fetch;
1073            src <= 1'b0;
1074            esi <= str_esi;
1075            // Загрузка в Acc
1076            if (size && opsize) eax         <= op1[31:0];
1077            else if (size)      eax[15:0]   <= op1[15:0];
1078            else                eax[7:0]    <= op1[ 7:0];
1079            if (rep[1]) begin ecx <= str_ecx; eip <= eip_rep; end
1080        end
1081        // AE SCASx
1082        8'b1010_111x: begin
1083            src     <= 1'b0;
1084            t       <= fetch;
1085            eflags  <= alu_f;
1086            edi     <= str_edi;
1087            if (rep[1]) ecx <= str_ecx;
1088            if (rep[1] && rep[0] == alu_f[ZF]) eip <= eip_rep;
1089        end
1090        // B0 MOV r, imm
1091        8'b1011_xxxx: begin
1092            t           <= modrm_wb;
1093            dir         <= 1'b1;
1094            size        <= opcode[3];
1095            modrm[5:3]  <= opcode[2:0];
1096            // 8 битное значение
1097            if (!opcode[3]) begin eip <= eip_next; wb <= in; end
1098        end
1099        // C6 MOV modrm, imm
1100        8'b1100_011x: case (fn)
1101            // Запросить считывание immediate
1102            0: begin
1103                fn  <= size ? 2 : 1;
1104                src <= 1'b0;
1105                if (size) t <= fetch_imm16;
1106            end
1107            1: begin fn  <= 2; wb <= in; eip <= eip_next; end
1108            2: begin src <= 1'b1; t <= modrm_wb; t_next <= fetch; end
1109        endcase
1110        // C0 SHIFT
1111        8'b1100_000x,
1112        8'b1101_00xx: begin
1113            t       <= shift;
1114            t_next  <= fetch;
1115            alu     <= modrm[5:3];
1116            src     <= 1'b1;
1117            if (opcode[4])
1118                op2 <= opcode[1] ? ecx[5:0] : 1'b1;
1119            else begin
1120                eip <= eip_next;
1121                op2 <= in;
1122            end
1123        end
1124        // C4 LES|LDS r,[m]
1125        8'b1100_010x: case (fn)
1126            0: begin fn <= 1; t <= modrm_wb; t_next <= exec; wb <= op2; end
1127            1: begin fn <= 2; src <= 1'b1; ea <= ea + (opsize ? 4 : 2); end
1128            2: begin wb[7:0] <= in; fn <= 3; ea <= ea + 1; end
1129            3: begin
1130                t           <= loadseg;
1131                t_next      <= fetch;
1132                regn        <= opcode[0] ? 3 : 0;
1133                wb[15:8]    <= in;
1134            end
1135        endcase
1136        // C2 RET; RET imm
1137        8'b1100_001x: case (fn)
1138            0: begin fn <= 1; t <= pop; op1 <= wb; end
1139            1: begin
1140                t <= fetch;
1141                if (defsize) eip <= wb; else eip[15:0] <= wb[15:0];
1142                if (stacksize) esp <= esp + op1; else esp[15:0] <= esp[15:0] + op1[15:0];
1143            end
1144        endcase
1145        // C8 ENTER imm,i8
1146        8'b1100_1000: case (fn)
1147            0: begin
1148                fn  <= in ? 1 : 2;
1149                op1 <= wb;
1150                op2 <= in;
1151                eip <= eip_next;
1152                t   <= push;
1153                wb  <= ebp;
1154                frametemp <= esp_dec;
1155            end
1156            1: begin
1157                t   <= push;
1158                wb  <= op2 >  1 ? ebp-2 : frametemp;
1159                ebp <= op2 >  1 ? ebp-2 : ebp;
1160                fn  <= op2 == 1 ? 2 : 1;
1161                op2 <= op2 - 1;
1162            end
1163            2: begin
1164                t       <= fetch;
1165                ebp     <= frametemp;
1166                esp     <= ebp - op1;
1167            end
1168        endcase
1169        // LEAVE
1170        8'b1100_1001: begin ebp <= wb; t <= fetch; end
1171        // CA RETF; RETF imm
1172        8'b1100_101x: case (fn)
1173            0: begin fn <= 1; t <= pop; op1 <= wb; end
1174            1: begin
1175                fn <= 2;
1176                t  <= pop;
1177                if (defsize) eip <= wb; else eip[15:0] <= wb[15:0];
1178            end
1179            2: begin
1180                t       <= loadseg;
1181                t_next  <= fetch;
1182                regn    <= 3'h1; // CS:
1183                if (stacksize) esp <= esp + op1; else esp[15:0] <= esp[15:0] + op1[15:0];
1184            end
1185        endcase
1186        // CD INT i8
1187        8'b1100_1101: begin t <= interrupt; eip <= eip_next; wb <= in; end
1188        // CF IRET
1189        8'b1100_1111: case (fn)
1190            1: begin fn <= 2; t <= pop; op1 <= wb; end
1191            2: begin fn <= 3; t <= pop; op2 <= wb; end
1192            3: begin
1193                t       <= loadseg;
1194                t_next  <= fetch;
1195                regn    <= 1;
1196                eflags  <= wb;
1197                wb      <= op2;
1198                if (defsize) eip <= op1; else eip[15:0] <= op1[15:0];
1199            end
1200        endcase
1201        // E4 IN eAX, dx/i8
1202        8'b1110_x10x: case (fn)
1203            0: begin
1204                fn       <= 1;
1205                eip      <= eip_next;
1206                port     <= in;
1207                port_clk <= 1'b0;
1208            end
1209            1: begin fn <= 2; port_clk <= 1; end
1210            2: begin fn <= 3; port_clk <= 0; end
1211            3: begin fn <= 1;
1212                case (op2[1:0])
1213                    0: eax[7:0]   <= port_i; // 8  bit
1214                    1: eax[15:8]  <= port_i; // 16 bit
1215                    2: eax[23:16] <= port_i;
1216                    3: eax[31:24] <= port_i; // 32 bit
1217                endcase
1218                port     <= port     + 1'b1;
1219                op2[1:0] <= op2[1:0] + 1'b1;
1220                if (op1[1:0] == op2[1:0]) t <= fetch;
1221            end
1222        endcase
1223        // E8 CALL a16
1224        8'b1110_1000: begin
1225            t       <= push;
1226            t_next  <= fetch;
1227            wb      <= eip;
1228            if (opsize) eip       <= eip       + wb;
1229            else        eip[15:0] <= eip[15:0] + wb[15:0];
1230        end
1231        // D4 AAM
1232        8'b1101_0100: case (fn)
1233            0: begin
1234                fn      <= 1;
1235                t       <= in ? divide : interrupt;
1236                t_next  <= exec;
1237                diva    <= {eax[7:0], 56'b0};
1238                divb    <= in;
1239                divcnt  <= 8;
1240                wb      <= 0;
1241                eip     <= eip_next;
1242            end
1243            1: begin
1244                src <= 1'b0;
1245                t   <= fetch;
1246                if (divb) begin
1247                    eax[15:0] <= {divres[7:0], divrem[7:0]};
1248                    eflags[ZF] <= eax[15:0] == 0;
1249                    eflags[SF] <= eax[15];
1250                    eflags[PF] <= ~^eax[15];
1251                end
1252            end
1253        endcase
1254        // D5 AAD
1255        8'b1101_0101: begin
1256            t           <= fetch;
1257            eip         <= eip_next;
1258            eax[15:0]   <= aam;
1259            eflags[ZF]  <= aam[15:0] == 0;
1260            eflags[SF]  <= aam[15];
1261            eflags[PF]  <= ~^aam[15];
1262        end
1263        // D7 XLATB
1264        8'b1101_0111: begin eax[7:0] <= in; src <= 1'b0; t <= fetch; end
1265        // E0 LOOP | JMP | J<ccc> short b8
1266        8'b1110_00xx,
1267        8'b1110_1011,
1268        8'b0111_xxxx: begin
1269            t   <= fetch;
1270            eip <= eip + 1'b1 + {{24{in[7]}}, in};
1271        end
1272        // E6 OUT dx/i8, eAX
1273        8'b1110_x11x: case (fn)
1274            0: begin
1275                fn       <= 1;
1276                eip      <= eip_next;
1277                port     <= in;
1278                port_clk <= 1'b0;
1279            end
1280            1: begin
1281                fn       <= 2;
1282                port_w   <= 1;
1283                port_clk <= 1;
1284                case (op2[1:0])
1285                    0: port_o <= eax[  7:0];
1286                    1: port_o <= eax[ 15:8];
1287                    2: port_o <= eax[23:16];
1288                    3: port_o <= eax[31:24];
1289                endcase
1290            end
1291            2: begin fn <= 3; port_w <= 0; port_clk <= 0; end
1292            3: begin fn <= 1;
1293                port     <= port     + 1'b1;
1294                op2[1:0] <= op2[1:0] + 1'b1;
1295                if (op1[1:0] == op2[1:0]) t <= fetch;
1296            end
1297        endcase
1298        // Групповые инструкции F6/F7
1299        8'b1111_011x: casex (modrm[5:3])
1300            // TEST rm, imm
1301            3'b00x: case (fn)
1302                // Сброс src, если был для imm8
1303                0: if (src) src <= 1'b0;
1304                else begin
1305                    fn  <= opcode[0] ? 1 : 2;
1306                    t   <= opcode[0] ? fetch_imm16 : exec;
1307                    op2 <= in;
1308                    alu <= alu_and;
1309                    src <= 1'b0;
1310                    if (opcode[0] == 1'b0) eip <= eip_next;
1311                end
1312                1: begin fn <= 2; op2 <= wb; end
1313                2: begin eflags <= alu_f; t <= fetch; end
1314            endcase
1315            // NOT rm
1316            3'b010: begin
1317                wb      <= ~op1;
1318                t       <= modrm_wb;
1319                t_next  <= fetch;
1320            end
1321            // NEG rm
1322            3'b011: case (fn)
1323                0: begin fn <= 1; op1 <= 0; op2 <= op1; alu <= alu_sub; end
1324                1: begin wb <= alu_r; eflags <= alu_f; t <= modrm_wb; t_next <= fetch; end
1325            endcase
1326            // MUL | IMUL
1327            3'b10x: case (fn)
1328                // Запрос
1329                0: begin
1330                    fn <= 1;
1331                    if (modrm[3]) begin
1332                        op1 <= size ? (opsize ? op1 : {{16{op1[15]}}, op1[15:0]}) : {{24{op1[7]}}, op1[7:0]};
1333                        op2 <= size ? (opsize ? eax : {{16{eax[15]}}, eax[15:0]}) : {{24{eax[7]}}, eax[7:0]};
1334                    end else begin
1335                        op2 <= size ? (opsize ? eax : eax[15:0]) : eax[7:0];
1336                    end
1337                end
1338                // Запись результата
1339                1: begin
1340                    src <= 1'b0;
1341                    t   <= fetch;
1342                    // CF,OF устанавливаются при переполнении
1343                    // ZF при нулевом результате
1344                    if (opsize && size) begin // 32 bit
1345                        eax         <= mult[31:0];
1346                        edx         <= mult[63:32];
1347                        eflags[ZF]  <= mult[63:0] == 64'b0;
1348                        eflags[CF]  <= edx[31:0]  != 32'b0;
1349                        eflags[OF]  <= edx[31:0]  != 32'b0;
1350                    end else if (size) begin // 16 bit
1351                        eax[15:0]   <= mult[15:0];
1352                        edx[15:0]   <= mult[31:16];
1353                        eflags[ZF]  <= mult[31:0] == 32'b0;
1354                        eflags[CF]  <= edx[15:0]  != 16'b0;
1355                        eflags[OF]  <= edx[15:0]  != 16'b0;
1356                    end else begin // 8 bit
1357                        eax[15:0]   <= mult[15:0];
1358                        eflags[ZF]  <= mult[15:0] == 16'b0;
1359                        eflags[CF]  <= eax[15:8]  != 8'b0;
1360                        eflags[OF]  <= eax[15:8]  != 8'b0;
1361                    end
1362                end
1363            endcase
1364            // DIV, IDIV
1365            3'b11x: case (fn)
1366                // Запрос
1367                0: begin
1368                    fn      <= 1;
1369                    t       <= divide;
1370                    diva    <= _diva;
1371                    divb    <= _divb;
1372                    divcnt  <= size ? (opsize ? 64 : 32) : 16;
1373                    divrem  <= 1'b0;
1374                    divres  <= 1'b0;
1375                    signa   <= 1'b0;
1376                    signb   <= 1'b0;
1377                    // IDIV
1378                    if (modrm[3]) begin
1379                        // Расстановка знаков
1380                        signa <= _diva[63];
1381                        signb <= _divb[alu_top];
1382                        // diva = |diva|
1383                        if (_diva[63]) begin
1384                            if (size && opsize) diva        <= -_diva;
1385                            else if (size)      diva[63:32] <= -_diva[63:32];
1386                            else                diva[63:48] <= -_diva[63:48];
1387                        end
1388                        // divb = |divb|
1389                        if (size && opsize && _divb[31]) divb[31:0] <= -_divb[31:0];
1390                        else if (size && _divb[15])      divb[15:0] <= -_divb[15:0];
1391                        else if (_divb[7])               divb[ 7:0] <= -_divb[ 7:0];
1392                    end
1393                end
1394                // Запись результата
1395                1: begin
1396                    t    <= fetch;
1397                    src  <= 1'b0;
1398                    wb   <= 1'b0;   // INT 0
1399                    if (size && opsize) begin
1400                        eax <= signd ? -divres[31:0] : divres[31:0];
1401                        edx <= divrem[31:0];
1402                        if (|divres[63:32] || divb[31:0] == 0) t <= interrupt;
1403                    end else if (size) begin
1404                        eax[15:0] <= signd ? -divres[15:0] : divres[15:0];
1405                        edx[15:0] <= divrem[15:0];
1406                        if (|divres[31:16] || divb[15:0] == 0) t <= interrupt;
1407                    end else begin
1408                        eax[ 7:0] <= signd ? -divres[7:0] : divres[7:0];
1409                        eax[15:8] <= divrem[7:0];
1410                        if (|divres[15:8] || divb[7:0] == 0) t <= interrupt;
1411                    end
1412                end
1413            endcase
1414        endcase
1415        // Групповые инструкции FE/FF
1416        8'b1111_111x: case (modrm[5:3])
1417            // INC|DEC rm
1418            3'b000,
1419            3'b001: case (fn)
1420                0: begin fn <= 1; op2 <= 1; alu <= modrm[3] ? 5 : 0; end
1421                1: begin wb <= alu_r; t <= modrm_wb; t_next <= fetch; eflags <= {alu_f[11:1], eflags[CF]}; end
1422            endcase
1423            // CALL | JMP rm
1424            3'b010,
1425            3'b100: if (size) begin
1426                t       <= modrm[4] ? push : fetch;
1427                t_next  <= fetch;
1428                src     <= modrm[4];
1429                wb      <= eip;
1430                if (opsize) eip <= op1; else eip[15:0] <= op1[15:0];
1431            end else t <= exception;
1432            // CALL | JMP far
1433            3'b011,
1434            3'b101: if (size) case (fn)
1435                0: begin
1436                    // Для PUSH (CALL)
1437                    op1 <= cs[15:0];
1438                    op2 <= eip;
1439                    // Переход по заданному адресу
1440                    if (defsize | opsize) eip <= op1; else eip[15:0] <= op1[15:0];
1441                    fn  <= 1;
1442                    ea  <= ea + (opsize? 4 : 2);
1443                end
1444                // Загрузка CS:
1445                1: begin fn <= 2; wb[7:0] <= in; ea <= ea + 1; end
1446                // Загрузка сегмента и либо выход к fetch, либо call far
1447                2: begin
1448                    t           <= loadseg;
1449                    t_next      <= modrm[5] ? fetch : exec;
1450                    fn          <= 3;
1451                    regn        <= 1;
1452                    wb[15:8]    <= in;
1453                end
1454                // PUSH для CALL FAR
1455                3: begin fn <= 4; t <= push; wb <= op1; end
1456                4: begin fn <= 5; t <= push; wb <= op2; t_next <= fetch; end
1457            endcase else t <= exception;
1458            // PUSH rm
1459            3'b110: if (size) begin
1460                t       <= push;
1461                t_next  <= fetch;
1462                wb      <= op1;
1463            end else t <= exception;
1464            // Undefined instruction
1465            3'b111: t <= exception;
1466        endcase
1467        // UNEXPECTED INSTRUCTION
1468        default: begin end
1469    endcase
1470endcase
1471end
1472// ---------------------------------------------------------------------
1473// Именованные константы
1474// ---------------------------------------------------------------------
1475localparam
1476    fetch           = 0,
1477    fetch_modrm     = 1,
1478    exec            = 2,
1479    modrm_wb        = 3,
1480    fetch_imm16     = 4,
1481    loadseg         = 5,
1482    exception       = 6,
1483    push            = 7,
1484    pop             = 8,
1485    shift           = 9,
1486    interrupt       = 10,
1487    divide          = 11,
1488    portin          = 12,
1489    portout         = 13;
1490localparam
1491    CF = 0, PF = 2, AF =  4, ZF =  6, SF = 7,
1492    TF = 8, IF = 9, DF = 10, OF = 11,
1493    IOPL0   = 12,
1494    IOPL1   = 13,
1495    NT      = 14,
1496    RF      = 16,
1497    VM      = 17;
1498localparam
1499    alu_add = 3'h0, alu_or  = 3'h1,
1500    alu_adc = 3'h2, alu_sbb = 3'h3,
1501    alu_and = 3'h4, alu_sub = 3'h5,
1502    alu_xor = 3'h6, alu_cmp = 3'h7;
1503// -----------------------------------------------------------------------------
1504// УПРАВЛЕНИЕ ПАМЯТЬЮ
1505// -----------------------------------------------------------------------------
1506// REAL-MODE
1507assign address =
1508    src ? {segment, 4'h0} + (adsize ? ea  :  ea[15:0]) :
1509          {     cs, 4'h0} + (adsize ? eip : eip[15:0]);
1510initial begin
1511    we       = 1'b0;
1512    out      = 1'b0;
1513    port     = 1'b0;
1514    port_clk = 1'b0;
1515    port_o   = 1'b0;
1516    port_w   = 1'b0;
1517end
1518// ---------------------------------------------------------------------
1519// РЕГИСТРЫ И СЕГМЕНТЫ
1520// ---------------------------------------------------------------------
1521// 8 x 32 битных регистров общего назначения
1522reg [31:0]  eax = 32'hDAEE_707F;
1523reg [31:0]  ebx = 32'h0177_AABC;
1524reg [31:0]  ecx = 32'h0000_0002;
1525reg [31:0]  edx = 32'h0000_0000;
1526reg [31:0]  esp = 32'h0000_FFFE;
1527reg [31:0]  ebp = 32'h0000_0000;
1528reg [31:0]  esi = 32'h0000_0000;
1529reg [31:0]  edi = 32'h0000_0004;
1530//                        VR  Nio ODIT SZ A  P1C
1531reg [17:0]  eflags  = 18'b00_0000_0000_0000_0010;
1532reg [31:0]  eip     = 32'h0000_0000;
1533reg [31:0]  eip_rep = 32'h0000_0000;
1534// Сегменты
1535reg [15:0]  es  = 80'hF000;
1536reg [15:0]  cs  = 80'hF000;
1537reg [15:0]  ss  = 80'h0000;
1538reg [15:0]  ds  = 80'hF800;
1539reg [15:0]  fs  = 80'h0000;
1540reg [15:0]  gs  = 80'h0000;
1541// -----------------------------------------------------------------------------
1542reg [3:0]   t               = 1'b0;     // Фаза исполнения
1543reg [3:0]   t_next          = 1'b0;     // Переход к фазе после исполнения процедуры
1544reg [4:0]   fn              = 1'b0;     // Фаза exec
1545reg [3:0]   fn2             = 1'b0;     // Фаза процедур
1546reg [8:0]   opcode          = 1'b0;     // Сохраненный опкод
1547reg [2:0]   psize           = 1'b0;     // Количество префиксов от 0 до 7
1548reg [7:0]   modrm           = 1'b0;     // Сохраненный modrm
1549reg         src             = 1'b0;     // Источник адреса segment:ea; cs:eip
1550reg         src_next        = 1'b1;     // src после fetch_modrm
1551reg         trace_ff        = 1'b0;     // Trace вызывается после инструкции
1552reg [79:0]  segment         = 1'b0;     // Рабочий сегмент
1553reg [31:0]  ea              = 1'b0;     // Эффективный адрес
1554reg         prot            = 1'b0;     // =1 Защищенный режим
1555reg         adsize          = 1'b0;     // =1 32х битная адресация
1556reg         opsize          = 1'b0;     // =1 32х битный операнд
1557reg         override        = 1'b0;     // =1 Сегмент префиксирован
1558reg         ignoreo         = 1'b0;     // Игнорировать чтение из памяти modrm
1559reg [1:0]   rep             = 1'b0;     // Режим REPNZ/REPZ
1560reg [2:0]   alu             = 3'h0;     // Режим АЛУ
1561reg         size            = 1'b0;     // =1 16/32 битный операнд
1562reg         dir             = 1'b0;     // =0 rm,r; =1 r,rm modrm
1563reg [ 2:0]  regn            = 3'b0;     // reg32 = register[regn]
1564reg [31:0]  op1             = 32'h0;    // Левый операнд
1565reg [31:0]  op2             = 32'h0;    // Правый операнд
1566reg [31:0]  wb              = 32'h0;    // Значение для записи
1567reg [31:0]  frametemp       = 32'h0;    // ENTER
1568reg         __opext         = 1'b0;
1569reg         __adsize        = 1'b0;
1570reg         __opsize        = 1'b0;
1571reg         __override      = 1'b0;
1572reg [1:0]   __rep           = 2'b00;
1573reg [15:0]  __segment       = 16'h0000;
1574// -----------------------------------------------------------------------------
1575// Модуль деления op1 / op2 -> divres | divrem
1576// -----------------------------------------------------------------------------
1577reg [63:0]  diva    = 1'b0;
1578reg [63:0]  divb    = 1'b0;
1579reg [ 6:0]  divcnt  = 1'b0;
1580reg [63:0]  divrem  = 1'b0;
1581reg [63:0]  divres  = 1'b0;
1582reg         signa   = 1'b0;
1583reg         signb   = 1'b0;
1584// -----------------------------------------------------------------------------
1585wire        signd   = signa ^ signb;
1586wire [63:0] mult    = op1 * op2;
1587wire [15:0] aam     = eax[15:8]*in + eax[7:0];
1588wire [63:0] _diva   = size ? (opsize ? {edx, eax} : {edx[15:0], eax[15:0], 32'h0}) : {eax[15:0], 48'h0};
1589wire [63:0] _divb   = size ? (opsize ? op1 : op1[15:0]) : op1[7:0];
1590wire [63:0] _divr   = {divrem, diva[63]};
1591// -----------------------------------------------------------------------------
1592// Вычисление следующего EIP в зависимости от 54-го бита
1593// По умолчанию процессор сразу же переходит в 32х битный режим работы
1594// -----------------------------------------------------------------------------
1595wire        defsize     = 1'b1;
1596wire        stacksize   = 1'b1;
1597wire [15:0] sp_dec      = esp[15:0] - (opsize ? 3'h4 : 2'h2);
1598wire [15:0] sp_inc      = esp[15:0] + (opsize ? 3'h4 : 2'h2);
1599wire [15:0] ipnext1     = eip[15:0] + 1'b1;
1600wire [15:0] ipnext2     = eip[15:0] + 2'h2;
1601wire [15:0] ipnext3     = eip[15:0] + 2'h3;
1602wire [15:0] ipnext5     = eip[15:0] + 3'h5;
1603// eip / esp
1604wire [31:0] eip_next    = defsize ? eip + 1'b1 : {eip[31:16], ipnext1};
1605wire [31:0] eip_next2   = defsize ? eip + 2'h2 : {eip[31:16], ipnext2};
1606wire [31:0] eip_next3   = defsize ? eip + 2'h3 : {eip[31:16], ipnext3};
1607wire [31:0] eip_next5   = defsize ? eip + 3'h5 : {eip[31:16], ipnext5};
1608wire [31:0] esp_dec     = defsize ? esp - 4'h4 : {esp[31:16], sp_dec};
1609wire [31:0] esp_inc     = defsize ? esp + 4'h4 : {esp[31:16], sp_inc};
1610// ---------------------------------------------------------------------
1611// Строковые инструкции, инкременты и декременты
1612// ---------------------------------------------------------------------
1613// Приращение +/- 1,2,4;
1614wire [ 2:0] str_inc     = t == fetch ?
1615    ((    in[0] ? (__opsize ? 3'h4 : 3'h2) : 3'h1)) :
1616    ((opcode[0] ? (  opsize ? 3'h4 : 3'h2) : 3'h1));
1617wire [31:0] str_ncx     = ecx - 1'b1;
1618wire [31:0] str_zcx     = defsize ? ecx : ecx[15:0];
1619wire [31:0] str_nsi     = eflags[DF] ? esi - str_inc : esi + str_inc;
1620wire [31:0] str_ndi     = eflags[DF] ? edi - str_inc : edi + str_inc;
1621// Следующий ESI:EDI:ECX
1622wire [31:0] str_esi     = defsize ? str_nsi : {esi[31:16], str_nsi[15:0]};
1623wire [31:0] str_edi     = defsize ? str_ndi : {edi[31:16], str_ndi[15:0]};
1624wire [31:0] str_ecx     = defsize ? str_ncx : {ecx[31:16], str_ncx[15:0]};
1625// ---------------------------------------------------------------------
1626// Получение регистров
1627// ---------------------------------------------------------------------
1628// Вычисление базы SIB
1629wire [31:0] sib_base =
1630    in[2:0] == 3'b000 ? eax :
1631    in[2:0] == 3'b001 ? ecx :
1632    in[2:0] == 3'b010 ? edx :
1633    in[2:0] == 3'b011 ? ebx :
1634    in[2:0] == 3'b100 ? esp :
1635    in[2:0] == 3'b101 ? (^modrm[7:6] ? ebp : 1'b0) :
1636    in[2:0] == 3'b110 ? esi :
1637                        edi;
1638// Извлечение регистра
1639wire [31:0] reg32 =
1640    regn == 3'd0 ? (opsize & size ? eax : (size ? eax[15:0] : eax[ 7:0])) :
1641    regn == 3'd1 ? (opsize & size ? ecx : (size ? ecx[15:0] : ecx[ 7:0])) :
1642    regn == 3'd2 ? (opsize & size ? edx : (size ? edx[15:0] : edx[ 7:0])) :
1643    regn == 3'd3 ? (opsize & size ? ebx : (size ? ebx[15:0] : ebx[ 7:0])) :
1644    regn == 3'd4 ? (opsize & size ? esp : (size ? esp[15:0] : eax[15:8])) :
1645    regn == 3'd5 ? (opsize & size ? ebp : (size ? ebp[15:0] : ecx[15:8])) :
1646    regn == 3'd6 ? (opsize & size ? esi : (size ? esi[15:0] : edx[15:8])) :
1647                   (opsize & size ? edi : (size ? edi[15:0] : ebx[15:8]));
1648// ---------------------------------------------------------------------
1649// Условные переходы
1650// ---------------------------------------------------------------------
1651wire [7:0] branches = {
1652    /*7*/ (eflags[SF] ^ eflags[OF]) | eflags[ZF],
1653    /*6*/ (eflags[SF] ^ eflags[OF]),
1654    /*5*/  eflags[PF],
1655    /*4*/  eflags[SF],
1656    /*3*/  eflags[CF] | eflags[ZF],
1657    /*2*/  eflags[ZF],
1658    /*1*/  eflags[CF],
1659    /*0*/  eflags[OF]
1660};
1661// ---------------------------------------------------------------------
1662// Арифметико-логика, базовая
1663// ---------------------------------------------------------------------
1664wire [32:0] alu_r =
1665    alu == alu_add ? op1 + op2 :
1666    alu == alu_or  ? op1 | op2 :
1667    alu == alu_adc ? op1 + op2 + eflags[CF] :
1668    alu == alu_sbb ? op1 - op2 - eflags[CF] :
1669    alu == alu_and ? op1 & op2:
1670    alu == alu_xor ? op1 ^ op2:
1671                     op1 - op2; // SUB, CMP
1672wire [ 4:0] alu_top = size ? (opsize ? 31 : 15) : 7;
1673wire [ 5:0] alu_up  = alu_top + 1'b1;
1674wire is_add  = alu == alu_add || alu == alu_adc;
1675wire is_lgc  = alu == alu_xor || alu == alu_and || alu == alu_or;
1676wire alu_cf  = alu_r[alu_up];
1677wire alu_af  = op1[4] ^ op2[4] ^ alu_r[4];
1678wire alu_sf  = alu_r[alu_top];
1679wire alu_zf  = size ? (opsize ? ~|alu_r[31:0] : ~|alu_r[15:0]) : ~|alu_r[7:0];
1680wire alu_pf  = ~^alu_r[7:0];
1681wire alu_of  = (op1[alu_top] ^ op2[alu_top] ^ is_add) & (op1[alu_top] ^ alu_r[alu_top]);
1682wire [17:0] alu_f = {
1683    /* ..  */ eflags[17:12],
1684    /* OF  */ alu_of & ~is_lgc,
1685    /* DIT */ eflags[10:8],
1686    /* SF  */ alu_sf,
1687    /* ZF  */ alu_zf,
1688    /* 5   */ 1'b0,
1689    /* AF  */ alu_af & ~is_lgc,
1690    /* 3   */ 1'b0,
1691    /* PF  */ alu_pf,
1692    /* 1   */ 1'b1,
1693    /* CF  */ alu_cf & ~is_lgc
1694};
1695// ---------------------------------------------------------------------
1696// Десятичная коррекция DAA, DAS, AAA, AAS
1697// ---------------------------------------------------------------------
1698reg         daa_a;
1699reg         daa_c;
1700reg         daa_x;
1701reg [8:0]   daa_i;
1702reg [7:0]   daa_h;
1703reg [15:0]  daa_r;
1704reg [11:0]  eflags_o;
1705reg [11:0]  eflags_d;
1706always @* begin
1707    daa_r    = eax[15:0];
1708    eflags_d = eflags;
1709    case (in[4:3])
1710        // DAA, DAS
1711        0, 1: begin
1712            daa_c = eflags[CF];
1713            daa_a = eflags[AF];
1714            daa_i = eax[7:0];
1715            // Младший ниббл
1716            if (eax[3:0] > 4'h9 || eflags[AF]) begin
1717                daa_i = in[3] ? eax[7:0] - 3'h6 : eax[7:0] + 3'h6;
1718                daa_c = daa_i[8];
1719                daa_a = 1'b1;
1720            end
1721            daa_r = daa_i[7:0];
1722            daa_x = daa_c;
1723            // Старший ниббл
1724            if (daa_c || daa_i[7:0] > 8'h9F) begin
1725                daa_r = in[3] ? daa_i[7:0] - 8'h60 : daa_i[7:0] + 8'h60;
1726                daa_x = 1'b1;
1727            end
1728            eflags_d[SF] =   daa_r[7];   // SF
1729            eflags_d[ZF] = ~|daa_r[7:0]; // ZF
1730            eflags_d[AF] =   daa_a;      // AF
1731            eflags_d[PF] = ~^daa_r[7:0]; // PF
1732            eflags_d[OF] =   daa_x;      // CF
1733        end
1734        // AAA, AAS
1735        2, 3: begin
1736            daa_i = eax[ 7:0];
1737            daa_r = eax[15:0];
1738            if (eflags[4] || eax[3:0] > 4'h9) begin
1739                daa_i = alu[0] ? eax[ 7:0] - 3'h6 : eax[ 7:0] + 3'h6;
1740                daa_h = alu[0] ? eax[15:8] - 1'b1 : eax[15:8] + 1'b1;
1741                daa_r = {daa_h, 4'h0, daa_i[3:0]};
1742                eflags_d[AF] = 1'b1;
1743                eflags_d[CF] = 1'b1;
1744            end
1745            else begin
1746                eflags_d[AF] = 1'b0;
1747                eflags_d[CF] = 1'b0;
1748            end
1749        end
1750    endcase
1751end
1752endmodule