Files
PCXT_MiSTer/rtl/KFPC-XT/HDL/RAM.sv
Aitor Gómez García 5d503bc064 PCXT: macro-driven build config and unified constraints
- Add config.tcl as the PCXT build profile and source it from PCXT.qsf with defaults for system/ROM and feature toggles.

- Gate video/audio/EMS/Tandy logic by macros in PCXT.sv, Peripherals.sv, RAM.sv, and cga.v to avoid unused I/O and logic.

- Update OSD options and video swap behavior to match CGA/HGC combos and hide Tandy-only items when disabled.

- Move constraints to SYSTEM.sdc and update files.qip.

- Refresh README.md with the PCXT default config and resource profile.
2026-01-06 20:13:11 +01:00

377 lines
12 KiB
Systemverilog

//
// MiSTer PCXT RAM
// Ported by @spark2k06
//
// Based on KFPC-XT written by @kitune-san
//
`ifndef SYSTEM_VARIANT_TANDY
`define SYSTEM_VARIANT_TANDY 0
`endif
`ifndef ROM_VARIANT_TANDY
`define ROM_VARIANT_TANDY `SYSTEM_VARIANT_TANDY
`endif
`ifndef ROM_IS_TANDY
`define ROM_IS_TANDY `ROM_VARIANT_TANDY
`endif
module RAM (
input logic clock,
input logic reset,
input logic enable_sdram,
output logic initilized_sdram,
// I/O Ports
input logic [19:0] address,
input logic [7:0] internal_data_bus,
output logic [7:0] data_bus_out,
input logic memory_read_n,
input logic memory_write_n,
input logic no_command_state,
output logic memory_access_ready,
output logic ram_address_select_n,
// SDRAM
output logic [12:0] sdram_address,
output logic sdram_cke,
output logic sdram_cs,
output logic sdram_ras,
output logic sdram_cas,
output logic sdram_we,
output logic [1:0] sdram_ba,
input logic [15:0] sdram_dq_in,
output logic [15:0] sdram_dq_out,
output logic sdram_dq_io,
output logic sdram_ldqm,
output logic sdram_udqm,
// EMS
input logic [6:0] map_ems[0:3],
input logic ems_b1,
input logic ems_b2,
input logic ems_b3,
input logic ems_b4,
// BIOS
input logic [1:0] bios_protect_flag,
input logic tandy_bios_flag,
// Optional flags
input logic enable_a000h,
// Wait mode
input logic wait_count_clk_en,
input logic [1:0] ram_read_wait_cycle,
input logic [1:0] ram_write_wait_cycle
);
typedef enum {IDLE, RAM_WRITE_1, RAM_WRITE_2, RAM_READ_1, RAM_READ_2, COMPLETE_RAM_RW, WAIT} state_t;
state_t state;
state_t next_state;
logic [21:0] latch_address;
logic [7:0] latch_data;
logic write_command;
logic read_command;
logic prev_no_command_state;
logic enable_refresh;
logic write_protect;
logic tandy_bios_select;
logic [1:0] read_wait_count;
logic [1:0] write_wait_count;
logic access_ready;
//
// RAM Address Select (0x00000-0xAFFFF and 0xC0000-0xFFFFF)
//
assign ram_address_select_n = ~(enable_sdram && ~(address[19:16] == 4'b1011) && // B0000h reserved for VRAM
~(~enable_a000h && address[19:16] == 4'b1010)); // A0000h is optional
assign tandy_bios_select = `ROM_IS_TANDY ? (tandy_bios_flag & (address[19:16] == 4'b1111)) : 1'b0;
//
// Write protect
//
assign write_protect = bios_protect_flag[1] & (address[19:16] == 4'b1111)
| bios_protect_flag[0] & (address[19:14] == 6'b111011);
//
// I/O Ports
//
// Address
always_comb begin
if (ems_b1)
latch_address = {1'b1, map_ems[0], address[13:0]};
else if (ems_b2)
latch_address = {1'b1, map_ems[1], address[13:0]};
else if (ems_b3)
latch_address = {1'b1, map_ems[2], address[13:0]};
else if (ems_b4)
latch_address = {1'b1, map_ems[3], address[13:0]};
else
latch_address = {1'b0, tandy_bios_select, address};
end
// Data
always_ff @(posedge clock, posedge reset) begin
if (reset)
latch_data <= 0;
else
latch_data <= internal_data_bus;
end
// Write Command
assign write_command = ~ram_address_select_n & ~memory_write_n & ~write_protect;
// Read Command
assign read_command = ~ram_address_select_n & ~memory_read_n;
// Generate refresh timing
always_ff @(posedge clock, posedge reset) begin
if (reset) begin
prev_no_command_state <= 1'b0;
end
else begin
prev_no_command_state <= no_command_state;
end
end
assign enable_refresh = no_command_state & ~prev_no_command_state;
//
// SDRAM Controller
//
logic [24:0] access_address;
logic [9:0] access_num;
logic [15:0] access_data_in;
logic [15:0] access_data_out;
logic write_request;
logic read_request;
logic write_flag;
logic read_flag;
logic idle;
logic refresh_mode;
KFSDRAM u_KFSDRAM (
.sdram_clock (clock),
.sdram_reset (reset),
.address (access_address),
.access_num (access_num),
.data_in (access_data_in),
.data_out (access_data_out),
.write_request (write_request),
.read_request (read_request),
.enable_refresh (enable_refresh),
.write_flag (write_flag),
.read_flag (read_flag),
.idle (idle),
.refresh_mode (refresh_mode),
.sdram_address (sdram_address),
.sdram_cke (sdram_cke),
.sdram_cs (sdram_cs),
.sdram_ras (sdram_ras),
.sdram_cas (sdram_cas),
.sdram_we (sdram_we),
.sdram_ba (sdram_ba),
.sdram_dq_in (sdram_dq_in),
.sdram_dq_out (sdram_dq_out),
.sdram_dq_io (sdram_dq_io)
);
//
// State machine
//
always_comb begin
next_state = state;
casez (state)
IDLE: begin
if (write_command)
next_state = RAM_WRITE_1;
else if (read_command)
next_state = RAM_READ_1;
end
RAM_WRITE_1: begin
if (~write_command)
next_state = WAIT;
if (write_flag)
next_state = RAM_WRITE_2;
end
RAM_WRITE_2: begin
if (~write_command)
next_state = WAIT;
if (~write_flag)
next_state = COMPLETE_RAM_RW;
end
RAM_READ_1: begin
if (~read_command)
next_state = WAIT;
if (read_flag)
next_state = RAM_READ_2;
end
RAM_READ_2: begin
if (~read_command)
next_state = WAIT;
if (~read_flag)
next_state = COMPLETE_RAM_RW;
end
COMPLETE_RAM_RW: begin
if ((~write_command) && (~read_command))
next_state = IDLE;
end
WAIT: begin
if (idle)
next_state = IDLE;
end
endcase
end
always_ff @(posedge clock, posedge reset) begin
if (reset)
state = IDLE;
else
state = next_state;
end
always_ff @(posedge clock, posedge reset) begin
if (reset)
initilized_sdram <= 1'b0;
else if (idle)
initilized_sdram <= 1'b1;
else
initilized_sdram <= initilized_sdram;
end
//
// Output SDRAM Control Signals
//
always_comb begin
casez (state)
IDLE: begin
access_address = {7'h00, latch_address};
access_num = 10'h001;
access_data_in = {8'h00, latch_data};
write_request = write_command ? 1'b1 : 1'b0;
read_request = read_command ? 1'b1 : 1'b0;
sdram_ldqm = 1'b0;
sdram_udqm = 1'b0;
end
RAM_WRITE_1: begin
access_address = {7'h00, latch_address};
access_num = 10'h001;
access_data_in = {8'h00, latch_data};
write_request = 1'b1;
read_request = 1'b0;
sdram_ldqm = 1'b0;
sdram_udqm = 1'b0;
end
RAM_WRITE_2: begin
access_address = {7'h00, latch_address};
access_num = 10'h001;
access_data_in = {8'h00, latch_data};
write_request = 1'b0;
read_request = 1'b0;
sdram_ldqm = 1'b0;
sdram_udqm = 1'b0;
end
RAM_READ_1: begin
access_address = {7'h00, latch_address};
access_num = 10'h001;
access_data_in = 16'h0000;
write_request = 1'b0;
read_request = 1'b1;
sdram_ldqm = 1'b0;
sdram_udqm = 1'b0;
end
RAM_READ_2: begin
access_address = {7'h00, latch_address};
access_num = 10'h001;
access_data_in = 16'h0000;
write_request = 1'b0;
read_request = 1'b0;
sdram_ldqm = 1'b0;
sdram_udqm = 1'b0;
end
COMPLETE_RAM_RW: begin
access_address = 25'h0000000;
access_num = 10'h001;
access_data_in = 16'h0000;
write_request = 1'b0;
read_request = 1'b0;
sdram_ldqm = 1'b0;
sdram_udqm = 1'b0;
end
WAIT: begin
access_address = 25'h0000000;
access_num = 10'h001;
access_data_in = 16'h0000;
write_request = 1'b0;
read_request = 1'b0;
sdram_ldqm = 1'b1;
sdram_udqm = 1'b1;
end
endcase
end
//
// Databus Out
//
logic [7:0] data_bus_out_reg;
always_ff @(posedge clock, posedge reset) begin
if (reset)
data_bus_out_reg <= 0;
else if (read_flag)
data_bus_out_reg <= access_data_out[7:0];
else
data_bus_out_reg <= data_bus_out_reg;
end
assign data_bus_out = ~read_command ? 0 : ~read_flag ? data_bus_out_reg : access_data_out[7:0];
//
// Ready/Wait Signal
//
always_ff @(posedge clock, posedge reset) begin
if (reset)
access_ready <= 1'b0;
else if (state == COMPLETE_RAM_RW)
access_ready <= 1'b1;
else if (state == IDLE)
access_ready <= idle;
else if ((write_command) && (refresh_mode))
access_ready <= 1'b0;
else if ((read_command) && (refresh_mode))
access_ready <= 1'b0;
else
access_ready <= access_ready;
end
always_ff @(posedge clock, posedge reset) begin
if (reset)
read_wait_count <= 0;
else if (~read_command)
read_wait_count <= ram_read_wait_cycle;
else if ((wait_count_clk_en) && (read_wait_count != 0))
read_wait_count <= read_wait_count - 1;
else
read_wait_count <= read_wait_count;
end
always_ff @(posedge clock, posedge reset) begin
if (reset)
write_wait_count <= 0;
else if (~write_command)
write_wait_count <= ram_write_wait_cycle;
else if ((wait_count_clk_en) && (write_wait_count != 0))
write_wait_count <= write_wait_count - 1;
else
write_wait_count <= write_wait_count;
end
assign memory_access_ready = ((~ram_address_select_n) && ((~memory_read_n) || (~memory_write_n)))
? (access_ready & ((read_wait_count==0) || (~read_command)) & ((write_wait_count==0) || (~write_command))) : 1'b1;
endmodule