diff --git a/TSConf.qsf b/TSConf.qsf index 1ddadf0..665236c 100644 --- a/TSConf.qsf +++ b/TSConf.qsf @@ -285,3 +285,6 @@ set_global_assignment -name PRE_FLOW_SCRIPT_FILE "quartus_sh:build_id_verilog.tc set_global_assignment -name QIP_FILE pll.qip set_global_assignment -name QIP_FILE files.qip set_global_assignment -name QIP_FILE "mist-modules/mist.qip" +set_global_assignment -name SYSTEMVERILOG_FILE TSConf.sv +set_global_assignment -name SDC_FILE TSConf.sdc + diff --git a/TSConf.sdc b/TSConf.sdc index da23f4e..512d651 100644 --- a/TSConf.sdc +++ b/TSConf.sdc @@ -35,13 +35,13 @@ set_false_path -to [get_ports {AUDIO_R}] set_false_path -to [get_ports {LED}] set_false_path -from [get_ports {UART_RX}] -set_multicycle_path -to {tsconf|U16|*} -setup 2 -set_multicycle_path -to {tsconf|U16|*} -hold 1 - set_multicycle_path -from {tsconf|CPU|*} -setup 2 set_multicycle_path -from {tsconf|CPU|*} -hold 1 set_multicycle_path -to {tsconf|CPU|*} -setup 2 set_multicycle_path -to {tsconf|CPU|*} -hold 1 -set_multicycle_path -to {tsconf|U15|*} -setup 2 -set_multicycle_path -to {tsconf|U15|*} -hold 1 +set_multicycle_path -to {tsconf|saa1099|*} -setup 2 +set_multicycle_path -to {tsconf|saa1099|*} -hold 1 + +set_multicycle_path -to {tsconf|gs|*} -setup 2 +set_multicycle_path -to {tsconf|gs|*} -hold 1 diff --git a/TSConf.srf b/TSConf.srf index 756ce36..0e1df68 100644 --- a/TSConf.srf +++ b/TSConf.srf @@ -13,6 +13,22 @@ { "" "" "" "Port \"reset_value\" on the entity instantiation of \"h_counter\" is connected to a signal of width 32. The formal width of the signal in the module is 16. The extra bits will be ignored." { } { } 0 12020 "" 0 0 "Quartus II" 0 -1 0 ""} { "" "" "" "Overwriting existing clock: vip\|hps\|fpga_interfaces\|clocks_resets\|h2f_user0_clk" { } { } 0 332043 "" 0 0 "Quartus II" 0 -1 0 ""} { "" "" "" "LOCKED port on the PLL is not properly connected on instance \"emu:emu\|pll:pll\|pll_0002:pll_inst\|altera_pll:altera_pll_i\|general\[0\].gpll\". The LOCKED port on the PLL should be connected when the FBOUTCLK port is connected. Although it is unnecessary to connect the LOCKED signal, any logic driven off of an output clock of the PLL will not know when the PLL is locked and ready." { } { } 0 21300 "" 0 0 "Quartus II" 0 -1 0 ""} +{ "" "" "" "Net \"lut.data_a\" at jt49_exp.v(37) has no driver or initial value, using a default initial value '0'" { } { } 0 10030 "" 0 0 "Quartus II" 0 -1 0 ""} +{ "" "" "" "Net \"lut.waddr_a\" at jt49_exp.v(37) has no driver or initial value, using a default initial value '0'" { } { } 0 10030 "" 0 0 "Quartus II" 0 -1 0 ""} +{ "" "" "" "Net \"lut.we_a\" at jt49_exp.v(37) has no driver or initial value, using a default initial value '0'" { } { } 0 10030 "" 0 0 "Quartus II" 0 -1 0 ""} +{ "" "" "" "Net \"lfo_sh1_lut.data_a\" at jt12_pm.v(38) has no driver or initial value, using a default initial value '0'" { } { } 0 10030 "" 0 0 "Quartus II" 0 -1 0 ""} +{ "" "" "" "Net \"lfo_sh1_lut.waddr_a\" at jt12_pm.v(38) has no driver or initial value, using a default initial value '0'" { } { } 0 10030 "" 0 0 "Quartus II" 0 -1 0 ""} +{ "" "" "" "Net \"lfo_sh2_lut.data_a\" at jt12_pm.v(39) has no driver or initial value, using a default initial value '0'" { } { } 0 10030 "" 0 0 "Quartus II" 0 -1 0 ""} +{ "" "" "" "Net \"lfo_sh2_lut.waddr_a\" at jt12_pm.v(39) has no driver or initial value, using a default initial value '0'" { } { } 0 10030 "" 0 0 "Quartus II" 0 -1 0 ""} +{ "" "" "" "Net \"lfo_sh1_lut.we_a\" at jt12_pm.v(38) has no driver or initial value, using a default initial value '0'" { } { } 0 10030 "" 0 0 "Quartus II" 0 -1 0 ""} +{ "" "" "" "Net \"lfo_sh2_lut.we_a\" at jt12_pm.v(39) has no driver or initial value, using a default initial value '0'" { } { } 0 10030 "" 0 0 "Quartus II" 0 -1 0 ""} +{ "" "" "" "Verilog HDL or VHDL warning at video_out.v(83): object \"red0\" assigned a value but never read" { } { } 0 10036 "" 0 0 "Quartus II" 0 -1 0 ""} +{ "" "" "" "Verilog HDL or VHDL warning at video_out.v(84): object \"grn0\" assigned a value but never read" { } { } 0 10036 "" 0 0 "Quartus II" 0 -1 0 ""} +{ "" "" "" "Verilog HDL or VHDL warning at video_out.v(85): object \"blu0\" assigned a value but never read" { } { } 0 10036 "" 0 0 "Quartus II" 0 -1 0 ""} +{ "" "" "" "Verilog HDL or VHDL warning at video_out.v(86): object \"red1\" assigned a value but never read" { } { } 0 10036 "" 0 0 "Quartus II" 0 -1 0 ""} +{ "" "" "" "Verilog HDL or VHDL warning at video_out.v(87): object \"grn1\" assigned a value but never read" { } { } 0 10036 "" 0 0 "Quartus II" 0 -1 0 ""} +{ "" "" "" "Verilog HDL or VHDL warning at video_out.v(88): object \"blu1\" assigned a value but never read" { } { } 0 10036 "" 0 0 "Quartus II" 0 -1 0 ""} +{ "" "" "" "Verilog HDL assignment warning at zports.v(572): truncated value with size 8 to match size of target (2)" { } { } 0 10230 "" 0 0 "Quartus II" 0 -1 0 ""} { "" "" "" "*" { } { } 0 292013 "" 0 0 "Quartus II" 0 -1 0 ""} { "" "" "" "Vip.vip: Module dependency loop involving: \"HPS\"" { } { } 0 9999 "" 0 0 "Quartus II" 0 -1 0 ""} { "" "" "" "alt_vip_common_frame_counter.v" { } { } 0 9999 "" 0 0 "Quartus II" 0 -1 0 ""} diff --git a/TSConf.sv b/TSConf.sv index 8db8e2f..236b9b9 100644 --- a/TSConf.sv +++ b/TSConf.sv @@ -301,9 +301,7 @@ sd_card sd_card //////////////////// MAIN ////////////////////// wire [7:0] R,G,B; -wire HBlank,VBlank; wire VS, HS; -wire ce_vid; wire [15:0] SOUND_L; wire [15:0] SOUND_R; @@ -324,14 +322,11 @@ tsconf tsconf .SDRAM_nCS(SDRAM_nCS), // .SDRAM_CLK(SDRAM_CLK), - .VGA_R(R), - .VGA_G(G), - .VGA_B(B), - .VGA_HS(HS), - .VGA_VS(VS), - .VGA_HBLANK(HBlank), - .VGA_VBLANK(VBlank), - .VGA_CEPIX(ce_vid), + .VRED(R), + .VGRN(G), + .VBLU(B), + .VHSYNC(HS), + .VVSYNC(VS), .SD_SO(sdmiso), .SD_SI(sdmosi), @@ -345,12 +340,13 @@ tsconf tsconf .WARM_RESET(buttons[1]), .RTC(rtc), .OUT0(~status[30]), + .TAPE_IN(UART_RX), .CMOSCfg(CMOSCfg), .PS2_KEY({key_strobe,key_pressed,key_extended,key_code}), .PS2_MOUSE(ps2_mouse), - .joystick(joystick_0[5:0] | joystick_1[5:0]), + .JOYSTICK(joystick_0 | joystick_1), .loader_act(ioctl_download), .loader_addr(ioctl_addr[15:0]), diff --git a/files.qip b/files.qip index 3b45528..1e12883 100644 --- a/files.qip +++ b/files.qip @@ -1,20 +1,20 @@ set_global_assignment -name QIP_FILE rtl/T80/T80.qip -set_global_assignment -name VERILOG_FILE rtl/memory/dma.v -set_global_assignment -name VERILOG_FILE rtl/memory/arbiter.v -set_global_assignment -name VERILOG_FILE rtl/memory/sdram.v -set_global_assignment -name VERILOG_FILE rtl/memory/dpram.v -set_global_assignment -name VERILOG_FILE rtl/common/zsignals.v -set_global_assignment -name VERILOG_FILE rtl/common/zports.v -set_global_assignment -name VERILOG_FILE rtl/common/zmem.v -set_global_assignment -name VERILOG_FILE rtl/common/zmaps.v -set_global_assignment -name VERILOG_FILE rtl/common/zint.v -set_global_assignment -name VERILOG_FILE rtl/common/zclock.v -set_global_assignment -name VERILOG_FILE rtl/rtc/mc146818a.v +set_global_assignment -name VERILOG_FILE rtl/common/clock.v +set_global_assignment -name VERILOG_FILE rtl/common/dma.v +set_global_assignment -name VERILOG_FILE rtl/common/resetter.v +set_global_assignment -name VERILOG_FILE rtl/common/spi.v +set_global_assignment -name VERILOG_FILE rtl/dram/arbiter.v +set_global_assignment -name VERILOG_FILE rtl/dram/dpram.v +set_global_assignment -name VERILOG_FILE rtl/dram/sdram.v +set_global_assignment -name VERILOG_FILE rtl/periph/kempston_mouse.v +set_global_assignment -name VHDL_FILE rtl/periph/keyboard.vhd +set_global_assignment -name VERILOG_FILE rtl/periph/mc146818a.v +set_global_assignment -name VERILOG_FILE rtl/periph/vdac.v set_global_assignment -name VHDL_FILE rtl/sound/soundrive.vhd set_global_assignment -name QIP_FILE rtl/sound/jt12/jt03.qip set_global_assignment -name SYSTEMVERILOG_FILE rtl/sound/turbosound.sv -set_global_assignment -name VERILOG_FILE rtl/sound/gs.v set_global_assignment -name SYSTEMVERILOG_FILE rtl/sound/saa1099.sv +set_global_assignment -name VERILOG_FILE rtl/sound/gs.v set_global_assignment -name SYSTEMVERILOG_FILE rtl/sound/compressor.sv set_global_assignment -name VERILOG_FILE rtl/video/video_ts_render.v set_global_assignment -name VERILOG_FILE rtl/video/video_ts.v @@ -25,10 +25,11 @@ set_global_assignment -name VERILOG_FILE rtl/video/video_out.v set_global_assignment -name VERILOG_FILE rtl/video/video_mode.v set_global_assignment -name VERILOG_FILE rtl/video/video_fetch.v set_global_assignment -name VERILOG_FILE rtl/video/video_top.v -set_global_assignment -name VHDL_FILE rtl/keyboard.vhd -set_global_assignment -name VERILOG_FILE rtl/kempston_mouse.v -set_global_assignment -name VERILOG_FILE rtl/spi.v -set_global_assignment -name VERILOG_FILE rtl/clock.v +set_global_assignment -name VERILOG_FILE rtl/z80/zclock.v +set_global_assignment -name VERILOG_FILE rtl/z80/zint.v +set_global_assignment -name VERILOG_FILE rtl/z80/zmaps.v +set_global_assignment -name VERILOG_FILE rtl/z80/zmem.v +set_global_assignment -name VERILOG_FILE rtl/z80/zports.v +set_global_assignment -name VERILOG_FILE rtl/z80/zsignals.v set_global_assignment -name VERILOG_FILE rtl/tsconf.v -set_global_assignment -name SDC_FILE TSConf.sdc -set_global_assignment -name SYSTEMVERILOG_FILE TSConf.sv +set_global_assignment -name SEARCH_PATH rtl/ diff --git a/rtl/clock.v b/rtl/clock.v deleted file mode 100644 index 2854276..0000000 --- a/rtl/clock.v +++ /dev/null @@ -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 diff --git a/rtl/common/clock.v b/rtl/common/clock.v new file mode 100644 index 0000000..998eb04 --- /dev/null +++ b/rtl/common/clock.v @@ -0,0 +1,61 @@ + +// This module receives 28 MHz as input clock +// and makes 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 + +`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 diff --git a/rtl/memory/dma.v b/rtl/common/dma.v similarity index 72% rename from rtl/memory/dma.v rename to rtl/common/dma.v index a7e6e5b..b42bbad 100644 --- a/rtl/memory/dma.v +++ b/rtl/common/dma.v @@ -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 diff --git a/rtl/common/resetter.v b/rtl/common/resetter.v new file mode 100644 index 0000000..d0a4ed2 --- /dev/null +++ b/rtl/common/resetter.v @@ -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 + diff --git a/rtl/common/spi.v b/rtl/common/spi.v new file mode 100644 index 0000000..c4a562c --- /dev/null +++ b/rtl/common/spi.v @@ -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 diff --git a/rtl/common/zclock.v b/rtl/common/zclock.v deleted file mode 100644 index ffe2773..0000000 --- a/rtl/common/zclock.v +++ /dev/null @@ -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 diff --git a/rtl/common/zint.v b/rtl/common/zint.v deleted file mode 100644 index d104ba5..0000000 --- a/rtl/common/zint.v +++ /dev/null @@ -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 diff --git a/rtl/common/zmaps.v b/rtl/common/zmaps.v deleted file mode 100644 index 449e751..0000000 --- a/rtl/common/zmaps.v +++ /dev/null @@ -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 diff --git a/rtl/common/zmem.v b/rtl/common/zmem.v deleted file mode 100644 index 5e25b63..0000000 --- a/rtl/common/zmem.v +++ /dev/null @@ -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 diff --git a/rtl/common/zports.v b/rtl/common/zports.v deleted file mode 100644 index c48d740..0000000 --- a/rtl/common/zports.v +++ /dev/null @@ -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 diff --git a/rtl/common/zsignals.v b/rtl/common/zsignals.v deleted file mode 100644 index af91523..0000000 --- a/rtl/common/zsignals.v +++ /dev/null @@ -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 diff --git a/rtl/dram/arbiter.v b/rtl/dram/arbiter.v new file mode 100644 index 0000000..d09cb6e --- /dev/null +++ b/rtl/dram/arbiter.v @@ -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 diff --git a/rtl/memory/dpram.v b/rtl/dram/dpram.v similarity index 97% rename from rtl/memory/dpram.v rename to rtl/dram/dpram.v index 2ac8d6a..da99493 100644 --- a/rtl/memory/dpram.v +++ b/rtl/dram/dpram.v @@ -1,72 +1,72 @@ - -module dpram #(parameter DATAWIDTH=8, ADDRWIDTH=8, NUMWORDS=1<------- -// sdi: --------< di7 | di6 | di5 | di4 | di3 | di2 | di1 | di0 >------- -// bsync: ________/`````\_________________________________________________ -// start: _____/``\_______________________________________________________ -// din: ------------------------------------------------------------ -// 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 diff --git a/rtl/tsconf.rom b/rtl/tsconf.rom index 410b1b7..45adb04 100644 Binary files a/rtl/tsconf.rom and b/rtl/tsconf.rom differ diff --git a/rtl/tsconf.v b/rtl/tsconf.v index 623a581..8fe3feb 100644 --- a/rtl/tsconf.v +++ b/rtl/tsconf.v @@ -1,913 +1,1088 @@ +`include "tune.v" -/* ----------------------------------------------------------------[02.11.2014] - u16-TSConf Version 0.2.9 - DEVBOARD ReVerSE-U16 By MVV - ---------------------------------------------------------------------------- - V0.1.0 27.07.2014 ミソミオムミイミーム ミイミオムムミクム - V0.2.0 31.07.2014 ミエミセミアミーミイミサミオミス ムびミーミスムミサム肖ひセム PS/2, HDMI - V0.2.1 03.08.2014 ミエミセミアミーミイミサミオミス Delta-Sigma DAC, I2C - V0.2.3 11.08.2014 ミエミセミアミーミイミサミオミス enc424j600 - V0.2.4 24.08.2014 ミエミセミアミーミイミサミオミスミー ミソミセミエミエミオムミカミコミー IDE Video DAC (zports.v, video_out.v) - V0.2.5 07.09.2014 ミエミセミアミーミイミサミオミス ミソミセムム #0001=key_scan, ミクミキミシミオミスミオミスミクム ミイ keyboard.vhd - V0.2.6 09.09.2014 ミクムミソムミーミイミサミオミス ミイム巾イミセミエ ミソミーミサミクムびム ミイ (lut.vhd) - V0.2.7 13.09.2014 ミエムミセミカミーミスミクミオ ミシムσサム袴ひクミコミセミサミセムミー ミスミー tv80s, ミキミーミシミオミスミクミサ ミスミー t80s - V0.2.8 19.10.2014 ミクミスミイミオミスムひクムミセミイミーミス CLK ミイ ミシミセミエムσサム肖 video_tmbuf, video_sfile ミク ミエミセミアミーミイミサミオミスム ムミオミウミクムムびム ミスミー ミイム錦ミセミエミオ - V0.2.9 02.11.2014 ミキミーミシミオミスミー t80s, ミクムミソムミーミイミサミオミスミクム ミイ zint.v, zports.v, delta-sigma (ミソムミクミイミセミエミクム ミコ ミスミーミシミーミウミスミクムミクミイミーミスミクム ミエミクミスミーミシミクミコミセミイ) - WXEDA 10.03.2015 ミソミセムム ミスミー ミエミオミイミアミセムミエム WXEDA - - http://tslabs.info/forum/viewtopic.php?f=31&t=401 - http://zx-pk.ru/showthread.php?t=23528 - - Copyright (c) 2014 MVV, TS-Labs, dsp, waybester, palsw - - All rights reserved - - Redistribution and use in source and synthezised forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * Redistributions in synthesized form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - * Neither the name of the author nor the names of other contributors may - be used to endorse or promote products derived from this software without - specific prior written agreement from the author. - - * License is granted for non-commercial use only. A fee may not be charged - for redistributions as source code or in synthesized/hardware form without - specific prior written agreement from the author. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE. -*/ +// Pentevo project(c) NedoPC 2008-2011 +// +// top-level module tsconf ( - // Clocks - input clk, - input ce, + // Clocks + input clk, + input ce, - // SDRAM (32MB 16x16bit) - inout [15:0] SDRAM_DQ, - output [12:0] SDRAM_A, - output [1:0] SDRAM_BA, - output SDRAM_DQML, - output SDRAM_DQMH, - output SDRAM_nCS, - output SDRAM_nCAS, - output SDRAM_nRAS, - output SDRAM_nWE, - output SDRAM_CKE, - output SDRAM_CLK, + // SDRAM (32MB 16x16bit) + inout [15:0] SDRAM_DQ, + output [12:0] SDRAM_A, + output [1:0] SDRAM_BA, + output SDRAM_DQML, + output SDRAM_DQMH, + output SDRAM_nCS, + output SDRAM_nCAS, + output SDRAM_nRAS, + output SDRAM_nWE, + output SDRAM_CKE, + output SDRAM_CLK, - // VGA - output [7:0] VGA_R, - output [7:0] VGA_G, - output [7:0] VGA_B, - output VGA_HS, - output VGA_VS, - output VGA_HBLANK, - output VGA_VBLANK, - output VGA_CEPIX, + // VGA + output [7:0] VRED, + output [7:0] VGRN, + output [7:0] VBLU, + output VHSYNC, + output VVSYNC, - // SD/MMC Memory Card - input SD_SO, - output SD_SI, - output SD_CLK, - output SD_CS_N, + // SD/MMC Memory Card + input SD_SO, + output SD_SI, + output SD_CLK, + output SD_CS_N, - // Audio - output [15:0] SOUND_L, - output [15:0] SOUND_R, + // Audio + output [15:0] SOUND_L, + output [15:0] SOUND_R, - // Misc. I/O - input COLD_RESET, - input WARM_RESET, - output RESET_OUT, - input [64:0] RTC, - input [31:0] CMOSCfg, - input OUT0, + // Misc. I/O + input COLD_RESET, + input WARM_RESET, + input [64:0] RTC, + input [31:0] CMOSCfg, + input OUT0, + input TAPE_IN, - // PS/2 Keyboard - input [10:0] PS2_KEY, - input [24:0] PS2_MOUSE, - input [5:0] joystick, + // User input + input [10:0] PS2_KEY, + input [24:0] PS2_MOUSE, + input [7:0] JOYSTICK, - input loader_act, - input [15:0] loader_addr, - input [7:0] loader_data, - input loader_wr + input loader_act, + input [15:0] loader_addr, + input [7:0] loader_data, + input loader_wr ); - -// CPU0 -wire [15:0] cpu_a_bus; -wire [7:0] cpu_do_bus; -wire [7:0] cpu_di_bus; -wire cpu_mreq_n; -wire cpu_iorq_n; -wire cpu_wr_n; -wire cpu_rd_n; -wire cpu_int_n_TS; -wire cpu_m1_n; -wire cpu_rfsh_n; -wire [1:0] turbo; -wire [7:0] im2vect; - -// zsignal -wire cpu_stall; // zmem -> zclock -wire cpu_req; // zmem -> arbiter -wire cpu_wrbsel; // zmem -> arbiter -wire cpu_next; // arbiter -> zmem -wire cpu_current; // arbiter -> zmem -wire cpu_strobe; // arbiter -> zmem -wire cpu_latch; // arbiter -> zmem -wire [23:0] cpu_addr; -wire [20:0] cpu_addr_20; -wire csrom; -wire curr_cpu; - -// SDRAM -wire [7:0] sdr_do_bus; -wire [15:0] sdr_do_bus_16; -wire [15:0] sdr_do_bus_16cpu; -wire sdr_wr; -wire sdr_rd; -wire req; -wire rnw; -wire [23:0] dram_addr; -wire [1:0] dram_bsel; -wire [15:0] dram_wrdata; -wire dram_req; -wire dram_rnw; -wire dos; - -wire vdos; -wire pre_vdos; -wire vdos_off; -wire vdos_on; -wire dos_on; -wire m1; -wire rd; -wire wr; -wire iorq; -wire mreq; -wire rdwr; -wire iord; -wire iowr; -wire iorw; -wire memrd; -wire memwr; -wire opfetch; -wire intack; -wire iorq_s; -wire iord_s; -wire iowr_s; -wire iorw_s; -wire memwr_s; -wire opfetch_s; -wire regs_we; - -// zports OUT -wire [7:0] dout_ports; -wire ena_ports; -wire [31:0] xt_page; -wire [4:0] fmaddr; -wire [7:0] sysconf; -wire [7:0] memconf; -wire [7:0] intmask; -wire [8:0] dmaport_wr; -wire go_arbiter; -wire [3:0] cacheconf; - -// z80 -wire [15:0] zmd; -wire [7:0] zma; -wire cram_we; -wire sfile_we; -wire zborder_wr; -wire border_wr; -wire zvpage_wr; -wire vpage_wr; -wire vconf_wr; -wire gx_offsl_wr; -wire gx_offsh_wr; -wire gy_offsl_wr; -wire gy_offsh_wr; -wire t0x_offsl_wr; -wire t0x_offsh_wr; -wire t0y_offsl_wr; -wire t0y_offsh_wr; -wire t1x_offsl_wr; -wire t1x_offsh_wr; -wire t1y_offsl_wr; -wire t1y_offsh_wr; -wire tsconf_wr; -wire palsel_wr; -wire tmpage_wr; -wire t0gpage_wr; -wire t1gpage_wr; -wire sgpage_wr; -wire hint_beg_wr; -wire vint_begl_wr; -wire vint_begh_wr; - -// ZX controls -wire res; -wire int_start_frm; -wire int_start_lin; - -// DRAM interface -wire [20:0] video_addr; -wire [4:0] video_bw; -wire video_go; -wire video_next; -wire video_pre_next; -wire next_video; -wire video_strobe; - -// TS -wire [20:0] ts_addr; -wire ts_req; - -// IN -wire ts_pre_next; -wire ts_next; - -// TM -wire [20:0] tm_addr; -wire tm_req; -wire tm_next; - -// DMA -wire dma_rnw; -wire dma_req; -wire [15:0] dma_wrdata; -wire [20:0] dma_addr; -wire dma_next; -wire dma_act; -wire dma_cram_we; -wire dma_sfile_we; - -// zmap -wire [15:0] dma_data; -wire [7:0] dma_wraddr; -wire int_start_dma; -// SPI -wire spi_start; -wire dma_spi_req; -wire [7:0] dma_spi_din; -wire cpu_spi_req; -wire [7:0] cpu_spi_din; -wire [7:0] spi_dout; - -wire [7:0] mouse_do; - - -// clock -wire clk_28mhz = clk & ce; - -wire f0,f1; -wire h0,h1; -wire c0,c1,c2,c3; - -clock TS01 -( - .clk(clk_28mhz), - .f0(f0), - .f1(f1), - .h0(h0), - .h1(h1), - .c0(c0), - .c1(c1), - .c2(c2), - .c3(c3) -); - -wire zclk; -wire zpos, zneg; -zclock TS02 -( - .clk(clk_28mhz), - .c0(c0), - .c2(c2), - .f0(f0), - .f1(f1), - .zclk_out(zclk), - .zpos(zpos), - .zneg(zneg), - .iorq_s(iorq_s), - .dos_on(dos_on), - .vdos_off(vdos_off), - .cpu_stall(cpu_stall), - .ide_stall(0), - .external_port(0), - .turbo(turbo) -); - -reg zclk_r; -always @(posedge clk) zclk_r <= zclk; - -T80s CPU -( - .RESET_n(~reset), - .CLK(clk), - .CEN(~zclk_r & zclk), - .INT_n(cpu_int_n_TS), - .M1_n(cpu_m1_n), - .MREQ_n(cpu_mreq_n), - .IORQ_n(cpu_iorq_n), - .RD_n(cpu_rd_n), - .WR_n(cpu_wr_n), - .RFSH_n(cpu_rfsh_n), - .OUT0(OUT0), - .A(cpu_a_bus), - .DI(cpu_di_bus), - .DO(cpu_do_bus) -); - -zsignals TS04 -( - .clk(clk_28mhz), - .iorq_n(cpu_iorq_n), - .mreq_n(cpu_mreq_n), - .m1_n(cpu_m1_n), - .rfsh_n(cpu_rfsh_n), - .rd_n(cpu_rd_n), - .wr_n(cpu_wr_n), - .rd(rd), - .wr(wr), - .iorq(iorq), - .mreq(mreq), - .rdwr(rdwr), - .iord(iord), - .iowr(iowr), - .iorw(iorw), - .memrd(memrd), - .memwr(memwr), - .opfetch(opfetch), - .intack(intack), - .iorq_s(iorq_s), - .iord_s(iord_s), - .iowr_s(iowr_s), - .iorw_s(iorw_s), - .memwr_s(memwr_s), - .opfetch_s(opfetch_s) -); - -zports TS05 -( - .clk(clk_28mhz), - .din(cpu_do_bus), - .dout(dout_ports), - .dataout(ena_ports), - .a(cpu_a_bus), - .rst(reset), - .opfetch(opfetch), // from zsignals - .rd(rd), - .wr(wr), - .rdwr(rdwr), - .iorq(iorq), - .iorq_s(iorq_s), - .iord(iord), - .iord_s(iord_s), - .iowr(iowr), - .iowr_s(iowr_s), - .iordwr(iorw), - .iordwr_s(iorw_s), - .zborder_wr(zborder_wr), - .border_wr(border_wr), - .zvpage_wr(zvpage_wr), - .vpage_wr(vpage_wr), - .vconf_wr(vconf_wr), - .gx_offsl_wr(gx_offsl_wr), - .gx_offsh_wr(gx_offsh_wr), - .gy_offsl_wr(gy_offsl_wr), - .gy_offsh_wr(gy_offsh_wr), - .t0x_offsl_wr(t0x_offsl_wr), - .t0x_offsh_wr(t0x_offsh_wr), - .t0y_offsl_wr(t0y_offsl_wr), - .t0y_offsh_wr(t0y_offsh_wr), - .t1x_offsl_wr(t1x_offsl_wr), - .t1x_offsh_wr(t1x_offsh_wr), - .t1y_offsl_wr(t1y_offsl_wr), - .t1y_offsh_wr(t1y_offsh_wr), - .tsconf_wr(tsconf_wr), - .palsel_wr(palsel_wr), - .tmpage_wr(tmpage_wr), - .t0gpage_wr(t0gpage_wr), - .t1gpage_wr(t1gpage_wr), - .sgpage_wr(sgpage_wr), - .hint_beg_wr(hint_beg_wr), - .vint_begl_wr(vint_begl_wr), - .vint_begh_wr(vint_begh_wr), - .xt_page(xt_page), - .fmaddr(fmaddr), - .regs_we(regs_we), - .sysconf(sysconf), - .memconf(memconf), - .cacheconf(cacheconf), - .intmask(intmask), - .dmaport_wr(dmaport_wr), // dmaport_wr - .dma_act(dma_act), // from DMA (status of DMA) - .dos(dos), - .vdos(vdos), - .vdos_on(vdos_on), - .vdos_off(vdos_off), - .tape_read(1), - .keys_in(kb_do_bus), // keys (port FE) - .mus_in(mouse_do), // mouse (xxDF) - .kj_in(joystick), - .vg_intrq(0), - .vg_drq(0), // from vg93 module - drq + irq read - .sdcs_n(SD_CS_N), // to SD card - .sd_start(cpu_spi_req), // to SPI - .sd_datain(cpu_spi_din), // to SPI(7 downto 0); - .sd_dataout(spi_dout), // from SPI(7 downto 0); - .wait_addr(wait_addr), - .wait_start_gluclock(wait_start_gluclock), - .wait_read(mc146818a_do_bus) -); - -zmem TS06 -( - .clk(clk_28mhz), - .c0(c0), - .c1(c1), - .c2(c2), - .c3(c3), - .zpos(zpos), - .zneg(zneg), - .rst(reset), // PLL locked - .za(cpu_a_bus), // from CPU - .zd_out(sdr_do_bus), // output to Z80 bus 8bit ==> - .zd_ena(), // output to Z80 bus enable - .opfetch(opfetch), // from zsignals - .opfetch_s(opfetch_s), // from zsignals - .mreq(mreq), // from zsignals - .memrd(memrd), // from zsignals - .memwr(memwr), // from zsignals - .memwr_s(memwr_s), // from zsignals - .turbo(turbo), - .cache_en(cacheconf), // from zport - .memconf(memconf[3:0]), - .xt_page(xt_page), - .csrom(csrom), - .dos(dos), - .dos_on(dos_on), - .vdos(vdos), - .pre_vdos(pre_vdos), - .vdos_on(vdos_on), - .vdos_off(vdos_off), - .cpu_req(cpu_req), - .cpu_addr(cpu_addr_20), - .cpu_wrbsel(cpu_wrbsel), // for 16bit data - .cpu_rddata(sdr_do_bus_16cpu), - .cpu_next(cpu_next), - .cpu_strobe(cpu_strobe), // from ARBITER ACTIVE=HI - .cpu_latch(cpu_latch), - .cpu_stall(cpu_stall) // for Zclock if HI-> STALL (ZCLK) -); - -arbiter TS07 -( - .clk(clk_28mhz), - .c0(c0), - .c1(c1), - .c2(c2), - .c3(c3), - .cyc(ce&c3), - .dram_addr(dram_addr), - .dram_req(dram_req), - .dram_rnw(dram_rnw), - .dram_bsel(dram_bsel), - .dram_wrdata(dram_wrdata), // data to be written - .video_addr(video_addr), // during access block, only when video_strobe==1 - .go(go_arbiter), // start video access blocks - .video_bw(video_bw), // ZX="11001", [4:3] -total cycles: 11 = 8 / 01 = 4 / 00 = 2 - .video_pre_next(video_pre_next), - .video_next(video_next), // (c2) at this signal video_addr may be changed; it is one clock leading the video_strobe - .video_strobe(video_strobe), // (c3) one-cycle strobe meaning that video_data is available - .next_vid(next_video), // used for TM prefetch - .cpu_addr(cpu_addr_20), - .cpu_wrdata(cpu_do_bus), - .cpu_req(cpu_req), - .cpu_rnw(rd | csrom), - .cpu_csrom(csrom), - .cpu_wrbsel(cpu_wrbsel), - .cpu_next(cpu_next), // next cycle is allowed to be used by CPU - .cpu_strobe(cpu_strobe), // c2 strobe - .cpu_latch(cpu_latch), // c2-c3 strobe - .curr_cpu_o(curr_cpu), - .dma_addr(dma_addr), - .dma_wrdata(dma_wrdata), - .dma_req(dma_req), - .dma_rnw(dma_rnw), - .dma_next(dma_next), - .ts_addr(ts_addr), - .ts_req(ts_req), - .ts_pre_next(ts_pre_next), - .ts_next(ts_next), - .tm_addr(tm_addr), - .tm_req(tm_req), - .tm_next(tm_next), - .loader_clk(clk), - .loader_addr(loader_addr), - .loader_data(loader_data), - .loader_wr(loader_wr) -); - -video_top TS08 -( - .clk(clk_28mhz), - .f0(f0), - .f1(f1), - .h0(h0), - .h1(h1), - .c0(c0), - .c1(c1), - .c2(c2), - .c3(c3), - .vred(VGA_R), - .vgrn(VGA_G), - .vblu(VGA_B), - .hsync(VGA_HS), - .vsync(VGA_VS), - .hblank(VGA_HBLANK), - .vblank(VGA_VBLANK), - .pix_stb(VGA_CEPIX), - .d(cpu_do_bus), - .zmd(zmd), - .zma(zma), - .cram_we(cram_we), - .sfile_we(sfile_we), - .zborder_wr(zborder_wr), - .border_wr(border_wr), - .zvpage_wr(zvpage_wr), - .vpage_wr(vpage_wr), - .vconf_wr(vconf_wr), - .gx_offsl_wr(gx_offsl_wr), - .gx_offsh_wr(gx_offsh_wr), - .gy_offsl_wr(gy_offsl_wr), - .gy_offsh_wr(gy_offsh_wr), - .t0x_offsl_wr(t0x_offsl_wr), - .t0x_offsh_wr(t0x_offsh_wr), - .t0y_offsl_wr(t0y_offsl_wr), - .t0y_offsh_wr(t0y_offsh_wr), - .t1x_offsl_wr(t1x_offsl_wr), - .t1x_offsh_wr(t1x_offsh_wr), - .t1y_offsl_wr(t1y_offsl_wr), - .t1y_offsh_wr(t1y_offsh_wr), - .tsconf_wr(tsconf_wr), - .palsel_wr(palsel_wr), - .tmpage_wr(tmpage_wr), - .t0gpage_wr(t0gpage_wr), - .t1gpage_wr(t1gpage_wr), - .sgpage_wr(sgpage_wr), - .hint_beg_wr(hint_beg_wr), - .vint_begl_wr(vint_begl_wr), - .vint_begh_wr(vint_begh_wr), - .res(reset), - .int_start(int_start_frm), - .line_start_s(int_start_lin), - .video_addr(video_addr), - .video_bw(video_bw), - .video_go(go_arbiter), - .dram_rdata(sdr_do_bus_16), // raw, should be latched by c2 (video_next) - .video_next(video_next), - .video_pre_next(video_pre_next), - .next_video(next_video), - .video_strobe(video_strobe), - .ts_addr(ts_addr), - .ts_req(ts_req), - .ts_pre_next(ts_pre_next), - .ts_next(ts_next), - .tm_addr(tm_addr), - .tm_req(tm_req), - .tm_next(tm_next) -); - -dma TS09 -( - .clk(clk_28mhz), - .c2(c2), - .reset(reset), - .dmaport_wr(dmaport_wr), - .dma_act(dma_act), - .data(dma_data), - .wraddr(dma_wraddr), - .int_start(int_start_dma), - .zdata(cpu_do_bus), - .dram_addr(dma_addr), - .dram_rddata(sdr_do_bus_16), - .dram_wrdata(dma_wrdata), - .dram_req(dma_req), - .dram_rnw(dma_rnw), - .dram_next(dma_next), - .spi_rddata(spi_dout), - .spi_wrdata(dma_spi_din), - .spi_req(dma_spi_req), - .spi_stb(spi_start), - .ide_in(0), - .ide_stb(0), - .cram_we(dma_cram_we), - .sfile_we(dma_sfile_we) -); - -zmaps TS10 -( - .clk(clk_28mhz), - .memwr_s(memwr_s), - .a(cpu_a_bus), - .d(cpu_do_bus), - .fmaddr(fmaddr), - .zmd(zmd), - .zma(zma), - .dma_data(dma_data), - .dma_wraddr(dma_wraddr), - .dma_cram_we(dma_cram_we), - .dma_sfile_we(dma_sfile_we), - .cram_we(cram_we), - .sfile_we(sfile_we), - .regs_we(regs_we) -); - -spi TS11 -( - .clk(clk_28mhz), - .sck(SD_CLK), - .sdo(SD_SI), - .sdi(SD_SO), - .dma_req(dma_spi_req), - .dma_din(dma_spi_din), - .cpu_req(cpu_spi_req), - .cpu_din(cpu_spi_din), - .start(spi_start), - .dout(spi_dout) -); - -zint TS13 -( - .clk(clk_28mhz), - .zpos(zpos), - .res(reset), - .int_start_frm(int_start_frm), //< N1 VIDEO - .int_start_lin(int_start_lin), //< N2 VIDEO - .int_start_dma(int_start_dma), //< N3 DMA - .vdos(pre_vdos), // vdos,--pre_vdos - .intack(intack), //< zsignals === (intack ? im2vect : 8'hFF))); - .intmask(intmask), //< ZPORT (7 downto 0); - .im2vect(im2vect), //> CPU Din (2 downto 0); - .int_n(cpu_int_n_TS) -); - -// SDRAM Controller -sdram SE4 -( - .clk(clk), - .cyc(ce&c3), - - .curr_cpu(curr_cpu), - .bsel(dram_bsel), - .A(dram_addr), - .DI(dram_wrdata), - .DO(sdr_do_bus_16), - .DO_cpu(sdr_do_bus_16cpu), - .REQ(dram_req), - .RNW(dram_rnw), - - .SDRAM_DQ(SDRAM_DQ), - .SDRAM_A(SDRAM_A), - .SDRAM_BA(SDRAM_BA), - .SDRAM_DQML(SDRAM_DQML), - .SDRAM_DQMH(SDRAM_DQMH), - .SDRAM_nCS(SDRAM_nCS), - .SDRAM_nCAS(SDRAM_nCAS), - .SDRAM_nRAS(SDRAM_nRAS), - .SDRAM_nWE(SDRAM_nWE), - .SDRAM_CKE(SDRAM_CKE), - .SDRAM_CLK(SDRAM_CLK) -); - - -// PS/2 Keyboard -wire [4:0] kb_do_bus; -wire key_reset; -wire [7:0] key_scancode; - -keyboard SE5 -( - .clk(clk), - .reset(COLD_RESET | WARM_RESET), - .a(cpu_a_bus[15:8]), - .keyb(kb_do_bus), - .KEY_RESET(key_reset), - .scancode(key_scancode), - .ps2_key(PS2_KEY) -); - -kempston_mouse KM -( - .clk_sys(clk), - .reset(reset), - .ps2_mouse(PS2_MOUSE), - .addr(cpu_a_bus[10:8]), - .dout(mouse_do) -); - -// MC146818A,RTC -wire [7:0] wait_addr; -wire wait_start_gluclock; -wire [7:0] mc146818a_do_bus; - -reg ena_0_4375mhz; -always @(posedge clk_28mhz) begin - reg [5:0] div; - div <= div + 1'd1; - ena_0_4375mhz <= !div; //28MHz/64 -end - -mc146818a SE9 -( - .RESET(reset), - .CLK(clk_28mhz), - .ENA(ena_0_4375mhz), - .CS(1), - .KEYSCANCODE(key_scancode), - .RTC(RTC), - .CMOSCfg(CMOSCfg), - .WR(wait_start_gluclock & ~cpu_wr_n), - .A(wait_addr), - .DI(cpu_do_bus), - .DO(mc146818a_do_bus) -); - - -// Soundrive -wire [7:0] covox_a; -wire [7:0] covox_b; -wire [7:0] covox_c; -wire [7:0] covox_d; - -soundrive SE10 -( - .reset(reset), - .clk(clk_28mhz), - .cs(1), - .wr_n(cpu_wr_n), - .a(cpu_a_bus[7:0]), - .di(cpu_do_bus), - .iorq_n(cpu_iorq_n), - .dos(dos), - .outa(covox_a), - .outb(covox_b), - .outc(covox_c), - .outd(covox_d) -); - -// Turbosound FM -reg ce_ym; -always @(posedge clk_28mhz) begin - reg [2:0] div; - - div <= div + 1'd1; - ce_ym <= !div; -end - -wire ts_enable = ~cpu_iorq_n & cpu_a_bus[0] & cpu_a_bus[15] & ~cpu_a_bus[1]; -wire ts_we = ts_enable & ~cpu_wr_n; - -wire [11:0] ts_l, ts_r; -wire [7:0] ts_do; - -turbosound SE12 -( - .RESET(reset), - - .CLK(clk_28mhz), - .CE(ce_ym), - .BDIR(ts_we), - .BC(cpu_a_bus[14]), - .DI(cpu_do_bus), - .DO(ts_do), - .CHANNEL_L(ts_l), - .CHANNEL_R(ts_r) -); - - -// General Sound -wire [20:0] gs_mem_addr; -wire [7:0] gs_mem_di; -wire [7:0] gs_mem_do; -wire gs_mem_rd; -wire gs_mem_wr; -wire gs_mem_wait; - -wire [14:0] gs_l; -wire [14:0] gs_r; -wire [7:0] gs_do_bus; -wire gs_sel = ~cpu_iorq_n & cpu_m1_n & (cpu_a_bus[7:4] == 'hB && cpu_a_bus[2:0] == 'h3); - -gs U15 -( - .RESET(reset | 1'b1), - .CLK(clk), - .CE(ce), - - .A(cpu_a_bus[3]), - .DI(cpu_do_bus), - .DO(gs_do_bus), - .CS_n(cpu_iorq_n | ~gs_sel), - .WR_n(cpu_wr_n), - .RD_n(cpu_rd_n), - - .MEM_ADDR(gs_mem_addr), - .MEM_DI(gs_mem_di), - .MEM_DO(gs_mem_do), - .MEM_RD(gs_mem_rd), - .MEM_WR(gs_mem_wr), - .MEM_WAIT(gs_mem_wait), - - .OUTL(gs_l), - .OUTR(gs_r) -); - - -// SAA1099 -wire [7:0] saa_out_l; -wire [7:0] saa_out_r; -wire saa_wr_n = ~cpu_iorq_n && ~cpu_wr_n && cpu_a_bus[7:0] == 8'hFF && ~dos; - -reg ce_saa; -always @(posedge clk_28mhz) begin - reg [2:0] div; - - div <= div + 1'd1; - if(div == 6) div <= 0; - - ce_saa <= (div == 0 || div == 3); -end - -saa1099 U16 -( - .clk_sys(clk_28mhz), - .ce(ce_saa), - .rst_n(~reset), - .cs_n(0), - .a0(cpu_a_bus[8]), // 0=data, 1=address - .wr_n(saa_wr_n), - .din(cpu_do_bus), - .out_l(saa_out_l), - .out_r(saa_out_r) -); - -wire [11:0] audio_l = ts_l + {gs_l[14], gs_l[14:4]} + {2'b00, covox_a, 2'b00} + {2'b00, covox_b, 2'b00} + {1'b0, saa_out_l, 3'b000} + {3'b000, port_xxfe_reg[4], 8'b00000000}; -wire [11:0] audio_r = ts_r + {gs_r[14], gs_r[14:4]} + {2'b00, covox_c, 2'b00} + {2'b00, covox_d, 2'b00} + {1'b0, saa_out_r, 3'b000} + {3'b000, port_xxfe_reg[4], 8'b00000000}; - -compressor compressor -( - clk_28mhz, - audio_l, audio_r, - SOUND_L, SOUND_R -); - - -//----------------------------------------------------------------------------- -// Global -//----------------------------------------------------------------------------- -reg reset; -assign RESET_OUT = reset; -always @(posedge clk) - reset <= COLD_RESET | WARM_RESET | key_reset; - -// CPU interface -assign cpu_di_bus = - (~cpu_mreq_n && ~cpu_rd_n) ? sdr_do_bus : // SDRAM - (intack) ? im2vect : - (gs_sel && ~cpu_rd_n) ? gs_do_bus : // General Sound - (ts_enable && ~cpu_rd_n) ? ts_do : // TurboSound - (cpu_a_bus == 16'h0001 && ~cpu_iorq_n && ~cpu_rd_n) ? key_scancode : - (ena_ports) ? dout_ports : - 8'b11111111; -// TURBO -assign turbo = sysconf[1:0]; - -reg [7:0] port_xxfe_reg; -always @(posedge clk_28mhz) begin - if (reset) port_xxfe_reg <= 0; - else if (~cpu_iorq_n && ~cpu_wr_n && cpu_a_bus[7:0] == 8'hFE) port_xxfe_reg <= cpu_do_bus; -end + wire f0, f1, h0, h1, c0, c1, c2, c3; + wire rst_n; // global reset + wire genrst; + + wire spi_mode; + + wire [1:0] ay_mod; + wire dos; + wire vdos; + wire pre_vdos; + wire zpos, zneg; + wire [7:0] zports_dout; + wire zports_dataout; + wire porthit; + wire [1:0] dmawpdev; + wire [7:0] kbd_data; + wire [2:0] kbd_data_sel; + wire [7:0] mus_data = 8'h00; + wire kbd_stb, mus_xstb, mus_ystb, mus_btnstb, kj_stb; + wire [4:0] kbd_port_data; + +`ifdef KEMPSTON_8BIT + wire [7:0] kj_port_data; +`else + wire [4:0] kj_port_data; +`endif + + wire [7:0] mus_port_data; + wire [7:0] wait_read,wait_write; + wire wait_start_gluclock; + wire wait_start_comport; + wire wait_end; + wire [7:0] wait_addr; + wire [1:0] wait_status; + + // config signals + wire cfg_tape_sound = 1'b0; + wire cfg_floppy_swap = 1'b0; + wire int_start_wtp = 1'b0; + wire cfg_60hz = 1'b0; + wire beeper_mux; // what is mixed to FPGA beeper output - beeper(0) or tapeout(1) + wire tape_read; // tapein data + wire set_nmi; + wire cfg_vga_on = 1'b0; + + // nmi signals + wire gen_nmi; + wire clr_nmi; + wire in_nmi; + + wire tape_in; + wire [7:0] zmem_dout; + wire zmem_dataout; + wire [7:0] received; + wire [7:0] tobesent; + wire intrq = 1'b1, drq = 1'b1; + wire vg_wrFF; + wire zclk = ~clkz_out; + + // assign nmi_n = gen_nmi ? 1'b0 : 1'bZ; + wire video_go; + wire beeper_wr, covox_wr; + wire external_port; + wire ide_stall; + + wire rampage_wr; // ports #10AF-#13AF + wire [7:0] memconf; + wire [7:0] xt_ramp[0:3]; + wire [4:0] rompg; + wire [7:0] sysconf; + +`ifdef FORCE_14MHZ + wire [1:0] turbo = 2'b10; +`elsif SIMULATE + wire [1:0] turbo = 2'b10; +`else + wire [1:0] turbo = sysconf[1:0]; +`endif + wire [3:0] cacheconf; + wire [7:0] border; + wire int_start_lin; + wire int_start_frm; + wire int_start_dma; + + wire [7:0] dout_ram; + wire [7:0] dout_ports; + wire [7:0] im2vect; + wire ena_ram; + wire ena_ports; + wire drive_ff; + + wire vdos_on, vdos_off; + wire dos_on, dos_off; + + wire [21:0] daddr; + wire dreq; + wire drnw; + wire [15:0] dram_rd_r; + wire [15:0] dram_wrdata; + wire [1:0] dbsel; + + wire cpu_req, cpu_wrbsel, cpu_strobe, cpu_latch; + wire [20:0] cpu_addr; + wire [20:0] video_addr; + wire cpu_next; + wire cpu_stall; + + wire [4:0] video_bw; + wire video_strobe; + wire video_next; + wire video_pre_next; + wire next_video; + + wire [20:0] dma_addr; + wire [15:0] dma_wrdata; + wire dma_req; + wire dma_rnw; + wire dma_next; + wire dma_strobe; + + wire [20:0] ts_addr; + wire ts_req; + wire ts_pre_next; + wire ts_next; + + wire [20:0] tm_addr; + wire tm_req; + wire tm_next; + + wire dbg_arb; // DEBUG!!! + + wire border_wr; + wire zborder_wr; + wire zvpage_wr; + wire vpage_wr; + wire vconf_wr; + wire gx_offsl_wr; + wire gx_offsh_wr; + wire gy_offsl_wr; + wire gy_offsh_wr; + wire t0x_offsl_wr; + wire t0x_offsh_wr; + wire t0y_offsl_wr; + wire t0y_offsh_wr; + wire t1x_offsl_wr; + wire t1x_offsh_wr; + wire t1y_offsl_wr; + wire t1y_offsh_wr; + wire palsel_wr; + wire hint_beg_wr; + wire vint_begl_wr; + wire vint_begh_wr; + wire tsconf_wr; + wire tmpage_wr; + wire t0gpage_wr; + wire t1gpage_wr; + wire sgpage_wr; + + wire [15:0] zmd; + wire [7:0] zma; + wire cram_we; + wire sfile_we; + wire regs_we; + +`ifdef PENT_312 + wire boost_start; + wire [4:0] hcnt; + wire upper8; +`endif + + wire rst; + wire m1; + wire rfsh; + wire zrd; + wire zwr; + wire iorq; + wire iorq_s; + // wire iorq_s2; + wire mreq; + wire mreq_s; + wire rdwr; + wire iord; + wire iowr; + wire iordwr; + wire iord_s; + wire iowr_s; + wire iordwr_s; + wire memrd; + wire memwr; + wire memrw; + wire memrd_s; + wire memwr_s; + wire memrw_s; + wire opfetch; + wire opfetch_s; + wire intack; + + wire [31:0] xt_page; + +`ifdef FDR + wire [9:0] dmaport_wr; +`else + wire [8:0] dmaport_wr; +`endif + wire [4:0] fmaddr; + + wire [7:0] fddvirt; + + wire [4:0] vred_raw; + wire [4:0] vgrn_raw; + wire [4:0] vblu_raw; + wire vdac_mode; + + wire [15:0] z80_ide_out; + wire z80_ide_cs0_n; + wire z80_ide_cs1_n; + wire z80_ide_req; + wire z80_ide_rnw; + wire [15:0] dma_ide_out; + wire dma_ide_req; + wire dma_ide_rnw; + wire ide_stb; + wire ide_ready; + wire [15:0] ide_out; + + wire [7:0] intmask; + + wire dma_act; + + wire [15:0] dma_data; + wire [7:0] dma_wraddr; + wire dma_cram_we; + wire dma_sfile_we; + + wire cpu_spi_req; + wire dma_spi_req; + wire spi_stb; + wire spi_start; + wire [7:0] cpu_spi_din; + wire [7:0] dma_spi_din; + wire [7:0] spi_dout; + + wire dma_wtp_req; + wire dma_wtp_stb = 1'b0; + wire wait_status_wrn; + + wire res = ~rst_n; + + // z80 + wire [15:0] a; + wire [7:0] d; + wire [7:0] di; + wire mreq_n; + wire iorq_n; + wire wr_n; + wire rd_n; + wire int_n; + wire m1_n; + wire rfsh_n; + + wire clkz_out; + wire csrom; + wire curr_cpu; + + wire [15:0] dram_do; + wire [15:0] dram_docpu; + + wire fclk = clk & ce; + + + clock clock + ( + .clk(fclk), + .f0(f0), + .f1(f1), + .h0(h0), + .h1(h1), + .c0(c0), + .c1(c1), + .c2(c2), + .c3(c3), + // .ay_clk(ay_clk), + // .ay_mod(sysconf[4:3]) + .ay_mod(2'b00) + ); + + resetter myrst + ( + .clk(fclk), + .rst_in_n(~(COLD_RESET | WARM_RESET | key_reset)), + .rst_out_n(rst_n) + ); + + zclock zclock + ( + .clk(fclk), + .c0(c0), + .c2(c2), + .iorq_s(iorq_s), + .zclk_out(clkz_out), + .zpos(zpos), + .zneg(zneg), + .turbo(turbo), + .dos_on(dos_on), + .vdos_off(vdos_off), + .cpu_stall(cpu_stall), +`ifdef IDE_HDD + .ide_stall(ide_stall), +`else + .ide_stall(1'b0), +`endif +`ifdef PENT_312 + .boost_start(boost_start), + .hcnt(hcnt), + .upper8(upper8), +`endif + .external_port(1'b0) + ); + + + zmem zmem + ( + .clk(fclk), + .c1(c1), + .c2(c2), + .c3(c3), + .rst(rst), + .zneg(zneg), + .za(a), + .zd_out(dout_ram), + .zd_ena(ena_ram), + .opfetch(opfetch), + .opfetch_s(opfetch_s), + .memrd(memrd), + .memwr(memwr), + .memwr_s(memwr_s), + .memconf(memconf[3:0]), + .xt_page(xt_page), + .rompg(rompg), + .cache_en(cacheconf[3:0]), + .romoe_n(), + .romwe_n(), + .csrom(csrom), + .dos(dos), + .dos_on(dos_on), + .dos_off(dos_off), + .vdos(vdos), + .pre_vdos(pre_vdos), + .vdos_on(vdos_on), + .vdos_off(vdos_off), + .cpu_req(cpu_req), + .cpu_wrbsel(cpu_wrbsel), + .cpu_strobe(cpu_strobe), + .cpu_latch(cpu_latch), + .cpu_addr(cpu_addr), + .cpu_rddata(dram_docpu), // raw + .cpu_stall(cpu_stall), + .cpu_next(cpu_next), + .turbo(turbo) + ); + + sdram sdram + ( + .clk(clk), + .cyc(ce&c3), + .curr_cpu(curr_cpu), + .bsel(dbsel), + .A(daddr), + .DI(dram_wrdata), + .DO(dram_do), + .DO_cpu(dram_docpu), + .REQ(dreq), + .RNW(drnw), + .SDRAM_DQ(SDRAM_DQ), + .SDRAM_A(SDRAM_A), + .SDRAM_BA(SDRAM_BA), + .SDRAM_DQML(SDRAM_DQML), + .SDRAM_DQMH(SDRAM_DQMH), + .SDRAM_nCS(SDRAM_nCS), + .SDRAM_nCAS(SDRAM_nCAS), + .SDRAM_nRAS(SDRAM_nRAS), + .SDRAM_nWE(SDRAM_nWE), + .SDRAM_CKE(SDRAM_CKE), + .SDRAM_CLK(SDRAM_CLK) + ); + + arbiter arbiter + ( + .clk(fclk), + .c1(c1), + .c2(c2), + .c3(c3), + .cyc(ce&c3), + .dram_addr(daddr), + .dram_req(dreq), + .dram_rnw(drnw), + .dram_bsel(dbsel), + .dram_wrdata(dram_wrdata), + .cpu_addr(cpu_addr), + .cpu_wrdata(d), + .cpu_req(cpu_req), + .cpu_rnw(zrd | csrom), + .cpu_wrbsel(cpu_wrbsel), + .cpu_csrom(csrom), + .cpu_next(cpu_next), + .cpu_strobe(cpu_strobe), + .cpu_latch(cpu_latch), + .curr_cpu_o(curr_cpu), + .video_go(video_go), + .video_bw(video_bw), + .video_addr(video_addr), + .video_strobe(video_strobe), + .video_pre_next(video_pre_next), + .video_next(video_next), + .next_vid(next_video), + .dma_addr(dma_addr), + .dma_wrdata(dma_wrdata), + .dma_req(dma_req), + .dma_rnw(dma_rnw), + .dma_next(dma_next), + .ts_req(ts_req), + .ts_addr(ts_addr), + .ts_pre_next(ts_pre_next), + .ts_next(ts_next), + .tm_addr(tm_addr), + .tm_req(tm_req), + .tm_next(tm_next), + .loader_clk(clk), + .loader_addr(loader_addr), + .loader_data(loader_data), + .loader_wr(loader_wr) + ); + + video_top video_top + ( + .clk(fclk), + .res(res), + .f0(f0), + .f1(f1), + .h1(h1), + .c0(c0), + .c1(c1), + .c3(c3), + .vred(), + .vgrn(), + .vblu(), + .vred_raw(vred_raw), + .vgrn_raw(vgrn_raw), + .vblu_raw(vblu_raw), + .vdac_mode(vdac_mode), +`ifdef IDE_VDAC2 + .vdac2_msel(vdac2_msel), +`endif + .hsync(VHSYNC), + .vsync(VVSYNC), + .csync(), + .cfg_60hz(cfg_60hz), + .vga_on(cfg_vga_on), + .border_wr(border_wr), + .zborder_wr(zborder_wr), + .zvpage_wr(zvpage_wr), + .vpage_wr(vpage_wr), + .vconf_wr(vconf_wr), + .gx_offsl_wr(gx_offsl_wr), + .gx_offsh_wr(gx_offsh_wr), + .gy_offsl_wr(gy_offsl_wr), + .gy_offsh_wr(gy_offsh_wr), + .t0x_offsl_wr(t0x_offsl_wr), + .t0x_offsh_wr(t0x_offsh_wr), + .t0y_offsl_wr(t0y_offsl_wr), + .t0y_offsh_wr(t0y_offsh_wr), + .t1x_offsl_wr(t1x_offsl_wr), + .t1x_offsh_wr(t1x_offsh_wr), + .t1y_offsl_wr(t1y_offsl_wr), + .t1y_offsh_wr(t1y_offsh_wr), + .palsel_wr(palsel_wr), + .hint_beg_wr(hint_beg_wr), + .vint_begl_wr(vint_begl_wr), + .vint_begh_wr(vint_begh_wr), + .tsconf_wr(tsconf_wr), + .tmpage_wr(tmpage_wr), + .t0gpage_wr(t0gpage_wr), + .t1gpage_wr(t1gpage_wr), + .sgpage_wr(sgpage_wr), + .video_addr(video_addr), + .video_bw(video_bw), + .video_go(video_go), + .dram_rdata(dram_do), // raw, should be latched by c2 + .video_strobe(video_strobe), + .video_pre_next(video_pre_next), + .ts_req(ts_req), + .ts_pre_next(ts_pre_next), + .ts_addr(ts_addr), + .ts_next(ts_next), + .tm_addr(tm_addr), + .tm_req(tm_req), + .tm_next(tm_next), +`ifdef PENT_312 + .hcnt(hcnt), + .upper8(upper8), +`endif + .d(d), + .zmd(zmd), + .zma(zma), + .cram_we(cram_we), + .sfile_we(sfile_we), + .int_start(int_start_frm), + .line_start_s(int_start_lin) + ); + + vdac vdac + ( + .mode(vdac_mode), + .o_r(vred_raw), + .o_g(vgrn_raw), + .o_b(vblu_raw), + .v_r(VRED), + .v_g(VGRN), + .v_b(VBLU) + ); + + zmaps zmaps + ( + .clk(fclk), + .memwr_s(memwr_s), + .a(a), + .d(d), + .fmaddr(fmaddr), + .zmd(zmd), + .zma(zma), + .dma_wraddr(dma_wraddr), + .dma_data(dma_data), + .dma_cram_we(dma_cram_we), + .dma_sfile_we(dma_sfile_we), + .cram_we(cram_we), + .sfile_we(sfile_we), + .regs_we(regs_we) + ); + + zsignals zsignals + ( + .clk(fclk), + .zpos(zpos), + .rst_n(rst_n), + .iorq_n(iorq_n), + .mreq_n(mreq_n), + .m1_n(m1_n), + .rfsh_n(rfsh_n), + .rd_n(rd_n), + .wr_n(wr_n), + .rst(rst), + .m1(m1), + .rfsh(rfsh), + .rd(zrd), + .wr(zwr), + .iorq(iorq), + .iorq_s(iorq_s), + // .iorq_s2 (iorq_s2), + .mreq(mreq), + .mreq_s(mreq_s), + .rdwr(rdwr), + .iord(iord), + .iowr(iowr), + .iordwr(iordwr), + .iord_s(iord_s), + .iowr_s(iowr_s), + .iordwr_s(iordwr_s), + .memrd(memrd), + .memwr(memwr), + .memrw(memrw), + .memrd_s(memrd_s), + .memwr_s(memwr_s), + .memrw_s(memrw_s), + .opfetch(opfetch), + .opfetch_s(opfetch_s), + .intack(intack) + ); + + zports zports + ( + .zclk(fclk), + .clk(fclk), + .din(d), + .dout(dout_ports), + .dataout(ena_ports), + .a(a), + .rst(rst), + .opfetch(opfetch), + .rd(zrd), + .wr(zwr), + .rdwr(rdwr), + .iorq(iorq), + .iord(iord), + .iowr(iowr), + .iordwr(iordwr), + .iorq_s(iorq_s), + .iord_s(iord_s), + .iowr_s(iowr_s), + .iordwr_s(iordwr_s), + .ay_bdir(), + .ay_bc1(), + .vg_intrq(intrq), + .vg_drq(drq), + .vg_cs_n(), + .vg_wrFF(vg_wrFF), + .sd_start(cpu_spi_req), + .sd_dataout(spi_dout), + .sd_datain(cpu_spi_din), + .sdcs_n(SD_CS_N), +`ifdef SD_CARD2 + .sd2cs_n(SD_CS2_N), +`endif + .spi_mode(spi_mode), +`ifdef IDE_VDAC2 + .ftcs_n(ftcs_n), +`ifdef ESP32_SPI + .espcs_n(espcs_n), +`endif +`endif +`ifdef IDE_HDD + .ide_in(ide_d), + .ide_out(z80_ide_out), + .ide_cs0_n(z80_ide_cs0_n), + .ide_cs1_n(z80_ide_cs1_n), + .ide_req(z80_ide_req), + .ide_stb(ide_stb), + .ide_ready(ide_ready), + .ide_stall(ide_stall), +`endif + .border_wr(border_wr), + .zborder_wr(zborder_wr), + .zvpage_wr(zvpage_wr), + .vpage_wr(vpage_wr), + .vconf_wr(vconf_wr), + .gx_offsl_wr(gx_offsl_wr), + .gx_offsh_wr(gx_offsh_wr), + .gy_offsl_wr(gy_offsl_wr), + .gy_offsh_wr(gy_offsh_wr), + .t0x_offsl_wr(t0x_offsl_wr), + .t0x_offsh_wr(t0x_offsh_wr), + .t0y_offsl_wr(t0y_offsl_wr), + .t0y_offsh_wr(t0y_offsh_wr), + .t1x_offsl_wr(t1x_offsl_wr), + .t1x_offsh_wr(t1x_offsh_wr), + .t1y_offsl_wr(t1y_offsl_wr), + .t1y_offsh_wr(t1y_offsh_wr), + .palsel_wr(palsel_wr), + .hint_beg_wr(hint_beg_wr), + .vint_begl_wr(vint_begl_wr), + .vint_begh_wr(vint_begh_wr), + .tsconf_wr(tsconf_wr), + .tmpage_wr(tmpage_wr), + .t0gpage_wr(t0gpage_wr), + .t1gpage_wr(t1gpage_wr), + .sgpage_wr(sgpage_wr), + .xt_page(xt_page), + .fmaddr(fmaddr), + .regs_we(regs_we), + .sysconf(sysconf), + .cacheconf(cacheconf), + .memconf(memconf), + .intmask(intmask), + .fddvirt(fddvirt), +`ifdef FDR + .fdr_cnt(fdr_cnt), + .fdr_en(fdr_en), + .fdr_cnt_lat(fdr_cnt_lat), +`endif + .cfg_floppy_swap(cfg_floppy_swap), + .drive_sel(), + .dos(dos), + .vdos(vdos), + .vdos_on(vdos_on), + .vdos_off(vdos_off), + .dmaport_wr(dmaport_wr), + .dma_act(dma_act), + .dmawpdev(dmawpdev), + .keys_in(kbd_port_data), + .mus_in(mus_port_data), + .kj_in(JOYSTICK), + .tape_read(TAPE_IN), + .beeper_wr(beeper_wr), + .covox_wr(covox_wr), + .wait_addr(wait_addr), + .wait_start_gluclock(wait_start_gluclock), + .wait_start_comport(wait_start_comport), + .wait_read(wait_read), + .wait_write(wait_write), + .porthit(porthit), + .external_port(external_port) + ); + + dma dma + ( + .clk(fclk), + .c2(c2), + .rst_n(rst_n), + .int_start(int_start_dma), + .zdata(d), + .dmaport_wr(dmaport_wr), + .dma_act(dma_act), + .dram_addr(dma_addr), + .dram_rnw(dma_rnw), + .dram_req(dma_req), + .dram_rddata(dram_do), + .dram_wrdata(dma_wrdata), + .dram_next(dma_next), + .data(dma_data), + .wraddr(dma_wraddr), + .cram_we(dma_cram_we), + .sfile_we(dma_sfile_we), +`ifdef IDE_HDD + .ide_in(ide_d), + .ide_out(dma_ide_out), + .ide_req(dma_ide_req), + .ide_rnw(dma_ide_rnw), + .ide_stb(ide_stb), +`endif + .spi_req(dma_spi_req), + .spi_stb(spi_start), + .spi_rddata(spi_dout), + .spi_wrdata(dma_spi_din), + .wtp_req(dma_wtp_req), + .wtp_stb(dma_wtp_stb), + .wtp_rddata(mus_data) // data must be available 1 clk earlier than wait_data (mus_data = shift_in in slavespi.v) + // .wtp_wrdata(dma_wtp_din) +`ifdef FDR + , + .fdr_in(fdr_rle), + .fdr_req(fdr_req), + .fdr_stb(fdr_stb), + .fdr_stop(fdr_stop) +`endif + ); + + zint zint + ( + .clk(fclk), + .zpos(zpos), + .res(res), + .wait_n(1'b1), + .im2vect(im2vect), + .intmask(intmask), +`ifdef IDE_VDAC2 + .int_start_lin(vdac2_msel ? int_start_ft : int_start_lin), +`else + .int_start_lin(int_start_lin), +`endif +`ifdef PENT_312 + .boost_start(boost_start), +`endif + .int_start_frm(int_start_frm), + .int_start_dma(int_start_dma), + .int_start_wtp(int_start_wtp), + .vdos(pre_vdos), + .intack(intack), + .int_n(int_n) + ); + + spi spi + ( + .clk(fclk), + .sck(SD_CLK), + .sdo(SD_SI), +`ifdef IDE_VDAC2 +`ifdef ESP32_SPI + .sdi((!ftcs_n || !espcs_n) ? ftdi : sddi), +`else + .sdi(!ftcs_n ? ftdi : sddi), +`endif +`else + .sdi(SD_SO), +`endif + .mode(spi_mode), + .dma_req(dma_spi_req), + .dma_din(dma_spi_din), + .cpu_req(cpu_spi_req), + .cpu_din(cpu_spi_din), + .start(spi_start), + .dout(spi_dout) + ); + +`ifdef IDE_HDD + ide ide + ( + .clk(fclk), + .reset(res), + .rdy_stb(ide_stb), + .rdy(ide_ready), + .ide_out(ide_out), + .ide_a(ide_a), + .ide_dir(ide_dir), + .ide_cs0_n(ide_cs0_n), + .ide_cs1_n(ide_cs1_n), + .ide_rd_n(ide_rd_n), + .ide_wr_n(ide_wr_n), + .dma_out(dma_ide_out), + .dma_req(dma_ide_req), + .dma_rnw(dma_ide_rnw), + .z80_out(z80_ide_out), + .z80_a(a[7:5]), + .z80_cs0_n(z80_ide_cs0_n), + .z80_cs1_n(z80_ide_cs1_n), + .z80_req(z80_ide_req), + .z80_rnw(!rd_n) // this should be the direct Z80 signal + ); +`endif + + + // Z80 CPU + T80pa CPU + ( + .RESET_n(rst_n), + .CLK(fclk), + .CEN_p(zpos), + .CEN_n(zneg), + .INT_n(int_n), + .M1_n(m1_n), + .MREQ_n(mreq_n), + .IORQ_n(iorq_n), + .RD_n(rd_n), + .WR_n(wr_n), + .RFSH_n(rfsh_n), + .OUT0(OUT0), + .A(a), + .DI(di), + .DO(d) + ); + + + // PS/2 Keyboard + wire key_reset; + wire [7:0] key_scancode; + + keyboard keyboard + ( + .clk(clk), + .reset(COLD_RESET | WARM_RESET), + .a(a[15:8]), + .keyb(kbd_port_data), + .KEY_RESET(key_reset), + .scancode(key_scancode), + .ps2_key(PS2_KEY) + ); + + + // PS/2 Mouse + kempston_mouse kempston_mouse + ( + .clk_sys(clk), + .reset(rst), + .ps2_mouse(PS2_MOUSE), + .addr(a[10:8]), + .dout(mus_port_data) + ); + + + // MC146818A RTC + reg ena_0_4375mhz; + always @(posedge fclk) begin + reg [5:0] div; + div <= div + 1'd1; + ena_0_4375mhz <= !div; //28MHz/64 + end + + mc146818a mc146818a + ( + .RESET(rst), + .CLK(fclk), + .ENA(ena_0_4375mhz), + .CS(1), + .KEYSCANCODE(key_scancode), + .RTC(RTC), + .CMOSCfg(CMOSCfg), + .WR(wait_start_gluclock & ~wr_n), + .A(wait_addr), + .DI(d), + .DO(wait_read) + ); + + + // Soundrive + wire [7:0] covox_a; + wire [7:0] covox_b; + wire [7:0] covox_c; + wire [7:0] covox_d; + + soundrive soundrive + ( + .reset(rst), + .clk(fclk), + .cs(1), + .wr_n(wr_n), + .a(a[7:0]), + .di(d), + .iorq_n(iorq_n), + .dos(dos), + .outa(covox_a), + .outb(covox_b), + .outc(covox_c), + .outd(covox_d) + ); + + + // Turbosound FM + reg ce_ym; + always @(posedge fclk) begin + reg [2:0] div; + + div <= div + 1'd1; + ce_ym <= !div; + end + + wire ts_enable = ~iorq_n & a[0] & a[15] & ~a[1]; + wire ts_we = ts_enable & ~wr_n; + + wire [11:0] ts_l, ts_r; + wire [7:0] ts_do; + + turbosound turbosound + ( + .RESET(rst), + .CLK(fclk), + .CE(ce_ym), + .BDIR(ts_we), + .BC(a[14]), + .DI(d), + .DO(ts_do), + .CHANNEL_L(ts_l), + .CHANNEL_R(ts_r) + ); + + + // General Sound + wire [20:0] gs_mem_addr; + wire [7:0] gs_mem_di; + wire [7:0] gs_mem_do; + wire gs_mem_rd; + wire gs_mem_wr; + wire gs_mem_wait; + + wire [14:0] gs_l; + wire [14:0] gs_r; + wire [7:0] gs_do_bus; + wire gs_sel = ~iorq_n & m1_n & (a[7:4] == 'hB && a[2:0] == 'h3); + + gs gs + ( + .RESET(rst | 1'b1), + .CLK(clk), + .CE(ce), + + .A(a[3]), + .DI(d), + .DO(gs_do_bus), + .CS_n(iorq_n | ~gs_sel), + .WR_n(wr_n), + .RD_n(rd_n), + + .MEM_ADDR(gs_mem_addr), + .MEM_DI(gs_mem_di), + .MEM_DO(gs_mem_do), + .MEM_RD(gs_mem_rd), + .MEM_WR(gs_mem_wr), + .MEM_WAIT(gs_mem_wait), + + .OUTL(gs_l), + .OUTR(gs_r) + ); + + + // SAA1099 + wire [7:0] saa_out_l; + wire [7:0] saa_out_r; + wire saa_wr_n = ~iorq_n && ~wr_n && a[7:0] == 8'hFF && ~dos; + + reg ce_saa; + always @(posedge fclk) begin + reg [2:0] div; + + div <= div + 1'd1; + if(div == 6) div <= 0; + + ce_saa <= (div == 0 || div == 3); + end + + saa1099 saa1099 + ( + .clk_sys(fclk), + .ce(ce_saa), + .rst_n(rst_n), + .cs_n(0), + .a0(a[8]), // 0=data, 1=address + .wr_n(saa_wr_n), + .din(d), + .out_l(saa_out_l), + .out_r(saa_out_r) + ); + + + // Beeper and Tape out + reg [7:0] port_xxfe_reg; + always @(posedge fclk) if (beeper_wr) port_xxfe_reg <= d; + + + // Audio output + wire [11:0] audio_l = ts_l + {gs_l[14], gs_l[14:4]} + {2'b00, covox_a, 2'b00} + {2'b00, covox_b, 2'b00} + {1'b0, saa_out_l, 3'b000} + {3'b000, port_xxfe_reg[4], 8'b00000000}; + wire [11:0] audio_r = ts_r + {gs_r[14], gs_r[14:4]} + {2'b00, covox_c, 2'b00} + {2'b00, covox_d, 2'b00} + {1'b0, saa_out_r, 3'b000} + {3'b000, port_xxfe_reg[4], 8'b00000000}; + + compressor compressor + ( + fclk, + audio_l, audio_r, + SOUND_L, SOUND_R + ); + + + // CPU interface + assign di = + (~mreq_n && ~rd_n) ? dout_ram : // SDRAM + (gs_sel && ~rd_n) ? gs_do_bus : // General Sound + (ts_enable && ~rd_n) ? ts_do : // TurboSound + (ena_ports) ? dout_ports : + (intack) ? im2vect : + 8'b11111111; endmodule diff --git a/rtl/tune.v b/rtl/tune.v new file mode 100644 index 0000000..8c86cd5 --- /dev/null +++ b/rtl/tune.v @@ -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 diff --git a/rtl/video/video_fetch.v b/rtl/video/video_fetch.v index 7eba80b..e61b87c 100644 --- a/rtl/video/video_fetch.v +++ b/rtl/video/video_fetch.v @@ -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 diff --git a/rtl/video/video_mode.v b/rtl/video/video_mode.v index 9c68b58..d220377 100644 --- a/rtl/video/video_mode.v +++ b/rtl/video/video_mode.v @@ -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 diff --git a/rtl/video/video_out.v b/rtl/video/video_out.v index 679c1ec..2df866a 100644 --- a/rtl/video/video_out.v +++ b/rtl/video/video_out.v @@ -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 diff --git a/rtl/video/video_ports.v b/rtl/video/video_ports.v index 5f99d5d..08c20bb 100644 --- a/rtl/video/video_ports.v +++ b/rtl/video/video_ports.v @@ -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 diff --git a/rtl/video/video_render.v b/rtl/video/video_render.v index 2c240fb..7040713 100644 --- a/rtl/video/video_render.v +++ b/rtl/video/video_render.v @@ -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 diff --git a/rtl/video/video_sync.v b/rtl/video/video_sync.v index 781d20f..6f2b4b2 100644 --- a/rtl/video/video_sync.v +++ b/rtl/video/video_sync.v @@ -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 diff --git a/rtl/video/video_top.v b/rtl/video/video_top.v index 7305dff..47e43df 100644 --- a/rtl/video/video_top.v +++ b/rtl/video/video_top.v @@ -1,467 +1,642 @@ +`include "tune.v" // This module is a video top-level - module video_top ( - // clocks - input wire clk, - input wire f0, f1, - input wire h0, h1, - input wire c0, c1, c2, c3, - // input wire t0, // debug!!! + // clocks + input wire clk, + input wire f0, f1, + input wire h1, + input wire c0, c1, c3, + // input wire t0, // debug!!! - // video DAC - output wire [7:0] vred, - output wire [7:0] vgrn, - output wire [7:0] vblu, - output wire vdac_mode, + // video DAC + output wire [1:0] vred, + output wire [1:0] vgrn, + output wire [1:0] vblu, - // video syncs - output wire hsync, - output wire vsync, - output wire hblank, - output wire vblank, - output wire pix_stb, + // video raw (for 15 bit DAC) + output wire [4:0] vred_raw, + output wire [4:0] vgrn_raw, + output wire [4:0] vblu_raw, + output wire vdac_mode, +`ifdef IDE_VDAC2 + output wire vdac2_msel, +`endif - // Z80 controls - input wire [ 7:0] d, - input wire [15:0] zmd, - input wire [ 7:0] zma, - input wire cram_we, - input wire sfile_we, + // video syncs + output wire hsync, + output wire vsync, + output wire csync, - // 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, + // Z80 controls + input wire [ 7:0] d, + input wire [15:0] zmd, + input wire [ 7:0] zma, + input wire cram_we, + input wire sfile_we, - // ZX controls - input wire res, - output wire int_start, - output 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, - // DRAM interface - output wire [20:0] video_addr, - output wire [ 4:0] video_bw, - output wire video_go, - input wire [15:0] dram_rdata, // raw, should be latched by c2 (video_next) - input wire video_next, - input wire video_pre_next, - input wire next_video, - input wire video_strobe, - output wire [20:0] ts_addr, - output wire ts_req, - input wire ts_pre_next, - input wire ts_next, - output wire [20:0] tm_addr, - output wire tm_req, - input wire tm_next + // ZX controls + input wire res, + output wire int_start, + output wire line_start_s, +`ifdef PENT_312 + output wire [4:0] hcnt, + output wire upper8, +`endif + + // DRAM interface + output wire [20:0] video_addr, + output wire [ 4:0] video_bw, + output wire video_go, + input wire [15:0] dram_rdata, // raw, should be latched by c2 + input wire video_pre_next, + input wire video_strobe, + output wire [20:0] ts_addr, + output wire ts_req, + input wire ts_pre_next, + input wire ts_next, + output wire [20:0] tm_addr, + output wire tm_req, + input wire tm_next, + + // video controls + input wire cfg_60hz, + input wire vga_on ); + // video config + wire [7:0] vpage; // re-latched at line_start + wire [7:0] vconf; // + wire [8:0] gx_offs; // + wire [8:0] gy_offs; // + wire [7:0] palsel; // + wire [8:0] t0x_offs; // + wire [8:0] t1x_offs; // + wire [7:0] t0gpage; // + wire [7:0] t1gpage; // + wire [7:0] sgpage; // * not yet !!! + wire [8:0] t0y_offs; + wire [8:0] t1y_offs; + wire [7:0] tsconf; + wire [7:0] tmpage; + wire [7:0] hint_beg; + wire [8:0] vint_beg; + wire [8:0] hpix_beg; + wire [8:0] hpix_end; + wire [8:0] vpix_beg; + wire [8:0] vpix_end; + wire [8:0] hpix_beg_ts; + wire [8:0] hpix_end_ts; + wire [8:0] vpix_beg_ts; + wire [8:0] vpix_end_ts; + wire [5:0] x_tiles; + wire [9:0] x_offs_mode; + wire [4:0] go_offs; + wire [1:0] render_mode; + wire tv_hires; + wire vga_hires; + wire v60hz; + wire nogfx = vconf[5]; + wire notsu = vconf[4]; +`ifdef IDE_VDAC2 + assign vdac2_msel = vconf[2]; +`endif + wire tv_blank; -// video config -wire [7:0] vpage; // re-latched at line_start -wire [7:0] vconf; // -wire [8:0] gx_offs; // -wire [8:0] gy_offs; // -wire [7:0] palsel; // -wire [8:0] t0x_offs; // -wire [8:0] t1x_offs; // -wire [7:0] t0gpage; // -wire [7:0] t1gpage; // -wire [7:0] sgpage; // * not yet !!! -wire [8:0] t0y_offs; -wire [8:0] t1y_offs; -wire [7:0] tsconf; -wire [7:0] tmpage; -wire [7:0] hint_beg; -wire [8:0] vint_beg; -wire [8:0] hpix_beg; -wire [8:0] hpix_end; -wire [8:0] vpix_beg; -wire [8:0] vpix_end; -wire [8:0] hpix_beg_ts; -wire [8:0] hpix_end_ts; -wire [8:0] vpix_beg_ts; -wire [8:0] vpix_end_ts; -wire [5:0] x_tiles; -wire [9:0] x_offs_mode; -wire [4:0] go_offs; -wire [1:0] render_mode; -wire tv_hires; -wire nogfx = vconf[5]; -wire notsu = vconf[4]; -wire gfxovr = vconf[3]; -wire tv_hblank; -wire tv_vblank; + // counters + wire [7:0] cnt_col; + wire [8:0] cnt_row; + wire cptr; + wire [3:0] scnt; + wire [8:0] lcount; -// counters -wire [7:0] cnt_col; -wire [8:0] cnt_row; -wire cptr; -wire [3:0] scnt; -wire [8:0] lcount; + // synchro + wire frame_start; + wire pix_start; + wire tv_pix_start; + wire vga_pix_start; + wire ts_start; + wire vga_blank; + wire vga_line; + wire v_ts; + wire v_pf; + wire hpix; + wire vpix; + wire hvpix; + wire hvtspix; + wire frame; + wire flash; + wire pix_stb; -// synchro -wire frame_start; -wire pix_start; -wire tv_pix_start; -wire ts_start; -wire v_ts; -wire v_pf; -wire hpix; -wire vpix; -wire hvpix; -wire hvtspix; -wire flash; + // fetcher + wire [31:0] fetch_data; + wire [31:0] fetch_temp; + wire [3:0] fetch_sel; + wire [1:0] fetch_bsl; + wire fetch_stb; -// fetcher -wire [31:0] fetch_data; -wire [31:0] fetch_temp; -wire [3:0] fetch_sel; -wire [1:0] fetch_bsl; -wire fetch_stb; + // video data + wire [7:0] border; + wire [7:0] vplex; + wire [7:0] vgaplex; -// video data -wire [7:0] border; -wire [7:0] vplex; + // TS + wire tsr_go; + wire [5:0] tsr_addr; + wire [8:0] tsr_line; + wire [7:0] tsr_page; + wire [8:0] tsr_x; + wire [2:0] tsr_xs; + wire tsr_xf; + wire [3:0] tsr_pal; + wire tsr_rdy; -// TS -wire tsr_go; -wire [5:0] tsr_addr; -wire [8:0] tsr_line; -wire [7:0] tsr_page; -wire [8:0] tsr_x; -wire [2:0] tsr_xs; -wire tsr_xf; -wire [3:0] tsr_pal; -wire tsr_rdy; + // TS-line + wire [8:0] ts_waddr; + wire [7:0] ts_wdata; + wire ts_we; + wire [8:0] ts_raddr; -// TS-line -wire [8:0] ts_waddr; -wire [7:0] ts_wdata; -wire ts_we; -wire [8:0] ts_raddr; + // VGA-line + wire [9:0] vga_cnt_in; + wire [9:0] vga_cnt_out; -video_ports video_ports -( - .clk (clk), - .d (d), - .res (res), - .line_start_s (line_start_s), - .border_wr (border_wr), - .zborder_wr (zborder_wr), - .zvpage_wr (zvpage_wr), - .vpage_wr (vpage_wr), - .vconf_wr (vconf_wr), - .gx_offsl_wr (gx_offsl_wr), - .gx_offsh_wr (gx_offsh_wr), - .gy_offsl_wr (gy_offsl_wr), - .gy_offsh_wr (gy_offsh_wr), - .t0x_offsl_wr (t0x_offsl_wr), - .t0x_offsh_wr (t0x_offsh_wr), - .t0y_offsl_wr (t0y_offsl_wr), - .t0y_offsh_wr (t0y_offsh_wr), - .t1x_offsl_wr (t1x_offsl_wr), - .t1x_offsh_wr (t1x_offsh_wr), - .t1y_offsl_wr (t1y_offsl_wr), - .t1y_offsh_wr (t1y_offsh_wr), - .palsel_wr (palsel_wr), - .hint_beg_wr (hint_beg_wr), - .vint_begl_wr (vint_begl_wr), - .vint_begh_wr (vint_begh_wr), - .tsconf_wr (tsconf_wr), - .tmpage_wr (tmpage_wr), - .t0gpage_wr (t0gpage_wr), - .t1gpage_wr (t1gpage_wr), - .sgpage_wr (sgpage_wr), - .border (border), - .vpage (vpage), - .vconf (vconf), - .gx_offs (gx_offs), - .gy_offs (gy_offs), - .t0x_offs (t0x_offs), - .t1x_offs (t1x_offs), - .t0y_offs (t0y_offs), - .t1y_offs (t1y_offs), - .palsel (palsel), - .hint_beg (hint_beg), - .vint_beg (vint_beg), - .int_start (0), - .tsconf (tsconf), - .tmpage (tmpage), - .t0gpage (t0gpage), - .t1gpage (t1gpage), - .sgpage (sgpage) -); + wire [7:0] ts_rdata0, ts_rdata1; + wire tl_act0 = lcount[0]; + wire tl_act1 = ~lcount[0]; + wire [8:0] ts_waddr0 = tl_act0 ? ts_raddr : ts_waddr; + wire [7:0] ts_wdata0 = tl_act0 ? 8'd0 : ts_wdata; + wire ts_we0 = tl_act0 ? c3 : ts_we; + wire [8:0] ts_waddr1 = tl_act1 ? ts_raddr : ts_waddr; + wire [7:0] ts_wdata1 = tl_act1 ? 8'd0 : ts_wdata; + wire ts_we1 = tl_act1 ? c3 : ts_we; + wire [7:0] ts_rdata = tl_act0 ? ts_rdata0 : ts_rdata1; + video_ports video_ports + ( + .clk (clk), + .d (d), + .res (res), + .line_start_s (line_start_s), + .border_wr (border_wr), + .zborder_wr (zborder_wr), + .zvpage_wr (zvpage_wr), + .vpage_wr (vpage_wr), + .vconf_wr (vconf_wr), + .gx_offsl_wr (gx_offsl_wr), + .gx_offsh_wr (gx_offsh_wr), + .gy_offsl_wr (gy_offsl_wr), + .gy_offsh_wr (gy_offsh_wr), + .t0x_offsl_wr (t0x_offsl_wr), + .t0x_offsh_wr (t0x_offsh_wr), + .t0y_offsl_wr (t0y_offsl_wr), + .t0y_offsh_wr (t0y_offsh_wr), + .t1x_offsl_wr (t1x_offsl_wr), + .t1x_offsh_wr (t1x_offsh_wr), + .t1y_offsl_wr (t1y_offsl_wr), + .t1y_offsh_wr (t1y_offsh_wr), + .palsel_wr (palsel_wr), + .hint_beg_wr (hint_beg_wr), + .vint_begl_wr (vint_begl_wr), + .vint_begh_wr (vint_begh_wr), + .tsconf_wr (tsconf_wr), + .tmpage_wr (tmpage_wr), + .t0gpage_wr (t0gpage_wr), + .t1gpage_wr (t1gpage_wr), + .sgpage_wr (sgpage_wr), + .border (border), + .vpage (vpage), + .vconf (vconf), + .gx_offs (gx_offs), + .gy_offs (gy_offs), + .t0x_offs (t0x_offs), + .t1x_offs (t1x_offs), + .t0y_offs (t0y_offs), + .t1y_offs (t1y_offs), + .palsel (palsel), + .hint_beg (hint_beg), + .vint_beg (vint_beg), +`ifdef AUTO_INT + .int_start (int_start), +`else + .int_start (1'b0), +`endif + .tsconf (tsconf), + .tmpage (tmpage), + .t0gpage (t0gpage), + .t1gpage (t1gpage), + .sgpage (sgpage) + ); -video_mode video_mode -( - .clk (clk), - .f1 (f1), - .c3 (c3), - .vpage (vpage), - .vconf (vconf), - .fetch_sel (fetch_sel), - .fetch_bsl (fetch_bsl), - .fetch_cnt (scnt), - .fetch_stb (fetch_stb), - .txt_char (fetch_temp[15:0]), - .gx_offs (gx_offs), - .x_offs_mode (x_offs_mode), - .ts_rres_ext (tsconf[0]), - .hpix_beg (hpix_beg), - .hpix_end (hpix_end), - .vpix_beg (vpix_beg), - .vpix_end (vpix_end), - .hpix_beg_ts (hpix_beg_ts), - .hpix_end_ts (hpix_end_ts), - .vpix_beg_ts (vpix_beg_ts), - .vpix_end_ts (vpix_end_ts), - .x_tiles (x_tiles), - .go_offs (go_offs), - .cnt_col (cnt_col), - .cnt_row (cnt_row), - .cptr (cptr), - .line_start_s (line_start_s), - .pix_start (pix_start), - .tv_hires (tv_hires), - .pix_stb (pix_stb), - .render_mode (render_mode), - .video_addr (video_addr), - .video_bw (video_bw) -); + video_mode video_mode + ( + .clk (clk), + .f1 (f1), + .c3 (c3), + .vpage (vpage), + .vconf (vconf), + .v60hz (v60hz), + .fetch_sel (fetch_sel), + .fetch_bsl (fetch_bsl), + .fetch_cnt (scnt), + .fetch_stb (fetch_stb), + .txt_char (fetch_temp[15:0]), + .gx_offs (gx_offs), + .x_offs_mode (x_offs_mode), +`ifdef XTR_FEAT + .ts_rres_ext (tsconf[0]), +`else + .ts_rres_ext (1'b0), +`endif + .hpix_beg (hpix_beg), + .hpix_end (hpix_end), + .vpix_beg (vpix_beg), + .vpix_end (vpix_end), + .hpix_beg_ts (hpix_beg_ts), + .hpix_end_ts (hpix_end_ts), + .vpix_beg_ts (vpix_beg_ts), + .vpix_end_ts (vpix_end_ts), + .x_tiles (x_tiles), + .go_offs (go_offs), + .cnt_col (cnt_col), + .cnt_row (cnt_row), + .cptr (cptr), + .line_start_s (line_start_s), + .pix_start (pix_start), + .tv_hires (tv_hires), + .vga_hires (vga_hires), + .pix_stb (pix_stb), + .render_mode (render_mode), + .video_addr (video_addr), + .video_bw (video_bw) + ); + video_sync video_sync + ( + .clk (clk), + .f1 (f1), + .c0 (c0), + .c3 (c3), + .hpix_beg (hpix_beg), + .hpix_end (hpix_end), + .vpix_beg (vpix_beg), + .vpix_end (vpix_end), + .hpix_beg_ts (hpix_beg_ts), + .hpix_end_ts (hpix_end_ts), + .vpix_beg_ts (vpix_beg_ts), + .vpix_end_ts (vpix_end_ts), + .go_offs (go_offs), + .x_offs (x_offs_mode[1:0]), + .y_offs_wr (gy_offsl_wr || gy_offsh_wr), + .line_start_s (line_start_s), + .hint_beg (hint_beg), + .vint_beg (vint_beg), + .hsync (hsync), + .vsync (vsync), + .csync (csync), + .tv_blank (tv_blank), + .vga_blank (vga_blank), + .vga_cnt_in (vga_cnt_in), + .vga_cnt_out (vga_cnt_out), + .ts_raddr (ts_raddr), + .lcount (lcount), + .cnt_col (cnt_col), + .cnt_row (cnt_row), + .cptr (cptr), + .scnt (scnt), +`ifdef PENT_312 + .hcnt (hcnt), + .upper8 (upper8), +`endif + .frame (frame), + .flash (flash), + .pix_stb (pix_stb), + .pix_start (pix_start), + .ts_start (ts_start), + .cstart (x_offs_mode[9:2]), + .rstart (gy_offs), + .vga_line (vga_line), + .frame_start (frame_start), + .int_start (int_start), + .v_pf (v_pf), + .hpix (hpix), + .v_ts (v_ts), + .vpix (vpix), + .hvpix (hvpix), + .hvtspix (hvtspix), + .nogfx (nogfx), + .vga_on (vga_on), + .cfg_60hz (cfg_60hz), + .v60hz (v60hz), + .video_go (video_go), + .video_pre_next (video_pre_next) + ); -video_sync video_sync -( - .clk (clk), - .f1 (f1), - .c0 (c0), - .c1 (c1), - .c3 (c3), - .hpix_beg (hpix_beg), - .hpix_end (hpix_end), - .vpix_beg (vpix_beg), - .vpix_end (vpix_end), - .hpix_beg_ts (hpix_beg_ts), - .hpix_end_ts (hpix_end_ts), - .vpix_beg_ts (vpix_beg_ts), - .vpix_end_ts (vpix_end_ts), - .go_offs (go_offs), - .x_offs (x_offs_mode[1:0]), - .y_offs_wr (gy_offsl_wr || gy_offsh_wr), - .line_start_s (line_start_s), - .hint_beg (hint_beg), - .vint_beg (vint_beg), - .hsync (hsync), - .vsync (vsync), - .tv_hblank (tv_hblank), - .tv_vblank (tv_vblank), - .ts_raddr (ts_raddr), - .lcount (lcount), - .cnt_col (cnt_col), - .cnt_row (cnt_row), - .cptr (cptr), - .scnt (scnt), - .flash (flash), - .pix_stb (pix_stb), - .pix_start (pix_start), - .ts_start (ts_start), - .cstart (x_offs_mode[9:2]), - .rstart (gy_offs), - .frame_start (frame_start), - .int_start (int_start), - .v_pf (v_pf), - .hpix (hpix), - .v_ts (v_ts), - .vpix (vpix), - .hvpix (hvpix), - .hvtspix (hvtspix), - .nogfx (nogfx), - .video_go (video_go), - .video_pre_next(video_pre_next) -); + video_fetch video_fetch + ( + .clk (clk), + .f_sel (fetch_sel), + .b_sel (fetch_bsl), + .fetch_stb (fetch_stb), + .fetch_data (fetch_data), + .fetch_temp (fetch_temp), + .video_strobe (video_strobe), + .video_data (dram_rdata) + ); + video_ts video_ts + ( + .clk (clk), + .start (ts_start), + .line (lcount), + .v_ts (v_ts), -video_fetch video_fetch -( - .clk (clk), - .f_sel (fetch_sel), - .b_sel (fetch_bsl), - .fetch_stb (fetch_stb), - .fetch_data (fetch_data), - .fetch_temp (fetch_temp), - .video_strobe (video_strobe), - .video_data (dram_rdata) -); +`ifdef DISABLE_TSU + .tsconf (0), +`else + .tsconf (tsconf), + // .tsconf ({3'b0, tsconf[4:0]}), // no TSU + // .tsconf ({1'b0, tsconf[6:0]}), // no sprites + // .tsconf ({tsconf[7], 2'b00, tsconf[4:0]}), // no tiles +`endif + .t0gpage (t0gpage), + .t1gpage (t1gpage), + .sgpage (sgpage), + .tmpage (tmpage), + .num_tiles (x_tiles), + .v_pf (v_pf), + .t0x_offs (t0x_offs), + .t1x_offs (t1x_offs), + .t0y_offs (t0y_offs), + .t1y_offs (t1y_offs), + .t0_palsel (palsel[5:4]), + .t1_palsel (palsel[7:6]), -video_ts video_ts -( - .clk (clk), - .start (ts_start), - .line (lcount), - .v_ts (v_ts), + .dram_addr (tm_addr), + .dram_req (tm_req), + .dram_next (tm_next), + .dram_rdata (dram_rdata), - .tsconf (tsconf), - .t0gpage (t0gpage), - .t1gpage (t1gpage), - .sgpage (sgpage), - .tmpage (tmpage), - .num_tiles (x_tiles), - .v_pf (v_pf), - .t0x_offs (t0x_offs), - .t1x_offs (t1x_offs), - .t0y_offs (t0y_offs), - .t1y_offs (t1y_offs), - .t0_palsel (palsel[5:4]), - .t1_palsel (palsel[7:6]), + .tsr_go (tsr_go), + .tsr_addr (tsr_addr), + .tsr_line (tsr_line), + .tsr_page (tsr_page), + .tsr_pal (tsr_pal), + .tsr_x (tsr_x), + .tsr_xs (tsr_xs), + .tsr_xf (tsr_xf), + .tsr_rdy (tsr_rdy), - .dram_addr (tm_addr), - .dram_req (tm_req), - .dram_next (tm_next), - .dram_rdata (dram_rdata), + .sfile_addr_in (zma), + .sfile_data_in (zmd), + .sfile_we (sfile_we) + ); - .tsr_go (tsr_go), - .tsr_addr (tsr_addr), - .tsr_line (tsr_line), - .tsr_page (tsr_page), - .tsr_pal (tsr_pal), - .tsr_x (tsr_x), - .tsr_xs (tsr_xs), - .tsr_xf (tsr_xf), - .tsr_rdy (tsr_rdy), + video_ts_render video_ts_render + ( + .clk (clk), - .sfile_addr_in (zma), - .sfile_data_in (zmd), - .sfile_we (sfile_we) -); + .reset (ts_start), -video_ts_render video_ts_render -( - .clk (clk), + .tsr_go (tsr_go), + .addr (tsr_addr), + .line (tsr_line), + .page (tsr_page), + .pal (tsr_pal), + .x_coord (tsr_x), + .x_size (tsr_xs), + .flip (tsr_xf), + .mem_rdy (tsr_rdy), - .reset (ts_start), + .ts_waddr (ts_waddr), + .ts_wdata (ts_wdata), + .ts_we (ts_we), - .tsr_go (tsr_go), - .addr (tsr_addr), - .line (tsr_line), - .page (tsr_page), - .pal (tsr_pal), - .x_coord (tsr_x), - .x_size (tsr_xs), - .flip (tsr_xf), - .mem_rdy (tsr_rdy), + .dram_addr (ts_addr), + .dram_req (ts_req), + .dram_pre_next (ts_pre_next), + .dram_next (ts_next), + .dram_rdata (dram_rdata) + ); - .ts_waddr (ts_waddr), - .ts_wdata (ts_wdata), - .ts_we (ts_we), + video_render video_render + ( + .clk (clk), + .c1 (c1), + .hvpix (hvpix), + .hvtspix (hvtspix), + .nogfx (nogfx), + .notsu (notsu), +`ifdef XTR_FEAT + .gfxovr (vconf[3]), +`else + .gfxovr (1'b0), +`endif + .flash (flash), + .hires (tv_hires), + .psel (scnt), + .palsel (palsel[3:0]), + .render_mode (render_mode), + .data (fetch_data), + .border_in (border), + .tsdata_in (ts_rdata), + .vplex_out (vplex) + ); - .dram_addr (ts_addr), - .dram_req (ts_req), - .dram_pre_next (ts_pre_next), - .dram_next (ts_next), - .dram_rdata (dram_rdata) -); + video_out video_out + ( + .clk (clk), + .c3 (c3), + .vga_on (vga_on), + .tv_blank (tv_blank), + .vga_blank (vga_blank), + .vga_line (vga_line), + .palsel (palsel[3:0]), + .plex_sel_in ({h1, f1}), + .tv_hires (tv_hires), + .vga_hires (vga_hires), + .cram_addr_in (zma), + .cram_data_in (zmd[15:0]), + .cram_we (cram_we), + .vplex_in (vplex), + .vgaplex (vgaplex), + .vred (vred), + .vgrn (vgrn), + .vblu (vblu), + .vred_raw (vred_raw), + .vgrn_raw (vgrn_raw), + .vblu_raw (vblu_raw), + .vdac_mode (vdac_mode) + ); + // 2 buffers: 512 pixels * 8 bits (9x8) - used as bitmap buffer for TS overlay over graphics + dpram #(.ADDRWIDTH(9)) video_tsline0 + ( + .clock (clk), + .address_a (ts_waddr0), + .data_a (ts_wdata0), + .wren_a (ts_we0), + .address_b (ts_raddr), + .q_b (ts_rdata0) + ); + dpram #(.ADDRWIDTH(9)) video_tsline1 + ( + .clock (clk), + .address_a (ts_waddr1), + .data_a (ts_wdata1), + .wren_a (ts_we1), + .address_b (ts_raddr), + .q_b (ts_rdata1) + ); +/* + altdpram video_tsline0 + ( + .inclock (clk), + .wren (ts_we0), + .data (ts_wdata0), + .rdaddress (ts_raddr), + .wraddress (ts_waddr0), + .q (ts_rdata0), + .aclr (1'b0), + .byteena (1'b1), + .inclocken (1'b1), + .outclock (1'b1), + .outclocken (1'b1), + .rdaddressstall (1'b0), + .rden (1'b1), + .wraddressstall (1'b0) + ); -video_render video_render -( - .clk (clk), - .c1 (c1), - .hvpix (hvpix), - .hvtspix (hvtspix), - .nogfx (nogfx), - .notsu (notsu), - .gfxovr (gfxovr), - .flash (flash), - .hires (tv_hires), - .psel (scnt), - .palsel (palsel[3:0]), - .render_mode (render_mode), - .data (fetch_data), - .border_in (border), - .tsdata_in (ts_rdata), - .vplex_out (vplex) -); + defparam + video_tsline0.indata_aclr = "OFF", + video_tsline0.indata_reg = "INCLOCK", + video_tsline0.intended_device_family = "ACEX1K", + video_tsline0.lpm_type = "altdpram", + video_tsline0.outdata_aclr = "OFF", + video_tsline0.outdata_reg = "UNREGISTERED", + video_tsline0.rdaddress_aclr = "OFF", + video_tsline0.rdaddress_reg = "INCLOCK", + video_tsline0.rdcontrol_aclr = "OFF", + video_tsline0.rdcontrol_reg = "UNREGISTERED", + video_tsline0.width = 8, + video_tsline0.widthad = 9, + video_tsline0.wraddress_aclr = "OFF", + video_tsline0.wraddress_reg = "INCLOCK", + video_tsline0.wrcontrol_aclr = "OFF", + video_tsline0.wrcontrol_reg = "INCLOCK"; -video_out video_out -( - .clk (clk), - .c3 (c3), - .tv_blank (tv_hblank|tv_vblank), - .palsel (palsel[3:0]), - .plex_sel_in ({h1, f1}), - .tv_hires (tv_hires), - .cram_addr_in (zma), - .cram_data_in (zmd[15:0]), - .cram_we (cram_we), - .vplex_in (vplex), - .vred (vred), - .vgrn (vgrn), - .vblu (vblu), - .vdac_mode (vdac_mode) -); + altdpram video_tsline1 + ( + .inclock (clk), + .wren (ts_we1), + .data (ts_wdata1), + .rdaddress (ts_raddr), + .wraddress (ts_waddr1), + .q (ts_rdata1), + .aclr (1'b0), + .byteena (1'b1), + .inclocken (1'b1), + .outclock (1'b1), + .outclocken (1'b1), + .rdaddressstall (1'b0), + .rden (1'b1), + .wraddressstall (1'b0) + ); -assign hblank = tv_hblank; -assign vblank = tv_vblank; + defparam + video_tsline1.indata_aclr = "OFF", + video_tsline1.indata_reg = "INCLOCK", + video_tsline1.intended_device_family = "ACEX1K", + video_tsline1.lpm_type = "altdpram", + video_tsline1.outdata_aclr = "OFF", + video_tsline1.outdata_reg = "UNREGISTERED", + video_tsline1.rdaddress_aclr = "OFF", + video_tsline1.rdaddress_reg = "INCLOCK", + video_tsline1.rdcontrol_aclr = "OFF", + video_tsline1.rdcontrol_reg = "UNREGISTERED", + video_tsline1.width = 8, + video_tsline1.widthad = 9, + video_tsline1.wraddress_aclr = "OFF", + video_tsline1.wraddress_reg = "INCLOCK", + video_tsline1.wrcontrol_aclr = "OFF", + video_tsline1.wrcontrol_reg = "INCLOCK"; +*/ -// 2 buffers: 512 pixels * 8 bits (9x8) - used as bitmap buffer for TS overlay over graphics -// (2 altdprams) -wire tl_act0 = lcount[0]; -wire tl_act1 = ~lcount[0]; -wire [8:0] ts_waddr0 = tl_act0 ? ts_raddr : ts_waddr; -wire [7:0] ts_wdata0 = tl_act0 ? 8'd0 : ts_wdata; -wire ts_we0 = tl_act0 ? c3 : ts_we; -wire [8:0] ts_waddr1 = tl_act1 ? ts_raddr : ts_waddr; -wire [7:0] ts_wdata1 = tl_act1 ? 8'd0 : ts_wdata; -wire ts_we1 = tl_act1 ? c3 : ts_we; -wire [7:0] ts_rdata = tl_act0 ? ts_rdata0 : ts_rdata1; -wire [7:0] ts_rdata0, ts_rdata1; - -dpram #(.ADDRWIDTH(9)) video_tsline0 -( - .clock (clk), - .address_a (ts_waddr0), - .data_a (ts_wdata0), - .wren_a (ts_we0), - .address_b (ts_raddr), - .q_b (ts_rdata0) -); - -dpram #(.ADDRWIDTH(9)) video_tsline1 -( - .clock (clk), - .address_a (ts_waddr1), - .data_a (ts_wdata1), - .wren_a (ts_we1), - .address_b (ts_raddr), - .q_b (ts_rdata1) -); + // 2 lines * 512 pix * 8 bit (10x8) - used for VGA doubler + dpram #(.ADDRWIDTH(10)) video_vmem + ( + .clock (clk), + .address_a (vga_cnt_in), + .data_a (vplex), + .wren_a (c3), + .address_b (vga_cnt_out), + .q_b (vgaplex) + ); +/* + altdpram video_vmem + ( + .inclock (clk), + .outclock (clk), + .wren (c3), + .data (vplex), + .rdaddress (vga_cnt_out), + .wraddress (vga_cnt_in), + .q (vgaplex), + .aclr (1'b0), + .byteena (1'b1), + .inclocken (1'b1), + .outclocken (1'b1), + .rdaddressstall (1'b0), + .rden (1'b1), + .wraddressstall (1'b0) + ); + defparam + video_vmem.indata_aclr = "OFF", + video_vmem.indata_reg = "INCLOCK", + video_vmem.intended_device_family = "ACEX1K", + video_vmem.lpm_type = "altdpram", + video_vmem.outdata_aclr = "OFF", + video_vmem.outdata_reg = "OUTCLOCK", + video_vmem.rdaddress_aclr = "OFF", + video_vmem.rdaddress_reg = "INCLOCK", + video_vmem.rdcontrol_aclr = "OFF", + video_vmem.rdcontrol_reg = "UNREGISTERED", + video_vmem.width = 8, + video_vmem.widthad = 10, + video_vmem.wraddress_aclr = "OFF", + video_vmem.wraddress_reg = "INCLOCK", + video_vmem.wrcontrol_aclr = "OFF", + video_vmem.wrcontrol_reg = "INCLOCK"; +*/ endmodule diff --git a/rtl/video/video_ts.v b/rtl/video/video_ts.v index f49abe4..87b2e79 100644 --- a/rtl/video/video_ts.v +++ b/rtl/video/video_ts.v @@ -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 diff --git a/rtl/video/video_ts_render.v b/rtl/video/video_ts_render.v index ae6f991..7f9e08a 100644 --- a/rtl/video/video_ts_render.v +++ b/rtl/video/video_ts_render.v @@ -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 diff --git a/rtl/z80/zclock.v b/rtl/z80/zclock.v new file mode 100644 index 0000000..44200d3 --- /dev/null +++ b/rtl/z80/zclock.v @@ -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 diff --git a/rtl/z80/zint.v b/rtl/z80/zint.v new file mode 100644 index 0000000..3fefbf8 --- /dev/null +++ b/rtl/z80/zint.v @@ -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 diff --git a/rtl/z80/zmaps.v b/rtl/z80/zmaps.v new file mode 100644 index 0000000..c22e3b9 --- /dev/null +++ b/rtl/z80/zmaps.v @@ -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 diff --git a/rtl/z80/zmem.v b/rtl/z80/zmem.v new file mode 100644 index 0000000..0ebf55f --- /dev/null +++ b/rtl/z80/zmem.v @@ -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 diff --git a/rtl/z80/zports.v b/rtl/z80/zports.v new file mode 100644 index 0000000..8316554 --- /dev/null +++ b/rtl/z80/zports.v @@ -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 diff --git a/rtl/z80/zsignals.v b/rtl/z80/zsignals.v new file mode 100644 index 0000000..7ec6a58 --- /dev/null +++ b/rtl/z80/zsignals.v @@ -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