zx_cartridge/FW/src/zx_cartridge.v
MichailKaa 7aaf4a7b21 ext version
batty start, but not work
2026-02-19 23:33:01 +03:00

142 lines
8.2 KiB
Verilog
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

`timescale 1ns / 1ps
// Модуль картриджа для ZX Spectrum
// 19.02.2026 Mikhael Kaa
//
// Аппаратная часть:
// - 4 микросхем AM29F040 (по 512 КБ) -> всего 2 МБ = 256 страницы по 8 КБ.
// - Адресные линии CPU A0..A12 подключены напрямую ко всем микросхемам ПЗУ.
// - Старшие линии адреса A13..A18 формируются внутри этого модуля.
//
// Окно памяти 0x0000..0x3FFF (16 КБ) разделено на две 8килобайтные половины:
// - Нижняя половина (A13 = 0, 0x0000..0x1FFF) : всегда отображается на страницу 0 (BIOS картриджа).
// - Верхняя половина (A13 = 1, 0x2000..0x3FFF) : отображается на выбираемую страницу.
//
// Выбор страницы:
// 8битный номер страницы формируется как reg_bank[7:0].
// - биты [7:6] : выбор одной из четырех микросхем (03).
// - биты [5:0] : выбор 8килобайтной страницы внутри выбранной микросхемы (063).
// Таким образом, можно адресовать любую из 256 страниц.
//
// Регистр управления reg_ctl (8 бит):
// reg_ctl[7] : при установке в 1 отключает ПЗУ картриджа (все выходы пассивны).
// Остальные биты зарезервированы.
//
// Порты ввода‑вывода (запись/чтение, активный уровень низкий):
// bank : запись reg_bank (биты 7..0) происходит, когда
// A15=1, A14=1, A13=0, A7=0, IORQ=0, WR=0. Порт 0xdf7f.
// control : запись регистра управления reg_ctl происходит, когда
// A15=1, A14=0, A13=1, A7=0, IORQ=0, WR=0. Порт 0xbf7f.
// Чтение любого из этих портов возвращает значение соответствующего регистра.
//
// Выходы:
// ZX_ROM_blk активный высокий уровень; блокирует внутреннее ПЗУ ZX Spectrum.
// CR_ROM_oe_n выход разрешения выходов для всех микросхем ПЗУ (активный низкий).
// CR_ROM_A[5:0] линии адреса A13..A18 для микросхем ПЗУ.
// Для нижнего окна (A13=0) на эту шину выставляется 0.
// Для верхнего окна (A13=1) на ней передаётся 6битное смещение страницы.
// CR_ROM_CS[3:0] выбор микросхем (активный низкий). Одна линия становится низкой
// только при обращении к картриджу (cpu_use_rom, MREQ и RD активны,
// картридж не отключён) и совпадении выбранной микросхемы.
// В нижнем окне всегда выбирается микросхема 0.
//
// Сброс: почти все регистры асинхронно очищаются низким уровнем reset_n.
module zx_cartridge (
// Сброс
input reset_n,
// Управляющие сигналы CPU
input iorq_n,
input rd_n,
input wr_n,
input mreq_n,
// Часть адресной шины CPU
input A7,
input A13,
input A14,
input A15,
inout [7:0] D,
// Сигнал блокировки внутреннего ПЗУ ZX Spectrum
output ZX_ROM_blk,
// Выход разрешения для ПЗУ картриджа (активный низкий)
output CR_ROM_oe_n,
// Старшие биты адреса для ПЗУ (A13..A18)
output [5:0] CR_ROM_A,
// Выбор кристаллов для четырех ПЗУ 29040 (активный низкий)
output [3:0] CR_ROM_CS
);
// 8битный банковый регистр (хранит биты 7..0 номера страницы)
reg [7:0] reg_bank = 8'b0;
// 8битный регистр управления:
// reg_ctl[6:0] - доступны софтам после сброса
// reg_ctl[7] отключение картриджа (1 = отключён)
reg [7:0] reg_ctl = 8'b0;
// В спектруме декодирование порта 7ffd идет по А1, А15 == 0.
// Декодирование портов ввода‑вывода картриджа
wire bank = iorq_n | A7 | A13 | ~A14 | ~A15; // A15=1, A14=1, A13=0, A7=0
wire control = iorq_n | A7 | ~A13 | A14 | ~A15; // A15=1, A14=0, A13=1, A7=0
// CPU обращается к области ПЗУ 0x0000..0x3FFF (A15=0, A14=0)
wire cpu_use_rom = ~(A14 | A15);
wire is_enable = reg_ctl[7];
wire write_bank = ~bank & ~wr_n;
always @(posedge write_bank or negedge reset_n) begin
if (!reset_n)
reg_bank <= 8'b0;
else
reg_bank <= D;
end
wire write_control = ~control & ~wr_n;
always @(posedge write_control or negedge reset_n) begin
if (!reset_n)
reg_ctl[7] <= 1'b0; // только бит отключения сбрасывается
else
reg_ctl <= D;
end
// Чтение регистров обратно в CPU
assign D = (~bank & ~rd_n) ? reg_bank[7:0] :
(~control & ~rd_n) ? reg_ctl : 8'bz;
// Разделение на выбор микросхемы (2 бита) и смещение страницы (6 бит)
wire [1:0] chip_sel = reg_bank[7:6]; // какая из 4 микросхем (0..3)
wire [5:0] page_offs = reg_bank[5:0]; // смещение внутри микросхемы (0..63)
// Условие доступа к картриджу:
// CPU читает область ПЗУ, MREQ и RD активны, картридж не отключён
wire rom_access = cpu_use_rom & ~mreq_n & ~rd_n & ~is_enable;
// Сигнал разрешения выходов и блокировки ПЗУ
assign CR_ROM_oe_n = ~rom_access;
assign ZX_ROM_blk = rom_access;
// CR_ROM_A зависит от окна:
// нижнее окно (A13=0) : принудительный адрес 0 (страница 0)
// верхнее окно (A13=1) : используется смещение из регистра
assign CR_ROM_A = (A13 == 1'b0) ? 6'b0 : page_offs;
// Формирование сигналов выбора микросхем:
// Для нижнего окна всегда включается микросхема 0.
// Для верхнего окна включается микросхема, выбранная chip_sel.
// CS активен низким уровнем и активен только при rom_access = истина.
// CS активен (0) только при rom_access = 1 и выполнении условий:
// - для микросхемы 0: либо нижнее окно (A13=0), либо верхнее окно с chip_sel = 0
// - для микросхем 1..3: только верхнее окно (A13=1) и chip_sel равен номеру микросхемы
assign CR_ROM_CS[0] = ~( rom_access &
( (A13 == 1'b0) || // нижнее окно всегда выбирает чип 0
( (A13 == 1'b1) && (chip_sel == 2'd0) ) ) );
assign CR_ROM_CS[1] = ~( rom_access &
( (A13 == 1'b1) && (chip_sel == 2'd1) ) );
assign CR_ROM_CS[2] = ~( rom_access &
( (A13 == 1'b1) && (chip_sel == 2'd2) ) );
assign CR_ROM_CS[3] = ~( rom_access &
( (A13 == 1'b1) && (chip_sel == 2'd3) ) );
endmodule