mirror of
https://github.com/UzixLS/TSConf_MiST.git
synced 2025-07-18 23:01:37 +03:00
update tsconf to commit 83afbba6f5d366f96297028aa3d64512fa254a51
This commit is contained in:
61
rtl/common/clock.v
Normal file
61
rtl/common/clock.v
Normal file
@ -0,0 +1,61 @@
|
||||
|
||||
// This module receives 28 MHz as input clock
|
||||
// and makes strobes for all clocked parts
|
||||
|
||||
// clk |<EFBFBD>__<EFBFBD><EFBFBD>__<EFBFBD><EFBFBD>__<EFBFBD><EFBFBD>__<EFBFBD>| period = 28 duty = 50% phase = 0
|
||||
// cnt |< 0>< 1>< 2>< 3>|
|
||||
// f0 |<EFBFBD><EFBFBD><EFBFBD><EFBFBD>____<EFBFBD><EFBFBD><EFBFBD><EFBFBD>____| period = 14 duty = 50% phase = 0
|
||||
// f1 |____<EFBFBD><EFBFBD><EFBFBD><EFBFBD>____<EFBFBD><EFBFBD><EFBFBD><EFBFBD>| period = 14 duty = 50% phase = 180
|
||||
// h0 |<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>________| period = 7 duty = 50% phase = 0
|
||||
// h1 |________<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>| period = 7 duty = 50% phase = 180
|
||||
// c0 |<EFBFBD><EFBFBD><EFBFBD><EFBFBD>____________| period = 7 duty = 25% phase = 0
|
||||
// c1 |____<EFBFBD><EFBFBD><EFBFBD><EFBFBD>________| period = 7 duty = 25% phase = 90
|
||||
// c2 |________<EFBFBD><EFBFBD><EFBFBD><EFBFBD>____| period = 7 duty = 25% phase = 180
|
||||
// c3 |____________<EFBFBD><EFBFBD><EFBFBD><EFBFBD>| period = 7 duty = 25% phase = 270
|
||||
|
||||
`include "tune.v"
|
||||
|
||||
module clock
|
||||
(
|
||||
input wire clk,
|
||||
input wire [1:0] ay_mod,
|
||||
|
||||
output wire f0, f1,
|
||||
output wire h0, h1,
|
||||
output wire c0, c1, c2, c3,
|
||||
output wire ay_clk
|
||||
);
|
||||
|
||||
reg [1:0] f = 'b01;
|
||||
reg [1:0] h = 'b01;
|
||||
reg [3:0] c = 'b0001;
|
||||
|
||||
always @(posedge clk)
|
||||
begin
|
||||
f <= ~f;
|
||||
if (f[1]) h <= ~h;
|
||||
c <= {c[2:0], c[3]};
|
||||
end
|
||||
|
||||
assign f0 = f[0];
|
||||
assign f1 = f[1];
|
||||
assign h0 = h[0];
|
||||
assign h1 = h[1];
|
||||
assign c0 = c[0];
|
||||
assign c1 = c[1];
|
||||
assign c2 = c[2];
|
||||
assign c3 = c[3];
|
||||
|
||||
// AY clock generator
|
||||
// ay_mod - clock selection for AY, MHz: 00 - 1.75 / 01 - 1.7733 / 10 - 3.5 / 11 - 3.546
|
||||
reg [7:0] skip_cnt = 0;
|
||||
reg [3:0] ay_cnt = 0;
|
||||
assign ay_clk = ay_mod[1] ? ay_cnt[2] : ay_cnt[3];
|
||||
|
||||
always @(posedge clk)
|
||||
begin
|
||||
skip_cnt <= skip_cnt[7] ? 8'd73 : skip_cnt - 8'd1;
|
||||
ay_cnt <= ay_cnt + (skip_cnt[7] & ay_mod[0] ? 4'd2 : 4'd1);
|
||||
end
|
||||
|
||||
endmodule
|
429
rtl/common/dma.v
Normal file
429
rtl/common/dma.v
Normal file
@ -0,0 +1,429 @@
|
||||
// This module serves direct DRAM-to-device data transfer
|
||||
|
||||
`include "tune.v"
|
||||
|
||||
module dma
|
||||
(
|
||||
// clocks
|
||||
input wire clk,
|
||||
input wire c2,
|
||||
input wire rst_n,
|
||||
|
||||
// interface
|
||||
`ifdef FDR
|
||||
input wire [9:0] dmaport_wr,
|
||||
`else
|
||||
input wire [8:0] dmaport_wr,
|
||||
`endif
|
||||
output wire dma_act,
|
||||
output reg [15:0] data = 0,
|
||||
output wire [ 7:0] wraddr,
|
||||
output wire int_start,
|
||||
|
||||
// Z80
|
||||
input wire [7:0] zdata,
|
||||
|
||||
// DRAM interface
|
||||
output wire [20:0] dram_addr,
|
||||
input wire [15:0] dram_rddata,
|
||||
output wire [15:0] dram_wrdata,
|
||||
output wire dram_req,
|
||||
output wire dram_rnw,
|
||||
input wire dram_next,
|
||||
|
||||
// SPI interface
|
||||
input wire [7:0] spi_rddata,
|
||||
output wire [7:0] spi_wrdata,
|
||||
output wire spi_req,
|
||||
input wire spi_stb,
|
||||
|
||||
// WTPORT interface
|
||||
input wire [7:0] wtp_rddata,
|
||||
// output wire [7:0] wtp_wrdata,
|
||||
output wire wtp_req,
|
||||
input wire wtp_stb,
|
||||
|
||||
// IDE interface
|
||||
input wire [15:0] ide_in,
|
||||
output wire [15:0] ide_out,
|
||||
output wire ide_req,
|
||||
output wire ide_rnw,
|
||||
input wire ide_stb,
|
||||
|
||||
`ifdef FDR
|
||||
// FDD interface
|
||||
input wire [7:0] fdr_in,
|
||||
output wire fdr_req,
|
||||
input wire fdr_stb,
|
||||
input wire fdr_stop,
|
||||
`endif
|
||||
|
||||
// CRAM interface
|
||||
output wire cram_we,
|
||||
|
||||
// SFILE interface
|
||||
output wire sfile_we
|
||||
);
|
||||
|
||||
// mode:
|
||||
// 0 - device to RAM (read from device)
|
||||
// 1 - RAM to device (write to device)
|
||||
|
||||
wire dma_saddrl = dmaport_wr[0];
|
||||
wire dma_saddrh = dmaport_wr[1];
|
||||
wire dma_saddrx = dmaport_wr[2];
|
||||
wire dma_daddrl = dmaport_wr[3];
|
||||
wire dma_daddrh = dmaport_wr[4];
|
||||
wire dma_daddrx = dmaport_wr[5];
|
||||
wire dma_len = dmaport_wr[6];
|
||||
wire dma_launch = dmaport_wr[7];
|
||||
wire dma_num = dmaport_wr[8];
|
||||
`ifdef FDR
|
||||
wire dma_numh = dmaport_wr[9];
|
||||
`endif
|
||||
|
||||
// devices
|
||||
localparam DEV_RAM = 3'b001;
|
||||
localparam DEV_BLT1 = 4'b1001;
|
||||
`ifdef XTR_FEAT
|
||||
localparam DEV_BLT2 = 4'b0110;
|
||||
`endif
|
||||
localparam DEV_FIL = 4'b0100;
|
||||
localparam DEV_SPI = 3'b010;
|
||||
localparam DEV_IDE = 3'b011;
|
||||
localparam DEV_CRM = 4'b1100;
|
||||
localparam DEV_SFL = 4'b1101;
|
||||
localparam DEV_FDD = 4'b0101;
|
||||
localparam DEV_WTP = 4'b0111;
|
||||
|
||||
wire state_dev;
|
||||
wire ide_int_stb;
|
||||
wire byte_sw_stb;
|
||||
wire spi_int_stb;
|
||||
wire wtp_int_stb;
|
||||
|
||||
reg dma_salgn;
|
||||
reg dma_dalgn;
|
||||
reg dma_asz;
|
||||
|
||||
reg phase; // 0 - read / 1 - write
|
||||
reg phase_blt; // 0 - source / 1 - destination
|
||||
reg bsel; // 0 - lsb / 1 - msb
|
||||
reg dma_opt;
|
||||
|
||||
reg [3:0] device;
|
||||
wire [2:0] dev_bid = device[2:0]; // bidirectional
|
||||
wire [3:0] dev_uni = device[3:0]; // unidirectional
|
||||
wire dma_wnr = device[3]; // 0 - device to RAM / 1 - RAM to device
|
||||
|
||||
`ifdef XTR_FEAT
|
||||
wire dv_ram = (dev_uni == DEV_RAM) || (dev_uni == DEV_BLT1) || (dev_uni == DEV_BLT2) || (dev_uni == DEV_FIL);
|
||||
wire dv_blt = (dev_uni == DEV_BLT1) || (dev_uni == DEV_BLT2);
|
||||
`else
|
||||
wire dv_ram = (dev_uni == DEV_RAM) || (dev_uni == DEV_BLT1) || (dev_uni == DEV_FIL);
|
||||
wire dv_blt = (dev_uni == DEV_BLT1);
|
||||
`endif
|
||||
wire dv_fil = (dev_uni == DEV_FIL);
|
||||
wire dv_spi = (dev_bid == DEV_SPI);
|
||||
wire dv_ide = (dev_bid == DEV_IDE);
|
||||
wire dv_crm = (dev_uni == DEV_CRM);
|
||||
wire dv_sfl = (dev_uni == DEV_SFL);
|
||||
wire dv_wtp = (dev_uni == DEV_WTP);
|
||||
`ifdef FDR
|
||||
wire dv_fdd = (dev_uni == DEV_FDD);
|
||||
`endif
|
||||
|
||||
wire dev_req = dma_act && state_dev;
|
||||
wire dev_stb = cram_we || sfile_we || ide_int_stb || (byte_sw_stb && bsel && dma_act);
|
||||
|
||||
`ifdef FDR
|
||||
assign byte_sw_stb = spi_int_stb || wtp_int_stb || fdr_int_stb;
|
||||
`else
|
||||
assign byte_sw_stb = spi_int_stb || wtp_int_stb;
|
||||
`endif
|
||||
|
||||
// blitter
|
||||
// Mode 1
|
||||
wire [7:0] blt1_data10 = |data[7:0] ? data[7:0] : dram_rddata[7:0];
|
||||
wire [7:0] blt1_data32 = |data[15:8] ? data[15:8] : dram_rddata[15:8];
|
||||
wire [3:0] blt1_data0 = |data[3:0] ? data[3:0] : dram_rddata[3:0];
|
||||
wire [3:0] blt1_data1 = |data[7:4] ? data[7:4] : dram_rddata[7:4];
|
||||
wire [3:0] blt1_data2 = |data[11:8] ? data[11:8] : dram_rddata[11:8];
|
||||
wire [3:0] blt1_data3 = |data[15:12] ? data[15:12] : dram_rddata[15:12];
|
||||
wire [7:0] blt1_data_l = dma_asz ? blt1_data10 : {blt1_data1, blt1_data0};
|
||||
wire [7:0] blt1_data_h = dma_asz ? blt1_data32 : {blt1_data3, blt1_data2};
|
||||
wire [15:0] blt1_rddata = {blt1_data_h, blt1_data_l};
|
||||
|
||||
`ifdef XTR_FEAT
|
||||
// Mode 2
|
||||
localparam msk = 8'd255;
|
||||
|
||||
wire [8:0] sum80 = data[7:0] + dram_rddata[7:0];
|
||||
wire [8:0] sum81 = data[15:8] + dram_rddata[15:8];
|
||||
|
||||
wire [4:0] sum40 = data[3:0] + dram_rddata[3:0];
|
||||
wire [4:0] sum41 = data[7:4] + dram_rddata[7:4];
|
||||
wire [4:0] sum42 = data[11:8] + dram_rddata[11:8];
|
||||
wire [4:0] sum43 = data[15:12] + dram_rddata[15:12];
|
||||
|
||||
wire [7:0] blt2_8_data0 = ((sum80 > msk) && dma_opt) ? msk : sum80[7:0];
|
||||
wire [7:0] blt2_8_data1 = ((sum81 > msk) && dma_opt) ? msk : sum81[7:0];
|
||||
|
||||
wire [3:0] blt2_4_data0 = ((sum40 > msk[3:0]) && dma_opt) ? msk[3:0] : sum40[3:0];
|
||||
wire [3:0] blt2_4_data1 = ((sum41 > msk[3:0]) && dma_opt) ? msk[3:0] : sum41[3:0];
|
||||
wire [3:0] blt2_4_data2 = ((sum42 > msk[3:0]) && dma_opt) ? msk[3:0] : sum42[3:0];
|
||||
wire [3:0] blt2_4_data3 = ((sum43 > msk[3:0]) && dma_opt) ? msk[3:0] : sum43[3:0];
|
||||
wire [7:0] blt2_data_0 = dma_asz ? blt2_8_data0 : {blt2_4_data1, blt2_4_data0};
|
||||
wire [7:0] blt2_data_1 = dma_asz ? blt2_8_data1 : {blt2_4_data3, blt2_4_data2};
|
||||
wire [15:0] blt2_rddata = {blt2_data_1, blt2_data_0};
|
||||
wire [15:0] blt_rddata = (dev_uni == DEV_BLT1) ? blt1_rddata : blt2_rddata;
|
||||
|
||||
`else // XTR_FEAT
|
||||
wire [15:0] blt_rddata = blt1_rddata;
|
||||
`endif
|
||||
|
||||
// states
|
||||
wire state_rd = ~phase;
|
||||
wire state_wr = phase;
|
||||
assign state_dev = !dv_ram && (dma_wnr ^ !phase);
|
||||
wire state_mem = dv_ram || (dma_wnr ^ phase);
|
||||
|
||||
// states processing
|
||||
wire blt_hook = dv_blt && !phase_blt && !phase;
|
||||
wire phase_end_ram = state_mem && dram_next && !blt_hook;
|
||||
wire phase_end_dev = state_dev && dev_stb;
|
||||
wire phase_end = phase_end_ram || phase_end_dev;
|
||||
wire fil_hook = dv_fil && phase;
|
||||
wire phase_blt_end = state_mem && dram_next && !phase;
|
||||
|
||||
// blitter cycles:
|
||||
// phase phase_blt blt_hook activity
|
||||
// 0 0 1 read src
|
||||
// 0 1 0 read dst
|
||||
// 1 1 0 write dst
|
||||
|
||||
always @(posedge clk)
|
||||
if (dma_launch) // write to DMACtrl - launch of DMA burst
|
||||
begin
|
||||
dma_opt <= zdata[6];
|
||||
dma_salgn <= zdata[5];
|
||||
dma_dalgn <= zdata[4];
|
||||
dma_asz <= zdata[3];
|
||||
device <= {zdata[7], zdata[2:0]};
|
||||
phase <= 1'b0;
|
||||
phase_blt <= 1'b0;
|
||||
bsel <= 1'b0;
|
||||
end
|
||||
|
||||
else
|
||||
begin
|
||||
if (phase_end && !fil_hook)
|
||||
phase <= ~phase;
|
||||
if (phase_blt_end)
|
||||
phase_blt <= ~phase_blt;
|
||||
if (byte_sw_stb)
|
||||
bsel <= ~bsel;
|
||||
end
|
||||
|
||||
// data aquiring
|
||||
always @(posedge clk)
|
||||
if (state_rd)
|
||||
begin
|
||||
if (dram_next)
|
||||
data <= (dv_blt && phase_blt) ? blt_rddata : dram_rddata;
|
||||
|
||||
if (ide_int_stb)
|
||||
data <= ide_in;
|
||||
|
||||
if (spi_int_stb)
|
||||
begin
|
||||
if (bsel)
|
||||
data[15:8] <= spi_rddata;
|
||||
else
|
||||
data[7:0] <= spi_rddata;
|
||||
end
|
||||
|
||||
if (wtp_int_stb)
|
||||
begin
|
||||
if (bsel)
|
||||
data[15:8] <= wtp_rddata;
|
||||
else
|
||||
data[7:0] <= wtp_rddata;
|
||||
end
|
||||
|
||||
`ifdef FDR
|
||||
if (fdr_int_stb)
|
||||
begin
|
||||
if (bsel)
|
||||
data[15:8] <= fdr_in;
|
||||
else
|
||||
data[7:0] <= fdr_in;
|
||||
end
|
||||
`endif
|
||||
end
|
||||
|
||||
// counter processing
|
||||
reg [7:0] b_len; // length of burst
|
||||
reg [7:0] b_ctr; // counter for cycles in burst
|
||||
|
||||
wire [8:0] b_ctr_dec = {1'b0, b_ctr[7:0]} - 9'b1;
|
||||
wire next_burst = b_ctr_dec[8];
|
||||
wire [7:0] b_ctr_next = next_burst ? b_len : b_ctr_dec[7:0];
|
||||
|
||||
`ifdef FDR
|
||||
reg [9:0] b_num; // number of bursts
|
||||
reg [10:0] n_ctr; // counter for bursts
|
||||
wire [10:0] n_ctr_dec = n_ctr - next_burst;
|
||||
assign dma_act = !n_ctr[10];
|
||||
`else
|
||||
reg [7:0] b_num; // number of bursts
|
||||
reg [8:0] n_ctr; // counter for bursts
|
||||
wire [8:0] n_ctr_dec = n_ctr - next_burst;
|
||||
assign dma_act = !n_ctr[8];
|
||||
`endif
|
||||
|
||||
always @(posedge clk)
|
||||
`ifdef FDR
|
||||
if (!rst_n || (dv_fdd && fdr_stop))
|
||||
n_ctr[10] <= 1'b1;
|
||||
`else
|
||||
if (!rst_n)
|
||||
n_ctr[8] <= 1'b1;
|
||||
`endif
|
||||
|
||||
else if (dma_launch)
|
||||
begin
|
||||
b_ctr <= b_len;
|
||||
n_ctr <= {1'b0, b_num};
|
||||
end
|
||||
|
||||
else if (phase && phase_end) // cycle processed
|
||||
begin
|
||||
b_ctr <= b_ctr_next;
|
||||
n_ctr <= n_ctr_dec;
|
||||
end
|
||||
|
||||
// loading of burst parameters
|
||||
always @(posedge clk)
|
||||
begin
|
||||
if (dma_len)
|
||||
b_len <= zdata;
|
||||
|
||||
if (dma_num)
|
||||
`ifdef FDR
|
||||
b_num[7:0] <= zdata;
|
||||
|
||||
if (dma_numh)
|
||||
b_num[9:8] <= zdata[1:0];
|
||||
`else
|
||||
b_num <= zdata;
|
||||
`endif
|
||||
end
|
||||
|
||||
// address processing
|
||||
|
||||
// source
|
||||
reg [20:0] s_addr; // current source address
|
||||
reg [7:0] s_addr_r; // source lower address
|
||||
|
||||
wire [8:0] s_addr_inc_l = {1'b0, s_addr[7:0]} + 9'b1;
|
||||
wire [1:0] s_addr_add_h = dma_salgn ? {next_burst && dma_asz, next_burst && !dma_asz} : {s_addr_inc_l[8], 1'b0};
|
||||
wire [13:0] s_addr_next_h = s_addr[20:7] + s_addr_add_h;
|
||||
wire [7:0] s_addr_next_l = (dma_salgn && next_burst) ? s_addr_r : s_addr_inc_l[7:0];
|
||||
wire s_addr_next_m = dma_salgn ? (dma_asz ? s_addr_next_l[7] : s_addr_next_h[0]) : s_addr_inc_l[7];
|
||||
wire [20:0] s_addr_next = {s_addr_next_h[13:1], s_addr_next_m, s_addr_next_l[6:0]};
|
||||
|
||||
always @(posedge clk)
|
||||
if ((dram_next || dev_stb) && state_rd && (!dv_blt || !phase_blt)) // increment RAM source addr
|
||||
s_addr <= s_addr_next;
|
||||
|
||||
else
|
||||
begin
|
||||
if (dma_saddrl)
|
||||
begin
|
||||
s_addr[6:0] <= zdata[7:1];
|
||||
s_addr_r[6:0] <= zdata[7:1];
|
||||
end
|
||||
|
||||
if (dma_saddrh)
|
||||
begin
|
||||
s_addr[12:7] <= zdata[5:0];
|
||||
s_addr_r[7] <= zdata[0];
|
||||
end
|
||||
|
||||
if (dma_saddrx)
|
||||
s_addr[20:13] <= zdata;
|
||||
end
|
||||
|
||||
// destination
|
||||
reg [20:0] d_addr; // current dest address
|
||||
reg [7:0] d_addr_r; // dest lower address
|
||||
|
||||
wire [8:0] d_addr_inc_l = {1'b0, d_addr[7:0]} + 9'b1;
|
||||
wire [1:0] d_addr_add_h = dma_dalgn ? {next_burst && dma_asz, next_burst && !dma_asz} : {d_addr_inc_l[8], 1'b0};
|
||||
wire [13:0] d_addr_next_h = d_addr[20:7] + d_addr_add_h;
|
||||
wire [7:0] d_addr_next_l = (dma_dalgn && next_burst) ? d_addr_r : d_addr_inc_l[7:0];
|
||||
wire d_addr_next_m = dma_dalgn ? (dma_asz ? d_addr_next_l[7] : d_addr_next_h[0]) : d_addr_inc_l[7];
|
||||
wire [20:0] d_addr_next = {d_addr_next_h[13:1], d_addr_next_m, d_addr_next_l[6:0]};
|
||||
|
||||
always @(posedge clk)
|
||||
if ((dram_next || dev_stb) && state_wr) // increment RAM dest addr
|
||||
d_addr <= d_addr_next;
|
||||
else
|
||||
begin
|
||||
if (dma_daddrl)
|
||||
begin
|
||||
d_addr[6:0] <= zdata[7:1];
|
||||
d_addr_r[6:0] <= zdata[7:1];
|
||||
end
|
||||
|
||||
if (dma_daddrh)
|
||||
begin
|
||||
d_addr[12:7] <= zdata[5:0];
|
||||
d_addr_r[7] <= zdata[0];
|
||||
end
|
||||
|
||||
if (dma_daddrx)
|
||||
d_addr[20:13] <= zdata;
|
||||
end
|
||||
|
||||
// INT generation
|
||||
reg dma_act_r = 0;
|
||||
always @(posedge clk)
|
||||
dma_act_r <= dma_act && rst_n;
|
||||
|
||||
assign int_start = !dma_act && dma_act_r;
|
||||
|
||||
assign wraddr = d_addr[7:0];
|
||||
|
||||
// DRAM
|
||||
assign dram_addr = state_rd ? ((!dv_blt || !phase_blt) ? s_addr : d_addr) : d_addr;
|
||||
assign dram_wrdata = data;
|
||||
assign dram_req = dma_act && state_mem;
|
||||
assign dram_rnw = state_rd;
|
||||
|
||||
assign cram_we = dev_req && dv_crm && state_wr;
|
||||
assign sfile_we = dev_req && dv_sfl && state_wr;
|
||||
|
||||
`ifdef FDR
|
||||
// FDD
|
||||
wire fdr_int_stb = dv_fdd && fdr_stb;
|
||||
assign fdr_req = dev_req && dv_fdd;
|
||||
`endif
|
||||
|
||||
// SPI
|
||||
assign spi_int_stb = dv_spi && spi_stb;
|
||||
assign spi_wrdata = {8{state_rd}} | (bsel ? data[15:8] : data[7:0]); // send FF on read cycles
|
||||
assign spi_req = dev_req && dv_spi;
|
||||
|
||||
// WTPORT
|
||||
assign wtp_int_stb = dv_wtp && wtp_stb;
|
||||
assign wtp_req = dev_req && dv_wtp;
|
||||
|
||||
// IDE
|
||||
assign ide_int_stb = dv_ide && ide_stb;
|
||||
assign ide_out = data;
|
||||
assign ide_req = dev_req && dv_ide;
|
||||
assign ide_rnw = state_rd;
|
||||
|
||||
endmodule
|
15
rtl/common/resetter.v
Normal file
15
rtl/common/resetter.v
Normal file
@ -0,0 +1,15 @@
|
||||
`include "tune.v"
|
||||
|
||||
// Reset from MCU must be long enough
|
||||
module resetter
|
||||
(
|
||||
input wire clk,
|
||||
input wire rst_in_n, // external asynchronous reset
|
||||
output reg rst_out_n // synchronized reset
|
||||
);
|
||||
|
||||
always @(posedge clk)
|
||||
rst_out_n <= rst_in_n;
|
||||
|
||||
endmodule
|
||||
|
74
rtl/common/spi.v
Normal file
74
rtl/common/spi.v
Normal file
@ -0,0 +1,74 @@
|
||||
|
||||
`include "tune.v"
|
||||
|
||||
module spi
|
||||
(
|
||||
// SPI wires
|
||||
input wire clk, // system clock
|
||||
output wire sck, // SCK
|
||||
output reg sdo, // MOSI
|
||||
input wire sdi, // MISO
|
||||
input wire mode, // 0 - CPHA=0, CPOL=0 / 1 - CPHA=1, CPOL=0
|
||||
|
||||
// DMA interface
|
||||
input wire dma_req,
|
||||
input wire [7:0] dma_din,
|
||||
|
||||
// Z80 interface
|
||||
input wire cpu_req,
|
||||
input wire [7:0] cpu_din,
|
||||
|
||||
// output
|
||||
output wire start, // start strobe, 1 clock length
|
||||
output reg [7:0] dout
|
||||
);
|
||||
|
||||
reg [4:0] counter = 5'b10000;
|
||||
reg [7:0] shift = 0;
|
||||
reg busy_r;
|
||||
|
||||
wire busy = !counter[4];
|
||||
wire req = cpu_req || dma_req;
|
||||
|
||||
assign sck = counter[0];
|
||||
assign start = req && !busy;
|
||||
wire [7:0] din = dma_req ? dma_din : cpu_din;
|
||||
|
||||
wire cpha = mode;
|
||||
|
||||
always @(posedge clk)
|
||||
begin
|
||||
busy_r <= busy;
|
||||
|
||||
if (start)
|
||||
begin
|
||||
counter <= 5'b0;
|
||||
sdo <= din[7];
|
||||
shift[7:1] <= din[6:0];
|
||||
end
|
||||
else
|
||||
begin
|
||||
if (!counter[4])
|
||||
counter <= counter + 5'd1;
|
||||
|
||||
if (cpha ? busy_r : busy)
|
||||
begin
|
||||
// shift in
|
||||
if (cpha ? sck : !sck)
|
||||
begin
|
||||
shift[0] <= sdi;
|
||||
|
||||
if (&counter[3:1])
|
||||
dout <= {shift[7:1], sdi};
|
||||
end
|
||||
|
||||
// shift out
|
||||
if (cpha ? !sck : sck)
|
||||
begin
|
||||
sdo <= shift[7];
|
||||
shift[7:1] <= shift[6:0]; // last bit remains after end of exchange
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
endmodule
|
@ -1,106 +0,0 @@
|
||||
|
||||
// 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
|
@ -1,71 +0,0 @@
|
||||
|
||||
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
|
@ -1,56 +0,0 @@
|
||||
|
||||
// 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
|
@ -1,228 +0,0 @@
|
||||
// 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 = memrd;
|
||||
wire ramreq = ((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 && 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
|
@ -1,469 +0,0 @@
|
||||
|
||||
// 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
|
@ -1,85 +0,0 @@
|
||||
|
||||
// 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