§ Исходный код ядра
Ревизия 20210323
module c8086
(
input clock,
input ce,
input reset_n,
output [19:0] address,
input [ 7:0] in,
output reg [ 7:0] out,
output reg we,
output 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,
input irq,
input [ 7:0] irq_in
);
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],
(flags[SF] ^ flags[OF]),
flags[PF],
flags[SF],
flags[CF] | flags[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;
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;
cpen <= 1;
modrm <= 0;
segment <= ds;
over <= 1'b0;
rep <= 2'b0;
ea <= 0;
we <= 0;
rep_ft <= 0;
wb <= 0;
ip_start <= ip;
if ((iack ^ irq) && flags[IF]) begin
fn <= irq ? INTR : LOAD;
intr <= irq_in;
iack <= irq;
end
else if (flags[IF] && flags[TF] && trace_ff) begin
fn <= INTR;
intr <= 1;
end
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
8'b1111001x: begin rep <= in[1:0]; end
8'b00001111,
8'b0110010x,
8'b0110011x,
8'b10010000,
8'b10011011,
8'b11110000: begin end
8'b00xxx0xx: begin fn <= MODRM; end
8'b00xxx10x: begin fn <= INSTR; end
8'b1100011x,
8'b10001101: begin fn <= MODRM; cpen <= 0; end
8'b0100xxxx: begin
fn <= INSTR;
alu <= in[3] ? ALU_SUB : ALU_ADD;
op1 <= rin;
op2 <= 1;
size <= 1;
end
8'b10010xxx: begin
fn <= WBACK;
ax <= rin;
wb <= ax;
dir <= 1;
size <= 1;
modrm[5:3] <= in[2:0];
end
8'b01010xxx: begin fn <= PUSH; wb <= rin; end
8'b01011xxx,
8'b000xx111,
8'b10011101,
8'b1100101x,
8'b1x001111,
8'b1100001x: begin fn <= POP; fnext <= INSTR; end
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
8'b10011100: begin fn <= PUSH; wb <= flags; end
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
8'b10011110: begin fn <= START; flags <= ax[15:8]; end
8'b10011111: begin fn <= START; ax[15:8] <= flags[7:0] | 2; end
8'b11010110: begin fn <= START; ax[ 7:0] <= {8{flags[CF]}}; end
8'b11110100: begin fn <= START; ip <= ip; end
8'b100000xx,
8'b1000011x: begin fn <= MODRM; dir <= 0; end
8'b1000010x: begin fn <= MODRM; alu <= ALU_AND; end
8'b10011000: begin fn <= START; ax[15:8] <= {8{ax[7]}}; end
8'b10011001: begin fn <= START; dx <= {16{ax[15]}}; end
8'b10001110: begin fn <= MODRM; size <= 1; end
8'b11010111: begin fn <= INSTR; ea <= bx + ax[7:0]; cp <= 1; end
8'b1100010x: begin fn <= MODRM; size <= 1; dir <= 1; end
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
8'b1111x11x,
8'b1100000x,
8'b110100xx: begin fn <= MODRM; dir <= 0; end
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
8'b111000xx: begin
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
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: case (s1)
0: begin
modrm <= in;
ip <= ip + 1;
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
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;
3'b111: ea <= bx;
endcase
if (!over)
casex (in)
8'bxx_xxx_01x,
8'b01_xxx_110,
8'b10_xxx_110: segment <= ss;
endcase
casex (in)
8'b00_xxx_110: begin s1 <= 2; end
8'b00_xxx_xxx: begin s1 <= cpen ? 4 : 0; cp <= cpen; if (!cpen) fn <= INSTR; end
8'b01_xxx_xxx: begin s1 <= 1; end
8'b10_xxx_xxx: begin s1 <= 2; end
8'b11_xxx_xxx: begin s1 <= 0; fn <= INSTR; end
default: begin s1 <= 1; end
endcase
end
1: begin
s1 <= 4;
ip <= ip + 1;
ea <= ea + signex;
cp <= cpen;
if (!cpen) begin s1 <= 0; fn <= INSTR; end
end
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
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
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
wb <= alu_r;
flags <= alu_f;
fn <= (alu != ALU_CMP) ? WBACK : START;
end
8'b00xxx10x: case (s2)
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)
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
1: begin
wb[15:8] <= in;
fn <= WBACK;
ip <= ip + 1;
end
endcase
8'b100010xx: begin
wb <= op2;
fn <= WBACK;
end
8'b1100011x: case (s2)
0: begin
s2 <= 1; wb <= in; dir <= 0; ip <= ip + 1;
if (size == 0) begin fn <= WBACK; cp <= 1; end
end
1: begin fn <= WBACK; cp <= 1; ip <= ip + 1; wb[15:8] <= in; end
endcase
8'b10001101: begin
wb <= ea;
size <= 1;
dir <= 1;
fn <= WBACK;
end
8'b0100xxxx: begin
fn <= WBACK;
modrm[5:3] <= opcode[2:0];
dir <= 1;
wb <= alu_r;
flags <= {alu_f[11:1], flags[CF]};
end
8'b01011xxx: begin
fn <= WBACK;
size <= 1;
dir <= 1;
modrm[5:3] <= opcode[2:0];
end
8'b000xx111: begin
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)
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
2'b11: begin op2[15:8] <= {8{op2[7]}}; end
endcase
end
3: begin
cp <= cpen;
wb <= alu_r;
flags <= alu_f;
fn <= (alu != ALU_CMP) ? WBACK : START;
end
endcase
8'b101000xx: case (s2)
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
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
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
flags <= alu_f;
fn <= START;
end
8'b100001xx: case (s2)
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
fn <= START;
flags <= wb | 2;
end
8'b1010100x: case (s2)
0: begin s2 <= size ? 1 : 2; alu <= ALU_AND; op1 <= ax; op2 <= in; ip <= ip + 1; end
1: begin s2 <= 2; op2[15:8] <= in; ip <= ip + 1; end
2: begin flags <= alu_f; fn <= START; end
endcase
8'b0111xxxx,
8'b111000xx,
8'b11101011: begin
fn <= START;
ip <= ip + 1 + signex;
end
8'b11101001: case (s2)
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)
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)
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
fn <= START;
ip <= wb;
end
8'b11000010: case (s2)
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)
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)
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
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
fn <= START;
case (modrm[4:3])
0: es <= op2;
1: cs <= op2;
2: ss <= op2;
3: ds <= op2;
endcase
end
8'b10011010: case (s2)
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)
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)
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)
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
fn <= START;
ax[7:0] <= in;
end
8'b11001101: begin
fn <= INTR;
intr <= in;
ip <= ip + 1;
end
8'b1100000x,
8'b110100xx: case (s2)
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
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)
0: begin
s2 <= 1;
cpen <= 0;
port_a <= opcode[3] ? dx : in;
if (!opcode[3]) ip <= ip + 1;
end
1: begin s2 <= 2; port_r <= 1; end
2: begin s2 <= 3; end
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)
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])
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
2: begin wb <= ~op1; fn <= WBACK; end
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])
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
2: begin
ip <= op1;
wb <= ip;
fn <= size ? PUSH : UNDEF;
end
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
4: begin ip <= op1; fn <= size ? START : UNDEF; end
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
6: begin wb <= op1; fn <= PUSH; end
7: begin fn <= UNDEF; end
endcase
8'b1010101x: case (s2)
0: begin
s2 <= size ? 1 : 2;
cp <= 1;
we <= 1;
ea <= di;
out <= ax[7:0];
segment <= es;
end
1: begin
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)
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)
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
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
5: begin
s2 <= 6;
we <= 0;
cp <= 0;
si <= flags[DF] ? si - (opcode[0] + 1) : si + (opcode[0] + 1);
size <= 1;
end
6: begin s2 <= 6;
di <= flags[DF] ? di - (opcode[0] + 1) : di + (opcode[0] + 1);
fn <= rep[1] ? REPF : START;
end
endcase
8'b1010011x: case (s2)
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
6: begin
s2 <= 7;
flags <= alu_f;
cp <= 0;
si <= flags[DF] ? si - (opcode[0] + 1) : si + (opcode[0] + 1);
size <= 1;
end
7: begin
rep_ft <= 1;
di <= flags[DF] ? di - (opcode[0] + 1) : di + (opcode[0] + 1);
fn <= rep[1] ? REPF : START;
end
endcase
8'b1010111x: case (s2)
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
3: begin
flags <= alu_f;
cp <= 0;
rep_ft <= 1;
di <= flags[DF] ? di - (opcode[0] + 1) : di + (opcode[0] + 1);
fn <= rep[1] ? REPF : START;
end
endcase
endcase
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
WBACK: case (s1)
0: begin
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
else begin out <= wb[7:0]; we <= 1; s1 <= 1; end
end
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
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
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
REPF: case (s1)
0: begin s1 <= 1; cx <= cx - 1; end
1: begin
s1 <= 0;
fn <= START;
if (cx) begin
if (rep_ft) begin if (rep[0] == flags[ZF]) ip <= ip_start; end
else ip <= ip_start;
end
end
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;
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 = {
alu_of & ~is_lgc,
flags[10:8],
alu_sf,
alu_zf,
1'b0,
alu_af & ~is_lgc,
1'b0,
alu_pf,
1'b1,
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
rot_f[CF] = alu[0] ? op1[0] : op1[alu_top];
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
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