Files
TSConf_MiST/src/cpu/zmem.v
2018-08-21 20:15:54 +08:00

313 lines
9.8 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.

// PentEvo project (c) NedoPC 2008-2009
//
module zmem(
input wire clk,
input wire c0, c1, c2, c3,
input wire zneg, // strobes which show positive and negative edges of zclk
input wire zpos,
// Z80
input wire rst,
input wire [15:0] za,
output wire [ 7:0] zd_out, // output to Z80 bus
output wire zd_ena, // output to Z80 bus enable
input wire opfetch,
input wire opfetch_s,
input wire mreq,
input wire memrd,
input wire memwr,
input wire memwr_s,
input wire [ 1:0] turbo, // 2'b00 - 3.5,
// 2'b01 - 7.0,
// 2'b1x - 14.0
input wire [3:0] cache_en,
input wire [3:0] memconf,
input wire [31:0] xt_page,
output wire [7:0] xtpage_0,
output wire [4:0] rompg,
output wire csrom,
output wire romoe_n,
output wire romwe_n,
output wire csvrom,
output wire dos,
output wire dos_on,
output wire dos_off,
output wire dos_change,
output wire vdos,
output reg pre_vdos,
input wire vdos_on,
input wire vdos_off,
// DRAM
output wire cpu_req,
output wire [20:0] cpu_addr,
output wire cpu_wrbsel,
input wire [15:0] cpu_rddata,
input wire cpu_next,
input wire cpu_strobe,
input wire cpu_latch,
output wire cpu_stall, // for zclock
input wire loader,
input wire testkey, // DEBUG!!!
input wire intt, // DEBUG!!!
output wire [3:0] tst
);
assign tst[0] = memwr && win0;
assign tst[1] = rw_en;
assign tst[2] = ramwr;
assign tst[3] = 1'b0;
assign xtpage_0 = xtpage[0];
//assign xtpage_0 = { 4'b0, vdos, memconf[2], ~dos, memconf[0]};
//---SELECT ROM PAGE0---------
//localparam DOS_RESET = 1'h1; //DOS-ON
localparam DOS_RESET = 1'h0; //DOS-OFF
// pager
wire [1:0] win = za[15:14];
wire win0 = ~|win; // PAGE 1,2,3 (not PAGE0)
// loader = 1 : при выборе Bank3 - ВСЕГДА ПОДКЛЮЧЕНА ВЕРХНЯЯ ПАМЯТЬ - vROM
// загружаю RОМ через Bank3, запись всегда разрешена
wire rw_en = !win0 || memconf[1] || vdos; // =1 : WRITE ENABLE for PAGE0 when memconf[1]=1 or vDOS
//memconf[1] = 1 BANK0 WR_EN, 0 - DIS
//wire rw_en = !win0 || memconf[3] || memconf[1] || vdos; // WRITE EN for ALL Win if -RAM
wire [7:0] page = xtpage[win];
assign rompg = xtpage[0][4:0];
assign csrom = 1'b0; // csvrom && !loader; // 1'b0; //- сигнал ЗАПРЕЩЕНИЯ ЗАПИСИ в ВИРУАЛЬНОЕ ПЗУ
assign csvrom = win0 && !memconf[3] && !vdos; //- сигнал ДОСТУПА К ВИРУТАЛЬНОМУ ПЗУ
// memconf[3] = 1-RAM, =0-ROM
//assign csvrom = win0 && !memconf[3] && !vdos && !(memconf [1] && memwr); // - если WR EN - to RAM ???
wire [7:0] xtpage[0:3];
assign xtpage[0] = vdos ? 8'hFF : {xt_page[7:2], memconf[2] ? xt_page[1:0] : {~dos, memconf[0]}};
assign xtpage[1] = xt_page[15:8];
assign xtpage[2] = xt_page[23:16];
assign xtpage[3] = xt_page[31:24]; //rampage[3]
// DOS signal control
assign dos_on = win0 && opfetch_s && (za[13:8]==6'h3D) && memconf[0] && !memconf[2];
//assign dos_on = win0 && opfetch_s && (za[13:8]==6'h3D) && memconf[0];
assign dos_off = !win0 && opfetch_s && !vdos;
//assign dos_off = !win0 && opfetch_s;
assign dos_change = (dos_off && dos_r) || (dos_on && !dos_r);
//assign dos = (dos_on || dos_off) ^^ dos_r; // to make dos appear 1 clock earlier than dos_r
//assign dos = (dos_on || dos_r);
assign dos = (dos_on || dos_r) && !dos_off;
reg dos_r;
always @(posedge clk)
if (rst)
//dos_r <= 1'b0;
dos_r <= DOS_RESET; //=1 ON
else if (dos_off)
dos_r <= 1'b0;
else if (dos_on)
dos_r <= 1'b1;
// VDOS signal control
// vdos turn on/off is delayed till next opfetch due to INIR that writes right after iord cycle
assign vdos = opfetch ? pre_vdos : vdos_r; // vdos appears as soon as first opfetch
reg vdos_r;
always @(posedge clk)
if (rst || vdos_off)
begin
pre_vdos <= 1'b0;
vdos_r <= 1'b0;
end
else if (vdos_on)
pre_vdos <= 1'b1;
else if (opfetch_s)
vdos_r <= pre_vdos;
// ===========================================================================
// Z80 controls
assign romoe_n = !memrd;
assign romwe_n = !(memwr && rw_en);
wire ramreq = mreq && !csrom;
wire ramrd = memrd && !csrom;
wire ramwr = memwr && !csrom && rw_en;
wire ramwr_s = memwr_s && !csrom && rw_en;
assign zd_ena = memrd && !csrom;
assign cpu_req = turbo14 ? cpureq_14 : cpureq_357;
assign cpu_stall = turbo14 ? stall14 : stall357;
wire turbo14 = turbo[1];
// 7/3.5MHz support =========================================
wire cpureq_357 = (ramrd_zs && !cache_hit_en) || ramwr_zs;
wire stall357 = cpureq_357 && !cpu_next;
wire ramwr_zs = ramwr && !ramwr_zr;
wire ramrd_zs = ramrd && !ramrd_zr;
reg ramrd_zr, ramwr_zr;
always @(posedge clk)
if (c3 && !cpu_stall)
begin
ramrd_zr <= ramrd;
ramwr_zr <= ramwr;
end
// 14MHz support ============================================
// wait tables:
//
// M1 opcode fetch, dram_beg concurs with:
// c3: +3
// c2: +4
// c1: +5
// c0: +6
//
// memory read, dram_beg concurs with:
// c3: +2
// c2: +3
// c1: +4
// c0: +5
//
// memory write: no wait
//
// special case: if dram_beg pulses 1 when cpu_next is 0,
// unconditional wait has to be performed until cpu_next is 1, and
// then wait as if dram_beg would concur with c0
// memrd, opfetch - wait till c3 && cpu_next,
// memwr - wait till cpu_next
wire cpureq_14 = dram_beg || pending_cpu_req;
//wire stall14 = stall14_ini || stall14_cyc || stall14_fin; //- not work
wire stall14 = stall14_ini || stall14_cyc; //WORK
//wire dram_beg = (!cache_hit_en || ramwr) && zpos && ramreq_s_n; //modif N1
wire dram_beg = (!cache_hit_en && ( memconf[3] ? 1'b1 : ramrd ) || ramwr) && zpos && ramreq_s_n; //-- N2
//if BANK0-RAM, WR enable all time for 14 MHz
wire ramreq_s_n = ramreq_r_n && ramreq;
reg ramreq_r_n;
//always @(posedge clk) if (zneg)
always @(posedge clk) if (zpos)
ramreq_r_n <= !mreq;
reg pending_cpu_req;
always @(posedge clk)
if (rst)
pending_cpu_req <= 1'b0;
else if (cpu_next && c3)
pending_cpu_req <= 1'b0;
else if (dram_beg)
pending_cpu_req <= 1'b1;
wire stall14_ini = dram_beg && (!cpu_next || opfetch || memrd); // no wait at all in write cycles, if next dram cycle is available
wire stall14_cyc = memrd ? stall14_cycrd : !cpu_next;
reg stall14_cycrd;
always @(posedge clk)
if (rst)
stall14_cycrd <= 1'b0;
else if (cpu_next && c3)
stall14_cycrd <= 1'b0;
else if (dram_beg && (!c3 || !cpu_next) && (opfetch || memrd))
stall14_cycrd <= 1'b1;
reg stall14_fin;
always @(posedge clk)
if (rst)
stall14_fin <= 1'b0;
else if (stall14_fin && ((opfetch && cc[0]) || (memrd && cc[1])))
stall14_fin <= 1'b0;
else if (cpu_next && c3 && cpu_req && (opfetch || memrd))
stall14_fin <= 1'b1;
wire [1:0] cc = turbo[0] ? {c1, c0} : {c2, c1}; // normal or overclock
// address, data in and data out =============================================
assign cpu_wrbsel = za[0];
assign cpu_addr[20:0] = {page, za[13:1]};
wire [15:0] mem_d = cpu_latch ? cpu_rddata : cache_d;
//assign zd_out = ~cpu_wrbsel ? cpu_rddata[7:0] : cpu_rddata[15:8];
assign zd_out = ~cpu_wrbsel ? mem_d[7:0] : mem_d[15:8];
//=================================================================
// CACHE ==INPUT:ramwr,csvrom,cpu_addr,cpu_rddata =================
wire [7:0] ch_addr1 = cpu_addr[7:0];
wire [12:0] cpu_hi_addr1 = cpu_addr[20:8];
wire csvrom1 = csvrom;
reg [7:0] ch_addr2;
reg [12:0] cpu_hi_addr2;
reg csvrom2;
always @(posedge clk) //- !clk
if (c0) // ready for cx ------------c1 -not stable
begin //------------c0 -0k
ch_addr2 <= cpu_addr[7:0]; //--c3 -not stable
cpu_hi_addr2 <= cpu_addr[20:8];
csvrom2 <= csvrom;
end
//----------------------------------
//===========================================================
wire [12:0] cache_a; //address from CACHE
wire [15:0] cache_d; //data from CACHE
wire cache_v; //data valid
wire [1:0] cache_tmp; //empty 16bit: 2 cache_tmp + csvrom + 13cpu_hi_addr1
dpram #(.DATAWIDTH(16), .ADDRWIDTH(9)) cache_data
(
.clock (clk), // -- CLK
.address_b ({csvrom1, ch_addr1}), // ADDR for RD
.address_a (loader ? za[8:0] : cpu_strobe ? {csvrom2, ch_addr2} : {csvrom1, ch_addr1}),//WR
//-----------------CACHE DATA -------------------------
.wren_a (loader ? 1'b1 : cpu_strobe), //c2 -strobe
.data_a (loader ? 16'b0 : cpu_rddata), //<=====
.q_b (cache_d) // ==> data from CACHE
);
dpram #(.DATAWIDTH(16), .ADDRWIDTH(9)) cache_addr
(
.clock (clk), //---- CLK
.address_b ({csvrom1, ch_addr1}), //
.address_a (loader ? za[8:0] : cpu_strobe ? {csvrom2, ch_addr2} : {csvrom1, ch_addr1}), //WR
//--------------arbiter.cpu_strobe <= curr_cpu && cpu_rnw_r;
.q_b ({cache_tmp, cache_v, cache_a}), // valid, addr from CACHE
.data_a (loader ? 16'b0 : cpu_strobe ? {cache_tmp, 1'b1, cpu_hi_addr2} : {2'b0, 1'b0, 8'b0}), //wrdata
.wren_a (loader ? 1'b1 : (cpu_strobe || cache_inv)) //c2 -strobe
);
//-----------
wire cache_hit = (cpu_hi_addr1 == cache_a) && cache_v;
//---ONLY RAM
//wire cache_hit = !csvrom1 && (cpu_hi_addr1 == cache_a) && cache_v; // asynchronous signal meaning that address requested by CPU is cached and valid
//---ONLY ROM
//wire cache_hit = csvrom1 && (cpu_hi_addr1 == cache_a) && cache_v;
//wire cache_hit_en = (cache_hit && cache_en) ;
wire cache_hit_en = (cache_hit && (cache_en[win] || csvrom)) ;
wire cache_inv = ramwr_s && cache_hit; // cache invalidation should be only performed if write happens to cached address
endmodule