§ Описание пинов
- clock — тактовая частота, обычно 25 мгц
- reset_n — сброс процессора на 0
- ce — если 1, такты включены (chip enabled)
- in — входящие данные
- address — 16-битный адрес (в том числе порт)
- we — запись в память
- pw — запись в порт
- rd — чтение из порта
- out — значение на запись в память или порт
§ Ядро процессора
Процессор содержит почти все 256 инструкции, кроме отключенных EXX и EX AF,AF', если раскомментировать, то они активируются. Нет префиксов IX,IY, битовых префиксов и ED-инструкции.
module kr580
(
input clock,
input reset_n,
input ce,
input [ 7:0] in,
output [15:0] address,
output reg we,
output reg pw,
output reg rd,
output reg [ 7:0] out,
input wire irq
);
localparam
ALU_ADD = 0, ALU_ADC = 1, ALU_SUB = 2, ALU_SBC = 3,
ALU_AND = 4, ALU_XOR = 5, ALU_OR = 6, ALU_CP = 7,
ALU_RLC = 0, ALU_RRC = 1, ALU_RL = 2, ALU_RR = 3,
ALU_DAA = 4, ALU_CPL = 5, ALU_SCF = 6, ALU_CCF = 7;
localparam
REG_B = 0, REG_C = 1, REG_D = 2, REG_E = 3,
REG_H = 4, REG_L = 5, REG_M = 6, REG_A = 7,
REG_BC = 0, REG_DE = 1, REG_HL = 2, REG_SP = 3;
localparam CF = 0, NF = 1, PF = 2, AF = 4, ZF = 6, SF = 7;
localparam
EX_DE_HL = 1, EX_AF = 2,
INCSP2 = 3, DECSP2 = 4,
EXX = 5;
initial begin we = 0; out = 0; end
assign address = alt ? cp : pc;
reg [ 3:0] t = 0;
reg [ 2:0] m = 0;
reg ei = 0;
reg ei_ = 0;
reg [15:0] cp = 0;
reg alt = 1'b0;
reg [15:0] bc = 16'hAFB1, de = 16'h0305, hl = 16'hBEEF;
reg [15:0] bc_ = 16'h0000, de_ = 16'h0000, hl_ = 16'h0000;
reg [15:0] pc = 16'h0000, sp = 16'h0001;
reg [ 1:0] im = 2'b00;
reg [ 7:0] i = 8'h00,
a = 8'h0A, a_ = 8'hFF,
f = 8'b11000100, f_ = 8'h00;
wire [ 7:0] opcode = t ? latch : in;
reg [ 7:0] latch = 8'h00;
reg irqp = 1'b0;
reg _b = 1'b0;
reg _w = 1'b0;
reg [ 2:0] _n = 3'h0;
reg [ 7:0] _l = 8'h00;
reg [ 7:0] _u = 8'h00;
reg [ 7:0] _f = 8'h00;
reg fw;
reg [ 2:0] spec;
wire [15:0] pci = pc + 1;
wire [15:0] pcn = pci + {{8{in[7]}}, in[7:0]};
wire [7:0] ccc = {f[SF], ~f[SF], f[PF], ~f[PF], f[CF], ~f[CF], f[ZF], ~f[ZF]};
wire ccx = ccc[op53] || opcode == 8'hC9 || opcode == 8'hC3 || opcode == 8'hCD;
wire [2:0] op20 = opcode[2:0];
wire [2:0] op53 = opcode[5:3];
wire [1:0] op54 = opcode[5:4];
wire [7:0] r20 =
op20 == REG_B ? bc[15:8] : op20 == REG_C ? bc[ 7:0] :
op20 == REG_D ? de[15:8] : op20 == REG_E ? de[ 7:0] :
op20 == REG_H ? hl[15:8] : op20 == REG_L ? hl[ 7:0] :
op20 == REG_M ? in : a;
wire [7:0] r53 =
op53 == REG_B ? bc[15:8] : op53 == REG_C ? bc[ 7:0] :
op53 == REG_D ? de[15:8] : op53 == REG_E ? de[ 7:0] :
op53 == REG_H ? hl[15:8] : op53 == REG_L ? hl[ 7:0] :
op53 == REG_M ? in : a;
wire [15:0] r16 =
op54 == REG_BC ? bc :
op54 == REG_DE ? de :
op54 == REG_HL ? hl : sp;
wire [16:0] hladd = hl + r16;
wire [8:0] incdec = opcode[0] ? r53 - 1 : r53 + 1;
wire r53ido = r53 == (127 + opcode[0]);
wire [7:0] idflag = {incdec[7], incdec[7:0] == 8'b0, 1'b0, incdec[4] ^ r53[4], 1'b0, r53ido, 1'b0, incdec[8]};
always @(posedge clock)
if (reset_n == 1'b0) begin t <= 0; pc <= 0; alt <= 0; end
else if (ce) begin
alt <= 0;
_b <= 0;
_w <= 0;
we <= 0;
pw <= 0;
rd <= 0;
fw <= 0;
spec <= 0;
if (t == 0 && ei && (irqp != irq)) begin
t <= 1;
alt <= 1;
we <= 1;
cp <= sp - 1;
irqp <= irq;
out <= (in == 8'h76) ? pci[15:8] : pc[15:7];
latch <= 8'hFF;
{ei,ei_} <= 0;
if (in == 8'h76) pc <= pc + 1;
end
else begin
t <= t + 1;
if (t == 0) begin
latch <= in;
ei <= ei_;
pc <= pc + 1;
end
casex (opcode)
8'b00_000_000: t <= 0;
8'b00_001_000: begin t <= 0; spec <= EX_AF; end
8'b00_010_000: case (t)
0: begin
_b <= 1;
_n <= REG_B;
_l <= bc[15:8] - 1;
if (bc[15:8] == 1) pc <= pc + 2;
end
1: begin t <= 0; pc <= pcn; end
endcase
8'b00_011_000: if (t == 1) begin t <= 0; pc <= pcn; end
8'b00_1xx_000: case (t)
0: if (!ccc[opcode[4:3]]) begin t <= 0; pc <= pc + 2; end
1: begin t <= 0; pc <= pcn; end
endcase
8'b00_xx0_001: case (t)
0: begin _n <= opcode[5:4]; end
1: begin pc <= pc + 1; _l <= in; end
2: begin pc <= pc + 1; _u <= in; _w <= 1; t <= 0; end
endcase
8'b00_xx1_001: begin
t <= 0;
_w <= 1;
_n <= REG_HL;
{_u, _l} <= hladd;
_f[NF] <= 1'b0;
_f[CF] <= hladd[16];
_f[ZF] <= hladd[15:0] == 0;
_f[SF] <= hladd[15];
end
8'b00_0x0_010: case (t)
0: begin alt <= 1; cp <= opcode[4] ? de : bc; out <= a; we <= 1; end
1: begin alt <= 0; t <= 0; end
endcase
8'b00_0x1_010: case (t)
0: begin alt <= 1; cp <= opcode[4] ? de : bc; end
1: begin t <= 0; _n <= REG_A; _b <= 1; _l <= in; end
endcase
8'b00_100_010: case (t)
1: begin cp[ 7:0] <= in; pc <= pc + 1; end
2: begin cp[15:8] <= in; we <= 1; alt <= 1; out <= hl[ 7:0]; pc <= pc + 1; end
3: begin cp <= cp + 1; we <= 1; alt <= 1; out <= hl[15:8]; end
4: begin t <= 0; end
endcase
8'b00_101_010: case (t)
1: begin pc <= pc + 1; cp[ 7:0] <= in; end
2: begin pc <= pc + 1; cp[15:8] <= in; alt <= 1; end
3: begin _n <= REG_L; _b <= 1; _l <= in; alt <= 1; cp <= cp + 1; end
4: begin _n <= REG_H; _b <= 1; _l <= in; t <= 0; end
endcase
8'b00_110_010: case (t)
1: begin cp[ 7:0] <= in; pc <= pc + 1; out <= a; end
2: begin cp[15:8] <= in; pc <= pc + 1; we <= 1; alt <= 1; end
3: begin t <= 0; end
endcase
8'b00_111_010: case (t)
1: begin pc <= pc + 1; cp[ 7:0] <= in; end
2: begin pc <= pc + 1; cp[15:8] <= in; alt <= 1; end
3: begin _b <= 1; _n <= REG_A; _l <= in; t <= 0; end
endcase
8'b00_000_011: begin t <= 0; {_u, _l} <= bc + 1; _n <= 0; _w <= 1; end
8'b00_010_011: begin t <= 0; {_u, _l} <= de + 1; _n <= 1; _w <= 1; end
8'b00_100_011: begin t <= 0; {_u, _l} <= hl + 1; _n <= 2; _w <= 1; end
8'b00_110_011: begin t <= 0; {_u, _l} <= sp + 1; _n <= 3; _w <= 1; end
8'b00_001_011: begin t <= 0; {_u, _l} <= bc - 1; _n <= 0; _w <= 1; end
8'b00_011_011: begin t <= 0; {_u, _l} <= de - 1; _n <= 1; _w <= 1; end
8'b00_101_011: begin t <= 0; {_u, _l} <= hl - 1; _n <= 2; _w <= 1; end
8'b00_111_011: begin t <= 0; {_u, _l} <= sp - 1; _n <= 3; _w <= 1; end
8'b00_110_10x: case (t)
0: begin cp <= hl; alt <= 1; end
1: begin
_f <= idflag;
out <= incdec;
fw <= 1;
we <= 1;
alt <= 1;
end
2: t <= 0;
endcase
8'b00_xxx_10x: begin
t <= 0;
_n <= op53;
_b <= 1;
_l <= incdec;
_f <= idflag;
fw <= 1;
end
8'b00_xxx_110: case (t)
0: cp <= hl;
1: begin
t <= op53 == REG_M ? 2 : 0;
we <= op53 == REG_M;
alt <= op53 == REG_M;
_b <= op53 != REG_M;
_n <= op53;
_l <= in;
out <= in;
pc <= pc + 1;
end
2: t <= 0;
endcase
8'b00_xxx_111: begin
t <= 0;
fw <= 1;
_n <= REG_A;
_b <= 1;
_l <= alu_sr;
_f <= alu_sf;
end
8'b01_110_110: begin pc <= pc; t <= 0; end
8'b01_xxx_110: case (t)
0: begin alt <= 1; cp <= hl; end
1: begin t <= 0; _b <= 1; _n <= op53; _l <= in; end
endcase
8'b01_110_xxx: case (t)
0: begin alt <= 1; cp <= hl; we <= 1; out <= r20; end
1: begin t <= 0; end
endcase
8'b01_xxx_xxx: begin
t <= 0;
_b <= 1;
_n <= op53;
_l <= r20;
end
8'b10_xxx_110: case (t)
0: begin cp <= hl; alt <= 1; end
1: begin
t <= 0;
fw <= 1;
_b <= (op53 != ALU_CP);
_l <= alu_r;
_f <= alu_f;
_n <= REG_A;
end
endcase
8'b10_xxx_xxx: begin
t <= 0;
fw <= 1;
_b <= (op53 != ALU_CP);
_l <= alu_r;
_f <= alu_f;
_n <= REG_A;
end
8'b11_001_001,
8'b11_xxx_000: case (t)
0: begin t <= ccx; alt <= ccx; cp <= sp; end
1: begin pc[ 7:0] <= in; alt <= 1; cp <= cp + 1; end
2: begin pc[15:8] <= in; spec <= INCSP2; t <= 0; end
endcase
8'b11_xx0_001: case (t)
0: begin cp <= sp; alt <= 1; spec <= INCSP2; end
1: begin _l <= in; alt <= 1; cp <= cp + 1; end
2: begin
_u <= in;
t <= 0;
if (opcode[5:4] == 2'b11)
begin _n <= REG_A; _b <= 1; _l <= in; fw <= 1'b1; _f <= _l; end
else begin _n <= opcode[5:4]; _w <= 1; end
end
endcase
8'b11_011_001: begin t <= 0; spec <= EXX; end
8'b11_101_001: begin t <= 0; pc <= hl; end
8'b11_111_001: begin t <= 0; _w <= 1; _n <= REG_SP; {_u, _l} <= hl; end
8'b11_000_011,
8'b11_xxx_010: case (t)
0: if (!ccx) begin t <= 0; pc <= pc + 3; end
1: begin _l <= in; pc <= pc + 1'b1; end
2: begin pc <= {in, _l}; t <= 0; end
endcase
8'b11_010_011: case (t)
1: begin
pw <= 1;
alt <= 1;
cp <= in;
pc <= pc + 1;
out <= a;
end
2: t <= 0;
endcase
8'b11_011_011: case (t)
1: begin pc <= pc + 1; cp <= in; rd <= 1; alt <= 1; end
2: begin _b <= 1; _n <= REG_A; _l <= in; t <= 0; end
endcase
8'b11_100_011: case (t)
0: begin alt <= 1; cp <= sp; end
1: begin alt <= 1; _l <= in; out <= hl[ 7:0]; we <= 1; end
2: begin alt <= 1; cp <= cp + 1; end
3: begin alt <= 1; _u <= in; out <= hl[15:8]; we <= 1; _w <= 1; _n <= REG_HL; end
4: begin t <= 0; end
endcase
8'b11_101_011: begin t <= 0; spec <= EX_DE_HL; end
8'b11_11x_011: begin t <= 0; ei_ <= opcode[3]; end
8'b11_001_101,
8'b11_xxx_100: case (t)
0: if (!ccx) begin t <= 0; pc <= pc + 3; end
1: begin _l <= in; pc <= pc + 1; end
2: begin
alt <= 1;
we <= 1;
cp <= sp - 1;
out <= pci[15:8];
_u <= in;
end
3: begin
alt <= 1;
we <= 1;
out <= pci[ 7:0];
cp <= cp - 1;
pc <= {_u, _l};
spec <= DECSP2;
end
4: t <= 0;
endcase
8'b11_xx0_101: case (t)
0: begin
alt <= 1;
we <= 1;
cp <= sp - 1;
out <= (op54 == 2'b11) ? a : r16[15:8];
spec <= DECSP2;
end
1: begin
t <= 2;
alt <= 1;
we <= 1;
cp <= cp - 1;
out <= (op54 == 2'b11) ? f : r16[ 7:0];
end
2: t <= 0;
endcase
8'b11_xxx_110: case (t)
1: begin
t <= 0;
pc <= pc + 1;
fw <= 1;
_b <= (op53 != ALU_CP);
_l <= alu_r;
_f <= alu_f;
_n <= REG_A;
end
endcase
8'b11_xxx_111: case (t)
0: begin out <= pci[15:8]; cp <= sp - 1; we <= 1; alt <= 1; end
1: begin out <= pc [ 7:0]; cp <= cp - 1; we <= 1; alt <= 1; end
2: begin spec <= DECSP2; pc <= {op53, 3'b000}; t <= 0; end
endcase
endcase
end
end
wire is_add = (op53 == ALU_ADD) || (op53 == ALU_ADC);
wire is_lgc = (op53 == ALU_AND) || (op53 == ALU_OR) || op53 == ALU_XOR;
wire [16:0] alu_r =
op53 == ALU_ADD ? a + r20 :
op53 == ALU_ADC ? a + r20 + f[CF] :
op53 == ALU_SBC ? a - r20 - f[CF] :
op53 == ALU_AND ? a & r20 :
op53 == ALU_XOR ? a ^ r20 :
op53 == ALU_OR ? a | r20 : a - r20;
wire carry = alu_r[8];
wire sign = alu_r[7];
wire zero = ~|alu_r[7:0];
wire prty = ~^alu_r[7:0];
wire aux = a[4] ^ r20[4] ^ alu_r[4];
wire over = (a[7] ^ r20[7] ^ is_add) && (a[7] != alu_r[7]);
wire [7:0] alu_f =
is_lgc? {sign, zero, alu_r[5], 1'b0, alu_r[3], prty, 1'b0, 1'b0} :
{sign, zero, alu_r[5], aux, alu_r[3], over, !is_add, carry};
wire [7:0] daa =
(f[NF]) ? a - ((f[AF] | (a[3:0] > 4'h9)) ? 8'h06 : 0) - ((f[CF] | (a[7:0] > 8'h99)) ? 8'h60 : 0) :
a + ((f[AF] | (a[3:0] > 4'h9)) ? 8'h06 : 0) + ((f[CF] | (a[7:0] > 8'h99)) ? 8'h60 : 0);
wire sr_prty = ~^alu_sr[7:0];
wire sr_zero = alu_sr[7:0] == 8'b0;
wire [7:0] alu_sr =
op53 == ALU_RLC ? {a[6:0], a[ 7]} :
op53 == ALU_RRC ? {a[0], a[7:1]} :
op53 == ALU_RL ? {a[6:0], f[ CF]} :
op53 == ALU_RR ? {f[CF], a[7:1]} :
op53 == ALU_DAA ? daa :
op53 == ALU_CPL ? ~a : a;
wire [7:0] alu_sf =
op53 == ALU_RLC || op53 == ALU_RL ? {alu_sr[7], sr_zero, 3'b000, sr_prty, 1'b1, a[7]} :
op53 == ALU_RRC || op53 == ALU_RR ? {alu_sr[7], sr_zero, 3'b000, sr_prty, 1'b1, a[0]} :
op53 == ALU_DAA ? {daa[7], sr_zero, daa[5], a[4] ^ daa[4], daa[3], sr_prty, f[NF], f[CF] | (a > 8'h99)} :
op53 == ALU_CPL ? {f[SF], f[ZF], 1'b0, 1'b1, 1'b0, f[PF], 1'b1, f[CF]} :
op53 == ALU_SCF ? {f[SF], f[ZF], 1'b0, f[AF], 1'b0, f[PF], 1'b1, 1'b1} :
{f[SF], f[ZF], 1'b0, f[AF], 1'b0, f[PF], 1'b1, !f[CF]};
always @(negedge clock)
begin
if (fw) f <= _f;
case (spec)
INCSP2: sp <= sp + 2;
DECSP2: sp <= sp - 2;
EX_DE_HL: begin {de, hl} <= {hl, de}; end
default:
if (_w) case (_n)
REG_BC: bc <= {_u, _l};
REG_DE: de <= {_u, _l};
REG_HL: hl <= {_u, _l};
REG_SP: sp <= {_u, _l};
endcase
else if (_b) case (_n)
REG_B: bc[15:8] <= _l;
REG_C: bc[ 7:0] <= _l;
REG_D: de[15:8] <= _l;
REG_E: de[ 7:0] <= _l;
REG_H: hl[15:8] <= _l;
REG_L: hl[ 7:0] <= _l;
REG_A: a <= _l;
endcase
endcase
end
endmodule