diff --git a/src/cpu/zmem.v b/src/cpu/zmem.v index 2b0146a..ce58656 100644 --- a/src/cpu/zmem.v +++ b/src/cpu/zmem.v @@ -1,307 +1,228 @@ - // PentEvo project (c) NedoPC 2008-2009 // - +// Z80 memory manager: routes ROM/RAM accesses, makes wait-states for 14MHz or stall condition, etc. +// +// +// clk _/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\ +// | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | +// zclk /```\___/```\___/```\___/```````\_______/```````\_______/```````````````\_______________/```````````````\_______________/` +// | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | +// zpos `\___/```\___/```\___/```\___________/```\___________/```\___________________________/```\___________________________/```\ +// | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | +// zneg _/```\___/```\___/```\_______/```\___________/```\___________________/```\___________________________/```\________________ module zmem ( - input wire clk, - input wire c0, c1, c2, c3, - input wire zpos, + input clk, + input c0, c1, c2, c3, + input zneg, // strobes which show positive and negative edges of zclk + input 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 rst, + input [15:0] za, + output [ 7:0] zd_out, // output to Z80 bus + output 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 opfetch, + input opfetch_s, + input mreq, + input memrd, + input memwr, + input 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, + input [ 1:0] turbo, // 2'b00 - 3.5, + // 2'b01 - 7.0, + // 2'b1x - 14.0 + input [3:0] cache_en, + input [3:0] memconf, + input [31:0] xt_page, - output wire [4:0] rompg, - output wire csrom, - output wire romoe_n, - output wire romwe_n, + output [4:0] rompg, + output csrom, + output romoe_n, + output 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, + output dos, + output dos_on, + output dos_off, + output vdos, + output reg pre_vdos, + input vdos_on, + input 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 + output cpu_req, + output [20:0] cpu_addr, + output cpu_wrbsel, + input [15:0] cpu_rddata, + input cpu_next, + input cpu_strobe, + input cpu_latch, + output cpu_stall // for zclock ); - 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 +// controls +wire rom128 = memconf[0]; +wire w0_we = memconf[1]; +wire w0_map_n = memconf[2]; +wire w0_ram = memconf[3]; // 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]; +wire [1:0] win = za[15:14]; +wire win0 = ~|win; +wire ramwr_en = !win0 || w0_we || vdos; +wire rom_n_ram = win0 && !w0_ram && !vdos; +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] +wire [7:0] xtpage[0:3]; +assign xtpage[0] = vdos ? 8'hFF : {xt_page[7:2], w0_map_n ? xt_page[1:0] : {~dos, rom128}}; +assign xtpage[1] = xt_page[15:8]; +assign xtpage[2] = xt_page[23:16]; +assign xtpage[3] = xt_page[31:24]; +// ROM chip +assign csrom = rom_n_ram; +assign romoe_n = !memrd; +assign romwe_n = !(memwr && w0_we); +assign rompg = xtpage[0][4:0]; + +// RAM +assign zd_ena = !rom_n_ram && memrd; +wire ramreq = !rom_n_ram && ((memrd && !cache_hit_en) || (memwr && ramwr_en)); // 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_on = win0 && opfetch_s && (za[13:8]==6'h3D) && rom128 && !w0_map_n; +assign dos_off = !win0 && opfetch_s && !vdos; - //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; +assign dos = (dos_on || dos_off) ^^ dos_r; // to make dos appear 1 clock earlier than dos_r +reg dos_r; +always @(posedge clk) begin + if (rst) dos_r <= 0; + else if (dos_off) dos_r <= 0; + else if (dos_on) dos_r <= 1; +end // 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 +// 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; +reg vdos_r; +always @(posedge clk) begin + if (rst || vdos_off) begin + pre_vdos <= 0; + vdos_r <= 0; end - else if (vdos_on) - pre_vdos <= 1'b1; - else if (opfetch_s) - vdos_r <= pre_vdos; + else if (vdos_on) pre_vdos <= 1; + else if (opfetch_s) vdos_r <= pre_vdos; +end -// =========================================================================== +// 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 ? mem_d[7:0] : mem_d[15:8]; // Z80 controls - assign romoe_n = !memrd; - assign romwe_n = !(memwr && rw_en); +assign cpu_req = turbo14 ? cpureq_14 : cpureq_357; +assign cpu_stall = turbo14 ? stall14 : stall357; +wire turbo14 = turbo[1]; - 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; +// 7/3.5MHz support +wire cpureq_357 = ramreq && !ramreq_r; +wire stall357 = cpureq_357 && !cpu_next; - wire turbo14 = turbo[1]; - -// 7/3.5MHz support ========================================= - wire cpureq_357 = (ramrd_zs && !cache_hit_en) || ramwr_zs; - wire stall357 = cpureq_357 && !cpu_next; +reg ramreq_r; +always @(posedge clk) if (c3 && !cpu_stall) ramreq_r <= ramreq; - wire ramwr_zs = ramwr && !ramwr_zr; - wire ramrd_zs = ramrd && !ramrd_zr; +// 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 - reg ramrd_zr, ramwr_zr; - always @(posedge clk) - if (c3 && !cpu_stall) - begin - ramrd_zr <= ramrd; - ramwr_zr <= ramwr; - end +// memrd, opfetch - wait till c3 && cpu_next, +// memwr - wait till cpu_next -// 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 +wire cpureq_14 = dram_beg || pending_cpu_req; +wire stall14 = stall14_ini || stall14_cyc || stall14_fin; - // 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 && ( 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 (zpos) ramreq_r_n <= !mreq; +wire dram_beg = ramreq && !pre_ramreq_r && zneg; - 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; +reg pre_ramreq_r; +always @(posedge clk) if (zneg) pre_ramreq_r <= ramreq; - 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 pending_cpu_req; +always @(posedge clk) begin + if (rst) pending_cpu_req <= 0; + else if (cpu_next && c3) pending_cpu_req <= 0; + else if (dram_beg) pending_cpu_req <= 1; +end +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_cycrd; +always @(posedge clk) begin + if (rst) stall14_cycrd <= 0; + else if (cpu_next && c3) stall14_cycrd <= 0; + else if (dram_beg && (!c3 || !cpu_next) && (opfetch || memrd)) stall14_cycrd <= 1; +end - 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; +reg stall14_fin; +always @(posedge clk) begin + if (rst) stall14_fin <= 0; + else if (stall14_fin && ((opfetch && c1) || (memrd && c2))) stall14_fin <= 0; + else if (cpu_next && c3 && cpu_req && (opfetch || memrd)) stall14_fin <= 1; +end - wire [1:0] cc = turbo[0] ? {c1, c0} : {c2, c1}; // normal or overclock +// cache +// wire cache_hit = (ch_addr[7:2] != 6'b011100) && (cpu_hi_addr == cache_a) && cache_v; // debug for BM +wire cache_hit = (cpu_hi_addr == cache_a) && cache_v; // asynchronous signal meaning that address requested by CPU is cached and valid +wire cache_hit_en = cache_hit && cache_en[win]; +wire cache_inv = cache_hit && !rom_n_ram && memwr_s && ramwr_en; // cache invalidation should be only performed if write happens to cached address -// 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]; +wire [12:0] cpu_hi_addr = {page[7:0], za[13:9]}; +wire [12:0] cache_a; +wire [7:0] ch_addr = cpu_addr[7:0]; -//================================================================= -// 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 - ); +wire [15:0] cache_d; +wire cache_v; + +dpram #(.DATAWIDTH(16), .ADDRWIDTH(8)) cache_data +( + .clock(clk), + .address_a(ch_addr), + .data_a(cpu_rddata), + .wren_a(cpu_strobe), + .address_b(ch_addr), + .q_b(cache_d) +); + +dpram #(.DATAWIDTH(14), .ADDRWIDTH(8)) cache_addr +( + .clock(clk), + .address_a(ch_addr), + .data_a({!cache_inv, cpu_hi_addr}), + .wren_a(cpu_strobe || cache_inv), + .address_b(ch_addr), + .q_b({cache_v, cache_a}) +); - 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 diff --git a/src/tsconf.v b/src/tsconf.v index 3da28ec..03e20ba 100644 --- a/src/tsconf.v +++ b/src/tsconf.v @@ -142,7 +142,7 @@ wire cpu_strobe; // arbiter -> zmem wire cpu_latch; // arbiter -> zmem wire [23:0] cpu_addr; wire [20:0] cpu_addr_20; -wire csvrom; +wire csrom; wire curr_cpu; // SDRAM @@ -166,7 +166,7 @@ wire vdos; wire pre_vdos; wire vdos_off; wire vdos_on; -wire dos_change; +wire dos_on; wire m1; wire rd; wire wr; @@ -304,7 +304,7 @@ clock TS01 ); wire zclk; -wire zpos; +wire zpos, zneg; zclock TS02 ( .clk(clk_28mhz), @@ -314,8 +314,9 @@ zclock TS02 .f1(f1), .zclk_out(zclk), .zpos(zpos), + .zneg(zneg), .iorq_s(iorq_s), - .dos_on(dos_change), + .dos_on(dos_on), .vdos_off(vdos_off), .cpu_stall(cpu_stall), .ide_stall(0), @@ -460,6 +461,7 @@ zmem TS06 .c2(c2), .c3(c3), .zpos(zpos), + .zneg(zneg), .rst(reset), // PLL locked .za(cpu_a_bus), // from CPU .zd_out(sdr_do_bus), // output to Z80 bus 8bit ==> @@ -474,9 +476,9 @@ zmem TS06 .cache_en(cacheconf), // from zport .memconf(memconf[3:0]), .xt_page(xt_page), - .csvrom(csvrom), + .csrom(csrom), .dos(dos), - .dos_change(dos_change), + .dos_on(dos_on), .vdos(vdos), .pre_vdos(pre_vdos), .vdos_on(vdos_on), @@ -488,10 +490,7 @@ zmem TS06 .cpu_next(cpu_next), .cpu_strobe(cpu_strobe), // from ARBITER ACTIVE=HI .cpu_latch(cpu_latch), - .cpu_stall(cpu_stall), // for Zclock if HI-> STALL (ZCLK) - .loader(0), // ROM for loader active - .testkey(1), - .intt(0) + .cpu_stall(cpu_stall) // for Zclock if HI-> STALL (ZCLK) ); arbiter TS07 @@ -516,7 +515,7 @@ arbiter TS07 .cpu_addr(cpu_addr_20), .cpu_wrdata(cpu_do_bus), .cpu_req(cpu_req), - .cpu_rnw(rd | csvrom), + .cpu_rnw(rd | csrom), .cpu_wrbsel(cpu_wrbsel), .cpu_next(cpu_next), // next cycle is allowed to be used by CPU .cpu_strobe(cpu_strobe), // c2 strobe @@ -910,7 +909,7 @@ assign RESET_OUT = reset; // CPU interface assign cpu_di_bus = - (csvrom && ~cpu_mreq_n && ~cpu_rd_n) ? bios_do_bus : // BIOS + (csrom && ~cpu_mreq_n && ~cpu_rd_n) ? bios_do_bus : // BIOS (~cpu_mreq_n && ~cpu_rd_n) ? sdr_do_bus : // SDRAM (intack) ? im2vect : (port_bff7 && port_eff7_reg[7] && ~cpu_iorq_n && ~cpu_rd_n) ? mc146818a_do_bus : // MC146818A