§ Исходный код ядра
/** * Небольшой процессор с ограниченным набором инструкции */ module c8086 ( // Основной контур для процессора input clock, input ce, input reset_n, output [19:0] address, input [ 7:0] in, // in = ram[address] output reg [ 7:0] out, output reg we, output m0, // M0-считывание инструкции // Порты ввода-вывода output reg [15:0] port_a, output reg port_w, output reg port_r, input [ 7:0] port_i, output reg [ 7:0] port_o, // PIC: Программируемый контроллер прерываний input irq, // Срабатывает на posedge input [ 7:0] irq_in // Номер IRQ (0..255) ); // Выбор текущего адреса, segment_id[2] = 1 означает прерывание assign address = cp ? {segment, 4'h0} + ea : {cs, 4'h0} + ip; assign m0 = (fn == START); localparam ALU_ROL = 0, ALU_ROR = 1, ALU_RCL = 2, ALU_RCR = 3, ALU_SHL = 4, ALU_SHR = 5, ALU_SAL = 6, ALU_SAR = 7; localparam ALU_ADD = 0, ALU_OR = 1, ALU_ADC = 2, ALU_SBB = 3, ALU_AND = 4, ALU_SUB = 5, ALU_XOR = 6, ALU_CMP = 7; localparam CF = 0, PF = 2, AF = 4, ZF = 6, SF = 7, TF = 8, IF = 9, DF = 10, OF = 11; localparam REG_AX = 0, REG_CX = 1, REG_DX = 2, REG_BX = 3, REG_SP = 4, REG_BP = 5, REG_SI = 6, REG_DI = 7; localparam START = 0, LOAD = 1, MODRM = 2, INSTR = 3, INTR = 4, WBACK = 5, PUSH = 6, POP = 7, REPF = 8, UNDEF = 9; // ----------------------------------------------------------------------------- wire [15:0] signex = {{8{in[7]}}, in}; wire [15:0] rin = in[2:0] == REG_AX ? ax : in[2:0] == REG_CX ? cx : in[2:0] == REG_DX ? dx : in[2:0] == REG_BX ? bx : in[2:0] == REG_SP ? sp : in[2:0] == REG_BP ? bp : in[2:0] == REG_SI ? si : di; // Вычисление условий 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], flags[SF], flags[CF] | flags[OF], // 3: CF != OF flags[ZF], flags[CF], flags[OF] }; // Управляющие регистры и регистры общего назначения // ----------------------------------------------------------------------------- reg cp, size, dir, cpen, over, rep_ft, iack, trace_ff; reg [15:0] ax, bx, cx, dx, sp, bp, si, di; reg [15:0] es, cs, ss, ds; reg [ 1:0] rep; reg [ 3:0] fn, fnext, s1, s2; reg [ 7:0] opcode, modrm; reg [15:0] segment, ea, wb, ip, ip_start; reg [ 7:0] intr; reg [ 2:0] alu; reg [15:0] op1, op2; reg [11:0] flags; // Исполнительный блок // ----------------------------------------------------------------------------- always @(posedge clock) if (reset_n == 1'b0) begin fn <= START; cs <= 16'hF000; es <= 16'h0000; ds <= 16'h0000; ss <= 16'h0000; sp <= 16'h0000; ip <= 16'hFFF0; iack <= 1'b0; // ODIT SZ A P C flags <= 12'b0010_0000_0010; end else if (ce) begin port_r <= 0; // Строб чтения из порта port_w <= 0; // Строб записи в порт case (fn) // Сброс перед запуском инструкции // ------------------------------------------------------------- START: begin fn <= LOAD; fnext <= START; // Возврат по умолчанию s1 <= 0; s2 <= 0; cp <= 0; // address = CS:IP cpen <= 1; // Считывать из памяти modrm rm-часть modrm <= 0; segment <= ds; // Значение сегмента по умолчанию DS: over <= 1'b0; // Наличие сегментного префикса rep <= 2'b0; // Нет префикса REP: ea <= 0; // Эффективный адрес we <= 0; // Разрешение записи rep_ft <= 0; // =0 REP, =1 REPZ|NZ wb <= 0; // Данные на запись (modrm | reg) ip_start <= ip; // Для REP: // IRQ прерывание вызывается, если счетчик изменился (iack != irq_signal) и IF=1 if ((iack ^ irq) && flags[IF]) begin fn <= irq ? INTR : LOAD; intr <= irq_in; iack <= irq; end // TF=1 (Trace Flag включен) и IF=1 else if (flags[IF] && flags[TF] && trace_ff) begin fn <= INTR; intr <= 1; end // FlipFlop: сначала выполнится инструкция, потом вызывается INT 1 if (flags[IF] && flags[TF]) trace_ff <= ~trace_ff; end // Дешифратор опкода // ------------------------------------------------------------- LOAD: begin // Параметры по умолчанию fn <= LOAD; ip <= ip + 1; size <= in[0]; dir <= in[1]; alu <= in[5:3]; opcode <= in; // Поиск опкода по маске casex (in) // Сегментные префиксы 8'b00100110: begin segment <= es; over <= 1; end 8'b00101110: begin segment <= cs; over <= 1; end 8'b00110110: begin segment <= ss; over <= 1; end 8'b00111110: begin segment <= ds; over <= 1; end // REPNZ, REPZ 8'b1111001x: begin rep <= in[1:0]; end // FS, GS, OpSize, AdSize, Ext 8'b00001111, 8'b0110010x, 8'b0110011x, // NOP, LOCK: FWAIT 8'b10010000, 8'b10011011, 8'b11110000: begin /* LOAD */ end // ALU rm | ALU a,imm 8'b00xxx0xx: begin fn <= MODRM; end 8'b00xxx10x: begin fn <= INSTR; end // MOV rm, i | LEA r, m 8'b1100011x, 8'b10001101: begin fn <= MODRM; cpen <= 0; end // INC | DEC r 8'b0100xxxx: begin fn <= INSTR; alu <= in[3] ? ALU_SUB : ALU_ADD; op1 <= rin; op2 <= 1; size <= 1; end // XCHG r, a 8'b10010xxx: begin fn <= WBACK; ax <= rin; wb <= ax; dir <= 1; size <= 1; modrm[5:3] <= in[2:0]; end // PUSH r 8'b01010xxx: begin fn <= PUSH; wb <= rin; end // POP r,s,etc. 8'b01011xxx, // POP r 8'b000xx111, // POP s 8'b10011101, // POPF 8'b1100101x, // RETF [i] 8'b1x001111, // POP rm; IRET; RET [i] 8'b1100001x: begin fn <= POP; fnext <= INSTR; end // PUSH s 8'b00000110: begin fn <= PUSH; wb <= es; end 8'b00001110: begin fn <= PUSH; wb <= cs; end 8'b00010110: begin fn <= PUSH; wb <= ss; end 8'b00011110: begin fn <= PUSH; wb <= ds; end // PUSHF 8'b10011100: begin fn <= PUSH; wb <= flags; end // CLx/STx, CMC 8'b1111100x: begin fn <= START; flags[CF] <= in[0]; end 8'b1111101x: begin fn <= START; flags[IF] <= in[0]; end 8'b1111110x: begin fn <= START; flags[DF] <= in[0]; end 8'b11110101: begin fn <= START; flags[CF] <= ~flags[CF]; end // SAHF, LAHF 8'b10011110: begin fn <= START; flags <= ax[15:8]; end 8'b10011111: begin fn <= START; ax[15:8] <= flags[7:0] | 2; end // SALC 8'b11010110: begin fn <= START; ax[ 7:0] <= {8{flags[CF]}}; end // HALT 8'b11110100: begin fn <= START; ip <= ip; end // Grp#1 ALU; XCHG rm, r 8'b100000xx, 8'b1000011x: begin fn <= MODRM; dir <= 0; end // TEST rm | TEST a,i 8'b1000010x: begin fn <= MODRM; alu <= ALU_AND; end // CBW, CWD 8'b10011000: begin fn <= START; ax[15:8] <= {8{ax[7]}}; end 8'b10011001: begin fn <= START; dx <= {16{ax[15]}}; end // MOV s,rm 8'b10001110: begin fn <= MODRM; size <= 1; end // XLATB 8'b11010111: begin fn <= INSTR; ea <= bx + ax[7:0]; cp <= 1; end // LES|LDS r,m 8'b1100010x: begin fn <= MODRM; size <= 1; dir <= 1; end // INT 1,3; INTO 8'b11110001: begin intr <= 1; fn <= INTR; end 8'b11001100: begin intr <= 3; fn <= INTR; end 8'b11001110: begin intr <= 4; fn <= flags[OF] ? INTR : START; end // Grp#4|5; Сдвиги 8'b1111x11x, 8'b1100000x, 8'b110100xx: begin fn <= MODRM; dir <= 0; end // Jccc; JCXZ 8'b0111xxxx, 8'b11100011: begin if ((branches[ in[3:1] ] == in[0] && !in[7]) || (in[7] && cx)) begin fn <= START; ip <= ip + 2; end else begin fn <= INSTR; end end // LOOP[NZ|Z] 8'b111000xx: begin // Если бит 1 равен 1, то ZF=bit[0] не имеет значения if ((cx != 1) && (in[1] || flags[ZF] == in[0])) begin fn <= INSTR; end else begin fn <= START; ip <= ip + 2; end cx <= cx - 1; end // Определить наличие байта ModRM для опкода default: casex (in) 8'b1000xxxx, 8'b1100000x, 8'b110001xx, 8'b011010x1, 8'b110100xx, 8'b11011xxx, 8'b1111x11x, 8'b0110001x: fn <= MODRM; default: fn <= INSTR; endcase endcase end // Считывание MODRM // ------------------------------------------------------------- MODRM: case (s1) // Считывание адреса или регистров 0: begin modrm <= in; ip <= ip + 1; // Первый операнд (dir=1 будет выбрана reg-часть) case (dir ? in[5:3] : in[2:0]) REG_AX: op1 <= size ? ax : ax[ 7:0]; REG_CX: op1 <= size ? cx : cx[ 7:0]; REG_DX: op1 <= size ? dx : dx[ 7:0]; REG_BX: op1 <= size ? bx : bx[ 7:0]; REG_SP: op1 <= size ? sp : ax[15:8]; REG_BP: op1 <= size ? bp : cx[15:8]; REG_SI: op1 <= size ? si : dx[15:8]; REG_DI: op1 <= size ? di : bx[15:8]; endcase // Второй операнд (dir=1 будет выбрана rm-часть) case (dir ? in[2:0] : in[5:3]) REG_AX: op2 <= size ? ax : ax[ 7:0]; REG_CX: op2 <= size ? cx : cx[ 7:0]; REG_DX: op2 <= size ? dx : dx[ 7:0]; REG_BX: op2 <= size ? bx : bx[ 7:0]; REG_SP: op2 <= size ? sp : ax[15:8]; REG_BP: op2 <= size ? bp : cx[15:8]; REG_SI: op2 <= size ? si : dx[15:8]; REG_DI: op2 <= size ? di : bx[15:8]; endcase // Подготовка эффективного адреса case (in[2:0]) 3'b000: ea <= bx + si; 3'b001: ea <= bx + di; 3'b010: ea <= bp + si; 3'b011: ea <= bp + di; 3'b100: ea <= si; 3'b101: ea <= di; 3'b110: ea <= in[7:6] == 2'b00 ? 0 : bp; // disp16 | bp 3'b111: ea <= bx; endcase // Выбор сегмента SS: для BP if (!over) casex (in) 8'bxx_xxx_01x, // [bp+si|di] 8'b01_xxx_110, // [bp+d8|d16] 8'b10_xxx_110: segment <= ss; endcase // Переход сразу к исполнению инструкции: операнды уже получены casex (in) 8'b00_xxx_110: begin s1 <= 2; end // +disp16 // Читать операнд из памяти 8'b00_xxx_xxx: begin s1 <= cpen ? 4 : 0; cp <= cpen; if (!cpen) fn <= INSTR; end 8'b01_xxx_xxx: begin s1 <= 1; end // +disp8 8'b10_xxx_xxx: begin s1 <= 2; end // +disp16 8'b11_xxx_xxx: begin s1 <= 0; fn <= INSTR; end // Перейти к исполнению default: begin s1 <= 1; end endcase end // Чтение 8 битного signed disp 1: begin s1 <= 4; ip <= ip + 1; ea <= ea + signex; cp <= cpen; if (!cpen) begin s1 <= 0; fn <= INSTR; end end // Чтение 16 битного unsigned disp16 2: begin s1 <= 3; ip <= ip + 1; ea <= ea + in; end 3: begin s1 <= 4; ip <= ip + 1; cp <= cpen; ea <= ea + {in, 8'h00}; if (!cpen) begin s1 <= 0; fn <= INSTR; end end // Чтение операнда из памяти 8 bit 4: begin if (dir) op2 <= in; else op1 <= in; if (size) begin s1 <= 5; ea <= ea + 1; end else begin s1 <= 0; fn <= INSTR; end end // Операнд 16 bit 5: begin if (dir) op2[15:8] <= in; else op1[15:8] <= in; s1 <= 0; fn <= INSTR; ea <= ea - 1; end endcase // Исполнение инструкции // ------------------------------------------------------------- INSTR: casex (opcode) 8'b00xxx0xx: begin // <alu> rm wb <= alu_r; flags <= alu_f; fn <= (alu != ALU_CMP) ? WBACK : START; end 8'b00xxx10x: case (s2) // <alu> a, imm // Инициализация 0: begin op1 <= size ? ax : ax[7:0]; op2 <= in; s2 <= size ? 1 : 2; ip <= ip + 1; end // Считывание старшего байта 1: begin s2 <= 2; op2[15:8] <= in; ip <= ip + 1; end // Запись в регистр и выход из процедуры 2: begin fn <= START; flags <= alu_f; if (alu != ALU_CMP) begin if (size) ax <= alu_r; else ax[7:0] <= alu_r[7:0]; end end endcase 8'b1011xxxx: case (s2) // MOV r, i // 8 bit 0: begin s2 <= 1; dir <= 1; size <= opcode[3]; modrm[5:3] <= opcode[2:0]; wb <= in; ip <= ip + 1; if (opcode[3] == 0) fn <= WBACK; end // 16 bit 1: begin wb[15:8] <= in; fn <= WBACK; ip <= ip + 1; end endcase 8'b100010xx: begin // MOV rm wb <= op2; fn <= WBACK; end 8'b1100011x: case (s2) // MOV rm, i // 8 bit 0: begin s2 <= 1; wb <= in; dir <= 0; ip <= ip + 1; if (size == 0) begin fn <= WBACK; cp <= 1; end end // 16 bit 1: begin fn <= WBACK; cp <= 1; ip <= ip + 1; wb[15:8] <= in; end endcase 8'b10001101: begin // LEA r16, m wb <= ea; size <= 1; dir <= 1; fn <= WBACK; end 8'b0100xxxx: begin // INC | DEC r16 fn <= WBACK; modrm[5:3] <= opcode[2:0]; dir <= 1; wb <= alu_r; flags <= {alu_f[11:1], flags[CF]}; end 8'b01011xxx: begin // POP r fn <= WBACK; size <= 1; dir <= 1; modrm[5:3] <= opcode[2:0]; end 8'b000xx111: begin // POP s fn <= START; case (opcode[4:3]) 2'b00: es <= wb; 2'b01: cs <= wb; 2'b10: ss <= wb; 2'b11: ds <= wb; endcase end 8'b100000xx: case (s2) // <alu> imm // Считывание imm и номера кода операции 0: begin s2 <= 1; alu <= modrm[5:3]; cpen <= cp; cp <= 0; end 1: begin s2 <= 2; op2 <= in; ip <= ip + 1; end 2: begin s2 <= 3; case (opcode[1:0]) 2'b01: begin op2[15:8] <= in; ip <= ip + 1; end // imm16 2'b11: begin op2[15:8] <= {8{op2[7]}}; end // sign8 endcase end // Запись 3: begin cp <= cpen; wb <= alu_r; flags <= alu_f; fn <= (alu != ALU_CMP) ? WBACK : START; end endcase 8'b101000xx: case (s2) // MOV a,[m] | [m],a // Прочесть адрес 0: begin ea[ 7:0] <= in; ip <= ip + 1; s2 <= 1; end 1: begin ea[15:8] <= in; ip <= ip + 1; cp <= 1; s2 <= dir ? 2 : 5; end // Запись A в память 2: begin we <= 1; out <= ax[ 7:0]; s2 <= size ? 3 : 4; end 3: begin we <= 1; out <= ax[15:8]; s2 <= 4; ea <= ea + 1; end 4: begin fn <= START; we <= 0; end // Чтение A из памяти 5: begin s2 <= 6; ax[ 7:0] <= in; ea <= ea + 1; if (!size) fn <= START; end 6: begin fn <= START; ax[15:8] <= in; end endcase 8'b1000010x: begin // TEST rm,r flags <= alu_f; fn <= START; end 8'b100001xx: case (s2) // XCHG rm,r 0: begin fn <= WBACK; fnext <= INSTR; s2 <= 1; dir <= 1; wb <= op1; end 1: begin fn <= WBACK; fnext <= START; dir <= 0; wb <= op2; end endcase 8'b10011101: begin // POPF fn <= START; flags <= wb | 2; end 8'b1010100x: case (s2) // TEST a,i // Считывание младшего байта 0: begin s2 <= size ? 1 : 2; alu <= ALU_AND; op1 <= ax; op2 <= in; ip <= ip + 1; end // Если size, считывание старшего байта 1: begin s2 <= 2; op2[15:8] <= in; ip <= ip + 1; end // Запись результата в АЛУ 2: begin flags <= alu_f; fn <= START; end endcase 8'b0111xxxx, // Jccc 8'b111000xx, // LOOPNZ, JCXZ 8'b11101011: begin // JMP b8 fn <= START; ip <= ip + 1 + signex; end 8'b11101001: case (s2) // JMP b16 0: begin s2 <= 1; ip <= ip + 1; ea[7:0] <= in; end 1: begin fn <= START; ip <= ip + 1 + {in, ea[7:0]}; end endcase 8'b11101010: case (s2) // JMP far // Прочитаьть 4 байта для нового CS:IP 0: begin ip <= ip + 1; s2 <= 1; ea <= in; end 1: begin ip <= ip + 1; s2 <= 2; ea[15:8] <= in; end 2: begin ip <= ip + 1; s2 <= 3; op1 <= in; end 3: begin ip <= ea; cs <= {in, op1[7:0]}; fn <= START; end endcase 8'b11101000: case (s2) // CALL b16 0: begin s2 <= 1; ea <= in; ip <= ip + 1; end 1: begin fn <= PUSH; wb <= ip + 1; ip <= ip + 1 + {in, ea[7:0]}; end endcase 8'b11000011: begin // RET fn <= START; ip <= wb; end 8'b11000010: case (s2) // RET i16 0: begin s2 <= 1; ea <= in; ip <= ip + 1; end 1: begin fn <= START; ip <= wb; sp <= sp + {in, ea[7:0]}; end endcase 8'b1100101x: case (s2) // RETF; RETF i16 0: begin fn <= POP; s2 <= 1; op1 <= wb; op2 <= in; ip <= ip + 1; end 1: begin fn <= START; cs <= wb; ip <= op1; if (!opcode[0]) sp <= sp + {in, op2[7:0]}; end endcase 8'b11001111: case (s2) // IRET 0: begin s2 <= 1; fn <= POP; ip <= wb; end 1: begin s2 <= 2; fn <= POP; cs <= wb; end 2: begin fn <= START; flags <= wb[11:0] | 2; end endcase 8'b10001100: begin // MOV rm,s fn <= WBACK; size <= 1; case (modrm[4:3]) 2'b00: wb <= es; 2'b01: wb <= cs; 2'b10: wb <= ss; 2'b11: wb <= ds; endcase end 8'b10001110: begin // MOV s,rm fn <= START; case (modrm[4:3]) 0: es <= op2; 1: cs <= op2; 2: ss <= op2; 3: ds <= op2; endcase end 8'b10011010: case (s2) // CALLF b16 0: begin s2 <= 1; ip <= ip + 1; op1[ 7:0] <= in; end 1: begin s2 <= 2; ip <= ip + 1; op1[15:8] <= in; end 2: begin s2 <= 3; ip <= ip + 1; op2[ 7:0] <= in; end 3: begin s2 <= 4; ip <= ip + 1; op2[15:8] <= in; fn <= PUSH; wb <= cs; fnext <= INSTR; end 4: begin s2 <= 5; fn <= PUSH; wb <= ip; fnext <= INSTR; end 5: begin ip <= op1; fn <= START; cs <= op2; end endcase 8'b1100010x: case (s2) // LES|LDS r,m 0: begin s2 <= 1; ea <= ea + 2; end 1: begin s2 <= 2; wb[7:0] <= in; ea <= ea + 1; end 2: begin fn <= WBACK; wb <= op2; if (opcode[0]) ds <= {in, wb[7:0]}; else es <= {in, wb[7:0]}; end endcase 8'b10001111: case (s2) // POP rm 0: begin s2 <= 1; cpen <= 0; fn <= MODRM; dir <= 0; end 1: begin cp <= 1; fn <= WBACK; fnext <= START; end endcase 8'b011010x0: case (s2) // PUSH i 0: begin s2 <= opcode[1] ? 2 : 1; wb <= signex; ip <= ip + 1; end 1: begin s2 <= 2; wb[15:8] <= in; ip <= ip + 1; end 2: begin fn <= PUSH; fnext <= START; end endcase 8'b11010111: begin // XLATB fn <= START; ax[7:0] <= in; end 8'b11001101: begin // INT i fn <= INTR; intr <= in; ip <= ip + 1; end 8'b1100000x, 8'b110100xx: case (s2) // Grp#2 Сдвиги // Выбор второго операнда // Если тут был указатель на памятьЮ, то сбросить его 0: if (cp) cp <= 0; else begin s2 <= 1; alu <= modrm[5:3]; if (opcode[4]) begin op2 <= (opcode[1] ? cx[3:0] : 1); end else begin op2 <= in[3:0]; ip <= ip + 1; end end // Процедура сдвига на 0..15 шагов 1: begin // Вычисление if (op2) begin op1 <= rot_r; flags <= rot_f; end // Запись результата else begin wb <= op1; cp <= 1; fn <= WBACK; end op2 <= op2 - 1; end endcase 8'b1110x10x: case (s2) // IN a,p // Чтение номера порта 0: begin s2 <= 1; cpen <= 0; port_a <= opcode[3] ? dx : in; if (!opcode[3]) ip <= ip + 1; end // Чтение, ожидание результата 1 такт 1: begin s2 <= 2; port_r <= 1; end 2: begin s2 <= 3; end // Запись ответа в AL|AH 3: begin if (size) begin s2 <= 1; cpen <= 1; end else fn <= START; if (cpen) ax[15:8] <= port_i; else ax[ 7:0] <= port_i; port_a <= port_a + 1; size <= 0; end endcase 8'b1110x11x: case (s2) // OUT p,a 0: begin s2 <= 1; port_a <= opcode[3] ? dx : in; port_o <= ax[7:0]; port_w <= 1; if (!opcode[3]) ip <= ip + 1; if (!size) fn <= START; end 1: begin port_a <= port_a + 1; port_o <= ax[15:8]; port_w <= 1; fn <= START; end endcase 8'b1111011x: case (modrm[5:3]) // Grp#3 // TEST imm8/16 0, 1: case (s2) 0: begin s2 <= 1; cp <= 0; alu <= ALU_AND; end 1: begin s2 <= size ? 2 : 3; op2 <= in; ip <= ip + 1; end 2: begin s2 <= 3; op2[15:8] <= in; ip <= ip + 1; end 3: begin fn <= START; flags <= alu_f; end endcase // NOT rm 2: begin wb <= ~op1; fn <= WBACK; end // NEG rm 3: case (s2) 0: begin s2 <= 1; alu <= ALU_SUB; op2 <= op1; op1 <= 0; end 1: begin fn <= WBACK; wb <= alu_r; flags <= alu_f; end endcase endcase 8'b1111111x: case (modrm[5:3]) // Grp#4|5 // INC|DEC rm 0, 1: case (s2) 0: begin s2 <= 1; op2 <= 1; alu <= modrm[3] ? ALU_SUB : ALU_ADD; end 1: begin fn <= WBACK; wb <= alu_r; flags <= alu_f; end endcase // CALL rm 2: begin ip <= op1; wb <= ip; fn <= size ? PUSH : UNDEF; end // CALL far rm 3: case (s2) 0: begin s2 <= 1; ea <= ea + 2; ip <= op1; op1 <= ip; op2 <= cs; if (size == 0) fn <= UNDEF; end 1: begin s2 <= 2; ea <= ea + 1; wb <= in; fnext <= INSTR; end 2: begin s2 <= 3; fn <= PUSH; cs <= {in, wb[7:0]}; wb <= op2; end 3: begin s2 <= 4; fn <= PUSH; wb <= op1; end 4: begin fn <= START; end endcase // JMP rm 4: begin ip <= op1; fn <= size ? START : UNDEF; end // JMP far rm 5: case (s2) 0: begin s2 <= 1; ea <= ea + 2; ip <= op1; if (size == 0) fn <= UNDEF; end 1: begin s2 <= 2; ea <= ea + 1; wb <= in; end 2: begin fn <= START; cs <= {in, wb[7:0]}; end endcase // PUSH rm 6: begin wb <= op1; fn <= PUSH; end 7: begin fn <= UNDEF; end endcase 8'b1010101x: case (s2) // STOSx 0: begin // STOSB s2 <= size ? 1 : 2; cp <= 1; we <= 1; ea <= di; out <= ax[7:0]; segment <= es; end 1: begin // STOSW s2 <= 2; we <= 1; ea <= ea + 1; out <= ax[15:8]; end 2: begin we <= 0; fn <= rep[1] ? REPF : START; cp <= 0; di <= flags[DF] ? di - (size + 1) : di + (size + 1); size <= 1; end endcase 8'b1010110x: case (s2) // LODSx 0: begin s2 <= 1; cp <= 1; ea <= si; end 1: begin s2 <= size ? 2 : 3; ea <= ea + 1; ax[7:0] <= in; end 2: begin s2 <= 3; ax[15:8] <= in; end 3: begin fn <= rep[1] ? REPF : START; cp <= 0; si <= flags[DF] ? si - (opcode[0] + 1) : si + (opcode[0] + 1); size <= 1; end endcase 8'b1010010x: case (s2) // MOVSx // Загрузка 8 или 16 бит DS:SI 0: begin s2 <= 1; ea <= si; cp <= 1; end 1: begin s2 <= size ? 2 : 3; wb <= in; ea <= ea + 1; end 2: begin s2 <= 3; wb[15:8] <= in; end // Запись 8 или 16 бит ES:DI 3: begin s2 <= size ? 4 : 5; we <= 1; ea <= di; segment <= es; out <= wb[7:0]; end 4: begin s2 <= 5; we <= 1; ea <= ea + 1; out <= wb[15:8]; end // Инкремент или декремент SI 5: begin s2 <= 6; we <= 0; cp <= 0; si <= flags[DF] ? si - (opcode[0] + 1) : si + (opcode[0] + 1); size <= 1; end // Инкремент или декремент DI 6: begin s2 <= 6; di <= flags[DF] ? di - (opcode[0] + 1) : di + (opcode[0] + 1); // Использование REP: fn <= rep[1] ? REPF : START; end endcase 8'b1010011x: case (s2) // CMPSx 0: begin s2 <= 1; cp <= 1; ea <= si; alu <= ALU_SUB; end 1: begin s2 <= size ? 2 : 3; op1 <= in; ea <= ea + 1; end 2: begin s2 <= 3; op1[15:8] <= in; end 3: begin s2 <= 4; segment <= es; ea <= di; end 4: begin s2 <= size ? 5 : 6; op2 <= in; ea <= ea + 1; end 5: begin s2 <= 6; op2[15:8] <= in; end // Инкремент или декремент SI 6: begin s2 <= 7; flags <= alu_f; cp <= 0; si <= flags[DF] ? si - (opcode[0] + 1) : si + (opcode[0] + 1); size <= 1; end // Инкремент или декремент DI 7: begin rep_ft <= 1; // Проверять на REPNZ или REPZ di <= flags[DF] ? di - (opcode[0] + 1) : di + (opcode[0] + 1); // Использование REP: fn <= rep[1] ? REPF : START; end endcase 8'b1010111x: case (s2) // SCASx 0: begin s2 <= 1; cp <= 1; alu <= ALU_SUB; op1 <= ax; ea <= di; segment <= es; end 1: begin s2 <= size ? 2 : 3; op2 <= in; ea <= ea + 1; end 2: begin s2 <= 3; op2[15:8] <= in; end // Инкремент или декремент DI 3: begin flags <= alu_f; cp <= 0; rep_ft <= 1; // Проверять на REPNZ или REPZ di <= flags[DF] ? di - (opcode[0] + 1) : di + (opcode[0] + 1); fn <= rep[1] ? REPF : START; // Использование REP: end endcase endcase // Прерывание intr; считается за выполнение инструкции // ------------------------------------------------------------- INTR: case (s2) 0: begin s2 <= 1; fn <= PUSH; wb <= flags; fnext <= INTR; end 1: begin s2 <= 2; fn <= PUSH; wb <= cs; end 2: begin s2 <= 3; fn <= PUSH; wb <= ip; end 3: begin s2 <= 4; ea <= {intr, 2'b00}; segment <= 0; cp <= 1; end 4: begin s2 <= 5; ea <= ea + 1; ip[ 7:0] <= in; end 5: begin s2 <= 6; ea <= ea + 1; ip[15:8] <= in; end 6: begin s2 <= 7; ea <= ea + 1; cs[ 7:0] <= in; end 7: begin cp <= 0; ea <= ea + 1; cs[15:8] <= in; fn <= START; flags[IF] <= 1'b0; end endcase // Сохранение данных [wb, size, dir, modrm] // ------------------------------------------------------------- WBACK: case (s1) // Выбор - регистр или память 0: begin // reg-часть или rm:reg if (dir || modrm[7:6] == 2'b11) begin cp <= 0; s1 <= 0; fn <= fnext; case (dir ? modrm[5:3] : modrm[2:0]) REG_AX: if (size) ax <= wb; else ax[ 7:0] <= wb[7:0]; REG_CX: if (size) cx <= wb; else cx[ 7:0] <= wb[7:0]; REG_DX: if (size) dx <= wb; else dx[ 7:0] <= wb[7:0]; REG_BX: if (size) bx <= wb; else bx[ 7:0] <= wb[7:0]; REG_SP: if (size) sp <= wb; else ax[15:8] <= wb[7:0]; REG_BP: if (size) bp <= wb; else cx[15:8] <= wb[7:0]; REG_SI: if (size) si <= wb; else dx[15:8] <= wb[7:0]; REG_DI: if (size) di <= wb; else bx[15:8] <= wb[7:0]; endcase end // Если modrm указывает на память, записать первые 8 бит else begin out <= wb[7:0]; we <= 1; s1 <= 1; end end // Запись 16 бит | Либо завершение 8/16 бит записи 1: if (size) begin size <= 0; ea <= ea + 1; out <= wb[15:8]; end else begin s1 <= 0; cp <= 0; we <= 0; fn <= fnext; end endcase // Запись в стек <= wb [cp,ea,segment] // ------------------------------------------------------------- PUSH: case (s1) 0: begin s1 <= 1; out <= wb[ 7:0]; ea <= sp - 2; we <= 1; cp <= 1; segment <= ss; end 1: begin s1 <= 2; out <= wb[15:8]; ea <= ea + 1; end 2: begin s1 <= 0; we <= 0; cp <= 0; sp <= sp - 2; fn <= fnext; end endcase // Чтение из стека => wb [cp,ea,segment] // ------------------------------------------------------------- POP: case (s1) 0: begin s1 <= 1; segment <= ss; ea <= sp; cp <= 1; end 1: begin s1 <= 2; wb[ 7:0] <= in; ea <= ea + 1; end 2: begin s1 <= 0; wb[15:8] <= in; cp <= 0; sp <= sp + 2; fn <= fnext; end endcase // Выполнение инструкции REP REPF: case (s1) // Уменьшить CX - 1 0: begin s1 <= 1; cx <= cx - 1; end 1: begin s1 <= 0; fn <= START; // CX=0, повтор закончен if (cx) begin // REPNZ|REPZ if (rep_ft) begin if (rep[0] == flags[ZF]) ip <= ip_start; end // REP: else ip <= ip_start; end end endcase // Деление op1 на op2, size -> wb // DIV: case (s5) // endcase endcase end // Арифметико-логическое устройство // --------------------------------------------------------------------- wire [16:0] alu_r = alu == ALU_ADD ? op1 + op2 : alu == ALU_OR ? op1 | op2 : alu == ALU_ADC ? op1 + op2 + flags[CF] : alu == ALU_SBB ? op1 - op2 - flags[CF] : alu == ALU_AND ? op1 & op2: alu == ALU_XOR ? op1 ^ op2: op1 - op2; // SUB, CMP wire [ 3:0] alu_top = size ? 15 : 7; wire [ 4:0] alu_up = alu_top + 1'b1; wire is_add = alu == ALU_ADD || alu == ALU_ADC; wire is_lgc = alu == ALU_XOR || alu == ALU_AND || alu == ALU_OR; wire alu_cf = alu_r[alu_up]; wire alu_af = op1[4] ^ op2[4] ^ alu_r[4]; wire alu_sf = alu_r[alu_top]; wire alu_zf = (size ? alu_r[15:0] : alu_r[7:0]) == 0; wire alu_pf = ~^alu_r[7:0]; wire alu_of = (op1[alu_top] ^ op2[alu_top] ^ is_add) & (op1[alu_top] ^ alu_r[alu_top]); wire [11:0] alu_f = { /* OF */ alu_of & ~is_lgc, /* DIT */ flags[10:8], /* SF */ alu_sf, /* ZF */ alu_zf, /* 5 */ 1'b0, /* AF */ alu_af & ~is_lgc, /* 3 */ 1'b0, /* PF */ alu_pf, /* 1 */ 1'b1, /* CF */ alu_cf & ~is_lgc }; // Сдвиговый регистр // --------------------------------------------------------------------- reg [15:0] rot_r; reg [11:0] rot_f; always @* begin rot_f = flags; case (alu) ALU_ROL: rot_r = size ? {op1[14:0], op1[15]} : {op1[6:0], op1[7]}; ALU_ROR: rot_r = size ? {op1[0], op1[15:1]} : {op1[0], op1[7:1]}; ALU_RCL: rot_r = size ? {op1[14:0], flags[CF]} : {op1[6:0], flags[CF]}; ALU_RCR: rot_r = size ? {flags[CF], op1[15:1]} : {flags[CF], op1[7:1]}; ALU_SHL, ALU_SAL: rot_r = size ? {op1[14:0], 1'b0} : {op1[6:0], 1'b0}; ALU_SHR: rot_r = size ? {1'b0, op1[15:1]} : {1'b0, op1[7:1]}; ALU_SHR: rot_r = size ? {op1[15], op1[15:1]} : {op1[7], op1[7:1]}; endcase // Флаг CF rot_f[CF] = alu[0] ? op1[0] : op1[alu_top]; // Флаг OF case (alu) ALU_ROL, ALU_RCL, ALU_SAL, ALU_SHL: rot_f[OF] = op1[alu_top] ^ op1[alu_top - 1]; ALU_ROR, ALU_RCR: rot_f[OF] = rot_r[alu_top] ^ rot_r[alu_top - 1]; ALU_SHR: rot_f[OF] = op1[alu_top]; ALU_SAR: rot_f[OF] = 1'b0; endcase // S, Z, P для 4 инструкции if (alu == ALU_SHL || alu == ALU_SHR || alu == ALU_SAL || alu == ALU_SHR) begin rot_f[SF] = rot_r[alu_top]; rot_f[ZF] = (size ? rot_r[15:0] : rot_r[7:0]) == 0; rot_f[PF] = ~^rot_r[7:0]; end end endmodule
23 мар, 2021
© 2007-2023 Ситуация крадет все права