§ Исходный код ядра

1/**
2 * Небольшой процессор с ограниченным набором инструкции
3 */
4
5module c8086
6(
7    // Основной контур для процессора
8    input               clock,
9    input               ce,
10    input               reset_n,
11    output       [19:0] address,
12    input        [ 7:0] in,             // in = ram[address]
13    output  reg  [ 7:0] out,
14    output  reg         we,
15    output              m0,             // M0-считывание инструкции
16
17    // Порты ввода-вывода
18    output  reg  [15:0] port_a,
19    output  reg         port_w,
20    output  reg         port_r,
21    input        [ 7:0] port_i,
22    output  reg  [ 7:0] port_o,
23
24    // PIC: Программируемый контроллер прерываний
25    input               irq,            // Срабатывает на posedge
26    input        [ 7:0] irq_in          // Номер IRQ (0..255)
27);
28
29// Выбор текущего адреса, segment_id[2] = 1 означает прерывание
30assign address = cp ? {segment, 4'h0} + ea : {cs, 4'h0} + ip;
31assign m0 = (fn == START);
32
33localparam
34
35    ALU_ROL = 0, ALU_ROR = 1,
36    ALU_RCL = 2, ALU_RCR = 3,
37    ALU_SHL = 4, ALU_SHR = 5,
38    ALU_SAL = 6, ALU_SAR = 7;
39
40localparam
41    ALU_ADD = 0, ALU_OR  = 1, ALU_ADC = 2, ALU_SBB = 3,
42    ALU_AND = 4, ALU_SUB = 5, ALU_XOR = 6, ALU_CMP = 7;
43
44localparam
45    CF = 0, PF = 2, AF = 4, ZF = 6, SF = 7, TF = 8, IF = 9, DF = 10, OF = 11;
46
47localparam
48    REG_AX = 0, REG_CX = 1, REG_DX = 2, REG_BX = 3,
49    REG_SP = 4, REG_BP = 5, REG_SI = 6, REG_DI = 7;
50
51localparam
52    START = 0, LOAD = 1, MODRM = 2, INSTR = 3,  INTR = 4,
53    WBACK = 5, PUSH = 6, POP = 7,   REPF = 8,   UNDEF = 9;
54
55// -----------------------------------------------------------------------------
56wire [15:0] signex = {{8{in[7]}}, in};
57wire [15:0] rin =
58    in[2:0] == REG_AX ? ax : in[2:0] == REG_CX ? cx :
59    in[2:0] == REG_DX ? dx : in[2:0] == REG_BX ? bx :
60    in[2:0] == REG_SP ? sp : in[2:0] == REG_BP ? bp :
61    in[2:0] == REG_SI ? si : di;
62
63// Вычисление условий
64wire [7:0] branches =
65{
66    (flags[SF] ^ flags[OF]) | flags[ZF], // 7: (ZF=1) OR (SF!=OF)
67    (flags[SF] ^ flags[OF]),             // 6: SF!=OF
68     flags[PF],
69     flags[SF],
70     flags[CF] | flags[OF],              // 3: CF != OF
71     flags[ZF],
72     flags[CF],
73     flags[OF]
74};
75
76// Управляющие регистры и регистры общего назначения
77// -----------------------------------------------------------------------------
78reg         cp, size, dir, cpen, over, rep_ft, iack, trace_ff;
79reg [15:0]  ax, bx, cx, dx, sp, bp, si, di;
80reg [15:0]  es, cs, ss, ds;
81reg [ 1:0]  rep;
82reg [ 3:0]  fn, fnext, s1, s2;
83reg [ 7:0]  opcode, modrm;
84reg [15:0]  segment, ea, wb, ip, ip_start;
85reg [ 7:0]  intr;
86reg [ 2:0]  alu;
87reg [15:0]  op1, op2;
88reg [11:0]  flags;
89
90// Исполнительный блок
91// -----------------------------------------------------------------------------
92always @(posedge clock)
93if (reset_n == 1'b0) begin
94
95    fn      <= START;
96    cs      <= 16'hF000;
97    es      <= 16'h0000;
98    ds      <= 16'h0000;
99    ss      <= 16'h0000;
100    sp      <= 16'h0000;
101    ip      <= 16'hFFF0;
102    iack    <= 1'b0;
103    //             ODIT SZ A  P C
104    flags   <= 12'b0010_0000_0010;
105
106end
107else if (ce) begin
108
109    port_r <= 0; // Строб чтения из порта
110    port_w <= 0; // Строб записи в порт
111
112    case (fn)
113
114        // Сброс перед запуском инструкции
115        // -------------------------------------------------------------
116        START: begin
117
118            fn          <= LOAD;
119            fnext       <= START;       // Возврат по умолчанию
120            s1          <= 0;
121            s2          <= 0;
122            cp          <= 0;           // address = CS:IP
123            cpen        <= 1;           // Считывать из памяти modrm rm-часть
124            modrm       <= 0;
125            segment     <= ds;          // Значение сегмента по умолчанию DS:
126            over        <= 1'b0;        // Наличие сегментного префикса
127            rep         <= 2'b0;        // Нет префикса REP:
128            ea          <= 0;           // Эффективный адрес
129            we          <= 0;           // Разрешение записи
130            rep_ft      <= 0;           // =0 REP, =1 REPZ|NZ
131            wb          <= 0;           // Данные на запись (modrm | reg)
132            ip_start    <= ip;          // Для REP:
133
134            // IRQ прерывание вызывается, если счетчик изменился (iack != irq_signal) и IF=1
135            if ((iack ^ irq) && flags[IF]) begin
136
137                fn    <= irq ? INTR : LOAD;
138                intr  <= irq_in;
139                iack  <= irq;
140
141            end
142            // TF=1 (Trace Flag включен) и IF=1
143            else if (flags[IF] && flags[TF] && trace_ff) begin
144
145                fn   <= INTR;
146                intr <= 1;
147
148            end
149
150            // FlipFlop: сначала выполнится инструкция, потом вызывается INT 1
151            if (flags[IF] && flags[TF]) trace_ff <= ~trace_ff;
152
153        end
154
155        // Дешифратор опкода
156        // -------------------------------------------------------------
157        LOAD: begin
158
159            // Параметры по умолчанию
160            fn      <= LOAD;
161            ip      <= ip + 1;
162            size    <= in[0];
163            dir     <= in[1];
164            alu     <= in[5:3];
165            opcode  <= in;
166
167            // Поиск опкода по маске
168            casex (in)
169
170                 // Сегментные префиксы
171                8'b00100110: begin segment <= es; over <= 1; end
172                8'b00101110: begin segment <= cs; over <= 1; end
173                8'b00110110: begin segment <= ss; over <= 1; end
174                8'b00111110: begin segment <= ds; over <= 1; end
175                // REPNZ, REPZ
176                8'b1111001x: begin rep <= in[1:0]; end
177                // FS, GS, OpSize, AdSize, Ext
178                8'b00001111,
179                8'b0110010x,
180                8'b0110011x,
181                // NOP, LOCK: FWAIT
182                8'b10010000,
183                8'b10011011,
184                8'b11110000: begin /* LOAD */ end
185                // ALU rm | ALU a,imm
186                8'b00xxx0xx: begin fn <= MODRM; end
187                8'b00xxx10x: begin fn <= INSTR; end
188                // MOV rm, i | LEA r, m
189                8'b1100011x,
190                8'b10001101: begin fn <= MODRM; cpen <= 0; end
191                // INC | DEC r
192                8'b0100xxxx: begin
193
194                    fn      <= INSTR;
195                    alu     <= in[3] ? ALU_SUB : ALU_ADD;
196                    op1     <= rin;
197                    op2     <= 1;
198                    size    <= 1;
199
200                end
201                // XCHG r, a
202                8'b10010xxx: begin
203
204                    fn          <= WBACK;
205                    ax          <= rin;
206                    wb          <= ax;
207                    dir         <= 1;
208                    size        <= 1;
209                    modrm[5:3]  <= in[2:0];
210
211                end
212                // PUSH r
213                8'b01010xxx: begin fn <= PUSH; wb <= rin; end
214                // POP r,s,etc.
215                8'b01011xxx, // POP r
216                8'b000xx111, // POP s
217                8'b10011101, // POPF
218                8'b1100101x, // RETF [i]
219                8'b1x001111, // POP rm; IRET; RET [i]
220                8'b1100001x: begin fn <= POP; fnext <= INSTR; end
221                // PUSH s
222                8'b00000110: begin fn <= PUSH; wb <= es; end
223                8'b00001110: begin fn <= PUSH; wb <= cs; end
224                8'b00010110: begin fn <= PUSH; wb <= ss; end
225                8'b00011110: begin fn <= PUSH; wb <= ds; end
226                // PUSHF
227                8'b10011100: begin fn <= PUSH; wb <= flags; end
228                // CLx/STx, CMC
229                8'b1111100x: begin fn <= START; flags[CF] <= in[0]; end
230                8'b1111101x: begin fn <= START; flags[IF] <= in[0]; end
231                8'b1111110x: begin fn <= START; flags[DF] <= in[0]; end
232                8'b11110101: begin fn <= START; flags[CF] <= ~flags[CF]; end
233                // SAHF, LAHF
234                8'b10011110: begin fn <= START; flags     <= ax[15:8]; end
235                8'b10011111: begin fn <= START; ax[15:8]  <= flags[7:0] | 2; end
236                // SALC
237                8'b11010110: begin fn <= START; ax[ 7:0]  <= {8{flags[CF]}}; end
238                // HALT
239                8'b11110100: begin fn <= START; ip <= ip; end
240                // Grp#1 ALU; XCHG rm, r
241                8'b100000xx,
242                8'b1000011x: begin fn <= MODRM; dir <= 0; end
243                // TEST rm | TEST a,i
244                8'b1000010x: begin fn <= MODRM; alu <= ALU_AND; end
245                // CBW, CWD
246                8'b10011000: begin fn <= START; ax[15:8] <= {8{ax[7]}}; end
247                8'b10011001: begin fn <= START; dx       <= {16{ax[15]}}; end
248                // MOV s,rm
249                8'b10001110: begin fn <= MODRM; size <= 1; end
250                // XLATB
251                8'b11010111: begin fn <= INSTR; ea <= bx + ax[7:0]; cp <= 1; end
252                // LES|LDS r,m
253                8'b1100010x: begin fn <= MODRM; size <= 1; dir <= 1; end
254                // INT 1,3; INTO
255                8'b11110001: begin intr <= 1; fn <= INTR; end
256                8'b11001100: begin intr <= 3; fn <= INTR; end
257                8'b11001110: begin intr <= 4; fn <= flags[OF] ? INTR : START; end
258                // Grp#4|5; Сдвиги
259                8'b1111x11x,
260                8'b1100000x,
261                8'b110100xx: begin fn <= MODRM; dir <= 0; end
262                // Jccc; JCXZ
263                8'b0111xxxx,
264                8'b11100011: begin
265
266                    if ((branches[ in[3:1] ] == in[0] && !in[7]) || (in[7] && cx))
267                         begin fn <= START; ip <= ip + 2; end
268                    else begin fn <= INSTR; end
269
270                end
271                // LOOP[NZ|Z]
272                8'b111000xx: begin
273
274                    // Если бит 1 равен 1, то ZF=bit[0] не имеет значения
275                    if ((cx != 1) && (in[1] || flags[ZF] == in[0]))
276                         begin fn <= INSTR; end
277                    else begin fn <= START; ip <= ip + 2; end
278
279                    cx <= cx - 1;
280
281                end
282                // Определить наличие байта ModRM для опкода
283                default: casex (in)
284
285                    8'b1000xxxx, 8'b1100000x, 8'b110001xx, 8'b011010x1,
286                    8'b110100xx, 8'b11011xxx, 8'b1111x11x, 8'b0110001x:
287                             fn <= MODRM;
288                    default: fn <= INSTR;
289
290                endcase
291
292            endcase
293
294        end
295
296        // Считывание MODRM
297        // -------------------------------------------------------------
298        MODRM: case (s1)
299
300            // Считывание адреса или регистров
301            0: begin
302
303                modrm <= in;
304                ip    <= ip + 1;
305
306                // Первый операнд (dir=1 будет выбрана reg-часть)
307                case (dir ? in[5:3] : in[2:0])
308                REG_AX: op1 <= size ? ax : ax[ 7:0];
309                REG_CX: op1 <= size ? cx : cx[ 7:0];
310                REG_DX: op1 <= size ? dx : dx[ 7:0];
311                REG_BX: op1 <= size ? bx : bx[ 7:0];
312                REG_SP: op1 <= size ? sp : ax[15:8];
313                REG_BP: op1 <= size ? bp : cx[15:8];
314                REG_SI: op1 <= size ? si : dx[15:8];
315                REG_DI: op1 <= size ? di : bx[15:8];
316                endcase
317
318                // Второй операнд (dir=1 будет выбрана rm-часть)
319                case (dir ? in[2:0] : in[5:3])
320                REG_AX: op2 <= size ? ax : ax[ 7:0];
321                REG_CX: op2 <= size ? cx : cx[ 7:0];
322                REG_DX: op2 <= size ? dx : dx[ 7:0];
323                REG_BX: op2 <= size ? bx : bx[ 7:0];
324                REG_SP: op2 <= size ? sp : ax[15:8];
325                REG_BP: op2 <= size ? bp : cx[15:8];
326                REG_SI: op2 <= size ? si : dx[15:8];
327                REG_DI: op2 <= size ? di : bx[15:8];
328                endcase
329
330                // Подготовка эффективного адреса
331                case (in[2:0])
332                3'b000: ea <= bx + si;
333                3'b001: ea <= bx + di;
334                3'b010: ea <= bp + si;
335                3'b011: ea <= bp + di;
336                3'b100: ea <= si;
337                3'b101: ea <= di;
338                3'b110: ea <= in[7:6] == 2'b00 ? 0 : bp; // disp16 | bp
339                3'b111: ea <= bx;
340                endcase
341
342                // Выбор сегмента SS: для BP
343                if (!over)
344                casex (in)
345                8'bxx_xxx_01x, // [bp+si|di]
346                8'b01_xxx_110, // [bp+d8|d16]
347                8'b10_xxx_110: segment <= ss;
348                endcase
349
350                // Переход сразу к исполнению инструкции: операнды уже получены
351                casex (in)
352                8'b00_xxx_110: begin s1 <= 2; end // +disp16
353                // Читать операнд из памяти
354                8'b00_xxx_xxx: begin s1 <= cpen ? 4 : 0; cp <= cpen; if (!cpen) fn <= INSTR; end
355                8'b01_xxx_xxx: begin s1 <= 1; end // +disp8
356                8'b10_xxx_xxx: begin s1 <= 2; end // +disp16
357                8'b11_xxx_xxx: begin s1 <= 0; fn <= INSTR; end // Перейти к исполнению
358                default:       begin s1 <= 1; end
359                endcase
360
361            end
362
363            // Чтение 8 битного signed disp
364            1: begin
365
366                s1 <= 4;
367                ip <= ip + 1;
368                ea <= ea + signex;
369                cp <= cpen;
370
371                if (!cpen) begin s1 <= 0; fn <= INSTR; end
372
373            end
374
375            // Чтение 16 битного unsigned disp16
376            2: begin s1 <= 3; ip <= ip + 1; ea <= ea + in; end
377            3: begin
378
379                s1 <= 4;
380                ip <= ip + 1;
381                cp <= cpen;
382                ea <= ea + {in, 8'h00};
383
384                if (!cpen) begin s1 <= 0; fn <= INSTR; end
385
386            end
387
388            // Чтение операнда из памяти 8 bit
389            4: begin
390
391                if (dir) op2 <= in; else op1 <= in;
392                if (size)
393                     begin s1 <= 5; ea <= ea + 1; end
394                else begin s1 <= 0; fn <= INSTR;  end
395
396            end
397
398            // Операнд 16 bit
399            5: begin
400
401                if (dir) op2[15:8] <= in; else op1[15:8] <= in;
402
403                s1 <= 0;
404                fn <= INSTR;
405                ea <= ea - 1;
406
407            end
408
409        endcase
410
411        // Исполнение инструкции
412        // -------------------------------------------------------------
413        INSTR: casex (opcode)
414
415            8'b00xxx0xx: begin              // <alu> rm
416
417                wb    <= alu_r;
418                flags <= alu_f;
419
420                fn <= (alu != ALU_CMP) ? WBACK : START;
421
422            end
423            8'b00xxx10x: case (s2)          // <alu> a, imm
424
425                // Инициализация
426                0: begin
427
428                    op1 <= size ? ax : ax[7:0];
429                    op2 <= in;
430                    s2  <= size ? 1 : 2;
431                    ip  <= ip + 1;
432
433                end
434
435                // Считывание старшего байта
436                1: begin s2 <= 2; op2[15:8] <= in; ip <= ip + 1; end
437
438                // Запись в регистр и выход из процедуры
439                2: begin
440
441                    fn      <= START;
442                    flags   <= alu_f;
443
444                    if (alu != ALU_CMP) begin
445
446                        if (size) ax      <= alu_r;
447                        else      ax[7:0] <= alu_r[7:0];
448
449                    end
450
451                end
452
453            endcase
454            8'b1011xxxx: case (s2)          // MOV r, i
455
456                // 8 bit
457                0: begin
458
459                    s2          <= 1;
460                    dir         <= 1;
461                    size        <= opcode[3];
462                    modrm[5:3]  <= opcode[2:0];
463                    wb          <= in;
464                    ip          <= ip + 1;
465
466                    if (opcode[3] == 0) fn <= WBACK;
467
468                end
469
470                // 16 bit
471                1: begin
472
473                    wb[15:8] <= in;
474
475                    fn <= WBACK;
476                    ip <= ip + 1;
477
478                end
479
480            endcase
481            8'b100010xx: begin              // MOV rm
482
483                wb <= op2;
484                fn <= WBACK;
485
486            end
487            8'b1100011x: case (s2)          // MOV rm, i
488
489                // 8 bit
490                0: begin
491
492                    s2  <= 1; wb <= in; dir <= 0; ip  <= ip + 1;
493                    if (size == 0) begin fn <= WBACK; cp <= 1; end
494
495                end
496
497                // 16 bit
498                1: begin fn <= WBACK; cp <= 1; ip <= ip + 1; wb[15:8] <= in; end
499
500            endcase
501            8'b10001101: begin              // LEA r16, m
502
503                wb   <= ea;
504                size <= 1;
505                dir  <= 1;
506                fn   <= WBACK;
507
508            end
509            8'b0100xxxx: begin              // INC | DEC r16
510
511                fn          <= WBACK;
512                modrm[5:3]  <= opcode[2:0];
513                dir         <= 1;
514                wb          <= alu_r;
515                flags       <= {alu_f[11:1], flags[CF]};
516
517            end
518            8'b01011xxx: begin              // POP r
519
520                fn   <= WBACK;
521                size <= 1;
522                dir  <= 1;
523                modrm[5:3] <= opcode[2:0];
524
525            end
526            8'b000xx111: begin              // POP s
527
528                fn <= START;
529
530                case (opcode[4:3])
531                2'b00: es <= wb;
532                2'b01: cs <= wb;
533                2'b10: ss <= wb;
534                2'b11: ds <= wb;
535                endcase
536
537            end
538            8'b100000xx: case (s2)          // <alu> imm
539
540                // Считывание imm и номера кода операции
541                0: begin s2 <= 1; alu <= modrm[5:3]; cpen <= cp; cp <= 0; end
542                1: begin s2 <= 2; op2 <= in; ip <= ip + 1; end
543                2: begin s2 <= 3;
544
545                    case (opcode[1:0])
546                    2'b01: begin op2[15:8] <= in; ip <= ip + 1; end // imm16
547                    2'b11: begin op2[15:8] <= {8{op2[7]}}; end      // sign8
548                    endcase
549
550                end
551                // Запись
552                3: begin
553
554                    cp      <= cpen;
555                    wb      <= alu_r;
556                    flags   <= alu_f;
557                    fn      <= (alu != ALU_CMP) ? WBACK : START;
558
559                end
560
561            endcase
562            8'b101000xx: case (s2)          // MOV a,[m] | [m],a
563
564                // Прочесть адрес
565                0: begin ea[ 7:0] <= in; ip <= ip + 1; s2 <= 1; end
566                1: begin ea[15:8] <= in; ip <= ip + 1; cp <= 1; s2 <= dir ? 2 : 5; end
567
568                // Запись A в память
569                2: begin we <= 1; out <= ax[ 7:0]; s2 <= size ? 3 : 4; end
570                3: begin we <= 1; out <= ax[15:8]; s2 <= 4; ea <= ea + 1; end
571                4: begin fn <= START; we <= 0; end
572
573                // Чтение A из памяти
574                5: begin s2 <= 6;     ax[ 7:0] <= in; ea <= ea + 1; if (!size) fn <= START; end
575                6: begin fn <= START; ax[15:8] <= in; end
576
577            endcase
578            8'b1000010x: begin              // TEST rm,r
579
580                flags <= alu_f;
581                fn    <= START;
582
583            end
584            8'b100001xx: case (s2)          // XCHG rm,r
585
586                0: begin
587
588                    fn      <= WBACK;
589                    fnext   <= INSTR;
590                    s2      <= 1;
591                    dir     <= 1;
592                    wb      <= op1;
593
594                end
595                1: begin
596
597                    fn      <= WBACK;
598                    fnext   <= START;
599                    dir     <= 0;
600                    wb      <= op2;
601
602                end
603
604            endcase
605            8'b10011101: begin              // POPF
606
607                fn      <= START;
608                flags   <= wb | 2;
609
610            end
611            8'b1010100x: case (s2)          // TEST a,i
612
613                // Считывание младшего байта
614                0: begin s2 <= size ? 1 : 2; alu <= ALU_AND; op1 <= ax; op2 <= in; ip <= ip + 1; end
615
616                // Если size, считывание старшего байта
617                1: begin s2 <= 2; op2[15:8] <= in; ip <= ip + 1; end
618
619                // Запись результата в АЛУ
620                2: begin flags <= alu_f; fn <= START; end
621
622            endcase
623            8'b0111xxxx,                    // Jccc
624            8'b111000xx,                    // LOOPNZ, JCXZ
625            8'b11101011: begin              // JMP b8
626
627                fn <= START;
628                ip <= ip + 1 + signex;
629
630            end
631            8'b11101001: case (s2)          // JMP b16
632
633                0: begin s2 <= 1;     ip <= ip + 1; ea[7:0] <= in; end
634                1: begin fn <= START; ip <= ip + 1 + {in, ea[7:0]}; end
635
636            endcase
637            8'b11101010: case (s2)          // JMP far
638
639                // Прочитаьть 4 байта для нового CS:IP
640                0: begin ip <= ip + 1; s2 <= 1; ea       <= in; end
641                1: begin ip <= ip + 1; s2 <= 2; ea[15:8] <= in; end
642                2: begin ip <= ip + 1; s2 <= 3; op1      <= in; end
643                3: begin ip <= ea;     cs <= {in, op1[7:0]}; fn <= START; end
644
645            endcase
646            8'b11101000: case (s2)          // CALL b16
647
648                0: begin s2 <= 1; ea <= in; ip <= ip + 1; end
649                1: begin fn <= PUSH; wb <= ip + 1; ip <= ip + 1 + {in, ea[7:0]}; end
650
651            endcase
652            8'b11000011: begin              // RET
653
654                fn <= START;
655                ip <= wb;
656
657            end
658            8'b11000010: case (s2)          // RET i16
659
660                0: begin s2 <= 1; ea <= in; ip <= ip + 1; end
661                1: begin fn <= START; ip <= wb; sp <= sp + {in, ea[7:0]}; end
662
663            endcase
664            8'b1100101x: case (s2)          // RETF; RETF i16
665
666                0: begin fn <= POP;   s2 <= 1;  op1 <= wb;  op2 <= in; ip <= ip + 1; end
667                1: begin fn <= START; cs <= wb; ip  <= op1; if (!opcode[0]) sp <= sp + {in, op2[7:0]}; end
668
669            endcase
670            8'b11001111: case (s2)          // IRET
671
672                0: begin s2 <= 1; fn <= POP; ip <= wb; end
673                1: begin s2 <= 2; fn <= POP; cs <= wb; end
674                2: begin fn <= START; flags <= wb[11:0] | 2; end
675
676            endcase
677            8'b10001100: begin              // MOV rm,s
678
679                fn   <= WBACK;
680                size <= 1;
681
682                case (modrm[4:3])
683                2'b00: wb <= es;
684                2'b01: wb <= cs;
685                2'b10: wb <= ss;
686                2'b11: wb <= ds;
687                endcase
688
689            end
690            8'b10001110: begin              // MOV s,rm
691
692                fn <= START;
693                case (modrm[4:3])
694                0: es <= op2;
695                1: cs <= op2;
696                2: ss <= op2;
697                3: ds <= op2;
698                endcase
699
700            end
701            8'b10011010: case (s2)          // CALLF b16
702
703                0: begin s2 <= 1;   ip <= ip + 1; op1[ 7:0] <= in; end
704                1: begin s2 <= 2;   ip <= ip + 1; op1[15:8] <= in; end
705                2: begin s2 <= 3;   ip <= ip + 1; op2[ 7:0] <= in; end
706                3: begin s2 <= 4;   ip <= ip + 1; op2[15:8] <= in; fn <= PUSH; wb <= cs; fnext <= INSTR; end
707                4: begin s2 <= 5;   fn <= PUSH;  wb <= ip; fnext <= INSTR; end
708                5: begin ip <= op1; fn <= START; cs <= op2;  end
709
710            endcase
711            8'b1100010x: case (s2)          // LES|LDS r,m
712
713                0: begin
714
715                    s2 <= 1;
716                    ea <= ea + 2;
717
718                end
719                1: begin s2 <= 2; wb[7:0] <= in;  ea <= ea + 1; end
720                2: begin
721
722                    fn <= WBACK;
723                    wb <= op2;
724
725                    if (opcode[0])
726                         ds <= {in, wb[7:0]};
727                    else es <= {in, wb[7:0]};
728
729                end
730
731            endcase
732            8'b10001111: case (s2)          // POP rm
733
734                0: begin s2 <= 1; cpen <= 0; fn <= MODRM; dir <= 0; end
735                1: begin cp <= 1; fn <= WBACK; fnext <= START; end
736
737            endcase
738            8'b011010x0: case (s2)          // PUSH i
739
740                0: begin s2 <= opcode[1] ? 2 : 1; wb <= signex; ip <= ip + 1; end
741                1: begin s2 <= 2; wb[15:8] <= in; ip <= ip + 1; end
742                2: begin fn <= PUSH; fnext <= START; end
743
744            endcase
745            8'b11010111: begin              // XLATB
746
747                fn      <= START;
748                ax[7:0] <= in;
749
750            end
751            8'b11001101: begin              // INT i
752
753                fn      <= INTR;
754                intr    <= in;
755                ip      <= ip + 1;
756
757            end
758            8'b1100000x,
759            8'b110100xx: case (s2)          // Grp#2 Сдвиги
760
761                // Выбор второго операнда
762                // Если тут был указатель на памятьЮ, то сбросить его
763                0: if (cp) cp <= 0; else
764                begin
765
766                    s2  <= 1;
767                    alu <= modrm[5:3];
768
769                    if (opcode[4])
770                         begin op2 <= (opcode[1] ? cx[3:0] : 1); end
771                    else begin op2 <= in[3:0]; ip <= ip + 1; end
772
773                end
774
775                // Процедура сдвига на 0..15 шагов
776                1: begin
777
778                    // Вычисление
779                    if (op2) begin op1 <= rot_r; flags <= rot_f; end
780                    // Запись результата
781                    else begin wb <= op1; cp <= 1; fn <= WBACK; end
782
783                    op2 <= op2 - 1;
784
785                end
786
787            endcase
788            8'b1110x10x: case (s2)          // IN a,p
789
790                // Чтение номера порта
791                0: begin
792
793                    s2     <= 1;
794                    cpen   <= 0;
795                    port_a <= opcode[3] ? dx : in;
796                    if (!opcode[3]) ip <= ip + 1;
797
798                end
799
800                // Чтение, ожидание результата 1 такт
801                1: begin s2 <= 2; port_r <= 1; end
802                2: begin s2 <= 3; end
803
804                // Запись ответа в AL|AH
805                3: begin
806
807                    if (size) begin s2 <= 1; cpen <= 1; end
808                    else fn <= START;
809
810                    if (cpen)
811                         ax[15:8] <= port_i;
812                    else ax[ 7:0] <= port_i;
813
814                    port_a <= port_a + 1;
815                    size   <= 0;
816
817                end
818
819            endcase
820            8'b1110x11x: case (s2)          // OUT p,a
821
822                0: begin
823
824                    s2 <= 1;
825
826                    port_a  <= opcode[3] ? dx : in;
827                    port_o  <= ax[7:0];
828                    port_w  <= 1;
829
830                    if (!opcode[3]) ip <= ip + 1;
831                    if (!size) fn <= START;
832
833                end
834                1: begin
835
836                    port_a  <= port_a + 1;
837                    port_o  <= ax[15:8];
838                    port_w  <= 1;
839                    fn      <= START;
840
841                end
842
843            endcase
844            8'b1111011x: case (modrm[5:3])  // Grp#3
845
846                // TEST imm8/16
847                0, 1: case (s2)
848
849                    0: begin s2 <= 1; cp <= 0; alu <= ALU_AND; end
850                    1: begin s2 <= size ? 2 : 3; op2 <= in; ip <= ip + 1; end
851                    2: begin s2 <= 3; op2[15:8] <= in; ip <= ip + 1; end
852                    3: begin fn <= START; flags <= alu_f; end
853
854                endcase
855
856                // NOT rm
857                2: begin wb <= ~op1; fn <= WBACK; end
858
859                // NEG rm
860                3: case (s2)
861
862                    0: begin s2 <= 1; alu <= ALU_SUB; op2 <= op1; op1 <= 0; end
863                    1: begin fn <= WBACK; wb <= alu_r; flags <= alu_f; end
864
865                endcase
866
867            endcase
868            8'b1111111x: case (modrm[5:3])  // Grp#4|5
869
870                // INC|DEC rm
871                0,
872                1: case (s2)
873
874                    0: begin s2 <= 1; op2 <= 1; alu <= modrm[3] ? ALU_SUB : ALU_ADD; end
875                    1: begin fn <= WBACK; wb <= alu_r; flags <= alu_f; end
876
877                endcase
878
879                // CALL rm
880                2: begin
881
882                    ip <= op1;
883                    wb <= ip;
884                    fn <= size ? PUSH : UNDEF;
885
886                end
887
888                // CALL far rm
889                3: case (s2)
890
891                    0: begin s2 <= 1; ea <= ea + 2; ip <= op1; op1 <= ip; op2 <= cs; if (size == 0) fn <= UNDEF; end
892                    1: begin s2 <= 2; ea <= ea + 1; wb <= in; fnext <= INSTR; end
893                    2: begin s2 <= 3; fn <= PUSH; cs <= {in, wb[7:0]}; wb <= op2;  end
894                    3: begin s2 <= 4; fn <= PUSH; wb <= op1; end
895                    4: begin fn <= START; end
896
897                endcase
898
899                // JMP rm
900                4: begin ip <= op1; fn <= size ? START : UNDEF; end
901
902                // JMP far rm
903                5: case (s2)
904
905                    0: begin s2 <= 1; ea <= ea + 2; ip <= op1; if (size == 0) fn <= UNDEF; end
906                    1: begin s2 <= 2; ea <= ea + 1; wb <= in; end
907                    2: begin fn <= START;           cs <= {in, wb[7:0]}; end
908
909                endcase
910
911                // PUSH rm
912                6: begin wb <= op1; fn <= PUSH; end
913                7: begin fn <= UNDEF; end
914
915            endcase
916            8'b1010101x: case (s2)          // STOSx
917
918                0: begin // STOSB
919
920                    s2      <= size ? 1 : 2;
921                    cp      <= 1;
922                    we      <= 1;
923                    ea      <= di;
924                    out     <= ax[7:0];
925                    segment <= es;
926
927                end
928                1: begin // STOSW
929
930                    s2  <= 2;
931                    we  <= 1;
932                    ea  <= ea + 1;
933                    out <= ax[15:8];
934
935                end
936                2: begin
937
938                    we  <= 0;
939                    fn  <= rep[1] ? REPF : START;
940                    cp  <= 0;
941                    di  <= flags[DF] ? di - (size + 1) : di + (size + 1);
942                    size <= 1;
943
944                end
945
946            endcase
947            8'b1010110x: case (s2)          // LODSx
948
949                0: begin s2 <= 1; cp <= 1;   ea <= si; end
950                1: begin s2 <= size ? 2 : 3; ea <= ea + 1; ax[7:0] <= in; end
951                2: begin s2 <= 3; ax[15:8] <= in; end
952                3: begin
953
954                    fn      <= rep[1] ? REPF : START;
955                    cp      <= 0;
956                    si      <= flags[DF] ? si - (opcode[0] + 1) : si + (opcode[0] + 1);
957                    size    <= 1;
958
959                end
960
961            endcase
962            8'b1010010x: case (s2)          // MOVSx
963
964                // Загрузка 8 или 16 бит DS:SI
965                0: begin s2 <= 1; ea <= si; cp <= 1; end
966                1: begin s2 <= size ? 2 : 3; wb <= in; ea <= ea + 1; end
967                2: begin s2 <= 3; wb[15:8] <= in; end
968
969                // Запись 8 или 16 бит ES:DI
970                3: begin
971
972                    s2      <= size ? 4 : 5;
973                    we      <= 1;
974                    ea      <= di;
975                    segment <= es;
976                    out     <= wb[7:0];
977
978                end
979                4: begin s2 <= 5; we <= 1; ea <= ea + 1; out <= wb[15:8]; end
980
981                // Инкремент или декремент SI
982                5: begin
983
984                    s2  <= 6;
985                    we  <= 0;
986                    cp  <= 0;
987                    si  <= flags[DF] ? si - (opcode[0] + 1) : si + (opcode[0] + 1);
988                    size <= 1;
989
990                end
991
992                // Инкремент или декремент DI
993                6: begin s2 <= 6;
994
995                    di <= flags[DF] ? di - (opcode[0] + 1) : di + (opcode[0] + 1);
996
997                    // Использование REP:
998                    fn  <= rep[1] ? REPF : START;
999
1000                end
1001
1002            endcase
1003            8'b1010011x: case (s2)          // CMPSx
1004
1005                0: begin s2 <= 1;            cp        <= 1;  ea <= si; alu <= ALU_SUB; end
1006                1: begin s2 <= size ? 2 : 3; op1       <= in; ea <= ea + 1; end
1007                2: begin s2 <= 3;            op1[15:8] <= in; end
1008                3: begin s2 <= 4;            segment   <= es; ea <= di; end
1009                4: begin s2 <= size ? 5 : 6; op2       <= in; ea <= ea + 1; end
1010                5: begin s2 <= 6;            op2[15:8] <= in; end
1011
1012                // Инкремент или декремент SI
1013                6: begin
1014
1015                    s2      <= 7;
1016                    flags   <= alu_f;
1017                    cp      <= 0;
1018                    si      <= flags[DF] ? si - (opcode[0] + 1) : si + (opcode[0] + 1);
1019                    size    <= 1;
1020
1021                end
1022
1023                // Инкремент или декремент DI
1024                7: begin
1025
1026                    rep_ft  <= 1;
1027
1028                    // Проверять на REPNZ или REPZ
1029                    di  <= flags[DF] ? di - (opcode[0] + 1) : di + (opcode[0] + 1);
1030
1031                    // Использование REP:
1032                    fn  <= rep[1] ? REPF : START;
1033
1034                end
1035
1036            endcase
1037            8'b1010111x: case (s2)          // SCASx
1038
1039                0: begin
1040
1041                    s2      <= 1;
1042                    cp      <= 1;
1043                    alu     <= ALU_SUB;
1044                    op1     <= ax;
1045                    ea      <= di;
1046                    segment <= es;
1047
1048                end
1049                1: begin s2 <= size ? 2 : 3; op2       <= in; ea <= ea + 1; end
1050                2: begin s2 <= 3;            op2[15:8] <= in; end
1051
1052                // Инкремент или декремент DI
1053                3: begin
1054
1055                    flags   <= alu_f;
1056                    cp      <= 0;
1057                    rep_ft  <= 1; // Проверять на REPNZ или REPZ
1058                    di      <= flags[DF] ? di - (opcode[0] + 1) : di + (opcode[0] + 1);
1059                    fn      <= rep[1] ? REPF : START;   // Использование REP:
1060
1061                end
1062
1063            endcase
1064
1065        endcase
1066
1067        // Прерывание intr; считается за выполнение инструкции
1068        // -------------------------------------------------------------
1069        INTR: case (s2)
1070
1071            0: begin s2 <= 1; fn <= PUSH; wb <= flags; fnext <= INTR; end
1072            1: begin s2 <= 2; fn <= PUSH; wb <= cs; end
1073            2: begin s2 <= 3; fn <= PUSH; wb <= ip; end
1074            3: begin s2 <= 4; ea <= {intr, 2'b00}; segment <= 0; cp <= 1; end
1075            4: begin s2 <= 5; ea <= ea + 1; ip[ 7:0] <= in; end
1076            5: begin s2 <= 6; ea <= ea + 1; ip[15:8] <= in; end
1077            6: begin s2 <= 7; ea <= ea + 1; cs[ 7:0] <= in; end
1078            7: begin cp <= 0; ea <= ea + 1; cs[15:8] <= in; fn <= START; flags[IF] <= 1'b0; end
1079
1080        endcase
1081
1082        // Сохранение данных [wb, size, dir, modrm]
1083        // -------------------------------------------------------------
1084        WBACK: case (s1)
1085
1086            // Выбор - регистр или память
1087            0: begin
1088
1089                // reg-часть или rm:reg
1090                if (dir || modrm[7:6] == 2'b11) begin
1091
1092                    cp <= 0;
1093                    s1 <= 0;
1094                    fn <= fnext;
1095
1096                    case (dir ? modrm[5:3] : modrm[2:0])
1097                    REG_AX: if (size) ax <= wb; else ax[ 7:0] <= wb[7:0];
1098                    REG_CX: if (size) cx <= wb; else cx[ 7:0] <= wb[7:0];
1099                    REG_DX: if (size) dx <= wb; else dx[ 7:0] <= wb[7:0];
1100                    REG_BX: if (size) bx <= wb; else bx[ 7:0] <= wb[7:0];
1101                    REG_SP: if (size) sp <= wb; else ax[15:8] <= wb[7:0];
1102                    REG_BP: if (size) bp <= wb; else cx[15:8] <= wb[7:0];
1103                    REG_SI: if (size) si <= wb; else dx[15:8] <= wb[7:0];
1104                    REG_DI: if (size) di <= wb; else bx[15:8] <= wb[7:0];
1105                    endcase
1106
1107                end
1108                // Если modrm указывает на память, записать первые 8 бит
1109                else begin out <= wb[7:0]; we <= 1; s1 <= 1; end
1110
1111            end
1112
1113            // Запись 16 бит | Либо завершение 8/16 бит записи
1114            1: if (size) begin size <= 0; ea <= ea + 1; out <= wb[15:8]; end
1115               else      begin s1   <= 0; cp <= 0; we <= 0; fn <= fnext; end
1116
1117        endcase
1118
1119        // Запись в стек <= wb [cp,ea,segment]
1120        // -------------------------------------------------------------
1121        PUSH: case (s1)
1122
1123            0: begin s1 <= 1; out <= wb[ 7:0]; ea <= sp - 2; we <= 1; cp <= 1; segment <= ss; end
1124            1: begin s1 <= 2; out <= wb[15:8]; ea <= ea + 1; end
1125            2: begin s1 <= 0; we  <= 0; cp <= 0; sp <= sp - 2; fn <= fnext; end
1126
1127        endcase
1128
1129        // Чтение из стека => wb [cp,ea,segment]
1130        // -------------------------------------------------------------
1131        POP: case (s1)
1132
1133            0: begin s1 <= 1; segment  <= ss; ea <= sp; cp <= 1; end
1134            1: begin s1 <= 2; wb[ 7:0] <= in; ea <= ea + 1; end
1135            2: begin s1 <= 0; wb[15:8] <= in; cp <= 0; sp <= sp + 2; fn <= fnext; end
1136
1137        endcase
1138
1139        // Выполнение инструкции REP
1140        REPF: case (s1)
1141
1142            // Уменьшить CX - 1
1143            0: begin s1 <= 1; cx <= cx - 1; end
1144            1: begin
1145
1146                s1 <= 0;
1147                fn <= START;
1148
1149                // CX=0, повтор закончен
1150                if (cx) begin
1151
1152                    // REPNZ|REPZ
1153                    if (rep_ft) begin if (rep[0] == flags[ZF]) ip <= ip_start; end
1154                    // REP:
1155                    else ip <= ip_start;
1156
1157                end
1158
1159            end
1160
1161        endcase
1162
1163        // Деление op1 на op2, size -> wb
1164        // DIV: case (s5)
1165        // endcase
1166
1167    endcase
1168
1169end
1170
1171// Арифметико-логическое устройство
1172// ---------------------------------------------------------------------
1173
1174wire [16:0] alu_r =
1175
1176    alu == ALU_ADD ? op1 + op2 :
1177    alu == ALU_OR  ? op1 | op2 :
1178    alu == ALU_ADC ? op1 + op2 + flags[CF] :
1179    alu == ALU_SBB ? op1 - op2 - flags[CF] :
1180    alu == ALU_AND ? op1 & op2:
1181    alu == ALU_XOR ? op1 ^ op2:
1182                     op1 - op2; // SUB, CMP
1183
1184wire [ 3:0] alu_top = size ? 15 : 7;
1185wire [ 4:0] alu_up  = alu_top + 1'b1;
1186
1187wire is_add  = alu == ALU_ADD || alu == ALU_ADC;
1188wire is_lgc  = alu == ALU_XOR || alu == ALU_AND || alu == ALU_OR;
1189wire alu_cf  = alu_r[alu_up];
1190wire alu_af  = op1[4] ^ op2[4] ^ alu_r[4];
1191wire alu_sf  = alu_r[alu_top];
1192wire alu_zf  = (size ? alu_r[15:0] : alu_r[7:0]) == 0;
1193wire alu_pf  = ~^alu_r[7:0];
1194wire alu_of  = (op1[alu_top] ^ op2[alu_top] ^ is_add) & (op1[alu_top] ^ alu_r[alu_top]);
1195
1196wire [11:0] alu_f = {
1197    /* OF  */ alu_of & ~is_lgc,
1198    /* DIT */ flags[10:8],
1199    /* SF  */ alu_sf,
1200    /* ZF  */ alu_zf,
1201    /* 5   */ 1'b0,
1202    /* AF  */ alu_af & ~is_lgc,
1203    /* 3   */ 1'b0,
1204    /* PF  */ alu_pf,
1205    /* 1   */ 1'b1,
1206    /* CF  */ alu_cf & ~is_lgc
1207};
1208
1209// Сдвиговый регистр
1210// ---------------------------------------------------------------------
1211
1212reg [15:0] rot_r;
1213reg [11:0] rot_f;
1214
1215always @* begin
1216
1217    rot_f = flags;
1218
1219    case (alu)
1220    ALU_ROL: rot_r = size ? {op1[14:0], op1[15]}   : {op1[6:0], op1[7]};
1221    ALU_ROR: rot_r = size ? {op1[0], op1[15:1]}    : {op1[0], op1[7:1]};
1222    ALU_RCL: rot_r = size ? {op1[14:0], flags[CF]} : {op1[6:0], flags[CF]};
1223    ALU_RCR: rot_r = size ? {flags[CF], op1[15:1]} : {flags[CF], op1[7:1]};
1224    ALU_SHL,
1225    ALU_SAL: rot_r = size ? {op1[14:0], 1'b0}    : {op1[6:0], 1'b0};
1226    ALU_SHR: rot_r = size ? {1'b0, op1[15:1]}    : {1'b0, op1[7:1]};
1227    ALU_SHR: rot_r = size ? {op1[15], op1[15:1]} : {op1[7], op1[7:1]};
1228    endcase
1229
1230    // Флаг CF
1231    rot_f[CF] = alu[0] ? op1[0] : op1[alu_top];
1232
1233    // Флаг OF
1234    case (alu)
1235    ALU_ROL,
1236    ALU_RCL,
1237    ALU_SAL,
1238    ALU_SHL: rot_f[OF] = op1[alu_top] ^ op1[alu_top - 1];
1239    ALU_ROR,
1240    ALU_RCR: rot_f[OF] = rot_r[alu_top] ^ rot_r[alu_top - 1];
1241    ALU_SHR: rot_f[OF] = op1[alu_top];
1242    ALU_SAR: rot_f[OF] = 1'b0;
1243    endcase
1244
1245    // S, Z, P для 4 инструкции
1246    if (alu == ALU_SHL || alu == ALU_SHR || alu == ALU_SAL || alu == ALU_SHR) begin
1247
1248        rot_f[SF] = rot_r[alu_top];
1249        rot_f[ZF] = (size ? rot_r[15:0] : rot_r[7:0]) == 0;
1250        rot_f[PF] = ~^rot_r[7:0];
1251
1252    end
1253
1254end
1255
1256endmodule