mirror of
https://github.com/UzixLS/TSConf_MiST.git
synced 2025-07-19 07:11:22 +03:00
Update sys. Re-organize the sources.
This commit is contained in:
106
rtl/common/zclock.v
Normal file
106
rtl/common/zclock.v
Normal file
@ -0,0 +1,106 @@
|
||||
|
||||
// PentEvo project (c) NedoPC 2008-2011
|
||||
//
|
||||
// Z80 clocking module, also contains some wait-stating when 14MHz
|
||||
//
|
||||
// IDEAL:
|
||||
// clk _/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\
|
||||
// | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
|
||||
// zclk /```\___/```\___/```\___/```````\_______/```````\_______/```````````````\_______________/```````````````\_______________/`
|
||||
// | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
|
||||
// zpos `\___/```\___/```\___/```\___________/```\___________/```\___________________________/```\___________________________/```\
|
||||
// | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
|
||||
// zneg _/```\___/```\___/```\_______/```\___________/```\___________________/```\___________________________/```\________________
|
||||
|
||||
// clock phasing:
|
||||
// c3 must be zpos for 7mhz, therefore c1 - zneg
|
||||
// for 3.5 mhz, c3 is both zpos and zneg (alternating)
|
||||
|
||||
|
||||
// 14MHz rulez:
|
||||
// 1. do variable stalls for memory access.
|
||||
// 2. do fallback on 7mhz for external IO accesses
|
||||
// 3. clock switch 14-7-3.5 only at RFSH
|
||||
|
||||
module zclock
|
||||
(
|
||||
input clk,
|
||||
output zclk_out,
|
||||
input c0, c2, f0, f1,
|
||||
|
||||
input iorq_s,
|
||||
input external_port,
|
||||
|
||||
output reg zpos,
|
||||
output reg zneg,
|
||||
|
||||
// stall enables and triggers
|
||||
input cpu_stall,
|
||||
input ide_stall,
|
||||
input dos_on,
|
||||
input vdos_off,
|
||||
|
||||
input [1:0] turbo // 2'b00 - 3.5 MHz
|
||||
// 2'b01 - 7.0 MHz
|
||||
// 2'b1x - 14.0 MHz
|
||||
);
|
||||
|
||||
assign zclk_out = ~zclk_o;
|
||||
reg zclk_o;
|
||||
|
||||
wire [1:0] turbo_int = turbo;
|
||||
|
||||
// wait generator
|
||||
wire dos_io_stall = stall_start || !stall_count_end;
|
||||
wire stall_start = dos_stall || io_stall;
|
||||
wire dos_stall = dos_on || vdos_off;
|
||||
wire io_stall = iorq_s && external_port && turbo_int[1];
|
||||
wire stall_count_end = stall_count[3];
|
||||
|
||||
reg [3:0] stall_count;
|
||||
always @(posedge clk) begin
|
||||
if (stall_start) begin
|
||||
if (dos_stall) stall_count <= 4; // 4 tacts 28MHz (1 tact 7MHz)
|
||||
else if (io_stall) stall_count <= 0; // 8 tacts 28MHz (1 tact 3.5MHz)
|
||||
end
|
||||
else if (!stall_count_end) stall_count <= stall_count + 3'd1;
|
||||
end
|
||||
|
||||
// Z80 clocking pre-strobes
|
||||
wire pre_zpos = turbo_int[1] ? pre_zpos_140 : (turbo_int[0] ? pre_zpos_70 : pre_zpos_35);
|
||||
wire pre_zneg = turbo_int[1] ? pre_zneg_140 : (turbo_int[0] ? pre_zneg_70 : pre_zneg_35);
|
||||
|
||||
wire pre_zpos_140 = f1;
|
||||
wire pre_zneg_140 = f0;
|
||||
|
||||
wire pre_zpos_70 = c2;
|
||||
wire pre_zneg_70 = c0;
|
||||
|
||||
wire pre_zpos_35 = c2_cnt && c2;
|
||||
wire pre_zneg_35 = !c2_cnt && c2;
|
||||
|
||||
reg c2_cnt;
|
||||
always @(posedge clk) if (c2) c2_cnt <= ~c2_cnt;
|
||||
|
||||
|
||||
// Z80 clocking strobes
|
||||
wire stall = cpu_stall || dos_io_stall || ide_stall;
|
||||
|
||||
always @(posedge clk) begin
|
||||
zpos <= !stall && pre_zpos && zclk_o;
|
||||
zneg <= !stall && pre_zneg && !zclk_o;
|
||||
end
|
||||
|
||||
// make Z80 clock: account for external inversion and make some leading of clock
|
||||
// 9.5 ns propagation delay: from clk posedge to zclk returned back any edge
|
||||
// (1/28)/2=17.9ns half a clock lead
|
||||
// 2.6ns lag because of non-output register emitting of zclk_o
|
||||
// total: 5.8 ns lead of any edge of zclk relative to posedge of clk => ACCOUNT FOR THIS WHEN DOING INTER-CLOCK DATA TRANSFERS
|
||||
|
||||
// Z80 clocking
|
||||
always @(negedge clk) begin
|
||||
if (zpos) zclk_o <= 0;
|
||||
if (zneg) zclk_o <= 1;
|
||||
end
|
||||
|
||||
endmodule
|
71
rtl/common/zint.v
Normal file
71
rtl/common/zint.v
Normal file
@ -0,0 +1,71 @@
|
||||
|
||||
module zint
|
||||
(
|
||||
input wire clk,
|
||||
input wire zpos,
|
||||
input wire res,
|
||||
input wire int_start_frm,
|
||||
input wire int_start_lin,
|
||||
input wire int_start_dma,
|
||||
input wire vdos,
|
||||
input wire intack,
|
||||
input wire [7:0] intmask,
|
||||
output reg [7:0] im2vect,
|
||||
output wire int_n
|
||||
);
|
||||
|
||||
// In VDOS INTs are focibly disabled.
|
||||
// For Frame, Line INT its generation is blocked, it will be lost.
|
||||
// For DMA INT only its output is blocked, so DMA ISR will will be processed as soon as returned from VDOS.
|
||||
|
||||
assign int_n = ~(int_frm || int_lin || int_dma) | vdos;
|
||||
|
||||
wire dis_int_frm = !intmask[0];
|
||||
wire dis_int_lin = !intmask[1];
|
||||
wire dis_int_dma = !intmask[2];
|
||||
|
||||
wire intack_s = intack && !intack_r;
|
||||
reg intack_r;
|
||||
always @(posedge clk) intack_r <= intack;
|
||||
|
||||
reg [1:0] int_sel;
|
||||
always @(posedge clk) begin
|
||||
if (intack_s) begin
|
||||
if (int_frm) im2vect <= 8'hFF; // priority 0
|
||||
else if (int_lin) im2vect <= 8'hFD; // priority 1
|
||||
else if (int_dma) im2vect <= 8'hFB; // priority 2
|
||||
end
|
||||
end
|
||||
|
||||
// ~INT generating
|
||||
reg int_frm;
|
||||
always @(posedge clk) begin
|
||||
if (res || dis_int_frm) int_frm <= 0;
|
||||
else if (int_start_frm) int_frm <= 1;
|
||||
else if (intack_s || intctr_fin) int_frm <= 0; // priority 0
|
||||
end
|
||||
|
||||
reg int_lin;
|
||||
always @(posedge clk) begin
|
||||
if (res || dis_int_lin) int_lin <= 0;
|
||||
else if (int_start_lin) int_lin <= 1;
|
||||
else if (intack_s && !int_frm) int_lin <= 0; // priority 1
|
||||
end
|
||||
|
||||
reg int_dma;
|
||||
always @(posedge clk) begin
|
||||
if (res || dis_int_dma) int_dma <= 0;
|
||||
else if (int_start_dma) int_dma <= 1;
|
||||
else if (intack_s && !int_frm && !int_lin) int_dma <= 0; // priority 2
|
||||
end
|
||||
|
||||
// ~INT counter
|
||||
reg [5:0] intctr;
|
||||
wire intctr_fin = intctr[5]; // 32 clks
|
||||
|
||||
always @(posedge clk, posedge int_start_frm) begin
|
||||
if (int_start_frm) intctr <= 0;
|
||||
else if (zpos && !intctr_fin && !vdos) intctr <= intctr + 1'b1;
|
||||
end
|
||||
|
||||
endmodule
|
56
rtl/common/zmaps.v
Normal file
56
rtl/common/zmaps.v
Normal file
@ -0,0 +1,56 @@
|
||||
|
||||
// This module maps z80 memory accesses into FPGA RAM and ports
|
||||
|
||||
module zmaps
|
||||
(
|
||||
// Z80 controls
|
||||
input wire clk,
|
||||
input wire memwr_s,
|
||||
input wire [15:0] a,
|
||||
input wire [7:0] d,
|
||||
|
||||
// config data
|
||||
input wire [4:0] fmaddr,
|
||||
|
||||
// FPRAM data
|
||||
output wire [15:0] zmd,
|
||||
output wire [7:0] zma,
|
||||
|
||||
// DMA
|
||||
input wire [15:0] dma_data,
|
||||
input wire [7:0] dma_wraddr,
|
||||
input wire dma_cram_we,
|
||||
input wire dma_sfile_we,
|
||||
|
||||
// write strobes
|
||||
output wire cram_we,
|
||||
output wire sfile_we,
|
||||
output wire regs_we
|
||||
);
|
||||
|
||||
|
||||
// addresses of files withing zmaps
|
||||
localparam CRAM = 3'b000;
|
||||
localparam SFYS = 3'b001;
|
||||
localparam REGS = 4'b0100;
|
||||
|
||||
|
||||
// control signals
|
||||
wire hit = (a[15:12] == fmaddr[3:0]) && fmaddr[4] && memwr_s;
|
||||
|
||||
// write enables
|
||||
assign cram_we = dma_req ? dma_cram_we : (a[11:9] == CRAM) && a[0] && hit;
|
||||
assign sfile_we = dma_req ? dma_sfile_we : (a[11:9] == SFYS) && a[0] && hit;
|
||||
assign regs_we = (a[11:8] == REGS) && hit;
|
||||
|
||||
// LSB fetching
|
||||
assign zma = dma_req ? dma_wraddr : a[8:1];
|
||||
assign zmd = dma_req ? dma_data : {d, zmd0};
|
||||
|
||||
reg [7:0] zmd0;
|
||||
always @(posedge clk) if (!a[0] && hit) zmd0 <= d;
|
||||
|
||||
// DMA
|
||||
wire dma_req = dma_cram_we || dma_sfile_we;
|
||||
|
||||
endmodule
|
228
rtl/common/zmem.v
Normal file
228
rtl/common/zmem.v
Normal file
@ -0,0 +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 clk,
|
||||
input c0, c1, c2, c3,
|
||||
input zneg, // strobes which show positive and negative edges of zclk
|
||||
input zpos,
|
||||
|
||||
// Z80
|
||||
input rst,
|
||||
input [15:0] za,
|
||||
output [ 7:0] zd_out, // output to Z80 bus
|
||||
output zd_ena, // output to Z80 bus enable
|
||||
|
||||
input opfetch,
|
||||
input opfetch_s,
|
||||
input mreq,
|
||||
input memrd,
|
||||
input memwr,
|
||||
input memwr_s,
|
||||
|
||||
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 [4:0] rompg,
|
||||
output csrom,
|
||||
output romoe_n,
|
||||
output romwe_n,
|
||||
|
||||
output dos,
|
||||
output dos_on,
|
||||
output dos_off,
|
||||
output vdos,
|
||||
output reg pre_vdos,
|
||||
input vdos_on,
|
||||
input vdos_off,
|
||||
|
||||
// DRAM
|
||||
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
|
||||
);
|
||||
|
||||
// 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;
|
||||
wire ramwr_en = !win0 || w0_we || vdos;
|
||||
wire rom_n_ram = win0 && !w0_ram && !vdos;
|
||||
wire [7:0] page = xtpage[win];
|
||||
|
||||
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) && 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
|
||||
|
||||
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
|
||||
|
||||
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;
|
||||
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 cpu_req = turbo14 ? cpureq_14 : cpureq_357;
|
||||
assign cpu_stall = turbo14 ? stall14 : stall357;
|
||||
wire turbo14 = turbo[1];
|
||||
|
||||
// 7/3.5MHz support
|
||||
wire cpureq_357 = ramreq && !ramreq_r;
|
||||
wire stall357 = cpureq_357 && !cpu_next;
|
||||
|
||||
reg ramreq_r;
|
||||
always @(posedge clk) if (c3 && !cpu_stall) ramreq_r <= ramreq;
|
||||
|
||||
// 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;
|
||||
|
||||
wire dram_beg = ramreq && !pre_ramreq_r && zneg;
|
||||
|
||||
reg pre_ramreq_r;
|
||||
always @(posedge clk) if (zneg) pre_ramreq_r <= ramreq;
|
||||
|
||||
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) 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) 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
|
||||
|
||||
// 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
|
||||
|
||||
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];
|
||||
|
||||
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})
|
||||
);
|
||||
|
||||
endmodule
|
469
rtl/common/zports.v
Normal file
469
rtl/common/zports.v
Normal file
@ -0,0 +1,469 @@
|
||||
|
||||
// PentEvo project (c) NedoPC 2008-2010
|
||||
|
||||
module zports
|
||||
(
|
||||
input clk,
|
||||
|
||||
input [7:0] din,
|
||||
output reg [7:0] dout,
|
||||
output dataout,
|
||||
input [15:0] a,
|
||||
|
||||
input rst, // system reset
|
||||
input opfetch,
|
||||
|
||||
input rd,
|
||||
input wr,
|
||||
input rdwr,
|
||||
|
||||
input iorq,
|
||||
input iorq_s,
|
||||
input iord,
|
||||
input iord_s,
|
||||
input iowr,
|
||||
input iowr_s,
|
||||
input iordwr,
|
||||
input iordwr_s,
|
||||
|
||||
output porthit, // when internal port hit occurs, this is 1, else 0; used for iorq1_n iorq2_n on zxbus
|
||||
output external_port, // asserts for AY and VG93 accesses
|
||||
|
||||
output zborder_wr,
|
||||
output border_wr,
|
||||
output zvpage_wr,
|
||||
output vpage_wr,
|
||||
output vconf_wr,
|
||||
output gx_offsl_wr,
|
||||
output gx_offsh_wr,
|
||||
output gy_offsl_wr,
|
||||
output gy_offsh_wr,
|
||||
output t0x_offsl_wr,
|
||||
output t0x_offsh_wr,
|
||||
output t0y_offsl_wr,
|
||||
output t0y_offsh_wr,
|
||||
output t1x_offsl_wr,
|
||||
output t1x_offsh_wr,
|
||||
output t1y_offsl_wr,
|
||||
output t1y_offsh_wr,
|
||||
output tsconf_wr,
|
||||
output palsel_wr,
|
||||
output tmpage_wr,
|
||||
output t0gpage_wr,
|
||||
output t1gpage_wr,
|
||||
output sgpage_wr,
|
||||
output hint_beg_wr ,
|
||||
output vint_begl_wr,
|
||||
output vint_begh_wr,
|
||||
|
||||
output [31:0] xt_page,
|
||||
|
||||
output reg [4:0] fmaddr,
|
||||
input regs_we,
|
||||
|
||||
output reg [7:0] sysconf,
|
||||
output reg [7:0] memconf,
|
||||
output reg [3:0] cacheconf,
|
||||
output reg [7:0] fddvirt,
|
||||
|
||||
output [8:0] dmaport_wr,
|
||||
input dma_act,
|
||||
output reg [1:0] dmawpdev,
|
||||
|
||||
|
||||
output reg [7:0] intmask,
|
||||
|
||||
input dos,
|
||||
input vdos,
|
||||
output vdos_on,
|
||||
output vdos_off,
|
||||
|
||||
output ay_bdir,
|
||||
output ay_bc1,
|
||||
output covox_wr,
|
||||
output beeper_wr,
|
||||
|
||||
input tape_read,
|
||||
|
||||
input [4:0] keys_in, // keys (port FE)
|
||||
input [7:0] mus_in, // mouse (xxDF)
|
||||
input [5:0] kj_in,
|
||||
|
||||
input vg_intrq,
|
||||
input vg_drq, // from vg93 module - drq + irq read
|
||||
output vg_cs_n,
|
||||
output vg_wrFF,
|
||||
output [1:0] drive_sel, // disk drive selection
|
||||
|
||||
// SPI
|
||||
output sdcs_n,
|
||||
output sd_start,
|
||||
output [7:0] sd_datain,
|
||||
input [7:0] sd_dataout,
|
||||
|
||||
// WAIT-ports related
|
||||
output reg [7:0] wait_addr,
|
||||
output wait_start_gluclock, // begin wait from some ports
|
||||
output wait_start_comport, //
|
||||
output reg [7:0] wait_write,
|
||||
input [7:0] wait_read
|
||||
);
|
||||
|
||||
assign sdcs_n = spi_cs_n[0];
|
||||
|
||||
localparam FDR_VER = 1'b0;
|
||||
|
||||
localparam VDAC_VER = 3'h3;
|
||||
|
||||
localparam PORTFE = 8'hFE;
|
||||
localparam PORTFD = 8'hFD;
|
||||
localparam PORTXT = 8'hAF;
|
||||
localparam PORTF7 = 8'hF7;
|
||||
localparam COVOX = 8'hFB;
|
||||
|
||||
localparam VGCOM = 8'h1F;
|
||||
localparam VGTRK = 8'h3F;
|
||||
localparam VGSEC = 8'h5F;
|
||||
localparam VGDAT = 8'h7F;
|
||||
localparam VGSYS = 8'hFF;
|
||||
|
||||
localparam KJOY = 8'h1F;
|
||||
localparam KMOUSE = 8'hDF;
|
||||
|
||||
localparam SDCFG = 8'h77;
|
||||
localparam SDDAT = 8'h57;
|
||||
|
||||
localparam COMPORT = 8'hEF; // F8EF..FFEF - rs232 ports
|
||||
|
||||
|
||||
wire [7:0] loa = a[7:0];
|
||||
wire [7:0] hoa = regs_we ? a[7:0] : a[15:8];
|
||||
|
||||
assign porthit = ((loa==PORTFE) || (loa==PORTXT) || (loa==PORTFD) || (loa==COVOX))
|
||||
|| ((loa==PORTF7) && !dos)
|
||||
|| ((vg_port || vgsys_port) && (dos || open_vg))
|
||||
|| ((loa==KJOY) && !dos && !open_vg)
|
||||
|| (loa==KMOUSE)
|
||||
|| (((loa==SDCFG) || (loa==SDDAT)) && (!dos || vdos))
|
||||
|| (loa==COMPORT);
|
||||
|
||||
wire vg_port = (loa==VGCOM) || (loa==VGTRK) || (loa==VGSEC) || (loa==VGDAT);
|
||||
wire vgsys_port = (loa==VGSYS);
|
||||
|
||||
assign external_port = ((loa==PORTFD) && a[15]) // AY
|
||||
|| (((loa==VGCOM) || (loa==VGTRK) || (loa==VGSEC) || (loa==VGDAT)) && (dos || open_vg));
|
||||
|
||||
assign dataout = porthit && iord && (~external_port);
|
||||
|
||||
|
||||
reg iowr_reg;
|
||||
reg iord_reg;
|
||||
reg port_wr;
|
||||
reg port_rd;
|
||||
|
||||
always @(posedge clk) begin
|
||||
iowr_reg <= iowr;
|
||||
port_wr <= (!iowr_reg && iowr);
|
||||
|
||||
iord_reg <= iord;
|
||||
port_rd <= (!iord_reg && iord);
|
||||
end
|
||||
|
||||
|
||||
// reading ports
|
||||
always @(*) begin
|
||||
case (loa)
|
||||
PORTFE:
|
||||
dout = {1'b1, tape_read, 1'b0, keys_in};
|
||||
|
||||
PORTXT:
|
||||
begin
|
||||
case (hoa)
|
||||
XSTAT:
|
||||
dout = {1'b0, pwr_up_reg, FDR_VER, 2'b0, VDAC_VER};
|
||||
|
||||
DMASTAT:
|
||||
dout = {dma_act, 7'b0};
|
||||
|
||||
RAMPAGE + 8'd2, RAMPAGE + 8'd3:
|
||||
dout = rampage[hoa[1:0]];
|
||||
|
||||
default:
|
||||
dout = 8'hFF;
|
||||
|
||||
endcase
|
||||
end
|
||||
|
||||
VGSYS:
|
||||
dout = {vg_intrq, vg_drq, 6'b111111};
|
||||
|
||||
KJOY:
|
||||
dout = {2'b00, kj_in};
|
||||
KMOUSE:
|
||||
dout = mus_in;
|
||||
|
||||
SDCFG:
|
||||
dout = 8'h00; // always SD inserted, SD is in R/W mode
|
||||
SDDAT:
|
||||
dout = sd_dataout;
|
||||
|
||||
PORTF7:
|
||||
begin
|
||||
if (!a[14] && (a[8] ^ dos) && gluclock_on) dout = wait_read; // $BFF7 - data i/o
|
||||
else dout = 8'hFF; // any other $xxF7 port
|
||||
end
|
||||
|
||||
COMPORT:
|
||||
dout = wait_read; // $F8EF..$FFEF
|
||||
|
||||
default:
|
||||
dout = 8'hFF;
|
||||
endcase
|
||||
end
|
||||
|
||||
|
||||
// power-up
|
||||
// This bit is loaded as 1 while FPGA is configured
|
||||
// and automatically reset to 0 after STATUS port reading
|
||||
reg pwr_up_reg;
|
||||
reg pwr_up = 1;
|
||||
always @(posedge clk) begin
|
||||
if (iord_s & (loa == PORTXT) & (hoa == XSTAT)) begin
|
||||
pwr_up_reg <= pwr_up;
|
||||
pwr_up <= 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
// writing ports
|
||||
|
||||
//#nnAF
|
||||
localparam VCONF = 8'h00;
|
||||
localparam VPAGE = 8'h01;
|
||||
localparam GXOFFSL = 8'h02;
|
||||
localparam GXOFFSH = 8'h03;
|
||||
localparam GYOFFSL = 8'h04;
|
||||
localparam GYOFFSH = 8'h05;
|
||||
localparam TSCONF = 8'h06;
|
||||
localparam PALSEL = 8'h07;
|
||||
localparam XBORDER = 8'h0F;
|
||||
|
||||
localparam T0XOFFSL = 8'h40;
|
||||
localparam T0XOFFSH = 8'h41;
|
||||
localparam T0YOFFSL = 8'h42;
|
||||
localparam T0YOFFSH = 8'h43;
|
||||
localparam T1XOFFSL = 8'h44;
|
||||
localparam T1XOFFSH = 8'h45;
|
||||
localparam T1YOFFSL = 8'h46;
|
||||
localparam T1YOFFSH = 8'h47;
|
||||
|
||||
localparam RAMPAGE = 8'h10; // this covers #10-#13
|
||||
localparam FMADDR = 8'h15;
|
||||
localparam TMPAGE = 8'h16;
|
||||
localparam T0GPAGE = 8'h17;
|
||||
localparam T1GPAGE = 8'h18;
|
||||
localparam SGPAGE = 8'h19;
|
||||
localparam DMASADDRL = 8'h1A;
|
||||
localparam DMASADDRH = 8'h1B;
|
||||
localparam DMASADDRX = 8'h1C;
|
||||
localparam DMADADDRL = 8'h1D;
|
||||
localparam DMADADDRH = 8'h1E;
|
||||
localparam DMADADDRX = 8'h1F;
|
||||
|
||||
localparam SYSCONF = 8'h20;
|
||||
localparam MEMCONF = 8'h21;
|
||||
localparam HSINT = 8'h22;
|
||||
localparam VSINTL = 8'h23;
|
||||
localparam VSINTH = 8'h24;
|
||||
localparam DMAWPD = 8'h25;
|
||||
localparam DMALEN = 8'h26;
|
||||
localparam DMACTRL = 8'h27;
|
||||
localparam DMANUM = 8'h28;
|
||||
localparam FDDVIRT = 8'h29;
|
||||
localparam INTMASK = 8'h2A;
|
||||
localparam CACHECONF = 8'h2B;
|
||||
localparam DMAWPA = 8'h2D;
|
||||
|
||||
localparam XSTAT = 8'h00;
|
||||
localparam DMASTAT = 8'h27;
|
||||
|
||||
assign dmaport_wr[0] = portxt_wr && (hoa == DMASADDRL);
|
||||
assign dmaport_wr[1] = portxt_wr && (hoa == DMASADDRH);
|
||||
assign dmaport_wr[2] = portxt_wr && (hoa == DMASADDRX);
|
||||
assign dmaport_wr[3] = portxt_wr && (hoa == DMADADDRL);
|
||||
assign dmaport_wr[4] = portxt_wr && (hoa == DMADADDRH);
|
||||
assign dmaport_wr[5] = portxt_wr && (hoa == DMADADDRX);
|
||||
assign dmaport_wr[6] = portxt_wr && (hoa == DMALEN);
|
||||
assign dmaport_wr[7] = portxt_wr && (hoa == DMACTRL);
|
||||
assign dmaport_wr[8] = portxt_wr && (hoa == DMANUM);
|
||||
|
||||
assign zborder_wr = portfe_wr;
|
||||
assign border_wr = (portxt_wr && (hoa == XBORDER));
|
||||
assign zvpage_wr = p7ffd_wr;
|
||||
assign vpage_wr = (portxt_wr && (hoa == VPAGE ));
|
||||
assign vconf_wr = (portxt_wr && (hoa == VCONF ));
|
||||
assign gx_offsl_wr = (portxt_wr && (hoa == GXOFFSL));
|
||||
assign gx_offsh_wr = (portxt_wr && (hoa == GXOFFSH));
|
||||
assign gy_offsl_wr = (portxt_wr && (hoa == GYOFFSL));
|
||||
assign gy_offsh_wr = (portxt_wr && (hoa == GYOFFSH));
|
||||
assign t0x_offsl_wr = (portxt_wr && (hoa == T0XOFFSL));
|
||||
assign t0x_offsh_wr = (portxt_wr && (hoa == T0XOFFSH));
|
||||
assign t0y_offsl_wr = (portxt_wr && (hoa == T0YOFFSL));
|
||||
assign t0y_offsh_wr = (portxt_wr && (hoa == T0YOFFSH));
|
||||
assign t1x_offsl_wr = (portxt_wr && (hoa == T1XOFFSL));
|
||||
assign t1x_offsh_wr = (portxt_wr && (hoa == T1XOFFSH));
|
||||
assign t1y_offsl_wr = (portxt_wr && (hoa == T1YOFFSL));
|
||||
assign t1y_offsh_wr = (portxt_wr && (hoa == T1YOFFSH));
|
||||
assign tsconf_wr = (portxt_wr && (hoa == TSCONF));
|
||||
assign palsel_wr = (portxt_wr && (hoa == PALSEL));
|
||||
assign tmpage_wr = (portxt_wr && (hoa == TMPAGE));
|
||||
assign t0gpage_wr = (portxt_wr && (hoa == T0GPAGE));
|
||||
assign t1gpage_wr = (portxt_wr && (hoa == T1GPAGE));
|
||||
assign sgpage_wr = (portxt_wr && (hoa == SGPAGE));
|
||||
assign hint_beg_wr = (portxt_wr && (hoa == HSINT ));
|
||||
assign vint_begl_wr = (portxt_wr && (hoa == VSINTL));
|
||||
assign vint_begh_wr = (portxt_wr && (hoa == VSINTH));
|
||||
|
||||
assign beeper_wr = portfe_wr;
|
||||
wire portfe_wr = (loa==PORTFE) && iowr_s;
|
||||
assign covox_wr = (loa==COVOX) && iowr_s;
|
||||
wire portxt_wr = ((loa==PORTXT) && iowr_s) || regs_we;
|
||||
|
||||
reg [7:0] rampage[0:3];
|
||||
assign xt_page = {rampage[3], rampage[2], rampage[1], rampage[0]};
|
||||
|
||||
wire lock128 = lock128_3 ? 1'b0 : (lock128_2 ? m1_lock128 : memconf[6]);
|
||||
wire lock128_2 = memconf[7:6] == 2'b10; // mode 2
|
||||
wire lock128_3 = memconf[7:6] == 2'b11; // mode 3
|
||||
|
||||
reg m1_lock128;
|
||||
always @(posedge clk) if (opfetch) m1_lock128 <= !(din[7] ^ din[6]);
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (rst) begin
|
||||
fmaddr[4] <= 1'b0;
|
||||
intmask <= 8'b1;
|
||||
fddvirt <= 8'b0;
|
||||
sysconf <= 8'h00; // 3.5 MHz
|
||||
memconf <= 8'h04; // no map
|
||||
cacheconf <= 4'h0; // no cache
|
||||
|
||||
rampage[0]<= 8'h00;
|
||||
rampage[1]<= 8'h05;
|
||||
rampage[2]<= 8'h02;
|
||||
rampage[3]<= 8'h00;
|
||||
end
|
||||
else if (p7ffd_wr) begin
|
||||
memconf[0] <= din[4];
|
||||
rampage[3] <= {2'b0, lock128_3 ? {din[5], din[7:6]} : ({1'b0, lock128 ? 2'b0 : din[7:6]}), din[2:0]};
|
||||
end
|
||||
else if (portxt_wr) begin
|
||||
if (hoa[7:2] == RAMPAGE[7:2]) rampage[hoa[1:0]] <= din;
|
||||
|
||||
if (hoa == FMADDR) fmaddr <= din[4:0];
|
||||
|
||||
if (hoa == SYSCONF) begin
|
||||
sysconf <= din;
|
||||
cacheconf <= {4{din[2]}};
|
||||
end
|
||||
|
||||
if (hoa == DMAWPD) dmawpdev <= din[1:0];
|
||||
if (hoa == CACHECONF) cacheconf <= din[3:0];
|
||||
if (hoa == MEMCONF) memconf <= din;
|
||||
if (hoa == FDDVIRT) fddvirt <= din;
|
||||
if (hoa == INTMASK) intmask <= din;
|
||||
end
|
||||
end
|
||||
|
||||
// 7FFD port
|
||||
wire p7ffd_wr = !a[15] && (loa==PORTFD) && iowr_s && !lock48;
|
||||
|
||||
reg lock48;
|
||||
always @(posedge clk) begin
|
||||
if (rst) lock48 <= 1'b0;
|
||||
else if (p7ffd_wr && !lock128_3) lock48 <= din[5];
|
||||
end
|
||||
|
||||
// AY control
|
||||
wire ay_hit = (loa==PORTFD) & a[15];
|
||||
assign ay_bc1 = ay_hit & a[14] & iordwr;
|
||||
assign ay_bdir = ay_hit & iowr;
|
||||
|
||||
// VG93
|
||||
wire [3:0] fddvrt = fddvirt[3:0];
|
||||
wire virt_vg = fddvrt[drive_sel_raw];
|
||||
wire open_vg = fddvirt[7];
|
||||
assign drive_sel = {drive_sel_raw[1], drive_sel_raw[0]};
|
||||
|
||||
wire vg_wen = (dos || open_vg) && !vdos && !virt_vg;
|
||||
assign vg_cs_n = !(iordwr && vg_port && vg_wen);
|
||||
assign vg_wrFF = iowr_s && vgsys_port && vg_wen;
|
||||
wire vg_wrDS = iowr_s && vgsys_port && (dos || open_vg);
|
||||
|
||||
assign vdos_on = iordwr_s && (vg_port || vgsys_port) && dos && !vdos && virt_vg;
|
||||
assign vdos_off = iordwr_s && vg_port && vdos;
|
||||
|
||||
// write drive number
|
||||
reg [1:0] drive_sel_raw;
|
||||
always @(posedge clk) if (vg_wrDS) drive_sel_raw <= din[1:0];
|
||||
|
||||
// SD card (Z-controller compatible)
|
||||
wire sdcfg_wr;
|
||||
wire sddat_wr;
|
||||
wire sddat_rd;
|
||||
reg [1:0] spi_cs_n;
|
||||
|
||||
assign sdcfg_wr = ((loa==SDCFG) && iowr_s && (!dos || vdos));
|
||||
assign sddat_wr = ((loa==SDDAT) && iowr_s && (!dos || vdos));
|
||||
assign sddat_rd = ((loa==SDDAT) && iord_s);
|
||||
|
||||
// SDCFG write - sdcs_n control
|
||||
always @(posedge clk) begin
|
||||
if (rst) spi_cs_n <= 2'b11;
|
||||
else if (sdcfg_wr) spi_cs_n <= {~din[2], din[1]};
|
||||
end
|
||||
|
||||
// start signal for SPI module with resyncing to fclk
|
||||
assign sd_start = sddat_wr || sddat_rd;
|
||||
|
||||
// data for SPI module
|
||||
assign sd_datain = wr ? din : 8'hFF;
|
||||
|
||||
// xxF7
|
||||
wire portf7_wr = ((loa==PORTF7) && (a[8]==1'b1) && port_wr && (!dos || vdos));
|
||||
wire portf7_rd = ((loa==PORTF7) && (a[8]==1'b1) && port_rd && (!dos || vdos));
|
||||
|
||||
// EFF7 port
|
||||
reg [7:0] peff7;
|
||||
always @(posedge clk) begin
|
||||
if (rst) peff7 <= 8'h00;
|
||||
else if (!a[12] && portf7_wr && !dos) peff7 <= din; // #EEF7 in dos is not accessible
|
||||
end
|
||||
|
||||
// gluclock ports
|
||||
wire gluclock_on = peff7[7] || dos; // in dos mode EEF7 is not accessible, gluclock access is ON in dos mode.
|
||||
|
||||
// comports
|
||||
wire comport_wr = ((loa == COMPORT) && port_wr);
|
||||
wire comport_rd = ((loa == COMPORT) && port_rd);
|
||||
|
||||
// write to wait registers
|
||||
always @(posedge clk) begin
|
||||
// gluclocks
|
||||
if (gluclock_on && portf7_wr) begin
|
||||
if (!a[14]) wait_write <= din; // $BFF7 - data reg
|
||||
if (!a[13]) wait_addr <= din; // $DFF7 - addr reg
|
||||
end
|
||||
|
||||
// com ports
|
||||
if (comport_wr) wait_write <= din; // $xxEF
|
||||
if (comport_wr || comport_rd) wait_addr <= a[15:8];
|
||||
|
||||
if ((loa==PORTXT) && (hoa == DMAWPA)) wait_addr <= din;
|
||||
end
|
||||
|
||||
// wait from wait registers
|
||||
// ACHTUNG!!!! here portxx_wr are ON Z80 CLOCK! logic must change when moving to clk strobes
|
||||
assign wait_start_gluclock = (gluclock_on && !a[14] && (portf7_rd || portf7_wr)); // $BFF7 - gluclock r/w
|
||||
assign wait_start_comport = (comport_rd || comport_wr);
|
||||
|
||||
endmodule
|
85
rtl/common/zsignals.v
Normal file
85
rtl/common/zsignals.v
Normal file
@ -0,0 +1,85 @@
|
||||
|
||||
// Decoding and strobing of z80 signals
|
||||
|
||||
module zsignals
|
||||
(
|
||||
// clocks
|
||||
input wire clk,
|
||||
|
||||
// z80 interface input
|
||||
input wire iorq_n,
|
||||
input wire mreq_n,
|
||||
input wire m1_n,
|
||||
input wire rfsh_n,
|
||||
input wire rd_n,
|
||||
input wire wr_n,
|
||||
|
||||
// Z80 signals
|
||||
output wire m1,
|
||||
output wire rfsh,
|
||||
output wire rd,
|
||||
output wire wr,
|
||||
output wire iorq,
|
||||
output wire mreq,
|
||||
output wire rdwr,
|
||||
output wire iord,
|
||||
output wire iowr,
|
||||
output wire iorw,
|
||||
output wire memrd,
|
||||
output wire memwr,
|
||||
output wire memrw,
|
||||
output wire opfetch,
|
||||
output wire intack,
|
||||
|
||||
// Z80 signals strobes, at fclk
|
||||
output wire iorq_s,
|
||||
output wire mreq_s,
|
||||
output wire iord_s,
|
||||
output wire iowr_s,
|
||||
output wire iorw_s,
|
||||
output wire memrd_s,
|
||||
output wire memwr_s,
|
||||
output wire memrw_s,
|
||||
output wire opfetch_s
|
||||
);
|
||||
|
||||
// invertors
|
||||
assign m1 = !m1_n;
|
||||
assign rfsh = !rfsh_n;
|
||||
assign rd = !rd_n;
|
||||
assign wr = !wr_n;
|
||||
|
||||
// requests
|
||||
assign iorq = !iorq_n && m1_n; // this is masked by ~M1 to avoid port decoding on INT ack
|
||||
assign mreq = !mreq_n && rfsh_n; // this is masked by ~RFSH to ignore refresh cycles as memory requests
|
||||
|
||||
// combined
|
||||
assign rdwr = rd || wr;
|
||||
assign iord = iorq && rd;
|
||||
assign iowr = iorq && wr;
|
||||
assign iorw = iorq && rdwr;
|
||||
assign memrd = mreq && rd;
|
||||
assign memwr = mreq && !rd;
|
||||
assign memrw = mreq && rdwr;
|
||||
assign opfetch = memrd && m1;
|
||||
assign intack = !iorq_n && m1; // NOT masked by M1
|
||||
|
||||
// strobed
|
||||
assign iorq_s = iorq_r[0] && !iorq_r[1];
|
||||
assign mreq_s = mreq_r[0] && !mreq_r[1];
|
||||
assign iord_s = iorq_s && rd;
|
||||
assign iowr_s = iorq_s && wr;
|
||||
assign iorw_s = iorq_s && rdwr;
|
||||
assign memrd_s = mreq_s && rd;
|
||||
assign memwr_s = mreq_s && !rd;
|
||||
assign memrw_s = mreq_s && rdwr;
|
||||
assign opfetch_s = memrd_s && m1;
|
||||
|
||||
// latch inputs on FPGA clock
|
||||
reg [1:0] iorq_r, mreq_r;
|
||||
always @(posedge clk) begin
|
||||
iorq_r <= {iorq_r[0], iorq};
|
||||
mreq_r <= {mreq_r[0], mreq};
|
||||
end
|
||||
|
||||
endmodule
|
Reference in New Issue
Block a user