mirror of
https://github.com/MikhaelKaa/zx_cartridge.git
synced 2026-03-16 14:37:57 +03:00
Оригинальный картридж. Работает.
This commit is contained in:
parent
a24c5d1045
commit
aeed47c59f
@ -1,6 +1,6 @@
|
|||||||
# Для тестирования модуля неодходимо чтобы тест назывался %имя_модуля%_tb
|
# Для тестирования модуля неодходимо чтобы тест назывался %имя_модуля%_tb
|
||||||
|
|
||||||
TARGET ?= zx_cartrige
|
TARGET ?= zx_cartridge
|
||||||
ICARUS = iverilog
|
ICARUS = iverilog
|
||||||
|
|
||||||
all:
|
all:
|
||||||
|
|||||||
65
FW/src/zx_cartridge.v
Normal file
65
FW/src/zx_cartridge.v
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
// Файл: zx_cartridge.v
|
||||||
|
// Модуль картриджа ZX Spectrum
|
||||||
|
// 17.02.2026 Miсhael Kaa
|
||||||
|
// Шина адреса CPU A0...A12 подключается напрямую к микросхеме CR_ROM
|
||||||
|
`timescale 1ns / 1ps
|
||||||
|
module zx_cartridge #(
|
||||||
|
// значение по умолчанию для оригинального картриджа
|
||||||
|
parameter SELF_LOCK_VAL = 15
|
||||||
|
)(
|
||||||
|
// Сброс
|
||||||
|
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
|
||||||
|
output ZX_ROM_blk,
|
||||||
|
// Разрешение ПЗУ картриджа (активный низкий)
|
||||||
|
output CR_ROM_oe_n,
|
||||||
|
// Старшая часть адреса ПЗУ картриджа (A13...A18)
|
||||||
|
output [5:0] CR_ROM_A,
|
||||||
|
output [3:0] CR_ROM_CS
|
||||||
|
);
|
||||||
|
// Счётчик банков ПЗУ картриджа по 8 кБ
|
||||||
|
reg [5:0] CR_ROM_bank_cnt = 6'b0;
|
||||||
|
// Регистр самоблокировки – отключает всю логику и ПЗУ картриджа
|
||||||
|
reg self_lock = 1'b0;
|
||||||
|
// Сигнал переключения страницы: чтение или запись в порт 0x7F
|
||||||
|
wire rom_page_up = iorq_n | A7;
|
||||||
|
// CPU работает с адресами 0000...1FFF (нижние 8 кб ПЗУ)
|
||||||
|
wire lower_rom = ({A13, A14, A15} == 3'b000) ? 1'b1 : 1'b0;
|
||||||
|
|
||||||
|
always @(negedge rom_page_up or negedge reset_n) begin
|
||||||
|
if(!reset_n) begin
|
||||||
|
CR_ROM_bank_cnt <= 6'b0;
|
||||||
|
self_lock <= 1'b0;
|
||||||
|
end else begin
|
||||||
|
// инкремент счётчика банков
|
||||||
|
CR_ROM_bank_cnt <= CR_ROM_bank_cnt + 1'b1;
|
||||||
|
// проверка достижения значения самоблокировки
|
||||||
|
if(CR_ROM_bank_cnt == SELF_LOCK_VAL) begin
|
||||||
|
self_lock <= 1'b1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
assign CR_ROM_oe_n = ~lower_rom | rd_n | mreq_n | self_lock ;
|
||||||
|
assign ZX_ROM_blk = ~CR_ROM_oe_n;
|
||||||
|
assign CR_ROM_CS[0] = CR_ROM_oe_n;
|
||||||
|
assign CR_ROM_CS[1] = 1'b1;
|
||||||
|
assign CR_ROM_CS[2] = 1'b1;
|
||||||
|
assign CR_ROM_CS[3] = 1'b1;
|
||||||
|
|
||||||
|
assign CR_ROM_A = CR_ROM_bank_cnt;
|
||||||
|
assign D = 8'bz;
|
||||||
|
|
||||||
|
endmodule
|
||||||
217
FW/src/zx_cartridge_tb.v
Normal file
217
FW/src/zx_cartridge_tb.v
Normal file
@ -0,0 +1,217 @@
|
|||||||
|
// Файл: zx_cartridge_tb.v
|
||||||
|
`timescale 1ns / 1ps
|
||||||
|
|
||||||
|
module zx_cartridge_tb();
|
||||||
|
// Управляющие сигналы
|
||||||
|
reg reset_n;
|
||||||
|
reg iorq_n;
|
||||||
|
reg rd_n;
|
||||||
|
reg mreq_n;
|
||||||
|
|
||||||
|
// Полная адресная шина (16 бит)
|
||||||
|
reg [15:0] address;
|
||||||
|
|
||||||
|
// Подключение отдельных бит к тестируемому модулю
|
||||||
|
wire A7 = address[7];
|
||||||
|
wire A13 = address[13];
|
||||||
|
wire A14 = address[14];
|
||||||
|
wire A15 = address[15];
|
||||||
|
|
||||||
|
// Выходы тестируемого модуля
|
||||||
|
wire ZX_ROM_blk;
|
||||||
|
wire CR_ROM_oe_n;
|
||||||
|
wire [5:0] CR_ROM_A;
|
||||||
|
|
||||||
|
// Тестируемый модуль с параметром SELF_LOCK_VAL = 15
|
||||||
|
zx_cartridge #(
|
||||||
|
.SELF_LOCK_VAL(15)
|
||||||
|
) uut (
|
||||||
|
.reset_n(reset_n),
|
||||||
|
.iorq_n(iorq_n),
|
||||||
|
.rd_n(rd_n),
|
||||||
|
.mreq_n(mreq_n),
|
||||||
|
.A7(A7),
|
||||||
|
.A13(A13),
|
||||||
|
.A14(A14),
|
||||||
|
.A15(A15),
|
||||||
|
.ZX_ROM_blk(ZX_ROM_blk),
|
||||||
|
.CR_ROM_oe_n(CR_ROM_oe_n),
|
||||||
|
.CR_ROM_A(CR_ROM_A)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Задачи для моделирования циклов Z80
|
||||||
|
// Запись в порт (активируется iorq_n, для инкремента важен его спад)
|
||||||
|
task write_port(input [15:0] addr);
|
||||||
|
begin
|
||||||
|
address = addr;
|
||||||
|
#10;
|
||||||
|
iorq_n = 0; // начало цикла IN/OUT
|
||||||
|
#10;
|
||||||
|
iorq_n = 1; // завершение цикла – отрицательный фронт
|
||||||
|
#10;
|
||||||
|
end
|
||||||
|
endtask
|
||||||
|
|
||||||
|
// Чтение из памяти с проверкой прямо во время цикла
|
||||||
|
task read_mem_check(input [15:0] addr, input exp_oe_n, input exp_blk);
|
||||||
|
begin
|
||||||
|
address = addr;
|
||||||
|
#10;
|
||||||
|
mreq_n = 0; // запрос памяти
|
||||||
|
rd_n = 0; // чтение
|
||||||
|
#10; // даём сигналам установиться
|
||||||
|
// проверяем прямо во время активного цикла
|
||||||
|
if (CR_ROM_oe_n !== exp_oe_n) begin
|
||||||
|
$display("ОШИБКА: read_mem_check по адресу %h: CR_ROM_oe_n ожидалось %b, получено %b", addr, exp_oe_n, CR_ROM_oe_n);
|
||||||
|
end
|
||||||
|
if (ZX_ROM_blk !== exp_blk) begin
|
||||||
|
$display("ОШИБКА: read_mem_check по адресу %h: ZX_ROM_blk ожидалось %b, получено %b", addr, exp_blk, ZX_ROM_blk);
|
||||||
|
end
|
||||||
|
#10;
|
||||||
|
mreq_n = 1;
|
||||||
|
rd_n = 1;
|
||||||
|
#10;
|
||||||
|
end
|
||||||
|
endtask
|
||||||
|
|
||||||
|
// Простое чтение без проверки (для создания циклов)
|
||||||
|
task read_mem(input [15:0] addr);
|
||||||
|
begin
|
||||||
|
address = addr;
|
||||||
|
#10;
|
||||||
|
mreq_n = 0;
|
||||||
|
rd_n = 0;
|
||||||
|
#20;
|
||||||
|
mreq_n = 1;
|
||||||
|
rd_n = 1;
|
||||||
|
#10;
|
||||||
|
end
|
||||||
|
endtask
|
||||||
|
|
||||||
|
// Проверка с выводом сообщения (для простых случаев)
|
||||||
|
task check_equal(input [31:0] expected, input [31:0] actual, input [80*8:0] msg);
|
||||||
|
if (expected !== actual) begin
|
||||||
|
$display("ОШИБКА: %s. Ожидалось %d, получено %d", msg, expected, actual);
|
||||||
|
end
|
||||||
|
endtask
|
||||||
|
|
||||||
|
integer i;
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
$dumpfile("zx_cartridge.vcd");
|
||||||
|
$dumpvars(0, zx_cartridge_tb);
|
||||||
|
|
||||||
|
// Исходное состояние: сброс активен, все сигналы неактивны
|
||||||
|
reset_n = 0;
|
||||||
|
iorq_n = 1;
|
||||||
|
rd_n = 1;
|
||||||
|
mreq_n = 1;
|
||||||
|
address = 16'h0000;
|
||||||
|
#100;
|
||||||
|
reset_n = 1;
|
||||||
|
#10;
|
||||||
|
|
||||||
|
// ------------------------------------------------------------
|
||||||
|
// Тест 1: Инкремент происходит только при A7=0 и спаде iorq_n
|
||||||
|
// ------------------------------------------------------------
|
||||||
|
$display("=== Тест 1: Условие инкремента (A7=0 и спад iorq_n) ===");
|
||||||
|
check_equal(0, CR_ROM_A, "Начальное значение CR_ROM_A");
|
||||||
|
|
||||||
|
// Попытка с A7=1 – не должен инкрементироваться
|
||||||
|
write_port(16'h0080); // A7=1 (адрес 0x80)
|
||||||
|
#10;
|
||||||
|
check_equal(0, CR_ROM_A, "После записи в порт 0x80 (A7=1)");
|
||||||
|
|
||||||
|
// Корректный инкремент с A7=0
|
||||||
|
write_port(16'h007F); // A7=0
|
||||||
|
#10;
|
||||||
|
check_equal(1, CR_ROM_A, "После первой записи в 0x7F");
|
||||||
|
|
||||||
|
write_port(16'h007F); // второй раз
|
||||||
|
#10;
|
||||||
|
check_equal(2, CR_ROM_A, "После второй записи в 0x7F");
|
||||||
|
|
||||||
|
// ------------------------------------------------------------
|
||||||
|
// Тест 2: Достижение SELF_LOCK_VAL (15) блокирует дальнейшие инкременты
|
||||||
|
// ------------------------------------------------------------
|
||||||
|
$display("=== Тест 2: Самоблокировка при значении 15 ===");
|
||||||
|
// Инкрементируем до 14 (с 3 до 14)
|
||||||
|
for (i = 3; i <= 14; i = i + 1) begin
|
||||||
|
write_port(16'h007F);
|
||||||
|
#10;
|
||||||
|
// Просто выводим текущее значение для информации
|
||||||
|
$display("После записи #%0d, CR_ROM_A = %0d", i, CR_ROM_A);
|
||||||
|
end
|
||||||
|
|
||||||
|
// Пятнадцатая запись – должна активировать блокировку
|
||||||
|
write_port(16'h007F);
|
||||||
|
#10;
|
||||||
|
$display("После пятнадцатой записи, CR_ROM_A = %0d (самоблокировка активирована)", CR_ROM_A);
|
||||||
|
|
||||||
|
// Ещё одна запись – после блокировки счётчик может измениться или нет,
|
||||||
|
// но картридж уже заблокирован, поэтому не проверяем
|
||||||
|
write_port(16'h007F);
|
||||||
|
#10;
|
||||||
|
$display("Запись после блокировки, CR_ROM_A = %0d (значение не важно)", CR_ROM_A);
|
||||||
|
|
||||||
|
// ------------------------------------------------------------
|
||||||
|
// Тест 3: При self_lock=1 CR_ROM_oe_n не активируется даже в нижней области ПЗУ
|
||||||
|
// ------------------------------------------------------------
|
||||||
|
$display("=== Тест 3: CR_ROM_oe_n неактивен во время блокировки ===");
|
||||||
|
read_mem_check(16'h0100, 1'b1, 1'b0); // ожидаем oe_n=1 (неактивен), blk=0
|
||||||
|
|
||||||
|
// ------------------------------------------------------------
|
||||||
|
// Тест 4: Сброс обнуляет счётчик и снимает блокировку
|
||||||
|
// ------------------------------------------------------------
|
||||||
|
$display("=== Тест 4: Сброс ===");
|
||||||
|
reset_n = 0;
|
||||||
|
#20;
|
||||||
|
reset_n = 1;
|
||||||
|
#10;
|
||||||
|
check_equal(0, CR_ROM_A, "После сброса");
|
||||||
|
check_equal(1, CR_ROM_oe_n, "CR_ROM_oe_n после сброса");
|
||||||
|
|
||||||
|
// ------------------------------------------------------------
|
||||||
|
// Тест 5: Активация CR_ROM_oe_n при чтении нижних 8 кБ (self_lock=0)
|
||||||
|
// ------------------------------------------------------------
|
||||||
|
$display("=== Тест 5: Активация CR_ROM_oe_n в нижней области ПЗУ (0x0000-0x1FFF) ===");
|
||||||
|
|
||||||
|
// Чтение внутри нижней области
|
||||||
|
read_mem_check(16'h0100, 1'b0, 1'b1); // ожидаем oe_n=0 (активен), blk=1
|
||||||
|
read_mem_check(16'h1FFF, 1'b0, 1'b1); // граница нижней области
|
||||||
|
|
||||||
|
// Чтение вне нижней области
|
||||||
|
read_mem_check(16'h2000, 1'b1, 1'b0); // A13=1
|
||||||
|
read_mem_check(16'h4001, 1'b1, 1'b0); // A14=1
|
||||||
|
|
||||||
|
// ------------------------------------------------------------
|
||||||
|
// Тест 6: Проверка влияния mreq_n и rd_n
|
||||||
|
// ------------------------------------------------------------
|
||||||
|
$display("=== Тест 6: Управляющие сигналы mreq_n и rd_n ===");
|
||||||
|
address = 16'h0100;
|
||||||
|
#10;
|
||||||
|
|
||||||
|
// mreq_n=0, rd_n=1 – чтение не активно
|
||||||
|
mreq_n = 0; rd_n = 1;
|
||||||
|
#10;
|
||||||
|
check_equal(1, CR_ROM_oe_n, "CR_ROM_oe_n при rd_n=1");
|
||||||
|
|
||||||
|
// mreq_n=1, rd_n=0 – нет запроса памяти
|
||||||
|
mreq_n = 1; rd_n = 0;
|
||||||
|
#10;
|
||||||
|
check_equal(1, CR_ROM_oe_n, "CR_ROM_oe_n при mreq_n=1");
|
||||||
|
|
||||||
|
// Оба активны – должно включиться
|
||||||
|
mreq_n = 0; rd_n = 0;
|
||||||
|
#10;
|
||||||
|
check_equal(0, CR_ROM_oe_n, "CR_ROM_oe_n при обоих активных");
|
||||||
|
|
||||||
|
// Возврат в исходное
|
||||||
|
mreq_n = 1; rd_n = 1;
|
||||||
|
#10;
|
||||||
|
|
||||||
|
$display("=== Все тесты завершены ===");
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
||||||
@ -1,62 +0,0 @@
|
|||||||
`timescale 1ns / 1ps
|
|
||||||
// ZX SPECTRUM cartrige module
|
|
||||||
// 17.02.2026 Mikhael Kaa
|
|
||||||
// CPU adr bus A0...A12 connect directly to CR_ROM chip
|
|
||||||
module zx_cartrige #(
|
|
||||||
// default example parameter
|
|
||||||
parameter SELF_LOCK_VAL = 15
|
|
||||||
)(
|
|
||||||
// Reset
|
|
||||||
input reset_n,
|
|
||||||
// CPU ctrl signals
|
|
||||||
input iorq_n,
|
|
||||||
input rd_n,
|
|
||||||
input mreq_n,
|
|
||||||
// Part of CPU adr bus
|
|
||||||
input A7,
|
|
||||||
input A13,
|
|
||||||
input A14,
|
|
||||||
input A15,
|
|
||||||
|
|
||||||
// ZX ROM block
|
|
||||||
output ZX_ROM_blk,
|
|
||||||
// Cartrige ROM enable
|
|
||||||
output CR_ROM_oe_n,
|
|
||||||
// Up part cartrige ROM adr bus (A13...A18)
|
|
||||||
output [5:0] CR_ROM_A,
|
|
||||||
output [3:0] CR_ROM_CS
|
|
||||||
|
|
||||||
);
|
|
||||||
// CR_ROM 8kb bank counter
|
|
||||||
reg [5:0] CR_ROM_bank_cnt = 6'b0;
|
|
||||||
// Self lock register, disable all logic and CR_ROM
|
|
||||||
reg self_lock = 1'b0;
|
|
||||||
// rd or wr port 0x7f increment CR_ROM bank
|
|
||||||
wire rom_page_up = iorq_n | A7 | self_lock;
|
|
||||||
// CPU work with 0000...1fff adr
|
|
||||||
wire lower_rom = ({A13, A14, A15} == 3'b000) ? 1'b1 : 1'b0;
|
|
||||||
|
|
||||||
always @(negedge rom_page_up or negedge reset_n) begin
|
|
||||||
if(!reset_n) begin
|
|
||||||
CR_ROM_bank_cnt <= 6'b0;
|
|
||||||
self_lock <= 1'b0;
|
|
||||||
end else begin
|
|
||||||
// increment bank counter
|
|
||||||
CR_ROM_bank_cnt <= CR_ROM_bank_cnt + 1'b1;
|
|
||||||
// check self lock
|
|
||||||
if(CR_ROM_bank_cnt == SELF_LOCK_VAL) begin
|
|
||||||
self_lock <= 1'b1;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
assign CR_ROM_oe_n = ~lower_rom | rd_n | mreq_n | self_lock ;
|
|
||||||
assign ZX_ROM_blk = ~CR_ROM_oe_n;
|
|
||||||
assign CR_ROM_CS[0] = CR_ROM_oe_n;
|
|
||||||
assign CR_ROM_CS[1] = 1'b1;
|
|
||||||
assign CR_ROM_CS[2] = 1'b1;
|
|
||||||
assign CR_ROM_CS[3] = 1'b1;
|
|
||||||
|
|
||||||
assign CR_ROM_A = CR_ROM_bank_cnt;
|
|
||||||
|
|
||||||
endmodule
|
|
||||||
@ -1,196 +0,0 @@
|
|||||||
`timescale 1ns / 1ps
|
|
||||||
|
|
||||||
module tb_zx_cartrige();
|
|
||||||
// Управляющие сигналы
|
|
||||||
reg reset_n;
|
|
||||||
reg iorq_n;
|
|
||||||
reg rd_n;
|
|
||||||
reg mreq_n;
|
|
||||||
|
|
||||||
// Полная адресная шина (16 бит)
|
|
||||||
reg [15:0] address;
|
|
||||||
|
|
||||||
// Подключение отдельных бит к DUT
|
|
||||||
wire A7 = address[7];
|
|
||||||
wire A13 = address[13];
|
|
||||||
wire A14 = address[14];
|
|
||||||
wire A15 = address[15];
|
|
||||||
|
|
||||||
// Выходы DUT
|
|
||||||
wire ZX_ROM_blk;
|
|
||||||
wire CR_ROM_oe_n;
|
|
||||||
wire [5:0] CR_ROM_A;
|
|
||||||
|
|
||||||
// Тестируемый модуль (с уменьшенным параметром для быстрой проверки)
|
|
||||||
zx_cartrige #(
|
|
||||||
.SELF_LOCK_VAL(3)
|
|
||||||
) uut (
|
|
||||||
.reset_n(reset_n),
|
|
||||||
.iorq_n(iorq_n),
|
|
||||||
.rd_n(rd_n),
|
|
||||||
.mreq_n(mreq_n),
|
|
||||||
.A7(A7),
|
|
||||||
.A13(A13),
|
|
||||||
.A14(A14),
|
|
||||||
.A15(A15),
|
|
||||||
.ZX_ROM_blk(ZX_ROM_blk),
|
|
||||||
.CR_ROM_oe_n(CR_ROM_oe_n),
|
|
||||||
.CR_ROM_A(CR_ROM_A)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Задачи для моделирования циклов Z80
|
|
||||||
// Запись в порт (активируется iorq_n, для инкремента важен его спад)
|
|
||||||
task write_port(input [15:0] addr);
|
|
||||||
begin
|
|
||||||
address = addr;
|
|
||||||
#10;
|
|
||||||
iorq_n = 0; // начало цикла IN/OUT
|
|
||||||
#10;
|
|
||||||
iorq_n = 1; // завершение цикла – отрицательный фронт
|
|
||||||
#10;
|
|
||||||
end
|
|
||||||
endtask
|
|
||||||
|
|
||||||
// Чтение из памяти
|
|
||||||
task read_mem(input [15:0] addr);
|
|
||||||
begin
|
|
||||||
address = addr;
|
|
||||||
#10;
|
|
||||||
mreq_n = 0; // запрос памяти
|
|
||||||
rd_n = 0; // чтение
|
|
||||||
#20; // удерживаем для проверки
|
|
||||||
mreq_n = 1;
|
|
||||||
rd_n = 1;
|
|
||||||
#10;
|
|
||||||
end
|
|
||||||
endtask
|
|
||||||
|
|
||||||
// Проверка с выводом сообщения
|
|
||||||
task check_equal(input [31:0] expected, input [31:0] actual, input [80*8:0] msg);
|
|
||||||
if (expected !== actual) begin
|
|
||||||
$display("ERROR: %s. Expected %d, got %d", msg, expected, actual);
|
|
||||||
end
|
|
||||||
endtask
|
|
||||||
|
|
||||||
initial begin
|
|
||||||
$dumpfile("zx_cartrige.vcd");
|
|
||||||
$dumpvars(0, tb_zx_cartrige);
|
|
||||||
|
|
||||||
// Исходное состояние: сброс активен, все сигналы неактивны
|
|
||||||
reset_n = 0;
|
|
||||||
iorq_n = 1;
|
|
||||||
rd_n = 1;
|
|
||||||
mreq_n = 1;
|
|
||||||
address = 16'h0000;
|
|
||||||
#100;
|
|
||||||
reset_n = 1;
|
|
||||||
#10;
|
|
||||||
|
|
||||||
// ------------------------------------------------------------
|
|
||||||
// Test 1: Инкремент происходит только при A7=0 и спаде iorq_n
|
|
||||||
// ------------------------------------------------------------
|
|
||||||
$display("=== Test 1: Increment condition (A7=0 and iorq_n falling) ===");
|
|
||||||
check_equal(0, CR_ROM_A, "Initial CR_ROM_A");
|
|
||||||
|
|
||||||
// Попытка с A7=1 – не должен инкрементироваться
|
|
||||||
write_port(16'h0080); // A7=1 (адрес 0x80)
|
|
||||||
#10;
|
|
||||||
check_equal(0, CR_ROM_A, "After write to port 0x80 (A7=1)");
|
|
||||||
|
|
||||||
// Корректный инкремент с A7=0
|
|
||||||
write_port(16'h007F); // A7=0
|
|
||||||
#10;
|
|
||||||
check_equal(1, CR_ROM_A, "After first write to 0x7F");
|
|
||||||
|
|
||||||
write_port(16'h007F); // второй раз
|
|
||||||
#10;
|
|
||||||
check_equal(2, CR_ROM_A, "After second write to 0x7F");
|
|
||||||
|
|
||||||
// ------------------------------------------------------------
|
|
||||||
// Test 2: Достижение SELF_LOCK_VAL (3) блокирует дальнейшие инкременты
|
|
||||||
// ------------------------------------------------------------
|
|
||||||
$display("=== Test 2: Self-lock at value 3 ===");
|
|
||||||
write_port(16'h007F); // третий раз -> lock
|
|
||||||
#10;
|
|
||||||
check_equal(3, CR_ROM_A, "After third write (should lock)");
|
|
||||||
|
|
||||||
// Попытка инкремента после блокировки
|
|
||||||
write_port(16'h007F);
|
|
||||||
#10;
|
|
||||||
check_equal(3, CR_ROM_A, "Write after lock - no increment");
|
|
||||||
|
|
||||||
// ------------------------------------------------------------
|
|
||||||
// Test 3: При self_lock=1 CR_ROM_oe_n не активируется даже в нижней ROM
|
|
||||||
// ------------------------------------------------------------
|
|
||||||
$display("=== Test 3: CR_ROM_oe_n inactive while locked ===");
|
|
||||||
read_mem(16'h0100); // адрес в нижней области (0x100)
|
|
||||||
#10;
|
|
||||||
check_equal(1, CR_ROM_oe_n, "CR_ROM_oe_n during locked read");
|
|
||||||
check_equal(0, ZX_ROM_blk, "ZX_ROM_blk during locked read");
|
|
||||||
|
|
||||||
// ------------------------------------------------------------
|
|
||||||
// Test 4: Сброс обнуляет счётчик и снимает блокировку
|
|
||||||
// ------------------------------------------------------------
|
|
||||||
$display("=== Test 4: Reset ===");
|
|
||||||
reset_n = 0;
|
|
||||||
#20;
|
|
||||||
reset_n = 1;
|
|
||||||
#10;
|
|
||||||
check_equal(0, CR_ROM_A, "After reset");
|
|
||||||
check_equal(1, CR_ROM_oe_n, "CR_ROM_oe_n after reset");
|
|
||||||
|
|
||||||
// ------------------------------------------------------------
|
|
||||||
// Test 5: Активация CR_ROM_oe_n при чтении нижних 8KB (self_lock=0)
|
|
||||||
// ------------------------------------------------------------
|
|
||||||
$display("=== Test 5: CR_ROM_oe_n activation in lower ROM (0x0000-0x1FFF) ===");
|
|
||||||
|
|
||||||
// Чтение внутри нижней области
|
|
||||||
read_mem(16'h0100);
|
|
||||||
#10;
|
|
||||||
check_equal(1, CR_ROM_oe_n, "CR_ROM_oe_n at 0x100");
|
|
||||||
check_equal(0, ZX_ROM_blk, "ZX_ROM_blk at 0x100");
|
|
||||||
|
|
||||||
read_mem(16'h1FFF); // граница нижней области
|
|
||||||
#10;
|
|
||||||
check_equal(1, CR_ROM_oe_n, "CR_ROM_oe_n at 0x1FFF");
|
|
||||||
|
|
||||||
// Чтение вне нижней области
|
|
||||||
read_mem(16'h2000); // A13=1
|
|
||||||
#10;
|
|
||||||
check_equal(1, CR_ROM_oe_n, "CR_ROM_oe_n at 0x2000 (outside)");
|
|
||||||
|
|
||||||
read_mem(16'h4001); // A14=1
|
|
||||||
#10;
|
|
||||||
check_equal(1, CR_ROM_oe_n, "CR_ROM_oe_n at 0x4001 (outside)");
|
|
||||||
|
|
||||||
// ------------------------------------------------------------
|
|
||||||
// Test 6: Проверка влияния mreq_n и rd_n
|
|
||||||
// ------------------------------------------------------------
|
|
||||||
$display("=== Test 6: Control signals mreq_n and rd_n ===");
|
|
||||||
address = 16'h0100;
|
|
||||||
#10;
|
|
||||||
|
|
||||||
// mreq_n=0, rd_n=1 – чтение не активно
|
|
||||||
mreq_n = 0; rd_n = 1;
|
|
||||||
#10;
|
|
||||||
check_equal(1, CR_ROM_oe_n, "CR_ROM_oe_n with rd_n=1");
|
|
||||||
|
|
||||||
// mreq_n=1, rd_n=0 – нет запроса памяти
|
|
||||||
mreq_n = 1; rd_n = 0;
|
|
||||||
#10;
|
|
||||||
check_equal(1, CR_ROM_oe_n, "CR_ROM_oe_n with mreq_n=1");
|
|
||||||
|
|
||||||
// Оба активны – должно включиться
|
|
||||||
mreq_n = 0; rd_n = 0;
|
|
||||||
#10;
|
|
||||||
check_equal(0, CR_ROM_oe_n, "CR_ROM_oe_n with both active");
|
|
||||||
|
|
||||||
// Возврат в исходное
|
|
||||||
mreq_n = 1; rd_n = 1;
|
|
||||||
#10;
|
|
||||||
|
|
||||||
$display("=== All tests completed ===");
|
|
||||||
$finish;
|
|
||||||
end
|
|
||||||
|
|
||||||
endmodule
|
|
||||||
@ -38,7 +38,7 @@
|
|||||||
|
|
||||||
set_global_assignment -name FAMILY MAX7000S
|
set_global_assignment -name FAMILY MAX7000S
|
||||||
set_global_assignment -name DEVICE "EPM7064SLC44-10"
|
set_global_assignment -name DEVICE "EPM7064SLC44-10"
|
||||||
set_global_assignment -name TOP_LEVEL_ENTITY zx_cartrige
|
set_global_assignment -name TOP_LEVEL_ENTITY zx_cartridge
|
||||||
set_global_assignment -name ORIGINAL_QUARTUS_VERSION "13.0 SP1"
|
set_global_assignment -name ORIGINAL_QUARTUS_VERSION "13.0 SP1"
|
||||||
set_global_assignment -name PROJECT_CREATION_TIME_DATE "14:32:59 FEBRUARY 06, 2026"
|
set_global_assignment -name PROJECT_CREATION_TIME_DATE "14:32:59 FEBRUARY 06, 2026"
|
||||||
set_global_assignment -name LAST_QUARTUS_VERSION "13.0 SP1"
|
set_global_assignment -name LAST_QUARTUS_VERSION "13.0 SP1"
|
||||||
@ -50,25 +50,34 @@ set_global_assignment -name ERROR_CHECK_FREQUENCY_DIVISOR "-1"
|
|||||||
set_global_assignment -name MIN_CORE_JUNCTION_TEMP 0
|
set_global_assignment -name MIN_CORE_JUNCTION_TEMP 0
|
||||||
set_global_assignment -name MAX_CORE_JUNCTION_TEMP 85
|
set_global_assignment -name MAX_CORE_JUNCTION_TEMP 85
|
||||||
set_global_assignment -name MAX7000_DEVICE_IO_STANDARD TTL
|
set_global_assignment -name MAX7000_DEVICE_IO_STANDARD TTL
|
||||||
set_location_assignment PIN_1 -to reset_n
|
set_global_assignment -name VERILOG_FILE src/zx_cartridge.v
|
||||||
set_global_assignment -name VERILOG_FILE src/zx_cartrige.v
|
|
||||||
set_global_assignment -name CDF_FILE output_files/Chain1.cdf
|
set_global_assignment -name CDF_FILE output_files/Chain1.cdf
|
||||||
set_location_assignment PIN_18 -to A7
|
set_location_assignment PIN_1 -to reset_n
|
||||||
set_location_assignment PIN_19 -to A13
|
set_location_assignment PIN_2 -to rd_n
|
||||||
set_location_assignment PIN_20 -to A14
|
set_location_assignment PIN_4 -to wr_n
|
||||||
set_location_assignment PIN_21 -to A15
|
set_location_assignment PIN_6 -to A14
|
||||||
set_location_assignment PIN_31 -to CR_ROM_A[5]
|
set_location_assignment PIN_8 -to A15
|
||||||
set_location_assignment PIN_29 -to CR_ROM_A[4]
|
set_location_assignment PIN_9 -to A13
|
||||||
set_location_assignment PIN_28 -to CR_ROM_A[3]
|
set_location_assignment PIN_11 -to CR_ROM_CS[0]
|
||||||
set_location_assignment PIN_9 -to CR_ROM_A[2]
|
set_location_assignment PIN_12 -to CR_ROM_CS[1]
|
||||||
set_location_assignment PIN_11 -to CR_ROM_A[1]
|
set_location_assignment PIN_14 -to CR_ROM_CS[2]
|
||||||
set_location_assignment PIN_12 -to CR_ROM_A[0]
|
set_location_assignment PIN_16 -to CR_ROM_A[5]
|
||||||
set_location_assignment PIN_34 -to CR_ROM_oe_n
|
set_location_assignment PIN_18 -to CR_ROM_A[4]
|
||||||
set_location_assignment PIN_27 -to ZX_ROM_blk
|
set_location_assignment PIN_19 -to CR_ROM_A[3]
|
||||||
set_location_assignment PIN_24 -to iorq_n
|
set_location_assignment PIN_20 -to CR_ROM_A[1]
|
||||||
set_location_assignment PIN_25 -to mreq_n
|
set_location_assignment PIN_21 -to CR_ROM_A[2]
|
||||||
set_location_assignment PIN_26 -to rd_n
|
set_location_assignment PIN_24 -to A7
|
||||||
set_location_assignment PIN_8 -to CR_ROM_CS[3]
|
set_location_assignment PIN_25 -to CR_ROM_A[0]
|
||||||
set_location_assignment PIN_6 -to CR_ROM_CS[2]
|
set_location_assignment PIN_26 -to CR_ROM_oe_n
|
||||||
set_location_assignment PIN_5 -to CR_ROM_CS[1]
|
set_location_assignment PIN_27 -to CR_ROM_CS[3]
|
||||||
set_location_assignment PIN_4 -to CR_ROM_CS[0]
|
set_location_assignment PIN_28 -to D[0]
|
||||||
|
set_location_assignment PIN_29 -to D[1]
|
||||||
|
set_location_assignment PIN_31 -to D[7]
|
||||||
|
set_location_assignment PIN_33 -to ZX_ROM_blk
|
||||||
|
set_location_assignment PIN_34 -to D[2]
|
||||||
|
set_location_assignment PIN_37 -to D[6]
|
||||||
|
set_location_assignment PIN_39 -to D[4]
|
||||||
|
set_location_assignment PIN_40 -to D[3]
|
||||||
|
set_location_assignment PIN_41 -to D[5]
|
||||||
|
set_location_assignment PIN_43 -to mreq_n
|
||||||
|
set_location_assignment PIN_44 -to iorq_n
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
Subproject commit c41200a6ad7d258b53d009f64863589a1fd4ec8b
|
Subproject commit d32899a31a641d1caf2bda05e2c799e5582739e4
|
||||||
Loading…
Reference in New Issue
Block a user