Лисья Нора

§ Код процессора

Этот процессор был мной написан "с нуля". Процессор проходит все тесты ZXALL. Дата последней ревизии: 21 сен 2024.
/* verilator lint_off WIDTH */
/* verilator lint_off CASEX */
/* verilator lint_off CASEINCOMPLETE */
/* verilator lint_off CASEOVERLAP */
module z80
(
// -----------------------------------------------------------------
// Ввод-вывод
// -----------------------------------------------------------------
input clock, // 3.5 или 25 Мгц
input reset_n, // =0 Сброс процессора
input compat, // =1 Включена совместимость с Z80 Cycles
input hold, // Если 0: не выполнять инструкции
input irq, // Вызов IRQ на позитивном фронте
output [15:0] address, // Адресная шина
input [ 7:0] i_data, // Входящие данные с шины
output reg [ 7:0] o_data, // Данные на запись
output reg we, // =1 Запись в память
output m0, // =1 Сигнал начала инструкции
input [ 7:0] portin, // portin=port[address]
output reg portrd, // Сигнал чтения из порта address
output reg portwe, // Сигнал записи в порт address
// -----------------------------------------------------------------
// Регистры процессора z80 [здесь для отладки]
// -----------------------------------------------------------------
// Основной и дополнительный наборы регистров
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
// -----------------------------------------------------------------------------
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)
// Запись PC[7:0]
0: begin
t_state <= 1;
// Писать в память
bus <= 1; we <= 1; cp <= sp - 2; o_data <= pc[7:0];
// SP=SP-2
reg_w16 <= 1; reg_dt <= sp - 2; reg_id <= 3;
end
// Запись PC[15:8]
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
// imode=0 [8080], imode=1 [standart]
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
// На первом такте инструкции обнаружен вызов IRQ (и прерывания разрешены)
else if (iff1 && prefix == 0 && t_state == 0 && irq ^ irq_latch) begin
// Проверить, что прерывания разрешены и что IRQ=0->1
if (irq) begin
irq_process <= 1;
iff1 <= 1'b0; iff1_ <= 1'b0;
iff2 <= 1'b0; iff2_ <= 1'b0;
// Если текущая инструкция HALT
if (i_data == 8'h76) pc <= pc + 1;
end
irq_latch <= irq;
end
// Исполнение инструкции
else begin
// Защелкнуть опкод и увеличить R+1
if (t_state == 0) begin
// Если запрошено прерывание imode=0, то выбирает FF
opcode_latch <= i_data;
pc <= pc + 1;
ir[6:0] <= ir[6:0] + 1;
// Защелкивание DI/EI через одну инструкцию
if (prefix == 0) begin
iff1 <= iff1_;
iff2 <= iff2_;
end
end
t_state <= t_state + 1;
casex (opcode)
// 1T|4T: EX AF,AF'
8'b00_001_000: begin exxw <= spec_exaf; {set_prefix, t_state} <= 0; delay <= 4-1; end
// 1/2T|8/13T: DJNZ *
8'b00_010_000: case (t_state)
0: begin
// Запись в регистр B
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
// 2T|12T: JR *
8'b00_011_000: case (t_state)
1: begin pc <= pc + signex + 1; {set_prefix, t_state} <= 0; delay <= 12-2; end
endcase
// 1/2T|12/7T: JR cc, *
8'b00_1xx_000: case (t_state)
0: begin
set_prefix <= 0;
// Если условие не совпало, пропуск +2 байта вперед
// Пример, opcode[4:3]=0, то если ZF=1, то произойдет выход из JR
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
// 3T|10T: LD r16, nn
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
// 1T/11T: ADD HL, r16
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
// 2T|7T: LD (BC|DE), A
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
// 2T|7T: LD A, (BC|DE)
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
// 5T|16T: LD (**), HL
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
// 4T|13T: LD (**), A
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
// 5T|16T: LD HL, (**)
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 <= /*L*/ 5; reg_dt <= i_data; reg_w8 <= 1; cp <= cp + 1; end
4: begin
reg_id <= /*H*/ 4; reg_dt <= i_data; reg_w8 <= 1;
{set_prefix, t_state, bus} <= 0; delay <= 16-5;
end
endcase
// 4T|13T: LD A, (**)
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 <= /*A*/ 7; reg_dt <= i_data; reg_w8 <= 1;
{set_prefix, t_state, bus} <= 0; delay <= 13-4;
end
endcase
// 1T|6T: INC|DEC r16
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
// 4T|11T: INC|DEC (HL)
// 6T|23T: INC|DEC (IX|IY+d)
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
// Дочитать смещение к IX|IY
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
// 2T|4T: INC|DEC r8
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
// 3T|10T: LD (HL), *
// 5T|19T: LD (IX|IY+d), *
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
// 2T|7T: LD r8, *
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
// 4T: <RLCA,RRCA,RLA,RRA,DAA,CPL,SCF,CCF>
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
// 1T: HALT
8'b01_110_110: begin pc <= pc; {set_prefix, t_state} <= 0; delay <= 4-1; end
// 2T|7T: LD (HL), r8
// 4T|19T: LD (IX|IY+d), r8
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
// 2T|7T: LD r8, (HL)
// 4T|19T: LD r8, (IX|IY+d)
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
// 1T|4T: LD r8, r8
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
// 3T|7T: <ALU> a, (HL)
// 5T|19T: <ALU> a, (IX|IY+d)
8'b10_xxx_110: case (t_state)
// Установить адрес на шину (если это HL)
0: begin
bus <= prefix ? 0 : 1;
t_state <= prefix ? 1 : 2;
alu_m <= opcode[5:3];
op1 <= af[7:0];
cp <= hl;
end
// Дочитывание смещения к префиксу и адрес IX|IY+d
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
// 2T|4T: <ALU> a, r8
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
// 1/3T|10/11/5T: RET ccc|RET
8'b11_001_001,
8'b11_xxx_000: case (t_state)
0: begin
set_prefix <= 0;
// Условие не сработало, к следующей инструкции
// Если opcode[0]=1, то RET безусловный
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
// 3T|10T: POP r16
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
// POP AF
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
// 1T/4T: EXX
8'b11_011_001: case (t_state)
0: begin {set_prefix, t_state} <= 0; exxw <= spec_exx; delay <= 4-1; end
endcase
// 1T/4T: JP (HL)
8'b11_101_001: case (t_state)
0: begin pc <= hlx; {set_prefix, t_state} <= 0; delay <= 4-1; end
endcase
// 1T/6T: LD SP, HL
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
// 2/3T|10T: JP ccc, **; JP **
8'b11_000_011,
8'b11_xxx_010: case (t_state)
0: begin
set_prefix <= 0;
// Условие не сработало, к следующей инструкции
// Если opcode[0]=1, то переход безусловный
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
// Необходимо для получения HPTR
3: begin hptr <= i_data; pc <= pc + 1; t_state <= 0; delay <= 10-2; end
endcase
// CB: Битовые инструкции
// 4T/8T: <opcode> r8
// 5T/15T: <opcode> (HL)
// 5T/23T: <opcode> (IX+*)
// 4T/12T: BIT n,(HL)
// 4T/20T: BIT n,(IX+*)
8'b11_001_011: case (t_state)
// Чтение опкода или смещения
1: begin
pc <= pc + 1;
cp <= prefix ? hlx + signex : hl;
bus <= prefix ? 0 : 1; // Если (Ixy+*), дочитать PC+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;
// Убрать префиксирование для BIT
t_pref <= prefix ? 1 : 0;
set_prefix <= 0;
end
// Исполнение и сохранение
4: casex (opcode_ext[7:6])
// BIT n, r8
// BIT n, (HL)
8'b01: begin
reg_wfex <= 1;
flag_ex <= t_pref ? bit_flags_xx : bit_flags;
// BIT n, (HL)
if (t_pref == 0 && opcode_ext[2:0] == 6)
{flag_ex[5],flag_ex[3]} <= {hptr[5],hptr[3]};
// Все префиксированные выполняются за 20T
{bus, t_state} <= 0;
delay <= t_pref ? 20-4-5 : (opcode_ext[2:0] == 6 ? 12-4 : 8-4);
end
// SHIFT|RES|SET n, reg|idata
// Сохранение в регистры и в память (если выбрано)
8'b00,
8'b1x: begin
// Кроме HL и префиксированных
we <= (opcode_ext[2:0] == 6) || t_pref;
reg_w8 <= (opcode_ext[2:0] != 6);
reg_id <= opcode_ext[2:0];
// Если это RES|SET, то из rsop, иначе из alu_r
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;
// Нет префикса и нет (HL)
if (t_pref == 0 && (opcode_ext[2:0] != 6)) begin
{bus, t_state} <= 0; delay <= 8-4;
end
end
endcase
// Завершение записи для инструкции [00-3F,80-FF]
5: begin {bus, t_state} <= 0; delay <= t_pref ? 23-4-6 : 15-5; end
endcase
// 3T/11T: OUT (*), A
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
// 3T/11T: IN A,(*)
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
// 5T/19T: EX (SP), HL
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
// 1T/4T: EX DE,HL
8'b11_101_011: case (t_state)
0: begin {set_prefix, t_state} <= 0; exxw <= spec_exdehl; delay <= 4-1; end
endcase
// 1T/4T: DI/EI
8'b11_11x_011: case (t_state)
// Срабатывает активация iff1/2 через одну инструкцию
0: begin
iff1_ <= opcode[3];
iff2_ <= opcode[3];
{set_prefix, t_state} <= 0; delay <= 4-1;
end
endcase
// 2/5T|10/17T: CALL ccc, **; CALL **
8'b11_001_101,
8'b11_xxx_100: case (t_state)
0: begin
set_prefix <= 0;
// Условие не сработало, к следующей инструкции
// Если opcode[0]=1, то переход безусловный
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
// Для получения HPTR
5: begin hptr <= i_data; pc <= pc + 1; t_state <= 0; delay <= 10-2; end
endcase
// 3T|11T: PUSH r16
8'b11_xx0_101: case (t_state)
// Запись младшего байта
0: begin
bus <= 1;
we <= 1;
cp <= sp - 2;
// sp = 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]; // Флаги (LO)
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]; // Аккумулятор (HI)
endcase
end
2: begin {set_prefix, t_state, bus} <= 0; delay <= 11-3; end
endcase
// EXTENDED
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)
// IN r8, (C)
8'b01_xxx_000: begin cp <= bc; bus <= 1; portrd <= 1; end
// OUT (C), r8
8'b01_xxx_001: begin
bus <= 1;
portwe <= 1;
cp <= bc;
o_data <= reg8_outc;
end
// 2T: SBC|ADC hl, r16
8'b01_xxx_010: begin
reg_w16 <= 1;
reg_wfex <= 1;
reg_id <= 2; // HL
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
// 6T: LD (**),r16 | r16,(**)
8'b01_xxx_011: begin /* nothing */ end
// NEG
8'b01_xxx_100: begin
op1 <= 0;
op2 <= af[7:0];
alu_m <= alu_sub;
end
// RETN/RETI
8'b01_xxx_101: begin
bus <= 1;
cp <= sp;
reg_w16 <= 1;
reg_dt <= sp + 2;
reg_id <= 3;
// RETN, кроме RETI
if (i_data[5:3] != 3'b001) begin
iff1 <= iff2;
iff1_ <= iff2_;
end
end
// IM n: [00120012]
8'b01_xxx_110: begin
i_mode <= i_data[4] ? (i_data[3] ? 2 : 1) : 0;
t_state <= 0; delay <= 8-2;
end
// LD i|r, a
// LD a, i|r
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];
// LD A, I|R записывает флаги
if (i_data[4]) begin
reg_wfex <= 1;
if (i_data[3]) // Если выполняется прерывание то PV=0
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
// RRD |RLD
// LDI |LDD |LDIR|LDDR
// CPI |CPD |CPIR|CPDR
// OUTI|OUTD|OTIR|OTDR
8'b01_10x_111,
8'b10_1xx_00x,
8'b10_1xx_011: begin cp <= hl; bus <= 1; end
// INI |IND |INIR|INDR
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
// NOP инструкция
default: begin t_state <= 0; delay <= 8-2; end
endcase
end
2: begin
t_state <= 2;
n_state <= n_state + 1;
casex (opcode_ext)
// 3T: IN r8, (C)
8'b01_xxx_000: begin
reg_w8 <= 1;
reg_wfex <= 1;
// При записи в 6-й регистр ничего не происходит
reg_id <= opcode_ext[5:3];
reg_dt <= portin;
// Вычисление флагов
flag_ex <= {
portin[7], // S
portin == 0, // Z
portin[5], // F5
1'b0, // H
portin[3], // F3
~^portin[7:0], // P
1'b0, // N
af[CF] // C
};
{t_state, bus} <= 0; delay <= 12-3;
end
// 3T: OUT (C), r8
8'b01_xxx_001: begin {t_state, bus} <= 0; delay <= 12-3; end
// 6T: LD (**), r16
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
// 6T: LD r16, (**)
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
// 4T: RETN/RETI
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
// 3T: NEG
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
// 4T: RRD|RLD
8'b01_10x_111: case (n_state)
0: begin
we <= 1; // Запись в память
reg_w8 <= 1; // Запись в регистр A
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
// 4T: LDI|LDD|LDIR|LDDR
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]
};
// Уменьшить BC--; икремент/декремент HL/DE
ldcmd <= opcode_ext[3] ? ldcmd_ldd : ldcmd_ldi;
end
// Завершение инструкции
1: begin
delay <= 16-4;
// Если это LDIR, LDDR то проверить BC на 0
if (opcode_ext[4] && bc) begin pc <= pc - 2; delay <= 21-4; end
{t_state, bus} <= 0;
end
endcase
// 4T: CPI|CPD|CPIR|CPDR
8'b10_1xx_001: case (n_state)
// Запрос к АЛУ на вычисление CP
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;
// Если это CPIR, CPDR то проверить BC на 0 и чтобы ZF=0
if (opcode_ext[4] && !alu_f[6] && bc)
begin pc <= pc - 2; delay <= 21-4; end
{t_state, bus} <= 0;
end
endcase
// 4T: INI|IND|INIR|INDR
8'b10_1xx_010: case (n_state)
0: begin
// Чтение из порта
we <= 1;
cp <= hl;
o_data <= portin;
// Обновление B
reg_wf <= 1;
reg_w8 <= 1;
reg_id <= 0;
reg_dt <= alu_r;
end
1: begin
// Икремент или декремент HL
reg_w16 <= 1;
reg_id <= 2;
reg_dt <= opcode_ext[3] ? hl - 1 : hl + 1;
delay <= 16-4;
// Если это CPIR, CPDR то проверить B на 0
if (opcode_ext[4] && alu_r[7:0]) begin pc <= pc - 2; delay <= 21-4; end
{t_state, bus} <= 0;
end
endcase
// 4T: OUTI|OUTD|OTIR|OTDR
8'b10_1xx_011: case (n_state)
// Запись в порт, HL++/--, декремент B
0: begin
// Запись в порт значения из памяти
portwe <= 1;
cp <= bc;
o_data <= i_data;
// Инкремент или декремент HL
reg_w16 <= 1;
reg_id <= 2;
reg_dt <= opcode_ext[3] ? hl - 1 : hl + 1;
// Декремент B через АЛУ
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;
// Если это CPIR, CPDR то проверить B на 0
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
// 3T|7T: <ALU> a,*
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
// 3T|11T: RST #n
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
// 1T|4T: Префиксы IX и IY
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; // Фаза исполнения EDh опкода
reg [ 4:0] delay = 0; // Задержка для совместимости
reg bus = 1'b0; // Выбор источника адреса
reg [15:0] cp = 16'h0000; // CurrentPointer: альтернативный address
reg [ 7:0] opcode_latch; // Защелка для опкода
reg [ 7:0] opcode_ext; // Дополнительный опкод
reg [ 1:0] set_prefix = 0; // Команда для установки префикса на обратном фронте
reg [ 1:0] prefix = 0; // Текущий префикс, 0=нет, 1=IX, 2=IY
reg t_pref = 0; // Наличие префикса в запросе инструкции
reg [ 1:0] exxw = 0; // Специальная запись в регистры
reg [ 2:0] ldcmd = 0; // =1 HL++,DE++,BC--; =2 HL++,BC--;
// =3 HL--,DE--,BC--; =4 HL--,BC--
reg reg_w8 = 0; // Писать результат в регистр 8 бит
reg reg_w16 = 0; // Писать результат в регистр 16 бит
reg reg_wfex = 0; // Запись специальных флагов
reg reg_wf = 0; // Запись флагов из alu_f в af[15:8]
reg [ 3:0] reg_id = 0; // Номер регистра для записи
reg [15:0] reg_dt = 0; // Данные для записи в регистр
reg [ 7:0] flag_ex = 0; // Специальные флаги для reg_wfex=1
reg [ 7:0] hptr = 0; // Специальный регистр для BIT n,(HL)
// Аппаратное прерывание
// -----------------------------------------------------------------------------
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;
// Выбор регистра из opcode[2:0]
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];
// Выбор регистра из opcode[5:3]
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];
// Для префикса CB **
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];
// Для OUT (C), r8
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];
// Выбор оригинального H,L при префиксированных инструкциях
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;
// 0-nz, 1-z, 2-nc, 3-c
// 4-po, 5-pe, 6-p, 7-m
wire [7:0] condition = {
~af[SF], af[SF], // 7,6 s
~af[PF], af[PF], // 5,4 p
~af[CF], af[CF], // 3,2 c
~af[ZF], af[ZF] // 1,0 Z
};
// АЛУ
// -----------------------------------------------------------------------------
reg [4:0] alu_m; // Режим работы АЛУ
reg [7:0] op1; // Операнды
reg [7:0] op2;
wire zf8 = alu_r[7:0]==0; // Zero
wire pf8 = ~^alu_r[7:0]; // Parity
wire sf8 = alu_r[7]; // Sign
wire cf8 = alu_r[8]; // Carry
wire f58 = alu_r[5]; // H5 Undocumented
wire f38 = alu_r[3]; // H3 Undocumented
wire hf8 = alu_r[4]^op1[4]^op2[4]; // Half-Carry
wire oa8 = (op1[7] == op2[7]) & (op1[7] != alu_r[7]);
wire os8 = (op1[7] != op2[7]) & (op1[7] != alu_r[7]);
// Специальный расчет флага H
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]} : // a << 1
alu_m == alu_rrca || alu_m == alu_rrc ? {op1[0], op1[7:1]} : // a >> 1
alu_m == alu_rla || alu_m == alu_rl ? {op1[6:0], af[CF]} : // a << 1
alu_m == alu_rra || alu_m == alu_rr ? {af[CF], op1[7:1]} : // a >> 1
alu_m == alu_sla ? {op1[6:0], 1'b0} : // a << 1
alu_m == alu_sll ? {op1[6:0], 1'b1} : // a << 1
alu_m == alu_sra ? {op1[7], op1[7:1]} : // a >> 1
alu_m == alu_srl ? {1'b0, op1[7:1]} : // a >> 1
// Коррекции
alu_m == alu_daa ? daa_2 :
alu_m == alu_cpl ? ~op1 :
// Все остальные
op1;
// Результат флаговых вычислений [S Z F5 H F3 P/V N C]
wire [7:0] alu_f =
// Группа ADD, ADC
(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} :
// Для AND выставляет H=1
(alu_m == alu_and) ? {sf8, zf8, f58, 1'b1, f38, pf8, 2'b00} :
// Другие логические (XOR|OR)
(alu_m == alu_xor || alu_m == alu_or) ? {sf8, zf8, f58, 1'b0, f38, pf8, 2'b00} :
// INC, DEC не меняют флаг CF
(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];
// DAA
// -----------------------------------------------------------------------------
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]) : // SUB
(daa_hf ? af[7:0] + 6 : af[7:0]); // ADD
// Второй этап
wire [7:0] daa_2 =
af[NF] ? (daa_cf ? daa_1 - 16'h60 : daa_1) : // SUB
(daa_cf ? daa_1 + 16'h60 : daa_1); // ADD
// 16-битная операция HL +/- r16
// -----------------------------------------------------------------------------
// Второй операнд для ADD HL, r16
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;
// Второй операнд для ADC|SBC HL, r16
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], // H
do_hl_add[3+8],
af[PF],
1'b0, // N=0
do_hl_add[16] // C=x
};
// Флаги после сложения HL + r16
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]
};
// Флаги после вычитания HL - r16
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]
};
// RLD|RRD
// -----------------------------------------------------------------------------
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]};
// LDI, CPI, INI, OUTI
// -----------------------------------------------------------------------------
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;
// BIT
// -----------------------------------------------------------------------------
wire bit_zf = ~op1[ op2[2:0] ];
wire bit_sf = (op2[2:0] == 7) && !bit_zf;
// Не префиксированные BITs устанавливают Y/X флаги
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]};
// RES|SET, зависит от op2[3]
// -----------------------------------------------------------------------------
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)
// EX AF, AF'
spec_exaf: begin af <= af_prime; af_prime <= af; end
// EXX
spec_exx: begin
bc_prime <= bc; bc <= bc_prime;
de_prime <= de; de <= de_prime;
hl_prime <= hl; hl <= hl_prime;
end
// EX DE, HL
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
// Запись результата в 16-битный регистр
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
// Запись в 8-битный регистр
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