Этот процессор был мной написан "с нуля". Процессор проходит все тесты ZXALL. Дата последней ревизии: 21 сен 2024.
module z80
(
input clock,
input reset_n,
input compat,
input hold,
input irq,
output [15:0] address,
input [ 7:0] i_data,
output reg [ 7:0] o_data,
output reg we,
output m0,
input [ 7:0] portin,
output reg portrd,
output reg portwe,
output reg [15:0] bc,
output reg [15:0] de,
output reg [15:0] hl,
output reg [15:0] af,
output reg [15:0] bc_prime,
output reg [15:0] de_prime,
output reg [15:0] hl_prime,
output reg [15:0] af_prime,
output reg [15:0] ix,
output reg [15:0] iy,
output reg [15:0] pc,
output reg [15:0] sp,
output reg [15:0] ir,
output reg [ 1:0] i_mode,
output reg iff1,
output reg iff2
);
localparam
CF = 8, NF = 9, PF = 10, F3F = 11, HF = 12, F5F = 13, ZF = 14, SF = 15;
localparam
alu_add = 0, alu_rlc = 8, alu_inc = 16, alu_rlca = 24,
alu_adc = 1, alu_rrc = 9, alu_dec = 17, alu_rrca = 25,
alu_sub = 2, alu_rl = 10, alu_rla = 26,
alu_sbc = 3, alu_rr = 11, alu_rra = 27,
alu_and = 4, alu_sla = 12, alu_daa = 20, alu_bit = 28,
alu_xor = 5, alu_sra = 13, alu_cpl = 21, alu_set = 29,
alu_or = 6, alu_sll = 14, alu_scf = 22, alu_res = 30,
alu_cp = 7, alu_srl = 15, alu_ccf = 23;
localparam
spec_exaf = 1,
spec_exx = 2,
spec_exdehl = 3;
localparam
ldcmd_ldi = 1,
ldcmd_ldd = 2,
ldcmd_cpi = 3,
ldcmd_cpd = 4;
assign address = bus ? cp : pc;
assign m0 = (t_state == 0 && prefix == 0 && delay == 0);
always @(posedge clock) if (hold) begin
exxw <= 0;
ldcmd <= 0;
reg_w8 <= 0;
reg_w16 <= 0;
reg_wf <= 0;
reg_wfex <= 0;
we <= 0;
portwe <= 0;
portrd <= 0;
if (compat && delay) delay <= delay - 1;
else if (reset_n == 1'b0) begin
pc <= 0;
bus <= 0;
t_state <= 0;
set_prefix <= 0;
i_mode <= 0;
hptr <= 0;
iff1 <= 1'b0; iff1_ <= 1'b0;
iff2 <= 1'b0; iff2_ <= 1'b0;
end
else if (irq_process) case (t_state)
0: begin
t_state <= 1;
bus <= 1; we <= 1; cp <= sp - 2; o_data <= pc[7:0];
reg_w16 <= 1; reg_dt <= sp - 2; reg_id <= 3;
end
1: begin t_state <= 2; we <= 1; o_data <= pc[15:8]; cp <= cp + 1; end
2: begin
if (i_mode == 2) begin
t_state <= 3;
hptr <= ir[15:8];
cp <= {ir[15:8], 8'hFF};
end
else begin
t_state <= 0;
bus <= 0;
pc <= 8'h38;
delay <= 13-3-1;
irq_process <= 0;
end
end
3: begin t_state <= 4; cp <= cp + 1; pc[7:0] <= i_data; end
4: begin
t_state <= 0;
bus <= 0;
pc[15:8] <= i_data;
delay <= 19-5-1;
irq_process <= 0;
end
endcase
else if (iff1 && prefix == 0 && t_state == 0 && irq ^ irq_latch) begin
if (irq) begin
irq_process <= 1;
iff1 <= 1'b0; iff1_ <= 1'b0;
iff2 <= 1'b0; iff2_ <= 1'b0;
if (i_data == 8'h76) pc <= pc + 1;
end
irq_latch <= irq;
end
else begin
if (t_state == 0) begin
opcode_latch <= i_data;
pc <= pc + 1;
ir[6:0] <= ir[6:0] + 1;
if (prefix == 0) begin
iff1 <= iff1_;
iff2 <= iff2_;
end
end
t_state <= t_state + 1;
casex (opcode)
8'b00_001_000: begin exxw <= spec_exaf; {set_prefix, t_state} <= 0; delay <= 4-1; end
8'b00_010_000: case (t_state)
0: begin
reg_w8 <= 1;
reg_id <= 0;
reg_dt <= bc[15:8] - 1;
set_prefix <= 0;
if (bc[15:8] == 1) begin pc <= pc + 2; t_state <= 0; delay <= 8-1; end
end
1: begin
pc <= pc + 1 + signex;
t_state <= 0;
delay <= 13-2;
end
endcase
8'b00_011_000: case (t_state)
1: begin pc <= pc + signex + 1; {set_prefix, t_state} <= 0; delay <= 12-2; end
endcase
8'b00_1xx_000: case (t_state)
0: begin
set_prefix <= 0;
if (condition[ opcode[4:3] ]) begin
t_state <= 0;
pc <= pc + 2;
delay <= 7-1;
end
end
1: begin
pc <= pc + 1 + signex;
t_state <= 0;
delay <= 12-2;
end
endcase
8'b00_xx_0001: case (t_state)
1: begin pc <= pc + 1; reg_dt[ 7:0] <= i_data; end
2: begin pc <= pc + 1; reg_dt[15:8] <= i_data;
reg_w16 <= 1;
reg_id <= opcode[5:4];
{set_prefix, t_state} <= 0;
delay <= 10-3;
end
endcase
8'b00_xx_1001: case (t_state)
0: begin
reg_w16 <= 1;
reg_wfex <= 1;
reg_id <= 2;
reg_dt <= do_hl_add[15:0];
flag_ex <= do_hl_flag;
{set_prefix, t_state} <= 0; delay <= 11-1;
end
endcase
8'b00_0x_0010: case (t_state)
0: begin
cp <= opcode[4] ? de : bc;
bus <= 1;
we <= 1;
o_data <= af[7:0];
hptr <= af[7:0];
end
1: begin {set_prefix, t_state, bus} <= 0; delay <= 7-2; end
endcase
8'b00_0x_1010: case (t_state)
0: begin cp <= opcode[4] ? de : bc; bus <= 1; end
1: begin
reg_w8 <= 1;
reg_id <= 7;
reg_dt <= i_data;
{set_prefix, t_state, bus} <= 0; delay <= 7-2;
end
endcase
8'b00_10_0010: case (t_state)
1: begin cp[ 7:0] <= i_data; pc <= pc + 1; end
2: begin
bus <= 1;
cp[15:8] <= i_data;
hptr <= i_data;
pc <= pc + 1;
o_data <= hlx[7:0];
we <= 1;
end
3: begin cp <= cp + 1; o_data <= hlx[15:8]; we <= 1; end
4: begin {set_prefix, t_state, bus} <= 0; delay <= 16-5; end
endcase
8'b00_11_0010: case (t_state)
1: begin cp[ 7:0] <= i_data; pc <= pc + 1; end
2: begin
we <= 1;
bus <= 1;
cp[15:8] <= i_data;
pc <= pc + 1;
o_data <= af[7:0];
hptr <= af[7:0];
end
3: begin {set_prefix, t_state, bus} <= 0; delay <= 16-4; end
endcase
8'b00_10_1010: case (t_state)
1: begin cp[ 7:0] <= i_data; pc <= pc + 1; end
2: begin cp[15:8] <= i_data; pc <= pc + 1; bus <= 1; hptr <= i_data; end
3: begin reg_id <= 5; reg_dt <= i_data; reg_w8 <= 1; cp <= cp + 1; end
4: begin
reg_id <= 4; reg_dt <= i_data; reg_w8 <= 1;
{set_prefix, t_state, bus} <= 0; delay <= 16-5;
end
endcase
8'b00_11_1010: case (t_state)
1: begin cp[ 7:0] <= i_data; pc <= pc + 1; end
2: begin cp[15:8] <= i_data; pc <= pc + 1; bus <= 1; hptr <= i_data; end
3: begin
reg_id <= 7; reg_dt <= i_data; reg_w8 <= 1;
{set_prefix, t_state, bus} <= 0; delay <= 13-4;
end
endcase
8'b00_xx_x011: case (t_state)
0: begin
reg_w16 <= 1;
reg_id <= opcode[5:4];
case (opcode[5:4])
2'b00: reg_dt <= opcode[3] ? bc - 1 : bc + 1;
2'b01: reg_dt <= opcode[3] ? de - 1 : de + 1;
2'b10: reg_dt <= opcode[3] ? hlx - 1 : hlx + 1;
2'b11: reg_dt <= opcode[3] ? sp - 1 : sp + 1;
endcase
{set_prefix, t_state} <= 0; delay <= 6-1;
end
endcase
8'b00_110_10x: case (t_state)
0: begin
bus <= prefix ? 0 : 1;
t_state <= prefix ? 1 : 2;
alu_m <= opcode[0] ? alu_dec : alu_inc;
cp <= hl;
end
1: begin
bus <= 1;
cp <= hlx + signex;
pc <= pc + 1;
end
2: begin op1 <= i_data; op2 <= 1; end
3: begin we <= 1; o_data <= alu_r[7:0]; reg_wf <= 1; end
4: begin {set_prefix, t_state, bus} <= 0; delay <= prefix ? 23-4-5: 11-4; end
endcase
8'b00_xxx_10x: case (t_state)
0: begin op1 <= reg8_53; op2 <= 1; alu_m <= opcode[0] ? alu_dec : alu_inc; end
1: begin
reg_wf <= 1;
reg_w8 <= 1;
reg_id <= opcode[5:3];
reg_dt <= alu_r[7:0];
{set_prefix, t_state} <= 0; delay <= 4-2;
end
endcase
8'b00_110_110: case (t_state)
1: begin
we <= prefix ? 0 : 1;
bus <= prefix ? 0 : 1;
t_state <= prefix ? 2 : 3;
cp <= prefix ? (hlx + signex) : hl;
pc <= pc + 1;
o_data <= i_data;
end
2: begin
we <= 1;
bus <= 1;
pc <= pc + 1;
o_data <= i_data;
end
3: begin {bus, set_prefix, t_state} <= 0; delay <= prefix ? 19-4-4 : 10-3; end
endcase
8'b00_xxx_110: case (t_state)
1: begin
pc <= pc + 1;
reg_w8 <= 1;
reg_id <= opcode[5:3];
reg_dt <= i_data;
{set_prefix, t_state} <= 0; delay <= 7-2;
end
endcase
8'b00_xxx_111: case (t_state)
0: begin op1 <= af[7:0]; alu_m <= (opcode[5] ? alu_daa : alu_rlca) + opcode[4:3]; end
1: begin
reg_w8 <= 1;
reg_wf <= 1;
reg_id <= 7;
reg_dt <= alu_r;
{set_prefix, t_state} <= 0; delay <= 4-2;
end
endcase
8'b01_110_110: begin pc <= pc; {set_prefix, t_state} <= 0; delay <= 4-1; end
8'b01_110_xxx: case (t_state)
0: begin
bus <= prefix ? 0 : 1;
we <= prefix ? 0 : 1;
t_state <= prefix ? 1 : 2;
cp <= hl;
o_data <= reg8_20;
end
1: begin
we <= 1;
bus <= 1;
cp <= hlx + signex;
pc <= pc + 1;
o_data <= hl20_org;
end
2: begin {set_prefix, t_state, bus} <= 0; delay <= prefix ? 19-4-3 : 7-2; end
endcase
8'b01_xxx_110: case (t_state)
0: begin
bus <= prefix ? 0 : 1;
t_state <= prefix ? 1 : 2;
t_pref <= prefix ? 1 : 0;
cp <= hl;
end
1: begin
bus <= 1;
cp <= hlx + signex;
pc <= pc + 1;
set_prefix <= 0;
end
2: begin
reg_w8 <= 1;
reg_id <= opcode[5:3];
reg_dt <= i_data;
{t_state, bus} <= 0; delay <= t_pref ? 19-4-3 : 7-2;
end
endcase
8'b01_xxx_xxx: case (t_state)
0: begin
reg_w8 <= 1;
reg_id <= opcode[5:3];
reg_dt <= reg8_20;
{set_prefix, t_state} <= 0; delay <= 4-1;
end
endcase
8'b10_xxx_110: case (t_state)
0: begin
bus <= prefix ? 0 : 1;
t_state <= prefix ? 1 : 2;
alu_m <= opcode[5:3];
op1 <= af[7:0];
cp <= hl;
end
1: begin
bus <= 1;
cp <= hlx + signex;
pc <= pc + 1;
end
2: begin op2 <= i_data; bus <= 0; end
3: begin
reg_wf <= 1;
reg_id <= 7;
reg_w8 <= opcode[5:3] != alu_cp;
reg_dt <= alu_r[7:0];
{set_prefix, t_state} <= 0; delay <= prefix ? 19-4-4: 7-3;
end
endcase
8'b10_xxx_xxx: case (t_state)
0: begin op1 <= af[7:0]; op2 <= reg8_20; alu_m <= opcode[5:3]; end
1: begin
reg_wf <= 1;
reg_id <= 7;
reg_w8 <= opcode[5:3] != alu_cp;
reg_dt <= alu_r[7:0];
{set_prefix, t_state} <= 0; delay <= 4-2;
end
endcase
8'b11_001_001,
8'b11_xxx_000: case (t_state)
0: begin
set_prefix <= 0;
if (condition[ opcode[5:3] ] && (opcode[0] == 1'b0)) begin
t_state <= 0;
delay <= 5-1;
end
else begin
bus <= 1;
cp <= sp;
reg_w16 <= 1;
reg_dt <= sp + 2;
reg_id <= 3;
end
end
1: begin pc[7:0] <= i_data; cp <= cp + 1; end
2: begin
pc[15:8] <= i_data;
{t_state, bus} <= 0; delay <= opcode[0] ? 10-3 : 11-3;
end
endcase
8'b11_xx0_001: case (t_state)
0: begin
bus <= 1;
cp <= sp;
reg_w16 <= 1;
reg_dt <= sp + 2;
reg_id <= 3;
end
1: begin
if (opcode[5:4] == 2'b11) begin
reg_wfex <= 1;
flag_ex <= i_data;
end else begin
reg_w8 <= 1;
reg_id <= {opcode[5:4], 1'b1};
reg_dt <= i_data;
end
cp <= cp + 1;
end
2: begin
reg_w8 <= 1;
reg_id <= opcode[5:4] == 2'b11 ? 7 : {opcode[5:4], 1'b0};
reg_dt <= i_data;
{set_prefix, t_state, bus} <= 0; delay <= 10-3;
end
endcase
8'b11_011_001: case (t_state)
0: begin {set_prefix, t_state} <= 0; exxw <= spec_exx; delay <= 4-1; end
endcase
8'b11_101_001: case (t_state)
0: begin pc <= hlx; {set_prefix, t_state} <= 0; delay <= 4-1; end
endcase
8'b11_111_001: case (t_state)
0: begin
reg_w16 <= 1;
reg_dt <= hlx;
reg_id <= 3;
{set_prefix, t_state} <= 0; delay <= 6-1;
end
endcase
8'b11_000_011,
8'b11_xxx_010: case (t_state)
0: begin
set_prefix <= 0;
if (condition[ opcode[5:3] ] && (opcode[0] == 1'b0)) begin
pc <= pc + 2;
t_state <= 3;
end
end
1: begin reg_dt <= i_data; pc <= pc + 1; end
2: begin hptr <= i_data; pc <= {i_data, reg_dt[7:0]}; t_state <= 0; delay <= 10-3; end
3: begin hptr <= i_data; pc <= pc + 1; t_state <= 0; delay <= 10-2; end
endcase
8'b11_001_011: case (t_state)
1: begin
pc <= pc + 1;
cp <= prefix ? hlx + signex : hl;
bus <= prefix ? 0 : 1;
opcode_ext <= i_data;
ir[6:0] <= ir[6:0] + 1;
if (prefix == 0) t_state <= 3;
end
2: begin opcode_ext <= i_data; pc <= pc + 1; bus <= 1; end
3: begin
op1 <= prefix ? i_data : reg8_cb20;
op2 <= opcode_ext[6:3];
alu_m <= opcode_ext[5:3] + alu_rlc;
t_pref <= prefix ? 1 : 0;
set_prefix <= 0;
end
4: casex (opcode_ext[7:6])
8'b01: begin
reg_wfex <= 1;
flag_ex <= t_pref ? bit_flags_xx : bit_flags;
if (t_pref == 0 && opcode_ext[2:0] == 6)
{flag_ex[5],flag_ex[3]} <= {hptr[5],hptr[3]};
{bus, t_state} <= 0;
delay <= t_pref ? 20-4-5 : (opcode_ext[2:0] == 6 ? 12-4 : 8-4);
end
8'b00,
8'b1x: begin
we <= (opcode_ext[2:0] == 6) || t_pref;
reg_w8 <= (opcode_ext[2:0] != 6);
reg_id <= opcode_ext[2:0];
reg_dt <= opcode_ext[7] ? rsop : alu_r;
o_data <= opcode_ext[7] ? rsop : alu_r;
if (opcode_ext[7] == 1'b0) reg_wf <= 1;
if (t_pref == 0 && (opcode_ext[2:0] != 6)) begin
{bus, t_state} <= 0; delay <= 8-4;
end
end
endcase
5: begin {bus, t_state} <= 0; delay <= t_pref ? 23-4-6 : 15-5; end
endcase
8'b11_010_011: case (t_state)
1: begin
bus <= 1;
portwe <= 1;
o_data <= af[7:0];
hptr <= af[7:0];
cp <= {af[7:0], i_data};
pc <= pc + 1;
end
2: begin {set_prefix, t_state, bus} <= 0; delay <= 11-3; end
endcase
8'b11_011_011: case (t_state)
1: begin bus <= 1; cp <= {af[7:0], i_data}; hptr <= af[7:0]; pc <= pc + 1; portrd <= 1; end
2: begin
reg_id <= 7;
reg_w8 <= 1;
reg_dt <= portin;
{set_prefix, t_state, bus} <= 0; delay <= 11-3;
end
endcase
8'b11_100_011: case (t_state)
0: begin bus <= 1; cp <= sp; end
1: begin reg_dt[ 7:0] <= i_data; cp <= cp + 1; end
2: begin reg_dt[15:8] <= i_data; cp <= cp - 1; we <= 1; o_data <= hlx[7:0]; end
3: begin
reg_w16 <= 1;
reg_id <= 2;
we <= 1;
cp <= cp + 1;
o_data <= hlx[15:8];
end
4: begin {set_prefix, t_state, bus} <= 0; delay <= 19-5; end
endcase
8'b11_101_011: case (t_state)
0: begin {set_prefix, t_state} <= 0; exxw <= spec_exdehl; delay <= 4-1; end
endcase
8'b11_11x_011: case (t_state)
0: begin
iff1_ <= opcode[3];
iff2_ <= opcode[3];
{set_prefix, t_state} <= 0; delay <= 4-1;
end
endcase
8'b11_001_101,
8'b11_xxx_100: case (t_state)
0: begin
set_prefix <= 0;
if (condition[ opcode[5:3] ] && (opcode[0] == 1'b0)) begin
pc <= pc + 2;
t_state <= 5;
end
else begin
reg_w16 <= 1;
reg_dt <= sp - 2;
reg_id <= 3;
end
end
1: begin reg_dt <= i_data; pc <= pc + 1; end
2: begin
bus <= 1;
we <= 1;
cp <= sp;
pc <= {i_data, reg_dt[7:0]};
hptr <= i_data;
o_data <= pc1[7:0];
reg_dt <= pc1;
end
3: begin
we <= 1;
cp <= cp + 1;
o_data <= reg_dt[15:8];
end
4: begin {t_state, bus} <= 0; delay <= 17-5; end
5: begin hptr <= i_data; pc <= pc + 1; t_state <= 0; delay <= 10-2; end
endcase
8'b11_xx0_101: case (t_state)
0: begin
bus <= 1;
we <= 1;
cp <= sp - 2;
reg_w16 <= 1;
reg_dt <= sp - 2;
reg_id <= 3;
case (opcode[5:4])
0: o_data <= bc[ 7:0];
1: o_data <= de[ 7:0];
2: o_data <= hlx[ 7:0];
3: o_data <= af[15:8];
endcase
end
1: begin
we <= 1;
cp <= cp + 1;
case (opcode[5:4])
0: o_data <= bc[15:8];
1: o_data <= de[15:8];
2: o_data <= hlx[15:8];
3: o_data <= af[ 7:0];
endcase
end
2: begin {set_prefix, t_state, bus} <= 0; delay <= 11-3; end
endcase
8'b11_101_101: case (t_state)
0: begin set_prefix <= 0; n_state <= 0; end
1: begin
pc <= pc + 1;
opcode_ext <= i_data;
casex (i_data)
8'b01_xxx_000: begin cp <= bc; bus <= 1; portrd <= 1; end
8'b01_xxx_001: begin
bus <= 1;
portwe <= 1;
cp <= bc;
o_data <= reg8_outc;
end
8'b01_xxx_010: begin
reg_w16 <= 1;
reg_wfex <= 1;
reg_id <= 2;
reg_dt <= i_data[3] ? ed_hl_adc : ed_hl_sbc;
flag_ex <= i_data[3] ? hl_adc_flag : hl_sbc_flag;
t_state <= 0; delay <= 15-2;
end
8'b01_xxx_011: begin end
8'b01_xxx_100: begin
op1 <= 0;
op2 <= af[7:0];
alu_m <= alu_sub;
end
8'b01_xxx_101: begin
bus <= 1;
cp <= sp;
reg_w16 <= 1;
reg_dt <= sp + 2;
reg_id <= 3;
if (i_data[5:3] != 3'b001) begin
iff1 <= iff2;
iff1_ <= iff2_;
end
end
8'b01_xxx_110: begin
i_mode <= i_data[4] ? (i_data[3] ? 2 : 1) : 0;
t_state <= 0; delay <= 8-2;
end
8'b01_0xx_111: begin
reg_id <= 7;
reg_dt <= i_data[3] ? ir[7:0] : ir[15:8];
if (i_data[4]) reg_w8 <= 1;
else if (i_data[3]) ir[7:0] <= af[7:0]; else ir[15:8] <= af[7:0];
if (i_data[4]) begin
reg_wfex <= 1;
if (i_data[3])
flag_ex <= {ir[ 7], ir[ 7:0] == 0, ir[ 5], 1'b0, ir[ 3], (irqcause ? 1'b0 : iff2), 1'b0, af[CF]};
else flag_ex <= {ir[15], ir[15:8] == 0, ir[13], 1'b0, ir[11], (irqcause ? 1'b0 : iff2), 1'b0, af[CF]};
end
t_state <= 0; delay <= 9-2;
end
8'b01_10x_111,
8'b10_1xx_00x,
8'b10_1xx_011: begin cp <= hl; bus <= 1; end
8'b10_1xx_010: begin
cp <= {b_dec, bc[7:0]};
bus <= 1;
alu_m <= alu_dec;
op1 <= bc[15:8];
op2 <= 1;
portrd <= 1;
end
default: begin t_state <= 0; delay <= 8-2; end
endcase
end
2: begin
t_state <= 2;
n_state <= n_state + 1;
casex (opcode_ext)
8'b01_xxx_000: begin
reg_w8 <= 1;
reg_wfex <= 1;
reg_id <= opcode_ext[5:3];
reg_dt <= portin;
flag_ex <= {
portin[7],
portin == 0,
portin[5],
1'b0,
portin[3],
~^portin[7:0],
1'b0,
af[CF]
};
{t_state, bus} <= 0; delay <= 12-3;
end
8'b01_xxx_001: begin {t_state, bus} <= 0; delay <= 12-3; end
8'b01_xx0_011: case (n_state)
0: begin cp[7:0] <= i_data; pc <= pc + 1; end
1: begin
cp[15:8] <= i_data;
hptr <= i_data;
pc <= pc + 1;
bus <= 1;
we <= 1;
case (opcode_ext[5:4])
2'b00: o_data <= bc[7:0];
2'b01: o_data <= de[7:0];
2'b10: o_data <= hl[7:0];
2'b11: o_data <= sp[7:0];
endcase
end
2: begin
we <= 1;
cp <= cp + 1;
case (opcode_ext[5:4])
2'b00: o_data <= bc[15:8];
2'b01: o_data <= de[15:8];
2'b10: o_data <= hl[15:8];
2'b11: o_data <= sp[15:8];
endcase
end
3: begin {t_state, bus} <= 0; delay <= 20-6; end
endcase
8'b01_xx1_011: case (n_state)
0: begin cp[ 7:0] <= i_data; pc <= pc + 1; end
1: begin cp[15:8] <= i_data; pc <= pc + 1; bus <= 1; hptr <= i_data; end
2: begin reg_dt[7:0] <= i_data; cp <= cp + 1; end
3: begin
reg_w16 <= 1;
reg_id <= opcode_ext[5:4];
reg_dt[15:8] <= i_data;
{t_state, bus} <= 0; delay <= 20-6;
end
endcase
8'b01_xxx_101: case (n_state)
0: begin pc[ 7:0] <= i_data; cp <= cp + 1; end
1: begin pc[15:8] <= i_data; {t_state, bus} <= 0; delay <= 14-4; end
endcase
8'b01_xxx_100: begin
reg_id <= 7;
reg_wf <= 1;
reg_w8 <= 1;
reg_dt <= alu_r;
t_state <= 0; delay <= 8-3;
end
8'b01_10x_111: case (n_state)
0: begin
we <= 1;
reg_w8 <= 1;
reg_wfex <= 1;
reg_id <= 7;
o_data <= opcode_ext[3] ? rld_w : rrd_w;
reg_dt <= opcode_ext[3] ? rld_a : rrd_a;
flag_ex <= opcode_ext[3] ? {
rld_a[7], rld_a == 0, rld_a[5], 1'b0,
rld_a[3], ~^rld_a[7:0], 1'b0, af[CF]
} : {
rrd_a[7], rrd_a == 0, rrd_a[5], 1'b0,
rrd_a[3], ~^rrd_a[7:0], 1'b0, af[CF]
};
end
1: begin {t_state, bus} <= 0; delay <= 18-4; end
endcase
8'b10_1xx_000: case (n_state)
0: begin
we <= 1;
cp <= de;
o_data <= i_data;
reg_wfex <= 1;
flag_ex <= {
af[SF], af[ZF], ldixy[1], 1'b0,
ldixy[3], bc != 1, 1'b0, af[CF]
};
ldcmd <= opcode_ext[3] ? ldcmd_ldd : ldcmd_ldi;
end
1: begin
delay <= 16-4;
if (opcode_ext[4] && bc) begin pc <= pc - 2; delay <= 21-4; end
{t_state, bus} <= 0;
end
endcase
8'b10_1xx_001: case (n_state)
0: begin
alu_m <= alu_cp;
op1 <= af[7:0];
op2 <= i_data;
ldcmd <= opcode_ext[3] ? ldcmd_cpd : ldcmd_cpi;
end
1: begin
reg_wfex <= 1;
flag_ex <= {
alu_f[7], alu_f[6], cpixy[1], alu_f[4],
cpixy[3], bc != 0, 1'b1, af[CF]
};
delay <= 16-4;
if (opcode_ext[4] && !alu_f[6] && bc)
begin pc <= pc - 2; delay <= 21-4; end
{t_state, bus} <= 0;
end
endcase
8'b10_1xx_010: case (n_state)
0: begin
we <= 1;
cp <= hl;
o_data <= portin;
reg_wf <= 1;
reg_w8 <= 1;
reg_id <= 0;
reg_dt <= alu_r;
end
1: begin
reg_w16 <= 1;
reg_id <= 2;
reg_dt <= opcode_ext[3] ? hl - 1 : hl + 1;
delay <= 16-4;
if (opcode_ext[4] && alu_r[7:0]) begin pc <= pc - 2; delay <= 21-4; end
{t_state, bus} <= 0;
end
endcase
8'b10_1xx_011: case (n_state)
0: begin
portwe <= 1;
cp <= bc;
o_data <= i_data;
reg_w16 <= 1;
reg_id <= 2;
reg_dt <= opcode_ext[3] ? hl - 1 : hl + 1;
alu_m <= alu_dec;
op1 <= bc[15:8];
op2 <= 1;
end
1: begin
reg_wf <= 1;
reg_w8 <= 1;
reg_dt <= alu_r;
reg_id <= 0;
delay <= 16-4;
if (opcode_ext[4] && alu_r[7:0]) begin pc <= pc - 2; delay <= 21-4; end
{t_state, bus} <= 0;
end
endcase
endcase
end
endcase
8'b11_xxx_110: case (t_state)
0: begin op1 <= af[7:0]; alu_m <= opcode[5:3]; end
1: begin op2 <= i_data; pc <= pc + 1; end
2: begin
reg_wf <= 1;
reg_id <= 7;
reg_w8 <= opcode[5:3] != alu_cp;
reg_dt <= alu_r[7:0];
{set_prefix, t_state} <= 0; delay <= 7-3;
end
endcase
8'b11_xxx_111: case (t_state)
0: begin
bus <= 1;
we <= 1;
cp <= sp - 2;
o_data <= pc1[7:0];
reg_w16 <= 1;
reg_dt <= sp - 2;
reg_id <= 3;
set_prefix <= 0;
end
1: begin we <= 1; o_data <= pc[15:8]; cp <= cp + 1; end
2: begin pc <= {opcode[5:3], 3'b000}; {t_state, bus} <= 0; delay <= 11-3; end
endcase
8'b1101_1101: begin t_state <= 0; set_prefix <= 1; delay <= 4-1; end
8'b1111_1101: begin t_state <= 0; set_prefix <= 2; delay <= 4-1; end
default: begin {set_prefix, t_state} <= 0; delay <= 4-1; end
endcase
if (compat == 0) delay <= 0;
end
end
initial begin o_data = 0; we = 0; portwe = 0; end
reg [ 3:0] t_state = 0;
reg [ 2:0] n_state = 0;
reg [ 4:0] delay = 0;
reg bus = 1'b0;
reg [15:0] cp = 16'h0000;
reg [ 7:0] opcode_latch;
reg [ 7:0] opcode_ext;
reg [ 1:0] set_prefix = 0;
reg [ 1:0] prefix = 0;
reg t_pref = 0;
reg [ 1:0] exxw = 0;
reg [ 2:0] ldcmd = 0;
reg reg_w8 = 0;
reg reg_w16 = 0;
reg reg_wfex = 0;
reg reg_wf = 0;
reg [ 3:0] reg_id = 0;
reg [15:0] reg_dt = 0;
reg [ 7:0] flag_ex = 0;
reg [ 7:0] hptr = 0;
reg iff1_ = 1'b0;
reg iff2_ = 1'b1;
reg irq_latch = 1'b0;
reg irq_process = 1'b0;
wire [7:0] opcode = t_state? opcode_latch : i_data;
wire [15:0] hlx = prefix == 1 ? ix : (prefix == 2 ? iy : hl);
wire [15:0] signex = {{8{i_data[7]}}, i_data[7:0]};
wire irqcause = irq ^ irq_latch;
wire [7:0] reg8_20 =
opcode[2:0] == 0 ? bc[15:8] : opcode[2:0] == 1 ? bc[ 7:0] :
opcode[2:0] == 2 ? de[15:8] : opcode[2:0] == 3 ? de[ 7:0] :
opcode[2:0] == 4 ? hlx[15:8] : opcode[2:0] == 5 ? hlx[ 7:0] :
opcode[2:0] == 6 ? i_data : af[7:0];
wire [7:0] reg8_53 =
opcode[5:3] == 0 ? bc[15:8] : opcode[5:3] == 1 ? bc[ 7:0] :
opcode[5:3] == 2 ? de[15:8] : opcode[5:3] == 3 ? de[ 7:0] :
opcode[5:3] == 4 ? hlx[15:8] : opcode[5:3] == 5 ? hlx[ 7:0] :
opcode[5:3] == 6 ? i_data : af[7:0];
wire [7:0] reg8_cb20 =
opcode_ext[2:0] == 0 ? bc[15:8] : opcode_ext[2:0] == 1 ? bc[ 7:0] :
opcode_ext[2:0] == 2 ? de[15:8] : opcode_ext[2:0] == 3 ? de[ 7:0] :
opcode_ext[2:0] == 4 ? hl[15:8] : opcode_ext[2:0] == 5 ? hl[ 7:0] :
opcode_ext[2:0] == 6 ? i_data : af[7:0];
wire [7:0] reg8_outc =
i_data[5:3] == 0 ? bc[15:8] : i_data[5:3] == 1 ? bc[ 7:0] :
i_data[5:3] == 2 ? de[15:8] : i_data[5:3] == 3 ? de[ 7:0] :
i_data[5:3] == 4 ? hl[15:8] : i_data[5:3] == 5 ? hl[ 7:0] :
i_data[5:3] == 6 ? 0 : af[7:0];
wire [7:0] hl20_org = opcode[2:0] == 4 ? hl[15:8] :
opcode[2:0] == 5 ? hl[ 7:0] : reg8_20;
wire [15:0] pc1 = pc + 1;
wire [7:0] condition = {
~af[SF], af[SF],
~af[PF], af[PF],
~af[CF], af[CF],
~af[ZF], af[ZF]
};
reg [4:0] alu_m;
reg [7:0] op1;
reg [7:0] op2;
wire zf8 = alu_r[7:0]==0;
wire pf8 = ~^alu_r[7:0];
wire sf8 = alu_r[7];
wire cf8 = alu_r[8];
wire f58 = alu_r[5];
wire f38 = alu_r[3];
wire hf8 = alu_r[4]^op1[4]^op2[4];
wire oa8 = (op1[7] == op2[7]) & (op1[7] != alu_r[7]);
wire os8 = (op1[7] != op2[7]) & (op1[7] != alu_r[7]);
wire [4:0] ha8 = op1[3:0] + op2[3:0] + af[CF];
wire [4:0] hs8 = op1[3:0] - op2[3:0] - af[CF];
wire [8:0] alu_r =
alu_m == alu_add ? op1 + op2 :
alu_m == alu_adc ? op1 + op2 + af[CF] :
alu_m == alu_sub ? op1 - op2 :
alu_m == alu_sbc ? op1 - op2 - af[CF] :
alu_m == alu_and ? op1 & op2 :
alu_m == alu_xor ? op1 ^ op2 :
alu_m == alu_or ? op1 | op2 :
alu_m == alu_cp ? op1 - op2 :
alu_m == alu_inc ? op1 + op2 :
alu_m == alu_dec ? op1 - op2 :
alu_m == alu_rlca || alu_m == alu_rlc ? {op1[6:0], op1[7]} :
alu_m == alu_rrca || alu_m == alu_rrc ? {op1[0], op1[7:1]} :
alu_m == alu_rla || alu_m == alu_rl ? {op1[6:0], af[CF]} :
alu_m == alu_rra || alu_m == alu_rr ? {af[CF], op1[7:1]} :
alu_m == alu_sla ? {op1[6:0], 1'b0} :
alu_m == alu_sll ? {op1[6:0], 1'b1} :
alu_m == alu_sra ? {op1[7], op1[7:1]} :
alu_m == alu_srl ? {1'b0, op1[7:1]} :
alu_m == alu_daa ? daa_2 :
alu_m == alu_cpl ? ~op1 :
op1;
wire [7:0] alu_f =
(alu_m == alu_add) ? {sf8, zf8, f58, hf8, f38, oa8, 1'b0, cf8} :
(alu_m == alu_adc) ? {sf8, zf8, f58, ha8[4], f38, oa8, 1'b0, cf8} :
(alu_m == alu_sbc) ? {sf8, zf8, f58, hs8[4], f38, os8, 1'b1, cf8} :
(alu_m == alu_sub) ? {sf8, zf8, f58, hf8, f38, os8, 1'b1, cf8} :
(alu_m == alu_cp) ? {sf8, zf8, op2[5], hf8, op2[3], os8, 1'b1, cf8} :
(alu_m == alu_and) ? {sf8, zf8, f58, 1'b1, f38, pf8, 2'b00} :
(alu_m == alu_xor || alu_m == alu_or) ? {sf8, zf8, f58, 1'b0, f38, pf8, 2'b00} :
(alu_m == alu_inc) ? {sf8, zf8, f58, hf8, f38, oa8, 1'b0, af[CF]} :
(alu_m == alu_dec) ? {sf8, zf8, f58, hf8, f38, os8, 1'b1, af[CF]} :
(alu_m == alu_rlca || alu_m == alu_rla) ?
{af[SF], af[ZF], f58, 1'b0, f38, af[PF], 1'b0, op1[7]} :
(alu_m == alu_rrca || alu_m == alu_rra) ?
{af[SF], af[ZF], f58, 1'b0, f38, af[PF], 1'b0, op1[0]} :
(alu_m == alu_rlc || alu_m == alu_rl || alu_m == alu_sla || alu_m == alu_sll) ?
{sf8, zf8, f58, 1'b0, f38, pf8, 1'b0, op1[7]} :
(alu_m == alu_rrc || alu_m == alu_rr || alu_m == alu_sra || alu_m == alu_srl) ?
{sf8, zf8, f58, 1'b0, f38, pf8, 1'b0, op1[0]} :
(alu_m == alu_daa) ? {sf8, zf8, f58, af[4]^daa_2[4], f38, pf8, af[NF], daa_cf} :
(alu_m == alu_cpl) ? {af[SF], af[ZF], f58, 1'b1, f38, af[PF], 1'b1, af[CF]} :
(alu_m == alu_scf) ? {af[SF], af[ZF], f58, 1'b0, f38, af[PF], 1'b0, 1'b1} :
(alu_m == alu_ccf) ? {af[SF], af[ZF], f58, af[CF], f38, af[PF], 1'b0, ~af[CF]} :
af[15:8];
wire daa_hf = af[HF] | (af[3:0] > 8'h09);
wire daa_cf = af[CF] | (af[7:0] > 8'h99);
wire [7:0] daa_1 =
af[NF] ? (daa_hf ? af[7:0] - 6 : af[7:0]) :
(daa_hf ? af[7:0] + 6 : af[7:0]);
wire [7:0] daa_2 =
af[NF] ? (daa_cf ? daa_1 - 16'h60 : daa_1) :
(daa_cf ? daa_1 + 16'h60 : daa_1);
wire [15:0] do_hl_op2 =
opcode[5:4] == 2'b00 ? bc :
opcode[5:4] == 2'b01 ? de :
opcode[5:4] == 2'b10 ? hlx : sp;
wire [16:0] ed_hl_op2 = (
i_data[5:4] == 2'b00 ? bc :
i_data[5:4] == 2'b01 ? de :
i_data[5:4] == 2'b10 ? hl : sp) + af[CF];
wire [16:0] do_hl_add = hlx + do_hl_op2;
wire [16:0] ed_hl_adc = hl + ed_hl_op2;
wire [16:0] ed_hl_sbc = hl - ed_hl_op2;
wire [ 7:0] do_hl_flag = {
af[SF],
af[ZF],
do_hl_add[5+8],
hlx[12]^do_hl_op2[12]^do_hl_add[12],
do_hl_add[3+8],
af[PF],
1'b0,
do_hl_add[16]
};
wire [ 7:0] hl_adc_flag = {
ed_hl_adc[15],
ed_hl_adc[15:0] == 0,
ed_hl_adc[13],
ed_hl_adc[12]^hl[12]^ed_hl_op2[12],
ed_hl_adc[11],
(hl[15] == ed_hl_op2[15]) && (ed_hl_adc[15] ^ hl[15]),
1'b0,
ed_hl_adc[16]
};
wire [ 7:0] hl_sbc_flag = {
ed_hl_sbc[15],
ed_hl_sbc[15:0] == 0,
ed_hl_sbc[13],
ed_hl_sbc[12]^hl[12]^ed_hl_op2[12],
ed_hl_sbc[11],
(hl[15] ^ ed_hl_op2[15]) && (ed_hl_sbc[15] ^ hl[15]),
1'b1,
ed_hl_sbc[16]
};
wire [7:0] rrd_w = {af[3:0], i_data[7:4]};
wire [7:0] rrd_a = {af[7:4], i_data[3:0]};
wire [7:0] rld_w = {i_data[3:0], af[3:0]};
wire [7:0] rld_a = {af[7:4], i_data[7:4]};
wire [3:0] ldixy = af[7:0] + i_data;
wire [3:0] cpixy = op1 - op2 - alu_f[4];
wire [7:0] b_dec = bc[15:8] - 1;
wire bit_zf = ~op1[ op2[2:0] ];
wire bit_sf = (op2[2:0] == 7) && !bit_zf;
wire [7:0] bit_flags = {bit_sf, bit_zf, op1[5], 1'b1, op1[3], bit_zf, 1'b0, af[CF]};
wire [7:0] bit_flags_xx = {bit_sf, bit_zf, af[F5F], 1'b1, af[F3F], bit_zf, 1'b0, af[CF]};
wire [7:0] rsop =
op2[2:0] == 0 ? {op1[7:1], op2[3]} :
op2[2:0] == 1 ? {op1[7:2], op2[3], op1[ 0]} :
op2[2:0] == 2 ? {op1[7:3], op2[3], op1[1:0]} :
op2[2:0] == 3 ? {op1[7:4], op2[3], op1[2:0]} :
op2[2:0] == 4 ? {op1[7:5], op2[3], op1[3:0]} :
op2[2:0] == 5 ? {op1[7:6], op2[3], op1[4:0]} :
op2[2:0] == 6 ? {op1[7], op2[3], op1[5:0]} :
{ op2[3], op1[6:0]};
always @(negedge clock)
if (reset_n == 1'b0) begin
af <= 16'hFFFF;
sp <= 16'hFFFF;
end
else if (hold) begin
if (exxw)
case (exxw)
spec_exaf: begin af <= af_prime; af_prime <= af; end
spec_exx: begin
bc_prime <= bc; bc <= bc_prime;
de_prime <= de; de <= de_prime;
hl_prime <= hl; hl <= hl_prime;
end
spec_exdehl: begin de <= hl; hl <= de; end
endcase
else if (ldcmd)
case (ldcmd)
ldcmd_ldi: begin bc <= bc - 1; hl <= hl + 1; de <= de + 1; end
ldcmd_ldd: begin bc <= bc - 1; hl <= hl - 1; de <= de - 1; end
ldcmd_cpi: begin bc <= bc - 1; hl <= hl + 1; end
ldcmd_cpd: begin bc <= bc - 1; hl <= hl - 1; end
endcase
else if (reg_w16)
case (reg_id)
0: bc <= reg_dt;
1: de <= reg_dt;
2: case (prefix) 0: hl <= reg_dt; 1: ix <= reg_dt; 2: iy <= reg_dt; endcase
3: sp <= reg_dt;
endcase
else if (reg_w8)
case (reg_id)
0: bc[15:8] <= reg_dt;
1: bc[ 7:0] <= reg_dt;
2: de[15:8] <= reg_dt;
3: de[ 7:0] <= reg_dt;
4: case (prefix) 0: hl[15:8] <= reg_dt; 1: ix[15:8] <= reg_dt; 2: iy[15:8] <= reg_dt; endcase
5: case (prefix) 0: hl[ 7:0] <= reg_dt; 1: ix[ 7:0] <= reg_dt; 2: iy[ 7:0] <= reg_dt; endcase
7: af[ 7:0] <= reg_dt;
endcase
if (reg_wfex) af[15:8] <= flag_ex;
else if (reg_wf) af[15:8] <= alu_f;
prefix <= set_prefix;
end
endmodule