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:
33
rtl/clock.v
33
rtl/clock.v
@ -1,33 +0,0 @@
|
||||
// This module receives 28 MHz as input clock
|
||||
// and strobes strobes for all clocked parts
|
||||
|
||||
// clk|-__--__--__--__-| period = 28 duty = 50% phase = 0
|
||||
// cnt|< 0>< 1>< 2>< 3>|
|
||||
// f0 |----____----____| period = 14 duty = 50% phase = 0
|
||||
// f1 |____----____----| period = 14 duty = 50% phase = 180
|
||||
// h0 |--------________| period = 7 duty = 50% phase = 0
|
||||
// h1 |________--------| period = 7 duty = 50% phase = 180
|
||||
// c0 |----____________| period = 7 duty = 25% phase = 0
|
||||
// c1 |____----________| period = 7 duty = 25% phase = 90
|
||||
// c2 |________----____| period = 7 duty = 25% phase = 180
|
||||
// c3 |____________----| period = 7 duty = 25% phase = 270
|
||||
|
||||
module clock
|
||||
(
|
||||
input wire clk,
|
||||
|
||||
output reg f0, f1,
|
||||
output reg h0, h1,
|
||||
output reg c0, c1, c2, c3
|
||||
);
|
||||
|
||||
reg [1:0] cnt;
|
||||
always @(posedge clk) begin
|
||||
cnt <= cnt + 2'b1;
|
||||
|
||||
{f1, f0} <= 2'b1 << cnt[0];
|
||||
{h1, h0} <= 2'b1 << cnt[1];
|
||||
{c3, c2, c1, c0} <= 4'b1 << cnt;
|
||||
end
|
||||
|
||||
endmodule
|
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
|
@ -1,59 +1,74 @@
|
||||
// This module serves direct DRAM-to-device data transfer
|
||||
|
||||
// to do
|
||||
// - probably add the extra 8 bit counter for number of bursts
|
||||
`include "tune.v"
|
||||
|
||||
module dma
|
||||
(
|
||||
// clocks
|
||||
input wire clk,
|
||||
input wire c2,
|
||||
input wire reset,
|
||||
// clocks
|
||||
input wire clk,
|
||||
input wire c2,
|
||||
input wire rst_n,
|
||||
|
||||
// interface
|
||||
input wire [8:0] dmaport_wr,
|
||||
output wire dma_act,
|
||||
output reg [15:0] data,
|
||||
output wire [ 7:0] wraddr,
|
||||
output wire int_start,
|
||||
// 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,
|
||||
// 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,
|
||||
// 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,
|
||||
// SPI interface
|
||||
input wire [7:0] spi_rddata,
|
||||
output wire [7:0] spi_wrdata,
|
||||
output wire spi_req,
|
||||
input wire spi_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,
|
||||
// WTPORT interface
|
||||
input wire [7:0] wtp_rddata,
|
||||
// output wire [7:0] wtp_wrdata,
|
||||
output wire wtp_req,
|
||||
input wire wtp_stb,
|
||||
|
||||
// CRAM interface
|
||||
output wire cram_we,
|
||||
// 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,
|
||||
|
||||
// SFILE interface
|
||||
output wire sfile_we
|
||||
`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)
|
||||
|
||||
assign wraddr = d_addr[7:0];
|
||||
|
||||
wire dma_saddrl = dmaport_wr[0];
|
||||
wire dma_saddrh = dmaport_wr[1];
|
||||
wire dma_saddrx = dmaport_wr[2];
|
||||
@ -63,72 +78,84 @@ module dma
|
||||
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
|
||||
|
||||
// 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;
|
||||
|
||||
// devices
|
||||
localparam DEV_RAM = 3'b0001;
|
||||
// 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 || (spi_int_stb && bsel && dma_act);
|
||||
|
||||
assign cram_we = dev_req && dv_crm && state_wr;
|
||||
assign sfile_we = dev_req && dv_sfl && state_wr;
|
||||
wire dev_stb = cram_we || sfile_we || ide_int_stb || (byte_sw_stb && bsel && dma_act);
|
||||
|
||||
// SPI
|
||||
wire 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;
|
||||
|
||||
// IDE
|
||||
wire ide_int_stb = dv_ide && ide_stb;
|
||||
assign ide_out = data;
|
||||
assign ide_req = dev_req && dv_ide;
|
||||
assign ide_rnw = state_rd;
|
||||
`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
|
||||
wire [15:0] blt_rddata = (dev_uni == DEV_BLT1) ? blt1_rddata : blt2_rddata;
|
||||
|
||||
// Mode 1
|
||||
wire [15:0] blt1_rddata = {blt1_data_h, blt1_data_l};
|
||||
wire [7:0] blt1_data_h = dma_asz ? blt1_data32 : {blt1_data3, blt1_data2};
|
||||
wire [7:0] blt1_data_l = dma_asz ? blt1_data10 : {blt1_data1, blt1_data0};
|
||||
wire [7:0] blt1_data32 = |data[15:8] ? data[15:8] : dram_rddata[15:8];
|
||||
wire [7:0] blt1_data10 = |data[7:0] ? data[7:0] : dram_rddata[7:0];
|
||||
wire [3:0] blt1_data3 = |data[15:12] ? data[15:12] : dram_rddata[15:12];
|
||||
wire [3:0] blt1_data2 = |data[11:8] ? data[11:8] : dram_rddata[11:8];
|
||||
wire [3:0] blt1_data1 = |data[7:4] ? data[7:4] : dram_rddata[7:4];
|
||||
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
|
||||
wire [15:0] blt2_rddata = {blt2_data_1, blt2_data_0};
|
||||
wire [7:0] blt2_data_1 = dma_asz ? blt2_8_data1 : {blt2_4_data3, blt2_4_data2};
|
||||
wire [7:0] blt2_data_0 = dma_asz ? blt2_8_data0 : {blt2_4_data1, blt2_4_data0};
|
||||
|
||||
localparam msk = 8'd255;
|
||||
|
||||
wire [8:0] sum80 = data[7:0] + dram_rddata[7:0];
|
||||
@ -146,38 +173,26 @@ module dma
|
||||
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;
|
||||
|
||||
// data aquiring
|
||||
always @(posedge clk)
|
||||
if (state_rd)
|
||||
begin
|
||||
if (dram_next)
|
||||
data <= (dv_blt && phase_blt) ? blt_rddata : dram_rddata;
|
||||
`else // XTR_FEAT
|
||||
wire [15:0] blt_rddata = blt1_rddata;
|
||||
`endif
|
||||
|
||||
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
|
||||
|
||||
end
|
||||
|
||||
// states
|
||||
// states
|
||||
wire state_rd = ~phase;
|
||||
wire state_wr = phase;
|
||||
wire state_dev = !dv_ram && (dma_wnr ^ !phase);
|
||||
assign state_dev = !dv_ram && (dma_wnr ^ !phase);
|
||||
wire state_mem = dv_ram || (dma_wnr ^ phase);
|
||||
|
||||
// states processing
|
||||
wire phase_end = phase_end_ram || phase_end_dev;
|
||||
// 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 blt_hook = dv_blt && !phase_blt && !phase;
|
||||
wire phase_end = phase_end_ram || phase_end_dev;
|
||||
wire fil_hook = dv_fil && phase;
|
||||
wire phase_blt_end = state_mem && dram_next && !phase;
|
||||
|
||||
@ -187,15 +202,6 @@ module dma
|
||||
// 0 1 0 read dst
|
||||
// 1 1 0 write dst
|
||||
|
||||
reg [3:0] device;
|
||||
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;
|
||||
|
||||
always @(posedge clk)
|
||||
if (dma_launch) // write to DMACtrl - launch of DMA burst
|
||||
begin
|
||||
@ -215,26 +221,75 @@ module dma
|
||||
phase <= ~phase;
|
||||
if (phase_blt_end)
|
||||
phase_blt <= ~phase_blt;
|
||||
if (spi_int_stb)
|
||||
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;
|
||||
|
||||
// counter processing
|
||||
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];
|
||||
reg [7:0] b_ctr; // counter for cycles in burst
|
||||
|
||||
wire [7:0] b_ctr_next = next_burst ? b_len : b_ctr_dec[7:0];
|
||||
wire [8:0] b_ctr_dec = {1'b0, b_ctr[7:0]} - 9'b1;
|
||||
wire next_burst = b_ctr_dec[8];
|
||||
`endif
|
||||
|
||||
always @(posedge clk)
|
||||
if (reset)
|
||||
`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
|
||||
@ -248,31 +303,36 @@ module dma
|
||||
n_ctr <= n_ctr_dec;
|
||||
end
|
||||
|
||||
|
||||
// loading of burst parameters
|
||||
// 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
|
||||
// address processing
|
||||
|
||||
// source
|
||||
wire [20:0] s_addr_next = {s_addr_next_h[13:1], s_addr_next_m, s_addr_next_l[6:0]};
|
||||
wire [13:0] s_addr_next_h = s_addr[20:7] + s_addr_add_h;
|
||||
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 s_addr_next_m = dma_salgn ? (dma_asz ? s_addr_next_l[7] : s_addr_next_h[0]) : s_addr_inc_l[7];
|
||||
wire [7:0] s_addr_next_l = (dma_salgn && next_burst) ? s_addr_r : s_addr_inc_l[7:0];
|
||||
wire [8:0] s_addr_inc_l = {1'b0, s_addr[7:0]} + 9'b1;
|
||||
|
||||
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;
|
||||
@ -296,16 +356,16 @@ module dma
|
||||
end
|
||||
|
||||
// destination
|
||||
wire [20:0] d_addr_next = {d_addr_next_h[13:1], d_addr_next_m, d_addr_next_l[6:0]};
|
||||
wire [13:0] d_addr_next_h = d_addr[20:7] + d_addr_add_h;
|
||||
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 d_addr_next_m = dma_dalgn ? (dma_asz ? d_addr_next_l[7] : d_addr_next_h[0]) : d_addr_inc_l[7];
|
||||
wire [7:0] d_addr_next_l = (dma_dalgn && next_burst) ? d_addr_r : d_addr_inc_l[7:0];
|
||||
wire [8:0] d_addr_inc_l = {1'b0, d_addr[7:0]} + 9'b1;
|
||||
|
||||
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;
|
||||
@ -328,10 +388,42 @@ module dma
|
||||
end
|
||||
|
||||
// INT generation
|
||||
reg dma_act_r;
|
||||
reg dma_act_r = 0;
|
||||
always @(posedge clk)
|
||||
dma_act_r <= dma_act && ~reset;
|
||||
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
|
267
rtl/dram/arbiter.v
Normal file
267
rtl/dram/arbiter.v
Normal file
@ -0,0 +1,267 @@
|
||||
`include "tune.v"
|
||||
|
||||
// PentEvo project (c) NedoPC 2008-2011
|
||||
//
|
||||
// DRAM arbiter. Shares DRAM between CPU, video data fetcher and other devices
|
||||
//
|
||||
|
||||
// Arbitration is made on full 8-cycle access blocks. Each cycle is defined by dram.v and consists of 4 fpga clocks.
|
||||
// During each access block, there can be either no videodata access, 1 videodata access, 2, 4 or 8 accesses.
|
||||
// All spare cycles can be used by CPU or other devices. If no device uses memory in the given cycle, refresh cycle is performed.
|
||||
//
|
||||
// In each access block, videodata accesses are spreaded all over the block so that CPU receives cycle
|
||||
// as fast as possible, until there is absolute need to fetch remaining video data.
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// | access block | 4 video accesses during block, no processor accesses. video accesses are done
|
||||
// | vid | vid | vid | vid | ref | ref | ref | ref | as soon as possible, spare cycles are refresh ones
|
||||
//
|
||||
// | access block | 4 video accesses during block, processor requests access every other cycle
|
||||
// | vid | prc | vid | prc | vid | prc | vid | prc |
|
||||
//
|
||||
// | access block | 4 video accesses, processor begins requesting cycles continously from second one
|
||||
// | vid | prc | prc | prc | prc | vid | vid | vid | so it is given cycles while there is such possibility. after that processor
|
||||
// can't access mem until the end of access block and stalls
|
||||
//
|
||||
// | access block | 8 video accesses, processor stalls, if it is requesting cycles
|
||||
// | vid | vid | vid | vid | vid | vid | vid | vid |
|
||||
//
|
||||
// | access block | 2 video accesses, single processor request, other cycles are refresh ones
|
||||
// | vid | vid | ref | ref | cpu | ref | ref | ref |
|
||||
//
|
||||
// | access block | 4 video accesses, single processor request, other cycles are refresh ones
|
||||
// | vid | vid | cpu | vid | vid | ref | ref | ref |
|
||||
//
|
||||
// access block begins at any dram cycle, then blocks video_go back-to-back
|
||||
//
|
||||
// key signals are video_go and XXX_req, sampled at the end of each dram cycle. Must be set to the module at c3 clock cycle.
|
||||
|
||||
// CPU can have either normal or lower access priority to the DRAM.
|
||||
// At the INT active (32 of 3.5MHz clocks) the priority is raised to normal, so that CPU won't miss its interrupt.
|
||||
// This should be considered if dummy RAM access used for waiting for the end of DMA operation instead of status bit polling.
|
||||
//
|
||||
// DRAM access priority:
|
||||
// Z80 normal Z80 low
|
||||
// - VIDEO - VIDEO
|
||||
// - CPU - TS
|
||||
// - TM - TM
|
||||
// - TS - DMA
|
||||
// - DMA - CPU
|
||||
|
||||
module arbiter
|
||||
(
|
||||
input wire clk,
|
||||
input wire c1,
|
||||
input wire c2,
|
||||
input wire c3,
|
||||
input wire cyc,
|
||||
|
||||
// dram.v interface
|
||||
output wire [21:0] dram_addr, // address for dram access
|
||||
output wire dram_req, // dram request
|
||||
output wire dram_rnw, // Read-NotWrite
|
||||
output wire [ 1:0] dram_bsel, // byte select: bsel[1] for wrdata[15:8], bsel[0] for wrdata[7:0]
|
||||
output wire [15:0] dram_wrdata, // data to be written
|
||||
|
||||
// video
|
||||
input wire [20:0] video_addr, // during access block, only when video_strobe==1
|
||||
input wire video_go, // start video access blocks
|
||||
input wire [ 4:0] video_bw, // [4:3] - total cycles: 11 = 8 / 01 = 4 / 00 = 2
|
||||
// [2:0] - need cycles
|
||||
output wire video_pre_next, // (c1)
|
||||
output wire video_next, // (c2) at this signal video_addr may be changed; it is one clock leading the video_strobe
|
||||
output wire video_strobe, // (c3) one-cycle strobe meaning that video_data is available
|
||||
output wire next_vid, // used for TM prefetch
|
||||
|
||||
// CPU
|
||||
input wire [20:0] cpu_addr,
|
||||
input wire [ 7:0] cpu_wrdata,
|
||||
input wire cpu_req,
|
||||
input wire cpu_rnw,
|
||||
input wire cpu_wrbsel,
|
||||
input wire cpu_csrom,
|
||||
output reg cpu_next, // next cycle is allowed to be used by CPU
|
||||
output reg cpu_strobe,
|
||||
output reg cpu_latch,
|
||||
output wire curr_cpu_o,
|
||||
|
||||
// DMA
|
||||
input wire [20:0] dma_addr,
|
||||
input wire [15:0] dma_wrdata,
|
||||
input wire dma_req,
|
||||
input wire dma_rnw,
|
||||
output wire dma_next,
|
||||
|
||||
// TS
|
||||
input wire [20:0] ts_addr,
|
||||
input wire ts_req,
|
||||
output wire ts_pre_next,
|
||||
output wire ts_next,
|
||||
|
||||
// TM
|
||||
input wire [20:0] tm_addr,
|
||||
input wire tm_req,
|
||||
output wire tm_next,
|
||||
|
||||
// ROM loader
|
||||
input wire loader_clk,
|
||||
input wire [15:0] loader_addr,
|
||||
input wire [7:0] loader_data,
|
||||
input wire loader_wr
|
||||
);
|
||||
|
||||
localparam CYCLES = 6;
|
||||
|
||||
localparam CYC_CPU = 6'b000001;
|
||||
localparam CYC_VID = 6'b000010;
|
||||
localparam CYC_TS = 6'b000100;
|
||||
localparam CYC_TM = 6'b001000;
|
||||
localparam CYC_DMA = 6'b010000;
|
||||
localparam CYC_LOADER = 6'b100000;
|
||||
localparam CYC_FREE = 6'b000000;
|
||||
|
||||
localparam CPU = 0;
|
||||
localparam VIDEO = 1;
|
||||
localparam TS = 2;
|
||||
localparam TM = 3;
|
||||
localparam DMA = 4;
|
||||
localparam LOADER = 5;
|
||||
|
||||
reg [CYCLES-1:0] curr_cycle; // type of the cycle in progress
|
||||
reg [CYCLES-1:0] next_cycle; // type of the next cycle
|
||||
|
||||
reg [2:0] blk_rem = 0; // remaining accesses in a block (7..0)
|
||||
reg [2:0] vid_rem = 0; // remaining video accesses in block
|
||||
reg stall = 0;
|
||||
|
||||
wire dev_over_cpu = 0; // can be used to rise devices priority over CPU
|
||||
|
||||
wire next_cpu = next_cycle[CPU];
|
||||
assign next_vid = next_cycle[VIDEO];
|
||||
wire next_ts = next_cycle[TS];
|
||||
wire next_tm = next_cycle[TM];
|
||||
wire next_dma = next_cycle[DMA];
|
||||
wire next_loader = next_cycle[LOADER];
|
||||
|
||||
wire curr_cpu = curr_cycle[CPU];
|
||||
wire curr_vid = curr_cycle[VIDEO];
|
||||
wire curr_ts = curr_cycle[TS];
|
||||
wire curr_tm = curr_cycle[TM];
|
||||
wire curr_dma = curr_cycle[DMA];
|
||||
wire curr_loader = curr_cycle[LOADER];
|
||||
|
||||
assign curr_cpu_o = curr_cpu;
|
||||
|
||||
|
||||
// track blk_rem counter:
|
||||
// how many cycles left to the end of block (7..0)
|
||||
wire video_start = ~|blk_rem;
|
||||
wire [2:0] blk_nrem = (video_start && video_go) ? {video_bw[4:3], 1'b1} : (video_start ? 3'd0 : (blk_rem - 3'd1));
|
||||
wire bw_full = ~|{video_bw[4] & video_bw[2], video_bw[3] & video_bw[1], video_bw[0]}; // stall when 000/00/0
|
||||
wire video_only = stall || (vid_rem == blk_rem);
|
||||
wire video_idle = ~|vid_rem;
|
||||
|
||||
always @(posedge clk) if (c3)
|
||||
begin
|
||||
blk_rem <= blk_nrem;
|
||||
|
||||
if (video_start)
|
||||
stall <= bw_full & video_go;
|
||||
end
|
||||
|
||||
// track vid_rem counter
|
||||
// how many video cycles left to the end of block (7..0)
|
||||
wire [2:0] vidmax = {video_bw[2:0]}; // number of cycles for video access
|
||||
wire [2:0] vid_nrem_next = video_idle ? 3'd0 : (vid_rem - 3'd1);
|
||||
wire [2:0] vid_nrem_start = (cpu_req && !dev_over_cpu) ? vidmax : (vidmax - 3'd1);
|
||||
wire [2:0] vid_nrem = (video_go && video_start) ? vid_nrem_start : (next_vid ? vid_nrem_next : vid_rem);
|
||||
|
||||
always @(posedge clk) if (c3)
|
||||
vid_rem <= vid_nrem;
|
||||
|
||||
reg loader_wr0;
|
||||
reg [7:0] loader_data0;
|
||||
always @(posedge loader_clk) begin
|
||||
if (loader_wr) begin
|
||||
loader_wr0 <= 1'd1;
|
||||
loader_data0 <= loader_data;
|
||||
end
|
||||
else if (cyc) begin
|
||||
loader_wr0 <= 1'd0;
|
||||
end
|
||||
end
|
||||
|
||||
// next cycle decision
|
||||
wire [CYCLES-1:0] cyc_dev = tm_req ? CYC_TM : (ts_req ? CYC_TS : CYC_DMA);
|
||||
wire dev_req = ts_req || tm_req || dma_req;
|
||||
|
||||
always @*
|
||||
if (loader_wr0) begin
|
||||
cpu_next = 1'b0;
|
||||
next_cycle = CYC_LOADER;
|
||||
end
|
||||
else
|
||||
if (video_start) // video burst start
|
||||
if (video_go) // video active
|
||||
begin
|
||||
cpu_next = dev_over_cpu ? 1'b0 : !bw_full;
|
||||
next_cycle = dev_over_cpu ? CYC_VID : (bw_full ? CYC_VID : (cpu_req ? CYC_CPU : CYC_VID));
|
||||
end
|
||||
|
||||
else // video idle
|
||||
begin
|
||||
cpu_next = !dev_over_cpu;
|
||||
next_cycle = dev_over_cpu ? cyc_dev : (cpu_req ? CYC_CPU : (dev_req ? cyc_dev : CYC_FREE));
|
||||
end
|
||||
|
||||
else // video burst in progress
|
||||
begin
|
||||
cpu_next = dev_over_cpu ? 1'b0 : !video_only;
|
||||
next_cycle = video_only ? CYC_VID : (dev_over_cpu ? cyc_dev : (cpu_req ? CYC_CPU : (!video_idle ? CYC_VID : (dev_req ? cyc_dev : CYC_FREE))));
|
||||
end
|
||||
|
||||
always @(posedge clk) if (c3)
|
||||
curr_cycle <= next_cycle;
|
||||
|
||||
|
||||
// DRAM interface
|
||||
assign dram_wrdata = curr_loader? {2{loader_data0}} : curr_dma ? dma_wrdata : {2{cpu_wrdata[7:0]}}; // write data has to be clocked at c0 in dram.v
|
||||
assign dram_bsel[1:0] = next_loader? {loader_addr[0], ~loader_addr[0]} : next_dma ? 2'b11 : {cpu_wrbsel, ~cpu_wrbsel};
|
||||
assign dram_req = |next_cycle;
|
||||
assign dram_rnw = next_loader? 1'b0 : next_cpu ? cpu_rnw : (next_dma ? dma_rnw : 1'b1);
|
||||
assign dram_addr = {22{next_loader}} & { 1'b1, 6'b000000, loader_addr[15:1] }
|
||||
| {22{next_cpu}} & { cpu_csrom, {6{~cpu_csrom}} & cpu_addr[20:15], cpu_addr[14:0] }
|
||||
| {22{next_vid}} & { 1'b0, video_addr }
|
||||
| {22{next_ts}} & { 1'b0, ts_addr }
|
||||
| {22{next_tm}} & { 1'b0, tm_addr }
|
||||
| {22{next_dma}} & { 1'b0, dma_addr };
|
||||
|
||||
reg cpu_rnw_r;
|
||||
always @(posedge clk) if (c3)
|
||||
cpu_rnw_r <= cpu_rnw;
|
||||
|
||||
// read strobes generation for video and cpu
|
||||
always @(posedge clk)
|
||||
if (c1)
|
||||
begin
|
||||
cpu_strobe <= curr_cpu && cpu_rnw_r;
|
||||
cpu_latch <= curr_cpu && cpu_rnw_r;
|
||||
end
|
||||
else if (c2)
|
||||
cpu_strobe <= 1'b0;
|
||||
else if (c3)
|
||||
cpu_latch <= 1'b0;
|
||||
|
||||
assign video_pre_next = curr_vid & c1;
|
||||
assign video_next = curr_vid & c2;
|
||||
assign video_strobe = curr_vid && c3;
|
||||
|
||||
assign ts_pre_next = curr_ts & c1;
|
||||
assign ts_next = curr_ts & c2;
|
||||
|
||||
assign tm_next = curr_tm & c2;
|
||||
|
||||
assign dma_next = curr_dma & c2;
|
||||
|
||||
endmodule
|
@ -1,72 +1,72 @@
|
||||
|
||||
module dpram #(parameter DATAWIDTH=8, ADDRWIDTH=8, NUMWORDS=1<<ADDRWIDTH, MEM_INIT_FILE="")
|
||||
(
|
||||
input clock,
|
||||
|
||||
input [ADDRWIDTH-1:0] address_a,
|
||||
input [DATAWIDTH-1:0] data_a,
|
||||
input wren_a,
|
||||
output [DATAWIDTH-1:0] q_a,
|
||||
|
||||
input [ADDRWIDTH-1:0] address_b,
|
||||
input [DATAWIDTH-1:0] data_b,
|
||||
input wren_b,
|
||||
output [DATAWIDTH-1:0] q_b
|
||||
);
|
||||
|
||||
altsyncram altsyncram_component (
|
||||
.address_a (address_a),
|
||||
.address_b (address_b),
|
||||
.clock0 (clock),
|
||||
.data_a (data_a),
|
||||
.data_b (data_b),
|
||||
.wren_a (wren_a),
|
||||
.wren_b (wren_b),
|
||||
.q_a (q_a),
|
||||
.q_b (q_b),
|
||||
.aclr0 (1'b0),
|
||||
.aclr1 (1'b0),
|
||||
.addressstall_a (1'b0),
|
||||
.addressstall_b (1'b0),
|
||||
.byteena_a (1'b1),
|
||||
.byteena_b (1'b1),
|
||||
.clock1 (1'b1),
|
||||
.clocken0 (1'b1),
|
||||
.clocken1 (1'b1),
|
||||
.clocken2 (1'b1),
|
||||
.clocken3 (1'b1),
|
||||
.eccstatus (),
|
||||
.rden_a (1'b1),
|
||||
.rden_b (1'b1));
|
||||
defparam
|
||||
altsyncram_component.wrcontrol_wraddress_reg_b = "CLOCK0",
|
||||
altsyncram_component.address_reg_b = "CLOCK0",
|
||||
altsyncram_component.indata_reg_b = "CLOCK0",
|
||||
altsyncram_component.numwords_a = NUMWORDS,
|
||||
altsyncram_component.numwords_b = NUMWORDS,
|
||||
altsyncram_component.widthad_a = ADDRWIDTH,
|
||||
altsyncram_component.widthad_b = ADDRWIDTH,
|
||||
altsyncram_component.width_a = DATAWIDTH,
|
||||
altsyncram_component.width_b = DATAWIDTH,
|
||||
altsyncram_component.width_byteena_a = 1,
|
||||
altsyncram_component.width_byteena_b = 1,
|
||||
|
||||
altsyncram_component.init_file = MEM_INIT_FILE,
|
||||
altsyncram_component.clock_enable_input_a = "BYPASS",
|
||||
altsyncram_component.clock_enable_input_b = "BYPASS",
|
||||
altsyncram_component.clock_enable_output_a = "BYPASS",
|
||||
altsyncram_component.clock_enable_output_b = "BYPASS",
|
||||
altsyncram_component.intended_device_family = "Cyclone III",
|
||||
altsyncram_component.lpm_type = "altsyncram",
|
||||
altsyncram_component.operation_mode = "BIDIR_DUAL_PORT",
|
||||
altsyncram_component.outdata_aclr_a = "NONE",
|
||||
altsyncram_component.outdata_aclr_b = "NONE",
|
||||
altsyncram_component.outdata_reg_a = "UNREGISTERED",
|
||||
altsyncram_component.outdata_reg_b = "UNREGISTERED",
|
||||
altsyncram_component.power_up_uninitialized = "FALSE",
|
||||
altsyncram_component.read_during_write_mode_mixed_ports = "DONT_CARE",
|
||||
altsyncram_component.read_during_write_mode_port_a = "NEW_DATA_NO_NBE_READ",
|
||||
altsyncram_component.read_during_write_mode_port_b = "NEW_DATA_NO_NBE_READ";
|
||||
|
||||
|
||||
endmodule
|
||||
|
||||
module dpram #(parameter DATAWIDTH=8, ADDRWIDTH=8, NUMWORDS=1<<ADDRWIDTH, MEM_INIT_FILE="")
|
||||
(
|
||||
input clock,
|
||||
|
||||
input [ADDRWIDTH-1:0] address_a,
|
||||
input [DATAWIDTH-1:0] data_a,
|
||||
input wren_a,
|
||||
output [DATAWIDTH-1:0] q_a,
|
||||
|
||||
input [ADDRWIDTH-1:0] address_b,
|
||||
input [DATAWIDTH-1:0] data_b,
|
||||
input wren_b,
|
||||
output [DATAWIDTH-1:0] q_b
|
||||
);
|
||||
|
||||
altsyncram altsyncram_component (
|
||||
.address_a (address_a),
|
||||
.address_b (address_b),
|
||||
.clock0 (clock),
|
||||
.data_a (data_a),
|
||||
.data_b (data_b),
|
||||
.wren_a (wren_a),
|
||||
.wren_b (wren_b),
|
||||
.q_a (q_a),
|
||||
.q_b (q_b),
|
||||
.aclr0 (1'b0),
|
||||
.aclr1 (1'b0),
|
||||
.addressstall_a (1'b0),
|
||||
.addressstall_b (1'b0),
|
||||
.byteena_a (1'b1),
|
||||
.byteena_b (1'b1),
|
||||
.clock1 (1'b1),
|
||||
.clocken0 (1'b1),
|
||||
.clocken1 (1'b1),
|
||||
.clocken2 (1'b1),
|
||||
.clocken3 (1'b1),
|
||||
.eccstatus (),
|
||||
.rden_a (1'b1),
|
||||
.rden_b (1'b1));
|
||||
defparam
|
||||
altsyncram_component.wrcontrol_wraddress_reg_b = "CLOCK0",
|
||||
altsyncram_component.address_reg_b = "CLOCK0",
|
||||
altsyncram_component.indata_reg_b = "CLOCK0",
|
||||
altsyncram_component.numwords_a = NUMWORDS,
|
||||
altsyncram_component.numwords_b = NUMWORDS,
|
||||
altsyncram_component.widthad_a = ADDRWIDTH,
|
||||
altsyncram_component.widthad_b = ADDRWIDTH,
|
||||
altsyncram_component.width_a = DATAWIDTH,
|
||||
altsyncram_component.width_b = DATAWIDTH,
|
||||
altsyncram_component.width_byteena_a = 1,
|
||||
altsyncram_component.width_byteena_b = 1,
|
||||
|
||||
altsyncram_component.init_file = MEM_INIT_FILE,
|
||||
altsyncram_component.clock_enable_input_a = "BYPASS",
|
||||
altsyncram_component.clock_enable_input_b = "BYPASS",
|
||||
altsyncram_component.clock_enable_output_a = "BYPASS",
|
||||
altsyncram_component.clock_enable_output_b = "BYPASS",
|
||||
altsyncram_component.intended_device_family = "Cyclone III",
|
||||
altsyncram_component.lpm_type = "altsyncram",
|
||||
altsyncram_component.operation_mode = "BIDIR_DUAL_PORT",
|
||||
altsyncram_component.outdata_aclr_a = "NONE",
|
||||
altsyncram_component.outdata_aclr_b = "NONE",
|
||||
altsyncram_component.outdata_reg_a = "UNREGISTERED",
|
||||
altsyncram_component.outdata_reg_b = "UNREGISTERED",
|
||||
altsyncram_component.power_up_uninitialized = "FALSE",
|
||||
altsyncram_component.read_during_write_mode_mixed_ports = "DONT_CARE",
|
||||
altsyncram_component.read_during_write_mode_port_a = "NEW_DATA_NO_NBE_READ",
|
||||
altsyncram_component.read_during_write_mode_port_b = "NEW_DATA_NO_NBE_READ";
|
||||
|
||||
|
||||
endmodule
|
@ -1,263 +0,0 @@
|
||||
|
||||
// PentEvo project (c) NedoPC 2008-2011
|
||||
//
|
||||
// DRAM arbiter. Shares DRAM between CPU, video data fetcher and other devices
|
||||
//
|
||||
|
||||
// Arbitration is made on full 8-cycle access blocks. Each cycle is defined by dram.v and consists of 4 fpga clocks.
|
||||
// During each access block, there can be either no videodata access, 1 videodata access, 2, 4 or 8 accesses.
|
||||
// All spare cycles can be used by CPU or other devices. If no device uses memory in the given cycle, refresh cycle is performed.
|
||||
//
|
||||
// In each access block, videodata accesses are spreaded all over the block so that CPU receives cycle
|
||||
// as fast as possible, until there is absolute need to fetch remaining video data.
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// | access block | 4 video accesses during block, no processor accesses. video accesses are done
|
||||
// | vid | vid | vid | vid | ref | ref | ref | ref | as soon as possible, spare cycles are refresh ones
|
||||
//
|
||||
// | access block | 4 video accesses during block, processor requests access every other cycle
|
||||
// | vid | prc | vid | prc | vid | prc | vid | prc |
|
||||
//
|
||||
// | access block | 4 video accesses, processor begins requesting cycles continously from second one
|
||||
// | vid | prc | prc | prc | prc | vid | vid | vid | so it is given cycles while there is such possibility. after that processor
|
||||
// can't access mem until the end of access block and stalls
|
||||
//
|
||||
// | access block | 8 video accesses, processor stalls, if it is requesting cycles
|
||||
// | vid | vid | vid | vid | vid | vid | vid | vid |
|
||||
//
|
||||
// | access block | 2 video accesses, single processor request, other cycles are refresh ones
|
||||
// | vid | vid | ref | ref | cpu | ref | ref | ref |
|
||||
//
|
||||
// | access block | 4 video accesses, single processor request, other cycles are refresh ones
|
||||
// | vid | vid | cpu | vid | vid | ref | ref | ref |
|
||||
//
|
||||
// access block begins at any dram cycle, then blocks go back-to-back
|
||||
//
|
||||
// key signals are go and XXX_req, sampled at the end of each dram cycle. Must be set to the module at c3 clock cycle.
|
||||
|
||||
// CPU can have either normal or lower access priority to the DRAM.
|
||||
// At the INT active (32 of 3.5MHz clocks) the priority is raised to normal, so that CPU won't miss its interrupt.
|
||||
// This should be considered if dummy RAM access used for waiting for the end of DMA operation instead of status bit polling.
|
||||
//
|
||||
// DRAM access priority:
|
||||
// Z80 normal Z80 low
|
||||
// - VIDEO - VIDEO
|
||||
// - CPU - TS
|
||||
// - TM - TM
|
||||
// - TS - DMA
|
||||
// - DMA - CPU
|
||||
|
||||
|
||||
module arbiter
|
||||
(
|
||||
|
||||
input clk,
|
||||
input c0,
|
||||
input c1,
|
||||
input c2,
|
||||
input c3,
|
||||
input cyc,
|
||||
|
||||
// dram.v interface
|
||||
output [21:0] dram_addr, // address for dram access
|
||||
output dram_req, // dram request
|
||||
output dram_rnw, // Read-NotWrite
|
||||
output [ 1:0] dram_bsel, // byte select: bsel[1] for wrdata[15:8], bsel[0] for wrdata[7:0]
|
||||
output [15:0] dram_wrdata, // data to be written
|
||||
|
||||
// video
|
||||
input [20:0] video_addr, // during access block, only when video_strobe==1
|
||||
input go, // start video access blocks
|
||||
input [ 4:0] video_bw, // [4:3] - total cycles: 11 = 8 / 01 = 4 / 00 = 2
|
||||
// [2:0] - need cycles
|
||||
output video_pre_next, // (c1)
|
||||
output video_next, // (c2) at this signal video_addr may be changed; it is one clock leading the video_strobe
|
||||
output video_strobe, // (c3) one-cycle strobe meaning that video_data is available
|
||||
output video_next_strobe, // (c3) one-cycle strobe meaning that video_data is available
|
||||
output next_vid, // used for TM prefetch
|
||||
|
||||
// CPU
|
||||
input [20:0] cpu_addr,
|
||||
input [ 7:0] cpu_wrdata,
|
||||
input cpu_req,
|
||||
input cpu_rnw,
|
||||
input cpu_csrom,
|
||||
input cpu_wrbsel,
|
||||
output reg cpu_next, // next cycle is allowed to be used by CPU
|
||||
output reg cpu_strobe, // c2 strobe
|
||||
output reg cpu_latch, // c2-c3 strobe
|
||||
output curr_cpu_o,
|
||||
|
||||
// DMA
|
||||
input [20:0] dma_addr,
|
||||
input [15:0] dma_wrdata,
|
||||
input dma_req,
|
||||
input dma_rnw,
|
||||
output dma_next,
|
||||
|
||||
// TS
|
||||
input [20:0] ts_addr,
|
||||
input ts_req,
|
||||
output ts_pre_next,
|
||||
output ts_next,
|
||||
|
||||
// TM
|
||||
input [20:0] tm_addr,
|
||||
input tm_req,
|
||||
output tm_next,
|
||||
|
||||
// ROM loader
|
||||
input loader_clk,
|
||||
input [15:0] loader_addr,
|
||||
input [7:0] loader_data,
|
||||
input loader_wr
|
||||
);
|
||||
|
||||
assign curr_cpu_o = curr_cpu;
|
||||
|
||||
localparam CYCLES = 6;
|
||||
|
||||
localparam CYC_CPU = 6'b000001;
|
||||
localparam CYC_VID = 6'b000010;
|
||||
localparam CYC_TS = 6'b000100;
|
||||
localparam CYC_TM = 6'b001000;
|
||||
localparam CYC_DMA = 6'b010000;
|
||||
localparam CYC_LOADER = 6'b100000;
|
||||
localparam CYC_FREE = 6'b000000;
|
||||
|
||||
localparam CPU = 0;
|
||||
localparam VIDEO = 1;
|
||||
localparam TS = 2;
|
||||
localparam TM = 3;
|
||||
localparam DMA = 4;
|
||||
localparam LOADER = 5;
|
||||
|
||||
reg [CYCLES-1:0] curr_cycle; // type of the cycle in progress
|
||||
reg [CYCLES-1:0] next_cycle; // type of the next cycle
|
||||
|
||||
wire next_cpu = next_cycle[CPU];
|
||||
assign next_vid = next_cycle[VIDEO];
|
||||
wire next_ts = next_cycle[TS];
|
||||
wire next_tm = next_cycle[TM];
|
||||
wire next_dma = next_cycle[DMA];
|
||||
wire next_loader = next_cycle[LOADER];
|
||||
|
||||
wire curr_cpu = curr_cycle[CPU];
|
||||
wire curr_vid = curr_cycle[VIDEO];
|
||||
wire curr_ts = curr_cycle[TS];
|
||||
wire curr_tm = curr_cycle[TM];
|
||||
wire curr_dma = curr_cycle[DMA];
|
||||
wire curr_loader = curr_cycle[LOADER];
|
||||
|
||||
|
||||
// track blk_rem counter:
|
||||
// how many cycles left to the end of block (7..0)
|
||||
wire [2:0] blk_nrem = (video_start && go) ? {video_bw[4:3], 1'b1} : (video_start ? 3'd0 : (blk_rem - 3'd1));
|
||||
wire bw_full = ~|{video_bw[4] & video_bw[2], video_bw[3] & video_bw[1], video_bw[0]}; // stall when 000/00/0
|
||||
wire video_start = ~|blk_rem;
|
||||
wire video_only = stall || (vid_rem == blk_rem);
|
||||
wire video_idle = ~|vid_rem;
|
||||
|
||||
reg [2:0] blk_rem; // remaining accesses in a block (7..0)
|
||||
reg stall;
|
||||
always @(posedge clk) begin
|
||||
if (c3) begin
|
||||
blk_rem <= blk_nrem;
|
||||
if (video_start) stall <= bw_full & go;
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
// track vid_rem counter
|
||||
// how many video cycles left to the end of block (7..0)
|
||||
wire [2:0] vid_nrem = (go && video_start) ? vid_nrem_start : (next_vid ? vid_nrem_next : vid_rem);
|
||||
wire [2:0] vid_nrem_start = (cpu_req && !dev_over_cpu) ? vidmax : (vidmax - 3'd1);
|
||||
wire [2:0] vid_nrem_next = video_idle ? 3'd0 : (vid_rem - 3'd1);
|
||||
wire [2:0] vidmax = {video_bw[2:0]}; // number of cycles for video access
|
||||
|
||||
reg [2:0] vid_rem; // remaining video accesses in block
|
||||
always @(posedge clk) if (c3) vid_rem <= vid_nrem;
|
||||
|
||||
|
||||
reg loader_wr0;
|
||||
reg [7:0] loader_data0;
|
||||
always @(posedge loader_clk) begin
|
||||
if (loader_wr) begin
|
||||
loader_wr0 <= 1'd1;
|
||||
loader_data0 <= loader_data;
|
||||
end
|
||||
else if (cyc) begin
|
||||
loader_wr0 <= 1'd0;
|
||||
end
|
||||
end
|
||||
|
||||
// next cycle decision
|
||||
wire [CYCLES-1:0] cyc_dev = tm_req ? CYC_TM : (ts_req ? CYC_TS : CYC_DMA);
|
||||
wire dev_req = ts_req || tm_req || dma_req;
|
||||
// wire dev_over_cpu = (((ts_req || tm_req) && ts_z80_lp) || (dma_req && dma_z80_lp)) && int_n; // CPU gets higher priority to acknowledge the INT
|
||||
wire dev_over_cpu = 0;
|
||||
|
||||
always @* begin
|
||||
if (loader_wr0) begin
|
||||
cpu_next = 1'b0;
|
||||
next_cycle = CYC_LOADER;
|
||||
end
|
||||
else if (video_start) begin // video burst start
|
||||
if (go) begin // video active line - 38us-ON, 26us-ON
|
||||
cpu_next = dev_over_cpu ? 1'b0 : !bw_full;
|
||||
next_cycle = dev_over_cpu ? CYC_VID : (bw_full ? CYC_VID : (cpu_req ? CYC_CPU : CYC_VID));
|
||||
end
|
||||
else begin // video idle
|
||||
cpu_next = !dev_over_cpu;
|
||||
next_cycle = dev_over_cpu ? cyc_dev : (cpu_req ? CYC_CPU : (dev_req ? cyc_dev : CYC_FREE));
|
||||
end
|
||||
end
|
||||
else begin // video burst in progress
|
||||
cpu_next = dev_over_cpu ? 1'b0 : !video_only;
|
||||
next_cycle = video_only ? CYC_VID : (dev_over_cpu ? cyc_dev : (cpu_req ? CYC_CPU : (!video_idle ? CYC_VID : (dev_req ? cyc_dev : CYC_FREE))));
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge clk) if (c3) curr_cycle <= next_cycle;
|
||||
|
||||
// DRAM interface
|
||||
assign dram_wrdata= curr_loader? {loader_data0,loader_data0} : curr_dma ? dma_wrdata : {cpu_wrdata,cpu_wrdata}; // write data has to be clocked at c0 in dram.v
|
||||
assign dram_bsel = next_loader? {loader_addr[0], ~loader_addr[0]} : next_dma ? 2'b11 : {cpu_wrbsel, ~cpu_wrbsel};
|
||||
assign dram_req = |next_cycle;
|
||||
assign dram_rnw = next_loader? 1'b0 : next_cpu ? cpu_rnw : ~next_dma | dma_rnw;
|
||||
assign dram_addr = {22{next_loader}} & { 1'b1, 6'b000000, loader_addr[15:1] }
|
||||
| {22{next_cpu}} & { cpu_csrom, {6{~cpu_csrom}} & cpu_addr[20:15], cpu_addr[14:0] }
|
||||
| {22{next_vid}} & { 1'b0, video_addr }
|
||||
| {22{next_ts }} & { 1'b0, ts_addr }
|
||||
| {22{next_tm }} & { 1'b0, tm_addr }
|
||||
| {22{next_dma}} & { 1'b0, dma_addr };
|
||||
|
||||
reg cpu_rnw_r;
|
||||
always @(posedge clk) if (c3) cpu_rnw_r <= cpu_rnw;
|
||||
|
||||
|
||||
// generation of read strobes: for video and cpu
|
||||
always @(posedge clk) begin
|
||||
if (c1) begin
|
||||
cpu_strobe <= curr_cpu && cpu_rnw_r;
|
||||
cpu_latch <= curr_cpu && cpu_rnw_r;
|
||||
end
|
||||
else if (c2) cpu_strobe <= 1'b0;
|
||||
else if (c3) cpu_latch <= 1'b0;
|
||||
end
|
||||
|
||||
assign video_pre_next = curr_vid & c1;
|
||||
assign video_next = curr_vid & c2;
|
||||
assign video_strobe = curr_vid && c3;
|
||||
assign video_next_strobe = next_vid && c3;
|
||||
|
||||
assign ts_pre_next = curr_ts & c1;
|
||||
assign ts_next = curr_ts & c2;
|
||||
|
||||
assign tm_next = curr_tm & c2;
|
||||
|
||||
assign dma_next = curr_dma & c2;
|
||||
|
||||
|
||||
endmodule
|
BIN
rtl/periph/CMOS.bin
Normal file
BIN
rtl/periph/CMOS.bin
Normal file
Binary file not shown.
21
rtl/periph/CMOS.mif
Normal file
21
rtl/periph/CMOS.mif
Normal file
@ -0,0 +1,21 @@
|
||||
-- http://srecord.sourceforge.net/
|
||||
--
|
||||
-- Generated automatically by srec_cat -o --mif
|
||||
--
|
||||
DEPTH = 256;
|
||||
WIDTH = 8;
|
||||
ADDRESS_RADIX = HEX;
|
||||
DATA_RADIX = HEX;
|
||||
CONTENT BEGIN
|
||||
0000: 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 AA 00 00 00 00 00 00;
|
||||
0018: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00;
|
||||
0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00;
|
||||
0048: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00;
|
||||
0060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00;
|
||||
0078: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00;
|
||||
0090: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00;
|
||||
00A8: 00 00 00 00 00 00 00 00 00 00 00 01 03 00 00 02 01 00 00 00 02 00 00 00;
|
||||
00C0: 00 00 00 00 00 00 00 00 42 08 84 10 C6 18 08 21 4A 29 8C 31 CE 39 21 04;
|
||||
00D8: 63 0C A5 14 E7 1C 29 25 6B 2D AD 35 EF 3D 78 7B 00 00 00 00 00 00 00 00;
|
||||
00F0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00;
|
||||
END;
|
@ -1,66 +1,66 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PS2-to-Kempston Mouse v2
|
||||
// (C) 2017,2018 Sorgelig
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU General Public License as published by the Free
|
||||
// Software Foundation; either version 2 of the License, or (at your option)
|
||||
// any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
// more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License along
|
||||
// with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
module kempston_mouse
|
||||
(
|
||||
input clk_sys,
|
||||
input reset,
|
||||
|
||||
input [24:0] ps2_mouse,
|
||||
|
||||
input [2:0] addr,
|
||||
output sel,
|
||||
output [7:0] dout
|
||||
);
|
||||
|
||||
assign dout = data;
|
||||
assign sel = port_sel;
|
||||
|
||||
reg [11:0] dx;
|
||||
reg [11:0] dy;
|
||||
|
||||
reg [7:0] data;
|
||||
reg port_sel;
|
||||
always @* begin
|
||||
port_sel = 1;
|
||||
casex(addr)
|
||||
3'b011: data = dx[7:0];
|
||||
3'b111: data = dy[7:0];
|
||||
3'bX10: data = ~{5'b00000,ps2_mouse[2], ps2_mouse[0], ps2_mouse[1]} ;
|
||||
default: {port_sel,data} = 8'hFF;
|
||||
endcase
|
||||
end
|
||||
|
||||
always @(posedge clk_sys) begin
|
||||
reg old_status;
|
||||
old_status <= ps2_mouse[24];
|
||||
|
||||
if(reset) begin
|
||||
dx <= 128; // dx != dy for better mouse detection
|
||||
dy <= 0;
|
||||
end
|
||||
else if(old_status != ps2_mouse[24]) begin
|
||||
dx <= dx + {{4{ps2_mouse[4]}},ps2_mouse[15:8]};
|
||||
dy <= dy + {{4{ps2_mouse[5]}},ps2_mouse[23:16]};
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PS2-to-Kempston Mouse v2
|
||||
// (C) 2017,2018 Sorgelig
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU General Public License as published by the Free
|
||||
// Software Foundation; either version 2 of the License, or (at your option)
|
||||
// any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
// more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License along
|
||||
// with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
module kempston_mouse
|
||||
(
|
||||
input clk_sys,
|
||||
input reset,
|
||||
|
||||
input [24:0] ps2_mouse,
|
||||
|
||||
input [2:0] addr,
|
||||
output sel,
|
||||
output [7:0] dout
|
||||
);
|
||||
|
||||
assign dout = data;
|
||||
assign sel = port_sel;
|
||||
|
||||
reg [11:0] dx;
|
||||
reg [11:0] dy;
|
||||
|
||||
reg [7:0] data;
|
||||
reg port_sel;
|
||||
always @* begin
|
||||
port_sel = 1;
|
||||
casex(addr)
|
||||
3'b011: data = dx[7:0];
|
||||
3'b111: data = dy[7:0];
|
||||
3'bX10: data = ~{5'b00000,ps2_mouse[2], ps2_mouse[0], ps2_mouse[1]} ;
|
||||
default: {port_sel,data} = 8'hFF;
|
||||
endcase
|
||||
end
|
||||
|
||||
always @(posedge clk_sys) begin
|
||||
reg old_status;
|
||||
old_status <= ps2_mouse[24];
|
||||
|
||||
if(reset) begin
|
||||
dx <= 128; // dx != dy for better mouse detection
|
||||
dy <= 0;
|
||||
end
|
||||
else if(old_status != ps2_mouse[24]) begin
|
||||
dx <= dx + {{4{ps2_mouse[4]}},ps2_mouse[15:8]};
|
||||
dy <= dy + {{4{ps2_mouse[5]}},ps2_mouse[23:16]};
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
@ -59,17 +59,17 @@ always @(*) begin
|
||||
8'h0c : Dout <= c_reg;
|
||||
8'h0d : Dout <= 8'b10000000;
|
||||
|
||||
8'hb1 : Dout <= CMOSCfg[7:6]; // CPU Speed
|
||||
8'hb2 : Dout <= 0; // Boot device
|
||||
8'hb3 : Dout <= CMOSCfg[8]; // CPU Cache
|
||||
8'hb4 : Dout <= CMOSCfg[13:11]; // F11
|
||||
8'hb5 : Dout <= CMOSCfg[15:14]; // F11 bank
|
||||
8'hb6 : Dout <= CMOSCfg[18:16]; // Shift+F11
|
||||
8'hb7 : Dout <= CMOSCfg[20:19]; // Shift+F11 bank
|
||||
8'hb8 : Dout <= CMOSCfg[10:9]; // #7FFD
|
||||
8'hb9 : Dout <= CMOSCfg[23:21]; // ZX Palette
|
||||
8'hba : Dout <= CMOSCfg[24]; // NGS Reset
|
||||
8'hbb : Dout <= CMOSCfg[27:25]; // INT offset
|
||||
// 8'hb1 : Dout <= CMOSCfg[7:6]; // CPU Speed
|
||||
// 8'hb2 : Dout <= 0; // Boot device
|
||||
// 8'hb3 : Dout <= CMOSCfg[8]; // CPU Cache
|
||||
// 8'hb4 : Dout <= CMOSCfg[13:11]; // F11
|
||||
// 8'hb5 : Dout <= CMOSCfg[15:14]; // F11 bank
|
||||
// 8'hb6 : Dout <= CMOSCfg[18:16]; // Shift+F11
|
||||
// 8'hb7 : Dout <= CMOSCfg[20:19]; // Shift+F11 bank
|
||||
// 8'hb8 : Dout <= CMOSCfg[10:9]; // #7FFD
|
||||
// 8'hb9 : Dout <= CMOSCfg[23:21]; // ZX Palette
|
||||
// 8'hba : Dout <= CMOSCfg[24]; // NGS Reset
|
||||
// 8'hbb : Dout <= CMOSCfg[27:25]; // INT offset
|
||||
|
||||
8'hf0 : Dout <= KEYSCANCODE;
|
||||
default: Dout <= CMOS_Dout;
|
||||
@ -233,7 +233,7 @@ always @(posedge CLK) begin
|
||||
end
|
||||
|
||||
// 50 Bytes of General Purpose RAM
|
||||
dpram #(.DATAWIDTH(8), .ADDRWIDTH(8), .MEM_INIT_FILE("rtl/rtc/CMOS.mif")) CMOS
|
||||
dpram #(.DATAWIDTH(8), .ADDRWIDTH(8), .MEM_INIT_FILE("rtl/periph/CMOS.mif")) CMOS
|
||||
(
|
||||
.clock (CLK),
|
||||
.address_a (A),
|
60
rtl/periph/vdac.v
Normal file
60
rtl/periph/vdac.v
Normal file
@ -0,0 +1,60 @@
|
||||
module vdac
|
||||
(
|
||||
input wire mode,
|
||||
|
||||
input wire [4:0] o_r, // input from FPGA
|
||||
input wire [4:0] o_g,
|
||||
input wire [4:0] o_b,
|
||||
|
||||
output wire [7:0] v_r, // output to VDAC
|
||||
output wire [7:0] v_g,
|
||||
output wire [7:0] v_b
|
||||
);
|
||||
|
||||
vdac_lut vdac_lut_r (.mode(mode), .in(o_r), .out(v_r));
|
||||
vdac_lut vdac_lut_g (.mode(mode), .in(o_g), .out(v_g));
|
||||
vdac_lut vdac_lut_b (.mode(mode), .in(o_b), .out(v_b));
|
||||
|
||||
endmodule
|
||||
|
||||
module vdac_lut
|
||||
(
|
||||
input wire mode,
|
||||
input wire [4:0] in,
|
||||
output wire [7:0] out
|
||||
);
|
||||
|
||||
reg [7:0] lut;
|
||||
assign out = mode ? {in, 3'b0} : lut;
|
||||
|
||||
always @*
|
||||
case (in)
|
||||
5'd0: lut = 8'd0;
|
||||
5'd1: lut = 8'd10;
|
||||
5'd2: lut = 8'd21;
|
||||
5'd3: lut = 8'd31;
|
||||
5'd4: lut = 8'd42;
|
||||
5'd5: lut = 8'd53;
|
||||
5'd6: lut = 8'd63;
|
||||
5'd7: lut = 8'd74;
|
||||
5'd8: lut = 8'd85;
|
||||
5'd9: lut = 8'd95;
|
||||
5'd10: lut = 8'd106;
|
||||
5'd11: lut = 8'd117;
|
||||
5'd12: lut = 8'd127;
|
||||
5'd13: lut = 8'd138;
|
||||
5'd14: lut = 8'd149;
|
||||
5'd15: lut = 8'd159;
|
||||
5'd16: lut = 8'd170;
|
||||
5'd17: lut = 8'd181;
|
||||
5'd18: lut = 8'd191;
|
||||
5'd19: lut = 8'd202;
|
||||
5'd20: lut = 8'd213;
|
||||
5'd21: lut = 8'd223;
|
||||
5'd22: lut = 8'd234;
|
||||
5'd23: lut = 8'd245;
|
||||
5'd24: lut = 8'd255;
|
||||
default: lut = 8'd255;
|
||||
endcase
|
||||
|
||||
endmodule
|
BIN
rtl/rtc/CMOS.bin
BIN
rtl/rtc/CMOS.bin
Binary file not shown.
@ -1,71 +0,0 @@
|
||||
-- Copyright (C) 2017 Intel Corporation. All rights reserved.
|
||||
-- Your use of Intel Corporation's design tools, logic functions
|
||||
-- and other software and tools, and its AMPP partner logic
|
||||
-- functions, and any output files from any of the foregoing
|
||||
-- (including device programming or simulation files), and any
|
||||
-- associated documentation or information are expressly subject
|
||||
-- to the terms and conditions of the Intel Program License
|
||||
-- Subscription Agreement, the Intel Quartus Prime License Agreement,
|
||||
-- the Intel MegaCore Function License Agreement, or other
|
||||
-- applicable license agreement, including, without limitation,
|
||||
-- that your use is for the sole purpose of programming logic
|
||||
-- devices manufactured by Intel and sold by Intel or its
|
||||
-- authorized distributors. Please refer to the applicable
|
||||
-- agreement for further details.
|
||||
|
||||
-- Quartus Prime generated Memory Initialization File (.mif)
|
||||
|
||||
WIDTH=8;
|
||||
DEPTH=256;
|
||||
|
||||
ADDRESS_RADIX=HEX;
|
||||
DATA_RADIX=HEX;
|
||||
|
||||
CONTENT BEGIN
|
||||
[000..010] : 00;
|
||||
011 : AA;
|
||||
[012..0B0] : 00;
|
||||
0B1 : 01;
|
||||
0B2 : 00;
|
||||
0B3 : 01;
|
||||
0B4 : 03;
|
||||
[0B5..0B7] : 00;
|
||||
0B8 : 01;
|
||||
[0B9..0BA] : 00;
|
||||
0BB : 02;
|
||||
[0BC..0CD] : FF;
|
||||
[0CE..0CF] : 00;
|
||||
0D0 : 42;
|
||||
0D1 : 08;
|
||||
0D2 : 84;
|
||||
0D3 : 10;
|
||||
0D4 : C6;
|
||||
0D5 : 18;
|
||||
0D6 : 08;
|
||||
0D7 : 21;
|
||||
0D8 : 4A;
|
||||
0D9 : 29;
|
||||
0DA : 8C;
|
||||
0DB : 31;
|
||||
0DC : CE;
|
||||
0DD : 39;
|
||||
0DE : 21;
|
||||
0DF : 04;
|
||||
0E0 : 63;
|
||||
0E1 : 0C;
|
||||
0E2 : A5;
|
||||
0E3 : 14;
|
||||
0E4 : E7;
|
||||
0E5 : 1C;
|
||||
0E6 : 29;
|
||||
0E7 : 25;
|
||||
0E8 : 6B;
|
||||
0E9 : 2D;
|
||||
0EA : AD;
|
||||
0EB : 35;
|
||||
0EC : EF;
|
||||
0ED : 3D;
|
||||
0EE : 6B;
|
||||
0EF : A2;
|
||||
[0F0..0FF] : 00;
|
||||
END;
|
88
rtl/spi.v
88
rtl/spi.v
@ -1,88 +0,0 @@
|
||||
// part of NeoGS project (c) 2007-2008 NedoPC
|
||||
//
|
||||
|
||||
// SPI mode 0 8-bit master module
|
||||
//
|
||||
// short diagram for speed=0 (Fclk/Fspi=2, no rdy shown)
|
||||
//
|
||||
// clk: ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ (positive edges)
|
||||
// counter: 00|00|00|10|11|12|13|14|15|16|17|18|19|1A|1B|1C|1D|1E|1F|00|00|00 // internal!
|
||||
// sck: ___________/``\__/``\__/``\__/``\__/``\__/``\__/``\__/``\_______
|
||||
// sdo: --------< do7 | do6 | do5 | do4 | do3 | do2 | do1 | do0 >-------
|
||||
// sdi: --------< di7 | di6 | di5 | di4 | di3 | di2 | di1 | di0 >-------
|
||||
// bsync: ________/`````\_________________________________________________
|
||||
// start: _____/``\_______________________________________________________
|
||||
// din: -----<IN>-------------------------------------------------------
|
||||
// dout: old old old old old old old old old old old old old | new new new
|
||||
//
|
||||
// data on sdo must be latched by slave on rising sck edge. data on sdo changes on falling edge of sck
|
||||
//
|
||||
// data from sdi is latched by master on positive edge of sck, while slave changes it on falling edge.
|
||||
// WARNING: slave must emit valid di7 bit BEFORE first pulse on sck!
|
||||
//
|
||||
// start is synchronous pulse, which starts all transfer and also latches din data on the same clk edge
|
||||
// as it is registered high. start can be given anytime (only when speed=0),
|
||||
// so it is functioning then as synchronous reset. when speed!=0, there is global enable for majority of
|
||||
// flipflops in the module, so start can't be accepted at any time
|
||||
//
|
||||
// dout updates with freshly received data at the clk edge in which sck goes high for the last time, thus
|
||||
// latching last bit on sdi.
|
||||
//
|
||||
// sdo emits last bit shifted out after the transfer end
|
||||
|
||||
module spi
|
||||
(
|
||||
// SPI wires
|
||||
input clk, // system clock
|
||||
output sck, // SCK
|
||||
output reg sdo, // MOSI
|
||||
input sdi, // MISO
|
||||
|
||||
// DMA interface
|
||||
input dma_req,
|
||||
input [7:0] dma_din,
|
||||
|
||||
// Z80 interface
|
||||
input cpu_req,
|
||||
input [7:0] cpu_din,
|
||||
|
||||
// output
|
||||
output start, // start strobe, 1 clock length
|
||||
output reg [7:0] dout
|
||||
);
|
||||
|
||||
assign sck = counter[0];
|
||||
assign start = req && rdy;
|
||||
|
||||
wire [7:0] din = dma_req ? dma_din : cpu_din;
|
||||
wire rdy = counter[4]; // 0 - transmission in progress
|
||||
wire req = cpu_req || dma_req;
|
||||
|
||||
reg [4:0] counter;
|
||||
always @(posedge clk) begin
|
||||
reg [7:0] shift;
|
||||
|
||||
if (start) begin
|
||||
counter <= 5'b0;
|
||||
sdo <= din[7];
|
||||
shift[7:1] <= din[6:0];
|
||||
end
|
||||
else if (!rdy) begin
|
||||
counter <= counter + 5'd1;
|
||||
|
||||
// shift in (rising edge of SCK)
|
||||
if (!sck) begin
|
||||
shift[0] <= sdi;
|
||||
|
||||
if (&counter[3:1]) dout <= {shift[7:1], sdi};
|
||||
end
|
||||
|
||||
// shift out (falling edge of sck)
|
||||
if (sck) begin
|
||||
sdo <= shift[7];
|
||||
shift[7:1] <= shift[6:0]; // last bit remains after end of exchange
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
BIN
rtl/tsconf.rom
BIN
rtl/tsconf.rom
Binary file not shown.
1971
rtl/tsconf.v
1971
rtl/tsconf.v
File diff suppressed because it is too large
Load Diff
28
rtl/tune.v
Normal file
28
rtl/tune.v
Normal file
@ -0,0 +1,28 @@
|
||||
`timescale 1ns/100ps
|
||||
|
||||
`ifdef MODEL_TECH
|
||||
`define SIMULATE
|
||||
`endif
|
||||
|
||||
//`define DRAMMEM_VERBOSE
|
||||
//`define FETCH_VERBOSE
|
||||
|
||||
// `define FREE_IORQ // for non-blocked by internal ports !IORQ
|
||||
|
||||
// `define IDE_HDD // for IDE HDD
|
||||
`define IDE_VDAC // for VideoDAC instead of IDE
|
||||
// `define IDE_VDAC2 // for VideoDAC2 instead of IDE
|
||||
|
||||
`define XTR_FEAT // extra features, in only IDEless version
|
||||
|
||||
// `define SD_CARD2 // for second SD Card
|
||||
|
||||
// `define AUTO_INT // auto-incremented Frame Interrpt
|
||||
|
||||
// `define FDR // FDD Ripper version (use with DISABLE_TSU)
|
||||
|
||||
// `define DISABLE_TSU // disable TSU
|
||||
|
||||
// `define PENT_312 // for Pentagon 71680 tacts emulation with 312 video lines
|
||||
|
||||
`define KEMPSTON_8BIT // 8-bit enhanced Kempston Joystick interface
|
@ -1,33 +1,35 @@
|
||||
// This module fetches video data from DRAM
|
||||
|
||||
// This module fetches video data from DRAM
|
||||
|
||||
`include "tune.v"
|
||||
|
||||
module video_fetch
|
||||
(
|
||||
// clocks
|
||||
input wire clk,
|
||||
|
||||
// control
|
||||
input wire [3:0] f_sel,
|
||||
input wire [1:0] b_sel,
|
||||
input wire fetch_stb,
|
||||
|
||||
// video data
|
||||
output reg [31:0] fetch_data,
|
||||
output reg [31:0] fetch_temp,
|
||||
|
||||
// DRAM interface
|
||||
input wire video_strobe,
|
||||
input wire [15:0] video_data
|
||||
);
|
||||
|
||||
// fetching data
|
||||
always @(posedge clk) if (video_strobe)
|
||||
begin
|
||||
if (f_sel[0]) fetch_temp[ 7: 0] <= b_sel[0] ? video_data[15:8] : video_data[ 7:0];
|
||||
if (f_sel[1]) fetch_temp[15: 8] <= b_sel[1] ? video_data[15:8] : video_data[ 7:0];
|
||||
if (f_sel[2]) fetch_temp[23:16] <= video_data[ 7:0];
|
||||
if (f_sel[3]) fetch_temp[31:24] <= video_data[15:8];
|
||||
end
|
||||
|
||||
always @(posedge clk) if (fetch_stb) fetch_data <= fetch_temp;
|
||||
|
||||
(
|
||||
// clocks
|
||||
input wire clk,
|
||||
|
||||
// control
|
||||
input wire [3:0] f_sel,
|
||||
input wire [1:0] b_sel,
|
||||
input wire fetch_stb,
|
||||
|
||||
// video data
|
||||
output reg [31:0] fetch_data,
|
||||
output reg [31:0] fetch_temp,
|
||||
|
||||
// DRAM interface
|
||||
input wire video_strobe,
|
||||
input wire [15:0] video_data
|
||||
);
|
||||
|
||||
always @(posedge clk) if (video_strobe)
|
||||
begin
|
||||
if (f_sel[0]) fetch_temp[ 7: 0] <= b_sel[0] ? video_data[15:8] : video_data[ 7:0];
|
||||
if (f_sel[1]) fetch_temp[15: 8] <= b_sel[1] ? video_data[15:8] : video_data[ 7:0];
|
||||
if (f_sel[2]) fetch_temp[23:16] <= video_data[ 7:0];
|
||||
if (f_sel[3]) fetch_temp[31:24] <= video_data[15:8];
|
||||
end
|
||||
|
||||
always @(posedge clk) if (fetch_stb)
|
||||
fetch_data <= fetch_temp;
|
||||
|
||||
endmodule
|
||||
|
@ -1,235 +1,230 @@
|
||||
|
||||
// This module decodes video modes
|
||||
|
||||
// This module decodes video modes
|
||||
|
||||
`include "tune.v"
|
||||
|
||||
module video_mode
|
||||
(
|
||||
// clocks
|
||||
input wire clk, f1, c3,
|
||||
|
||||
// video config
|
||||
input wire [7:0] vpage,
|
||||
input wire [7:0] vconf,
|
||||
input wire ts_rres_ext,
|
||||
|
||||
// video parameters & mode controls
|
||||
input wire [8:0] gx_offs,
|
||||
output wire [9:0] x_offs_mode,
|
||||
output wire [8:0] hpix_beg,
|
||||
output wire [8:0] hpix_end,
|
||||
output wire [8:0] vpix_beg,
|
||||
output wire [8:0] vpix_end,
|
||||
output wire [8:0] hpix_beg_ts,
|
||||
output wire [8:0] hpix_end_ts,
|
||||
output wire [8:0] vpix_beg_ts,
|
||||
output wire [8:0] vpix_end_ts,
|
||||
output wire [5:0] x_tiles,
|
||||
output wire [4:0] go_offs,
|
||||
output wire [3:0] fetch_sel,
|
||||
output wire [1:0] fetch_bsl,
|
||||
input wire [3:0] fetch_cnt,
|
||||
input wire pix_start,
|
||||
input wire line_start_s,
|
||||
output wire tv_hires,
|
||||
output wire [1:0] render_mode,
|
||||
output wire pix_stb,
|
||||
output wire fetch_stb,
|
||||
|
||||
// video data
|
||||
input wire [15:0] txt_char,
|
||||
|
||||
// video counters
|
||||
input wire [7:0] cnt_col,
|
||||
input wire [8:0] cnt_row,
|
||||
input wire cptr,
|
||||
|
||||
// DRAM interface
|
||||
output wire [20:0] video_addr,
|
||||
output wire [ 4:0] video_bw
|
||||
);
|
||||
|
||||
wire [1:0] vmod = vconf[1:0];
|
||||
wire [1:0] rres = vconf[7:6];
|
||||
|
||||
// clocking strobe for pixels (TV)
|
||||
assign pix_stb = tv_hires ? f1 : c3;
|
||||
|
||||
// Modes
|
||||
localparam M_ZX = 2'h0; // ZX
|
||||
localparam M_HC = 2'h1; // 16c
|
||||
localparam M_XC = 2'h2; // 256c
|
||||
localparam M_TX = 2'h3; // Text
|
||||
|
||||
|
||||
// Render modes (affects 'video_render.v')
|
||||
localparam R_ZX = 2'h0;
|
||||
localparam R_HC = 2'h1;
|
||||
localparam R_XC = 2'h2;
|
||||
localparam R_TX = 2'h3;
|
||||
|
||||
|
||||
// fetch strobes
|
||||
wire ftch[0:3];
|
||||
assign fetch_stb = (pix_start | ftch[render_mode]) && c3;
|
||||
assign ftch[R_ZX] = &fetch_cnt[3:0];
|
||||
assign ftch[R_HC] = &fetch_cnt[1:0];
|
||||
assign ftch[R_XC] = fetch_cnt[0];
|
||||
assign ftch[R_TX] = &fetch_cnt[3:0];
|
||||
|
||||
|
||||
// fetch window
|
||||
wire [4:0] g_offs[0:3];
|
||||
// these values are from a thin air!!! recheck them occasionally!
|
||||
assign g_offs[M_ZX] = 5'd18;
|
||||
assign g_offs[M_HC] = 5'd6;
|
||||
assign g_offs[M_XC] = 5'd4;
|
||||
assign g_offs[M_TX] = 5'd10;
|
||||
assign go_offs = g_offs[vmod];
|
||||
|
||||
|
||||
// fetch selectors
|
||||
// Attention: counter is already incremented at the time of video data fetching!
|
||||
|
||||
// wire m_c = (vmod == M_HC) | (vmod == M_XC);
|
||||
// assign fetch_sel = vmod == M_TX ? f_txt_sel[cnt_col[1:0]] : {~cptr, ~cptr, cptr | m_c, cptr | m_c};
|
||||
|
||||
// wire [3:0] f_sel[0:7];
|
||||
wire [3:0] f_sel[0:3];
|
||||
assign f_sel[M_ZX] = {~cptr, ~cptr, cptr, cptr};
|
||||
assign f_sel[M_HC] = {~cptr, ~cptr, 2'b11};
|
||||
assign f_sel[M_XC] = {~cptr, ~cptr, 2'b11};
|
||||
assign f_sel[M_TX] = f_txt_sel[cnt_col[1:0]];
|
||||
assign fetch_sel = f_sel[vmod];
|
||||
|
||||
assign fetch_bsl = (vmod == M_TX) ? f_txt_bsl[cnt_col[1:0]] : 2'b10;
|
||||
|
||||
// wire [1:0] f_bsl[0:7];
|
||||
// assign f_bsl[M_ZX] = 2'b10;
|
||||
// assign f_bsl[M_HC] = 2'b10;
|
||||
// assign f_bsl[M_XC] = 2'b10;
|
||||
// assign f_bsl[M_TX] = f_txt_bsl[cnt_col[1:0]];
|
||||
// assign fetch_bsl = f_bsl[vmod];
|
||||
|
||||
wire [3:0] f_txt_sel[0:3];
|
||||
assign f_txt_sel[1] = 4'b0011; // char
|
||||
assign f_txt_sel[2] = 4'b1100; // attr
|
||||
assign f_txt_sel[3] = 4'b0001; // gfx0
|
||||
assign f_txt_sel[0] = 4'b0010; // gfx1
|
||||
|
||||
wire [1:0] f_txt_bsl[0:3];
|
||||
assign f_txt_bsl[1] = 2'b10; // char
|
||||
assign f_txt_bsl[2] = 2'b10; // attr
|
||||
assign f_txt_bsl[3] = {2{cnt_row[0]}}; // gfx0
|
||||
assign f_txt_bsl[0] = {2{cnt_row[0]}}; // gfx1
|
||||
|
||||
|
||||
// X offset
|
||||
assign x_offs_mode = {vmod == M_XC ? {gx_offs[8:1], 1'b0} : {1'b0, gx_offs[8:1]}, gx_offs[0]};
|
||||
|
||||
|
||||
// DRAM bandwidth usage
|
||||
localparam BW2 = 2'b00;
|
||||
localparam BW4 = 2'b01;
|
||||
localparam BW8 = 2'b11;
|
||||
|
||||
localparam BU1 = 3'b001;
|
||||
localparam BU2 = 3'b010;
|
||||
localparam BU4 = 3'b100;
|
||||
|
||||
// [4:3] - total cycles: 11 = 8 / 01 = 4 / 00 = 2
|
||||
// [2:0] - need cycles
|
||||
wire [4:0] bw[0:3];
|
||||
assign bw[M_ZX] = {BW8, BU1}; // '1 of 8' (ZX)
|
||||
assign bw[M_HC] = {BW4, BU1}; // '1 of 4' (16c)
|
||||
assign bw[M_XC] = {BW2, BU1}; // '1 of 2' (256c)
|
||||
assign bw[M_TX] = {BW8, BU4}; // '4 of 8' (text)
|
||||
assign video_bw = bw[vmod];
|
||||
|
||||
|
||||
// pixelrate
|
||||
wire [3:0] pixrate = 4'b1000; // change these if you change the modes indexes!
|
||||
assign tv_hires = pixrate[vmod];
|
||||
|
||||
|
||||
// render mode
|
||||
// wire [1:0] r_mode[0:7];
|
||||
wire [1:0] r_mode[0:3];
|
||||
assign r_mode[M_ZX] = R_ZX;
|
||||
assign r_mode[M_HC] = R_HC;
|
||||
assign r_mode[M_XC] = R_XC;
|
||||
assign r_mode[M_TX] = R_TX;
|
||||
assign render_mode = r_mode[vmod];
|
||||
|
||||
|
||||
// raster resolution
|
||||
wire [8:0] hp_beg[0:3];
|
||||
wire [8:0] hp_end[0:3];
|
||||
wire [8:0] vp_beg[0:3];
|
||||
wire [8:0] vp_end[0:3];
|
||||
wire [5:0] x_tile[0:3];
|
||||
|
||||
assign hp_beg[0] = 9'd136; // 256 (88-52-256-52)
|
||||
assign hp_beg[1] = 9'd108; // 320 (88-20-320-20)
|
||||
assign hp_beg[2] = 9'd108; // 320 (88-20-320-20)
|
||||
assign hp_beg[3] = 9'd88; // 360 (88-0-360-0)
|
||||
|
||||
assign hp_end[0] = 9'd392; // 256
|
||||
assign hp_end[1] = 9'd428; // 320
|
||||
assign hp_end[2] = 9'd428; // 320
|
||||
assign hp_end[3] = 9'd448; // 360
|
||||
|
||||
assign vp_beg[0] = 9'd080; // 192 (22-24-192-24)/(32-48-192-48) (blank-border-pixels-border)
|
||||
assign vp_beg[1] = 9'd076; // 200 (22-20-200-20)/(32-44-200-44)
|
||||
assign vp_beg[2] = 9'd056; // 240 (22-0-240-0)/(32-24-240-24)
|
||||
assign vp_beg[3] = 9'd032; // 288 (22-0-240-0)/(32-0-288-0)
|
||||
|
||||
assign vp_end[0] = 9'd272; // 192
|
||||
assign vp_end[1] = 9'd276; // 200
|
||||
assign vp_end[2] = 9'd296; // 240
|
||||
assign vp_end[3] = 9'd320; // 240/288
|
||||
|
||||
assign x_tile[0] = 6'd34; // 256
|
||||
assign x_tile[1] = 6'd42; // 320
|
||||
assign x_tile[2] = 6'd42; // 320
|
||||
assign x_tile[3] = 6'd47; // 360
|
||||
|
||||
assign hpix_beg = hp_beg[rres];
|
||||
assign hpix_end = hp_end[rres];
|
||||
assign vpix_beg = vp_beg[rres];
|
||||
assign vpix_end = vp_end[rres];
|
||||
(
|
||||
// clocks
|
||||
input wire clk, f1, c3,
|
||||
|
||||
assign hpix_beg_ts = ts_rres_ext ? hp_beg[3] : hp_beg[rres];
|
||||
assign hpix_end_ts = ts_rres_ext ? hp_end[3] : hp_end[rres];
|
||||
assign vpix_beg_ts = ts_rres_ext ? vp_beg[3] : vp_beg[rres];
|
||||
assign vpix_end_ts = ts_rres_ext ? vp_end[3] : vp_end[rres];
|
||||
// video config
|
||||
input wire [7:0] vpage,
|
||||
input wire [7:0] vconf,
|
||||
input wire ts_rres_ext,
|
||||
input wire v60hz,
|
||||
|
||||
assign x_tiles = ts_rres_ext ? x_tile[3] : x_tile[rres];
|
||||
|
||||
// videomode addresses
|
||||
wire [20:0] v_addr[0:3];
|
||||
assign v_addr[M_ZX] = addr_zx;
|
||||
assign v_addr[M_HC] = addr_16c;
|
||||
assign v_addr[M_XC] = addr_256c;
|
||||
assign v_addr[M_TX] = addr_text;
|
||||
assign video_addr = v_addr[vmod];
|
||||
|
||||
// ZX
|
||||
wire [20:0] addr_zx = {vpage, 1'b0, ~cnt_col[0] ? addr_zx_gfx : addr_zx_atr};
|
||||
wire [11:0] addr_zx_gfx = {cnt_row[7:6], cnt_row[2:0], cnt_row[5:3], cnt_col[4:1]};
|
||||
wire [11:0] addr_zx_atr = {3'b110, cnt_row[7:3], cnt_col[4:1]};
|
||||
|
||||
// 16c
|
||||
wire [20:0] addr_16c = {vpage[7:3], cnt_row, cnt_col[6:0]};
|
||||
|
||||
// 256c
|
||||
wire [20:0] addr_256c = {vpage[7:4], cnt_row, cnt_col[7:0]};
|
||||
|
||||
// Textmode
|
||||
wire [20:0] addr_text = {vpage[7:1], addr_tx[cnt_col[1:0]]};
|
||||
wire [13:0] addr_tx[0:3];
|
||||
assign addr_tx[0] = {vpage[0], cnt_row[8:3], 1'b0, cnt_col[7:2]}; // char codes, data[15:0]
|
||||
assign addr_tx[1] = {vpage[0], cnt_row[8:3], 1'b1, cnt_col[7:2]}; // char attributes, data[31:16]
|
||||
assign addr_tx[2] = {~vpage[0], 3'b000, (txt_char[7:0]), cnt_row[2:1]}; // char0 graphics, data[7:0]
|
||||
assign addr_tx[3] = {~vpage[0], 3'b000, (txt_char[15:8]), cnt_row[2:1]}; // char1 graphics, data[15:8]
|
||||
|
||||
|
||||
endmodule
|
||||
// video parameters & mode controls
|
||||
input wire [8:0] gx_offs,
|
||||
output wire [9:0] x_offs_mode,
|
||||
output wire [8:0] hpix_beg,
|
||||
output wire [8:0] hpix_end,
|
||||
output wire [8:0] vpix_beg,
|
||||
output wire [8:0] vpix_end,
|
||||
output wire [8:0] hpix_beg_ts,
|
||||
output wire [8:0] hpix_end_ts,
|
||||
output wire [8:0] vpix_beg_ts,
|
||||
output wire [8:0] vpix_end_ts,
|
||||
output wire [5:0] x_tiles,
|
||||
output wire [4:0] go_offs,
|
||||
output wire [3:0] fetch_sel,
|
||||
output wire [1:0] fetch_bsl,
|
||||
input wire [3:0] fetch_cnt,
|
||||
input wire pix_start,
|
||||
input wire line_start_s,
|
||||
output wire tv_hires,
|
||||
output reg vga_hires = 0,
|
||||
output wire [1:0] render_mode,
|
||||
output wire pix_stb,
|
||||
output wire fetch_stb,
|
||||
|
||||
// video data
|
||||
input wire [15:0] txt_char,
|
||||
|
||||
// video counters
|
||||
input wire [7:0] cnt_col,
|
||||
input wire [8:0] cnt_row,
|
||||
input wire cptr,
|
||||
|
||||
// DRAM interface
|
||||
output wire [20:0] video_addr,
|
||||
output wire [ 4:0] video_bw
|
||||
);
|
||||
|
||||
wire [1:0] vmod = vconf[1:0];
|
||||
wire [1:0] rres = vconf[7:6];
|
||||
|
||||
// clocking strobe for pixels (TV)
|
||||
assign pix_stb = tv_hires ? f1 : c3;
|
||||
|
||||
always @(posedge clk)
|
||||
if (line_start_s)
|
||||
vga_hires <= tv_hires;
|
||||
|
||||
// Modes
|
||||
localparam M_ZX = 2'h0; // ZX
|
||||
localparam M_HC = 2'h1; // 16c
|
||||
localparam M_XC = 2'h2; // 256c
|
||||
localparam M_TX = 2'h3; // Text
|
||||
|
||||
// Render modes (affects 'video_render.v')
|
||||
localparam R_ZX = 2'h0;
|
||||
localparam R_HC = 2'h1;
|
||||
localparam R_XC = 2'h2;
|
||||
localparam R_TX = 2'h3;
|
||||
|
||||
// fetch strobes
|
||||
wire ftch[0:3];
|
||||
assign fetch_stb = (pix_start | ftch[render_mode]) && c3;
|
||||
assign ftch[R_ZX] = &fetch_cnt[3:0];
|
||||
assign ftch[R_HC] = &fetch_cnt[1:0];
|
||||
assign ftch[R_XC] = fetch_cnt[0];
|
||||
assign ftch[R_TX] = &fetch_cnt[3:0];
|
||||
|
||||
// fetch window
|
||||
wire [4:0] g_offs[0:3];
|
||||
assign g_offs[M_ZX] = 5'd18;
|
||||
assign g_offs[M_HC] = 5'd6;
|
||||
assign g_offs[M_XC] = 5'd4;
|
||||
assign g_offs[M_TX] = 5'd10;
|
||||
assign go_offs = g_offs[vmod];
|
||||
|
||||
// fetch selectors
|
||||
// Attention: counter is already incremented at the time of video data fetching!
|
||||
wire [3:0] f_sel[0:3];
|
||||
wire [3:0] f_txt_sel[0:3];
|
||||
wire [1:0] f_txt_bsl[0:3];
|
||||
|
||||
assign f_sel[M_ZX] = {~cptr, ~cptr, cptr, cptr};
|
||||
assign f_sel[M_HC] = {~cptr, ~cptr, 2'b11};
|
||||
assign f_sel[M_XC] = {~cptr, ~cptr, 2'b11};
|
||||
assign f_sel[M_TX] = f_txt_sel[cnt_col[1:0]];
|
||||
assign fetch_sel = f_sel[vmod];
|
||||
assign fetch_bsl = (vmod == M_TX) ? f_txt_bsl[cnt_col[1:0]] : 2'b10;
|
||||
|
||||
assign f_txt_sel[1] = 4'b0011; // char
|
||||
assign f_txt_sel[2] = 4'b1100; // attr
|
||||
assign f_txt_sel[3] = 4'b0001; // gfx0
|
||||
assign f_txt_sel[0] = 4'b0010; // gfx1
|
||||
|
||||
assign f_txt_bsl[1] = 2'b10; // char
|
||||
assign f_txt_bsl[2] = 2'b10; // attr
|
||||
assign f_txt_bsl[3] = {2{cnt_row[0]}}; // gfx0
|
||||
assign f_txt_bsl[0] = {2{cnt_row[0]}}; // gfx1
|
||||
|
||||
// X offset
|
||||
assign x_offs_mode = {vmod == M_XC ? {gx_offs[8:1], 1'b0} : {1'b0, gx_offs[8:1]}, gx_offs[0]};
|
||||
|
||||
// DRAM bandwidth usage
|
||||
localparam BW2 = 2'b00;
|
||||
localparam BW4 = 2'b01;
|
||||
localparam BW8 = 2'b11;
|
||||
|
||||
localparam BU1 = 3'b001;
|
||||
localparam BU2 = 3'b010;
|
||||
localparam BU4 = 3'b100;
|
||||
|
||||
// [4:3] - total cycles: 11 = 8 / 01 = 4 / 00 = 2
|
||||
// [2:0] - need cycles
|
||||
wire [4:0] bw[0:3];
|
||||
assign bw[M_ZX] = {BW8, BU1}; // '1 of 8' (ZX)
|
||||
assign bw[M_HC] = {BW4, BU1}; // '1 of 4' (16c)
|
||||
assign bw[M_XC] = {BW2, BU1}; // '1 of 2' (256c)
|
||||
assign bw[M_TX] = {BW8, BU4}; // '4 of 8' (text)
|
||||
assign video_bw = bw[vmod];
|
||||
|
||||
// pixelrate
|
||||
wire [3:0] pixrate = 4'b1000; // change these if you change the modes indexes!
|
||||
assign tv_hires = pixrate[vmod];
|
||||
|
||||
// render mode
|
||||
wire [1:0] r_mode[0:3];
|
||||
assign r_mode[M_ZX] = R_ZX;
|
||||
assign r_mode[M_HC] = R_HC;
|
||||
assign r_mode[M_XC] = R_XC;
|
||||
assign r_mode[M_TX] = R_TX;
|
||||
assign render_mode = r_mode[vmod];
|
||||
|
||||
// raster resolution
|
||||
wire [8:0] hp_beg[0:3];
|
||||
wire [8:0] hp_end[0:3];
|
||||
wire [8:0] vp_beg[0:3];
|
||||
wire [8:0] vp_end[0:3];
|
||||
wire [5:0] x_tile[0:3];
|
||||
|
||||
assign hp_beg[0] = 9'd140; // 256 (88-52-256-52)
|
||||
assign hp_beg[1] = 9'd108; // 320 (88-20-320-20)
|
||||
assign hp_beg[2] = 9'd108; // 320 (88-20-320-20)
|
||||
assign hp_beg[3] = 9'd88; // 360 (88-0-360-0)
|
||||
|
||||
assign hp_end[0] = 9'd396; // 256
|
||||
assign hp_end[1] = 9'd428; // 320
|
||||
assign hp_end[2] = 9'd428; // 320
|
||||
assign hp_end[3] = 9'd448; // 360
|
||||
|
||||
`ifdef PENT_312
|
||||
assign vp_beg[0] = v60hz ? 9'd046 : 9'd072; // 192 (22-24-192-24)/(24-48-192-48) (blank-border-pixels-border)
|
||||
assign vp_beg[1] = v60hz ? 9'd042 : 9'd068; // 200 (22-20-200-20)/(24-44-200-44)
|
||||
assign vp_beg[2] = v60hz ? 9'd022 : 9'd048; // 240 (22-0-240-0)/(24-24-240-24)
|
||||
assign vp_beg[3] = v60hz ? 9'd022 : 9'd024; // 240/288 (22-0-240-0)/(24-0-288-0)
|
||||
|
||||
assign vp_end[0] = v60hz ? 9'd238 : 9'd264; // 192
|
||||
assign vp_end[1] = v60hz ? 9'd242 : 9'd268; // 200
|
||||
assign vp_end[2] = v60hz ? 9'd262 : 9'd288; // 240
|
||||
assign vp_end[3] = v60hz ? 9'd262 : 9'd312; // 240/288
|
||||
`else
|
||||
assign vp_beg[0] = v60hz ? 9'd046 : 9'd080; // 192 (22-24-192-24)/(32-48-192-48) (blank-border-pixels-border)
|
||||
assign vp_beg[1] = v60hz ? 9'd042 : 9'd076; // 200 (22-20-200-20)/(32-44-200-44)
|
||||
assign vp_beg[2] = v60hz ? 9'd022 : 9'd056; // 240 (22-0-240-0)/(32-24-240-24)
|
||||
assign vp_beg[3] = v60hz ? 9'd022 : 9'd032; // 240/288 (22-0-240-0)/(32-0-288-0)
|
||||
|
||||
assign vp_end[0] = v60hz ? 9'd238 : 9'd272; // 192
|
||||
assign vp_end[1] = v60hz ? 9'd242 : 9'd276; // 200
|
||||
assign vp_end[2] = v60hz ? 9'd262 : 9'd296; // 240
|
||||
assign vp_end[3] = v60hz ? 9'd262 : 9'd320; // 240/288
|
||||
`endif
|
||||
|
||||
assign x_tile[0] = 6'd34; // 256
|
||||
assign x_tile[1] = 6'd42; // 320
|
||||
assign x_tile[2] = 6'd42; // 320
|
||||
assign x_tile[3] = 6'd47; // 360
|
||||
|
||||
assign hpix_beg = hp_beg[rres];
|
||||
assign hpix_end = hp_end[rres];
|
||||
assign vpix_beg = vp_beg[rres];
|
||||
assign vpix_end = vp_end[rres];
|
||||
|
||||
assign hpix_beg_ts = ts_rres_ext ? hp_beg[3] : hp_beg[rres];
|
||||
assign hpix_end_ts = ts_rres_ext ? hp_end[3] : hp_end[rres];
|
||||
assign vpix_beg_ts = ts_rres_ext ? vp_beg[3] : vp_beg[rres];
|
||||
assign vpix_end_ts = ts_rres_ext ? vp_end[3] : vp_end[rres];
|
||||
|
||||
assign x_tiles = ts_rres_ext ? x_tile[3] : x_tile[rres];
|
||||
|
||||
// ZX
|
||||
wire [11:0] addr_zx_gfx = {cnt_row[7:6], cnt_row[2:0], cnt_row[5:3], cnt_col[4:1]};
|
||||
wire [11:0] addr_zx_atr = {3'b110, cnt_row[7:3], cnt_col[4:1]};
|
||||
wire [20:0] addr_zx = {vpage, 1'b0, ~cnt_col[0] ? addr_zx_gfx : addr_zx_atr};
|
||||
|
||||
// 16c
|
||||
wire [20:0] addr_16c = {vpage[7:3], cnt_row, cnt_col[6:0]};
|
||||
|
||||
// 256c
|
||||
wire [20:0] addr_256c = {vpage[7:4], cnt_row, cnt_col[7:0]};
|
||||
|
||||
// Textmode
|
||||
wire [13:0] addr_tx[0:3];
|
||||
wire [20:0] addr_text = {vpage[7:1], addr_tx[cnt_col[1:0]]};
|
||||
assign addr_tx[0] = {vpage[0], cnt_row[8:3], 1'b0, cnt_col[7:2]}; // char codes, data[15:0]
|
||||
assign addr_tx[1] = {vpage[0], cnt_row[8:3], 1'b1, cnt_col[7:2]}; // char attributes, data[31:16]
|
||||
assign addr_tx[2] = {~vpage[0], 3'b000, (txt_char[7:0]), cnt_row[2:1]}; // char0 graphics, data[7:0]
|
||||
assign addr_tx[3] = {~vpage[0], 3'b000, (txt_char[15:8]), cnt_row[2:1]}; // char1 graphics, data[15:8]
|
||||
|
||||
// videomode addresses
|
||||
wire [20:0] v_addr[0:3];
|
||||
assign v_addr[M_ZX] = addr_zx;
|
||||
assign v_addr[M_HC] = addr_16c;
|
||||
assign v_addr[M_XC] = addr_256c;
|
||||
assign v_addr[M_TX] = addr_text;
|
||||
assign video_addr = v_addr[vmod];
|
||||
|
||||
endmodule
|
||||
|
@ -2,59 +2,181 @@
|
||||
// This module generates video for DAC
|
||||
// (c)2015 TSL
|
||||
|
||||
`include "tune.v"
|
||||
|
||||
module video_out
|
||||
(
|
||||
// clocks
|
||||
input wire clk, c3,
|
||||
// clocks
|
||||
input wire clk, c3,
|
||||
|
||||
// video controls
|
||||
input wire tv_blank,
|
||||
input wire [1:0] plex_sel_in,
|
||||
// video controls
|
||||
input wire vga_on,
|
||||
input wire tv_blank,
|
||||
input wire vga_blank,
|
||||
input wire vga_line,
|
||||
input wire [1:0] plex_sel_in,
|
||||
|
||||
// mode controls
|
||||
input wire tv_hires,
|
||||
input wire [3:0] palsel,
|
||||
// mode controls
|
||||
input wire tv_hires,
|
||||
input wire vga_hires,
|
||||
input wire [3:0] palsel,
|
||||
|
||||
// Z80 pins
|
||||
input wire [15:0] cram_data_in,
|
||||
input wire [7:0] cram_addr_in,
|
||||
input wire cram_we,
|
||||
// Z80 pins
|
||||
input wire [15:0] cram_data_in,
|
||||
input wire [7:0] cram_addr_in,
|
||||
input wire cram_we,
|
||||
|
||||
// video data
|
||||
input wire [7:0] vplex_in,
|
||||
output wire [7:0] vred,
|
||||
output wire [7:0] vgrn,
|
||||
output wire [7:0] vblu,
|
||||
output wire vdac_mode
|
||||
// video data
|
||||
input wire [7:0] vplex_in,
|
||||
input wire [7:0] vgaplex,
|
||||
output wire [1:0] vred,
|
||||
output wire [1:0] vgrn,
|
||||
output wire [1:0] vblu,
|
||||
output wire [4:0] vred_raw,
|
||||
output wire [4:0] vgrn_raw,
|
||||
output wire [4:0] vblu_raw,
|
||||
output wire vdac_mode
|
||||
);
|
||||
|
||||
wire [14:0] vpix;
|
||||
wire [15:0] vpixel;
|
||||
wire [1:0] phase;
|
||||
wire [7:0] pwm[0:7];
|
||||
|
||||
reg [7:0] vplex;
|
||||
always @(posedge clk) if (c3) vplex <= vplex_in;
|
||||
reg blank1; // GOVNOKOD!!!!!!!!!!!!!!!!!!!!!
|
||||
|
||||
wire [7:0] vdata = tv_hires ? {palsel, plex_sel_in[1] ? vplex[3:0] : vplex[7:4]} : vplex;
|
||||
assign vred_raw = vpix[14:10];
|
||||
assign vgrn_raw = vpix[9:5];
|
||||
assign vblu_raw = vpix[4:0];
|
||||
assign vdac_mode = vpixel[15];
|
||||
|
||||
// TV/VGA mux
|
||||
reg [7:0] vplex;
|
||||
always @(posedge clk) if (c3)
|
||||
vplex <= vplex_in;
|
||||
|
||||
wire [7:0] plex = vga_on ? vgaplex : vplex;
|
||||
wire hires = vga_on ? vga_hires : tv_hires;
|
||||
wire plex_sel = vga_on ? plex_sel_in[0] : plex_sel_in[1];
|
||||
wire [7:0] vdata = hires ? {palsel, plex_sel ? plex[3:0] : plex[7:4]} : plex;
|
||||
wire blank = vga_on ? vga_blank : tv_blank;
|
||||
|
||||
assign vpix = blank1 ? 15'b0 : vpixel[14:0];
|
||||
// assign vpix = blank1 ? 15'b0 : (vpixel[14:0] & 15'b111001110011100); // test for 373 colors
|
||||
// assign vpix = blank1 ? 15'b0 : (vpixel[14:0] & 15'b110001100011000); // test for 64 colors
|
||||
|
||||
// GOVNOKOD!!!!!!!!!!!!!!!!!!!!!
|
||||
always @(posedge clk)
|
||||
begin
|
||||
blank1 <= blank;
|
||||
end
|
||||
|
||||
// color components extraction
|
||||
wire [1:0] cred = vpix[14:13];
|
||||
wire [2:0] ired = vpix[12:10];
|
||||
wire [1:0] cgrn = vpix[ 9: 8];
|
||||
wire [2:0] igrn = vpix[ 7: 5];
|
||||
wire [1:0] cblu = vpix[ 4: 3];
|
||||
wire [2:0] iblu = vpix[ 2: 0];
|
||||
|
||||
// prepare and clocking two phases of output
|
||||
reg [1:0] red0;
|
||||
reg [1:0] grn0;
|
||||
reg [1:0] blu0;
|
||||
reg [1:0] red1;
|
||||
reg [1:0] grn1;
|
||||
reg [1:0] blu1;
|
||||
|
||||
always @(posedge clk)
|
||||
begin
|
||||
red0 <= (!pwm[ired][{phase, 1'b0}] | &cred) ? cred : (cred + 2'b1);
|
||||
grn0 <= (!pwm[igrn][{phase, 1'b0}] | &cgrn) ? cgrn : (cgrn + 2'b1);
|
||||
blu0 <= (!pwm[iblu][{phase, 1'b0}] | &cblu) ? cblu : (cblu + 2'b1);
|
||||
red1 <= (!pwm[ired][{phase, 1'b1}] | &cred) ? cred : (cred + 2'b1);
|
||||
grn1 <= (!pwm[igrn][{phase, 1'b1}] | &cgrn) ? cgrn : (cgrn + 2'b1);
|
||||
blu1 <= (!pwm[iblu][{phase, 1'b1}] | &cblu) ? cblu : (cblu + 2'b1);
|
||||
end
|
||||
|
||||
`ifdef IDE_VDAC
|
||||
// no PWM
|
||||
assign vred = cred;
|
||||
assign vgrn = cgrn;
|
||||
assign vblu = cblu;
|
||||
`elsif IDE_VDAC2
|
||||
// no PWM
|
||||
assign vred = cred;
|
||||
assign vgrn = cgrn;
|
||||
assign vblu = cblu;
|
||||
`else
|
||||
// output muxing for 56MHz PWM resolution
|
||||
assign vred = clk ? red1 : red0;
|
||||
assign vgrn = clk ? grn1 : grn0;
|
||||
assign vblu = clk ? blu1 : blu0;
|
||||
`endif
|
||||
|
||||
// PWM phase
|
||||
reg [1:0] ph;
|
||||
always @(posedge clk)
|
||||
ph <= ph + 2'b1;
|
||||
|
||||
assign phase = {vga_on ? vga_line : ph[1], ph[0]};
|
||||
|
||||
// PWM
|
||||
assign pwm[0] = 8'b00000000;
|
||||
assign pwm[1] = 8'b00000001;
|
||||
assign pwm[2] = 8'b01000001;
|
||||
assign pwm[3] = 8'b01000101;
|
||||
assign pwm[4] = 8'b10100101;
|
||||
assign pwm[5] = 8'b10100111;
|
||||
assign pwm[6] = 8'b11010111;
|
||||
assign pwm[7] = 8'b11011111;
|
||||
|
||||
// CRAM
|
||||
wire [15:0] vpixel;
|
||||
dpram #(.DATAWIDTH(16), .ADDRWIDTH(8), .MEM_INIT_FILE("rtl/video/video_cram.mif")) video_cram
|
||||
(
|
||||
.clock (clk),
|
||||
.address_a(cram_addr_in),
|
||||
.data_a (cram_data_in),
|
||||
.wren_a (cram_we),
|
||||
.address_b(vdata),
|
||||
.q_b (vpixel)
|
||||
);
|
||||
|
||||
reg blank;
|
||||
always @(posedge clk) blank <= tv_blank;
|
||||
|
||||
wire [14:0] vpix = blank ? 15'b0 : vpixel[14:0];
|
||||
|
||||
assign vred = {vpix[14:10], vpix[14:12]};
|
||||
assign vgrn = {vpix[ 9: 5], vpix[ 9: 7]};
|
||||
assign vblu = {vpix[ 4: 0], vpix[ 4: 2]};
|
||||
assign vdac_mode = vpixel[15];
|
||||
dpram #(.DATAWIDTH(16), .ADDRWIDTH(8), .MEM_INIT_FILE("rtl/video/video_cram.mif")) video_cram
|
||||
(
|
||||
.clock (clk),
|
||||
.address_a(cram_addr_in),
|
||||
.data_a (cram_data_in),
|
||||
.wren_a (cram_we),
|
||||
.address_b(vdata),
|
||||
.q_b (vpixel)
|
||||
);
|
||||
/*
|
||||
altdpram video_cram
|
||||
(
|
||||
.inclock (clk),
|
||||
.data (cram_data_in),
|
||||
.rdaddress (vdata),
|
||||
.wraddress (cram_addr_in),
|
||||
.wren (cram_we),
|
||||
.q (vpixel),
|
||||
.aclr (1'b0),
|
||||
.byteena (1'b1),
|
||||
.inclocken (1'b1),
|
||||
.outclock (1'b1),
|
||||
.outclocken (1'b1),
|
||||
.rdaddressstall (1'b0),
|
||||
.rden (1'b1),
|
||||
.wraddressstall (1'b0)
|
||||
);
|
||||
|
||||
defparam
|
||||
video_cram.indata_aclr = "OFF",
|
||||
video_cram.indata_reg = "INCLOCK",
|
||||
video_cram.intended_device_family = "ACEX1K",
|
||||
video_cram.lpm_file = "../video/mem/video_cram.mif",
|
||||
video_cram.lpm_type = "altdpram",
|
||||
video_cram.outdata_aclr = "OFF",
|
||||
video_cram.outdata_reg = "UNREGISTERED",
|
||||
video_cram.rdaddress_aclr = "OFF",
|
||||
video_cram.rdaddress_reg = "INCLOCK",
|
||||
video_cram.rdcontrol_aclr = "OFF",
|
||||
video_cram.rdcontrol_reg = "UNREGISTERED",
|
||||
video_cram.width = 16,
|
||||
video_cram.widthad = 8,
|
||||
video_cram.wraddress_aclr = "OFF",
|
||||
video_cram.wraddress_reg = "INCLOCK",
|
||||
video_cram.wrcontrol_aclr = "OFF",
|
||||
video_cram.wrcontrol_reg = "INCLOCK";
|
||||
*/
|
||||
endmodule
|
||||
|
@ -1,149 +1,166 @@
|
||||
// This module latches all port parameters for video from Z80
|
||||
|
||||
|
||||
module video_ports
|
||||
(
|
||||
// clocks
|
||||
input wire clk,
|
||||
|
||||
input wire [ 7:0] d,
|
||||
input wire res,
|
||||
input wire int_start,
|
||||
input wire line_start_s,
|
||||
|
||||
// port write strobes
|
||||
input wire zborder_wr,
|
||||
input wire border_wr,
|
||||
input wire zvpage_wr,
|
||||
input wire vpage_wr,
|
||||
input wire vconf_wr,
|
||||
input wire gx_offsl_wr,
|
||||
input wire gx_offsh_wr,
|
||||
input wire gy_offsl_wr,
|
||||
input wire gy_offsh_wr,
|
||||
input wire t0x_offsl_wr,
|
||||
input wire t0x_offsh_wr,
|
||||
input wire t0y_offsl_wr,
|
||||
input wire t0y_offsh_wr,
|
||||
input wire t1x_offsl_wr,
|
||||
input wire t1x_offsh_wr,
|
||||
input wire t1y_offsl_wr,
|
||||
input wire t1y_offsh_wr,
|
||||
input wire tsconf_wr,
|
||||
input wire palsel_wr,
|
||||
input wire tmpage_wr,
|
||||
input wire t0gpage_wr,
|
||||
input wire t1gpage_wr,
|
||||
input wire sgpage_wr,
|
||||
input wire hint_beg_wr ,
|
||||
input wire vint_begl_wr,
|
||||
input wire vint_begh_wr,
|
||||
|
||||
// video parameters
|
||||
output reg [7:0] border,
|
||||
output reg [7:0] vpage,
|
||||
output reg [7:0] vconf,
|
||||
output reg [8:0] gx_offs,
|
||||
output reg [8:0] gy_offs,
|
||||
output reg [8:0] t0x_offs,
|
||||
output reg [8:0] t0y_offs,
|
||||
output reg [8:0] t1x_offs,
|
||||
output reg [8:0] t1y_offs,
|
||||
output reg [7:0] palsel,
|
||||
output reg [7:0] hint_beg,
|
||||
output reg [8:0] vint_beg,
|
||||
output reg [7:0] tsconf,
|
||||
output reg [7:0] tmpage,
|
||||
output reg [7:0] t0gpage,
|
||||
output reg [7:0] t1gpage,
|
||||
output reg [7:0] sgpage
|
||||
);
|
||||
|
||||
reg [7:0] vpage_r;
|
||||
reg [7:0] vconf_r;
|
||||
reg [7:0] t0gpage_r;
|
||||
reg [7:0] t1gpage_r;
|
||||
reg [8:0] gx_offs_r;
|
||||
reg [8:0] t0x_offs_r;
|
||||
reg [8:0] t1x_offs_r;
|
||||
reg [7:0] palsel_r;
|
||||
|
||||
wire [8:0] vint_beg_inc = vint_beg + vint_inc;
|
||||
wire [8:0] vint_beg_next = {(vint_beg_inc[8:6] == 3'b101) ? 3'b0 : vint_beg_inc[8:6], vint_beg_inc[5:0]}; // if over 319 lines, decrement 320
|
||||
// This module latches all port parameters for video from Z80
|
||||
|
||||
reg [3:0] vint_inc;
|
||||
always @(posedge clk) begin
|
||||
if (res) begin
|
||||
vint_beg <= 9'd0;
|
||||
vint_inc <= 4'b0;
|
||||
end
|
||||
else if (vint_begl_wr) vint_beg[7:0] <= d;
|
||||
else if (vint_begh_wr) begin
|
||||
vint_beg[8] <= d[0];
|
||||
vint_inc <= d[7:4];
|
||||
end
|
||||
else if (int_start) vint_beg <= vint_beg_next;
|
||||
end
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (res) begin
|
||||
vpage_r <= 8'h05;
|
||||
vconf_r <= 8'h00;
|
||||
gx_offs_r <= 9'b0;
|
||||
palsel_r <= 8'h0F;
|
||||
gy_offs <= 9'b0;
|
||||
tsconf <= 8'b0;
|
||||
hint_beg <= 8'd1;
|
||||
end
|
||||
else begin
|
||||
if (zborder_wr ) border <= {palsel[3:0], 1'b0, d[2:0]};
|
||||
if (border_wr ) border <= d;
|
||||
if (gy_offsl_wr ) gy_offs[7:0] <= d;
|
||||
if (gy_offsh_wr ) gy_offs[8] <= d[0];
|
||||
if (t0y_offsl_wr) t0y_offs[7:0] <= d;
|
||||
if (t0y_offsh_wr) t0y_offs[8] <= d[0];
|
||||
if (t1y_offsl_wr) t1y_offs[7:0] <= d;
|
||||
if (t1y_offsh_wr) t1y_offs[8] <= d[0];
|
||||
if (tsconf_wr ) tsconf <= d;
|
||||
if (tmpage_wr ) tmpage <= d;
|
||||
if (sgpage_wr ) sgpage <= d;
|
||||
if (hint_beg_wr ) hint_beg <= d;
|
||||
|
||||
if (zvpage_wr ) vpage_r <= {6'b000001, d[3], 1'b1};
|
||||
if (vpage_wr ) vpage_r <= d;
|
||||
if (vconf_wr ) vconf_r <= d;
|
||||
if (gx_offsl_wr ) gx_offs_r[7:0] <= d;
|
||||
if (gx_offsh_wr ) gx_offs_r[8] <= d[0];
|
||||
if (palsel_wr ) palsel_r <= d;
|
||||
if (t0x_offsl_wr) t0x_offs_r[7:0] <= d;
|
||||
if (t0x_offsh_wr) t0x_offs_r[8] <= d[0];
|
||||
if (t1x_offsl_wr) t1x_offs_r[7:0] <= d;
|
||||
if (t1x_offsh_wr) t1x_offs_r[8] <= d[0];
|
||||
if (t0gpage_wr ) t0gpage_r <= d;
|
||||
if (t1gpage_wr ) t1gpage_r <= d;
|
||||
end
|
||||
end
|
||||
|
||||
// latching regs at line start, delaying hires for 1 line
|
||||
always @(posedge clk) begin
|
||||
if (res)
|
||||
begin
|
||||
vpage <= 8'h05;
|
||||
vconf <= 8'h00;
|
||||
gx_offs <= 9'b0;
|
||||
palsel <= 8'h0F;
|
||||
end
|
||||
else if (zvpage_wr) vpage <= {6'b000001, d[3], 1'b1};
|
||||
else if (line_start_s) begin
|
||||
vpage <= vpage_r;
|
||||
vconf <= vconf_r;
|
||||
gx_offs <= gx_offs_r;
|
||||
palsel <= palsel_r;
|
||||
t0x_offs <= t0x_offs_r;
|
||||
t1x_offs <= t1x_offs_r;
|
||||
t0gpage <= t0gpage_r;
|
||||
t1gpage <= t1gpage_r;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
`include "tune.v"
|
||||
|
||||
module video_ports
|
||||
(
|
||||
// clocks
|
||||
input wire clk,
|
||||
|
||||
input wire [ 7:0] d,
|
||||
input wire res,
|
||||
input wire int_start,
|
||||
input wire line_start_s,
|
||||
|
||||
// port write strobes
|
||||
input wire zborder_wr,
|
||||
input wire border_wr,
|
||||
input wire zvpage_wr,
|
||||
input wire vpage_wr,
|
||||
input wire vconf_wr,
|
||||
input wire gx_offsl_wr,
|
||||
input wire gx_offsh_wr,
|
||||
input wire gy_offsl_wr,
|
||||
input wire gy_offsh_wr,
|
||||
input wire t0x_offsl_wr,
|
||||
input wire t0x_offsh_wr,
|
||||
input wire t0y_offsl_wr,
|
||||
input wire t0y_offsh_wr,
|
||||
input wire t1x_offsl_wr,
|
||||
input wire t1x_offsh_wr,
|
||||
input wire t1y_offsl_wr,
|
||||
input wire t1y_offsh_wr,
|
||||
input wire tsconf_wr,
|
||||
input wire palsel_wr,
|
||||
input wire tmpage_wr,
|
||||
input wire t0gpage_wr,
|
||||
input wire t1gpage_wr,
|
||||
input wire sgpage_wr,
|
||||
input wire hint_beg_wr ,
|
||||
input wire vint_begl_wr,
|
||||
input wire vint_begh_wr,
|
||||
|
||||
// video parameters
|
||||
output reg [7:0] border = 0,
|
||||
output reg [7:0] vpage = 0,
|
||||
output reg [7:0] vconf = 0,
|
||||
output reg [8:0] gx_offs = 0,
|
||||
output reg [8:0] gy_offs = 0,
|
||||
output reg [8:0] t0x_offs = 0,
|
||||
output reg [8:0] t0y_offs = 0,
|
||||
output reg [8:0] t1x_offs = 0,
|
||||
output reg [8:0] t1y_offs = 0,
|
||||
output reg [7:0] palsel = 0,
|
||||
output reg [7:0] hint_beg = 0,
|
||||
output reg [8:0] vint_beg = 0,
|
||||
output reg [7:0] tsconf = 0,
|
||||
output reg [7:0] tmpage = 0,
|
||||
output reg [7:0] t0gpage = 0,
|
||||
output reg [7:0] t1gpage = 0,
|
||||
output reg [7:0] sgpage = 0
|
||||
);
|
||||
|
||||
reg [7:0] vpage_r = 0;
|
||||
reg [7:0] vconf_r = 0;
|
||||
reg [7:0] t0gpage_r = 0;
|
||||
reg [7:0] t1gpage_r = 0;
|
||||
reg [8:0] gx_offs_r = 0;
|
||||
reg [8:0] t0x_offs_r = 0;
|
||||
reg [8:0] t1x_offs_r = 0;
|
||||
reg [7:0] palsel_r = 0;
|
||||
reg [3:0] vint_inc = 0;
|
||||
|
||||
wire [8:0] vint_beg_inc = vint_beg + vint_inc;
|
||||
wire [8:0] vint_beg_next = {(vint_beg_inc[8:6] == 3'b101) ? 3'b0 : vint_beg_inc[8:6], vint_beg_inc[5:0]}; // if over 319 lines, decrement 320
|
||||
|
||||
always @(posedge clk or posedge res)
|
||||
if (res)
|
||||
begin
|
||||
vint_beg <= 9'd0;
|
||||
vint_inc <= 4'b0;
|
||||
end
|
||||
else if (vint_begl_wr)
|
||||
vint_beg[7:0] <= d;
|
||||
|
||||
else if (vint_begh_wr)
|
||||
begin
|
||||
vint_beg[8] <= d[0];
|
||||
vint_inc <= d[7:4];
|
||||
end
|
||||
|
||||
else if (int_start)
|
||||
vint_beg <= vint_beg_next;
|
||||
|
||||
always @(posedge clk or posedge res)
|
||||
if (res)
|
||||
begin
|
||||
vpage_r <= 8'h05;
|
||||
vconf_r <= 8'h00;
|
||||
gx_offs_r <= 9'b0;
|
||||
palsel_r <= 8'h0F;
|
||||
gy_offs <= 9'b0;
|
||||
tsconf <= 8'b0;
|
||||
hint_beg <= 8'd1;
|
||||
end
|
||||
|
||||
else
|
||||
begin
|
||||
if (zborder_wr ) border <= {palsel[3:0], 1'b0, d[2:0]};
|
||||
if (border_wr ) border <= d;
|
||||
if (gy_offsl_wr ) gy_offs[7:0] <= d;
|
||||
if (gy_offsh_wr ) gy_offs[8] <= d[0];
|
||||
if (t0y_offsl_wr) t0y_offs[7:0] <= d;
|
||||
if (t0y_offsh_wr) t0y_offs[8] <= d[0];
|
||||
if (t1y_offsl_wr) t1y_offs[7:0] <= d;
|
||||
if (t1y_offsh_wr) t1y_offs[8] <= d[0];
|
||||
if (tsconf_wr ) tsconf <= d;
|
||||
if (tmpage_wr ) tmpage <= d;
|
||||
if (sgpage_wr ) sgpage <= d;
|
||||
if (hint_beg_wr ) hint_beg <= d;
|
||||
|
||||
if (zvpage_wr ) vpage_r <= {6'b000001, d[3], 1'b1};
|
||||
if (vpage_wr ) vpage_r <= d;
|
||||
if (vconf_wr ) vconf_r <= d;
|
||||
if (gx_offsl_wr ) gx_offs_r[7:0] <= d;
|
||||
if (gx_offsh_wr ) gx_offs_r[8] <= d[0];
|
||||
if (palsel_wr ) palsel_r <= d;
|
||||
if (t0x_offsl_wr) t0x_offs_r[7:0] <= d;
|
||||
if (t0x_offsh_wr) t0x_offs_r[8] <= d[0];
|
||||
if (t1x_offsl_wr) t1x_offs_r[7:0] <= d;
|
||||
if (t1x_offsh_wr) t1x_offs_r[8] <= d[0];
|
||||
if (t0gpage_wr ) t0gpage_r <= d;
|
||||
if (t1gpage_wr ) t1gpage_r <= d;
|
||||
end
|
||||
|
||||
// latching regs at line start, delaying hires for 1 line
|
||||
always @(posedge clk or posedge res)
|
||||
if (res)
|
||||
begin
|
||||
vpage <= 8'h05;
|
||||
`ifdef FORCE_TEXT_MODE
|
||||
vconf <= 8'h83;
|
||||
`else
|
||||
vconf <= 8'h00;
|
||||
`endif
|
||||
gx_offs <= 9'b0;
|
||||
palsel <= 8'h0F;
|
||||
end
|
||||
|
||||
else if (zvpage_wr)
|
||||
vpage <= {6'b000001, d[3], 1'b1};
|
||||
|
||||
else if (line_start_s)
|
||||
begin
|
||||
vpage <= vpage_r;
|
||||
`ifndef FORCE_TEXT_MODE
|
||||
vconf <= vconf_r;
|
||||
`endif
|
||||
gx_offs <= gx_offs_r;
|
||||
palsel <= palsel_r;
|
||||
t0x_offs <= t0x_offs_r;
|
||||
t1x_offs <= t1x_offs_r;
|
||||
t0gpage <= t0gpage_r;
|
||||
t1gpage <= t1gpage_r;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
@ -1,84 +1,87 @@
|
||||
// This module renders video data for output
|
||||
|
||||
// This module renders video data for output
|
||||
|
||||
`include "tune.v"
|
||||
|
||||
module video_render
|
||||
(
|
||||
// clocks
|
||||
input wire clk, c1,
|
||||
|
||||
// video controls
|
||||
input wire hvpix,
|
||||
input wire hvtspix,
|
||||
input wire nogfx,
|
||||
input wire notsu,
|
||||
input wire gfxovr,
|
||||
input wire flash,
|
||||
input wire hires,
|
||||
input wire [3:0] psel,
|
||||
input wire [3:0] palsel,
|
||||
|
||||
// mode controls
|
||||
input wire [1:0] render_mode,
|
||||
|
||||
// video data
|
||||
input wire [31:0] data,
|
||||
input wire [ 7:0] border_in,
|
||||
input wire [ 7:0] tsdata_in,
|
||||
output wire [ 7:0] vplex_out
|
||||
);
|
||||
|
||||
localparam R_ZX = 2'h0;
|
||||
localparam R_HC = 2'h1;
|
||||
localparam R_XC = 2'h2;
|
||||
localparam R_TX = 2'h3;
|
||||
|
||||
// ZX graphics
|
||||
wire [15:0] zx_gfx = data[15: 0];
|
||||
wire [15:0] zx_atr = data[31:16];
|
||||
wire zx_dot = zx_gfx[{psel[3], ~psel[2:0]}];
|
||||
wire [7:0] zx_attr = ~psel[3] ? zx_atr[7:0] : zx_atr[15:8];
|
||||
wire [7:0] zx_pix = {palsel, zx_attr[6], zx_dot ^ (flash & zx_attr[7]) ? zx_attr[2:0] : zx_attr[5:3]};
|
||||
|
||||
// text graphics
|
||||
// (it uses common renderer with ZX, but different attributes)
|
||||
wire [7:0] tx_pix = {palsel, zx_dot ? zx_attr[3:0] : zx_attr[7:4]};
|
||||
|
||||
// 16c graphics
|
||||
wire [3:0] hc_dot[0:3];
|
||||
assign hc_dot[0] = data[ 7: 4];
|
||||
assign hc_dot[1] = data[ 3: 0];
|
||||
assign hc_dot[2] = data[15:12];
|
||||
assign hc_dot[3] = data[11: 8];
|
||||
wire [7:0] hc_pix = {palsel, hc_dot[psel[1:0]]};
|
||||
|
||||
// 256c graphics
|
||||
wire [7:0] xc_dot[0:1];
|
||||
assign xc_dot[0] = data[ 7: 0];
|
||||
assign xc_dot[1] = data[15: 8];
|
||||
wire [7:0] xc_pix = xc_dot[psel[0]];
|
||||
|
||||
// mode selects
|
||||
wire [7:0] pix[0:3];
|
||||
assign pix[R_ZX] = zx_pix; // ZX
|
||||
assign pix[R_HC] = hc_pix; // 16c
|
||||
assign pix[R_XC] = xc_pix; // 256c
|
||||
assign pix[R_TX] = tx_pix; // text
|
||||
|
||||
wire pixv[0:3];
|
||||
assign pixv[R_ZX] = zx_dot ^ (flash & zx_attr[7]);
|
||||
assign pixv[R_HC] = |hc_dot[psel[1:0]];
|
||||
assign pixv[R_XC] = |xc_dot[psel[0]];
|
||||
assign pixv[R_TX] = zx_dot;
|
||||
|
||||
// video plex muxer
|
||||
wire tsu_visible = (|tsdata_in[3:0] && !notsu);
|
||||
wire gfx_visible = (pixv[render_mode] && !nogfx);
|
||||
wire [7:0] video1 = tsu_visible ? tsdata_in : (nogfx ? border_in : pix[render_mode]);
|
||||
wire [7:0] video2 = gfx_visible ? pix[render_mode] : (tsu_visible ? tsdata_in : border_in);
|
||||
wire [7:0] video = hvpix ? (gfxovr ? video2 : video1) : ((hvtspix && tsu_visible) ? tsdata_in : border_in);
|
||||
assign vplex_out = hires ? {temp, video[3:0]} : video; // in hi-res plex contains two pixels 4 bits each
|
||||
|
||||
reg [3:0] temp;
|
||||
always @(posedge clk) if (c1) temp <= video[3:0];
|
||||
|
||||
endmodule
|
||||
|
||||
(
|
||||
// clocks
|
||||
input wire clk, c1,
|
||||
|
||||
// video controls
|
||||
input wire hvpix,
|
||||
input wire hvtspix,
|
||||
input wire nogfx,
|
||||
input wire notsu,
|
||||
input wire gfxovr,
|
||||
input wire flash,
|
||||
input wire hires,
|
||||
input wire [3:0] psel,
|
||||
input wire [3:0] palsel,
|
||||
|
||||
// mode controls
|
||||
input wire [1:0] render_mode,
|
||||
|
||||
// video data
|
||||
input wire [31:0] data,
|
||||
input wire [ 7:0] border_in,
|
||||
input wire [ 7:0] tsdata_in,
|
||||
output wire [ 7:0] vplex_out
|
||||
);
|
||||
|
||||
localparam R_ZX = 2'h0;
|
||||
localparam R_HC = 2'h1;
|
||||
localparam R_XC = 2'h2;
|
||||
localparam R_TX = 2'h3;
|
||||
|
||||
reg [3:0] temp;
|
||||
|
||||
// ZX graphics
|
||||
wire [15:0] zx_gfx = data[15: 0];
|
||||
wire [15:0] zx_atr = data[31:16];
|
||||
wire zx_dot = zx_gfx[{psel[3], ~psel[2:0]}];
|
||||
wire [7:0] zx_attr = ~psel[3] ? zx_atr[7:0] : zx_atr[15:8];
|
||||
wire [7:0] zx_pix = {palsel, zx_attr[6], zx_dot ^ (flash & zx_attr[7]) ? zx_attr[2:0] : zx_attr[5:3]};
|
||||
|
||||
// text graphics
|
||||
// (uses common renderer with ZX, but different attributes)
|
||||
wire [7:0] tx_pix = {palsel, zx_dot ? zx_attr[3:0] : zx_attr[7:4]};
|
||||
|
||||
// 16c graphics
|
||||
wire [3:0] hc_dot[0:3];
|
||||
assign hc_dot[0] = data[ 7: 4];
|
||||
assign hc_dot[1] = data[ 3: 0];
|
||||
assign hc_dot[2] = data[15:12];
|
||||
assign hc_dot[3] = data[11: 8];
|
||||
wire [7:0] hc_pix = {palsel, hc_dot[psel[1:0]]};
|
||||
|
||||
// 256c graphics
|
||||
wire [7:0] xc_dot[0:1];
|
||||
assign xc_dot[0] = data[ 7: 0];
|
||||
assign xc_dot[1] = data[15: 8];
|
||||
wire [7:0] xc_pix = xc_dot[psel[0]];
|
||||
|
||||
// mode selects
|
||||
wire [7:0] pix[0:3];
|
||||
assign pix[R_ZX] = zx_pix; // ZX
|
||||
assign pix[R_HC] = hc_pix; // 16c
|
||||
assign pix[R_XC] = xc_pix; // 256c
|
||||
assign pix[R_TX] = tx_pix; // text
|
||||
|
||||
wire pixv[0:3];
|
||||
assign pixv[R_ZX] = zx_dot ^ (flash & zx_attr[7]);
|
||||
assign pixv[R_HC] = |hc_dot[psel[1:0]];
|
||||
assign pixv[R_XC] = |xc_dot[psel[0]];
|
||||
assign pixv[R_TX] = zx_dot;
|
||||
|
||||
// video plex muxer
|
||||
wire tsu_visible = (|tsdata_in[3:0] && !notsu);
|
||||
wire gfx_visible = (pixv[render_mode] && !nogfx);
|
||||
wire [7:0] video1 = tsu_visible ? tsdata_in : (nogfx ? border_in : pix[render_mode]);
|
||||
wire [7:0] video2 = gfx_visible ? pix[render_mode] : (tsu_visible ? tsdata_in : border_in);
|
||||
wire [7:0] video = hvpix ? (gfxovr ? video2 : video1) : ((hvtspix && tsu_visible) ? tsdata_in : border_in);
|
||||
assign vplex_out = hires ? {temp, video[3:0]} : video; // in hi-res plex contains two pixels 4 bits each
|
||||
|
||||
always @(posedge clk) if (c1)
|
||||
temp <= video[3:0];
|
||||
|
||||
endmodule
|
||||
|
@ -1,169 +1,243 @@
|
||||
|
||||
// This module generates all video raster signals
|
||||
|
||||
|
||||
`include "tune.v"
|
||||
|
||||
// This module generates video raster signals
|
||||
|
||||
module video_sync
|
||||
(
|
||||
// clocks
|
||||
input wire clk, f1, c0, c1, c3, pix_stb,
|
||||
|
||||
// video parameters
|
||||
input wire [8:0] hpix_beg,
|
||||
input wire [8:0] hpix_end,
|
||||
input wire [8:0] vpix_beg,
|
||||
input wire [8:0] vpix_end,
|
||||
input wire [8:0] hpix_beg_ts,
|
||||
input wire [8:0] hpix_end_ts,
|
||||
input wire [8:0] vpix_beg_ts,
|
||||
input wire [8:0] vpix_end_ts,
|
||||
input wire [4:0] go_offs,
|
||||
input wire [1:0] x_offs,
|
||||
input wire [7:0] hint_beg,
|
||||
input wire [8:0] vint_beg,
|
||||
input wire [7:0] cstart,
|
||||
input wire [8:0] rstart,
|
||||
|
||||
// video syncs
|
||||
output reg hsync,
|
||||
output reg vsync,
|
||||
|
||||
// video controls
|
||||
input wire nogfx,
|
||||
output wire v_pf,
|
||||
output wire hpix,
|
||||
output wire vpix,
|
||||
output wire v_ts,
|
||||
output wire hvpix,
|
||||
output wire hvtspix,
|
||||
output wire tv_hblank,
|
||||
output wire tv_vblank,
|
||||
output wire frame_start,
|
||||
output wire line_start_s,
|
||||
output wire pix_start,
|
||||
output wire ts_start,
|
||||
output wire frame,
|
||||
output wire flash,
|
||||
|
||||
// video counters
|
||||
output wire [8:0] ts_raddr,
|
||||
output reg [8:0] lcount,
|
||||
output reg [7:0] cnt_col,
|
||||
output reg [8:0] cnt_row,
|
||||
output reg cptr,
|
||||
output reg [3:0] scnt,
|
||||
|
||||
// DRAM
|
||||
input wire video_pre_next,
|
||||
output reg video_go,
|
||||
|
||||
// ZX controls
|
||||
input wire y_offs_wr,
|
||||
output wire int_start
|
||||
);
|
||||
|
||||
localparam HSYNC_BEG = 9'd11;
|
||||
localparam HSYNC_END = 9'd43;
|
||||
localparam HBLNK_BEG = 9'd00;
|
||||
localparam HBLNK_END = 9'd88;
|
||||
localparam HSYNCV_BEG = 9'd5;
|
||||
localparam HSYNCV_END = 9'd31;
|
||||
localparam HBLNKV_END = 9'd42;
|
||||
localparam HPERIOD = 9'd448;
|
||||
|
||||
localparam VSYNC_BEG = 9'd08;
|
||||
localparam VSYNC_END = 9'd11;
|
||||
localparam VBLNK_BEG = 9'd00;
|
||||
localparam VBLNK_END = 9'd32;
|
||||
localparam VPERIOD = 9'd320;
|
||||
|
||||
// counters
|
||||
reg [8:0] hcount = 0;
|
||||
reg [8:0] vcount = 0;
|
||||
|
||||
// horizontal TV (7 MHz)
|
||||
always @(posedge clk) if (c3) hcount <= line_start ? 9'b0 : hcount + 9'b1;
|
||||
|
||||
// vertical TV (15.625 kHz)
|
||||
always @(posedge clk) if (line_start_s) vcount <= (vcount == (VPERIOD - 1)) ? 9'b0 : vcount + 9'b1;
|
||||
|
||||
// column address for DRAM
|
||||
always @(posedge clk) begin
|
||||
if (line_start2) begin
|
||||
cnt_col <= cstart;
|
||||
cptr <= 1'b0;
|
||||
end
|
||||
else if (video_pre_next) begin
|
||||
cnt_col <= cnt_col + 8'b1;
|
||||
cptr <= ~cptr;
|
||||
end
|
||||
end
|
||||
|
||||
// row address for DRAM
|
||||
always @(posedge clk) begin if (c3)
|
||||
if (vis_start || (line_start && y_offs_wr_r)) cnt_row <= rstart;
|
||||
else if (line_start && vpix) cnt_row <= cnt_row + 9'b1;
|
||||
end
|
||||
|
||||
// pixel counter
|
||||
always @(posedge clk) if (pix_stb) scnt <= pix_start ? 4'b0 : scnt + 4'b1; // f1 or c3
|
||||
|
||||
// TS-line counter
|
||||
assign ts_raddr = hcount - hpix_beg_ts;
|
||||
|
||||
always @(posedge clk) if (ts_start_coarse) lcount <= vcount - vpix_beg_ts + 9'b1;
|
||||
|
||||
// Y offset re-latch trigger
|
||||
reg y_offs_wr_r;
|
||||
always @(posedge clk) begin
|
||||
if (y_offs_wr) y_offs_wr_r <= 1'b1;
|
||||
else if (line_start_s) y_offs_wr_r <= 1'b0;
|
||||
end
|
||||
|
||||
// FLASH generator
|
||||
reg [4:0] flash_ctr;
|
||||
assign frame = flash_ctr[0];
|
||||
assign flash = flash_ctr[4];
|
||||
always @(posedge clk) begin
|
||||
if (frame_start && c3) begin
|
||||
flash_ctr <= flash_ctr + 5'b1;
|
||||
end
|
||||
end
|
||||
|
||||
// sync strobes
|
||||
wire hs = (hcount >= HSYNC_BEG) && (hcount < HSYNC_END);
|
||||
wire vs = (vcount >= VSYNC_BEG) && (vcount < VSYNC_END);
|
||||
|
||||
assign tv_hblank = (hcount > HBLNK_BEG) && (hcount <= HBLNK_END);
|
||||
assign tv_vblank = (vcount >= VBLNK_BEG) && (vcount < VBLNK_END);
|
||||
|
||||
assign hvpix = hpix && vpix;
|
||||
|
||||
assign hpix = (hcount >= hpix_beg) && (hcount < hpix_end);
|
||||
|
||||
assign vpix = (vcount >= vpix_beg) && (vcount < vpix_end);
|
||||
(
|
||||
// clocks
|
||||
input wire clk, f1, c0, c3, pix_stb,
|
||||
|
||||
assign hvtspix = htspix && vtspix;
|
||||
wire htspix = (hcount >= hpix_beg_ts) && (hcount < hpix_end_ts);
|
||||
wire vtspix = (vcount >= vpix_beg_ts) && (vcount < vpix_end_ts);
|
||||
// video parameters
|
||||
input wire [8:0] hpix_beg,
|
||||
input wire [8:0] hpix_end,
|
||||
input wire [8:0] vpix_beg,
|
||||
input wire [8:0] vpix_end,
|
||||
input wire [8:0] hpix_beg_ts,
|
||||
input wire [8:0] hpix_end_ts,
|
||||
input wire [8:0] vpix_beg_ts,
|
||||
input wire [8:0] vpix_end_ts,
|
||||
input wire [4:0] go_offs,
|
||||
input wire [1:0] x_offs,
|
||||
input wire [7:0] hint_beg,
|
||||
input wire [8:0] vint_beg,
|
||||
input wire [7:0] cstart,
|
||||
input wire [8:0] rstart,
|
||||
|
||||
assign v_ts = (vcount >= (vpix_beg_ts - 1)) && (vcount < (vpix_end_ts - 1)); // vertical TS window
|
||||
assign v_pf = (vcount >= (vpix_beg_ts - 17)) && (vcount < (vpix_end_ts - 9)); // vertical tilemap prefetch window
|
||||
|
||||
always @(posedge clk) video_go <= (hcount >= (hpix_beg - go_offs - x_offs)) && (hcount < (hpix_end - go_offs - x_offs + 4)) && vpix && !nogfx;
|
||||
|
||||
wire line_start = hcount == (HPERIOD - 1);
|
||||
assign line_start_s = line_start && c3;
|
||||
wire line_start2 = hcount == (HSYNC_END - 1);
|
||||
assign frame_start = line_start && (vcount == (VPERIOD - 1));
|
||||
wire vis_start = line_start && (vcount == (VBLNK_END - 1));
|
||||
assign pix_start = hcount == (hpix_beg - x_offs - 1);
|
||||
wire ts_start_coarse = hcount == (hpix_beg_ts - 1);
|
||||
assign ts_start = c3 && ts_start_coarse;
|
||||
assign int_start = (hcount == {hint_beg, 1'b0}) && (vcount == vint_beg) && c0;
|
||||
|
||||
always @(posedge clk) begin
|
||||
hsync <= hs;
|
||||
vsync <= vs;
|
||||
end
|
||||
|
||||
endmodule
|
||||
// video syncs
|
||||
output reg hsync,
|
||||
output reg vsync,
|
||||
output reg csync,
|
||||
|
||||
// video controls
|
||||
input wire cfg_60hz,
|
||||
input wire vga_on,
|
||||
output reg v60hz = 0,
|
||||
input wire nogfx,
|
||||
output wire v_pf,
|
||||
output wire hpix,
|
||||
output wire vpix,
|
||||
output wire v_ts,
|
||||
output wire hvpix,
|
||||
output wire hvtspix,
|
||||
output wire tv_blank,
|
||||
output wire vga_blank,
|
||||
output wire vga_line,
|
||||
output wire frame_start,
|
||||
output wire line_start_s,
|
||||
output wire pix_start,
|
||||
output wire ts_start,
|
||||
output wire frame,
|
||||
output wire flash,
|
||||
|
||||
// video counters
|
||||
output wire [9:0] vga_cnt_in,
|
||||
output wire [9:0] vga_cnt_out,
|
||||
output wire [8:0] ts_raddr,
|
||||
output reg [8:0] lcount = 0,
|
||||
output reg [7:0] cnt_col = 0,
|
||||
output reg [8:0] cnt_row = 0,
|
||||
output reg cptr = 0,
|
||||
output reg [3:0] scnt = 0,
|
||||
`ifdef PENT_312
|
||||
output wire [4:0] hcnt,
|
||||
output wire upper8,
|
||||
`endif
|
||||
|
||||
// DRAM
|
||||
input wire video_pre_next,
|
||||
output reg video_go = 0,
|
||||
|
||||
// ZX controls
|
||||
input wire y_offs_wr,
|
||||
output wire int_start
|
||||
);
|
||||
|
||||
localparam HSYNC_BEG = 9'd11;
|
||||
localparam HSYNC_END = 9'd43;
|
||||
localparam HBLNK_BEG = 9'd00;
|
||||
localparam HBLNK_END = 9'd88;
|
||||
localparam HSYNCV_BEG = 9'd5;
|
||||
localparam HSYNCV_END = 9'd31;
|
||||
localparam HBLNKV_END = 9'd42;
|
||||
localparam HPERIOD = 9'd448;
|
||||
|
||||
localparam VSYNC_BEG_50 = 9'd08;
|
||||
localparam VSYNC_END_50 = 9'd11;
|
||||
localparam VBLNK_BEG_50 = 9'd00;
|
||||
`ifdef PENT_312
|
||||
localparam VBLNK_END_50 = 9'd24;
|
||||
localparam VPERIOD_50 = 9'd312;
|
||||
`else
|
||||
localparam VBLNK_END_50 = 9'd32;
|
||||
localparam VPERIOD_50 = 9'd320;
|
||||
`endif
|
||||
|
||||
localparam VSYNC_BEG_60 = 9'd04;
|
||||
localparam VSYNC_END_60 = 9'd07;
|
||||
localparam VBLNK_BEG_60 = 9'd00;
|
||||
localparam VBLNK_END_60 = 9'd22;
|
||||
localparam VPERIOD_60 = 9'd262;
|
||||
|
||||
wire [8:0] vsync_beg = v60hz ? VSYNC_BEG_60 : VSYNC_BEG_50;
|
||||
wire [8:0] vsync_end = v60hz ? VSYNC_END_60 : VSYNC_END_50;
|
||||
wire [8:0] vblnk_beg = v60hz ? VBLNK_BEG_60 : VBLNK_BEG_50;
|
||||
wire [8:0] vblnk_end = v60hz ? VBLNK_END_60 : VBLNK_END_50;
|
||||
wire [8:0] vperiod = v60hz ? VPERIOD_60 : VPERIOD_50;
|
||||
|
||||
`ifdef PENT_312
|
||||
assign hcnt = hcount[4:0];
|
||||
assign upper8 = vcount < 8;
|
||||
`endif
|
||||
|
||||
reg [8:0] hcount = 0;
|
||||
reg [8:0] vcount = 0;
|
||||
reg [8:0] cnt_out = 0;
|
||||
reg vga_hblank = 0;
|
||||
reg vga_vblank = 0;
|
||||
|
||||
wire line_start = hcount == (HPERIOD - 1);
|
||||
wire line_start2 = hcount == (HSYNC_END - 1);
|
||||
assign line_start_s = line_start && c3;
|
||||
assign frame_start = line_start && (vcount == (vperiod - 1));
|
||||
wire vis_start = line_start && (vcount == (vblnk_end - 1));
|
||||
assign pix_start = hcount == (hpix_beg - x_offs - 1);
|
||||
wire ts_start_coarse = hcount == (hpix_beg_ts - 1);
|
||||
assign ts_start = c3 && ts_start_coarse;
|
||||
assign int_start = (hcount == {hint_beg, 1'b0}) && (vcount == vint_beg) && c0;
|
||||
wire vga_pix_start = ((hcount == (HBLNKV_END)) || (hcount == (HBLNKV_END + HPERIOD/2)));
|
||||
wire hs_vga = ((hcount >= HSYNCV_BEG) && (hcount < HSYNCV_END)) || ((hcount >= (HSYNCV_BEG + HPERIOD/2)) && (hcount < (HSYNCV_END + HPERIOD/2)));
|
||||
assign vga_line = (hcount >= HPERIOD/2);
|
||||
wire hs = (hcount >= HSYNC_BEG) && (hcount < HSYNC_END);
|
||||
wire vs = (vcount >= vsync_beg) && (vcount < vsync_end);
|
||||
assign vga_cnt_in = {vcount[0], hcount - HBLNK_END};
|
||||
assign vga_cnt_out = {~vcount[0], cnt_out};
|
||||
wire tv_hblank = (hcount > HBLNK_BEG) && (hcount <= HBLNK_END);
|
||||
wire tv_vblank = (vcount >= vblnk_beg) && (vcount < vblnk_end);
|
||||
assign vga_blank = vga_hblank || vga_vblank;
|
||||
assign tv_blank = tv_hblank || tv_vblank;
|
||||
|
||||
// horizontal TV (7 MHz)
|
||||
always @(posedge clk) if (c3)
|
||||
hcount <= line_start ? 9'b0 : hcount + 9'b1;
|
||||
|
||||
// vertical TV (15.625 kHz)
|
||||
always @(posedge clk) if (line_start_s)
|
||||
vcount <= (vcount == (vperiod - 1)) ? 9'b0 : vcount + 9'b1;
|
||||
|
||||
// horizontal VGA (14MHz)
|
||||
always @(posedge clk) if (f1)
|
||||
cnt_out <= vga_pix_start && c3 ? 9'b0 : cnt_out + 9'b1;
|
||||
|
||||
// column address for DRAM
|
||||
always @(posedge clk)
|
||||
begin
|
||||
if (line_start2)
|
||||
begin
|
||||
cnt_col <= cstart;
|
||||
cptr <= 1'b0;
|
||||
end
|
||||
|
||||
else if (video_pre_next)
|
||||
begin
|
||||
cnt_col <= cnt_col + 8'b1;
|
||||
cptr <= ~cptr;
|
||||
end
|
||||
end
|
||||
|
||||
// row address for DRAM
|
||||
reg y_offs_wr_r;
|
||||
|
||||
always @(posedge clk) if (c3)
|
||||
if (vis_start || (line_start && y_offs_wr_r))
|
||||
cnt_row <= rstart;
|
||||
else
|
||||
if (line_start && vpix)
|
||||
cnt_row <= cnt_row + 9'b1;
|
||||
|
||||
// pixel counter
|
||||
always @(posedge clk) if (pix_stb) // f1 or c3
|
||||
scnt <= pix_start ? 4'b0 : scnt + 4'b1;
|
||||
|
||||
// TS-line counter
|
||||
assign ts_raddr = hcount - hpix_beg_ts;
|
||||
|
||||
always @(posedge clk)
|
||||
if (ts_start_coarse)
|
||||
lcount <= vcount - vpix_beg_ts + 9'b1;
|
||||
|
||||
// Y offset re-latch trigger
|
||||
always @(posedge clk)
|
||||
if (y_offs_wr)
|
||||
y_offs_wr_r <= 1'b1;
|
||||
else if (line_start_s)
|
||||
y_offs_wr_r <= 1'b0;
|
||||
|
||||
// FLASH generator
|
||||
reg [4:0] flash_ctr;
|
||||
assign frame = flash_ctr[0];
|
||||
assign flash = flash_ctr[4];
|
||||
|
||||
always @(posedge clk)
|
||||
if (frame_start && c3)
|
||||
begin
|
||||
flash_ctr <= flash_ctr + 5'b1;
|
||||
// re-sync 60Hz mode selector
|
||||
`ifdef FORCE_60HZ
|
||||
v60hz <= 1'b1;
|
||||
`elsif ENABLE_60HZ
|
||||
v60hz <= !cfg_60hz;
|
||||
`else
|
||||
v60hz <= 1'b0;
|
||||
`endif
|
||||
end
|
||||
|
||||
// sync strobes
|
||||
wire vga_hblank1 = (cnt_out > 9'd359);
|
||||
always @(posedge clk) if (f1) // fix me - bydlocode !!!
|
||||
vga_hblank <= vga_hblank1;
|
||||
|
||||
assign hvpix = hpix && vpix;
|
||||
assign hpix = (hcount >= hpix_beg) && (hcount < hpix_end);
|
||||
assign vpix = (vcount >= vpix_beg) && (vcount < vpix_end);
|
||||
|
||||
wire htspix = (hcount >= hpix_beg_ts) && (hcount < hpix_end_ts);
|
||||
wire vtspix = (vcount >= vpix_beg_ts) && (vcount < vpix_end_ts);
|
||||
assign hvtspix = htspix && vtspix;
|
||||
|
||||
assign v_ts = (vcount >= (vpix_beg_ts - 1)) && (vcount < (vpix_end_ts - 1)); // vertical TS window
|
||||
assign v_pf = (vcount >= (vpix_beg_ts - 17)) && (vcount < (vpix_end_ts - 9)); // vertical tilemap prefetch window
|
||||
|
||||
always @(posedge clk)
|
||||
video_go <= (hcount >= (hpix_beg - go_offs - x_offs)) && (hcount < (hpix_end - go_offs - x_offs + 4)) && vpix && !nogfx;
|
||||
|
||||
always @(posedge clk) if (line_start_s) // fix me - bydlocode !!!
|
||||
vga_vblank <= tv_vblank;
|
||||
|
||||
always @(posedge clk)
|
||||
begin
|
||||
hsync <= vga_on ? hs_vga : hs;
|
||||
vsync <= vs;
|
||||
csync <= ~(vs ^ hs);
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,383 +1,459 @@
|
||||
|
||||
// This is the Tile Sprite Processing Unit
|
||||
|
||||
// Tiles map address:
|
||||
// bits desc
|
||||
// 20:13 tmpage
|
||||
// 12:
|
||||
|
||||
// Graphics address:
|
||||
// bits desc
|
||||
// 20:13 Xgpage
|
||||
// 15:7 line (bits 15:13 are added) - 512 lines
|
||||
// 6:0 word within line - 128 words = 512 pixels
|
||||
|
||||
|
||||
module video_ts
|
||||
(
|
||||
|
||||
// clocks
|
||||
input wire clk,
|
||||
|
||||
// video controls
|
||||
input wire start,
|
||||
input wire [8:0] line, // = vcount - vpix_beg + 9'b1;
|
||||
input wire v_ts,
|
||||
input wire v_pf, // vertical tilemap prefetch window
|
||||
|
||||
// video config
|
||||
input wire [7:0] tsconf,
|
||||
input wire [7:0] t0gpage,
|
||||
input wire [7:0] t1gpage,
|
||||
input wire [7:0] sgpage,
|
||||
input wire [7:0] tmpage,
|
||||
input wire [5:0] num_tiles,
|
||||
input wire [8:0] t0x_offs,
|
||||
input wire [8:0] t1x_offs,
|
||||
input wire [8:0] t0y_offs,
|
||||
input wire [8:0] t1y_offs,
|
||||
input wire [1:0] t0_palsel,
|
||||
input wire [1:0] t1_palsel,
|
||||
|
||||
// SFYS interface
|
||||
input wire [7:0] sfile_addr_in,
|
||||
input wire [15:0] sfile_data_in,
|
||||
input wire sfile_we,
|
||||
|
||||
// renderer interface
|
||||
output wire tsr_go,
|
||||
output wire [5:0] tsr_addr, // graphics address within the line
|
||||
output wire [8:0] tsr_line, // bitmap line
|
||||
output wire [7:0] tsr_page, // bitmap 1st page
|
||||
output wire [8:0] tsr_x, // addr in buffer (0-359 visibles)
|
||||
output wire [2:0] tsr_xs, // size (8-64 pix)
|
||||
output wire tsr_xf, // X flip
|
||||
output wire [3:0] tsr_pal, // palette
|
||||
input wire tsr_rdy, // renderer is done and ready to receive a new task
|
||||
|
||||
// DRAM interface
|
||||
output wire [20:0] dram_addr,
|
||||
output wire dram_req,
|
||||
input wire dram_next,
|
||||
input wire [15:0] dram_rdata
|
||||
);
|
||||
|
||||
|
||||
// config
|
||||
wire s_en = tsconf[7];
|
||||
wire t1_en = tsconf[6];
|
||||
wire t0_en = tsconf[5];
|
||||
wire t1z_en = tsconf[3];
|
||||
wire t0z_en = tsconf[2];
|
||||
|
||||
|
||||
// TS renderer interface
|
||||
assign tsr_go = sprite_go || tile_go;
|
||||
assign tsr_x = sprites ? sprites_x : tile_x;
|
||||
assign tsr_xs = sprites ? sprites_xs : 3'd0;
|
||||
assign tsr_xf = sprites ? sprites_xf : t_xflp;
|
||||
assign tsr_page = sprites ? sgpage : tile_page;
|
||||
assign tsr_line = sprites ? sprites_line : tile_line;
|
||||
assign tsr_addr = sprites ? sprites_addr : tile_addr;
|
||||
assign tsr_pal = sprites ? s_pal : tile_pal;
|
||||
|
||||
|
||||
// Layer selectors control
|
||||
|
||||
localparam LAYERS = 6; // Total number of layers to process
|
||||
localparam TM = 0; // Individual layers
|
||||
localparam S0 = 1;
|
||||
localparam T0 = 2;
|
||||
localparam S1 = 3;
|
||||
localparam T1 = 4;
|
||||
localparam S2 = 5;
|
||||
|
||||
wire tmap = layer_active[TM];
|
||||
wire sprites = layer_active[S0] || layer_active[S1] || layer_active[S2];
|
||||
wire tiles = layer_active[T0] || layer_active[T1];
|
||||
|
||||
reg [LAYERS-1:0] layer;
|
||||
always @(posedge clk)
|
||||
if (start)
|
||||
layer <= 1;
|
||||
else if (|(layer & layer_skip))
|
||||
layer <= {layer[LAYERS-2:0], 1'b0};
|
||||
|
||||
reg [LAYERS-1:0] layer_active;
|
||||
always @(posedge clk)
|
||||
if (start)
|
||||
layer_active <= 0;
|
||||
else
|
||||
layer_active <= layer & ~layer_skip;
|
||||
|
||||
wire [LAYERS-1:0] layer_enabled = {s_en, t1_en, s_en, t0_en, s_en, t1_en || t0_en};
|
||||
wire [LAYERS-1:0] layer_allowed = {{5{v_ts}}, v_pf};
|
||||
wire [LAYERS-1:0] layer_end = {spr_end[2], tile_end[1], spr_end[1], tile_end[0], spr_end[0], tm_end};
|
||||
|
||||
reg [LAYERS-1:0] layer_skip;
|
||||
always @(posedge clk)
|
||||
if (start)
|
||||
layer_skip <= ~(layer_enabled & layer_allowed);
|
||||
else
|
||||
layer_skip <= layer_skip | layer_end;
|
||||
|
||||
|
||||
// --- Tile map prefetch ---
|
||||
|
||||
// DRAM controls
|
||||
assign dram_addr = {tmpage, tm_b_row, tm_layer, tm_b_line, tm_num}; // 20:13 - page, 12:7 - row, 6 - layer, 5:0 - column (burst number : number in burst)
|
||||
assign dram_req = tmap;
|
||||
|
||||
// TMB control
|
||||
wire [8:0] tmb_waddr = {tm_line[4:3], tm_b_line, tm_num, tm_layer}; // 8:7 - buffer #, 6:4 - burst number (of 8 bursts), 3:1 - number in burst (8 tiles per burst), 0 - layer
|
||||
wire [8:0] tm_line = line + 9'd16;
|
||||
wire [2:0] tm_b_line = tm_line[2:0];
|
||||
wire [5:0] tm_b_row = tm_line[8:3] + (tm_layer ? t1y_offs[8:3] : t0y_offs[8:3]);
|
||||
wire [2:0] tm_num = tm_x[2:0];
|
||||
wire tm_layer = tm_x[3];
|
||||
|
||||
// internal layers control
|
||||
wire tm_end = tm_x == (t1_en ? 5'd16 : 5'd8);
|
||||
wire tm_next = dram_next && tmap;
|
||||
|
||||
reg [1:0] m_layer;
|
||||
always @(posedge clk)
|
||||
if (start)
|
||||
m_layer <= 2'b1;
|
||||
else if (tm_end)
|
||||
m_layer <= {m_layer[0], 1'b0};
|
||||
|
||||
// tilemap X coordinate
|
||||
reg [4:0] tm_x;
|
||||
always @(posedge clk)
|
||||
if (start)
|
||||
tm_x <= t0_en ? 5'd0 : 5'd8;
|
||||
else if (tm_next)
|
||||
tm_x <= tm_x + 5'd1;
|
||||
|
||||
|
||||
// --- Tiles ---
|
||||
|
||||
// tile descriptor fields
|
||||
wire [11:0] t_tnum = tmb_rdata[11:0];
|
||||
wire [1:0] t_pal = tmb_rdata[13:12];
|
||||
wire t_xflp = tmb_rdata[14];
|
||||
wire t_yflp = tmb_rdata[15];
|
||||
|
||||
// TSR control
|
||||
wire [7:0] tile_page = t_sel ? t0gpage : t1gpage;
|
||||
wire [8:0] tile_line = {t_tnum[11:6], (t_line[2:0] ^ {3{t_yflp}})};
|
||||
wire [5:0] tile_addr = t_tnum[5:0];
|
||||
wire [8:0] tile_x = {(tx - 6'd1), 3'd0} - tx_offs[2:0];
|
||||
wire [3:0] tile_pal = {t_sel ? t0_palsel : t1_palsel, t_pal};
|
||||
|
||||
// TMB control
|
||||
wire [8:0] tmb_raddr = {t_line[4:3], tx + tx_offs[8:3], ~t_sel};
|
||||
|
||||
// layer parameter selectors
|
||||
wire [8:0] tx_offs = t_sel ? t0x_offs : t1x_offs;
|
||||
wire [3:0] ty_offs = t_sel ? t0y_offs[2:0] : t1y_offs[2:0];
|
||||
wire t_sel = t_layer[0];
|
||||
|
||||
// internal layers control
|
||||
wire [1:0] tile_end = {2{t_layer_end}} & t_layer[1:0];
|
||||
wire t_layer_end = tx == num_tiles;
|
||||
wire t_layer_start = start || t_layer_end;
|
||||
|
||||
reg [1:0] t_layer;
|
||||
always @(posedge clk)
|
||||
if (start)
|
||||
t_layer <= t0_en ? 2'b01 : 2'b10;
|
||||
else if (t_layer_end)
|
||||
t_layer <= {t_layer[0], 1'b0};
|
||||
|
||||
// TMBUF control
|
||||
// condition write to tx write to tm_valid
|
||||
// t_layer_start 0 TM_PRE_VALID
|
||||
// tm_pre_valid tx+1 TM_VALID
|
||||
// tile_skip tx+1 -
|
||||
// tile_go tx+1 TM_VALID
|
||||
// tile_wait tx-1 TM_PRE_VALID
|
||||
|
||||
localparam TM_PRE_VALID = 2'b01;
|
||||
localparam TM_VALID = 2'b10;
|
||||
|
||||
wire tile_go = tile_good && tsr_allowed;
|
||||
wire tile_wait = tile_good && !tsr_allowed;
|
||||
wire tile_good = tm_valid && tile_valid;
|
||||
wire tile_skip = tm_valid && !tile_valid;
|
||||
wire tsr_allowed = tiles && tsr_rdy;
|
||||
wire tile_valid = |t_tnum || (t_sel ? t0z_en : t1z_en);
|
||||
|
||||
wire tm_pre_valid = tm_valid_r[0];
|
||||
wire tm_valid = tm_valid_r[1];
|
||||
|
||||
reg [1:0] tm_valid_r;
|
||||
always @(posedge clk)
|
||||
if (t_layer_start || tile_wait)
|
||||
tm_valid_r <= TM_PRE_VALID;
|
||||
else if (tm_pre_valid || tile_go)
|
||||
tm_valid_r <= TM_VALID;
|
||||
|
||||
reg [5:0] tx;
|
||||
always @(posedge clk)
|
||||
if (t_layer_start)
|
||||
tx <= 6'd0;
|
||||
else if (tm_pre_valid || tile_skip || tile_go)
|
||||
tx <= tx + 6'd1;
|
||||
else if (tile_wait)
|
||||
tx <= tx - 6'd1;
|
||||
|
||||
// tile Y geometry
|
||||
wire [4:0] t_line = line[4:0] + ty_offs;
|
||||
|
||||
|
||||
// --- Sprites ---
|
||||
|
||||
// sprite descriptor fields
|
||||
// R0
|
||||
wire [8:0] s_ycrd = sfile_rdata[8:0];
|
||||
wire [2:0] s_ysz = sfile_rdata[11:9];
|
||||
wire s_act = sfile_rdata[13];
|
||||
wire s_leap = sfile_rdata[14];
|
||||
wire s_yflp = sfile_rdata[15];
|
||||
// R1
|
||||
wire [8:0] s_xcrd = sfile_rdata[8:0];
|
||||
wire [2:0] s_xsz = sfile_rdata[11:9];
|
||||
wire s_xflp = sfile_rdata[15];
|
||||
// R2
|
||||
wire [11:0] s_tnum = sfile_rdata[11:0];
|
||||
wire [3:0] s_pal = sfile_rdata[15:12];
|
||||
|
||||
// TSR control
|
||||
reg [8:0] sprites_x;
|
||||
reg [2:0] sprites_xs;
|
||||
reg sprites_xf;
|
||||
wire [5:0] sprites_addr = s_tnum[5:0];
|
||||
|
||||
// internal layers control
|
||||
wire [2:0] spr_end = ({3{s_layer_end}} & s_layer[2:0]) | {3{sprites_last}};
|
||||
wire s_layer_end = (sr0_valid && !spr_valid && s_leap) || (sprite_go && s_leap_r);
|
||||
wire sprites_last = sr0_valid && sprites_last_r;
|
||||
|
||||
reg sprites_last_r;
|
||||
always @(posedge clk) sprites_last_r <= sreg == 8'd255;
|
||||
|
||||
|
||||
reg [2:0] s_layer;
|
||||
always @(posedge clk)
|
||||
if (start)
|
||||
s_layer <= 3'b1;
|
||||
else if (s_layer_end)
|
||||
s_layer <= {s_layer[1:0], 1'b0};
|
||||
|
||||
// SFile registers control
|
||||
// condition write to sreg write to sr_valid action
|
||||
// start 0 SR0_PRE_VALID Start
|
||||
// sr0_pre_valid sreg+3 SR0_VALID SR0 pre-read
|
||||
// sr0_valid && !spr_valid sreg+3 - Skip sprite
|
||||
// sr0_valid && spr_valid sreg-2 SR1_PRE_VALID SR1 pre-read
|
||||
// sr1_pre_valid sreg+1 SR1_VALID SR1 read
|
||||
// sr1_valid sreg+1 SR2_VALID SR2 pre-read
|
||||
// sr2_valid && !tsr_rdy - - Wait for TSR ready
|
||||
// sr2_valid && tsr_rdy sreg+1 SR0_PRE_VALID Next sprite
|
||||
// sprites_last - NONE_VALID End
|
||||
|
||||
localparam NONE_VALID = 5'b00000;
|
||||
localparam SR0_PRE_VALID = 5'b00001;
|
||||
localparam SR0_VALID = 5'b00010;
|
||||
localparam SR1_PRE_VALID = 5'b00100;
|
||||
localparam SR1_VALID = 5'b01000;
|
||||
localparam SR2_VALID = 5'b10000;
|
||||
|
||||
wire sprite_go = sr2_valid && sprites && tsr_rdy; // kick to renderer
|
||||
wire spr_valid = s_visible && s_act;
|
||||
|
||||
wire sr0_pre_valid = sr_valid[0];
|
||||
wire sr0_valid = sr_valid[1];
|
||||
wire sr1_pre_valid = sr_valid[2];
|
||||
wire sr1_valid = sr_valid[3];
|
||||
wire sr2_valid = sr_valid[4];
|
||||
|
||||
reg [4:0] sr_valid;
|
||||
always @(posedge clk)
|
||||
if (start)
|
||||
sr_valid <= SR0_PRE_VALID;
|
||||
else if (sprites_last)
|
||||
sr_valid <= NONE_VALID;
|
||||
else if (sr0_pre_valid)
|
||||
sr_valid <= SR0_VALID;
|
||||
else if (sr0_valid && spr_valid)
|
||||
sr_valid <= SR1_PRE_VALID;
|
||||
else if (sr1_pre_valid)
|
||||
sr_valid <= SR1_VALID;
|
||||
else if (sr1_valid)
|
||||
sr_valid <= SR2_VALID;
|
||||
else if (sprite_go)
|
||||
sr_valid <= SR0_PRE_VALID;
|
||||
|
||||
reg [7:0] sreg;
|
||||
always @(posedge clk)
|
||||
if (start)
|
||||
sreg <= 8'd0;
|
||||
else if (sr0_pre_valid)
|
||||
sreg <= sreg + 8'd3;
|
||||
else if (sr0_valid)
|
||||
sreg <= spr_valid ? (sreg - 8'd2) : (sreg + 8'd3);
|
||||
else if (sr1_pre_valid || sprite_go)
|
||||
sreg <= sreg + 8'd1;
|
||||
|
||||
// SFile control
|
||||
reg [5:0] s_bmline_offset_r;
|
||||
reg s_leap_r;
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (sr0_valid)
|
||||
begin
|
||||
s_leap_r <= s_leap;
|
||||
s_bmline_offset_r <= s_bmline_offset;
|
||||
end
|
||||
|
||||
if (sr1_valid)
|
||||
begin
|
||||
sprites_x <= s_xcrd;
|
||||
sprites_xs <= s_xsz;
|
||||
sprites_xf <= s_xflp;
|
||||
end
|
||||
end
|
||||
|
||||
// sprite Y geometry
|
||||
wire [8:0] s_line = line - s_ycrd; // visible line of sprite in current video line
|
||||
wire s_visible = (s_line <= s_ymax); // check if sprite line is within Y size
|
||||
wire [5:0] s_ymax = {s_ysz, 3'b111};
|
||||
|
||||
wire [8:0] sprites_line = {s_tnum[11:6], 3'b0} + s_bmline_offset_r;
|
||||
wire [5:0] s_bmline_offset = s_yflp ? (s_ymax - s_line[5:0]) : s_line[5:0];
|
||||
|
||||
|
||||
// SFile
|
||||
wire [15:0] sfile_rdata;
|
||||
dpram #(.DATAWIDTH(16), .ADDRWIDTH(8)) video_sfile
|
||||
`include "tune.v"
|
||||
|
||||
// This is the Tile Sprite Processing Unit
|
||||
|
||||
// Tiles map address:
|
||||
// bits desc
|
||||
// 20:13 tmpage
|
||||
// 12:
|
||||
|
||||
// Graphics address:
|
||||
// bits desc
|
||||
// 20:13 Xgpage
|
||||
// 15:7 line (bits 15:13 are added) - 512 lines
|
||||
// 6:0 word within line - 128 words = 512 pixels
|
||||
|
||||
|
||||
module video_ts
|
||||
(
|
||||
.clock (clk),
|
||||
.address_a (sfile_addr_in),
|
||||
.data_a (sfile_data_in),
|
||||
.wren_a (sfile_we),
|
||||
.address_b (sreg),
|
||||
.q_b (sfile_rdata)
|
||||
);
|
||||
|
||||
// 4 buffers * 2 tile-planes * 64 tiles * 16 bits (9x16) - used to prefetch tiles
|
||||
// (2 altdprams)
|
||||
wire [15:0] tmb_rdata;
|
||||
dpram #(.DATAWIDTH(16), .ADDRWIDTH(9)) video_tmbuf
|
||||
(
|
||||
.clock (clk),
|
||||
.address_a (tmb_waddr),
|
||||
.data_a (dram_rdata),
|
||||
.wren_a (tm_next),
|
||||
.address_b (tmb_raddr),
|
||||
.q_b (tmb_rdata)
|
||||
// clocks
|
||||
input wire clk,
|
||||
|
||||
// video controls
|
||||
input wire start,
|
||||
input wire [8:0] line, // = vcount - vpix_beg + 9'b1;
|
||||
input wire v_ts,
|
||||
input wire v_pf, // vertical tilemap prefetch window
|
||||
|
||||
// video config
|
||||
input wire [7:0] tsconf,
|
||||
input wire [7:0] t0gpage,
|
||||
input wire [7:0] t1gpage,
|
||||
input wire [7:0] sgpage,
|
||||
input wire [7:0] tmpage,
|
||||
input wire [5:0] num_tiles,
|
||||
input wire [8:0] t0x_offs,
|
||||
input wire [8:0] t1x_offs,
|
||||
input wire [8:0] t0y_offs,
|
||||
input wire [8:0] t1y_offs,
|
||||
input wire [1:0] t0_palsel,
|
||||
input wire [1:0] t1_palsel,
|
||||
|
||||
// SFYS interface
|
||||
input wire [7:0] sfile_addr_in,
|
||||
input wire [15:0] sfile_data_in,
|
||||
input wire sfile_we,
|
||||
|
||||
// renderer interface
|
||||
output wire tsr_go,
|
||||
output wire [5:0] tsr_addr, // graphics address within the line
|
||||
output wire [8:0] tsr_line, // bitmap line
|
||||
output wire [7:0] tsr_page, // bitmap 1st page
|
||||
output wire [8:0] tsr_x, // addr in buffer (0-359 visibles)
|
||||
output wire [2:0] tsr_xs, // size (8-64 pix)
|
||||
output wire tsr_xf, // X flip
|
||||
output wire [3:0] tsr_pal, // palette
|
||||
input wire tsr_rdy, // renderer is done and ready to receive a new task
|
||||
|
||||
// DRAM interface
|
||||
output wire [20:0] dram_addr,
|
||||
output wire dram_req,
|
||||
input wire dram_next,
|
||||
input wire [15:0] dram_rdata
|
||||
);
|
||||
|
||||
endmodule
|
||||
|
||||
// config
|
||||
wire s_en = tsconf[7];
|
||||
wire t1_en = tsconf[6];
|
||||
wire t0_en = tsconf[5];
|
||||
wire t1z_en = tsconf[3];
|
||||
wire t0z_en = tsconf[2];
|
||||
|
||||
// tile descriptor fields
|
||||
wire [15:0] tmb_rdata;
|
||||
|
||||
wire [11:0] t_tnum = tmb_rdata[11:0];
|
||||
wire [1:0] t_pal = tmb_rdata[13:12];
|
||||
wire t_xflp = tmb_rdata[14];
|
||||
wire t_yflp = tmb_rdata[15];
|
||||
|
||||
// Layer selectors control
|
||||
localparam LAYERS = 6; // total number of layers to process
|
||||
|
||||
localparam TM = 0; // Individual layers
|
||||
localparam S0 = 1;
|
||||
localparam T0 = 2;
|
||||
localparam S1 = 3;
|
||||
localparam T1 = 4;
|
||||
localparam S2 = 5;
|
||||
|
||||
reg [LAYERS-1:0] layer_active;
|
||||
reg [LAYERS-1:0] layer_skip;
|
||||
|
||||
wire tmap = layer_active[TM];
|
||||
wire sprites = layer_active[S0] || layer_active[S1] || layer_active[S2];
|
||||
wire tiles = layer_active[T0] || layer_active[T1];
|
||||
|
||||
reg [LAYERS-1:0] layer;
|
||||
always @(posedge clk)
|
||||
if (start)
|
||||
layer <= 1;
|
||||
else if (|(layer & layer_skip))
|
||||
layer <= {layer[LAYERS-2:0], 1'b0};
|
||||
|
||||
always @(posedge clk)
|
||||
if (start)
|
||||
layer_active <= 0;
|
||||
else
|
||||
layer_active <= layer & ~layer_skip;
|
||||
|
||||
wire [2:0] spr_end;
|
||||
wire [1:0] tile_end;
|
||||
wire tm_end;
|
||||
wire [LAYERS-1:0] layer_enabled = {s_en, t1_en, s_en, t0_en, s_en, t1_en || t0_en};
|
||||
wire [LAYERS-1:0] layer_allowed = {{5{v_ts}}, v_pf};
|
||||
wire [LAYERS-1:0] layer_end = {spr_end[2], tile_end[1], spr_end[1], tile_end[0], spr_end[0], tm_end};
|
||||
|
||||
always @(posedge clk)
|
||||
if (start)
|
||||
layer_skip <= ~(layer_enabled & layer_allowed);
|
||||
else
|
||||
layer_skip <= layer_skip | layer_end;
|
||||
|
||||
// --- Tile map prefetch ---
|
||||
// TMB control
|
||||
reg [4:0] tm_x;
|
||||
|
||||
wire [8:0] tm_line = line + 9'd16;
|
||||
wire [2:0] tm_b_line = tm_line[2:0];
|
||||
wire [2:0] tm_num = tm_x[2:0];
|
||||
wire tm_layer = tm_x[3];
|
||||
wire [8:0] tmb_waddr = {tm_line[4:3], tm_b_line, tm_num, tm_layer}; // 8:7 - buffer #, 6:4 - burst number (of 8 bursts), 3:1 - number in burst (8 tiles per burst), 0 - layer
|
||||
wire [5:0] tm_b_row = tm_line[8:3] + (tm_layer ? t1y_offs[8:3] : t0y_offs[8:3]);
|
||||
|
||||
// DRAM controls
|
||||
assign dram_addr = {tmpage, tm_b_row, tm_layer, tm_b_line, tm_num}; // 20:13 - page, 12:7 - row, 6 - layer, 5:0 - column (burst number : number in burst)
|
||||
assign dram_req = tmap;
|
||||
|
||||
// internal layers control
|
||||
assign tm_end = tm_x == (t1_en ? 5'd16 : 5'd8);
|
||||
wire tm_next = dram_next && tmap;
|
||||
|
||||
reg [1:0] m_layer;
|
||||
always @(posedge clk)
|
||||
if (start)
|
||||
m_layer <= 2'b1;
|
||||
else if (tm_end)
|
||||
m_layer <= {m_layer[0], 1'b0};
|
||||
|
||||
// tilemap X coordinate
|
||||
always @(posedge clk)
|
||||
if (start)
|
||||
tm_x <= t0_en ? 5'd0 : 5'd8;
|
||||
else if (tm_next)
|
||||
tm_x <= tm_x + 5'd1;
|
||||
|
||||
// --- Tiles ---
|
||||
// layer parameter selectors
|
||||
reg [1:0] t_layer;
|
||||
reg [5:0] tx;
|
||||
|
||||
wire t_sel = t_layer[0];
|
||||
wire [8:0] tx_offs = t_sel ? t0x_offs : t1x_offs;
|
||||
wire [3:0] ty_offs = t_sel ? t0y_offs[2:0] : t1y_offs[2:0];
|
||||
|
||||
// TSR control
|
||||
wire [4:0] t_line;
|
||||
wire [7:0] tile_page = t_sel ? t0gpage : t1gpage;
|
||||
wire [8:0] tile_line = {t_tnum[11:6], (t_line[2:0] ^ {3{t_yflp}})};
|
||||
wire [5:0] tile_addr = t_tnum[5:0];
|
||||
wire [8:0] tile_x = {(tx - 6'd1), 3'd0} - tx_offs[2:0];
|
||||
wire [3:0] tile_pal = {t_sel ? t0_palsel : t1_palsel, t_pal};
|
||||
|
||||
// TMB control
|
||||
wire [8:0] tmb_raddr = {t_line[4:3], tx + tx_offs[8:3], ~t_sel};
|
||||
|
||||
// internal layers control
|
||||
wire t_layer_end = tx == num_tiles;
|
||||
wire t_layer_start = start || t_layer_end;
|
||||
assign tile_end = {2{t_layer_end}} & t_layer[1:0];
|
||||
|
||||
always @(posedge clk)
|
||||
if (start)
|
||||
t_layer <= t0_en ? 2'b01 : 2'b10;
|
||||
else if (t_layer_end)
|
||||
t_layer <= {t_layer[0], 1'b0};
|
||||
|
||||
// TMBUF control
|
||||
// condition write to tx write to tm_valid
|
||||
// t_layer_start 0 TM_PRE_VALID
|
||||
// tm_pre_valid tx+1 TM_VALID
|
||||
// tile_skip tx+1 -
|
||||
// tile_go tx+1 TM_VALID
|
||||
// tile_wait tx-1 TM_PRE_VALID
|
||||
|
||||
localparam TM_PRE_VALID = 2'b01;
|
||||
localparam TM_VALID = 2'b10;
|
||||
|
||||
reg [1:0] tm_valid_r;
|
||||
wire tm_valid = tm_valid_r[1];
|
||||
wire tm_pre_valid = tm_valid_r[0];
|
||||
|
||||
wire tile_valid = |t_tnum || (t_sel ? t0z_en : t1z_en);
|
||||
wire tsr_allowed = tiles && tsr_rdy;
|
||||
wire tile_good = tm_valid && tile_valid;
|
||||
wire tile_wait = tile_good && !tsr_allowed;
|
||||
wire tile_skip = tm_valid && !tile_valid;
|
||||
wire tile_go = tile_good && tsr_allowed;
|
||||
|
||||
always @(posedge clk)
|
||||
if (t_layer_start || tile_wait)
|
||||
tm_valid_r <= TM_PRE_VALID;
|
||||
else if (tm_pre_valid || tile_go)
|
||||
tm_valid_r <= TM_VALID;
|
||||
|
||||
always @(posedge clk)
|
||||
if (t_layer_start)
|
||||
tx <= 6'd0;
|
||||
else if (tm_pre_valid || tile_skip || tile_go)
|
||||
tx <= tx + 6'd1;
|
||||
else if (tile_wait)
|
||||
tx <= tx - 6'd1;
|
||||
|
||||
// tile Y geometry
|
||||
assign t_line = line[4:0] + ty_offs;
|
||||
|
||||
// --- Sprites ---
|
||||
// sprite descriptor fields
|
||||
// R0
|
||||
wire [15:0] sfile_rdata;
|
||||
|
||||
wire [8:0] s_ycrd = sfile_rdata[8:0];
|
||||
wire [2:0] s_ysz = sfile_rdata[11:9];
|
||||
wire s_act = sfile_rdata[13];
|
||||
wire s_leap = sfile_rdata[14];
|
||||
wire s_yflp = sfile_rdata[15];
|
||||
// R1
|
||||
wire [8:0] s_xcrd = sfile_rdata[8:0];
|
||||
wire [2:0] s_xsz = sfile_rdata[11:9];
|
||||
wire s_xflp = sfile_rdata[15];
|
||||
// R2
|
||||
wire [11:0] s_tnum = sfile_rdata[11:0];
|
||||
wire [3:0] s_pal = sfile_rdata[15:12];
|
||||
|
||||
// TSR control
|
||||
wire [5:0] sprites_addr = s_tnum[5:0];
|
||||
|
||||
// internal layers control
|
||||
reg sprites_last_r;
|
||||
reg [2:0] s_layer;
|
||||
reg [7:0] sreg;
|
||||
reg [4:0] sr_valid;
|
||||
reg s_leap_r;
|
||||
|
||||
wire sr0_pre_valid = sr_valid[0];
|
||||
wire sr0_valid = sr_valid[1];
|
||||
wire sr1_pre_valid = sr_valid[2];
|
||||
wire sr1_valid = sr_valid[3];
|
||||
wire sr2_valid = sr_valid[4];
|
||||
|
||||
wire sprite_go;
|
||||
wire s_visible;
|
||||
wire spr_valid = s_visible && s_act;
|
||||
wire s_layer_end = (sr0_valid && !spr_valid && s_leap) || (sprite_go && s_leap_r);
|
||||
wire sprites_last = sr0_valid && sprites_last_r;
|
||||
assign spr_end = ({3{s_layer_end}} & s_layer[2:0]) | {3{sprites_last}};
|
||||
|
||||
always @(posedge clk)
|
||||
sprites_last_r <= sreg == 8'd255;
|
||||
|
||||
always @(posedge clk)
|
||||
if (start)
|
||||
s_layer <= 3'b1;
|
||||
else if (s_layer_end)
|
||||
s_layer <= {s_layer[1:0], 1'b0};
|
||||
|
||||
// SFile registers control
|
||||
// condition write to sreg write to sr_valid action
|
||||
// start 0 SR0_PRE_VALID Start
|
||||
// sr0_pre_valid sreg+3 SR0_VALID SR0 pre-read
|
||||
// sr0_valid && !spr_valid sreg+3 - Skip sprite
|
||||
// sr0_valid && spr_valid sreg-2 SR1_PRE_VALID SR1 pre-read
|
||||
// sr1_pre_valid sreg+1 SR1_VALID SR1 read
|
||||
// sr1_valid sreg+1 SR2_VALID SR2 pre-read
|
||||
// sr2_valid && !tsr_rdy - - Wait for TSR ready
|
||||
// sr2_valid && tsr_rdy sreg+1 SR0_PRE_VALID Next sprite
|
||||
// sprites_last - NONE_VALID End
|
||||
|
||||
localparam NONE_VALID = 5'b00000;
|
||||
localparam SR0_PRE_VALID = 5'b00001;
|
||||
localparam SR0_VALID = 5'b00010;
|
||||
localparam SR1_PRE_VALID = 5'b00100;
|
||||
localparam SR1_VALID = 5'b01000;
|
||||
localparam SR2_VALID = 5'b10000;
|
||||
|
||||
assign sprite_go = sr2_valid && sprites && tsr_rdy; // a kick to renderer
|
||||
|
||||
always @(posedge clk)
|
||||
if (start)
|
||||
sr_valid <= SR0_PRE_VALID;
|
||||
else if (sprites_last)
|
||||
sr_valid <= NONE_VALID;
|
||||
else if (sr0_pre_valid)
|
||||
sr_valid <= SR0_VALID;
|
||||
else if (sr0_valid && spr_valid)
|
||||
sr_valid <= SR1_PRE_VALID;
|
||||
else if (sr1_pre_valid)
|
||||
sr_valid <= SR1_VALID;
|
||||
else if (sr1_valid)
|
||||
sr_valid <= SR2_VALID;
|
||||
else if (sprite_go)
|
||||
sr_valid <= SR0_PRE_VALID;
|
||||
|
||||
always @(posedge clk)
|
||||
if (start)
|
||||
sreg <= 8'd0;
|
||||
else if (sr0_pre_valid)
|
||||
sreg <= sreg + 8'd3;
|
||||
else if (sr0_valid)
|
||||
sreg <= spr_valid ? (sreg - 8'd2) : (sreg + 8'd3);
|
||||
else if (sr1_pre_valid || sprite_go)
|
||||
sreg <= sreg + 8'd1;
|
||||
|
||||
// sprite Y geometry
|
||||
reg [5:0] s_bmline_offset_r;
|
||||
|
||||
wire [8:0] s_line = line - s_ycrd; // visible line of sprite in current video line
|
||||
wire [5:0] s_ymax = {s_ysz, 3'b111};
|
||||
assign s_visible = (s_line <= s_ymax); // check if sprite line is within Y size
|
||||
|
||||
wire [8:0] sprites_line = {s_tnum[11:6], 3'b0} + s_bmline_offset_r;
|
||||
wire [5:0] s_bmline_offset = s_yflp ? (s_ymax - s_line[5:0]) : s_line[5:0];
|
||||
|
||||
// SFile control
|
||||
reg [8:0] sprites_x;
|
||||
reg [2:0] sprites_xs;
|
||||
reg sprites_xf;
|
||||
|
||||
always @(posedge clk)
|
||||
begin
|
||||
if (sr0_valid)
|
||||
begin
|
||||
s_leap_r <= s_leap;
|
||||
s_bmline_offset_r <= s_bmline_offset;
|
||||
end
|
||||
|
||||
if (sr1_valid)
|
||||
begin
|
||||
sprites_x <= s_xcrd;
|
||||
sprites_xs <= s_xsz;
|
||||
sprites_xf <= s_xflp;
|
||||
end
|
||||
end
|
||||
|
||||
// SFile
|
||||
dpram #(.DATAWIDTH(16), .ADDRWIDTH(8)) video_sfile
|
||||
(
|
||||
.clock (clk),
|
||||
.address_a (sfile_addr_in),
|
||||
.data_a (sfile_data_in),
|
||||
.wren_a (sfile_we),
|
||||
.address_b (sreg),
|
||||
.q_b (sfile_rdata)
|
||||
);
|
||||
/*
|
||||
altdpram video_sfile
|
||||
(
|
||||
.outclock (clk),
|
||||
.wren (sfile_we),
|
||||
.inclock (clk),
|
||||
.data (sfile_data_in),
|
||||
.rdaddress (sreg),
|
||||
.wraddress (sfile_addr_in),
|
||||
.q (sfile_rdata),
|
||||
.aclr (1'b0),
|
||||
.byteena (1'b1),
|
||||
.inclocken (1'b1),
|
||||
.outclocken (1'b1),
|
||||
.rdaddressstall (1'b0),
|
||||
.rden (1'b1),
|
||||
.wraddressstall (1'b0)
|
||||
);
|
||||
|
||||
defparam
|
||||
video_sfile.indata_aclr = "OFF",
|
||||
video_sfile.indata_reg = "INCLOCK",
|
||||
video_sfile.intended_device_family = "ACEX1K",
|
||||
video_sfile.lpm_type = "altdpram",
|
||||
video_sfile.outdata_aclr = "OFF",
|
||||
video_sfile.outdata_reg = "OUTCLOCK",
|
||||
video_sfile.rdaddress_aclr = "OFF",
|
||||
video_sfile.rdaddress_reg = "UNREGISTERED",
|
||||
video_sfile.rdcontrol_aclr = "OFF",
|
||||
video_sfile.rdcontrol_reg = "UNREGISTERED",
|
||||
video_sfile.width = 16,
|
||||
video_sfile.widthad = 8,
|
||||
video_sfile.wraddress_aclr = "OFF",
|
||||
video_sfile.wraddress_reg = "INCLOCK",
|
||||
video_sfile.wrcontrol_aclr = "OFF",
|
||||
video_sfile.wrcontrol_reg = "INCLOCK";
|
||||
*/
|
||||
// 4 buffers * 2 tile-planes * 64 tiles * 16 bits (9x16) - used to prefetch tiles
|
||||
// (2 altdprams)
|
||||
dpram #(.DATAWIDTH(16), .ADDRWIDTH(9)) video_tmbuf
|
||||
(
|
||||
.clock (clk),
|
||||
.address_a (tmb_waddr),
|
||||
.data_a (dram_rdata),
|
||||
.wren_a (tm_next),
|
||||
.address_b (tmb_raddr),
|
||||
.q_b (tmb_rdata)
|
||||
);
|
||||
/*
|
||||
altdpram video_tmbuf
|
||||
(
|
||||
.outclock (clk),
|
||||
.wren (tm_next),
|
||||
.inclock (clk),
|
||||
.data (dram_rdata),
|
||||
.rdaddress (tmb_raddr),
|
||||
.wraddress (tmb_waddr),
|
||||
.q (tmb_rdata),
|
||||
.aclr (1'b0),
|
||||
.byteena (1'b1),
|
||||
.inclocken (1'b1),
|
||||
.outclocken (1'b1),
|
||||
.rdaddressstall (1'b0),
|
||||
.rden (1'b1),
|
||||
.wraddressstall (1'b0)
|
||||
);
|
||||
|
||||
defparam
|
||||
video_tmbuf.indata_aclr = "OFF",
|
||||
video_tmbuf.indata_reg = "INCLOCK",
|
||||
video_tmbuf.intended_device_family = "ACEX1K",
|
||||
video_tmbuf.lpm_type = "altdpram",
|
||||
video_tmbuf.outdata_aclr = "OFF",
|
||||
video_tmbuf.outdata_reg = "OUTCLOCK",
|
||||
video_tmbuf.rdaddress_aclr = "OFF",
|
||||
video_tmbuf.rdaddress_reg = "UNREGISTERED",
|
||||
video_tmbuf.rdcontrol_aclr = "OFF",
|
||||
video_tmbuf.rdcontrol_reg = "UNREGISTERED",
|
||||
video_tmbuf.width = 16,
|
||||
video_tmbuf.widthad = 9,
|
||||
video_tmbuf.wraddress_aclr = "OFF",
|
||||
video_tmbuf.wraddress_reg = "INCLOCK",
|
||||
video_tmbuf.wrcontrol_aclr = "OFF",
|
||||
video_tmbuf.wrcontrol_reg = "INCLOCK";
|
||||
*/
|
||||
// TS renderer interface
|
||||
assign tsr_go = sprite_go || tile_go;
|
||||
assign tsr_x = sprites ? sprites_x : tile_x;
|
||||
assign tsr_xs = sprites ? sprites_xs : 3'd0;
|
||||
assign tsr_xf = sprites ? sprites_xf : t_xflp;
|
||||
assign tsr_page = sprites ? sgpage : tile_page;
|
||||
assign tsr_line = sprites ? sprites_line : tile_line;
|
||||
assign tsr_addr = sprites ? sprites_addr : tile_addr;
|
||||
assign tsr_pal = sprites ? s_pal : tile_pal;
|
||||
|
||||
endmodule
|
||||
|
@ -1,150 +1,150 @@
|
||||
|
||||
// This module renders pixels into TS-line for tiles/sprites
|
||||
// Task execution is initiated by 'tsr_go' (one 'clk' period strobe).
|
||||
// Inputs (only valid by 'tsr_go'):
|
||||
// - DRAM address of graphics data (including page, line, word)
|
||||
// - number of cycles to render (one cycle is 2 words = 8 pixels; 8 cycles = 64 pixels max)
|
||||
// - X coordinate
|
||||
// - X flip bit
|
||||
// - palette selector
|
||||
// Address in TS-line is calculated from X coordinate respecting the X flip.
|
||||
// Inc/dec direction is set automatically.
|
||||
// At the 'c2' of last DRAM cycle 'mem_rdy' is asserted.
|
||||
// It should be used in comb to generate next cycle 'tsr_go' strobe for continuous renderer operation.
|
||||
// First 'tsr_go' may be issued at any DRAM cycle, but the operation starts only
|
||||
// after TS request recognized and processed by DRAM controller.
|
||||
// It is recommended to assert 'tsr_go' at 'c2'.
|
||||
|
||||
`include "tune.v"
|
||||
|
||||
// This module renders pixels into TS-line for tiles/sprites
|
||||
// Task execution is initiated by 'tsr_go' (one 'clk' period strobe).
|
||||
// Inputs (only valid by 'tsr_go'):
|
||||
// - DRAM address of graphics data (including page, line, word)
|
||||
// - number of cycles to render (one cycle is 2 words = 8 pixels; 8 cycles = 64 pixels max)
|
||||
// - X coordinate
|
||||
// - X flip bit
|
||||
// - palette selector
|
||||
// Address in TS-line is calculated from X coordinate respecting the X flip.
|
||||
// Inc/dec direction is set automatically.
|
||||
// At the 'c2' of last DRAM cycle 'mem_rdy' is asserted.
|
||||
// It should be used in comb to generate next cycle 'tsr_go' strobe for continuous renderer operation.
|
||||
// First 'tsr_go' may be issued at any DRAM cycle, but the operation starts only
|
||||
// after TS request recognized and processed by DRAM controller.
|
||||
// It is recommended to assert 'tsr_go' at 'c2'.
|
||||
|
||||
module video_ts_render
|
||||
(
|
||||
// clocks
|
||||
input wire clk,
|
||||
|
||||
// controls
|
||||
input wire reset, // line start strobe, inits the machine
|
||||
|
||||
input wire [ 8:0] x_coord, // address in TS-line where render to, auto-flipped to match 'flip' times 'x_size'
|
||||
input wire [ 2:0] x_size, // number of rendering cycles (each cycle is 8 pixels, 0 = 1 cycle)
|
||||
input wire flip, // indicates that sprite is X-flipped
|
||||
|
||||
input wire tsr_go, // 1 clk 28MHz strobe for render start. Should be issued along with 'mem_rdy' for continuous process
|
||||
input wire [ 5:0] addr, // address of dword within the line (dword = 8 pix)
|
||||
input wire [ 8:0] line, // line of bitmap
|
||||
input wire [ 7:0] page, // 1st page of bitmap (TxGpage or SGpage)
|
||||
input wire [ 3:0] pal, // palette selector, bits[7:4] of CRAM address
|
||||
output wire mem_rdy, // ready to receive new task
|
||||
|
||||
// TS-Line interface
|
||||
output reg [ 8:0] ts_waddr,
|
||||
output wire [ 7:0] ts_wdata,
|
||||
output wire ts_we,
|
||||
|
||||
// DRAM interface
|
||||
output wire [20:0] dram_addr,
|
||||
output wire dram_req,
|
||||
input wire [15:0] dram_rdata,
|
||||
input wire dram_pre_next,
|
||||
input wire dram_next
|
||||
);
|
||||
|
||||
|
||||
// DRAM request
|
||||
assign dram_req = tsr_go || !mem_rdy;
|
||||
|
||||
|
||||
// DRAM addressing
|
||||
assign dram_addr = tsr_go ? addr_in : addr_next;
|
||||
wire [20:0] addr_in = {addr_offset, addr, 1'b0};
|
||||
wire [13:0] addr_offset = {page[7:3], line};
|
||||
wire [20:0] addr_next = {addr_reg[20:7], addr_reg[6:0] + dram_next};
|
||||
// as renderer can't move outside the single bitmap line, only 7 bits are processed
|
||||
|
||||
reg [20:0] addr_reg;
|
||||
always @(posedge clk) addr_reg <= dram_addr;
|
||||
|
||||
|
||||
// DRAM cycles counter
|
||||
assign mem_rdy = cyc[4];
|
||||
|
||||
reg [4:0] cyc;
|
||||
always @(posedge clk)
|
||||
if (reset)
|
||||
cyc <= 5'b10000;
|
||||
else if (tsr_go)
|
||||
cyc <= {1'b0, x_size, 1'b1};
|
||||
else if (dram_pre_next)
|
||||
cyc <= cyc - 5'd1;
|
||||
|
||||
|
||||
// DRAM data fetching
|
||||
reg [15:0] data;
|
||||
always @(posedge clk) if (dram_next) data <= dram_rdata;
|
||||
|
||||
|
||||
// pixel render counter
|
||||
assign ts_we = render_on && |pix; // write signal for TS-line
|
||||
wire render_on = !cnt[2];
|
||||
|
||||
reg [2:0] cnt;
|
||||
always @(posedge clk)
|
||||
if (reset)
|
||||
cnt <= 3'b100;
|
||||
else if (dram_next)
|
||||
cnt <= 3'b000;
|
||||
else if (render_on)
|
||||
cnt <= cnt + 3'd1;
|
||||
|
||||
|
||||
// renderer reload
|
||||
reg tsr_rld;
|
||||
always @(posedge clk)
|
||||
if (reset)
|
||||
tsr_rld <= 1'b0;
|
||||
else if (tsr_go)
|
||||
tsr_rld <= 1'b1;
|
||||
else if (dram_next)
|
||||
tsr_rld <= 1'b0;
|
||||
|
||||
|
||||
// delayed values
|
||||
reg [8:0] x_coord_d;
|
||||
reg [3:0] pal_d;
|
||||
reg flip_d;
|
||||
always @(posedge clk)
|
||||
if (tsr_go)
|
||||
begin
|
||||
x_coord_d <= x_coord + (flip ? {x_size, 3'b111} : 6'd0);
|
||||
pal_d <= pal;
|
||||
flip_d <= flip;
|
||||
end
|
||||
|
||||
|
||||
// TS-line address
|
||||
wire [8:0] ts_waddr_mx = tsr_rld_stb ? x_coord_d : (render_on ? x_next : ts_waddr);
|
||||
wire [8:0] x_next = ts_waddr + {{8{flip_r}}, 1'b1};
|
||||
wire tsr_rld_stb = tsr_rld && dram_next;
|
||||
|
||||
always @(posedge clk) ts_waddr <= ts_waddr_mx;
|
||||
|
||||
reg [3:0] pal_r;
|
||||
reg flip_r;
|
||||
always @(posedge clk)
|
||||
if (tsr_rld_stb)
|
||||
begin
|
||||
pal_r <= pal_d;
|
||||
flip_r <= flip_d;
|
||||
end
|
||||
|
||||
|
||||
// renderer mux
|
||||
assign ts_wdata = {pal_r, pix};
|
||||
wire [3:0] pix = pix_m[cnt[1:0]];
|
||||
|
||||
wire [3:0] pix_m[0:3];
|
||||
assign pix_m[0] = data[7:4];
|
||||
assign pix_m[1] = data[3:0];
|
||||
assign pix_m[2] = data[15:12];
|
||||
assign pix_m[3] = data[11:8];
|
||||
|
||||
|
||||
endmodule
|
||||
(
|
||||
// clocks
|
||||
input wire clk,
|
||||
|
||||
// controls
|
||||
input wire reset, // line start strobe, inits the machine
|
||||
|
||||
input wire [ 8:0] x_coord, // address in TS-line where render to, auto-flipped to match 'flip' times 'x_size'
|
||||
input wire [ 2:0] x_size, // number of rendering cycles (each cycle is 8 pixels, 0 = 1 cycle)
|
||||
input wire flip, // indicates that sprite is X-flipped
|
||||
|
||||
input wire tsr_go, // 1 clk 28MHz strobe for render start. Should be issued along with 'mem_rdy' for continuous process
|
||||
input wire [ 5:0] addr, // address of dword within the line (dword = 8 pix)
|
||||
input wire [ 8:0] line, // line of bitmap
|
||||
input wire [ 7:0] page, // 1st page of bitmap (TxGpage or SGpage)
|
||||
input wire [ 3:0] pal, // palette selector, bits[7:4] of CRAM address
|
||||
output wire mem_rdy, // ready to receive new task
|
||||
|
||||
// TS-Line interface
|
||||
output reg [ 8:0] ts_waddr,
|
||||
output wire [ 7:0] ts_wdata,
|
||||
output wire ts_we,
|
||||
|
||||
// DRAM interface
|
||||
output wire [20:0] dram_addr,
|
||||
output wire dram_req,
|
||||
input wire [15:0] dram_rdata,
|
||||
input wire dram_pre_next,
|
||||
input wire dram_next
|
||||
);
|
||||
|
||||
// renderer mux
|
||||
reg [15:0] data;
|
||||
reg [3:0] pal_r;
|
||||
reg [2:0] pix_cnt;
|
||||
|
||||
wire [3:0] pix_m[0:3];
|
||||
wire [3:0] pix = pix_m[pix_cnt[1:0]];
|
||||
assign ts_wdata = {pal_r, pix};
|
||||
|
||||
assign pix_m[0] = data[7:4];
|
||||
assign pix_m[1] = data[3:0];
|
||||
assign pix_m[2] = data[15:12];
|
||||
assign pix_m[3] = data[11:8];
|
||||
|
||||
// DRAM request
|
||||
assign dram_req = tsr_go || !mem_rdy;
|
||||
|
||||
// DRAM addressing
|
||||
reg [20:0] addr_reg;
|
||||
|
||||
wire [13:0] addr_offset = {page[7:3], line};
|
||||
wire [20:0] addr_in = {addr_offset, addr, 1'b0};
|
||||
wire [20:0] addr_next = {addr_reg[20:7], addr_reg[6:0] + dram_next};
|
||||
assign dram_addr = tsr_go ? addr_in : addr_next;
|
||||
|
||||
always @(posedge clk)
|
||||
addr_reg <= dram_addr;
|
||||
|
||||
// DRAM cycles counter
|
||||
reg [4:0] cyc;
|
||||
|
||||
assign mem_rdy = cyc[4];
|
||||
|
||||
always @(posedge clk or posedge reset)
|
||||
if (reset)
|
||||
cyc <= 5'b10000;
|
||||
else if (tsr_go)
|
||||
cyc <= {1'b0, x_size, 1'b1};
|
||||
else if (dram_pre_next)
|
||||
cyc <= cyc - 5'd1;
|
||||
|
||||
// DRAM data fetching
|
||||
always @(posedge clk)
|
||||
if (dram_next)
|
||||
data <= dram_rdata;
|
||||
|
||||
// pixel render counter
|
||||
wire render_on = !pix_cnt[2];
|
||||
assign ts_we = render_on && |pix; // write signal for TS-line
|
||||
|
||||
always @(posedge clk or posedge reset)
|
||||
if (reset)
|
||||
pix_cnt <= 3'b100;
|
||||
else if (dram_next)
|
||||
pix_cnt <= 3'b000;
|
||||
else if (render_on)
|
||||
pix_cnt <= pix_cnt + 3'd1;
|
||||
|
||||
// renderer reload
|
||||
reg tsr_rld;
|
||||
always @(posedge clk or posedge reset)
|
||||
if (reset)
|
||||
tsr_rld <= 1'b0;
|
||||
else if (tsr_go)
|
||||
tsr_rld <= 1'b1;
|
||||
else if (dram_next)
|
||||
tsr_rld <= 1'b0;
|
||||
|
||||
// delayed values
|
||||
reg [8:0] x_coord_d;
|
||||
reg [3:0] pal_d;
|
||||
reg flip_d;
|
||||
|
||||
always @(posedge clk)
|
||||
if (tsr_go)
|
||||
begin
|
||||
x_coord_d <= x_coord + (flip ? {x_size, 3'b111} : 6'd0);
|
||||
pal_d <= pal;
|
||||
flip_d <= flip;
|
||||
end
|
||||
|
||||
|
||||
// TS-line address
|
||||
reg flip_r;
|
||||
|
||||
wire [8:0] x_next = ts_waddr + {{8{flip_r}}, 1'b1};
|
||||
wire tsr_rld_stb = tsr_rld && dram_next;
|
||||
wire [8:0] ts_waddr_mx = tsr_rld_stb ? x_coord_d : (render_on ? x_next : ts_waddr);
|
||||
|
||||
always @(posedge clk)
|
||||
ts_waddr <= ts_waddr_mx;
|
||||
|
||||
always @(posedge clk)
|
||||
if (tsr_rld_stb)
|
||||
begin
|
||||
pal_r <= pal_d;
|
||||
flip_r <= flip_d;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
140
rtl/z80/zclock.v
Normal file
140
rtl/z80/zclock.v
Normal file
@ -0,0 +1,140 @@
|
||||
// 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
|
||||
|
||||
`include "tune.v"
|
||||
|
||||
module zclock
|
||||
(
|
||||
input clk,
|
||||
output reg zclk_out = 0, // generated Z80 clock, passed through inverter externally
|
||||
input c0, c2,
|
||||
|
||||
input wire iorq_s,
|
||||
input wire external_port,
|
||||
|
||||
output reg zpos,
|
||||
output reg zneg,
|
||||
|
||||
// stall enables and triggers
|
||||
input wire cpu_stall,
|
||||
input wire ide_stall,
|
||||
input wire dos_on,
|
||||
input wire vdos_off,
|
||||
|
||||
`ifdef PENT_312
|
||||
input wire boost_start,
|
||||
input wire [4:0] hcnt,
|
||||
input wire upper8,
|
||||
`endif
|
||||
|
||||
input [1:0] turbo // 2'b00 - 3.5 MHz
|
||||
// 2'b01 - 7.0 MHz
|
||||
// 2'b1x - 14.0 MHz
|
||||
);
|
||||
|
||||
`ifdef PENT_312
|
||||
// Turbo-boost for Pentagon 71680 tacts emulation with 312 video lines
|
||||
wire [1:0] turbo_int = (turbo == 2'b00) ? (t_boost ? 2'b01 : 2'b00) : turbo;
|
||||
reg t_boost = 0;
|
||||
reg [4:0] hcnt_r = 0;
|
||||
always @(posedge clk)
|
||||
if (boost_start && !t_boost)
|
||||
begin
|
||||
t_boost <= 1'b1;
|
||||
hcnt_r <= hcnt;
|
||||
end
|
||||
else if (t_boost && !upper8 && (hcnt_r == hcnt))
|
||||
t_boost <= 1'b0;
|
||||
`else
|
||||
wire [1:0] turbo_int = turbo;
|
||||
`endif
|
||||
|
||||
// wait generator
|
||||
reg [3:0] stall_count = 0;
|
||||
|
||||
wire dos_stall = dos_on || vdos_off;
|
||||
wire io_stall = iorq_s && external_port && turbo_int[1];
|
||||
wire stall_start = dos_stall || io_stall;
|
||||
wire stall_count_end = stall_count[3];
|
||||
wire dos_io_stall = stall_start || !stall_count_end;
|
||||
|
||||
always @(posedge clk)
|
||||
if (stall_start)
|
||||
begin
|
||||
if (dos_stall)
|
||||
stall_count <= 4'd4; // 4 tacts 28MHz (1 tact 7MHz)
|
||||
else if (io_stall)
|
||||
stall_count <= 4'd0; // 8 tacts 28MHz (1 tact 3.5MHz)
|
||||
end
|
||||
else if (!stall_count_end)
|
||||
stall_count <= stall_count + 3'd1;
|
||||
|
||||
// Z80 clocking pre-strobes
|
||||
reg clk14_src = 0; // source for 14MHz clock
|
||||
reg c2_cnt = 0;
|
||||
|
||||
wire stall = cpu_stall || dos_io_stall || ide_stall;
|
||||
|
||||
wire pre_zpos_140 = clk14_src;
|
||||
wire pre_zneg_140 = ~clk14_src;
|
||||
|
||||
wire pre_zpos_70 = c2;
|
||||
wire pre_zneg_70 = c0;
|
||||
|
||||
wire pre_zpos_35 = c2_cnt && c2;
|
||||
wire pre_zneg_35 = !c2_cnt && c2;
|
||||
|
||||
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);
|
||||
|
||||
always @(posedge clk)
|
||||
if (!stall)
|
||||
clk14_src <= ~clk14_src;
|
||||
|
||||
always @(posedge clk) if (c2)
|
||||
c2_cnt <= ~c2_cnt;
|
||||
|
||||
// Z80 clocking strobes
|
||||
always @(posedge clk)
|
||||
begin
|
||||
zpos <= !stall && pre_zpos && zclk_out;
|
||||
zneg <= !stall && pre_zneg && !zclk_out;
|
||||
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_out
|
||||
// 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_out <= 1'b0;
|
||||
|
||||
if (zneg)
|
||||
zclk_out <= 1'b1;
|
||||
end
|
||||
|
||||
endmodule
|
136
rtl/z80/zint.v
Normal file
136
rtl/z80/zint.v
Normal file
@ -0,0 +1,136 @@
|
||||
|
||||
`include "tune.v"
|
||||
|
||||
module zint
|
||||
(
|
||||
input wire clk,
|
||||
input wire zpos,
|
||||
input wire res,
|
||||
input wire wait_n,
|
||||
input wire int_start_frm,
|
||||
input wire int_start_lin,
|
||||
input wire int_start_dma,
|
||||
input wire int_start_wtp,
|
||||
input wire vdos, // pre_vdos
|
||||
input wire intack,
|
||||
`ifdef PENT_312
|
||||
output wire boost_start,
|
||||
`endif
|
||||
|
||||
input wire [7:0] intmask,
|
||||
output wire [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.
|
||||
|
||||
reg [1:0] int_sel = 0;
|
||||
reg int_frm;
|
||||
reg int_dma;
|
||||
reg int_lin;
|
||||
reg int_wtp;
|
||||
reg intack_r;
|
||||
wire intctr_fin;
|
||||
|
||||
localparam INTFRM = 2'b00;
|
||||
localparam INTLIN = 2'b01;
|
||||
localparam INTDMA = 2'b10;
|
||||
localparam INTWTP = 2'b11;
|
||||
|
||||
wire [7:0] vect [0:3];
|
||||
assign vect[INTFRM] = 8'hFF;
|
||||
assign vect[INTLIN] = 8'hFD;
|
||||
assign vect[INTDMA] = 8'hFB;
|
||||
assign vect[INTWTP] = 8'hF9;
|
||||
|
||||
assign im2vect = {vect[int_sel]};
|
||||
|
||||
wire int_all = (int_frm || int_lin || int_dma || int_wtp) && !vdos;
|
||||
assign int_n = int_all ? 1'b0 : 1'b1;
|
||||
|
||||
wire dis_int_frm = !intmask[0];
|
||||
wire dis_int_lin = !intmask[1];
|
||||
wire dis_int_dma = !intmask[2];
|
||||
wire dis_int_wtp = !intmask[3];
|
||||
|
||||
`ifdef PENT_312
|
||||
assign boost_start = intack_s || intctr_fin_s;
|
||||
|
||||
wire intctr_fin_s = !intctr_fin_r && intctr_fin;
|
||||
reg intctr_fin_r;
|
||||
always @(posedge clk)
|
||||
intctr_fin_r <= intctr_fin;
|
||||
`endif
|
||||
|
||||
wire intack_s = intack && !intack_r;
|
||||
always @(posedge clk)
|
||||
intack_r <= intack;
|
||||
|
||||
// ~INT source latch
|
||||
always @(posedge clk)
|
||||
if (intack_s)
|
||||
begin
|
||||
if (int_frm)
|
||||
int_sel <= INTFRM; // priority 0
|
||||
else if (int_lin)
|
||||
int_sel <= INTLIN; // priority 1
|
||||
else if (int_dma)
|
||||
int_sel <= INTDMA; // priority 2
|
||||
else if (int_wtp)
|
||||
int_sel <= INTWTP; // priority 3
|
||||
end
|
||||
|
||||
// ~INT generating
|
||||
always @(posedge clk)
|
||||
if (res || dis_int_frm)
|
||||
int_frm <= 1'b0;
|
||||
else if (int_start_frm)
|
||||
int_frm <= 1'b1;
|
||||
else if (intack_s || intctr_fin) // priority 0
|
||||
int_frm <= 1'b0;
|
||||
|
||||
always @(posedge clk)
|
||||
if (res || dis_int_lin)
|
||||
int_lin <= 1'b0;
|
||||
else if (int_start_lin)
|
||||
int_lin <= 1'b1;
|
||||
else if (intack_s && !int_frm) // priority 1
|
||||
int_lin <= 1'b0;
|
||||
|
||||
always @(posedge clk)
|
||||
if (res || dis_int_dma)
|
||||
int_dma <= 1'b0;
|
||||
else if (int_start_dma)
|
||||
int_dma <= 1'b1;
|
||||
else if (intack_s && !int_frm && !int_lin) // priority 2
|
||||
int_dma <= 1'b0;
|
||||
|
||||
always @(posedge clk)
|
||||
if (res || dis_int_wtp)
|
||||
int_wtp <= 1'b0;
|
||||
else if (int_start_wtp)
|
||||
int_wtp <= 1'b1;
|
||||
else if (intack_s && !int_frm && !int_lin && !int_dma) // priority 3
|
||||
int_wtp <= 1'b0;
|
||||
|
||||
// ~WAIT resync
|
||||
reg wait_r;
|
||||
always @(posedge clk)
|
||||
wait_r <= !wait_n;
|
||||
|
||||
// ~INT counter
|
||||
reg [5:0] intctr;
|
||||
assign intctr_fin = intctr[5]; // 32 clks
|
||||
|
||||
always @(posedge clk, posedge int_start_frm)
|
||||
begin
|
||||
if (int_start_frm)
|
||||
intctr <= 1'b0;
|
||||
else if (zpos && !intctr_fin && !wait_r && !vdos)
|
||||
intctr <= intctr + 1'b1;
|
||||
end
|
||||
|
||||
endmodule
|
62
rtl/z80/zmaps.v
Normal file
62
rtl/z80/zmaps.v
Normal file
@ -0,0 +1,62 @@
|
||||
|
||||
// This module maps z80 memory accesses into FPGA RAM and ports
|
||||
|
||||
`include "tune.v"
|
||||
|
||||
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 SFIL = 3'b001;
|
||||
localparam REGS = 4'b0100;
|
||||
|
||||
// DMA
|
||||
wire dma_req = dma_cram_we || dma_sfile_we;
|
||||
|
||||
// control signals
|
||||
wire hit = (a[15:12] == fmaddr[3:0]) && fmaddr[4] && memwr_s;
|
||||
wire cram_hit = (a[11:9] == CRAM) && hit;
|
||||
wire sfile_hit = (a[11:9] == SFIL) && hit;
|
||||
|
||||
// write enables
|
||||
wire lower_byte_we = (cram_hit || sfile_hit) && !a[0];
|
||||
assign cram_we = dma_req ? dma_cram_we : cram_hit && a[0];
|
||||
assign sfile_we = dma_req ? dma_sfile_we : sfile_hit && a[0];
|
||||
assign regs_we = (a[11:8] == REGS) && hit;
|
||||
|
||||
// LSB fetching
|
||||
reg [7:0] lower_byte;
|
||||
|
||||
assign zma = dma_req ? dma_wraddr : a[8:1];
|
||||
assign zmd = dma_req ? dma_data : {d, lower_byte};
|
||||
|
||||
always @(posedge clk)
|
||||
if (lower_byte_we)
|
||||
lower_byte <= d;
|
||||
|
||||
endmodule
|
321
rtl/z80/zmem.v
Normal file
321
rtl/z80/zmem.v
Normal file
@ -0,0 +1,321 @@
|
||||
`include "tune.v"
|
||||
|
||||
// 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 c1, c2, c3,
|
||||
input wire zneg, // strobes which show positive and negative edges of zclk
|
||||
|
||||
// Z80
|
||||
input wire rst,
|
||||
input wire [15:0] za,
|
||||
output wire [ 7:0] zd_out, // output to Z80 bus
|
||||
output wire zd_ena, // output to Z80 bus enable
|
||||
|
||||
input wire opfetch,
|
||||
input wire opfetch_s,
|
||||
input wire memrd,
|
||||
input wire memwr,
|
||||
input wire memwr_s,
|
||||
|
||||
input wire [ 1:0] turbo, // 2'b00 - 3.5,
|
||||
// 2'b01 - 7.0,
|
||||
// 2'b1x - 14.0
|
||||
input wire [3:0] cache_en,
|
||||
input wire [3:0] memconf,
|
||||
input wire [31:0] xt_page,
|
||||
|
||||
output wire [4:0] rompg,
|
||||
output wire csrom,
|
||||
output wire romoe_n,
|
||||
output wire romwe_n,
|
||||
|
||||
output wire dos,
|
||||
output wire dos_on,
|
||||
output wire dos_off,
|
||||
output wire vdos,
|
||||
output reg pre_vdos,
|
||||
input wire vdos_on,
|
||||
input wire vdos_off,
|
||||
|
||||
// DRAM
|
||||
output wire cpu_req,
|
||||
output wire [20:0] cpu_addr,
|
||||
output wire cpu_wrbsel,
|
||||
input wire [15:0] cpu_rddata,
|
||||
input wire cpu_next,
|
||||
input wire cpu_strobe,
|
||||
input wire cpu_latch,
|
||||
output wire cpu_stall // for zclock
|
||||
);
|
||||
|
||||
// controls
|
||||
wire rom128 = memconf[0];
|
||||
wire w0_we = memconf[1];
|
||||
wire w0_map_n = memconf[2];
|
||||
wire w0_ram = memconf[3];
|
||||
|
||||
// pager
|
||||
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];
|
||||
|
||||
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];
|
||||
|
||||
// DOS signal control
|
||||
reg 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
|
||||
|
||||
always @(posedge clk)
|
||||
if (rst)
|
||||
dos_r <= 1'b0;
|
||||
|
||||
else if (dos_off)
|
||||
dos_r <= 1'b0;
|
||||
else if (dos_on)
|
||||
dos_r <= 1'b1;
|
||||
|
||||
// VDOS signal control
|
||||
// vdos switching is delayed till next opfetch due to INIR that writes right after iord cycle
|
||||
|
||||
reg vdos_r;
|
||||
|
||||
assign vdos = opfetch ? pre_vdos : vdos_r; // vdos appears as soon as first opfetch
|
||||
|
||||
always @(posedge clk)
|
||||
if (rst || vdos_off)
|
||||
begin
|
||||
pre_vdos <= 1'b0;
|
||||
vdos_r <= 1'b0;
|
||||
end
|
||||
else if (vdos_on)
|
||||
pre_vdos <= 1'b1;
|
||||
else if (opfetch_s)
|
||||
vdos_r <= pre_vdos;
|
||||
|
||||
// RAM
|
||||
wire cache_hit_en;
|
||||
assign zd_ena = !rom_n_ram && memrd;
|
||||
wire ramreq = ((memrd && !cache_hit_en) || (memwr && ramwr_en));
|
||||
|
||||
// address, data in and data out
|
||||
wire [15:0] cache_d;
|
||||
wire cache_v;
|
||||
|
||||
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
|
||||
|
||||
// 7/3.5MHz support
|
||||
reg ramreq_r;
|
||||
reg pre_ramreq_r;
|
||||
reg pending_cpu_req;
|
||||
reg stall14_cycrd;
|
||||
reg stall14_fin;
|
||||
|
||||
wire dram_beg = ramreq && !pre_ramreq_r && zneg;
|
||||
wire cpureq_357 = ramreq && !ramreq_r;
|
||||
wire cpureq_14 = dram_beg || pending_cpu_req;
|
||||
wire stall357 = cpureq_357 && !cpu_next;
|
||||
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;
|
||||
wire stall14 = stall14_ini || stall14_cyc || stall14_fin;
|
||||
|
||||
wire turbo14 = turbo[1];
|
||||
assign cpu_req = turbo14 ? cpureq_14 : cpureq_357;
|
||||
assign cpu_stall = turbo14 ? stall14 : stall357;
|
||||
|
||||
// 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
|
||||
|
||||
always @(posedge clk)
|
||||
if (c3 && !cpu_stall)
|
||||
ramreq_r <= ramreq;
|
||||
|
||||
always @(posedge clk)
|
||||
if (zneg)
|
||||
pre_ramreq_r <= ramreq;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
always @(posedge clk)
|
||||
if (rst)
|
||||
stall14_fin <= 1'b0;
|
||||
else if (stall14_fin && ((opfetch && c1) || (memrd && c2)))
|
||||
stall14_fin <= 1'b0;
|
||||
else if (cpu_next && c3 && cpu_req && (opfetch || memrd))
|
||||
stall14_fin <= 1'b1;
|
||||
|
||||
// cache
|
||||
wire [12:0] cache_a;
|
||||
wire [12:0] cpu_hi_addr = {page[7:0], za[13:9]};
|
||||
// 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
|
||||
assign 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 [7:0] ch_addr = cpu_addr[7:0];
|
||||
// wire [14:0] cpu_hi_addr = {page[7:0], za[13:7]};
|
||||
// wire [14:0] cache_a;
|
||||
// wire [7:0] ch_addr = {2'b0, cpu_addr[5:0]};
|
||||
|
||||
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})
|
||||
);
|
||||
/*
|
||||
altdpram cache_data
|
||||
(
|
||||
.inclock (clk),
|
||||
.outclock (clk),
|
||||
.data (cpu_rddata),
|
||||
.rdaddress (ch_addr),
|
||||
.wraddress (ch_addr),
|
||||
.wren (cpu_strobe),
|
||||
.q (cache_d),
|
||||
.aclr (1'b0),
|
||||
.byteena (1'b1),
|
||||
.inclocken (1'b1),
|
||||
.outclocken (1'b1),
|
||||
.rdaddressstall (1'b0),
|
||||
.rden (1'b1),
|
||||
.wraddressstall (1'b0)
|
||||
);
|
||||
|
||||
defparam
|
||||
cache_data.indata_aclr = "OFF",
|
||||
cache_data.indata_reg = "INCLOCK",
|
||||
cache_data.intended_device_family = "ACEX1K",
|
||||
cache_data.lpm_type = "altdpram",
|
||||
cache_data.outdata_aclr = "OFF",
|
||||
cache_data.outdata_reg = "OUTCLOCK",
|
||||
cache_data.rdaddress_aclr = "OFF",
|
||||
cache_data.rdaddress_reg = "UNREGISTERED",
|
||||
cache_data.rdcontrol_aclr = "OFF",
|
||||
cache_data.rdcontrol_reg = "UNREGISTERED",
|
||||
cache_data.width = 16,
|
||||
cache_data.widthad = 8,
|
||||
cache_data.wraddress_aclr = "OFF",
|
||||
cache_data.wraddress_reg = "INCLOCK",
|
||||
cache_data.wrcontrol_aclr = "OFF",
|
||||
cache_data.wrcontrol_reg = "INCLOCK";
|
||||
|
||||
altdpram cache_addr
|
||||
(
|
||||
.inclock (clk),
|
||||
.outclock (clk),
|
||||
.data ({!cache_inv, cpu_hi_addr}),
|
||||
.rdaddress (ch_addr),
|
||||
.wraddress (ch_addr),
|
||||
.wren (cpu_strobe || cache_inv),
|
||||
.q ({cache_v, cache_a}),
|
||||
.aclr (1'b0),
|
||||
.byteena (1'b1),
|
||||
.inclocken (1'b1),
|
||||
.outclocken (1'b1),
|
||||
.rdaddressstall (1'b0),
|
||||
.rden (1'b1),
|
||||
.wraddressstall (1'b0)
|
||||
);
|
||||
|
||||
defparam
|
||||
cache_addr.indata_aclr = "OFF",
|
||||
cache_addr.indata_reg = "INCLOCK",
|
||||
cache_addr.intended_device_family = "ACEX1K",
|
||||
cache_addr.lpm_type = "altdpram",
|
||||
cache_addr.outdata_aclr = "OFF",
|
||||
cache_addr.outdata_reg = "OUTCLOCK",
|
||||
cache_addr.rdaddress_aclr = "OFF",
|
||||
cache_addr.rdaddress_reg = "UNREGISTERED",
|
||||
cache_addr.rdcontrol_aclr = "OFF",
|
||||
cache_addr.rdcontrol_reg = "UNREGISTERED",
|
||||
cache_addr.width = 14,
|
||||
cache_addr.widthad = 8,
|
||||
cache_addr.wraddress_aclr = "OFF",
|
||||
cache_addr.wraddress_reg = "INCLOCK",
|
||||
cache_addr.wrcontrol_aclr = "OFF",
|
||||
cache_addr.wrcontrol_reg = "INCLOCK";
|
||||
*/
|
||||
|
||||
// ROM chip
|
||||
assign csrom = rom_n_ram;
|
||||
assign romoe_n = !memrd;
|
||||
assign romwe_n = !(memwr && w0_we);
|
||||
assign rompg = xtpage[0][4:0];
|
||||
|
||||
endmodule
|
746
rtl/z80/zports.v
Normal file
746
rtl/z80/zports.v
Normal file
@ -0,0 +1,746 @@
|
||||
|
||||
// PentEvo project (c) NedoPC 2008-2010
|
||||
|
||||
`include "tune.v"
|
||||
|
||||
module zports
|
||||
(
|
||||
input wire zclk, // z80 clock
|
||||
input wire clk,
|
||||
|
||||
input wire [ 7:0] din,
|
||||
output reg [ 7:0] dout,
|
||||
output wire dataout,
|
||||
input wire [15:0] a,
|
||||
|
||||
input wire rst, // system reset
|
||||
input wire opfetch,
|
||||
|
||||
input wire rd,
|
||||
input wire wr,
|
||||
input wire rdwr,
|
||||
|
||||
input wire iorq,
|
||||
input wire iorq_s,
|
||||
input wire iord,
|
||||
input wire iord_s,
|
||||
input wire iowr,
|
||||
input wire iowr_s,
|
||||
input wire iordwr,
|
||||
input wire iordwr_s,
|
||||
|
||||
output wire porthit, // when internal port hit occurs, this is 1, else 0; used for iorq1_n iorq2_n on zxbus
|
||||
output wire external_port, // asserts for AY and VG93 accesses
|
||||
|
||||
output wire zborder_wr,
|
||||
output wire border_wr,
|
||||
output wire zvpage_wr,
|
||||
output wire vpage_wr,
|
||||
output wire vconf_wr,
|
||||
output wire gx_offsl_wr,
|
||||
output wire gx_offsh_wr,
|
||||
output wire gy_offsl_wr,
|
||||
output wire gy_offsh_wr,
|
||||
output wire t0x_offsl_wr,
|
||||
output wire t0x_offsh_wr,
|
||||
output wire t0y_offsl_wr,
|
||||
output wire t0y_offsh_wr,
|
||||
output wire t1x_offsl_wr,
|
||||
output wire t1x_offsh_wr,
|
||||
output wire t1y_offsl_wr,
|
||||
output wire t1y_offsh_wr,
|
||||
output wire tsconf_wr,
|
||||
output wire palsel_wr,
|
||||
output wire tmpage_wr,
|
||||
output wire t0gpage_wr,
|
||||
output wire t1gpage_wr,
|
||||
output wire sgpage_wr,
|
||||
output wire hint_beg_wr,
|
||||
output wire vint_begl_wr,
|
||||
output wire vint_begh_wr,
|
||||
|
||||
output wire [31:0] xt_page,
|
||||
|
||||
output reg [4:0] fmaddr,
|
||||
input wire regs_we,
|
||||
|
||||
output reg [7:0] sysconf,
|
||||
output reg [7:0] memconf,
|
||||
output reg [3:0] cacheconf,
|
||||
input wire cfg_floppy_swap,
|
||||
output reg [7:0] fddvirt,
|
||||
|
||||
`ifdef FDR
|
||||
output reg fdr_en,
|
||||
output wire fdr_cnt_lat,
|
||||
input wire [18:0] fdr_cnt,
|
||||
|
||||
output wire [9:0] dmaport_wr,
|
||||
`else
|
||||
output wire [8:0] dmaport_wr,
|
||||
`endif
|
||||
input wire dma_act,
|
||||
output reg [1:0] dmawpdev,
|
||||
|
||||
|
||||
output reg [7:0] intmask,
|
||||
|
||||
input wire dos,
|
||||
input wire vdos,
|
||||
output wire vdos_on,
|
||||
output wire vdos_off,
|
||||
|
||||
output wire ay_bdir,
|
||||
output wire ay_bc1,
|
||||
output wire covox_wr,
|
||||
output wire beeper_wr,
|
||||
|
||||
input wire tape_read,
|
||||
|
||||
`ifdef IDE_HDD
|
||||
// IDE interface
|
||||
input wire [15:0] ide_in,
|
||||
output wire [15:0] ide_out,
|
||||
output wire ide_cs0_n,
|
||||
output wire ide_cs1_n,
|
||||
output wire ide_req,
|
||||
input wire ide_stb,
|
||||
input wire ide_ready,
|
||||
output reg ide_stall,
|
||||
`endif
|
||||
|
||||
input wire [ 4:0] keys_in, // keys (port FE)
|
||||
input wire [ 7:0] mus_in, // mouse (xxDF)
|
||||
|
||||
`ifdef KEMPSTON_8BIT
|
||||
input wire [ 7:0] kj_in,
|
||||
`else
|
||||
input wire [ 4:0] kj_in,
|
||||
`endif
|
||||
|
||||
input wire vg_intrq,
|
||||
input wire vg_drq, // from vg93 module - drq + irq read
|
||||
output wire vg_cs_n,
|
||||
output wire vg_wrFF,
|
||||
output wire [1:0] drive_sel, // disk drive selection
|
||||
|
||||
// SPI
|
||||
output wire sdcs_n,
|
||||
output wire sd2cs_n,
|
||||
`ifdef IDE_VDAC2
|
||||
output wire ftcs_n,
|
||||
`ifdef ESP32_SPI
|
||||
output wire espcs_n,
|
||||
`endif
|
||||
`endif
|
||||
output reg spi_mode,
|
||||
output wire sd_start,
|
||||
output wire [ 7:0] sd_datain,
|
||||
input wire [ 7:0] sd_dataout,
|
||||
|
||||
// WAIT-ports related
|
||||
output reg [ 7:0] wait_addr,
|
||||
output wire wait_start_gluclock, // begin wait from some ports
|
||||
output wire wait_start_comport, //
|
||||
output reg [ 7:0] wait_write,
|
||||
input wire [ 7:0] wait_read
|
||||
);
|
||||
|
||||
//#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;
|
||||
|
||||
`ifdef FDR
|
||||
localparam DMANUMH = 8'h2C;
|
||||
localparam FRCTRL = 8'h30;
|
||||
localparam FRCNT0 = 8'h30;
|
||||
localparam FRCNT1 = 8'h31;
|
||||
localparam FRCNT2 = 8'h32;
|
||||
`endif
|
||||
|
||||
`ifdef FDR
|
||||
localparam FDR_VER = 1'b1;
|
||||
`else
|
||||
localparam FDR_VER = 1'b0;
|
||||
`endif
|
||||
|
||||
`ifdef IDE_VDAC
|
||||
localparam VDAC_VER = 3'h3;
|
||||
`elsif IDE_VDAC2
|
||||
localparam VDAC_VER = 3'h7;
|
||||
`else
|
||||
localparam VDAC_VER = 3'h0;
|
||||
`endif
|
||||
|
||||
localparam PORTFE = 8'hFE;
|
||||
localparam PORTFD = 8'hFD;
|
||||
localparam PORTXT = 8'hAF;
|
||||
localparam PORTF7 = 8'hF7;
|
||||
localparam COVOX = 8'hFB;
|
||||
|
||||
`ifdef IDE_HDD
|
||||
localparam NIDE10 = 8'h10;
|
||||
localparam NIDE11 = 8'h11;
|
||||
localparam NIDE30 = 8'h30;
|
||||
localparam NIDE50 = 8'h50;
|
||||
localparam NIDE70 = 8'h70;
|
||||
localparam NIDE90 = 8'h90;
|
||||
localparam NIDEB0 = 8'hB0;
|
||||
localparam NIDED0 = 8'hD0;
|
||||
localparam NIDEF0 = 8'hF0;
|
||||
localparam NIDE08 = 8'h08;
|
||||
localparam NIDE28 = 8'h28;
|
||||
localparam NIDE48 = 8'h48;
|
||||
localparam NIDE68 = 8'h68;
|
||||
localparam NIDE88 = 8'h88;
|
||||
localparam NIDEA8 = 8'hA8;
|
||||
localparam NIDEC8 = 8'hC8;
|
||||
localparam NIDEE8 = 8'hE8;
|
||||
`endif
|
||||
|
||||
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
|
||||
|
||||
reg [3:0] spi_cs_n;
|
||||
reg pwr_up_reg;
|
||||
reg [7:0] rampage[0:3];
|
||||
wire gluclock_on;
|
||||
wire p7ffd_wr;
|
||||
|
||||
assign sdcs_n = spi_cs_n[0];
|
||||
assign sd2cs_n = spi_cs_n[2];
|
||||
`ifdef IDE_VDAC2
|
||||
assign ftcs_n = spi_cs_n[1];
|
||||
`ifdef ESP32_SPI
|
||||
assign espcs_n = spi_cs_n[3];
|
||||
`endif
|
||||
`endif
|
||||
|
||||
wire open_vg;
|
||||
wire [7:0] loa = a[7:0];
|
||||
wire [7:0] hoa = regs_we ? a[7:0] : a[15:8];
|
||||
|
||||
wire vg_port = (loa==VGCOM) || (loa==VGTRK) || (loa==VGSEC) || (loa==VGDAT);
|
||||
wire vgsys_port = (loa==VGSYS);
|
||||
|
||||
assign porthit = ((loa==PORTFE) || (loa==PORTXT) || (loa==PORTFD) || (loa==COVOX)) || ((loa==PORTF7) && !dos)
|
||||
`ifdef IDE_HDD
|
||||
|| ide_all
|
||||
`endif
|
||||
|| ((vg_port || vgsys_port) && (dos || open_vg)) || ((loa==KJOY) && !dos && !open_vg) || (loa==KMOUSE) || ((loa==SDCFG) || (loa==SDDAT)) || (loa==COMPORT);
|
||||
|
||||
`ifdef IDE_HDD
|
||||
wire ide_all = ide_even || ide_port11;
|
||||
wire ide_even = (loa[2:0] == 3'b000) && (loa[3] != loa[4]); // even ports
|
||||
wire ide_port11 = (loa==NIDE11); // 11
|
||||
wire ide_port10 = (loa==NIDE10); // 10
|
||||
wire ide_portc8 = (loa==NIDEC8); // C8
|
||||
`endif
|
||||
|
||||
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);
|
||||
|
||||
// zclk-synchronous strobes
|
||||
reg iowr_reg;
|
||||
reg iord_reg;
|
||||
reg port_wr;
|
||||
reg port_rd;
|
||||
|
||||
always @(posedge zclk)
|
||||
begin
|
||||
iowr_reg <= iowr;
|
||||
iord_reg <= iord;
|
||||
|
||||
if (!iowr_reg && iowr)
|
||||
port_wr <= 1'b1;
|
||||
else
|
||||
port_wr <= 1'b0;
|
||||
|
||||
if (!iord_reg && iord)
|
||||
port_rd <= 1'b1;
|
||||
else
|
||||
port_rd <= 1'b0;
|
||||
end
|
||||
|
||||
// reading ports
|
||||
always @*
|
||||
begin
|
||||
case (loa)
|
||||
PORTFE:
|
||||
dout = {1'b1, tape_read, 1'b1, keys_in};
|
||||
|
||||
`ifdef IDE_HDD
|
||||
NIDE10,NIDE30,NIDE50,NIDE70,NIDE90,NIDEB0,NIDED0,NIDEF0,NIDE08,NIDE28,NIDE48,NIDE68,NIDE88,NIDEA8,NIDEC8,NIDEE8:
|
||||
dout = iderdeven;
|
||||
NIDE11:
|
||||
dout = iderdodd;
|
||||
`endif
|
||||
|
||||
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]];
|
||||
|
||||
`ifdef FDR
|
||||
FRCNT0:
|
||||
dout = fdr_cnt[7:0];
|
||||
|
||||
FRCNT1:
|
||||
dout = fdr_cnt[15:8];
|
||||
|
||||
FRCNT2:
|
||||
dout = {5'b0, fdr_cnt[18:16]};
|
||||
`endif
|
||||
default:
|
||||
dout = 8'hFF;
|
||||
|
||||
endcase
|
||||
end
|
||||
|
||||
VGSYS:
|
||||
dout = {vg_intrq, vg_drq, 6'b111111};
|
||||
|
||||
KJOY:
|
||||
`ifdef KEMPSTON_8BIT
|
||||
dout = kj_in;
|
||||
`else
|
||||
dout = {3'b000, kj_in};
|
||||
`endif
|
||||
|
||||
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) // $BFF7 - data i/o
|
||||
dout = wait_read;
|
||||
// dout = 8'h55;
|
||||
else // any other $xxF7 port
|
||||
dout = 8'hFF;
|
||||
end
|
||||
|
||||
COMPORT:
|
||||
begin
|
||||
dout = wait_read; // $F8EF..$FFEF
|
||||
end
|
||||
|
||||
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 = 1'b1;
|
||||
always @(posedge clk)
|
||||
if (iord_s & (loa == PORTXT) & (hoa == XSTAT))
|
||||
begin
|
||||
pwr_up_reg <= pwr_up;
|
||||
pwr_up <= 1'b0;
|
||||
end
|
||||
|
||||
wire portfe_wr = (loa==PORTFE) && iowr_s;
|
||||
assign beeper_wr = portfe_wr;
|
||||
assign covox_wr = (loa==COVOX) && iowr_s;
|
||||
wire portxt_wr = ((loa==PORTXT) && iowr_s) || regs_we;
|
||||
wire portxt_rd = (loa==PORTXT) && iord_s;
|
||||
|
||||
assign xt_page = {rampage[3], rampage[2], rampage[1], rampage[0]};
|
||||
|
||||
// writing ports
|
||||
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);
|
||||
`ifdef FDR
|
||||
assign dmaport_wr[9] = portxt_wr && (hoa == DMANUMH);
|
||||
`endif
|
||||
|
||||
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));
|
||||
`ifdef FDR
|
||||
assign fdr_cnt_lat = (portxt_rd && (hoa == FRCNT0));
|
||||
`endif
|
||||
|
||||
reg m1_lock128;
|
||||
|
||||
wire lock128_2 = memconf[7:6] == 2'b10; // mode 2
|
||||
wire lock128_3 = memconf[7:6] == 2'b11; // mode 3
|
||||
wire lock128 = lock128_3 ? 1'b0 : (lock128_2 ? m1_lock128 : memconf[6]);
|
||||
|
||||
always @(posedge clk) if (opfetch)
|
||||
m1_lock128 <= !(din[7] ^ din[6]);
|
||||
|
||||
always @(posedge clk or posedge rst)
|
||||
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;
|
||||
|
||||
`ifdef FDR
|
||||
fdr_en <= 1'b0;
|
||||
`endif
|
||||
end
|
||||
else // if (rst)
|
||||
begin
|
||||
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;
|
||||
|
||||
`ifdef FDR
|
||||
if (hoa == FRCTRL)
|
||||
fdr_en <= din[0];
|
||||
`endif
|
||||
|
||||
if (hoa == INTMASK)
|
||||
intmask <= din;
|
||||
end
|
||||
end
|
||||
|
||||
// 7FFD port
|
||||
reg lock48;
|
||||
|
||||
assign p7ffd_wr = !a[15] && (loa==PORTFD) && iowr_s && !lock48;
|
||||
|
||||
always @(posedge clk or posedge rst)
|
||||
if (rst)
|
||||
lock48 <= 1'b0;
|
||||
else if (p7ffd_wr && !lock128_3)
|
||||
lock48 <= din[5];
|
||||
|
||||
// AY control
|
||||
wire ay_hit = (loa==PORTFD) & a[15];
|
||||
assign ay_bc1 = ay_hit & a[14] & iordwr;
|
||||
assign ay_bdir = ay_hit & iowr;
|
||||
|
||||
// VG93
|
||||
reg [1:0] drive_sel_raw;
|
||||
|
||||
wire [3:0] fddvrt = fddvirt[3:0];
|
||||
wire virt_vg = fddvrt[drive_sel_raw];
|
||||
assign open_vg = fddvirt[7];
|
||||
assign drive_sel = {drive_sel_raw[1], drive_sel_raw[0] ^ cfg_floppy_swap};
|
||||
|
||||
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
|
||||
always @(posedge clk)
|
||||
if (vg_wrDS)
|
||||
drive_sel_raw <= din;
|
||||
|
||||
// SD card (Z-controller compatible)
|
||||
wire sdcfg_wr;
|
||||
wire sddat_wr;
|
||||
wire sddat_rd;
|
||||
|
||||
assign sdcfg_wr = (loa==SDCFG) && iowr_s;
|
||||
assign sddat_wr = (loa==SDDAT) && iowr_s;
|
||||
assign sddat_rd = (loa==SDDAT) && iord_s;
|
||||
|
||||
// SDCFG write - sdcs_n control
|
||||
always @(posedge clk or posedge rst)
|
||||
if (rst)
|
||||
begin
|
||||
spi_cs_n <= 4'b1111;
|
||||
spi_mode <= 1'b0;
|
||||
end
|
||||
else if (sdcfg_wr)
|
||||
begin
|
||||
spi_cs_n <= {~din[4:2], din[1]};
|
||||
// spi_mode <= din[7];
|
||||
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 or posedge rst)
|
||||
if (rst)
|
||||
peff7 <= 8'h00;
|
||||
else if (!a[12] && portf7_wr && !dos) // #EEF7 in dos is not accessible
|
||||
peff7 <= din;
|
||||
|
||||
// gluclock ports
|
||||
assign 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 zclk)
|
||||
begin
|
||||
// gluclocks
|
||||
if (gluclock_on && portf7_wr)
|
||||
begin
|
||||
if (!a[14]) // $BFF7 - data reg
|
||||
wait_write <= din;
|
||||
|
||||
if (!a[13]) // $DFF7 - addr reg
|
||||
wait_addr <= din;
|
||||
end
|
||||
|
||||
// com ports
|
||||
if (comport_wr) // $xxEF
|
||||
wait_write <= din;
|
||||
|
||||
if (comport_wr || comport_rd)
|
||||
wait_addr <= a[15:8];
|
||||
|
||||
if ((loa==PORTXT) && (hoa == DMAWPA))
|
||||
wait_addr <= din;
|
||||
end
|
||||
|
||||
// wait from wait registers
|
||||
assign wait_start_gluclock = (gluclock_on && !a[14] && (portf7_rd || portf7_wr)); // $BFF7 - gluclock r/w
|
||||
assign wait_start_comport = (comport_rd || comport_wr);
|
||||
|
||||
`ifdef IDE_HDD
|
||||
// IDE ports
|
||||
// do NOT generate IDE write, if neither of ide_wrhi|lo latches set and writing to NIDE10
|
||||
wire ide_cs0 = ide_even && !ide_portc8;
|
||||
wire ide_cs1 = ide_portc8;
|
||||
wire ide_rd = rd && !(ide_rd_latch && ide_port10);
|
||||
wire ide_wr = wr && !(!ide_wrlo_latch && !ide_wrhi_latch && ide_port10);
|
||||
assign ide_req = iorq_s && ide_even && (ide_rd || ide_wr);
|
||||
assign ide_cs0_n = !ide_cs0;
|
||||
assign ide_cs1_n = !ide_cs1;
|
||||
|
||||
always @(posedge clk)
|
||||
if (ide_req)
|
||||
ide_stall <= 1'b1;
|
||||
else if (ide_ready)
|
||||
ide_stall <= 1'b0;
|
||||
|
||||
// control read & write triggers, which allow nemo-divide mod to work.
|
||||
// read trigger:
|
||||
reg ide_rd_trig; // nemo-divide read trigger
|
||||
always @(posedge zclk)
|
||||
begin
|
||||
if (ide_port10 && port_rd && !ide_rd_trig)
|
||||
ide_rd_trig <= 1'b1;
|
||||
else if (ide_all && (port_rd || port_wr))
|
||||
ide_rd_trig <= 1'b0;
|
||||
end
|
||||
|
||||
// two triggers for write sequence
|
||||
reg ide_wrlo_trig, ide_wrhi_trig; // nemo-divide write triggers
|
||||
always @(posedge zclk)
|
||||
if (ide_all && (port_rd || port_wr))
|
||||
begin
|
||||
if (ide_port11 && port_wr)
|
||||
ide_wrhi_trig <= 1'b1;
|
||||
else
|
||||
ide_wrhi_trig <= 1'b0;
|
||||
|
||||
if (ide_port10 && port_wr && !ide_wrhi_trig && !ide_wrlo_trig)
|
||||
ide_wrlo_trig <= 1'b1;
|
||||
else
|
||||
ide_wrlo_trig <= 1'b0;
|
||||
end
|
||||
|
||||
// normal read: #10(low), #11(high)
|
||||
// divide read: #10(low), #10(high)
|
||||
//
|
||||
// normal write: #11(high), #10(low)
|
||||
// divide write: #10(low), #10(high)
|
||||
|
||||
reg [15:0] idewrreg; // write register, either low or high part is pre-written here,
|
||||
// while other part is out directly from Z80 bus
|
||||
always @(posedge zclk)
|
||||
begin
|
||||
if (port_wr && ide_port11)
|
||||
idewrreg[15:8] <= din;
|
||||
|
||||
if (port_wr && ide_port10 && !ide_wrlo_trig)
|
||||
idewrreg[ 7:0] <= din;
|
||||
end
|
||||
|
||||
// generate read cycles for IDE as usual, except for reading #10
|
||||
// instead of #11 for high byte (nemo-divide). I use additional latch
|
||||
// since 'ide_rd_trig' clears during second Z80 IO read cycle to #10
|
||||
reg ide_rd_latch; // to save state of trigger during read cycle
|
||||
always @*
|
||||
if (!rd)
|
||||
ide_rd_latch <= ide_rd_trig;
|
||||
|
||||
reg ide_wrlo_latch, ide_wrhi_latch; // save state during write cycles
|
||||
always @*
|
||||
if (!wr)
|
||||
begin
|
||||
ide_wrlo_latch <= ide_wrlo_trig; // same for write triggers
|
||||
ide_wrhi_latch <= ide_wrhi_trig;
|
||||
end
|
||||
|
||||
// data read by Z80 from IDE
|
||||
wire idein_lo_rd = port_rd && ide_port10 && (!ide_rd_trig); // while high part is remembered here
|
||||
wire [7:0] iderdodd = iderdreg[15:8]; // read data from "odd" port (#11)
|
||||
wire [7:0] iderdeven = (ide_rd_latch && ide_port10) ? iderdreg[15:8] : iderdreg[7:0]; // to control read data from "even" ide ports (all except #11)
|
||||
// wire [7:0] iderdeven = (ide_rd_latch && ide_port10) ? idehiin[7:0] : ide_in[7:0]; // to control read data from "even" ide ports (all except #11)
|
||||
|
||||
reg [15:0] iderdreg;
|
||||
// reg [7:0] idehiin; // IDE high part read register: low part is read directly to Z80 bus,
|
||||
always @(posedge clk)
|
||||
if (ide_stb)
|
||||
iderdreg <= ide_in;
|
||||
// if (idein_lo_rd)
|
||||
// idehiin <= ide_in[15:8];
|
||||
|
||||
// data written to IDE from Z80
|
||||
wire [7:0] ideout1 = ide_wrhi_latch ? idewrreg[15:8] : din[ 7:0];
|
||||
wire [7:0] ideout0 = ide_wrlo_latch ? idewrreg[ 7:0] : din[ 7:0];
|
||||
assign ide_out = {ideout1, ideout0};
|
||||
`endif
|
||||
|
||||
endmodule
|
99
rtl/z80/zsignals.v
Normal file
99
rtl/z80/zsignals.v
Normal file
@ -0,0 +1,99 @@
|
||||
|
||||
// Decoding and strobing of z80 signals
|
||||
|
||||
`include "tune.v"
|
||||
|
||||
module zsignals
|
||||
(
|
||||
// clocks
|
||||
input wire clk,
|
||||
input wire zpos,
|
||||
|
||||
// z80 interface input
|
||||
input wire rst_n,
|
||||
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 rst,
|
||||
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 iordwr,
|
||||
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 iordwr_s,
|
||||
output wire memrd_s,
|
||||
output wire memwr_s,
|
||||
output wire memrw_s,
|
||||
output wire opfetch_s
|
||||
);
|
||||
|
||||
reg [1:0] iorq_r = 0, mreq_r = 0;
|
||||
|
||||
// invertors
|
||||
assign rst = !rst_n;
|
||||
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 iordwr = 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 iordwr_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
|
||||
always @(posedge clk) if (zpos)
|
||||
begin
|
||||
iorq_r[0] <= iorq;
|
||||
mreq_r[0] <= mreq;
|
||||
end
|
||||
|
||||
always @(posedge clk)
|
||||
begin
|
||||
iorq_r[1] <= iorq_r[0];
|
||||
mreq_r[1] <= mreq_r[0];
|
||||
end
|
||||
|
||||
endmodule
|
Reference in New Issue
Block a user