1
0
mirror of https://github.com/UzixLS/zx-sizif-xxs.git synced 2025-07-18 23:01:40 +03:00

refactor memory controller

Also this commit fixes ula+ io contention for classic timings. This
affects ham256.tap.
This commit is contained in:
Eugene Lozovoy
2024-01-08 20:15:34 +03:00
parent c69b7c8ba4
commit c8d83ac5c1
8 changed files with 218 additions and 123 deletions

View File

@ -16,6 +16,7 @@ interface cpu_bus();
reg rd;
reg wr;
wire ioreq;
wire memreq;
reg ioreq;
reg memreq;
reg memreq_rise;
endinterface

View File

@ -17,53 +17,53 @@ module cpu(
input machine_t machine,
input turbo_t turbo,
input init_done_in,
input hold,
output reg n_rstcpu_out,
output reg clkcpu,
output clkcpu_ck,
output clkcpu_stall,
output reg n_int,
output n_int_next,
output snow
output reg n_int_next,
output snow,
output contention
);
/* CONTENTION */
wire iorq_contended = bus.iorq && (~bus.a[0] || (~bus.a[1] && ~bus.a_raw[15] && bus.wr)) && (machine != MACHINE_S3);
wire iorq_contended = bus.ioreq && (~bus.a[0] || (bus.a == 16'hBF3B) || (bus.a == 16'hFF3B)) && (machine != MACHINE_S3);
reg mreq_delayed, iorq_delayed;
always @(negedge clk28) if (clkcpu_ck)
always @(posedge clkcpu)
mreq_delayed <= bus.mreq;
always @(negedge clk28) if (clkcpu_ck)
iorq_delayed <= bus.iorq && ~bus.a[0];
wire contention_mem_page = (machine == MACHINE_S3)? ram_page128[2] : ram_page128[0];
wire contention_mem_addr = bus.a_raw[14] & (~bus.a_raw[15] | (bus.a_raw[15] & contention_mem_page));
wire contention_mem = iorq_delayed == 1'b0 && mreq_delayed == 1'b0 && contention_mem_addr;
wire contention_io = iorq_delayed == 1'b0 && iorq_contended;
wire contention0 = video_contention && (contention_mem || contention_io);
wire contention = clkcpu && contention0 && turbo == TURBO_NONE && (machine == MACHINE_S48 || machine == MACHINE_S128 || machine == MACHINE_S3);
assign snow = bus.a_raw[14] && ~bus.a_raw[15] && bus.rfsh && (machine == MACHINE_S48 || machine == MACHINE_S128);
always @(posedge clkcpu)
iorq_delayed <= iorq_contended;
wire contention_page = (machine == MACHINE_S3)? ram_page128[2] : ram_page128[0];
wire contention_addr = bus.a_raw[14] & (~bus.a_raw[15] | (bus.a_raw[15] & contention_page));
wire contention_mem = !iorq_contended && !mreq_delayed && contention_addr;
wire contention0 = video_contention && !iorq_delayed && (contention_mem || iorq_contended);
assign contention = clkcpu && contention0 && turbo == TURBO_NONE && (machine == MACHINE_S48 || machine == MACHINE_S128 || machine == MACHINE_S3);
assign snow = video_contention && contention_addr && bus.rfsh && bus.mreq && (machine == MACHINE_S48 || machine == MACHINE_S128);
/* CLOCK */
reg [3:0] turbo_wait;
wire turbo_wait_trig0 = turbo == TURBO_14 && bus.mreq && !bus.rfsh;
wire turbo_wait_trig1 = turbo == TURBO_14 && (bus.rd || bus.wr);
reg turbo_wait_trig0_prev, turbo_wait_trig1_prev;
wire turbo_wait_cond = turbo == TURBO_14 && (bus.rd || bus.wr || (bus.iorq && bus.m1));
reg [2:0] turbo_wait_reg;
reg turbo_wait;
always @* begin
if (bus.iorq)
turbo_wait <= turbo_wait_cond && !turbo_wait_reg[2];
else
turbo_wait <= turbo_wait_cond && !turbo_wait_reg[1];
end
always @(posedge clk28) begin
turbo_wait[0] <= turbo_wait_trig0 && !turbo_wait_trig0_prev;
turbo_wait[1] <= turbo_wait[0] || (turbo_wait_trig1 && !turbo_wait_trig1_prev);
turbo_wait[2] <= turbo_wait[1];
turbo_wait[3] <= turbo_wait[2];
turbo_wait_trig0_prev <= turbo_wait_trig0;
turbo_wait_trig1_prev <= turbo_wait_trig1;
if (clkcpu != clk14)
turbo_wait_reg <= {turbo_wait_reg[1:0], turbo_wait_cond};
end
reg clkcpu_prev;
assign clkcpu_ck = clkcpu && !clkcpu_prev;
assign clkcpu_stall = contention || (|turbo_wait[3:1]);
always @(posedge clk28) begin
clkcpu_prev <= clkcpu;
if (clkcpu_stall)
if (contention || hold || turbo_wait)
clkcpu <= clkcpu;
else if (turbo == TURBO_14)
clkcpu <= clk14;

View File

@ -27,17 +27,17 @@ module divmmc(
output reg mapram,
output ram,
output ramwr_mask,
output cpuwait
output ext_wait_cycle2
);
reg automap0, automap_next;
reg automap, automap_next;
always @(posedge clk28 or negedge rst_n) begin
if (!rst_n) begin
automap_next <= 0;
automap0 <= 0;
automap <= 0;
end
else if (bus.m1 && bus.memreq && !mask_hooks) begin
else if (bus.m1 && bus.memreq_rise && !mask_hooks) begin
if (!en_hooks || !en || rammap) begin
automap_next <= 0;
end
@ -56,18 +56,14 @@ always @(posedge clk28 or negedge rst_n) begin
end
else if (bus.a[15:8] == 8'h3D) begin // tr-dos mapping area
automap_next <= 1'b1;
automap0 <= 1'b1;
automap <= 1'b1;
end
end
else if (!bus.m1) begin
automap0 <= automap_next;
automap <= automap_next;
end
end
// #3Dxx entrypoint is critical for timings, so we're arming 'map' signal as soon as possible
wire automap = automap0 || (bus.m1 && bus.memreq && !mask_hooks && en_hooks && en && !rammap && bus.a[15:8] == 8'h3D);
reg conmem;
wire port_e3_cs = en && bus.ioreq && bus.a[7:0] == 8'hE3;
wire port_e7_cs = en && bus.ioreq && bus.a[7:0] == 8'hE7;
@ -111,7 +107,7 @@ end
reg [3:0] spi_cnt;
wire spi_cnt_en = ~spi_cnt[3] | spi_cnt[2] | spi_cnt[1] | spi_cnt[0];
assign cpuwait = ~spi_cnt[3];
assign ext_wait_cycle2 = ~spi_cnt[3];
always @(posedge clk28 or negedge rst_n) begin
if (!rst_n)
spi_cnt <= 0;

View File

@ -16,7 +16,7 @@ module magic(
input div_paged,
output reg magic_mode,
output magic_map,
output reg magic_map,
output reg magic_reboot,
output reg magic_beeper,
@ -37,12 +37,11 @@ localparam magic_on_start = 1'b1;
reg magic_unmap_next;
reg magic_map_next;
reg magic_map0;
always @(posedge clk28 or negedge rst_n) begin
if (!rst_n) begin
n_nmi <= 1'b1;
magic_mode <= magic_on_start;
magic_map0 <= magic_on_start;
magic_map <= magic_on_start;
magic_map_next <= 0;
magic_unmap_next <= 0;
end
@ -53,29 +52,26 @@ always @(posedge clk28 or negedge rst_n) begin
magic_mode <= 1'b1;
end
if (magic_map0 && bus.memreq && bus.rd && bus.a == 16'hf000 && !magic_map_next) begin
if (magic_map && bus.memreq && bus.rd && bus.a == 16'hf000 && !magic_map_next) begin
magic_unmap_next <= 1'b1;
magic_mode <= 1'b0;
end
else if (magic_map0 && bus.memreq && bus.rd && bus.a == 16'hf008) begin
else if (magic_map && bus.memreq && bus.rd && bus.a == 16'hf008) begin
magic_unmap_next <= 1'b1;
magic_map_next <= 1'b1;
end
else if (magic_unmap_next && !bus.memreq) begin
magic_map0 <= 1'b0;
magic_map <= 1'b0;
magic_unmap_next <= 1'b0;
end
else if (magic_mode && bus.m1 && bus.memreq && (bus.a == 16'h0066 || magic_map_next)) begin
else if (magic_mode && bus.m1 && bus.memreq_rise && (bus.a == 16'h0066 || magic_map_next)) begin
n_nmi <= 1'b1;
magic_map0 <= 1'b1;
magic_map <= 1'b1;
magic_map_next <= 1'b0;
end
end
end
// this signal is critical for timings, so we're arming it as soon as possible
assign magic_map = magic_map0 || (magic_mode && bus.m1 && bus.memreq && (bus.a == 16'h0066 || magic_map_next) && !magic_unmap_next);
/* MAGIC CONFIG */
wire config_cs = magic_map && bus.ioreq && bus.a[7:0] == 8'hFF;

View File

@ -1,13 +1,19 @@
import common::*;
module mem(
input rst_n,
input clk28,
cpu_bus bus,
output [18:0] va,
output reg [18:0] va,
inout [7:0] vd,
output n_vrd,
output n_vwr,
output reg n_vrd,
output reg n_vwr,
output bus_valid,
output cpuwait,
input machine_t machine,
input turbo_t turbo,
input cpu_contention,
input magic_map,
input [2:0] ram_page128,
input rom_page128,
@ -23,10 +29,13 @@ module mem(
input video_page,
input video_read_req,
input [14:0] video_read_addr,
output video_read_req_ack,
output video_data_valid,
input [16:0] rom2ram_ram_address,
input rom2ram_ram_wren,
input [7:0] rom2ram_dataout,
input magic_dout_active,
input [7:0] magic_dout,
input up_dout_active,
@ -51,11 +60,11 @@ module mem(
reg romreq, ramreq, ramreq_wr;
reg [18:13] va_18_13;
wire [15:0] a = bus.a_raw[15:0];
always @(negedge clk28) begin
romreq = bus.mreq && a[15:14] == 2'b00 &&
always @* begin
romreq = a[15:14] == 2'b00 &&
(magic_map || (!div_ram && div_map) || (!div_ram && !port_dffd[4] && !port_1ffd[0]));
ramreq = bus.mreq && !romreq;
ramreq_wr = ramreq && bus.wr && div_ramwr_mask == 0;
ramreq = !romreq;
ramreq_wr = ramreq && div_ramwr_mask == 0;
if (romreq) va_18_13 =
(magic_map) ? {5'd2, 1'b0} :
@ -80,15 +89,6 @@ always @(negedge clk28) begin
{2'b11, a[14], a[15], a[14], a[13]} ;
end
assign n_vrd = (((bus.mreq && bus.rd) || video_read_req) && !rom2ram_ram_wren)? 1'b0 : 1'b1;
assign n_vwr = ((ramreq_wr && bus.wr && !video_read_req) || rom2ram_ram_wren)? 1'b0 : 1'b1;
assign va[18:0] =
(rom2ram_ram_wren) ? {2'b00, rom2ram_ram_address} :
(video_read_req && snow) ? {3'b111, video_page, video_read_addr[14:8], {8{1'bz}}} :
(video_read_req) ? {3'b111, video_page, video_read_addr} :
{va_18_13, {13{1'bz}}};
assign vd[7:0] =
~n_vrd ? {8{1'bz}} :
bus.wr ? {8{1'bz}} :
@ -102,5 +102,102 @@ assign vd[7:0] =
bus.rd ? 8'hFF :
{8{1'bz}} ;
localparam BUS_VALID_LATENCY = 2'd1;
reg [1:0] bus_valid_step;
localparam LATENCY = 2'd2;
reg [1:0] step;
localparam REQ_NONE = 3'd0;
localparam REQ_CPU_RD = 3'd1;
localparam REQ_CPU_WR = 3'd2;
localparam REQ_VIDEO_RD = 3'd3;
localparam REQ_ROM2RAM_WR = 3'd4;
reg [2:0] current_req;
reg cpuwait_reg;
always @(posedge clk28 or negedge rst_n) begin
if (!rst_n) begin
va <= {va_18_13, {13{1'bz}}};
n_vrd <= 1'b1;
n_vwr <= 1'b1;
cpuwait_reg <= 0;
bus_valid_step <= 0;
step <= 0;
current_req <= REQ_NONE;
end
else begin
if (step)
step <= step - 1'd1;
if (bus_valid_step)
bus_valid_step <= bus_valid_step - 1'd1;
if (!(bus.mreq && bus.rd))
cpuwait_reg <= 0;
if (rom2ram_ram_wren) begin
if (current_req != REQ_ROM2RAM_WR)
step <= LATENCY;
va <= {2'b00, rom2ram_ram_address};
n_vrd <= 1'b1;
n_vwr <= (current_req == REQ_ROM2RAM_WR && step == 0)? 1'b1 : 1'b0;
bus_valid_step <= BUS_VALID_LATENCY;
current_req <= REQ_ROM2RAM_WR;
end
else if (turbo == TURBO_14 && current_req == REQ_VIDEO_RD && step) begin
// complete current request
bus_valid_step <= BUS_VALID_LATENCY;
end
else if (bus.mreq && bus.wr && ramreq_wr) begin
if (current_req != REQ_CPU_WR)
step <= LATENCY;
va <= {va_18_13, {13{1'bz}}};
n_vrd <= 1'b1;
n_vwr <= (current_req == REQ_CPU_WR && step == 0)? 1'b1 : 1'b0;
current_req <= REQ_CPU_WR;
end
else if (bus.mreq && bus.rd) begin
if (current_req != REQ_CPU_RD) begin
step <= LATENCY;
end
else if (va[18:13] != va_18_13) begin
cpuwait_reg <= 1'b1;
step <= LATENCY;
end
else if (!step) begin
cpuwait_reg <= 1'b0;
end
va <= {va_18_13, {13{1'bz}}};
n_vrd <= 1'b0;
n_vwr <= 1'b1;
current_req <= REQ_CPU_RD;
end
else if ((bus.mreq || bus.iorq) && !bus.rfsh && !cpu_contention) begin
va <= {va_18_13, {13{1'bz}}};
n_vrd <= 1'b1;
n_vwr <= 1'b1;
current_req <= REQ_NONE;
end
else if (video_read_req) begin
if (current_req != REQ_VIDEO_RD || !step)
step <= LATENCY;
va <= snow? {3'b111, video_page, video_read_addr[14:7], {7{1'bz}}} :
{3'b111, video_page, video_read_addr} ;
n_vrd <= 1'b0;
n_vwr <= 1'b1;
bus_valid_step <= BUS_VALID_LATENCY;
current_req <= REQ_VIDEO_RD;
end
else begin
va <= {va_18_13, {13{1'bz}}};
n_vrd <= 1'b1;
n_vwr <= 1'b1;
current_req <= REQ_NONE;
end
end
end
assign cpuwait = cpuwait_reg || (bus.mreq && bus.rd && current_req == REQ_CPU_RD && va[18:13] != va_18_13);
assign bus_valid = bus_valid_step == 0;
assign video_data_valid = current_req == REQ_VIDEO_RD && step == 0;
assign video_read_req_ack = current_req == REQ_VIDEO_RD && step == 1'd1 && (!((bus.mreq || bus.iorq) && !bus.rfsh && !cpu_contention) || turbo == TURBO_14);
endmodule

View File

@ -58,30 +58,16 @@ wire ps2_key_reset, ps2_key_pause;
wire [2:0] border;
wire magic_reboot, magic_beeper;
wire up_active;
wire clkcpu_stall;
wire [2:0] ram_page128;
wire init_done;
wire video_read_req, video_read_req_next;
wire mem_bus_valid;
wire mem_wait;
wire sd_indication;
/* CPU BUS */
cpu_bus bus();
reg bus_memreq, bus_ioreq;
wire mem_bus_valid = !video_read_req && !video_read_req_next;
always @(posedge clk28 or negedge rst_n) begin
if (!rst_n) begin
bus_ioreq <= 0;
bus_memreq <= 0;
end
else begin
bus.a <= mem_bus_valid? {a[15:13], va[12:0]} : bus.a;
bus.d <= mem_bus_valid? vd : bus.d;
bus_ioreq <= (mem_bus_valid | bus_ioreq) & ~n_iorq & n_m1;
bus_memreq <= (mem_bus_valid | bus_memreq) & ~n_mreq & n_rfsh;
end
end
always @(posedge clk168) begin
always @(negedge clk28) begin
bus.a_raw <= {a[15:13], va[12:0]};
bus.iorq <= ~n_iorq;
bus.mreq <= ~n_mreq;
@ -90,8 +76,13 @@ always @(posedge clk168) begin
bus.rd <= ~n_rd;
bus.wr <= ~n_wr;
end
assign bus.ioreq = bus_ioreq & bus.iorq;
assign bus.memreq = bus_memreq & bus.mreq;
always @(posedge clk28) begin
bus.a <= mem_bus_valid? {a[15:13], va[12:0]} : bus.a;
bus.d <= mem_bus_valid? vd : bus.d;
bus.ioreq <= (mem_bus_valid | bus.ioreq) & ~n_iorq & n_m1;
bus.memreq <= (mem_bus_valid | bus.memreq) & ~n_mreq & n_rfsh;
bus.memreq_rise <= mem_bus_valid & ~bus.memreq & ~n_mreq & n_rfsh;
end
/* RESET */
@ -105,6 +96,7 @@ end
wire [5:0] r, g, b;
wire hsync, vsync, csync0;
wire video_contention, port_ff_active;
wire video_read_req, video_read_req_ack, video_read_data_valid;
wire [14:0] video_read_addr;
wire [5:0] up_ink_addr, up_paper_addr;
wire [7:0] up_ink_data, up_paper_data;
@ -116,7 +108,6 @@ video video0(
.clk28(clk28),
.machine(machine),
.turbo(turbo),
.border({border[2] ^ sd_indication, border[1] ^ magic_beeper, border[0]}),
.r(r),
@ -126,10 +117,10 @@ video video0(
.vsync(vsync),
.hsync(hsync),
.read_allow((!bus.iorq && !bus.mreq) || bus.rfsh || (clkcpu_stall && turbo == TURBO_NONE)),
.read_req(video_read_req),
.read_req_next(video_read_req_next),
.read_req_addr(video_read_addr),
.read_req_ack(video_read_req_ack),
.read_data_valid(video_read_data_valid),
.read_data(vd),
.up_en(up_active),
@ -190,7 +181,7 @@ ps2 #(.CLK_FREQ(28_000_000)) ps2_0(
/* CPU CONTROLLER */
wire n_int_next, clkcpu_ck, snow;
wire n_int_next, clkcpu_ck, snow, cpu_contention;
cpu cpu0(
.rst_n(usrrst_n),
.clk28(clk28),
@ -207,16 +198,17 @@ cpu cpu0(
.ram_page128(ram_page128),
.machine(machine),
.turbo(turbo),
.hold(mem_wait),
.video_contention(video_contention),
.init_done_in(init_done),
.n_rstcpu_out(n_rstcpu),
.clkcpu(clkcpu),
.clkcpu_ck(clkcpu_ck),
.clkcpu_stall(clkcpu_stall),
.n_int(n_int),
.n_int_next(n_int_next),
.snow(snow)
.snow(snow),
.contention(cpu_contention)
);
@ -479,6 +471,7 @@ asmi asmi0(
/* MEMORY CONTROLLER */
mem mem0(
.rst_n(rst_n),
.clk28(clk28),
.bus(bus),
.va(va),
@ -486,7 +479,12 @@ mem mem0(
.n_vrd(n_vrd),
.n_vwr(n_vwr),
.bus_valid(mem_bus_valid),
.cpuwait(mem_wait),
.machine(machine),
.turbo(turbo),
.cpu_contention(cpu_contention),
.magic_map(magic_map),
.ram_page128(ram_page128),
.rom_page128(rom_page128),
@ -502,6 +500,8 @@ mem mem0(
.video_page(video_page),
.video_read_req(video_read_req),
.video_read_addr(video_read_addr),
.video_read_req_ack(video_read_req_ack),
.video_data_valid(video_read_data_valid),
.rom2ram_ram_address(rom2ram_ram_address),
.rom2ram_ram_wren(rom2ram_ram_wren),

View File

@ -4,7 +4,6 @@ module video(
input clk28,
input machine_t machine,
input turbo_t turbo,
input [2:0] border,
output reg [5:0] r,
@ -14,10 +13,10 @@ module video(
output reg hsync,
output reg csync,
input read_allow,
output reg read_req,
output read_req_next,
output read_req,
output [14:0] read_req_addr,
input read_req_ack,
input read_data_valid,
input [7:0] read_data,
output contention,
@ -179,7 +178,7 @@ wire screen_show = (vc < V_AREA) && (hc0 >= (SCREEN_DELAY<<2) - 1) && (hc0 < ((H
wire screen_update = hc0[4:0] == 5'b10011;
wire border_update = (hc0[4:0] == 5'b10011) || (machine == MACHINE_PENT && ck7);
wire bitmap_shift = hc0[1:0] == 2'b11;
wire next_addr = hc0[4:0] == 5'b10000;
wire next_addr = hc0[4:0] == 5'b10001;
reg screen_read, up_read;
always @(posedge clk28 or negedge rst_n) begin
@ -188,7 +187,7 @@ always @(posedge clk28 or negedge rst_n) begin
up_read <= 0;
end
else begin
screen_read <= (vc < V_AREA) && (hc0 > 15) && (hc0 < (H_AREA<<2) + 17);
screen_read <= (vc < V_AREA) && (hc0 > 17) && (hc0 < (H_AREA<<2) + 17);
up_read <= screen_read && (screen_update || up_read);
end
end
@ -209,41 +208,39 @@ end
reg [7:0] bitmap, attr, bitmap_next, attr_next;
reg [7:0] up_ink, up_paper;
reg [1:0] read_cnt;
localparam READ_CYCLES = 2'd2;
assign read_req_next = screen_read && (read_allow || (|read_cnt && read_cnt != READ_CYCLES && turbo == TURBO_14));
reg read_step;
assign read_req_addr = (read_step == 1'd0)?
reg read_step, read_step_cur;
assign read_req = 1'b1; // just to simplify logic
assign read_req_addr = (read_step == 1'd1)?
{ 2'b10, vaddr[7:6], vaddr[2:0], vaddr[5:3], haddr[7:3] } :
{ 5'b10110, vaddr[7:3], haddr[7:3] };
assign up_ink_addr = up_read? { attr_next[7:6], 1'b0, attr_next[2:0] } : { 3'b0, border[2:0] };
assign up_ink_addr = up_read? { attr_next[7:6], 1'b0, attr_next[2:0] } : { 3'b0, border[2:0] };
assign up_paper_addr = up_read? { attr_next[7:6], 1'b1, attr_next[5:3] } : { 3'b0, border[2:0] };
always @(posedge clk28 or negedge rst_n) begin
if (!rst_n) begin
read_req <= 0;
read_step <= 0;
read_cnt <= 0;
read_step_cur <= 0;
attr_next <= 0;
bitmap_next <= 0;
end
else begin
read_req <= read_req_next;
if (read_cnt == READ_CYCLES) begin
if (read_step == 1'd1)
attr_next <= read_data;
if (read_step == 1'd0)
bitmap_next <= read_data;
read_step <= read_step + 1'b1;
read_cnt <= 0;
end
else if (read_req && read_req_next && !next_addr) begin
read_cnt <= read_cnt + 1'b1;
end
else begin
read_cnt <= 0;
end
if (next_addr)
read_step <= 0;
else if (read_req_ack)
read_step <= read_step + 1'd1;
if (read_req_ack)
read_step_cur <= read_step;
if (read_data_valid && read_step_cur == 2'd0 && screen_read)
attr_next <= read_data;
else if (!screen_read && hc0[0])
attr_next <= {2'b00, border[2:0], border[2:0]};
if (read_data_valid && read_step_cur == 2'd1 && screen_read)
bitmap_next <= read_data;
else if (!screen_read && hc0[0])
bitmap_next <= 0;
end
end

View File

@ -44,13 +44,21 @@ Loop:
ORG #8000 // mapped #0000
MagicROM_Start:
ld sp, #8000
ld bc, #09ff ; divmmc = 1
ld a, 1 ; ...
out (c), a ; ...
ld bc, #03ff ; cpu freq = 7mhz
ld a, 3 ; ...
ld bc, #02ff ; machine = 128
ld a, 1 ; ...
out (c), a ; ...
ld bc, #03ff ; cpu freq = 14mhz
ld a, 4 ; ...
out (c), a ; ...
.100 in a, (#fe)
ld bc, #0000
ld de, #5000
ld hl, #6000
ldir
push bc
jp #f008
ORG #F000