§ Код процессора
Процессор проходит все тесты 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