§ Описание
Здесь лишь только часть процессора, то есть, только его ядро: core88.Основные пины
-
clock
— 25 мгц -
resetn
— если 0, то процессор сбрасывается -
locked
— если 1, процессор работает -
address
— адрес -
bus
— входящие данные -
data
— исходящие данные -
wreq
— сигнал записи
-
port_clk
- тактовый импульс для защелкивания -
port
- номер порта -
port_i
- входящие данные из порта -
port_o
- исходящие данные -
port_w
- сигнал записи в порт
- intr - Запрос прерывания
- irq - Номер прерывания
- intr_latch - Защелка что прерывание обработано
§ Ядро процессора на Verilog
Ревизия процессора: 09/05/22// verilator lint_off CASEX // verilator lint_off CASEOVERLAP module core88 ( input wire clock, input wire reset_n, input wire locked, // Данные output wire [19:0] address, input wire [ 7:0] bus, output reg [ 7:0] data, output reg wreq, // Порты output reg port_clk, output reg [15:0] port, input wire [ 7:0] port_i, output reg [ 7:0] port_o, output reg port_w, // Прерывания input wire intr, // Запрос прерывания input wire [ 7:0] irq, // Номер прерывания output reg intr_latch, // ACCEPT прерывания // Отладочные LED output wire [ 3:0] iload ); assign iload = mode; // --------------------------------------------------------------------- // ОБЪЯВЛЕНИЕ РЕГИСТРОВ // --------------------------------------------------------------------- // Сегментные регистры reg [15:0] seg_cs = 16'hF000; reg [15:0] seg_ss = 16'h0000; reg [15:0] seg_es = 16'h0000; reg [15:0] seg_ds = 16'h0000; reg [15:0] seg_fs = 16'h0000; reg [15:0] seg_gs = 16'h0000; // Регистры reg [31:0] eax = 32'h4321_e21B; reg [31:0] ebx = 32'hefd0_0001; reg [31:0] ecx = 32'ha1ac_0005; reg [31:0] edx = 32'h0b21_8001; reg [31:0] esp = 32'haaa3_5432; reg [31:0] ebp = 32'ha940_5678; reg [31:0] esi = 32'ha580_0002; reg [31:0] edi = 32'ha670_0004; // Системные reg [15:0] ip = 16'h0000; reg [15:0] ipstart = 16'h0000; reg [15:0] seg_ea = 16'h0000; reg [31:0] ea = 32'h0000_0000; // ODIT SZ A P C reg [11:0] flags = 12'b0000_00000010; // --------------------------------------------------------------------- // Состояние процессора // --------------------------------------------------------------------- // Выбранная шина адреса (sel=1) seg:ea (sel=0) cs:ip reg [3:0] mode = 1'b0; reg sel = 1'b0; reg sel_seg = 1'b0; reg [1:0] sel_rep = 1'b0; reg [3:0] tstate = 1'b0; reg [4:0] estate = 1'b0; reg [8:0] opcode = 1'b0; reg [7:0] modrm = 1'b0; reg skip_op = 1'b0; // Не считывать операнды reg stack32 = 1'b0; // 16/32 reg isize = 1'b0; // 8/16 reg opsize = 1'b0; // 16/32 reg opsizet = 1'b0; reg adsize = 1'b0; // 16/32 reg idir = 1'b0; // rm,r | r,rm reg [ 2:0] regn = 1'b0; // regv = register[regn] reg [ 2:0] alumode = 1'b0; reg [31:0] op1 = 1'b0; reg [31:0] op2 = 1'b0; reg [31:0] wb = 1'b0; // Для записи в reg/rm reg [15:0] tmp16 = 1'b0; reg is_intr = 1'b0; reg [63:0] rdtsc = 1'b0; // Модуль деления op1 / op2 -> divres | divrem reg [63:0] diva = 1'b0; reg [63:0] divb = 1'b0; reg [ 6:0] divcnt = 1'b0; reg [63:0] divrem = 1'b0; reg [63:0] divres = 1'b0; reg signa = 1'b0; reg signb = 1'b0; // --------------------------------------------------------------------- // Константы и initial // --------------------------------------------------------------------- localparam CF = 0, PF = 2, AF = 4, ZF = 6, SF = 7, TF = 8, IF = 9, DF = 10, OF = 11; localparam PREPARE = 0, // Эта подготовки инструкции к исполнению MAIN = 1, // Обработка микрокода FETCHEA = 2, // Считывание ModRM/EA SETEA = 3, // Запись в память или регистр PUSH = 4, // Запись в стек POP = 5, // Извлечь из стека INTERRUPT = 6, // Вызов прерывания LOADSEG = 7, // Загрузка сегмента IMMEDIATE = 8, // Непосредственное значение SHIFT = 9, // Сдвиги DIVIDE = 10, // Деление 8/16/32 битного EXTENDED0 = 11, EXTENDED = 12; // Расширенный опкод initial begin data = 8'hFF; wreq = 0; port_w = 0; port_o = 0; port_clk = 0; port = 0; intr_latch = 0; end // --------------------------------------------------------------------- // Предвычисления // --------------------------------------------------------------------- // Выбор регистра wire [31:0] regv = regn == 0 ? (isize ? (opsize ? eax : eax[15:0]) : eax[ 7:0]) : regn == 1 ? (isize ? (opsize ? ecx : ecx[15:0]) : ecx[ 7:0]) : regn == 2 ? (isize ? (opsize ? edx : edx[15:0]) : edx[ 7:0]) : regn == 3 ? (isize ? (opsize ? ebx : ebx[15:0]) : ebx[ 7:0]) : regn == 4 ? (isize ? (opsize ? esp : esp[15:0]) : eax[15:8]) : regn == 5 ? (isize ? (opsize ? ebp : ebp[15:0]) : ecx[15:8]) : regn == 6 ? (isize ? (opsize ? esi : esi[15:0]) : edx[15:8]) : (isize ? (opsize ? edi : edi[15:0]) : ebx[15:8]); // Вычисление условий wire [7:0] branches = { (flags[SF] ^ flags[OF]) | flags[ZF], // 7: (ZF=1) OR (SF!=OF) (flags[SF] ^ flags[OF]), // 6: SF!=OF flags[PF], // 5: PF flags[SF], // 4: SF flags[CF] | flags[ZF], // 3: CF or ZF flags[ZF], // 2: ZF flags[CF], // 1: CF flags[OF] // 0: OF }; // Модуль умножения wire [63:0] mult = op1 * op2; wire signd = signa ^ signb; // Выбор источника памяти assign address = sel ? {seg_ea, 4'h0} + ea : {seg_cs, 4'h0} + ip; // ===================================================================== // Основная работа процессорного микрокода, так сказать // ===================================================================== // Считать такты процессора always @(posedge clock) rdtsc <= rdtsc + 1; always @(posedge clock) // Сброс if (reset_n == 0) begin seg_cs <= 16'hF000; ip <= 0; mode <= PREPARE; end // Исполнение else if (locked) case (mode) // Считывание опкода, сброс, прерывания PREPARE: begin opcode <= bus; idir <= 0; isize <= 0; modrm <= 0; opsize <= 0; adsize <= 0; sel_seg <= 0; sel_rep <= 0; stack32 <= 0; skip_op <= 0; seg_ea <= seg_ds; tstate <= 0; estate <= 0; ipstart <= ip; // Есть наличие IRQ из контроллера прерываний if (flags[IF] & (intr ^ intr_latch)) begin is_intr <= 1; mode <= INTERRUPT; wb <= irq; intr_latch <= intr; // Разблокировка HLT if (bus == 8'hF4) ip <= ip + 1; end else begin is_intr <= 0; ip <= ip + 1; mode <= MAIN; end end // Исполнение инструкции MAIN: casex (opcode) // Сегментные префиксы 8'h26: begin opcode <= bus; ip <= ip + 1; sel_seg <= 1; seg_ea <= seg_es; end 8'h2E: begin opcode <= bus; ip <= ip + 1; sel_seg <= 1; seg_ea <= seg_cs; end 8'h36: begin opcode <= bus; ip <= ip + 1; sel_seg <= 1; seg_ea <= seg_ss; end 8'h3E: begin opcode <= bus; ip <= ip + 1; sel_seg <= 1; seg_ea <= seg_ds; end 8'h64: begin opcode <= bus; ip <= ip + 1; sel_seg <= 1; seg_ea <= seg_fs; end 8'h65: begin opcode <= bus; ip <= ip + 1; sel_seg <= 1; seg_ea <= seg_gs; end // Расширения операнда и адреса 8'h66: begin opcode <= bus; ip <= ip + 1; opsize <= ~opsize; end 8'h67: begin opcode <= bus; ip <= ip + 1; adsize <= ~adsize; end // REP: 8'hF2: begin opcode <= bus; ip <= ip + 1; sel_rep <= 2'b10; end // REPNZ 8'hF3: begin opcode <= bus; ip <= ip + 1; sel_rep <= 2'b11; end // REPZ // Расширение опкода 8'h0F: begin opcode <= {1'b1, bus}; ip <= ip + 1; end // Неиспользуемые коды операции LOCK: FWAIT 8'hF0, 8'h9B: begin opcode <= bus; ip <= ip + 1; end // ==== Групповые инструкции должны идти первыми ==== // Групповые инструкции F6/F7 8'b1111_011x: case (tstate) 0: begin tstate <= 1; {idir, isize} <= opcode[0]; mode <= FETCHEA; end 1: begin tstate <= 2; case (modrm[5:3]) // TEST 0, 1: begin sel <= 0; mode <= IMMEDIATE; end // NOT 2: begin wb <= ~op1; mode <= SETEA; end // NEG 3: begin op1 <= 0; op2 <= op1; alumode <= 5; end // MUL 4: begin op2 <= isize ? (opsize ? eax : eax[15:0]) : eax[7:0]; end // IMUL 5: begin op1 <= isize ? (opsize ? op1 : {{16{op1[15]}},op1[15:0]}) : {{24{op1[7]}},op1[7:0]}; op2 <= isize ? (opsize ? eax : {{16{eax[15]}},eax[15:0]}) : {{24{eax[7]}},eax[7:0]}; end // DIV, IDIV 6, 7: begin divcnt <= isize ? (opsize ? 64 : 32) : 16; diva <= isize ? (opsize ? {edx, eax} : {edx[15:0],eax[15:0],32'h0}) : {eax[15:0],48'h0}; divb <= isize ? (opsize ? op1 : op1[15:0]) : op1[7:0]; divrem <= 0; divres <= 0; signa <= 0; signb <= 0; // Переход к IDIV вместо DIV if (modrm[3]) tstate <= 4; else mode <= DIVIDE; end endcase end 2: begin tstate <= 3; case (modrm[5:3]) 0, 1: begin op2 <= wb; alumode <= 4; end 2: begin sel <= 0; mode <= PREPARE; end 3: begin wb <= result; flags <= flags_o; mode <= SETEA; end 4, 5: begin sel <= 0; mode <= PREPARE; // CF,OF устанавливаются при переполнении // ZF при нулевом результате if (opsize && isize) begin // 32 bit eax <= mult[31:0]; edx <= mult[63:32]; flags[ZF] <= mult[63:0] == 0; flags[CF] <= edx != 0; flags[OF] <= edx != 0; end else if (isize) begin // 16 bit eax[15:0] <= mult[15:0]; edx[15:0] <= mult[31:16]; flags[ZF] <= mult[31:0] == 0; flags[CF] <= edx[15:0] != 0; flags[OF] <= edx[15:0] != 0; end else begin // 8 bit eax[15:0] <= mult[15:0]; flags[ZF] <= mult[15:0] == 0; flags[CF] <= eax[15:8] != 0; flags[OF] <= eax[15:8] != 0; end end 6, 7: begin sel <= 0; wb <= 0; mode <= PREPARE; if (isize && opsize) begin eax <= signd ? -divres[31:0] : divres[31:0]; edx <= divrem[31:0]; if (|divres[63:32] || divb[31:0] == 0) mode <= INTERRUPT; end else if (isize) begin eax[15:0] <= signd ? -divres[15:0] : divres[15:0]; edx[15:0] <= divrem[15:0]; if (|divres[31:16] || divb[15:0] == 0) mode <= INTERRUPT; end else begin eax[ 7:0] <= signd ? -divres[7:0] : divres[7:0]; eax[15:8] <= divrem[7:0]; if (|divres[15:8] || divb[7:0] == 0) mode <= INTERRUPT; end end endcase end 3: case (modrm[5:3]) 0, 1: begin flags <= flags_o; mode <= PREPARE; end 3, 6: begin sel <= 0; mode <= PREPARE; end endcase // Коррекция IDIV 4: begin signa <= diva[63]; // Определение знака A if (diva[63]) begin if (isize && opsize) diva <= -diva; else if (isize) diva[63:32] <= -diva[63:32]; else diva[63:48] <= -diva[63:48]; end // Определение знака A if (isize && opsize && divb[31]) begin signb <= 1; divb[31:0] <= -divb[31:0]; end else if (isize && divb[15]) begin signb <= 1; divb[15:0] <= -divb[15:0]; end else if (divb[7]) begin signb <= 1; divb[ 7:0] <= -divb[ 7:0]; end tstate <= 2; mode <= DIVIDE; end endcase // Групповые инструкции #2 INC/DEC r8 8'b1111_1110: case (tstate) 0: begin tstate <= 1; mode <= FETCHEA; {idir, isize} <= 2'b00; end 1: begin tstate <= 2; op2 <= 1; alumode <= modrm[3] ? 5 : 0; end 2: begin tstate <= 3; wb <= result; flags <= {flags_o[11:1], 1'b0}; mode <= SETEA; end 3: begin sel <= 0; mode <= PREPARE; end endcase // Групповые инструкции #3 Word/DWord 8'b1111_1111: case (tstate) 0: begin tstate <= 1; {idir, isize} <= 2'b01; mode <= FETCHEA; end 1: begin tstate <= 2; case (modrm[5:3]) // INC|DEC 0, 1: begin op2 <= 1; alumode <= modrm[3] ? 5 : 0; end // CALL rm16 2: begin wb <= ip; ip <= op1; mode <= PUSH; end // CALL far: Запись CS 3: begin wb <= seg_cs; mode <= PUSH; op2 <= ea; tmp16 <= seg_ea; end // JMP rm16 4: begin ip <= op1; sel <= 0; mode <= PREPARE; end // JMP far 5: begin ip <= op1; ea <= ea + (opsize ? 4 : 2); sel <= 1; end // PUSH rm16 6: begin wb <= op1; mode <= PUSH; end endcase end 2: begin tstate <= 3; case (modrm[5:3]) // INC|DEC 0, 1: begin mode <= SETEA; wb <= result; flags <= {flags_o[11:1], 1'b0}; {idir, isize} <= 2'b01; end // CALL far: запись IP 3: begin wb <= ip; ip <= op1; mode <= PUSH; end // JMP far 5: begin wb <= bus; ea <= ea + 1; end 2, 6: mode <= PREPARE; endcase end 3: begin tstate <= 4; case (modrm[5:3]) // INC|DEC 0, 1: begin sel <= 0; mode <= PREPARE; end // CALL far 3: begin sel <= 1; seg_ea <= op2; ea <= tmp16 + (opsize ? 4 : 2); end // JMP far 5: begin wb[15:8] <= bus; mode <= LOADSEG; regn <= 1; end endcase end 4: begin tstate <= 5; case (modrm[5:3]) 3: begin wb <= bus; ea <= ea + 1; end 5: begin sel <= 0; mode <= PREPARE; end endcase end 5: begin tstate <= 6; case (modrm[5:3]) 3: begin wb[15:8] <= bus; mode <= LOADSEG; regn <= 1; end endcase end 5: case (modrm[5:3]) 3: begin sel <= 0; mode <= PREPARE; end endcase endcase // Arithmetic Grp 8'b1000_00xx: case (tstate) // Прочесть байт modrm, найти ссылку на память 0: begin tstate <= 1; mode <= FETCHEA; isize <= opcode[0]; idir <= 0; end // Запрос на получение второго операнда 1: begin tstate <= 2; mode <= IMMEDIATE; alumode <= modrm[5:3]; sel <= 0; if (opcode[1:0] == 2'b11) isize <= 0; end // Распознание второго операнда 2: begin tstate <= 3; op2 <= opcode[1:0] == 2'b11 ? (opsize ? {{24{wb[7]}},wb[7:0]} : {{8{wb[7]}},wb[7:0]}) : wb; isize <= opcode[0]; end // Запись результата 3: begin tstate <= 4; mode <= alumode == 7 ? PREPARE : SETEA; sel <= alumode == 7 ? 0 : 1; wb <= result; flags <= flags_o; if (alumode == 7) sel <= 0; end 4: begin sel <= 0; mode <= PREPARE; end endcase // ALU modrm 8'b00_xxx_0xx: case (tstate) 0: begin tstate <= 1; mode <= FETCHEA; {idir, isize} <= opcode[1:0]; alumode <= opcode[5:3]; end 1: begin tstate <= 2; flags <= flags_o; if (alumode < 7) begin mode <= SETEA; wb <= result; end end 2: begin mode <= PREPARE; sel <= 0; end endcase // ALU ac, # 8'b00_xxx_10x: case (tstate) 0: begin tstate <= 1; mode <= IMMEDIATE; alumode <= opcode[5:3]; isize <= opcode[0]; op1 <= opcode[0] ? (opsize ? eax : eax[15:0]) : eax[7:0]; end 1: begin tstate <= 2; op2 <= wb; end 2: begin tstate <= 3; flags <= flags_o; idir <= 1; mode <= alumode == 7 ? PREPARE : SETEA; wb <= result; modrm[5:3] <= 0; end 3: mode <= PREPARE; endcase // IMUL r16, rm, i16/i8 8'b0110_10x1: case (tstate) 0: begin tstate <= 1; mode <= FETCHEA; {idir, isize} <= 2'b11; end 1: begin tstate <= 2; mode <= IMMEDIATE; isize <= ~opcode[1]; op1 <= op2; sel <= 0; end 2: begin tstate <= 3; isize <= 1'b1; op1 <= opsize ? op2 : {{16{op2[15]}}, op2[15:0]}; op2 <= isize ? (opsize ? wb : {{16{wb[15]}}, wb[15:0]}) : {{24{wb[7]}}, wb[7:0]}; end 3: begin tstate <= 4; if (opsize) begin wb <= mult[31:0]; flags[CF] <= mult[63:32] ? 1 : 0; flags[OF] <= mult[63:32] ? 1 : 0; end else begin wb <= mult[15:0]; flags[CF] <= mult[31:16] ? 1 : 0; flags[OF] <= mult[31:16] ? 1 : 0; end mode <= SETEA; end 4: begin mode <= PREPARE; sel <= 0; end endcase // PUSH i16/i8 8'b0110_10x0: case (tstate) 0: begin tstate <= 1; isize <= !opcode[1]; mode <= IMMEDIATE; end 1: begin tstate <= 2; isize <= 1; mode <= PUSH; if (isize == 0) wb <= {{24{wb[7]}}, wb[7:0]}; end 2: begin mode <= PREPARE; sel <= 0; end endcase // ==== Строковые инструкции ==== // MOVSx 8'b1010_010x: case (tstate) 0: begin // Читать tstate <= 1; isize <= opcode[0]; ea <= esi[15:0]; op1 <= 0; op2 <= opcode[0] ? (opsize ? 4 : 2) : 1; // Если REP и CX=0, то пропуск инструкции if (sel_rep && ecx[15:0] == 0) begin sel <= 0; mode <= PREPARE; end else begin sel <= 1; estate <= 4; mode <= FETCHEA; end end 1: begin // Писать tstate <= 2; estate <= 0; seg_ea <= seg_es; ea <= edi[15:0]; wb <= op1; mode <= SETEA; end 2: begin // Инкременты sel <= 0; mode <= PREPARE; esi[15:0] <= flags[DF] ? esi[15:0] - op2 : esi[15:0] + op2; edi[15:0] <= flags[DF] ? edi[15:0] - op2 : edi[15:0] + op2; if (sel_rep) begin ecx[15:0] <= ecx[15:0] - 1; ip <= ipstart; end end endcase // CMPSx 8'b1010_011x: case (tstate) 0: begin // Читать DS:SI tstate <= 1; isize <= opcode[0]; ea <= esi[15:0]; op1 <= 0; tmp16 <= opcode[0] ? (opsize ? 4 : 2) : 1; alumode <= 7; // alu=CMP // Если REP и CX=0, то пропуск инструкции if (sel_rep && ecx[15:0] == 0) begin sel <= 0; mode <= PREPARE; end else begin sel <= 1; mode <= FETCHEA; estate <= 4; end end 1: begin // Читать ES:DI tstate <= 2; estate <= 4; idir <= 1; seg_ea <= seg_es; ea <= edi[15:0]; mode <= FETCHEA; end 2: begin // Инкременты sel <= 0; mode <= PREPARE; flags <= flags_o; esi[15:0] <= flags[DF] ? esi[15:0] - tmp16 : esi[15:0] + tmp16; edi[15:0] <= flags[DF] ? edi[15:0] - tmp16 : edi[15:0] + tmp16; // При CMPSx всегда проверяется REPZ/REPNZ // При любом REP должен быть декрементирован CX if (sel_rep) ecx[15:0] <= ecx[15:0] - 1; if (sel_rep && sel_rep[0] == flags_o[ZF]) ip <= ipstart; end endcase // STOSx 8'b1010_101x: case (tstate) 0: begin tstate <= 1; isize <= opcode[0]; seg_ea <= seg_es; ea <= edi[15:0]; wb <= eax; op2 <= opcode[0] ? (opsize ? 4 : 2) : 1; // Если REP и CX=0, то пропуск инструкции if (sel_rep && ecx[15:0] == 0) mode <= PREPARE; else begin sel <= 1; mode <= SETEA; end end 1: begin sel <= 0; mode <= PREPARE; // Увеличить/Уменьшить DI edi[15:0] <= flags[DF] ? edi[15:0] - op2 : edi[15:0] + op2; // Если есть префикс REP: то повторить инструкцию if (sel_rep) begin ecx[15:0] <= ecx[15:0] - 1; ip <= ipstart; end end endcase // LODSx 8'b1010_110x: case (tstate) 0: begin tstate <= 1; estate <= 4; isize <= opcode[0]; ea <= esi[15:0]; op1 <= 0; op2 <= opcode[0] ? (opsize ? 4 : 2) : 1; // Если REP и CX=0, то пропуск инструкции if (sel_rep && ecx[15:0] == 0) mode <= PREPARE; else begin sel <= 1; mode <= FETCHEA; end end 1: begin sel <= 0; mode <= PREPARE; // Загрузка в Acc if (isize && opsize) eax <= op1; else if (isize) eax[15:0] <= op1[15:0]; else eax[7:0] <= op1[7:0]; esi[15:0] <= flags[DF] ? esi[15:0] - op2 : esi[15:0] + op2; if (sel_rep) begin ecx[15:0] <= ecx[15:0] - 1; ip <= ipstart; end end endcase // SCASx 8'b1010_111x: case (tstate) 0: begin // Читать ES:DI tstate <= 1; idir <= 1; isize <= opcode[0]; seg_ea <= seg_es; ea <= edi[15:0]; op1 <= eax; tmp16 <= opcode[0] ? (opsize ? 4 : 2) : 1; alumode <= 7; // alu=CMP // Если REP и CX=0, то пропуск инструкции if (sel_rep && ecx[15:0] == 0) begin sel <= 0; mode <= PREPARE; end else begin sel <= 1; mode <= FETCHEA; estate <= 4; end end 1: begin // Инкременты sel <= 0; mode <= PREPARE; flags <= flags_o; edi[15:0] <= flags[DF] ? edi[15:0] - tmp16 : edi[15:0] + tmp16; // Учет префикса REP: if (sel_rep) ecx[15:0] <= ecx[15:0] - 1; if (sel_rep && sel_rep[0] == flags_o[ZF]) ip <= ipstart; end endcase // ==== Все инструкции ==== // PUSH sr 8'b00_0xx_110: case (tstate) 0: begin tstate <= 1; mode <= PUSH; case (opcode[4:3]) 2'b00: wb <= seg_es; 2'b01: wb <= seg_cs; 2'b10: wb <= seg_ss; 2'b11: wb <= seg_ds; endcase end 1: mode <= PREPARE; endcase // POP sr 8'b00_0xx_111: case (tstate) 0: begin tstate <= 1; mode <= POP; end 1: begin tstate <= 2; mode <= LOADSEG; regn <= opcode[4:3]; end 2: mode <= PREPARE; endcase // DAA|DAS|AAA|AAS 8'b00_1xx_111: case (tstate) 0: begin tstate <= 1; op1 <= eax[15:0]; alumode <= opcode[4:3]; end 1: begin mode <= PREPARE; flags <= flags_d; if (opcode[4]) eax[15:0] <= daa_r; else eax[ 7:0] <= daa_r[7:0]; end endcase // INC|DEC r 8'b01_00x_xxx: case (tstate) 0: begin tstate <= 1; op2 <= 1; regn <= opcode[2:0]; isize <= 1'b1; end 1: begin tstate <= 2; op1 <= regv; alumode <= opcode[3] ? /*SUB*/ 5 : /*ADD*/ 0; end 2: begin tstate <= 3; mode <= SETEA; idir <= 1'b1; wb <= result; flags <= {flags_o[11:1], flags[0]}; modrm[5:3] <= regn; end 3: mode <= PREPARE; endcase // PUSH r 8'b01_010_xxx: case (tstate) 0: begin tstate <= 1; regn <= opcode[2:0]; isize <= 1'b1; end 1: begin tstate <= 2; wb <= regv; mode <= PUSH; end 2: mode <= PREPARE; endcase // POP r 8'b01_011_xxx: case (tstate) 0: begin tstate <= 1; mode <= POP; {idir, isize} <= 2'b11; end 1: begin tstate <= 2; mode <= SETEA; modrm[5:3] <= opcode[2:0]; end 2: begin mode <= PREPARE; end endcase // Jccc b8 8'b0111_xxxx: begin // Проверка на выполнение условия в branches if (branches[ opcode[3:1] ] ^ opcode[0]) ip <= ip + 1 + {{8{bus[7]}}, bus[7:0]}; else ip <= ip + 1; mode <= PREPARE; end // TEST rm, r 8'b1000_010x: case (tstate) 0: begin tstate <= 1; {idir, isize} <= opcode[1:0]; mode <= FETCHEA; alumode <= 4; end 1: begin flags <= flags_o; sel <= 0; mode <= PREPARE; end endcase // XCHG rm, r 8'b1000_011x: case (tstate) 0: begin tstate <= 1; {idir, isize} <= opcode[1:0]; mode <= FETCHEA; alumode <= 4; end 1: begin tstate <= 2; wb <= op2; mode <= SETEA; end 2: begin tstate <= 3; wb <= op1; mode <= SETEA; idir <= 0; end 3: begin sel <= 0; mode <= PREPARE; end endcase // MOV rmr 8'b1000_10xx: case (tstate) 0: begin tstate <= 1; {idir, isize} <= opcode[1:0]; mode <= FETCHEA; end 1: begin tstate <= 2; wb <= op2; mode <= SETEA; end 2: begin sel <= 0; mode <= PREPARE; end endcase // LEA r16, ea 8'b1000_1101: case (tstate) 0: begin tstate <= 1; {idir, isize} <= 2'b11; mode <= FETCHEA; skip_op <= 1; end 1: begin tstate <= 2; wb <= ea; mode <= SETEA; end 2: begin sel <= 0; mode <= PREPARE; end endcase // MOV sreg|rm 8'b1000_11x0: case (tstate) 0: begin tstate <= 1; {isize, idir} <= opcode[2:1]; skip_op <= ~opcode[1]; mode <= FETCHEA; end 1: begin tstate <= 2; // MOV sr, r16 if (opcode[1]) begin mode <= LOADSEG; regn <= modrm[5:3]; wb <= op2; end // MOV rm, sr else begin mode <= SETEA; case (modrm[5:3]) 0: wb <= seg_es; 1: wb <= seg_cs; 2: wb <= seg_ss; 3: wb <= seg_ds; 4: wb <= seg_fs; 5: wb <= seg_gs; endcase end end 2: begin sel <= 0; mode <= PREPARE; end endcase // POP rm 8'b1000_1111: case (tstate) 0: begin tstate <= 1; mode <= POP; {idir, isize} <= 2'b01; op1 <= seg_ea; end 1: begin tstate <= 2; mode <= FETCHEA; skip_op <= 1; seg_ea <= op1; end 2: begin tstate <= 3; mode <= SETEA; end 3: begin sel <= 0; mode <= PREPARE; end endcase // XCHG ax, r 8'b1001_0000: mode <= PREPARE; 8'b1001_0xxx: case (tstate) 0: begin tstate <= 1; regn <= opcode[2:0]; modrm[5:3] <= opcode[2:0]; {isize, idir} <= 2'b11; end 1: begin tstate <= 2; mode <= SETEA; wb <= eax; if (opsize) eax <= regv; else eax[15:0] <= regv; end 2: begin sel <= 0; mode <= PREPARE; end endcase // CBW, CWDE 8'b1001_1000: begin if (opsize) eax[31:16] <= {16{eax[15]}}; else eax[15:8] <= {8{eax[7]}}; mode <= PREPARE; end // CWD, CDQ 8'b1001_1001: begin if (opsize) edx <= {32{eax[31]}}; else edx[15:0] <= {16{eax[15]}}; mode <= PREPARE; end // CALL far 8'b1001_1010: case (tstate) 0: begin tstate <= 1; isize <= 1; mode <= IMMEDIATE; end 1: begin tstate <= 2; opsize <= 0; mode <= IMMEDIATE; op1 <= wb; end 2: begin tstate <= 3; mode <= PUSH; wb <= seg_cs; op2 <= wb; end 3: begin tstate <= 4; mode <= PUSH; wb <= ip; end 4: begin tstate <= 5; mode <= LOADSEG; wb <= op2; regn <= 1; ip <= op1; end 5: begin mode <= PREPARE; end endcase // PUSHF 8'b1001_1100: case (tstate) 0: begin tstate <= 1; mode <= PUSH; wb <= {flags[11:6],1'b0,flags[4],1'b0,flags[2],1'b1,flags[0]}; end 1: begin sel <= 0; mode <= PREPARE; end endcase // POPF 8'b1001_1101: case (tstate) 0: begin tstate <= 1; mode <= POP; end 1: begin flags <= wb[11:0]; sel <= 0; mode <= PREPARE; end endcase // SAHF, LAHF 8'b1001_1110: begin flags[7:0] <= eax[15:8]; mode <= PREPARE; end 8'b1001_1111: begin eax[15:8] <= flags[7:0]; mode <= PREPARE; end // MOV r,# 8'b1011_xxxx: case (tstate) 0: begin tstate <= 1; idir <= 1; isize <= opcode[3]; modrm[5:3] <= opcode[2:0]; mode <= IMMEDIATE; end 1: begin tstate <= 2; mode <= SETEA; end 2: mode <= PREPARE; endcase // MOV ac, [m16] 8'b1010_00xx: case (tstate) 0: begin // Чтение imm8/16/32 tstate <= 1; opsizet <= opsize; opsize <= adsize; isize <= 1; mode <= IMMEDIATE; end 1: begin // Запрос на чтение из памяти или запись в память tstate <= 2; sel <= 1; modrm <= 0; idir <= 0; isize <= opcode[0]; opsize <= opsizet; ea <= wb; // acc -> mem if (opcode[1]) begin mode <= SETEA; wb <= eax; end else // mem -> acc begin mode <= FETCHEA; sel <= 1; estate <= 4; end end 2: begin // Запись в регистр ACC или выход sel <= 0; mode <= PREPARE; // Запись в регистр AL, AX, EAX if (opcode[1] == 0) begin if (isize && opsize) eax <= op1; else if (isize) eax[15:0] <= op1[15:0]; else eax[7:0] <= op1[7:0]; end end endcase // TEST eax, # 8'b1010_100x: case (tstate) 0: begin tstate <= 1; isize <= opcode[0]; mode <= IMMEDIATE; end 1: begin tstate <= 2; alumode <= 4; op1 <= eax; op2 <= wb; end 2: begin flags <= flags_o; sel <= 0; mode <= PREPARE; end endcase // RET [i16] 8'b1100_001x: case (tstate) // Если opcode[0]=0, imm16 0: begin tstate <= 1; isize <= 1; mode <= POP; end 1: begin tstate <= 2; op1 <= wb; if (opcode[0] == 0) mode <= IMMEDIATE; end 2: begin ip <= op1; sel <= 0; mode <= PREPARE; // Если RET imm, то добавить к стеку if (opcode[0] == 0) begin if (stack32) esp <= esp + wb; else esp[15:0] <= esp[15:0] + wb; end end endcase // LES|LDS r16, [m] 8'b1100_010x: case (tstate) 0: begin tstate <= 1; {idir, isize} <= 2'b11; mode <= FETCHEA; end 1: begin tstate <= 2; mode <= SETEA; wb <= op2; end 2: begin tstate <= 3; ea <= ea + opsize ? 4 : 2; end 3: begin tstate <= 4; wb[7:0] <= bus; ea <= ea + 1; end 4: begin tstate <= 5; wb[15:8] <= bus; regn <= opcode[0] ? 3 : 0; mode <= LOADSEG; sel <= 0; end 5: begin mode <= PREPARE; end endcase // MOV rm, # 8'b1100_011x: case (tstate) 0: begin tstate <= 1; {idir, isize} <= {1'b0, opcode[0]}; skip_op <= 1; mode <= FETCHEA; end 1: begin tstate <= 2; sel <= 0; mode <= IMMEDIATE; end 2: begin tstate <= 3; sel <= 1; mode <= SETEA; end 3: begin sel <= 0; mode <= PREPARE; end endcase // RETF 8'b1100_101x: case (tstate) 0: begin tstate <= 1; isize <= 1; mode <= POP; end 1: begin tstate <= 2; op1 <= wb; mode <= POP; end 2: begin tstate <= 3; op2 <= wb; if (opcode[0] == 0) mode <= IMMEDIATE; end 3: begin tstate <= 4; ip <= op1; wb <= op2; regn <= 1; sel <= 0; mode <= LOADSEG; if (opcode[0] == 0) begin if (stack32) esp <= esp + wb; else esp[15:0] <= esp[15:0] + wb; end end 4: mode <= PREPARE; endcase // INT 1/3 8'b1111_0001, 8'b1100_1100: case (tstate) 0: begin tstate <= 1; wb <= opcode[0] ? 1 : 3; mode <= INTERRUPT; end 1: begin mode <= PREPARE; end endcase // INT i8 8'b1100_1101: case (tstate) 0: begin tstate <= 1; isize <= 0; mode <= IMMEDIATE; end 1: begin tstate <= 2; mode <= INTERRUPT; end 2: begin mode <= PREPARE; end endcase // INTO: Вызов INT4 если OF=1 8'b1100_1110: case (tstate) 0: begin tstate <= 1; wb <= 4; mode <= flags[OF] ? INTERRUPT : PREPARE; end 1: mode <= PREPARE; endcase // IRET 8'b1100_1111: case (tstate) 0: begin tstate <= 1; mode <= POP; end 1: begin tstate <= 2; mode <= POP; op1 <= wb; end 2: begin tstate <= 3; mode <= POP; op2 <= wb; end 3: begin tstate <= 4; mode <= LOADSEG; regn <= 1; ip <= op1; wb <= op2; flags <= wb; end 4: mode <= PREPARE; endcase // Сдвиговые инструкции (IMM) 8'b1100_000x: case (tstate) 0: begin tstate <= 1; mode <= FETCHEA; {idir, isize} <= opcode[1:0]; end 1: begin tstate <= 2; mode <= IMMEDIATE; sel <= 0; isize <= 0; opsizet <= isize; end 2: begin tstate <= 3; mode <= SHIFT; alumode <= modrm[5:3]; op2 <= wb; isize <= opsizet; end 3: begin tstate <= 4; mode <= SETEA; sel <= 1; wb <= op1; end 4: begin sel <= 0; mode <= PREPARE; end endcase // Сдвиговые инструкции (CL,N) 8'b1101_00xx: case (tstate) 0: begin tstate <= 1; mode <= FETCHEA; {idir, isize} <= {1'b0, opcode[0]}; end 1: begin tstate <= 2; mode <= SHIFT; alumode <= modrm[5:3]; op2 <= opcode[1] ? ecx[4:0] : 1; end 2: begin tstate <= 3; mode <= SETEA; wb <= op1; end 3: begin sel <= 0; mode <= PREPARE; end endcase // AAM 8'b1101_0100: case (tstate) 0: begin tstate <= 1; divcnt <= 8; diva <= {eax[7:0], 56'b0}; divb <= bus; wb <= 0; mode <= bus ? DIVIDE : INTERRUPT; ip <= ip + 1; end 1: begin sel <= 0; mode <= PREPARE; if (divb) begin eax[15:0] <= {divres[7:0], divrem[7:0]}; flags[ZF] <= eax[15:0] == 0; flags[SF] <= eax[15]; flags[PF] <= ~^eax[15]; end end endcase // AAD 8'b1101_0101: case (tstate) 0: begin tstate <= 1; eax[15:0] <= eax[15:8]*bus + eax[7:0]; ip <= ip + 1; end 1: begin mode <= PREPARE; flags[ZF] <= eax[15:0] == 0; flags[SF] <= eax[15]; flags[PF] <= ~^eax[15]; end endcase // SALC 8'b1101_0110: begin eax[7:0] <= {8{flags[CF]}}; mode <= PREPARE; end // XLATB 8'b1101_0111: case (tstate) 0: begin sel <= 1; tstate <= 1; ea <= ebx[15:0] + eax[7:0]; end 1: begin sel <= 0; eax[7:0] <= bus; mode <= PREPARE; end endcase // JCXZ 8'b1110_0011: begin mode <= PREPARE; if ((opsize && ecx == 0) || (!adsize && ecx[15:0] == 0)) ip <= ip + 1 + {{24{bus[7]}}, bus[7:0]}; else ip <= ip + 1; end // LOOPNZ, LOOPZ, LOOP 8'b1110_00xx: begin if (adsize) ecx <= ecx - 1; else ecx[15:0] <= ecx[15:0] - 1; // ZF=0/1 и CX != 0 (после декремента) if (((flags[ZF] == opcode[0]) || opcode[1]) && (adsize ? ecx : ecx[15:0]) != 1) ip <= ip + 1 + {{24{bus[7]}}, bus[7:0]}; else ip <= ip + 1; mode <= PREPARE; end // IN eAX, dx/i8 8'b1110_x10x: case (tstate) 0: begin tstate <= 1; if (opcode[3] == 0) ip <= ip + 1; port <= opcode[3] ? edx[15:0] : bus; op1 <= opcode[0] ? (opsize ? 3 : 1) : 0; op2 <= 0; end 1: begin tstate <= 2; port_clk <= 1; end 2: begin tstate <= 3; port_clk <= 0; end 3: begin tstate <= 1; case (op2[1:0]) 0: eax[7:0] <= port_i; 1: eax[15:8] <= port_i; 2: eax[23:16] <= port_i; 3: eax[31:24] <= port_i; endcase port <= port + 1; op2[1:0] <= op2[1:0] + 1; if (op1[1:0] == op2[1:0]) mode <= PREPARE; end endcase // OUT dx/i8, eAX 8'b1110_x11x: case (tstate) 0: begin tstate <= 1; if (opcode[3] == 0) ip <= ip + 1; port <= opcode[3] ? edx[15:0] : bus; op1 <= opcode[0] ? (opsize ? 3 : 1) : 0; op2 <= 0; end 1: begin tstate <= 2; case (op2[1:0]) 0: port_o <= eax[7:0]; 1: port_o <= eax[15:8]; 2: port_o <= eax[23:16]; 3: port_o <= eax[31:24]; endcase port_w <= 1; port_clk <= 1; end 2: begin tstate <= 3; port_w <= 0; port_clk <= 0; end 3: begin tstate <= 1; port <= port + 1; op2[1:0] <= op2[1:0] + 1; if (op1[1:0] == op2[1:0]) mode <= PREPARE; end endcase // CALL b16 8'b1110_1000: case (tstate) 0: begin tstate <= 1; isize <= 1; mode <= IMMEDIATE; end 1: begin tstate <= 2; wb <= ip; ip <= ip + wb; mode <= PUSH; end 2: begin mode <= PREPARE; end endcase // JMP b16 8'b1110_1001: case (tstate) 0: begin tstate <= 1; isize <= 1; mode <= IMMEDIATE; end 1: begin mode <= PREPARE; ip <= ip + wb; end endcase // JMP b16:c16 8'b1110_1010: case (tstate) 0: begin tstate <= 1; isize <= 1; mode <= IMMEDIATE; end 1: begin tstate <= 2; op1 <= wb; opsize <= 0; mode <= IMMEDIATE; end 2: begin tstate <= 3; mode <= LOADSEG; regn <= 1; ip <= op1; end 3: begin mode <= PREPARE; end endcase // JMP b8 8'b1110_1011: begin ip <= ip + 1 + {{8{bus[7]}}, bus[7:0]}; mode <= PREPARE; end // HLT 8'b1111_0100: begin ip <= ip - 1; mode <= PREPARE; end // CMC, CLC, STC, CLI, STI, CLD, STD 8'b1111_0101: begin flags[CF] <= ~flags[CF]; mode <= PREPARE; end 8'b1111_100x: begin flags[CF] <= opcode[0]; mode <= PREPARE; end 8'b1111_101x: begin flags[IF] <= opcode[0]; mode <= PREPARE; end 8'b1111_110x: begin flags[DF] <= opcode[0]; mode <= PREPARE; end // Коды расширенных инструкции // ============================================================= // Jccc NEAR b16 9'b1_1000_xxxx: case (tstate) 0: begin tstate <= 1; wb <= bus; ip <= ip + 1; end 1: begin if (branches[opcode[3:1]] ^ opcode[0]) ip <= ip + (adsize ? 3 : 1) + {bus, wb[7:0]}; else ip <= ip + (adsize ? 3 : 1); mode <= PREPARE; end endcase // RDTSC 9'b1_0011_0001: begin eax <= rdtsc[31:0]; edx <= rdtsc[63:32]; mode <= PREPARE; end endcase // Считывание эффективного адреса и регистров FETCHEA: case (estate) 0: begin modrm <= bus; ip <= ip + 1; // Операнд 1 case (idir ? bus[5:3] : bus[2:0]) 0: op1 <= isize ? (opsize ? eax : eax[15:0]) : eax[ 7:0]; 1: op1 <= isize ? (opsize ? ecx : ecx[15:0]) : ecx[ 7:0]; 2: op1 <= isize ? (opsize ? edx : edx[15:0]) : edx[ 7:0]; 3: op1 <= isize ? (opsize ? ebx : ebx[15:0]) : ebx[ 7:0]; 4: op1 <= isize ? (opsize ? esp : esp[15:0]) : eax[15:8]; 5: op1 <= isize ? (opsize ? ebp : ebp[15:0]) : ecx[15:8]; 6: op1 <= isize ? (opsize ? esi : esi[15:0]) : edx[15:8]; 7: op1 <= isize ? (opsize ? edi : edi[15:0]) : ebx[15:8]; endcase // Операнд 2 case (idir ? bus[2:0] : bus[5:3]) 0: op2 <= isize ? (opsize ? eax : eax[15:0]) : eax[ 7:0]; 1: op2 <= isize ? (opsize ? ecx : ecx[15:0]) : ecx[ 7:0]; 2: op2 <= isize ? (opsize ? edx : edx[15:0]) : edx[ 7:0]; 3: op2 <= isize ? (opsize ? ebx : ebx[15:0]) : ebx[ 7:0]; 4: op2 <= isize ? (opsize ? esp : esp[15:0]) : eax[15:8]; 5: op2 <= isize ? (opsize ? ebp : ebp[15:0]) : ecx[15:8]; 6: op2 <= isize ? (opsize ? esi : esi[15:0]) : edx[15:8]; 7: op2 <= isize ? (opsize ? edi : edi[15:0]) : ebx[15:8]; endcase // Вычисление эффективного адреса 32 bit if (adsize) case (bus[2:0]) 0: ea <= eax; 1: ea <= ecx; 2: ea <= edx; 3: ea <= ebx; // 4: SIB 5: ea <= ebp; 6: ea <= esi; 7: ea <= edi; endcase else // Вычисление эффективного адреса 16 bit case (bus[2:0]) 0: ea[15:0] <= ebx[15:0] + esi[15:0]; 1: ea[15:0] <= ebx[15:0] + edi[15:0]; 2: ea[15:0] <= ebp[15:0] + esi[15:0]; 3: ea[15:0] <= ebp[15:0] + edi[15:0]; 4: ea[15:0] <= esi[15:0]; 5: ea[15:0] <= edi[15:0]; 6: ea[15:0] <= ebp[15:0]; 7: ea[15:0] <= ebx[15:0]; endcase // Выбор SS: по умолчанию if (!sel_seg) begin // 32 bit if (adsize) begin if (bus[2:0] == 5 && ^bus[7:6]) seg_ea <= seg_ss; end // 16 bit else if ((bus[2:0] == 3'h6 && ^bus[7:6]) || (bus[2:1] == 2'b01)) seg_ea <= seg_ss; end // 32 bit if (adsize) casex (bus) 8'b11_xxx_xxx: begin estate <= 0; mode <= MAIN; end // reg 8'b00_xxx_101: begin estate <= 8; ea <= 0; end // disp32 8'bxx_xxx_100: begin estate <= 12; end // sib 8'b00_xxx_xxx: begin estate <= 4; sel <= 1; end // без disp 8'b01_xxx_xxx: begin estate <= 3; end // disp8 8'b10_xxx_xxx: begin estate <= 8; end // disp32 endcase // 16 bit else casex (bus) 8'b00_xxx_110: begin estate <= 1; ea <= 0; end // disp16 8'b00_xxx_xxx: begin estate <= 4; sel <= 1; end // без disp 8'b01_xxx_xxx: begin estate <= 3; end // disp8 8'b10_xxx_xxx: begin estate <= 1; end // disp16 8'b11_xxx_xxx: begin estate <= 0; mode <= MAIN; end endcase end // Считывание 16-бит displacement 1: begin estate <= 2; ip <= ip + 1; ea <= ea + bus; end 2: begin estate <= 4; ip <= ip + 1; ea[15:8] <= ea[15:8] + bus; ea[31:16] <= 0; sel <= 1; end // Считывание 8-бит displacement 3: begin estate <= 4; ip <= ip + 1; sel <= 1; if (adsize) ea <= ea + {{24{bus[7]}}, bus[7:0]}; else ea[15:0] <= ea[15:0] + {{8{bus[7]}}, bus[7:0]}; end // Чтение операнда 8bit из памяти 4: begin if (skip_op) begin estate <= 0; mode <= MAIN; end else begin if (idir) op2 <= bus; else op1 <= bus; if (isize) begin estate <= 5; ea <= ea + 1; end else begin estate <= 0; mode <= MAIN; end end end // Чтение операнда 16 бит (память) 5: begin if (idir) op2[15:8] <= bus; else op1[15:8] <= bus; if (opsize) begin estate <= 6; ea <= ea + 1; end else begin estate <= 0; ea <= ea - 1; mode <= MAIN; end end // Чтение операнда 32 бит (память) 6: begin estate <= 7; if (idir) op2[23:16] <= bus; else op1[23:16] <= bus; ea <= ea + 1; end 7: begin estate <= 0; if (idir) op2[31:24] <= bus; else op1[31:24] <= bus; ea <= ea - 3; mode <= MAIN; end // Чтение +disp32 и переход к чтение операнда из памяти 8: begin tstate <= 9; ip <= ip + 1; ea <= ea + bus; end 9: begin tstate <= 10; ip <= ip + 1; ea[31:8] <= ea[31:8] + bus; end 10: begin tstate <= 11; ip <= ip + 1; ea[31:16] <= ea[31:16] + bus; end 11: begin tstate <= 4; ip <= ip + 1; ea[31:24] <= ea[31:24] + bus; sel <= 1; end // Разбор байта SIB: Считывание SS*INDEX 12: begin estate <= 13; casex (bus) 8'bxx_000_xxx: ea <= eax << bus[7:6]; 8'bxx_001_xxx: ea <= ecx << bus[7:6]; 8'bxx_010_xxx: ea <= edx << bus[7:6]; 8'bxx_011_xxx: ea <= ebx << bus[7:6]; 8'bxx_100_xxx: ea <= 0; 8'bxx_101_xxx: ea <= ebp << bus[7:6]; 8'bxx_110_xxx: ea <= esi << bus[7:6]; 8'bxx_111_xxx: ea <= edi << bus[7:6]; endcase // Выбор сегмента SS: по умолчанию if (!sel_seg && bus[5:3] == 5) seg_ea <= seg_ss; end // Считывание BASE 13: begin estate <= 4; sel <= 1; ip <= ip + 1; case (bus[2:0]) // disp32 3'b000: ea <= ea + eax; 3'b001: ea <= ea + ecx; 3'b010: ea <= ea + edx; 3'b011: ea <= ea + ebx; 3'b100: ea <= ea + esp; 3'b101: if (^modrm[7:6]) begin ea <= ea + ebp; if (!sel_seg) seg_ea <= seg_ss; end 3'b110: ea <= ea + esi; 3'b111: ea <= ea + edi; endcase // +disp8/32 if (modrm[7:6] == 2'b00 && bus[2:0] == 5) begin sel <= 0; estate <= 8; end else if (modrm[7:6] == 2'b01) begin sel <= 0; estate <= 3; end else if (modrm[7:6] == 2'b10) begin sel <= 0; estate <= 8; end end endcase // Запись обратно в память или регистр [idir, isize, modrm, wb] // * idir (1 запись `wb` в регистр modrm[5:3]) // (0 запись в память ea) // * isize (0/1) // * wb (8/16) SETEA: case (estate) 0: begin // Запись результата в регистр if (idir || (modrm[7:6] == 2'b11)) begin case (idir ? modrm[5:3] : modrm[2:0]) 0: if (isize && opsize) eax <= wb; else if (isize) eax[15:0] <= wb; else eax[ 7:0] <= wb[7:0]; 1: if (isize && opsize) ecx <= wb; else if (isize) ecx[15:0] <= wb; else ecx[ 7:0] <= wb[7:0]; 2: if (isize && opsize) edx <= wb; else if (isize) edx[15:0] <= wb; else edx[ 7:0] <= wb[7:0]; 3: if (isize && opsize) ebx <= wb; else if (isize) ebx[15:0] <= wb; else ebx[ 7:0] <= wb[7:0]; 4: if (isize && opsize) esp <= wb; else if (isize) esp[15:0] <= wb; else eax[15:8] <= wb[7:0]; 5: if (isize && opsize) ebp <= wb; else if (isize) ebp[15:0] <= wb; else ecx[15:8] <= wb[7:0]; 6: if (isize && opsize) esi <= wb; else if (isize) esi[15:0] <= wb; else edx[15:8] <= wb[7:0]; 7: if (isize && opsize) edi <= wb; else if (isize) edi[15:0] <= wb; else ebx[15:8] <= wb[7:0]; endcase mode <= MAIN; end // Запись [7:0] в память else begin estate <= 1; wreq <= 1; data <= wb[7:0]; end end // Запись [15:8] или завершение 1: begin if (isize) begin estate <= 2; data <= wb[15:8]; ea <= ea + 1; end else begin estate <= 0; wreq <= 0; mode <= MAIN; end end // Завершение записи 16 bit 2: begin if (opsize) begin estate <= 3; data <= wb[23:16]; ea <= ea + 1; end else begin estate <= 0; wreq <= 0; mode <= MAIN; ea <= ea - 1; end end // Завершение записи 32 bit 3: begin estate <= 4; data <= wb[31:24]; ea <= ea + 1; end 4: begin estate <= 0; wreq <= 0; mode <= MAIN; ea <= ea - 3; end endcase // Получение imm8/16/32 [isize] IMMEDIATE: case (estate) 0: begin ip <= ip + 1; wb <= bus; if (isize == 0) mode <= MAIN; else begin estate <= 1; end end 1: begin ip <= ip + 1; wb[ 15:8] <= bus; if (opsize) estate <= 2; else begin estate <= 0; mode <= MAIN; end end 2: begin ip <= ip + 1; wb[23:16] <= bus; estate <= 3; end 3: begin ip <= ip + 1; wb[31:24] <= bus; estate <= 0; mode <= MAIN; end endcase // Сохранение данных в стек [wb] // Если стек 32-х разрядный, используются 4 байта PUSH: case (estate) 0: begin estate <= 1; sel <= 1; wreq <= 1; seg_ea <= seg_ss; data <= wb[7:0]; if (stack32) begin ea <= esp - 4; esp <= esp - 4; end else begin ea <= esp[15:0] - (opsize ? 4 : 2); esp[15:0] <= esp[15:0] - (opsize ? 4 : 2); end end 1: begin estate <= 2; ea <= ea + 1; data <= wb[15:8]; end 2: begin if (opsize) begin ea <= ea + 1; data <= wb[23:16]; estate <= 3; end else begin estate <= 0; sel <= 0; wreq <= 0; mode <= MAIN; end end 3: begin estate <= 4; ea <= ea + 1; data <= wb[31:24]; end 4: begin estate <= 0; sel <= 0; wreq <= 0; mode <= MAIN; end endcase // Извлечение данных из стека -> wb POP: case (estate) 0: begin estate <= 1; sel <= 1; seg_ea <= seg_ss; if (stack32) begin ea <= esp; esp <= esp - 4; end else begin ea <= esp[15:0]; esp[15:0] <= esp[15:0] + (opsize ? 4 : 2); end end 1: begin estate <= 2; wb <= bus; ea <= ea + 1; end 2: begin wb[15:8] <= bus; if (opsize) begin estate <= 3; ea <= ea + 1; end else begin estate <= 0; sel <= 0; mode <= MAIN; end end 3: begin estate <= 4; wb[23:16] <= bus; ea <= ea + 1; end 4: begin estate <= 0; wb[31:24] <= bus; sel <= 0; mode <= MAIN; end endcase // Загрузка и проверка нового сегментного регистра [regn, wb] LOADSEG: case (estate) 0: begin // Если это было прерывание if (is_intr) begin mode <= PREPARE; end else mode <= MAIN; case (regn) 3'b000: seg_es <= wb; 3'b001: seg_cs <= wb; 3'b010: seg_ss <= wb; 3'b011: seg_ds <= wb; 3'b100: seg_fs <= wb; 3'b101: seg_gs <= wb; endcase end endcase // Вызов прерывания [wb] INTERRUPT: case (estate) // Запись в стек CS:IP:FLAGS 0: begin estate <= 1; sel <= 1; wreq <= 1; seg_ea <= seg_ss; data <= ip[7:0]; if (stack32) begin ea <= esp - 4*3; esp <= esp - 4*3; end else begin ea <= esp[15:0] - 2*3; esp[15:0] <= esp[15:0] - 2*3; end end 1: begin data <= ip[15:8]; estate <= stack32 ? 2 : 4; ea <= ea + 1; end // 2, 3 4: begin data <= seg_cs[ 7:0]; estate <= 5; ea <= ea + 1; end 5: begin data <= seg_cs[15:8]; estate <= stack32 ? 6 : 8; ea <= ea + 1; end // 6, 7 8: begin data <= flags[7:0]; estate <= 9; ea <= ea + 1; end 9: begin data <= flags[11:8]; estate <= stack32 ? 10 : 12; ea <= ea + 1; end // 10, 11 12: begin estate <= 13; wreq <= 0; flags[IF] <= 1'b0; flags[TF] <= 1'b0; seg_ea <= 0; ea <= {wb, 2'b00}; end // Загрузка нового CS:IP из IVT 13: begin estate <= 14; ip[7:0] <= bus; ea <= ea + 1; end 14: begin estate <= 15; ip[15:8] <= bus; ea <= ea + 1; end 15: begin estate <= 16; wb[7:0] <= bus; ea <= ea + 1; end 16: begin estate <= 0; wb[15:8] <= bus; sel <= 0; regn <= 1; mode <= LOADSEG; end // 32-х битный default: begin estate <= estate + 1; data <= 0; ea <= ea + 1; end endcase // Сдвиги: // * alumode=операция // * isize, opsize // * op1 // * op2 SHIFT: case (estate) // Вычисление ограничения количества сдвигов // Если сдвиг не задан (0), то не срабатывает 0: begin estate <= 1; if (isize && opsize) begin wb <= 31; op2 <= op2[4:0]; if (op2[4:0] == 0) begin estate <= 0; mode <= MAIN; end end else if (isize) // DosBox так обрабатывает (4:0) begin wb <= 15; op2 <= op2[4:0]; if (op2[4:0] == 0) begin estate <= 0; mode <= MAIN; end end else begin wb <= 7; op2 <= op2[2:0]; if (op2[2:0] == 0) begin estate <= 0; mode <= MAIN; end end end // Вычисление 1: begin // Сдвиги if (op2) begin op2 <= op2 - 1; case (alumode) /* ROL */ 0: begin op1 <= isize ? (opsize ? {op1[30:0],op1[31]} : {op1[14:0],op1[15]}) : {op1[6:0],op1[7]}; end /* ROR */ 1: begin op1 <= isize ? (opsize ? {op1[0],op1[31:1]} : {op1[0],op1[15:1]}) : {op1[0],op1[7:1]}; end /* RCL */ 2: begin op1 <= isize ? (opsize ? {op1[30:0],flags[CF]} : {op1[14:0],flags[CF]}) : {op1[6:0],flags[CF]}; flags[CF] <= op1[wb]; end /* RCR */ 3: begin op1 <= isize ? (opsize ? {flags[CF],op1[31:1]} : {flags[CF],op1[15:1]}) : {flags[CF],op1[7:1]}; flags[CF] <= op1[0]; end /* SHL */ 4, 6: begin flags[CF] <= op1[wb-op2+1]; op1 <= op1 << op2; op2 <= 0; end /* SHR */ 5: begin flags[CF] <= op1[op2-1]; op1 <= op1 >> op2; op2 <= 0; end /* SAR */ 7: begin op1 <= isize ? (opsize ? {op1[31],op1[31:1]} : {op1[15],op1[15:1]}) : {op1[7],op1[7:1]}; flags[CF] <= op1[0]; end endcase end // Расчет флагов else begin estate <= 0; mode <= MAIN; case (alumode) 0: begin flags[CF] <= op1[0]; flags[OF] <= op1[0] ^ op1[wb]; end 1: begin flags[CF] <= op1[wb]; flags[OF] <= op1[wb] ^ op1[wb-1]; end 2: begin flags[OF] <= flags[CF] ^ op1[wb]; end 3: begin flags[OF] <= op1[wb] ^ op1[wb-1]; end default: begin flags[ZF] <= !op1; flags[SF] <= op1[wb]; flags[PF] <= ~^op1[7:0]; flags[AF] <= 1; end endcase end end endcase // Процедура деления [diva, divb, divcnt] DIVIDE: begin if (divcnt) begin divrem <= {divrem,diva[63]} >= divb ? {divrem,diva[63]} - divb : {divrem,diva[63]}; divres <= {divres[62:0], {divrem,diva[63]} >= divb}; diva <= {diva[62:0], 1'b0}; divcnt <= divcnt - 1; end else mode <= MAIN; end endcase // --------------------------------------------------------------------- // АРИФМЕТИКО-ЛОГИКА // --------------------------------------------------------------------- wire [31:0] result = isize ? (opsize ? res[31:0] : res[15:0]) : res[7:0]; reg [15:0] daa_r; reg [11:0] flags_o; reg [11:0] flags_d; reg [32:0] res; // Десятичная коррекция reg daa_a; reg daa_c; reg daa_x; reg [8:0] daa_i; reg [7:0] daa_h; // Верхний бит 7, 15 или 31 wire [3:0] signx = isize ? (opsize ? 31 : 15) : 7; wire parity = ~^res[7:0]; wire zerof = isize ? (opsize ? ~|res : ~|res[15:0]) : ~|res[7:0]; wire carryf = res[signx + 1]; wire signf = res[signx]; wire auxf = op1[4]^op2[4]^res[4]; // Самая хитрая логика из всего тут wire add_o = (op1[isize] ^ op2[isize] ^ 1) & (op1[isize] ^ res[isize]); wire sub_o = (op1[isize] ^ op2[isize] ^ 0) & (op1[isize] ^ res[isize]); // Общие АЛУ always @* begin case (alumode) /* ADD */ 0: res = op1 + op2; /* OR */ 1: res = op1 | op2; /* ADC */ 2: res = op1 + op2 + flags[0]; /* SBB */ 3: res = op1 - op2 - flags[0]; /* AND */ 4: res = op1 & op2; /* SUB */ 5, /* CMP */ 7: res = op1 - op2; /* XOR */ 6: res = op1 ^ op2; endcase case (alumode) // ADD | ADC 0, 2: flags_o = { /* O */ add_o, /* D */ flags[10], /* I */ flags[9], /* T */ flags[8], /* S */ signf, /* Z */ zerof, /* 0 */ 1'b0, /* A */ auxf, /* 0 */ 1'b0, /* P */ parity, /* 1 */ 1'b1, /* C */ carryf }; // SBB | SUB | CMP 3, 5, 7: flags_o = { /* O */ sub_o, /* D */ flags[10], /* I */ flags[9], /* T */ flags[8], /* S */ signf, /* Z */ zerof, /* 0 */ 1'b0, /* A */ auxf, /* 0 */ 1'b0, /* P */ parity, /* 1 */ 1'b1, /* C */ carryf }; // OR, AND, XOR одинаковые флаги 1, 4, 6: flags_o = { /* O */ 1'b0, /* D */ flags[10], /* I */ flags[9], /* T */ flags[8], /* S */ signf, /* Z */ zerof, /* 0 */ 1'b0, /* A */ 1'b0, /* 0 */ 1'b0, /* P */ parity, /* 1 */ 1'b1, /* C */ 1'b0 }; endcase end // Десятичная коррекция always @* begin daa_r = op1[7:0]; flags_d = flags; case (alumode) // DAA, DAS 0, 1: begin daa_c = flags[0]; daa_a = flags[4]; daa_i = op1[7:0]; // Младший ниббл if (op1[3:0] > 9 || flags[4]) begin daa_i = alumode[0] ? op1[7:0]-6 : op1[7:0]+6; daa_c = daa_i[8]; daa_a = 1; end daa_r = daa_i[7:0]; daa_x = daa_c; // Старший ниббл if (daa_c || daa_i[7:0] > 8'h9F) begin daa_r = alumode[0] ? daa_i[7:0]-8'h60 : daa_i[7:0]+8'h60; daa_x = 1; end flags_d[7] = daa_r[7]; // S flags_d[6] = ~|daa_r[7:0]; // Z flags_d[4] = daa_a; // A flags_d[2] = ~^daa_r[7:0]; // P flags_d[0] = daa_x; // C end // AAA, AAS 2, 3: begin daa_i = op1[ 7:0]; daa_r = op1[15:0]; if (flags[4] || op1[3:0] > 9) begin daa_i = alumode[0] ? op1[ 7:0] - 6 : op1[ 7:0] + 6; daa_h = alumode[0] ? op1[15:8] - 1 : op1[15:8] + 1; daa_r = {daa_h, 4'h0, daa_i[3:0]}; flags_d[4] = 1; // AF=1 flags_d[0] = 1; // CF=1 end else begin flags_d[4] = 0; flags_d[0] = 0; end end endcase end endmodule