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

263 lines
9.9 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
module tb_zx_cartridge();
// Управляющие сигналы
reg reset_n;
reg iorq_n;
reg rd_n;
reg wr_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];
// Шина данных (8 бит) двунаправленная
wire [7:0] D;
reg [7:0] D_drive; // данные для записи от тестбенча
wire [7:0] D_sample; // данные, читаемые из DUT
assign D = (wr_n == 0) ? D_drive : 8'bz;
assign D_sample = D;
// Выходы DUT
wire ZX_ROM_blk;
wire CR_ROM_oe_n;
wire [5:0] CR_ROM_A;
wire [3:0] CR_ROM_CS; // теперь 4 бита
// Вспомогательная переменная для чтения портов
reg [7:0] dummy;
// Тестируемый модуль (новая версия)
zx_cartridge uut (
.reset_n(reset_n),
.iorq_n(iorq_n),
.rd_n(rd_n),
.wr_n(wr_n),
.mreq_n(mreq_n),
.A7(A7),
.A13(A13),
.A14(A14),
.A15(A15),
.D(D),
.ZX_ROM_blk(ZX_ROM_blk),
.CR_ROM_oe_n(CR_ROM_oe_n),
.CR_ROM_A(CR_ROM_A),
.CR_ROM_CS(CR_ROM_CS)
);
// Задачи для моделирования циклов Z80
// Запись в порт ввода-вывода
task write_port(input [15:0] addr, input [7:0] data);
begin
address = addr;
D_drive = data;
#10;
iorq_n = 0;
wr_n = 0;
#20;
iorq_n = 1;
wr_n = 1;
#10;
D_drive = 8'bz;
end
endtask
// Чтение из порта ввода-вывода (возвращает прочитанные данные)
task read_port(input [15:0] addr, output [7:0] data);
begin
address = addr;
#10;
iorq_n = 0;
rd_n = 0;
#20;
data = D_sample;
iorq_n = 1;
rd_n = 1;
#10;
end
endtask
// Чтение из памяти с проверкой CR_ROM_A и CR_ROM_CS (новые сигналы)
task read_mem_check(input [15:0] addr, input [5:0] exp_A, input [3:0] exp_CS);
begin
address = addr;
#10;
mreq_n = 0;
rd_n = 0;
#10; // ждём стабилизации
check_equal(exp_A, CR_ROM_A, "CR_ROM_A during read");
check_equal(exp_CS, CR_ROM_CS, "CR_ROM_CS during read");
#10;
mreq_n = 1;
rd_n = 1;
#10;
end
endtask
// Чтение из памяти с проверкой CR_ROM_oe_n и ZX_ROM_blk
task read_mem_check_oe(input [15:0] addr, input exp_oe, input exp_blk);
begin
address = addr;
#10;
mreq_n = 0;
rd_n = 0;
#10;
check_equal(exp_oe, CR_ROM_oe_n, "CR_ROM_oe_n during read");
check_equal(exp_blk, ZX_ROM_blk, "ZX_ROM_blk during read");
#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
// Проверка равенства (поддерживает 4битные и 6битные аргументы)
task check_equal(input [31:0] expected, input [31:0] actual, input [80*8:0] msg);
if (expected !== actual) begin
$display("ERROR: %s. Expected %h, got %h", msg, expected, actual);
end else begin
$display("OK: %s", msg);
end
endtask
initial begin
$dumpfile("zx_cartridge.vcd");
$dumpvars(0, tb_zx_cartridge);
// Исходное состояние: сброс активен, все сигналы неактивны
reset_n = 0;
iorq_n = 1;
rd_n = 1;
wr_n = 1;
mreq_n = 1;
address = 16'h0000;
D_drive = 8'bz;
#100;
reset_n = 1;
#10;
// ------------------------------------------------------------
// Test 1: Запись и чтение регистров через порты
// ------------------------------------------------------------
$display("=== Test 1: Write and read registers via I/O ports ===");
// Запись в bank: адрес 0xC000 (A15=1, A14=1, A13=0, A7=0)
write_port(16'hC000, 8'hA5); // запись reg_bank = 0xA5
read_port(16'hC000, dummy);
check_equal(8'hA5, dummy, "Read bank returns written value");
// Запись в control: адрес 0xA000 (A15=1, A14=0, A13=1, A7=0)
write_port(16'hA000, 8'h80); // запись reg_ctl с битом 7 = 1 (отключение)
read_port(16'hA000, dummy);
check_equal(8'h80, dummy, "Read control returns written value");
// Сбрасываем бит disable (reg_ctl[7]=0) для дальнейших тестов
write_port(16'hA000, 8'h00);
read_port(16'hA000, dummy);
check_equal(8'h00, dummy, "Control = 0 after disable cleared");
// ------------------------------------------------------------
// Test 2: Формирование страницы и выбор микросхемы
// ------------------------------------------------------------
$display("=== Test 2: Page and chip select formation ===");
// Записываем bank = 0xA5 -> chip_sel = 2'b10 = 2, page_offs = 6'b100101 = 37
write_port(16'hC000, 8'hA5);
// Верхнее окно (A13=1): адрес 0x2000
// Ожидаем CR_ROM_A = 37, активный CS2 (бит 2 = 0) -> 4'b1011 (младший бит = CS0)
read_mem_check(16'h2000, 6'd37, 4'b1011); // CS2 активен (0), остальные 1
// Нижнее окно (A13=0): адрес 0x1000
// Ожидаем CR_ROM_A = 0, активный CS0 -> 4'b1110
read_mem_check(16'h1000, 6'd0, 4'b1110);
// ------------------------------------------------------------
// Test 3: Проверка всех вариантов chip_sel
// ------------------------------------------------------------
$display("=== Test 3: Chip select generation for all chip_sel values ===");
// chip_sel = 0
write_port(16'hC000, 8'h00); // 0b00000000
read_mem_check(16'h2000, 6'd0, 4'b1110); // CS0 активен (0) -> 1110
read_mem_check(16'h1000, 6'd0, 4'b1110); // нижнее окно тоже CS0
// chip_sel = 1
write_port(16'hC000, 8'h40); // 0b01000000 -> chip_sel=1, offs=0
read_mem_check(16'h2000, 6'd0, 4'b1101); // CS1 активен -> 1101
read_mem_check(16'h1000, 6'd0, 4'b1110); // нижнее окно CS0
// chip_sel = 2
write_port(16'hC000, 8'h80); // 0b10000000 -> chip_sel=2, offs=0
read_mem_check(16'h2000, 6'd0, 4'b1011); // CS2 активен -> 1011
read_mem_check(16'h1000, 6'd0, 4'b1110);
// chip_sel = 3
write_port(16'hC000, 8'hC0); // 0b11000000 -> chip_sel=3, offs=0
read_mem_check(16'h2000, 6'd0, 4'b0111); // CS3 активен -> 0111
read_mem_check(16'h1000, 6'd0, 4'b1110);
// ------------------------------------------------------------
// Test 4: Сигнал rom_access и CR_ROM_oe_n / ZX_ROM_blk
// ------------------------------------------------------------
$display("=== Test 4: rom_access control ===");
// Включим картридж (reg_ctl[7]=0) уже 0
// Чтение из области ROM (адрес 0x1000)
read_mem_check_oe(16'h1000, 1'b0, 1'b1); // CR_ROM_oe_n = 0, ZX_ROM_blk = 1
// Чтение из области не ROM (адрес 0x4000, A15=0, A14=1)
read_mem_check_oe(16'h4000, 1'b1, 1'b0); // оба неактивны
// Отключим картридж (установим бит 7)
write_port(16'hA000, 8'h80);
read_mem_check_oe(16'h1000, 1'b1, 1'b0); // неактивны, т.к. картридж отключён
// Снова включим
write_port(16'hA000, 8'h00);
// ------------------------------------------------------------
// Test 5: Сброс
// ------------------------------------------------------------
$display("=== Test 5: Reset ===");
reset_n = 0;
#20;
reset_n = 1;
#10;
// Проверим, что регистры сброшены в 0
read_port(16'hC000, dummy);
check_equal(8'h00, dummy, "bank reads 0 after reset");
read_port(16'hA000, dummy);
check_equal(8'h00, dummy, "control reads 0 after reset");
// Проверим поведение после сброса: нижнее окно CS0, страница 0
read_mem_check(16'h1000, 6'd0, 4'b1110); // нижнее окно: CS0 активен
read_mem_check(16'h2000, 6'd0, 4'b1110); // верхнее окно тоже должно быть CS0 (т.к. bank=0)
$display("=== All tests completed ===");
$finish;
end
endmodule