mirror of
https://github.com/MiSTer-devel/PCFX_MiSTer.git
synced 2026-05-24 03:04:18 +00:00
Refine FX-BMP implementation
- Add battery status readout - Narrow address range to E800_0000 .. EBFF_FFFF - Enable BMP only if it's mounted - Configure BMP size according to mounted image size
This commit is contained in:
@@ -14,6 +14,7 @@ set_global_assignment -name SYSTEMVERILOG_FILE rtl/v810/v810.sv
|
||||
set_global_assignment -name SYSTEMVERILOG_FILE rtl/mach.sv
|
||||
set_global_assignment -name SYSTEMVERILOG_FILE rtl/ram.sv
|
||||
set_global_assignment -name SYSTEMVERILOG_FILE rtl/sdram.v
|
||||
set_global_assignment -name SYSTEMVERILOG_FILE rtl/fx_bmp.sv
|
||||
set_global_assignment -name SYSTEMVERILOG_FILE rtl/dpram.sv
|
||||
# set_global_assignment -name VHDL_FILE rtl/dpram.vhd
|
||||
set_global_assignment -name SYSTEMVERILOG_FILE rtl/memif_sdram.sv
|
||||
|
||||
67
rtl/fx_bmp.sv
Normal file
67
rtl/fx_bmp.sv
Normal file
@@ -0,0 +1,67 @@
|
||||
// A FX-BMP with battery-backed SRAM, connected to the Memory Card Port
|
||||
//
|
||||
// Copyright (c) 2026 David Hunter
|
||||
//
|
||||
// This program is GPL licensed. See COPYING for the full license.
|
||||
|
||||
module fx_bmp
|
||||
(
|
||||
// Emulation configuration
|
||||
input CFG_EN,
|
||||
input [2:0] CFG_SIZE, // 0=128KB, 1=256KB, 2=512KB, .. 6=8MB
|
||||
|
||||
// Memory Card port interface
|
||||
input [26:1] MCP_A, // A24 is omitted
|
||||
input [7:0] MCP_DI,
|
||||
output [7:0] MCP_DO,
|
||||
input MCP_CSn, // aka /CartSel
|
||||
input MCP_RDn,
|
||||
input MCP_WRn,
|
||||
output MCP_READYn,
|
||||
|
||||
// Memory interface
|
||||
output [22:0] RAM_A,
|
||||
output [7:0] RAM_DI,
|
||||
input [7:0] RAM_DO,
|
||||
output RAM_CEn,
|
||||
output RAM_WEn,
|
||||
input RAM_READYn
|
||||
);
|
||||
|
||||
// Control size by masking (zeroing) RAM address bits above 128KB.
|
||||
wire [22:0] ram_a_mask;
|
||||
|
||||
always @* begin
|
||||
ram_a_mask[16:0] = '1;
|
||||
case (CFG_SIZE)
|
||||
3'd0: ram_a_mask[22:17] = 'b000_000; // 128KB
|
||||
3'd1: ram_a_mask[22:17] = 'b000_001; // 256KB
|
||||
3'd2: ram_a_mask[22:17] = 'b000_011; // 512KB
|
||||
3'd3: ram_a_mask[22:17] = 'b000_111; // 1MB
|
||||
3'd4: ram_a_mask[22:17] = 'b001_111; // 2MB
|
||||
3'd5: ram_a_mask[22:17] = 'b011_111; // 4MB
|
||||
default:ram_a_mask[22:17] = 'b111_111; // 8MB
|
||||
endcase
|
||||
end
|
||||
|
||||
// BMP address range is E800_0000 .. EBFF_FFFF -- half the port's addressable range.
|
||||
wire bmp_sel = ~(~CFG_EN | MCP_CSn | MCP_A[26]);
|
||||
|
||||
// BMP memory is split down the middle:
|
||||
// E800_0000 + (0000_0000 .. 01FF_FFFE) is SRAM
|
||||
// E800_0000 + (0200_0000 .. 03FF_FFFE) is battery status
|
||||
wire sram_sel = bmp_sel & ~MCP_A[25];
|
||||
wire bat_sel = bmp_sel & MCP_A[25];
|
||||
|
||||
// The battery is always "good".
|
||||
wire bat_good = '1;
|
||||
|
||||
assign RAM_A = MCP_A[23:1] & ram_a_mask;
|
||||
assign RAM_DI = MCP_DI;
|
||||
assign RAM_CEn = ~sram_sel;
|
||||
assign RAM_WEn = RAM_CEn | MCP_WRn;
|
||||
|
||||
assign MCP_DO = {8{~bmp_sel}} | (bat_sel ? {7'h7F, bat_good} : RAM_DO);
|
||||
assign MCP_READYn = MCP_CSn | (sram_sel & RAM_READYn);
|
||||
|
||||
endmodule
|
||||
12
rtl/fx_ga.sv
12
rtl/fx_ga.sv
@@ -30,7 +30,7 @@ module fx_ga
|
||||
output ROM_CEn,
|
||||
output RAM_CEn,
|
||||
output SRAM_CEn,
|
||||
output BMP_CEn,
|
||||
output MCP_CSn,
|
||||
output IO_CEn,
|
||||
|
||||
output FX_GA_CSn,
|
||||
@@ -45,7 +45,7 @@ module fx_ga
|
||||
input ROM_READYn,
|
||||
input RAM_READYn,
|
||||
input SRAM_READYn,
|
||||
input BMP_READYn,
|
||||
input MCP_READYn,
|
||||
|
||||
// Device control
|
||||
output WRn,
|
||||
@@ -77,8 +77,8 @@ module fx_ga
|
||||
logic unk_cen;
|
||||
logic io_readyn;
|
||||
|
||||
assign READYn = unk_cen & ROM_READYn & RAM_READYn & SRAM_READYn & BMP_READYn & io_readyn;
|
||||
assign SZRQn = ~unk_cen | (ROM_CEn & IO_CEn & SRAM_CEn & BMP_CEn);
|
||||
assign READYn = unk_cen & ROM_READYn & RAM_READYn & SRAM_READYn & MCP_READYn & io_readyn;
|
||||
assign SZRQn = ~unk_cen | (ROM_CEn & IO_CEn & SRAM_CEn & MCP_CSn);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Address decoder
|
||||
@@ -90,10 +90,10 @@ assign A1_16 = A[1] | (~&BEn[3:2] & &BEn[1:0]);
|
||||
assign ROM_CEn = ~(~MRQn & (A[31:28] == 4'hF)); // F000_0000 .. FFFF_FFFF
|
||||
assign RAM_CEn = ~(~MRQn & (A[31:24] == 8'h00)); // 0000_0000 .. 00FF_FFFF
|
||||
assign SRAM_CEn = ~(~MRQn & (A[31:27] == 5'b1110_0)); // E000_0000 .. E7FF_FFFF
|
||||
assign BMP_CEn = ~(~MRQn & (A[31:27] == 5'b1110_1)); // E800_0000 .. EFFF_FFFF
|
||||
assign MCP_CSn = ~(~MRQn & (A[31:27] == 5'b1110_1)); // E800_0000 .. EFFF_FFFF
|
||||
assign IO_CEn = ~((MRQn | (A[31:28] == 4'h8)) & (~BCYSTn | ~DAn)
|
||||
& (ST == 2'b10));
|
||||
assign unk_cen = ~(RAM_CEn & ROM_CEn & SRAM_CEn & BMP_CEn & IO_CEn);
|
||||
assign unk_cen = ~(RAM_CEn & ROM_CEn & SRAM_CEn & MCP_CSn & IO_CEn);
|
||||
|
||||
assign FX_GA_CSn = ~(~IO_CEn & (A[30:12] == 19'h00000)) |
|
||||
~(PSG_CSn & VPU_CSn & VCE_CSn & VDC0_CSn &
|
||||
|
||||
40
rtl/mach.sv
40
rtl/mach.sv
@@ -36,12 +36,13 @@ module mach
|
||||
output SRAM_WEn,
|
||||
input SRAM_READYn,
|
||||
|
||||
output [22:0] BMP_A,
|
||||
output [7:0] BMP_DI,
|
||||
input [7:0] BMP_DO,
|
||||
output BMP_CEn,
|
||||
output BMP_WEn,
|
||||
input BMP_READYn,
|
||||
output [26:1] MCP_A,
|
||||
output [7:0] MCP_DI,
|
||||
input [7:0] MCP_DO,
|
||||
output MCP_CSn,
|
||||
output MCP_RDn,
|
||||
output MCP_WRn,
|
||||
input MCP_READYn,
|
||||
|
||||
input hmi_t HMI,
|
||||
|
||||
@@ -85,9 +86,9 @@ logic sram_cen;
|
||||
wire [7:0] sram_do;
|
||||
logic sram_readyn;
|
||||
|
||||
logic bmp_cen;
|
||||
wire [7:0] bmp_do;
|
||||
logic bmp_readyn;
|
||||
logic mcp_csn;
|
||||
wire [7:0] mcp_do;
|
||||
logic mcp_readyn;
|
||||
|
||||
logic a1_16;
|
||||
logic [31:0] mem16_a;
|
||||
@@ -206,7 +207,7 @@ fx_ga ga
|
||||
.ROM_CEn(rom_cen),
|
||||
.RAM_CEn(ram_cen),
|
||||
.SRAM_CEn(sram_cen),
|
||||
.BMP_CEn(bmp_cen),
|
||||
.MCP_CSn(mcp_csn),
|
||||
.IO_CEn(io_cen),
|
||||
|
||||
.FX_GA_CSn(ga_csn),
|
||||
@@ -220,7 +221,7 @@ fx_ga ga
|
||||
.ROM_READYn(rom_readyn),
|
||||
.RAM_READYn(ram_readyn),
|
||||
.SRAM_READYn(sram_readyn),
|
||||
.BMP_READYn(bmp_readyn),
|
||||
.MCP_READYn(mcp_readyn),
|
||||
|
||||
.WRn(ga_wrn),
|
||||
.RDn(ga_rdn),
|
||||
@@ -451,8 +452,8 @@ always @* begin
|
||||
cpu_d_i = ram_do;
|
||||
else if (~sram_cen)
|
||||
cpu_d_i = {24'b0, sram_do};
|
||||
else if (~bmp_cen)
|
||||
cpu_d_i = {24'b0, bmp_do};
|
||||
else if (~mcp_csn)
|
||||
cpu_d_i = {24'b0, mcp_do};
|
||||
else if (~io_cen)
|
||||
cpu_d_i = {16'b0, io_do};
|
||||
else
|
||||
@@ -483,8 +484,8 @@ assign ram_readyn = ram_cen | RAM_READYn;
|
||||
assign sram_do = SRAM_DO;
|
||||
assign sram_readyn = sram_cen | SRAM_READYn;
|
||||
|
||||
assign bmp_do = BMP_DO;
|
||||
assign bmp_readyn = bmp_cen | BMP_READYn;
|
||||
assign mcp_do = MCP_DO;
|
||||
assign mcp_readyn = mcp_csn | MCP_READYn;
|
||||
|
||||
assign mem16_a = {cpu_a[31:2], a1_16, 1'b0};
|
||||
|
||||
@@ -507,10 +508,11 @@ assign SRAM_A = mem16_a[15:1];
|
||||
assign SRAM_DI = cpu_d_o[7:0];
|
||||
assign SRAM_WEn = sram_cen | cpu_rw;
|
||||
|
||||
assign BMP_CEn = bmp_cen;
|
||||
assign BMP_A = mem16_a[23:1];
|
||||
assign BMP_DI = cpu_d_o[7:0];
|
||||
assign BMP_WEn = bmp_cen | cpu_rw;
|
||||
assign MCP_CSn = mcp_csn;
|
||||
assign MCP_A = mem16_a[26:1];
|
||||
assign MCP_DI = cpu_d_o[7:0];
|
||||
assign MCP_RDn = mcp_csn | ~cpu_rw;
|
||||
assign MCP_WRn = mcp_csn | cpu_rw;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// SCSI interface
|
||||
|
||||
@@ -159,6 +159,15 @@ wire sram_cen;
|
||||
wire sram_wen;
|
||||
wire sram_readyn;
|
||||
|
||||
wire [26:1] mcp_a;
|
||||
wire [7:0] mcp_di, mcp_do;
|
||||
wire mcp_csn;
|
||||
wire mcp_rdn;
|
||||
wire mcp_wrn;
|
||||
wire mcp_readyn;
|
||||
|
||||
wire bmp_cfg_en;
|
||||
logic [2:0] bmp_cfg_size;
|
||||
wire [22:0] bmp_a;
|
||||
wire [7:0] bmp_di, bmp_do;
|
||||
wire bmp_cen;
|
||||
@@ -207,12 +216,13 @@ mach mach
|
||||
.SRAM_WEn(sram_wen),
|
||||
.SRAM_READYn(sram_readyn),
|
||||
|
||||
.BMP_A(bmp_a),
|
||||
.BMP_DI(bmp_di),
|
||||
.BMP_DO(bmp_do),
|
||||
.BMP_CEn(bmp_cen),
|
||||
.BMP_WEn(bmp_wen),
|
||||
.BMP_READYn(bmp_readyn),
|
||||
.MCP_A(mcp_a),
|
||||
.MCP_DI(mcp_di),
|
||||
.MCP_DO(mcp_do),
|
||||
.MCP_CSn(mcp_csn),
|
||||
.MCP_RDn(mcp_rdn),
|
||||
.MCP_WRn(mcp_wrn),
|
||||
.MCP_READYn(mcp_readyn),
|
||||
|
||||
.HMI(HMI),
|
||||
|
||||
@@ -276,6 +286,27 @@ memif_sdram memif_sdram
|
||||
.SDRAM_DOUT(sdram_dout)
|
||||
);
|
||||
|
||||
fx_bmp bmp
|
||||
(
|
||||
.CFG_EN(bmp_cfg_en),
|
||||
.CFG_SIZE(bmp_cfg_size),
|
||||
|
||||
.MCP_A(mcp_a),
|
||||
.MCP_DI(mcp_di),
|
||||
.MCP_DO(mcp_do),
|
||||
.MCP_CSn(mcp_csn),
|
||||
.MCP_RDn(mcp_rdn),
|
||||
.MCP_WRn(mcp_wrn),
|
||||
.MCP_READYn(mcp_readyn),
|
||||
|
||||
.RAM_A(bmp_a),
|
||||
.RAM_DI(bmp_di),
|
||||
.RAM_DO(bmp_do),
|
||||
.RAM_CEn(bmp_cen),
|
||||
.RAM_WEn(bmp_wen),
|
||||
.RAM_READYn(bmp_readyn)
|
||||
);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// ROM loader
|
||||
|
||||
@@ -318,6 +349,26 @@ always @(posedge clk_sys) begin
|
||||
end
|
||||
end
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// FX-BMP -> Memory Cord Port
|
||||
|
||||
wire [31:0] bmp_sd_blk_cnt = bk_sd_blk_cnt[1];
|
||||
|
||||
assign bmp_cfg_en = bk_mounted[1];
|
||||
|
||||
// Configure the BMP size to match the mounted image size.
|
||||
always @* begin
|
||||
casez ({|bmp_sd_blk_cnt[31:14], bmp_sd_blk_cnt[13:8]})
|
||||
7'b1??_????: bmp_cfg_size = 3'd6; // 8MB
|
||||
7'b01?_????: bmp_cfg_size = 3'd5; // 4MB
|
||||
7'b001_????: bmp_cfg_size = 3'd4; // 2MB
|
||||
7'b000_1???: bmp_cfg_size = 3'd3; // 1MB
|
||||
7'b000_01??: bmp_cfg_size = 3'd2; // 512KB
|
||||
7'b000_001?: bmp_cfg_size = 3'd1; // 256KB
|
||||
default: bmp_cfg_size = 3'd0; // 128KB
|
||||
endcase
|
||||
end
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Backup RAM transfer
|
||||
|
||||
@@ -347,7 +398,7 @@ logic sd_vd; // volume select
|
||||
logic sd_ack_d;
|
||||
|
||||
always @(posedge clk_sys) begin
|
||||
if (img_mounted) begin
|
||||
if (img_mounted != 0) begin
|
||||
bk_mounted[img_mounted[1]] <= |img_size;
|
||||
bk_sd_blk_cnt[img_mounted[1]] <= img_size[9+:32];
|
||||
end
|
||||
|
||||
@@ -8,6 +8,7 @@ dpram.sv
|
||||
../pcfx_top.sv
|
||||
../memif_sdram.sv
|
||||
../sdram.v
|
||||
../fx_bmp.sv
|
||||
|
||||
../mach.sv
|
||||
../huc6261.sv
|
||||
|
||||
@@ -346,7 +346,7 @@ integer code;
|
||||
sd_size[vd] = $ftell(fin);
|
||||
sd_vd = vd;
|
||||
-> mount_sd;
|
||||
repeat (2) @(posedge clk_sys) ; // wait for mount completion
|
||||
repeat (3) @(posedge clk_sys) ; // wait for mount completion
|
||||
end
|
||||
endtask
|
||||
|
||||
@@ -397,7 +397,7 @@ always @(negedge vs) begin
|
||||
$display("%t: Frame %03d A=%x", $time, frame, pcfx_top.mach.cpu_a);
|
||||
$sformat(fname, "frames/render-%03d", frame);
|
||||
pice = 0;
|
||||
if (frame >= 237) begin
|
||||
if (frame >= 220) begin
|
||||
fpic = $fopen({fname, ".hex"}, "w");
|
||||
end
|
||||
frame = frame + 1;
|
||||
@@ -424,6 +424,8 @@ end
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
event running;
|
||||
|
||||
initial #0 begin
|
||||
#10 ; // wait for sdram init.
|
||||
|
||||
@@ -443,9 +445,12 @@ initial #0 begin
|
||||
$display("RAMs loaded.");
|
||||
end
|
||||
`endif
|
||||
|
||||
-> running;
|
||||
end
|
||||
|
||||
initial begin
|
||||
@(running) ;
|
||||
repeat (4) #(1000e3) ;
|
||||
//#(500e3) ;
|
||||
|
||||
@@ -465,6 +470,7 @@ initial begin
|
||||
end
|
||||
|
||||
initial if (1) begin
|
||||
@(running) ;
|
||||
#(216e3);
|
||||
|
||||
repeat (4) begin
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
[*]
|
||||
[*] GTKWave Analyzer v3.4.0 (w)1999-2022 BSI
|
||||
[*] Mon Jan 19 23:30:13 2026
|
||||
[*] Sun Jan 25 01:51:43 2026
|
||||
[*]
|
||||
[dumpfile] "/Users/dhunter/src/mister/PCFX_MiSTer/rtl/tb/pcfx_top_tb.verilator.fst"
|
||||
[dumpfile_mtime] "Mon Jan 19 23:29:06 2026"
|
||||
[dumpfile_size] 9107446
|
||||
[dumpfile_mtime] "Sun Jan 25 01:48:02 2026"
|
||||
[dumpfile_size] 18901994
|
||||
[savefile] "/Users/dhunter/src/mister/PCFX_MiSTer/rtl/tb/pcfx_top_tb.verilator.gtkw"
|
||||
[timestart] 1230000
|
||||
[timestart] 0
|
||||
[size] 1334 601
|
||||
[pos] -1 -1
|
||||
*-24.251604 50041100 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
*-25.045605 50097180 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
[markername] AA
|
||||
[markername] BB
|
||||
[markername] CC
|
||||
@@ -37,7 +37,6 @@
|
||||
[markername] YY
|
||||
[markername] ZZ
|
||||
[treeopen] pcfx_top_tb.
|
||||
[treeopen] pcfx_top_tb.pcfx_top.
|
||||
[treeopen] pcfx_top_tb.pcfx_top.mach.cpu.
|
||||
[treeopen] pcfx_top_tb.pcfx_top.mach.vdc1.SAT.
|
||||
[sst_width] 255
|
||||
@@ -48,6 +47,7 @@
|
||||
-pcfx_top
|
||||
@28
|
||||
pcfx_top_tb.pcfx_top.img_mounted[1:0]
|
||||
pcfx_top_tb.pcfx_top.bk_mounted[1:0]
|
||||
pcfx_top_tb.pcfx_top.bk_load
|
||||
pcfx_top_tb.pcfx_top.bk_save
|
||||
pcfx_top_tb.pcfx_top.sd_vd
|
||||
@@ -62,7 +62,6 @@ pcfx_top_tb.pcfx_top.sd_buff_addr[7:0]
|
||||
pcfx_top_tb.pcfx_top.sd_buff_dout[15:0]
|
||||
@28
|
||||
pcfx_top_tb.pcfx_top.bk_loading
|
||||
@29
|
||||
pcfx_top_tb.pcfx_top.bk_saving
|
||||
@100000028
|
||||
pcfx_top_tb.pcfx_top.bk_state[3:0]
|
||||
@@ -107,6 +106,26 @@ pcfx_top_tb.pcfx_top.memif_sdram.wact
|
||||
pcfx_top_tb.pcfx_top.memif_sdram.mem_rdy
|
||||
@1000200
|
||||
-memif_sdram
|
||||
@800200
|
||||
-fx_bmp
|
||||
@28
|
||||
pcfx_top_tb.pcfx_top.bmp.CFG_EN
|
||||
@24
|
||||
pcfx_top_tb.pcfx_top.bmp.CFG_SIZE[2:0]
|
||||
@29
|
||||
pcfx_top_tb.pcfx_top.bmp.MCP_CSn
|
||||
@22
|
||||
pcfx_top_tb.pcfx_top.bmp.MCP_A[26:1]
|
||||
@28
|
||||
pcfx_top_tb.pcfx_top.bmp.MCP_READYn
|
||||
@22
|
||||
pcfx_top_tb.pcfx_top.bmp.MCP_DO[7:0]
|
||||
@28
|
||||
pcfx_top_tb.pcfx_top.bmp.bat_sel
|
||||
pcfx_top_tb.pcfx_top.bmp.RAM_CEn
|
||||
pcfx_top_tb.pcfx_top.bmp.RAM_READYn
|
||||
@1000200
|
||||
-fx_bmp
|
||||
@28
|
||||
pcfx_top_tb.pcfx_top.mach.ERROR
|
||||
@22
|
||||
@@ -123,7 +142,7 @@ pcfx_top_tb.pcfx_top.mach.mem16_a[31:0]
|
||||
pcfx_top_tb.pcfx_top.mach.ram_cen
|
||||
pcfx_top_tb.pcfx_top.mach.rom_cen
|
||||
pcfx_top_tb.pcfx_top.mach.sram_cen
|
||||
pcfx_top_tb.pcfx_top.mach.bmp_cen
|
||||
pcfx_top_tb.pcfx_top.mach.mcp_csn
|
||||
pcfx_top_tb.pcfx_top.mach.io_cen
|
||||
pcfx_top_tb.pcfx_top.mach.ga_rdn
|
||||
pcfx_top_tb.pcfx_top.mach.ga_wrn
|
||||
|
||||
Reference in New Issue
Block a user