mirror of
https://github.com/UzixLS/TSConf_MiST.git
synced 2025-07-18 23:01:37 +03:00
update tsconf to commit 83afbba6f5d366f96297028aa3d64512fa254a51
This commit is contained in:
@ -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
|
||||
|
||||
|
10
TSConf.sdc
10
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
|
||||
|
16
TSConf.srf
16
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 ""}
|
||||
|
18
TSConf.sv
18
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]),
|
||||
|
37
files.qip
37
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/
|
||||
|
33
rtl/clock.v
33
rtl/clock.v
@ -1,33 +0,0 @@
|
||||
// This module receives 28 MHz as input clock
|
||||
// and strobes strobes for all clocked parts
|
||||
|
||||
// clk|-__--__--__--__-| period = 28 duty = 50% phase = 0
|
||||
// cnt|< 0>< 1>< 2>< 3>|
|
||||
// f0 |----____----____| period = 14 duty = 50% phase = 0
|
||||
// f1 |____----____----| period = 14 duty = 50% phase = 180
|
||||
// h0 |--------________| period = 7 duty = 50% phase = 0
|
||||
// h1 |________--------| period = 7 duty = 50% phase = 180
|
||||
// c0 |----____________| period = 7 duty = 25% phase = 0
|
||||
// c1 |____----________| period = 7 duty = 25% phase = 90
|
||||
// c2 |________----____| period = 7 duty = 25% phase = 180
|
||||
// c3 |____________----| period = 7 duty = 25% phase = 270
|
||||
|
||||
module clock
|
||||
(
|
||||
input wire clk,
|
||||
|
||||
output reg f0, f1,
|
||||
output reg h0, h1,
|
||||
output reg c0, c1, c2, c3
|
||||
);
|
||||
|
||||
reg [1:0] cnt;
|
||||
always @(posedge clk) begin
|
||||
cnt <= cnt + 2'b1;
|
||||
|
||||
{f1, f0} <= 2'b1 << cnt[0];
|
||||
{h1, h0} <= 2'b1 << cnt[1];
|
||||
{c3, c2, c1, c0} <= 4'b1 << cnt;
|
||||
end
|
||||
|
||||
endmodule
|
61
rtl/common/clock.v
Normal file
61
rtl/common/clock.v
Normal file
@ -0,0 +1,61 @@
|
||||
|
||||
// This module receives 28 MHz as input clock
|
||||
// and makes strobes for all clocked parts
|
||||
|
||||
// clk |<EFBFBD>__<EFBFBD><EFBFBD>__<EFBFBD><EFBFBD>__<EFBFBD><EFBFBD>__<EFBFBD>| period = 28 duty = 50% phase = 0
|
||||
// cnt |< 0>< 1>< 2>< 3>|
|
||||
// f0 |<EFBFBD><EFBFBD><EFBFBD><EFBFBD>____<EFBFBD><EFBFBD><EFBFBD><EFBFBD>____| period = 14 duty = 50% phase = 0
|
||||
// f1 |____<EFBFBD><EFBFBD><EFBFBD><EFBFBD>____<EFBFBD><EFBFBD><EFBFBD><EFBFBD>| period = 14 duty = 50% phase = 180
|
||||
// h0 |<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>________| period = 7 duty = 50% phase = 0
|
||||
// h1 |________<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>| period = 7 duty = 50% phase = 180
|
||||
// c0 |<EFBFBD><EFBFBD><EFBFBD><EFBFBD>____________| period = 7 duty = 25% phase = 0
|
||||
// c1 |____<EFBFBD><EFBFBD><EFBFBD><EFBFBD>________| period = 7 duty = 25% phase = 90
|
||||
// c2 |________<EFBFBD><EFBFBD><EFBFBD><EFBFBD>____| period = 7 duty = 25% phase = 180
|
||||
// c3 |____________<EFBFBD><EFBFBD><EFBFBD><EFBFBD>| period = 7 duty = 25% phase = 270
|
||||
|
||||
`include "tune.v"
|
||||
|
||||
module clock
|
||||
(
|
||||
input wire clk,
|
||||
input wire [1:0] ay_mod,
|
||||
|
||||
output wire f0, f1,
|
||||
output wire h0, h1,
|
||||
output wire c0, c1, c2, c3,
|
||||
output wire ay_clk
|
||||
);
|
||||
|
||||
reg [1:0] f = 'b01;
|
||||
reg [1:0] h = 'b01;
|
||||
reg [3:0] c = 'b0001;
|
||||
|
||||
always @(posedge clk)
|
||||
begin
|
||||
f <= ~f;
|
||||
if (f[1]) h <= ~h;
|
||||
c <= {c[2:0], c[3]};
|
||||
end
|
||||
|
||||
assign f0 = f[0];
|
||||
assign f1 = f[1];
|
||||
assign h0 = h[0];
|
||||
assign h1 = h[1];
|
||||
assign c0 = c[0];
|
||||
assign c1 = c[1];
|
||||
assign c2 = c[2];
|
||||
assign c3 = c[3];
|
||||
|
||||
// AY clock generator
|
||||
// ay_mod - clock selection for AY, MHz: 00 - 1.75 / 01 - 1.7733 / 10 - 3.5 / 11 - 3.546
|
||||
reg [7:0] skip_cnt = 0;
|
||||
reg [3:0] ay_cnt = 0;
|
||||
assign ay_clk = ay_mod[1] ? ay_cnt[2] : ay_cnt[3];
|
||||
|
||||
always @(posedge clk)
|
||||
begin
|
||||
skip_cnt <= skip_cnt[7] ? 8'd73 : skip_cnt - 8'd1;
|
||||
ay_cnt <= ay_cnt + (skip_cnt[7] & ay_mod[0] ? 4'd2 : 4'd1);
|
||||
end
|
||||
|
||||
endmodule
|
@ -1,59 +1,74 @@
|
||||
// This module serves direct DRAM-to-device data transfer
|
||||
|
||||
// to do
|
||||
// - probably add the extra 8 bit counter for number of bursts
|
||||
`include "tune.v"
|
||||
|
||||
module dma
|
||||
(
|
||||
// clocks
|
||||
input wire clk,
|
||||
input wire c2,
|
||||
input wire reset,
|
||||
// clocks
|
||||
input wire clk,
|
||||
input wire c2,
|
||||
input wire rst_n,
|
||||
|
||||
// interface
|
||||
input wire [8:0] dmaport_wr,
|
||||
output wire dma_act,
|
||||
output reg [15:0] data,
|
||||
output wire [ 7:0] wraddr,
|
||||
output wire int_start,
|
||||
// interface
|
||||
`ifdef FDR
|
||||
input wire [9:0] dmaport_wr,
|
||||
`else
|
||||
input wire [8:0] dmaport_wr,
|
||||
`endif
|
||||
output wire dma_act,
|
||||
output reg [15:0] data = 0,
|
||||
output wire [ 7:0] wraddr,
|
||||
output wire int_start,
|
||||
|
||||
// Z80
|
||||
input wire [7:0] zdata,
|
||||
// Z80
|
||||
input wire [7:0] zdata,
|
||||
|
||||
// DRAM interface
|
||||
output wire [20:0] dram_addr,
|
||||
input wire [15:0] dram_rddata,
|
||||
output wire [15:0] dram_wrdata,
|
||||
output wire dram_req,
|
||||
output wire dram_rnw,
|
||||
input wire dram_next,
|
||||
// DRAM interface
|
||||
output wire [20:0] dram_addr,
|
||||
input wire [15:0] dram_rddata,
|
||||
output wire [15:0] dram_wrdata,
|
||||
output wire dram_req,
|
||||
output wire dram_rnw,
|
||||
input wire dram_next,
|
||||
|
||||
// SPI interface
|
||||
input wire [7:0] spi_rddata,
|
||||
output wire [7:0] spi_wrdata,
|
||||
output wire spi_req,
|
||||
input wire spi_stb,
|
||||
// SPI interface
|
||||
input wire [7:0] spi_rddata,
|
||||
output wire [7:0] spi_wrdata,
|
||||
output wire spi_req,
|
||||
input wire spi_stb,
|
||||
|
||||
// IDE interface
|
||||
input wire [15:0] ide_in,
|
||||
output wire [15:0] ide_out,
|
||||
output wire ide_req,
|
||||
output wire ide_rnw,
|
||||
input wire ide_stb,
|
||||
// WTPORT interface
|
||||
input wire [7:0] wtp_rddata,
|
||||
// output wire [7:0] wtp_wrdata,
|
||||
output wire wtp_req,
|
||||
input wire wtp_stb,
|
||||
|
||||
// CRAM interface
|
||||
output wire cram_we,
|
||||
// IDE interface
|
||||
input wire [15:0] ide_in,
|
||||
output wire [15:0] ide_out,
|
||||
output wire ide_req,
|
||||
output wire ide_rnw,
|
||||
input wire ide_stb,
|
||||
|
||||
// SFILE interface
|
||||
output wire sfile_we
|
||||
`ifdef FDR
|
||||
// FDD interface
|
||||
input wire [7:0] fdr_in,
|
||||
output wire fdr_req,
|
||||
input wire fdr_stb,
|
||||
input wire fdr_stop,
|
||||
`endif
|
||||
|
||||
// CRAM interface
|
||||
output wire cram_we,
|
||||
|
||||
// SFILE interface
|
||||
output wire sfile_we
|
||||
);
|
||||
|
||||
// mode:
|
||||
// 0 - device to RAM (read from device)
|
||||
// 1 - RAM to device (write to device)
|
||||
|
||||
assign wraddr = d_addr[7:0];
|
||||
|
||||
wire dma_saddrl = dmaport_wr[0];
|
||||
wire dma_saddrh = dmaport_wr[1];
|
||||
wire dma_saddrx = dmaport_wr[2];
|
||||
@ -63,72 +78,84 @@ module dma
|
||||
wire dma_len = dmaport_wr[6];
|
||||
wire dma_launch = dmaport_wr[7];
|
||||
wire dma_num = dmaport_wr[8];
|
||||
`ifdef FDR
|
||||
wire dma_numh = dmaport_wr[9];
|
||||
`endif
|
||||
|
||||
// DRAM
|
||||
assign dram_addr = state_rd ? ((!dv_blt || !phase_blt) ? s_addr : d_addr) : d_addr;
|
||||
assign dram_wrdata = data;
|
||||
assign dram_req = dma_act && state_mem;
|
||||
assign dram_rnw = state_rd;
|
||||
|
||||
// devices
|
||||
localparam DEV_RAM = 3'b0001;
|
||||
// devices
|
||||
localparam DEV_RAM = 3'b001;
|
||||
localparam DEV_BLT1 = 4'b1001;
|
||||
`ifdef XTR_FEAT
|
||||
localparam DEV_BLT2 = 4'b0110;
|
||||
`endif
|
||||
localparam DEV_FIL = 4'b0100;
|
||||
localparam DEV_SPI = 3'b010;
|
||||
localparam DEV_IDE = 3'b011;
|
||||
localparam DEV_CRM = 4'b1100;
|
||||
localparam DEV_SFL = 4'b1101;
|
||||
localparam DEV_FDD = 4'b0101;
|
||||
localparam DEV_WTP = 4'b0111;
|
||||
|
||||
wire state_dev;
|
||||
wire ide_int_stb;
|
||||
wire byte_sw_stb;
|
||||
wire spi_int_stb;
|
||||
wire wtp_int_stb;
|
||||
|
||||
reg dma_salgn;
|
||||
reg dma_dalgn;
|
||||
reg dma_asz;
|
||||
|
||||
reg phase; // 0 - read / 1 - write
|
||||
reg phase_blt; // 0 - source / 1 - destination
|
||||
reg bsel; // 0 - lsb / 1 - msb
|
||||
reg dma_opt;
|
||||
|
||||
reg [3:0] device;
|
||||
wire [2:0] dev_bid = device[2:0]; // bidirectional
|
||||
wire [3:0] dev_uni = device[3:0]; // unidirectional
|
||||
wire dma_wnr = device[3]; // 0 - device to RAM / 1 - RAM to device
|
||||
|
||||
`ifdef XTR_FEAT
|
||||
wire dv_ram = (dev_uni == DEV_RAM) || (dev_uni == DEV_BLT1) || (dev_uni == DEV_BLT2) || (dev_uni == DEV_FIL);
|
||||
wire dv_blt = (dev_uni == DEV_BLT1) || (dev_uni == DEV_BLT2);
|
||||
`else
|
||||
wire dv_ram = (dev_uni == DEV_RAM) || (dev_uni == DEV_BLT1) || (dev_uni == DEV_FIL);
|
||||
wire dv_blt = (dev_uni == DEV_BLT1);
|
||||
`endif
|
||||
wire dv_fil = (dev_uni == DEV_FIL);
|
||||
wire dv_spi = (dev_bid == DEV_SPI);
|
||||
wire dv_ide = (dev_bid == DEV_IDE);
|
||||
wire dv_crm = (dev_uni == DEV_CRM);
|
||||
wire dv_sfl = (dev_uni == DEV_SFL);
|
||||
wire dv_wtp = (dev_uni == DEV_WTP);
|
||||
`ifdef FDR
|
||||
wire dv_fdd = (dev_uni == DEV_FDD);
|
||||
`endif
|
||||
|
||||
wire dev_req = dma_act && state_dev;
|
||||
wire dev_stb = cram_we || sfile_we || ide_int_stb || (spi_int_stb && bsel && dma_act);
|
||||
wire dev_stb = cram_we || sfile_we || ide_int_stb || (byte_sw_stb && bsel && dma_act);
|
||||
|
||||
assign cram_we = dev_req && dv_crm && state_wr;
|
||||
assign sfile_we = dev_req && dv_sfl && state_wr;
|
||||
|
||||
// SPI
|
||||
wire spi_int_stb = dv_spi && spi_stb;
|
||||
assign spi_wrdata = {8{state_rd}} | (bsel ? data[15:8] : data[7:0]); // send FF on read cycles
|
||||
assign spi_req = dev_req && dv_spi;
|
||||
|
||||
// IDE
|
||||
wire ide_int_stb = dv_ide && ide_stb;
|
||||
assign ide_out = data;
|
||||
assign ide_req = dev_req && dv_ide;
|
||||
assign ide_rnw = state_rd;
|
||||
`ifdef FDR
|
||||
assign byte_sw_stb = spi_int_stb || wtp_int_stb || fdr_int_stb;
|
||||
`else
|
||||
assign byte_sw_stb = spi_int_stb || wtp_int_stb;
|
||||
`endif
|
||||
|
||||
// blitter
|
||||
wire [15:0] blt_rddata = (dev_uni == DEV_BLT1) ? blt1_rddata : blt2_rddata;
|
||||
|
||||
// Mode 1
|
||||
wire [15:0] blt1_rddata = {blt1_data_h, blt1_data_l};
|
||||
wire [7:0] blt1_data_h = dma_asz ? blt1_data32 : {blt1_data3, blt1_data2};
|
||||
wire [7:0] blt1_data_l = dma_asz ? blt1_data10 : {blt1_data1, blt1_data0};
|
||||
wire [7:0] blt1_data32 = |data[15:8] ? data[15:8] : dram_rddata[15:8];
|
||||
wire [7:0] blt1_data10 = |data[7:0] ? data[7:0] : dram_rddata[7:0];
|
||||
wire [3:0] blt1_data3 = |data[15:12] ? data[15:12] : dram_rddata[15:12];
|
||||
wire [3:0] blt1_data2 = |data[11:8] ? data[11:8] : dram_rddata[11:8];
|
||||
wire [3:0] blt1_data1 = |data[7:4] ? data[7:4] : dram_rddata[7:4];
|
||||
wire [7:0] blt1_data32 = |data[15:8] ? data[15:8] : dram_rddata[15:8];
|
||||
wire [3:0] blt1_data0 = |data[3:0] ? data[3:0] : dram_rddata[3:0];
|
||||
wire [3:0] blt1_data1 = |data[7:4] ? data[7:4] : dram_rddata[7:4];
|
||||
wire [3:0] blt1_data2 = |data[11:8] ? data[11:8] : dram_rddata[11:8];
|
||||
wire [3:0] blt1_data3 = |data[15:12] ? data[15:12] : dram_rddata[15:12];
|
||||
wire [7:0] blt1_data_l = dma_asz ? blt1_data10 : {blt1_data1, blt1_data0};
|
||||
wire [7:0] blt1_data_h = dma_asz ? blt1_data32 : {blt1_data3, blt1_data2};
|
||||
wire [15:0] blt1_rddata = {blt1_data_h, blt1_data_l};
|
||||
|
||||
`ifdef XTR_FEAT
|
||||
// Mode 2
|
||||
wire [15:0] blt2_rddata = {blt2_data_1, blt2_data_0};
|
||||
wire [7:0] blt2_data_1 = dma_asz ? blt2_8_data1 : {blt2_4_data3, blt2_4_data2};
|
||||
wire [7:0] blt2_data_0 = dma_asz ? blt2_8_data0 : {blt2_4_data1, blt2_4_data0};
|
||||
|
||||
localparam msk = 8'd255;
|
||||
|
||||
wire [8:0] sum80 = data[7:0] + dram_rddata[7:0];
|
||||
@ -146,38 +173,26 @@ module dma
|
||||
wire [3:0] blt2_4_data1 = ((sum41 > msk[3:0]) && dma_opt) ? msk[3:0] : sum41[3:0];
|
||||
wire [3:0] blt2_4_data2 = ((sum42 > msk[3:0]) && dma_opt) ? msk[3:0] : sum42[3:0];
|
||||
wire [3:0] blt2_4_data3 = ((sum43 > msk[3:0]) && dma_opt) ? msk[3:0] : sum43[3:0];
|
||||
wire [7:0] blt2_data_0 = dma_asz ? blt2_8_data0 : {blt2_4_data1, blt2_4_data0};
|
||||
wire [7:0] blt2_data_1 = dma_asz ? blt2_8_data1 : {blt2_4_data3, blt2_4_data2};
|
||||
wire [15:0] blt2_rddata = {blt2_data_1, blt2_data_0};
|
||||
wire [15:0] blt_rddata = (dev_uni == DEV_BLT1) ? blt1_rddata : blt2_rddata;
|
||||
|
||||
// data aquiring
|
||||
always @(posedge clk)
|
||||
if (state_rd)
|
||||
begin
|
||||
if (dram_next)
|
||||
data <= (dv_blt && phase_blt) ? blt_rddata : dram_rddata;
|
||||
`else // XTR_FEAT
|
||||
wire [15:0] blt_rddata = blt1_rddata;
|
||||
`endif
|
||||
|
||||
if (ide_int_stb)
|
||||
data <= ide_in;
|
||||
|
||||
if (spi_int_stb)
|
||||
begin
|
||||
if (bsel)
|
||||
data[15:8] <= spi_rddata;
|
||||
else
|
||||
data[7:0] <= spi_rddata;
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
// states
|
||||
// states
|
||||
wire state_rd = ~phase;
|
||||
wire state_wr = phase;
|
||||
wire state_dev = !dv_ram && (dma_wnr ^ !phase);
|
||||
assign state_dev = !dv_ram && (dma_wnr ^ !phase);
|
||||
wire state_mem = dv_ram || (dma_wnr ^ phase);
|
||||
|
||||
// states processing
|
||||
wire phase_end = phase_end_ram || phase_end_dev;
|
||||
// states processing
|
||||
wire blt_hook = dv_blt && !phase_blt && !phase;
|
||||
wire phase_end_ram = state_mem && dram_next && !blt_hook;
|
||||
wire phase_end_dev = state_dev && dev_stb;
|
||||
wire blt_hook = dv_blt && !phase_blt && !phase;
|
||||
wire phase_end = phase_end_ram || phase_end_dev;
|
||||
wire fil_hook = dv_fil && phase;
|
||||
wire phase_blt_end = state_mem && dram_next && !phase;
|
||||
|
||||
@ -187,15 +202,6 @@ module dma
|
||||
// 0 1 0 read dst
|
||||
// 1 1 0 write dst
|
||||
|
||||
reg [3:0] device;
|
||||
reg dma_salgn;
|
||||
reg dma_dalgn;
|
||||
reg dma_asz;
|
||||
reg phase; // 0 - read / 1 - write
|
||||
reg phase_blt; // 0 - source / 1 - destination
|
||||
reg bsel; // 0 - lsb / 1 - msb
|
||||
reg dma_opt;
|
||||
|
||||
always @(posedge clk)
|
||||
if (dma_launch) // write to DMACtrl - launch of DMA burst
|
||||
begin
|
||||
@ -215,26 +221,75 @@ module dma
|
||||
phase <= ~phase;
|
||||
if (phase_blt_end)
|
||||
phase_blt <= ~phase_blt;
|
||||
if (spi_int_stb)
|
||||
if (byte_sw_stb)
|
||||
bsel <= ~bsel;
|
||||
end
|
||||
|
||||
// data aquiring
|
||||
always @(posedge clk)
|
||||
if (state_rd)
|
||||
begin
|
||||
if (dram_next)
|
||||
data <= (dv_blt && phase_blt) ? blt_rddata : dram_rddata;
|
||||
|
||||
// counter processing
|
||||
if (ide_int_stb)
|
||||
data <= ide_in;
|
||||
|
||||
if (spi_int_stb)
|
||||
begin
|
||||
if (bsel)
|
||||
data[15:8] <= spi_rddata;
|
||||
else
|
||||
data[7:0] <= spi_rddata;
|
||||
end
|
||||
|
||||
if (wtp_int_stb)
|
||||
begin
|
||||
if (bsel)
|
||||
data[15:8] <= wtp_rddata;
|
||||
else
|
||||
data[7:0] <= wtp_rddata;
|
||||
end
|
||||
|
||||
`ifdef FDR
|
||||
if (fdr_int_stb)
|
||||
begin
|
||||
if (bsel)
|
||||
data[15:8] <= fdr_in;
|
||||
else
|
||||
data[7:0] <= fdr_in;
|
||||
end
|
||||
`endif
|
||||
end
|
||||
|
||||
// counter processing
|
||||
reg [7:0] b_len; // length of burst
|
||||
reg [7:0] b_ctr; // counter for cycles in burst
|
||||
|
||||
wire [8:0] b_ctr_dec = {1'b0, b_ctr[7:0]} - 9'b1;
|
||||
wire next_burst = b_ctr_dec[8];
|
||||
wire [7:0] b_ctr_next = next_burst ? b_len : b_ctr_dec[7:0];
|
||||
|
||||
`ifdef FDR
|
||||
reg [9:0] b_num; // number of bursts
|
||||
reg [10:0] n_ctr; // counter for bursts
|
||||
wire [10:0] n_ctr_dec = n_ctr - next_burst;
|
||||
assign dma_act = !n_ctr[10];
|
||||
`else
|
||||
reg [7:0] b_num; // number of bursts
|
||||
reg [8:0] n_ctr; // counter for bursts
|
||||
wire [8:0] n_ctr_dec = n_ctr - next_burst;
|
||||
assign dma_act = !n_ctr[8];
|
||||
reg [7:0] b_ctr; // counter for cycles in burst
|
||||
|
||||
wire [7:0] b_ctr_next = next_burst ? b_len : b_ctr_dec[7:0];
|
||||
wire [8:0] b_ctr_dec = {1'b0, b_ctr[7:0]} - 9'b1;
|
||||
wire next_burst = b_ctr_dec[8];
|
||||
`endif
|
||||
|
||||
always @(posedge clk)
|
||||
if (reset)
|
||||
`ifdef FDR
|
||||
if (!rst_n || (dv_fdd && fdr_stop))
|
||||
n_ctr[10] <= 1'b1;
|
||||
`else
|
||||
if (!rst_n)
|
||||
n_ctr[8] <= 1'b1;
|
||||
`endif
|
||||
|
||||
else if (dma_launch)
|
||||
begin
|
||||
@ -248,31 +303,36 @@ module dma
|
||||
n_ctr <= n_ctr_dec;
|
||||
end
|
||||
|
||||
|
||||
// loading of burst parameters
|
||||
// loading of burst parameters
|
||||
always @(posedge clk)
|
||||
begin
|
||||
if (dma_len)
|
||||
b_len <= zdata;
|
||||
|
||||
if (dma_num)
|
||||
`ifdef FDR
|
||||
b_num[7:0] <= zdata;
|
||||
|
||||
if (dma_numh)
|
||||
b_num[9:8] <= zdata[1:0];
|
||||
`else
|
||||
b_num <= zdata;
|
||||
`endif
|
||||
end
|
||||
|
||||
|
||||
// address processing
|
||||
// address processing
|
||||
|
||||
// source
|
||||
wire [20:0] s_addr_next = {s_addr_next_h[13:1], s_addr_next_m, s_addr_next_l[6:0]};
|
||||
wire [13:0] s_addr_next_h = s_addr[20:7] + s_addr_add_h;
|
||||
wire [1:0] s_addr_add_h = dma_salgn ? {next_burst && dma_asz, next_burst && !dma_asz} : {s_addr_inc_l[8], 1'b0};
|
||||
wire s_addr_next_m = dma_salgn ? (dma_asz ? s_addr_next_l[7] : s_addr_next_h[0]) : s_addr_inc_l[7];
|
||||
wire [7:0] s_addr_next_l = (dma_salgn && next_burst) ? s_addr_r : s_addr_inc_l[7:0];
|
||||
wire [8:0] s_addr_inc_l = {1'b0, s_addr[7:0]} + 9'b1;
|
||||
|
||||
reg [20:0] s_addr; // current source address
|
||||
reg [7:0] s_addr_r; // source lower address
|
||||
|
||||
wire [8:0] s_addr_inc_l = {1'b0, s_addr[7:0]} + 9'b1;
|
||||
wire [1:0] s_addr_add_h = dma_salgn ? {next_burst && dma_asz, next_burst && !dma_asz} : {s_addr_inc_l[8], 1'b0};
|
||||
wire [13:0] s_addr_next_h = s_addr[20:7] + s_addr_add_h;
|
||||
wire [7:0] s_addr_next_l = (dma_salgn && next_burst) ? s_addr_r : s_addr_inc_l[7:0];
|
||||
wire s_addr_next_m = dma_salgn ? (dma_asz ? s_addr_next_l[7] : s_addr_next_h[0]) : s_addr_inc_l[7];
|
||||
wire [20:0] s_addr_next = {s_addr_next_h[13:1], s_addr_next_m, s_addr_next_l[6:0]};
|
||||
|
||||
always @(posedge clk)
|
||||
if ((dram_next || dev_stb) && state_rd && (!dv_blt || !phase_blt)) // increment RAM source addr
|
||||
s_addr <= s_addr_next;
|
||||
@ -296,16 +356,16 @@ module dma
|
||||
end
|
||||
|
||||
// destination
|
||||
wire [20:0] d_addr_next = {d_addr_next_h[13:1], d_addr_next_m, d_addr_next_l[6:0]};
|
||||
wire [13:0] d_addr_next_h = d_addr[20:7] + d_addr_add_h;
|
||||
wire [1:0] d_addr_add_h = dma_dalgn ? {next_burst && dma_asz, next_burst && !dma_asz} : {d_addr_inc_l[8], 1'b0};
|
||||
wire d_addr_next_m = dma_dalgn ? (dma_asz ? d_addr_next_l[7] : d_addr_next_h[0]) : d_addr_inc_l[7];
|
||||
wire [7:0] d_addr_next_l = (dma_dalgn && next_burst) ? d_addr_r : d_addr_inc_l[7:0];
|
||||
wire [8:0] d_addr_inc_l = {1'b0, d_addr[7:0]} + 9'b1;
|
||||
|
||||
reg [20:0] d_addr; // current dest address
|
||||
reg [7:0] d_addr_r; // dest lower address
|
||||
|
||||
wire [8:0] d_addr_inc_l = {1'b0, d_addr[7:0]} + 9'b1;
|
||||
wire [1:0] d_addr_add_h = dma_dalgn ? {next_burst && dma_asz, next_burst && !dma_asz} : {d_addr_inc_l[8], 1'b0};
|
||||
wire [13:0] d_addr_next_h = d_addr[20:7] + d_addr_add_h;
|
||||
wire [7:0] d_addr_next_l = (dma_dalgn && next_burst) ? d_addr_r : d_addr_inc_l[7:0];
|
||||
wire d_addr_next_m = dma_dalgn ? (dma_asz ? d_addr_next_l[7] : d_addr_next_h[0]) : d_addr_inc_l[7];
|
||||
wire [20:0] d_addr_next = {d_addr_next_h[13:1], d_addr_next_m, d_addr_next_l[6:0]};
|
||||
|
||||
always @(posedge clk)
|
||||
if ((dram_next || dev_stb) && state_wr) // increment RAM dest addr
|
||||
d_addr <= d_addr_next;
|
||||
@ -328,10 +388,42 @@ module dma
|
||||
end
|
||||
|
||||
// INT generation
|
||||
reg dma_act_r;
|
||||
reg dma_act_r = 0;
|
||||
always @(posedge clk)
|
||||
dma_act_r <= dma_act && ~reset;
|
||||
dma_act_r <= dma_act && rst_n;
|
||||
|
||||
assign int_start = !dma_act && dma_act_r;
|
||||
|
||||
assign wraddr = d_addr[7:0];
|
||||
|
||||
// DRAM
|
||||
assign dram_addr = state_rd ? ((!dv_blt || !phase_blt) ? s_addr : d_addr) : d_addr;
|
||||
assign dram_wrdata = data;
|
||||
assign dram_req = dma_act && state_mem;
|
||||
assign dram_rnw = state_rd;
|
||||
|
||||
assign cram_we = dev_req && dv_crm && state_wr;
|
||||
assign sfile_we = dev_req && dv_sfl && state_wr;
|
||||
|
||||
`ifdef FDR
|
||||
// FDD
|
||||
wire fdr_int_stb = dv_fdd && fdr_stb;
|
||||
assign fdr_req = dev_req && dv_fdd;
|
||||
`endif
|
||||
|
||||
// SPI
|
||||
assign spi_int_stb = dv_spi && spi_stb;
|
||||
assign spi_wrdata = {8{state_rd}} | (bsel ? data[15:8] : data[7:0]); // send FF on read cycles
|
||||
assign spi_req = dev_req && dv_spi;
|
||||
|
||||
// WTPORT
|
||||
assign wtp_int_stb = dv_wtp && wtp_stb;
|
||||
assign wtp_req = dev_req && dv_wtp;
|
||||
|
||||
// IDE
|
||||
assign ide_int_stb = dv_ide && ide_stb;
|
||||
assign ide_out = data;
|
||||
assign ide_req = dev_req && dv_ide;
|
||||
assign ide_rnw = state_rd;
|
||||
|
||||
endmodule
|
15
rtl/common/resetter.v
Normal file
15
rtl/common/resetter.v
Normal file
@ -0,0 +1,15 @@
|
||||
`include "tune.v"
|
||||
|
||||
// Reset from MCU must be long enough
|
||||
module resetter
|
||||
(
|
||||
input wire clk,
|
||||
input wire rst_in_n, // external asynchronous reset
|
||||
output reg rst_out_n // synchronized reset
|
||||
);
|
||||
|
||||
always @(posedge clk)
|
||||
rst_out_n <= rst_in_n;
|
||||
|
||||
endmodule
|
||||
|
74
rtl/common/spi.v
Normal file
74
rtl/common/spi.v
Normal file
@ -0,0 +1,74 @@
|
||||
|
||||
`include "tune.v"
|
||||
|
||||
module spi
|
||||
(
|
||||
// SPI wires
|
||||
input wire clk, // system clock
|
||||
output wire sck, // SCK
|
||||
output reg sdo, // MOSI
|
||||
input wire sdi, // MISO
|
||||
input wire mode, // 0 - CPHA=0, CPOL=0 / 1 - CPHA=1, CPOL=0
|
||||
|
||||
// DMA interface
|
||||
input wire dma_req,
|
||||
input wire [7:0] dma_din,
|
||||
|
||||
// Z80 interface
|
||||
input wire cpu_req,
|
||||
input wire [7:0] cpu_din,
|
||||
|
||||
// output
|
||||
output wire start, // start strobe, 1 clock length
|
||||
output reg [7:0] dout
|
||||
);
|
||||
|
||||
reg [4:0] counter = 5'b10000;
|
||||
reg [7:0] shift = 0;
|
||||
reg busy_r;
|
||||
|
||||
wire busy = !counter[4];
|
||||
wire req = cpu_req || dma_req;
|
||||
|
||||
assign sck = counter[0];
|
||||
assign start = req && !busy;
|
||||
wire [7:0] din = dma_req ? dma_din : cpu_din;
|
||||
|
||||
wire cpha = mode;
|
||||
|
||||
always @(posedge clk)
|
||||
begin
|
||||
busy_r <= busy;
|
||||
|
||||
if (start)
|
||||
begin
|
||||
counter <= 5'b0;
|
||||
sdo <= din[7];
|
||||
shift[7:1] <= din[6:0];
|
||||
end
|
||||
else
|
||||
begin
|
||||
if (!counter[4])
|
||||
counter <= counter + 5'd1;
|
||||
|
||||
if (cpha ? busy_r : busy)
|
||||
begin
|
||||
// shift in
|
||||
if (cpha ? sck : !sck)
|
||||
begin
|
||||
shift[0] <= sdi;
|
||||
|
||||
if (&counter[3:1])
|
||||
dout <= {shift[7:1], sdi};
|
||||
end
|
||||
|
||||
// shift out
|
||||
if (cpha ? !sck : sck)
|
||||
begin
|
||||
sdo <= shift[7];
|
||||
shift[7:1] <= shift[6:0]; // last bit remains after end of exchange
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
endmodule
|
@ -1,106 +0,0 @@
|
||||
|
||||
// PentEvo project (c) NedoPC 2008-2011
|
||||
//
|
||||
// Z80 clocking module, also contains some wait-stating when 14MHz
|
||||
//
|
||||
// IDEAL:
|
||||
// clk _/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\
|
||||
// | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
|
||||
// zclk /```\___/```\___/```\___/```````\_______/```````\_______/```````````````\_______________/```````````````\_______________/`
|
||||
// | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
|
||||
// zpos `\___/```\___/```\___/```\___________/```\___________/```\___________________________/```\___________________________/```\
|
||||
// | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
|
||||
// zneg _/```\___/```\___/```\_______/```\___________/```\___________________/```\___________________________/```\________________
|
||||
|
||||
// clock phasing:
|
||||
// c3 must be zpos for 7mhz, therefore c1 - zneg
|
||||
// for 3.5 mhz, c3 is both zpos and zneg (alternating)
|
||||
|
||||
|
||||
// 14MHz rulez:
|
||||
// 1. do variable stalls for memory access.
|
||||
// 2. do fallback on 7mhz for external IO accesses
|
||||
// 3. clock switch 14-7-3.5 only at RFSH
|
||||
|
||||
module zclock
|
||||
(
|
||||
input clk,
|
||||
output zclk_out,
|
||||
input c0, c2, f0, f1,
|
||||
|
||||
input iorq_s,
|
||||
input external_port,
|
||||
|
||||
output reg zpos,
|
||||
output reg zneg,
|
||||
|
||||
// stall enables and triggers
|
||||
input cpu_stall,
|
||||
input ide_stall,
|
||||
input dos_on,
|
||||
input vdos_off,
|
||||
|
||||
input [1:0] turbo // 2'b00 - 3.5 MHz
|
||||
// 2'b01 - 7.0 MHz
|
||||
// 2'b1x - 14.0 MHz
|
||||
);
|
||||
|
||||
assign zclk_out = ~zclk_o;
|
||||
reg zclk_o;
|
||||
|
||||
wire [1:0] turbo_int = turbo;
|
||||
|
||||
// wait generator
|
||||
wire dos_io_stall = stall_start || !stall_count_end;
|
||||
wire stall_start = dos_stall || io_stall;
|
||||
wire dos_stall = dos_on || vdos_off;
|
||||
wire io_stall = iorq_s && external_port && turbo_int[1];
|
||||
wire stall_count_end = stall_count[3];
|
||||
|
||||
reg [3:0] stall_count;
|
||||
always @(posedge clk) begin
|
||||
if (stall_start) begin
|
||||
if (dos_stall) stall_count <= 4; // 4 tacts 28MHz (1 tact 7MHz)
|
||||
else if (io_stall) stall_count <= 0; // 8 tacts 28MHz (1 tact 3.5MHz)
|
||||
end
|
||||
else if (!stall_count_end) stall_count <= stall_count + 3'd1;
|
||||
end
|
||||
|
||||
// Z80 clocking pre-strobes
|
||||
wire pre_zpos = turbo_int[1] ? pre_zpos_140 : (turbo_int[0] ? pre_zpos_70 : pre_zpos_35);
|
||||
wire pre_zneg = turbo_int[1] ? pre_zneg_140 : (turbo_int[0] ? pre_zneg_70 : pre_zneg_35);
|
||||
|
||||
wire pre_zpos_140 = f1;
|
||||
wire pre_zneg_140 = f0;
|
||||
|
||||
wire pre_zpos_70 = c2;
|
||||
wire pre_zneg_70 = c0;
|
||||
|
||||
wire pre_zpos_35 = c2_cnt && c2;
|
||||
wire pre_zneg_35 = !c2_cnt && c2;
|
||||
|
||||
reg c2_cnt;
|
||||
always @(posedge clk) if (c2) c2_cnt <= ~c2_cnt;
|
||||
|
||||
|
||||
// Z80 clocking strobes
|
||||
wire stall = cpu_stall || dos_io_stall || ide_stall;
|
||||
|
||||
always @(posedge clk) begin
|
||||
zpos <= !stall && pre_zpos && zclk_o;
|
||||
zneg <= !stall && pre_zneg && !zclk_o;
|
||||
end
|
||||
|
||||
// make Z80 clock: account for external inversion and make some leading of clock
|
||||
// 9.5 ns propagation delay: from clk posedge to zclk returned back any edge
|
||||
// (1/28)/2=17.9ns half a clock lead
|
||||
// 2.6ns lag because of non-output register emitting of zclk_o
|
||||
// total: 5.8 ns lead of any edge of zclk relative to posedge of clk => ACCOUNT FOR THIS WHEN DOING INTER-CLOCK DATA TRANSFERS
|
||||
|
||||
// Z80 clocking
|
||||
always @(negedge clk) begin
|
||||
if (zpos) zclk_o <= 0;
|
||||
if (zneg) zclk_o <= 1;
|
||||
end
|
||||
|
||||
endmodule
|
@ -1,71 +0,0 @@
|
||||
|
||||
module zint
|
||||
(
|
||||
input wire clk,
|
||||
input wire zpos,
|
||||
input wire res,
|
||||
input wire int_start_frm,
|
||||
input wire int_start_lin,
|
||||
input wire int_start_dma,
|
||||
input wire vdos,
|
||||
input wire intack,
|
||||
input wire [7:0] intmask,
|
||||
output reg [7:0] im2vect,
|
||||
output wire int_n
|
||||
);
|
||||
|
||||
// In VDOS INTs are focibly disabled.
|
||||
// For Frame, Line INT its generation is blocked, it will be lost.
|
||||
// For DMA INT only its output is blocked, so DMA ISR will will be processed as soon as returned from VDOS.
|
||||
|
||||
assign int_n = ~(int_frm || int_lin || int_dma) | vdos;
|
||||
|
||||
wire dis_int_frm = !intmask[0];
|
||||
wire dis_int_lin = !intmask[1];
|
||||
wire dis_int_dma = !intmask[2];
|
||||
|
||||
wire intack_s = intack && !intack_r;
|
||||
reg intack_r;
|
||||
always @(posedge clk) intack_r <= intack;
|
||||
|
||||
reg [1:0] int_sel;
|
||||
always @(posedge clk) begin
|
||||
if (intack_s) begin
|
||||
if (int_frm) im2vect <= 8'hFF; // priority 0
|
||||
else if (int_lin) im2vect <= 8'hFD; // priority 1
|
||||
else if (int_dma) im2vect <= 8'hFB; // priority 2
|
||||
end
|
||||
end
|
||||
|
||||
// ~INT generating
|
||||
reg int_frm;
|
||||
always @(posedge clk) begin
|
||||
if (res || dis_int_frm) int_frm <= 0;
|
||||
else if (int_start_frm) int_frm <= 1;
|
||||
else if (intack_s || intctr_fin) int_frm <= 0; // priority 0
|
||||
end
|
||||
|
||||
reg int_lin;
|
||||
always @(posedge clk) begin
|
||||
if (res || dis_int_lin) int_lin <= 0;
|
||||
else if (int_start_lin) int_lin <= 1;
|
||||
else if (intack_s && !int_frm) int_lin <= 0; // priority 1
|
||||
end
|
||||
|
||||
reg int_dma;
|
||||
always @(posedge clk) begin
|
||||
if (res || dis_int_dma) int_dma <= 0;
|
||||
else if (int_start_dma) int_dma <= 1;
|
||||
else if (intack_s && !int_frm && !int_lin) int_dma <= 0; // priority 2
|
||||
end
|
||||
|
||||
// ~INT counter
|
||||
reg [5:0] intctr;
|
||||
wire intctr_fin = intctr[5]; // 32 clks
|
||||
|
||||
always @(posedge clk, posedge int_start_frm) begin
|
||||
if (int_start_frm) intctr <= 0;
|
||||
else if (zpos && !intctr_fin && !vdos) intctr <= intctr + 1'b1;
|
||||
end
|
||||
|
||||
endmodule
|
@ -1,56 +0,0 @@
|
||||
|
||||
// This module maps z80 memory accesses into FPGA RAM and ports
|
||||
|
||||
module zmaps
|
||||
(
|
||||
// Z80 controls
|
||||
input wire clk,
|
||||
input wire memwr_s,
|
||||
input wire [15:0] a,
|
||||
input wire [7:0] d,
|
||||
|
||||
// config data
|
||||
input wire [4:0] fmaddr,
|
||||
|
||||
// FPRAM data
|
||||
output wire [15:0] zmd,
|
||||
output wire [7:0] zma,
|
||||
|
||||
// DMA
|
||||
input wire [15:0] dma_data,
|
||||
input wire [7:0] dma_wraddr,
|
||||
input wire dma_cram_we,
|
||||
input wire dma_sfile_we,
|
||||
|
||||
// write strobes
|
||||
output wire cram_we,
|
||||
output wire sfile_we,
|
||||
output wire regs_we
|
||||
);
|
||||
|
||||
|
||||
// addresses of files withing zmaps
|
||||
localparam CRAM = 3'b000;
|
||||
localparam SFYS = 3'b001;
|
||||
localparam REGS = 4'b0100;
|
||||
|
||||
|
||||
// control signals
|
||||
wire hit = (a[15:12] == fmaddr[3:0]) && fmaddr[4] && memwr_s;
|
||||
|
||||
// write enables
|
||||
assign cram_we = dma_req ? dma_cram_we : (a[11:9] == CRAM) && a[0] && hit;
|
||||
assign sfile_we = dma_req ? dma_sfile_we : (a[11:9] == SFYS) && a[0] && hit;
|
||||
assign regs_we = (a[11:8] == REGS) && hit;
|
||||
|
||||
// LSB fetching
|
||||
assign zma = dma_req ? dma_wraddr : a[8:1];
|
||||
assign zmd = dma_req ? dma_data : {d, zmd0};
|
||||
|
||||
reg [7:0] zmd0;
|
||||
always @(posedge clk) if (!a[0] && hit) zmd0 <= d;
|
||||
|
||||
// DMA
|
||||
wire dma_req = dma_cram_we || dma_sfile_we;
|
||||
|
||||
endmodule
|
@ -1,228 +0,0 @@
|
||||
// PentEvo project (c) NedoPC 2008-2009
|
||||
//
|
||||
// Z80 memory manager: routes ROM/RAM accesses, makes wait-states for 14MHz or stall condition, etc.
|
||||
//
|
||||
//
|
||||
// clk _/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\
|
||||
// | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
|
||||
// zclk /```\___/```\___/```\___/```````\_______/```````\_______/```````````````\_______________/```````````````\_______________/`
|
||||
// | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
|
||||
// zpos `\___/```\___/```\___/```\___________/```\___________/```\___________________________/```\___________________________/```\
|
||||
// | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
|
||||
// zneg _/```\___/```\___/```\_______/```\___________/```\___________________/```\___________________________/```\________________
|
||||
|
||||
module zmem
|
||||
(
|
||||
input clk,
|
||||
input c0, c1, c2, c3,
|
||||
input zneg, // strobes which show positive and negative edges of zclk
|
||||
input zpos,
|
||||
|
||||
// Z80
|
||||
input rst,
|
||||
input [15:0] za,
|
||||
output [ 7:0] zd_out, // output to Z80 bus
|
||||
output zd_ena, // output to Z80 bus enable
|
||||
|
||||
input opfetch,
|
||||
input opfetch_s,
|
||||
input mreq,
|
||||
input memrd,
|
||||
input memwr,
|
||||
input memwr_s,
|
||||
|
||||
input [ 1:0] turbo, // 2'b00 - 3.5,
|
||||
// 2'b01 - 7.0,
|
||||
// 2'b1x - 14.0
|
||||
input [3:0] cache_en,
|
||||
input [3:0] memconf,
|
||||
input [31:0] xt_page,
|
||||
|
||||
output [4:0] rompg,
|
||||
output csrom,
|
||||
output romoe_n,
|
||||
output romwe_n,
|
||||
|
||||
output dos,
|
||||
output dos_on,
|
||||
output dos_off,
|
||||
output vdos,
|
||||
output reg pre_vdos,
|
||||
input vdos_on,
|
||||
input vdos_off,
|
||||
|
||||
// DRAM
|
||||
output cpu_req,
|
||||
output [20:0] cpu_addr,
|
||||
output cpu_wrbsel,
|
||||
input [15:0] cpu_rddata,
|
||||
input cpu_next,
|
||||
input cpu_strobe,
|
||||
input cpu_latch,
|
||||
output cpu_stall // for zclock
|
||||
);
|
||||
|
||||
// controls
|
||||
wire rom128 = memconf[0];
|
||||
wire w0_we = memconf[1];
|
||||
wire w0_map_n = memconf[2];
|
||||
wire w0_ram = memconf[3];
|
||||
|
||||
// pager
|
||||
wire [1:0] win = za[15:14];
|
||||
wire win0 = ~|win;
|
||||
wire ramwr_en = !win0 || w0_we || vdos;
|
||||
wire rom_n_ram = win0 && !w0_ram && !vdos;
|
||||
wire [7:0] page = xtpage[win];
|
||||
|
||||
wire [7:0] xtpage[0:3];
|
||||
assign xtpage[0] = vdos ? 8'hFF : {xt_page[7:2], w0_map_n ? xt_page[1:0] : {~dos, rom128}};
|
||||
assign xtpage[1] = xt_page[15:8];
|
||||
assign xtpage[2] = xt_page[23:16];
|
||||
assign xtpage[3] = xt_page[31:24];
|
||||
|
||||
// ROM chip
|
||||
assign csrom = rom_n_ram;
|
||||
assign romoe_n = !memrd;
|
||||
assign romwe_n = !(memwr && w0_we);
|
||||
assign rompg = xtpage[0][4:0];
|
||||
|
||||
// RAM
|
||||
assign zd_ena = memrd;
|
||||
wire ramreq = ((memrd && !cache_hit_en) || (memwr && ramwr_en));
|
||||
|
||||
// DOS signal control
|
||||
assign dos_on = win0 && opfetch_s && (za[13:8]==6'h3D) && rom128 && !w0_map_n;
|
||||
assign dos_off = !win0 && opfetch_s && !vdos;
|
||||
|
||||
assign dos = (dos_on || dos_off) ^^ dos_r; // to make dos appear 1 clock earlier than dos_r
|
||||
|
||||
reg dos_r;
|
||||
always @(posedge clk) begin
|
||||
if (rst) dos_r <= 0;
|
||||
else if (dos_off) dos_r <= 0;
|
||||
else if (dos_on) dos_r <= 1;
|
||||
end
|
||||
|
||||
// VDOS signal control
|
||||
// vdos turn on/off is delayed till next opfetch due to INIR that writes right after iord cycle
|
||||
assign vdos = opfetch ? pre_vdos : vdos_r; // vdos appears as soon as first opfetch
|
||||
|
||||
reg vdos_r;
|
||||
always @(posedge clk) begin
|
||||
if (rst || vdos_off) begin
|
||||
pre_vdos <= 0;
|
||||
vdos_r <= 0;
|
||||
end
|
||||
else if (vdos_on) pre_vdos <= 1;
|
||||
else if (opfetch_s) vdos_r <= pre_vdos;
|
||||
end
|
||||
|
||||
// address, data in and data out
|
||||
assign cpu_wrbsel = za[0];
|
||||
assign cpu_addr[20:0] = {page, za[13:1]};
|
||||
wire [15:0] mem_d = cpu_latch ? cpu_rddata : cache_d;
|
||||
assign zd_out = ~cpu_wrbsel ? mem_d[7:0] : mem_d[15:8];
|
||||
|
||||
// Z80 controls
|
||||
assign cpu_req = turbo14 ? cpureq_14 : cpureq_357;
|
||||
assign cpu_stall = turbo14 ? stall14 : stall357;
|
||||
wire turbo14 = turbo[1];
|
||||
|
||||
// 7/3.5MHz support
|
||||
wire cpureq_357 = ramreq && !ramreq_r;
|
||||
wire stall357 = cpureq_357 && !cpu_next;
|
||||
|
||||
reg ramreq_r;
|
||||
always @(posedge clk) if (c3 && !cpu_stall) ramreq_r <= ramreq;
|
||||
|
||||
// 14MHz support
|
||||
// wait tables:
|
||||
//
|
||||
// M1 opcode fetch, dram_beg concurs with:
|
||||
// c3: +3
|
||||
// c2: +4
|
||||
// c1: +5
|
||||
// c0: +6
|
||||
//
|
||||
// memory read, dram_beg concurs with:
|
||||
// c3: +2
|
||||
// c2: +3
|
||||
// c1: +4
|
||||
// c0: +5
|
||||
//
|
||||
// memory write: no wait
|
||||
//
|
||||
// special case: if dram_beg pulses 1 when cpu_next is 0,
|
||||
// unconditional wait has to be performed until cpu_next is 1, and
|
||||
// then wait as if dram_beg would concur with c0
|
||||
|
||||
// memrd, opfetch - wait till c3 && cpu_next,
|
||||
// memwr - wait till cpu_next
|
||||
|
||||
wire cpureq_14 = dram_beg || pending_cpu_req;
|
||||
wire stall14 = stall14_ini || stall14_cyc || stall14_fin;
|
||||
|
||||
wire dram_beg = ramreq && !pre_ramreq_r && zneg;
|
||||
|
||||
reg pre_ramreq_r;
|
||||
always @(posedge clk) if (zneg) pre_ramreq_r <= ramreq;
|
||||
|
||||
reg pending_cpu_req;
|
||||
always @(posedge clk) begin
|
||||
if (rst) pending_cpu_req <= 0;
|
||||
else if (cpu_next && c3) pending_cpu_req <= 0;
|
||||
else if (dram_beg) pending_cpu_req <= 1;
|
||||
end
|
||||
|
||||
wire stall14_ini = dram_beg && (!cpu_next || opfetch || memrd); // no wait at all in write cycles, if next dram cycle is available
|
||||
wire stall14_cyc = memrd ? stall14_cycrd : !cpu_next;
|
||||
|
||||
reg stall14_cycrd;
|
||||
always @(posedge clk) begin
|
||||
if (rst) stall14_cycrd <= 0;
|
||||
else if (cpu_next && c3) stall14_cycrd <= 0;
|
||||
else if (dram_beg && (!c3 || !cpu_next) && (opfetch || memrd)) stall14_cycrd <= 1;
|
||||
end
|
||||
|
||||
reg stall14_fin;
|
||||
always @(posedge clk) begin
|
||||
if (rst) stall14_fin <= 0;
|
||||
else if (stall14_fin && ((opfetch && c1) || (memrd && c2))) stall14_fin <= 0;
|
||||
else if (cpu_next && c3 && cpu_req && (opfetch || memrd)) stall14_fin <= 1;
|
||||
end
|
||||
|
||||
// cache
|
||||
// wire cache_hit = (ch_addr[7:2] != 6'b011100) && (cpu_hi_addr == cache_a) && cache_v; // debug for BM
|
||||
wire cache_hit = (cpu_hi_addr == cache_a) && cache_v; // asynchronous signal meaning that address requested by CPU is cached and valid
|
||||
wire cache_hit_en = cache_hit && cache_en[win];
|
||||
wire cache_inv = cache_hit && memwr_s && ramwr_en; // cache invalidation should be only performed if write happens to cached address
|
||||
|
||||
wire [12:0] cpu_hi_addr = {page[7:0], za[13:9]};
|
||||
wire [12:0] cache_a;
|
||||
wire [7:0] ch_addr = cpu_addr[7:0];
|
||||
|
||||
wire [15:0] cache_d;
|
||||
wire cache_v;
|
||||
|
||||
dpram #(.DATAWIDTH(16), .ADDRWIDTH(8)) cache_data
|
||||
(
|
||||
.clock(clk),
|
||||
.address_a(ch_addr),
|
||||
.data_a(cpu_rddata),
|
||||
.wren_a(cpu_strobe),
|
||||
.address_b(ch_addr),
|
||||
.q_b(cache_d)
|
||||
);
|
||||
|
||||
dpram #(.DATAWIDTH(14), .ADDRWIDTH(8)) cache_addr
|
||||
(
|
||||
.clock(clk),
|
||||
.address_a(ch_addr),
|
||||
.data_a({!cache_inv, cpu_hi_addr}),
|
||||
.wren_a(cpu_strobe || cache_inv),
|
||||
.address_b(ch_addr),
|
||||
.q_b({cache_v, cache_a})
|
||||
);
|
||||
|
||||
endmodule
|
@ -1,469 +0,0 @@
|
||||
|
||||
// PentEvo project (c) NedoPC 2008-2010
|
||||
|
||||
module zports
|
||||
(
|
||||
input clk,
|
||||
|
||||
input [7:0] din,
|
||||
output reg [7:0] dout,
|
||||
output dataout,
|
||||
input [15:0] a,
|
||||
|
||||
input rst, // system reset
|
||||
input opfetch,
|
||||
|
||||
input rd,
|
||||
input wr,
|
||||
input rdwr,
|
||||
|
||||
input iorq,
|
||||
input iorq_s,
|
||||
input iord,
|
||||
input iord_s,
|
||||
input iowr,
|
||||
input iowr_s,
|
||||
input iordwr,
|
||||
input iordwr_s,
|
||||
|
||||
output porthit, // when internal port hit occurs, this is 1, else 0; used for iorq1_n iorq2_n on zxbus
|
||||
output external_port, // asserts for AY and VG93 accesses
|
||||
|
||||
output zborder_wr,
|
||||
output border_wr,
|
||||
output zvpage_wr,
|
||||
output vpage_wr,
|
||||
output vconf_wr,
|
||||
output gx_offsl_wr,
|
||||
output gx_offsh_wr,
|
||||
output gy_offsl_wr,
|
||||
output gy_offsh_wr,
|
||||
output t0x_offsl_wr,
|
||||
output t0x_offsh_wr,
|
||||
output t0y_offsl_wr,
|
||||
output t0y_offsh_wr,
|
||||
output t1x_offsl_wr,
|
||||
output t1x_offsh_wr,
|
||||
output t1y_offsl_wr,
|
||||
output t1y_offsh_wr,
|
||||
output tsconf_wr,
|
||||
output palsel_wr,
|
||||
output tmpage_wr,
|
||||
output t0gpage_wr,
|
||||
output t1gpage_wr,
|
||||
output sgpage_wr,
|
||||
output hint_beg_wr ,
|
||||
output vint_begl_wr,
|
||||
output vint_begh_wr,
|
||||
|
||||
output [31:0] xt_page,
|
||||
|
||||
output reg [4:0] fmaddr,
|
||||
input regs_we,
|
||||
|
||||
output reg [7:0] sysconf,
|
||||
output reg [7:0] memconf,
|
||||
output reg [3:0] cacheconf,
|
||||
output reg [7:0] fddvirt,
|
||||
|
||||
output [8:0] dmaport_wr,
|
||||
input dma_act,
|
||||
output reg [1:0] dmawpdev,
|
||||
|
||||
|
||||
output reg [7:0] intmask,
|
||||
|
||||
input dos,
|
||||
input vdos,
|
||||
output vdos_on,
|
||||
output vdos_off,
|
||||
|
||||
output ay_bdir,
|
||||
output ay_bc1,
|
||||
output covox_wr,
|
||||
output beeper_wr,
|
||||
|
||||
input tape_read,
|
||||
|
||||
input [4:0] keys_in, // keys (port FE)
|
||||
input [7:0] mus_in, // mouse (xxDF)
|
||||
input [5:0] kj_in,
|
||||
|
||||
input vg_intrq,
|
||||
input vg_drq, // from vg93 module - drq + irq read
|
||||
output vg_cs_n,
|
||||
output vg_wrFF,
|
||||
output [1:0] drive_sel, // disk drive selection
|
||||
|
||||
// SPI
|
||||
output sdcs_n,
|
||||
output sd_start,
|
||||
output [7:0] sd_datain,
|
||||
input [7:0] sd_dataout,
|
||||
|
||||
// WAIT-ports related
|
||||
output reg [7:0] wait_addr,
|
||||
output wait_start_gluclock, // begin wait from some ports
|
||||
output wait_start_comport, //
|
||||
output reg [7:0] wait_write,
|
||||
input [7:0] wait_read
|
||||
);
|
||||
|
||||
assign sdcs_n = spi_cs_n[0];
|
||||
|
||||
localparam FDR_VER = 1'b0;
|
||||
|
||||
localparam VDAC_VER = 3'h3;
|
||||
|
||||
localparam PORTFE = 8'hFE;
|
||||
localparam PORTFD = 8'hFD;
|
||||
localparam PORTXT = 8'hAF;
|
||||
localparam PORTF7 = 8'hF7;
|
||||
localparam COVOX = 8'hFB;
|
||||
|
||||
localparam VGCOM = 8'h1F;
|
||||
localparam VGTRK = 8'h3F;
|
||||
localparam VGSEC = 8'h5F;
|
||||
localparam VGDAT = 8'h7F;
|
||||
localparam VGSYS = 8'hFF;
|
||||
|
||||
localparam KJOY = 8'h1F;
|
||||
localparam KMOUSE = 8'hDF;
|
||||
|
||||
localparam SDCFG = 8'h77;
|
||||
localparam SDDAT = 8'h57;
|
||||
|
||||
localparam COMPORT = 8'hEF; // F8EF..FFEF - rs232 ports
|
||||
|
||||
|
||||
wire [7:0] loa = a[7:0];
|
||||
wire [7:0] hoa = regs_we ? a[7:0] : a[15:8];
|
||||
|
||||
assign porthit = ((loa==PORTFE) || (loa==PORTXT) || (loa==PORTFD) || (loa==COVOX))
|
||||
|| ((loa==PORTF7) && !dos)
|
||||
|| ((vg_port || vgsys_port) && (dos || open_vg))
|
||||
|| ((loa==KJOY) && !dos && !open_vg)
|
||||
|| (loa==KMOUSE)
|
||||
|| (((loa==SDCFG) || (loa==SDDAT)) && (!dos || vdos))
|
||||
|| (loa==COMPORT);
|
||||
|
||||
wire vg_port = (loa==VGCOM) || (loa==VGTRK) || (loa==VGSEC) || (loa==VGDAT);
|
||||
wire vgsys_port = (loa==VGSYS);
|
||||
|
||||
assign external_port = ((loa==PORTFD) && a[15]) // AY
|
||||
|| (((loa==VGCOM) || (loa==VGTRK) || (loa==VGSEC) || (loa==VGDAT)) && (dos || open_vg));
|
||||
|
||||
assign dataout = porthit && iord && (~external_port);
|
||||
|
||||
|
||||
reg iowr_reg;
|
||||
reg iord_reg;
|
||||
reg port_wr;
|
||||
reg port_rd;
|
||||
|
||||
always @(posedge clk) begin
|
||||
iowr_reg <= iowr;
|
||||
port_wr <= (!iowr_reg && iowr);
|
||||
|
||||
iord_reg <= iord;
|
||||
port_rd <= (!iord_reg && iord);
|
||||
end
|
||||
|
||||
|
||||
// reading ports
|
||||
always @(*) begin
|
||||
case (loa)
|
||||
PORTFE:
|
||||
dout = {1'b1, tape_read, 1'b0, keys_in};
|
||||
|
||||
PORTXT:
|
||||
begin
|
||||
case (hoa)
|
||||
XSTAT:
|
||||
dout = {1'b0, pwr_up_reg, FDR_VER, 2'b0, VDAC_VER};
|
||||
|
||||
DMASTAT:
|
||||
dout = {dma_act, 7'b0};
|
||||
|
||||
RAMPAGE + 8'd2, RAMPAGE + 8'd3:
|
||||
dout = rampage[hoa[1:0]];
|
||||
|
||||
default:
|
||||
dout = 8'hFF;
|
||||
|
||||
endcase
|
||||
end
|
||||
|
||||
VGSYS:
|
||||
dout = {vg_intrq, vg_drq, 6'b111111};
|
||||
|
||||
KJOY:
|
||||
dout = {2'b00, kj_in};
|
||||
KMOUSE:
|
||||
dout = mus_in;
|
||||
|
||||
SDCFG:
|
||||
dout = 8'h00; // always SD inserted, SD is in R/W mode
|
||||
SDDAT:
|
||||
dout = sd_dataout;
|
||||
|
||||
PORTF7:
|
||||
begin
|
||||
if (!a[14] && (a[8] ^ dos) && gluclock_on) dout = wait_read; // $BFF7 - data i/o
|
||||
else dout = 8'hFF; // any other $xxF7 port
|
||||
end
|
||||
|
||||
COMPORT:
|
||||
dout = wait_read; // $F8EF..$FFEF
|
||||
|
||||
default:
|
||||
dout = 8'hFF;
|
||||
endcase
|
||||
end
|
||||
|
||||
|
||||
// power-up
|
||||
// This bit is loaded as 1 while FPGA is configured
|
||||
// and automatically reset to 0 after STATUS port reading
|
||||
reg pwr_up_reg;
|
||||
reg pwr_up = 1;
|
||||
always @(posedge clk) begin
|
||||
if (iord_s & (loa == PORTXT) & (hoa == XSTAT)) begin
|
||||
pwr_up_reg <= pwr_up;
|
||||
pwr_up <= 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
// writing ports
|
||||
|
||||
//#nnAF
|
||||
localparam VCONF = 8'h00;
|
||||
localparam VPAGE = 8'h01;
|
||||
localparam GXOFFSL = 8'h02;
|
||||
localparam GXOFFSH = 8'h03;
|
||||
localparam GYOFFSL = 8'h04;
|
||||
localparam GYOFFSH = 8'h05;
|
||||
localparam TSCONF = 8'h06;
|
||||
localparam PALSEL = 8'h07;
|
||||
localparam XBORDER = 8'h0F;
|
||||
|
||||
localparam T0XOFFSL = 8'h40;
|
||||
localparam T0XOFFSH = 8'h41;
|
||||
localparam T0YOFFSL = 8'h42;
|
||||
localparam T0YOFFSH = 8'h43;
|
||||
localparam T1XOFFSL = 8'h44;
|
||||
localparam T1XOFFSH = 8'h45;
|
||||
localparam T1YOFFSL = 8'h46;
|
||||
localparam T1YOFFSH = 8'h47;
|
||||
|
||||
localparam RAMPAGE = 8'h10; // this covers #10-#13
|
||||
localparam FMADDR = 8'h15;
|
||||
localparam TMPAGE = 8'h16;
|
||||
localparam T0GPAGE = 8'h17;
|
||||
localparam T1GPAGE = 8'h18;
|
||||
localparam SGPAGE = 8'h19;
|
||||
localparam DMASADDRL = 8'h1A;
|
||||
localparam DMASADDRH = 8'h1B;
|
||||
localparam DMASADDRX = 8'h1C;
|
||||
localparam DMADADDRL = 8'h1D;
|
||||
localparam DMADADDRH = 8'h1E;
|
||||
localparam DMADADDRX = 8'h1F;
|
||||
|
||||
localparam SYSCONF = 8'h20;
|
||||
localparam MEMCONF = 8'h21;
|
||||
localparam HSINT = 8'h22;
|
||||
localparam VSINTL = 8'h23;
|
||||
localparam VSINTH = 8'h24;
|
||||
localparam DMAWPD = 8'h25;
|
||||
localparam DMALEN = 8'h26;
|
||||
localparam DMACTRL = 8'h27;
|
||||
localparam DMANUM = 8'h28;
|
||||
localparam FDDVIRT = 8'h29;
|
||||
localparam INTMASK = 8'h2A;
|
||||
localparam CACHECONF = 8'h2B;
|
||||
localparam DMAWPA = 8'h2D;
|
||||
|
||||
localparam XSTAT = 8'h00;
|
||||
localparam DMASTAT = 8'h27;
|
||||
|
||||
assign dmaport_wr[0] = portxt_wr && (hoa == DMASADDRL);
|
||||
assign dmaport_wr[1] = portxt_wr && (hoa == DMASADDRH);
|
||||
assign dmaport_wr[2] = portxt_wr && (hoa == DMASADDRX);
|
||||
assign dmaport_wr[3] = portxt_wr && (hoa == DMADADDRL);
|
||||
assign dmaport_wr[4] = portxt_wr && (hoa == DMADADDRH);
|
||||
assign dmaport_wr[5] = portxt_wr && (hoa == DMADADDRX);
|
||||
assign dmaport_wr[6] = portxt_wr && (hoa == DMALEN);
|
||||
assign dmaport_wr[7] = portxt_wr && (hoa == DMACTRL);
|
||||
assign dmaport_wr[8] = portxt_wr && (hoa == DMANUM);
|
||||
|
||||
assign zborder_wr = portfe_wr;
|
||||
assign border_wr = (portxt_wr && (hoa == XBORDER));
|
||||
assign zvpage_wr = p7ffd_wr;
|
||||
assign vpage_wr = (portxt_wr && (hoa == VPAGE ));
|
||||
assign vconf_wr = (portxt_wr && (hoa == VCONF ));
|
||||
assign gx_offsl_wr = (portxt_wr && (hoa == GXOFFSL));
|
||||
assign gx_offsh_wr = (portxt_wr && (hoa == GXOFFSH));
|
||||
assign gy_offsl_wr = (portxt_wr && (hoa == GYOFFSL));
|
||||
assign gy_offsh_wr = (portxt_wr && (hoa == GYOFFSH));
|
||||
assign t0x_offsl_wr = (portxt_wr && (hoa == T0XOFFSL));
|
||||
assign t0x_offsh_wr = (portxt_wr && (hoa == T0XOFFSH));
|
||||
assign t0y_offsl_wr = (portxt_wr && (hoa == T0YOFFSL));
|
||||
assign t0y_offsh_wr = (portxt_wr && (hoa == T0YOFFSH));
|
||||
assign t1x_offsl_wr = (portxt_wr && (hoa == T1XOFFSL));
|
||||
assign t1x_offsh_wr = (portxt_wr && (hoa == T1XOFFSH));
|
||||
assign t1y_offsl_wr = (portxt_wr && (hoa == T1YOFFSL));
|
||||
assign t1y_offsh_wr = (portxt_wr && (hoa == T1YOFFSH));
|
||||
assign tsconf_wr = (portxt_wr && (hoa == TSCONF));
|
||||
assign palsel_wr = (portxt_wr && (hoa == PALSEL));
|
||||
assign tmpage_wr = (portxt_wr && (hoa == TMPAGE));
|
||||
assign t0gpage_wr = (portxt_wr && (hoa == T0GPAGE));
|
||||
assign t1gpage_wr = (portxt_wr && (hoa == T1GPAGE));
|
||||
assign sgpage_wr = (portxt_wr && (hoa == SGPAGE));
|
||||
assign hint_beg_wr = (portxt_wr && (hoa == HSINT ));
|
||||
assign vint_begl_wr = (portxt_wr && (hoa == VSINTL));
|
||||
assign vint_begh_wr = (portxt_wr && (hoa == VSINTH));
|
||||
|
||||
assign beeper_wr = portfe_wr;
|
||||
wire portfe_wr = (loa==PORTFE) && iowr_s;
|
||||
assign covox_wr = (loa==COVOX) && iowr_s;
|
||||
wire portxt_wr = ((loa==PORTXT) && iowr_s) || regs_we;
|
||||
|
||||
reg [7:0] rampage[0:3];
|
||||
assign xt_page = {rampage[3], rampage[2], rampage[1], rampage[0]};
|
||||
|
||||
wire lock128 = lock128_3 ? 1'b0 : (lock128_2 ? m1_lock128 : memconf[6]);
|
||||
wire lock128_2 = memconf[7:6] == 2'b10; // mode 2
|
||||
wire lock128_3 = memconf[7:6] == 2'b11; // mode 3
|
||||
|
||||
reg m1_lock128;
|
||||
always @(posedge clk) if (opfetch) m1_lock128 <= !(din[7] ^ din[6]);
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (rst) begin
|
||||
fmaddr[4] <= 1'b0;
|
||||
intmask <= 8'b1;
|
||||
fddvirt <= 8'b0;
|
||||
sysconf <= 8'h00; // 3.5 MHz
|
||||
memconf <= 8'h04; // no map
|
||||
cacheconf <= 4'h0; // no cache
|
||||
|
||||
rampage[0]<= 8'h00;
|
||||
rampage[1]<= 8'h05;
|
||||
rampage[2]<= 8'h02;
|
||||
rampage[3]<= 8'h00;
|
||||
end
|
||||
else if (p7ffd_wr) begin
|
||||
memconf[0] <= din[4];
|
||||
rampage[3] <= {2'b0, lock128_3 ? {din[5], din[7:6]} : ({1'b0, lock128 ? 2'b0 : din[7:6]}), din[2:0]};
|
||||
end
|
||||
else if (portxt_wr) begin
|
||||
if (hoa[7:2] == RAMPAGE[7:2]) rampage[hoa[1:0]] <= din;
|
||||
|
||||
if (hoa == FMADDR) fmaddr <= din[4:0];
|
||||
|
||||
if (hoa == SYSCONF) begin
|
||||
sysconf <= din;
|
||||
cacheconf <= {4{din[2]}};
|
||||
end
|
||||
|
||||
if (hoa == DMAWPD) dmawpdev <= din[1:0];
|
||||
if (hoa == CACHECONF) cacheconf <= din[3:0];
|
||||
if (hoa == MEMCONF) memconf <= din;
|
||||
if (hoa == FDDVIRT) fddvirt <= din;
|
||||
if (hoa == INTMASK) intmask <= din;
|
||||
end
|
||||
end
|
||||
|
||||
// 7FFD port
|
||||
wire p7ffd_wr = !a[15] && (loa==PORTFD) && iowr_s && !lock48;
|
||||
|
||||
reg lock48;
|
||||
always @(posedge clk) begin
|
||||
if (rst) lock48 <= 1'b0;
|
||||
else if (p7ffd_wr && !lock128_3) lock48 <= din[5];
|
||||
end
|
||||
|
||||
// AY control
|
||||
wire ay_hit = (loa==PORTFD) & a[15];
|
||||
assign ay_bc1 = ay_hit & a[14] & iordwr;
|
||||
assign ay_bdir = ay_hit & iowr;
|
||||
|
||||
// VG93
|
||||
wire [3:0] fddvrt = fddvirt[3:0];
|
||||
wire virt_vg = fddvrt[drive_sel_raw];
|
||||
wire open_vg = fddvirt[7];
|
||||
assign drive_sel = {drive_sel_raw[1], drive_sel_raw[0]};
|
||||
|
||||
wire vg_wen = (dos || open_vg) && !vdos && !virt_vg;
|
||||
assign vg_cs_n = !(iordwr && vg_port && vg_wen);
|
||||
assign vg_wrFF = iowr_s && vgsys_port && vg_wen;
|
||||
wire vg_wrDS = iowr_s && vgsys_port && (dos || open_vg);
|
||||
|
||||
assign vdos_on = iordwr_s && (vg_port || vgsys_port) && dos && !vdos && virt_vg;
|
||||
assign vdos_off = iordwr_s && vg_port && vdos;
|
||||
|
||||
// write drive number
|
||||
reg [1:0] drive_sel_raw;
|
||||
always @(posedge clk) if (vg_wrDS) drive_sel_raw <= din[1:0];
|
||||
|
||||
// SD card (Z-controller compatible)
|
||||
wire sdcfg_wr;
|
||||
wire sddat_wr;
|
||||
wire sddat_rd;
|
||||
reg [1:0] spi_cs_n;
|
||||
|
||||
assign sdcfg_wr = ((loa==SDCFG) && iowr_s && (!dos || vdos));
|
||||
assign sddat_wr = ((loa==SDDAT) && iowr_s && (!dos || vdos));
|
||||
assign sddat_rd = ((loa==SDDAT) && iord_s);
|
||||
|
||||
// SDCFG write - sdcs_n control
|
||||
always @(posedge clk) begin
|
||||
if (rst) spi_cs_n <= 2'b11;
|
||||
else if (sdcfg_wr) spi_cs_n <= {~din[2], din[1]};
|
||||
end
|
||||
|
||||
// start signal for SPI module with resyncing to fclk
|
||||
assign sd_start = sddat_wr || sddat_rd;
|
||||
|
||||
// data for SPI module
|
||||
assign sd_datain = wr ? din : 8'hFF;
|
||||
|
||||
// xxF7
|
||||
wire portf7_wr = ((loa==PORTF7) && (a[8]==1'b1) && port_wr && (!dos || vdos));
|
||||
wire portf7_rd = ((loa==PORTF7) && (a[8]==1'b1) && port_rd && (!dos || vdos));
|
||||
|
||||
// EFF7 port
|
||||
reg [7:0] peff7;
|
||||
always @(posedge clk) begin
|
||||
if (rst) peff7 <= 8'h00;
|
||||
else if (!a[12] && portf7_wr && !dos) peff7 <= din; // #EEF7 in dos is not accessible
|
||||
end
|
||||
|
||||
// gluclock ports
|
||||
wire gluclock_on = peff7[7] || dos; // in dos mode EEF7 is not accessible, gluclock access is ON in dos mode.
|
||||
|
||||
// comports
|
||||
wire comport_wr = ((loa == COMPORT) && port_wr);
|
||||
wire comport_rd = ((loa == COMPORT) && port_rd);
|
||||
|
||||
// write to wait registers
|
||||
always @(posedge clk) begin
|
||||
// gluclocks
|
||||
if (gluclock_on && portf7_wr) begin
|
||||
if (!a[14]) wait_write <= din; // $BFF7 - data reg
|
||||
if (!a[13]) wait_addr <= din; // $DFF7 - addr reg
|
||||
end
|
||||
|
||||
// com ports
|
||||
if (comport_wr) wait_write <= din; // $xxEF
|
||||
if (comport_wr || comport_rd) wait_addr <= a[15:8];
|
||||
|
||||
if ((loa==PORTXT) && (hoa == DMAWPA)) wait_addr <= din;
|
||||
end
|
||||
|
||||
// wait from wait registers
|
||||
// ACHTUNG!!!! here portxx_wr are ON Z80 CLOCK! logic must change when moving to clk strobes
|
||||
assign wait_start_gluclock = (gluclock_on && !a[14] && (portf7_rd || portf7_wr)); // $BFF7 - gluclock r/w
|
||||
assign wait_start_comport = (comport_rd || comport_wr);
|
||||
|
||||
endmodule
|
@ -1,85 +0,0 @@
|
||||
|
||||
// Decoding and strobing of z80 signals
|
||||
|
||||
module zsignals
|
||||
(
|
||||
// clocks
|
||||
input wire clk,
|
||||
|
||||
// z80 interface input
|
||||
input wire iorq_n,
|
||||
input wire mreq_n,
|
||||
input wire m1_n,
|
||||
input wire rfsh_n,
|
||||
input wire rd_n,
|
||||
input wire wr_n,
|
||||
|
||||
// Z80 signals
|
||||
output wire m1,
|
||||
output wire rfsh,
|
||||
output wire rd,
|
||||
output wire wr,
|
||||
output wire iorq,
|
||||
output wire mreq,
|
||||
output wire rdwr,
|
||||
output wire iord,
|
||||
output wire iowr,
|
||||
output wire iorw,
|
||||
output wire memrd,
|
||||
output wire memwr,
|
||||
output wire memrw,
|
||||
output wire opfetch,
|
||||
output wire intack,
|
||||
|
||||
// Z80 signals strobes, at fclk
|
||||
output wire iorq_s,
|
||||
output wire mreq_s,
|
||||
output wire iord_s,
|
||||
output wire iowr_s,
|
||||
output wire iorw_s,
|
||||
output wire memrd_s,
|
||||
output wire memwr_s,
|
||||
output wire memrw_s,
|
||||
output wire opfetch_s
|
||||
);
|
||||
|
||||
// invertors
|
||||
assign m1 = !m1_n;
|
||||
assign rfsh = !rfsh_n;
|
||||
assign rd = !rd_n;
|
||||
assign wr = !wr_n;
|
||||
|
||||
// requests
|
||||
assign iorq = !iorq_n && m1_n; // this is masked by ~M1 to avoid port decoding on INT ack
|
||||
assign mreq = !mreq_n && rfsh_n; // this is masked by ~RFSH to ignore refresh cycles as memory requests
|
||||
|
||||
// combined
|
||||
assign rdwr = rd || wr;
|
||||
assign iord = iorq && rd;
|
||||
assign iowr = iorq && wr;
|
||||
assign iorw = iorq && rdwr;
|
||||
assign memrd = mreq && rd;
|
||||
assign memwr = mreq && !rd;
|
||||
assign memrw = mreq && rdwr;
|
||||
assign opfetch = memrd && m1;
|
||||
assign intack = !iorq_n && m1; // NOT masked by M1
|
||||
|
||||
// strobed
|
||||
assign iorq_s = iorq_r[0] && !iorq_r[1];
|
||||
assign mreq_s = mreq_r[0] && !mreq_r[1];
|
||||
assign iord_s = iorq_s && rd;
|
||||
assign iowr_s = iorq_s && wr;
|
||||
assign iorw_s = iorq_s && rdwr;
|
||||
assign memrd_s = mreq_s && rd;
|
||||
assign memwr_s = mreq_s && !rd;
|
||||
assign memrw_s = mreq_s && rdwr;
|
||||
assign opfetch_s = memrd_s && m1;
|
||||
|
||||
// latch inputs on FPGA clock
|
||||
reg [1:0] iorq_r, mreq_r;
|
||||
always @(posedge clk) begin
|
||||
iorq_r <= {iorq_r[0], iorq};
|
||||
mreq_r <= {mreq_r[0], mreq};
|
||||
end
|
||||
|
||||
endmodule
|
267
rtl/dram/arbiter.v
Normal file
267
rtl/dram/arbiter.v
Normal file
@ -0,0 +1,267 @@
|
||||
`include "tune.v"
|
||||
|
||||
// PentEvo project (c) NedoPC 2008-2011
|
||||
//
|
||||
// DRAM arbiter. Shares DRAM between CPU, video data fetcher and other devices
|
||||
//
|
||||
|
||||
// Arbitration is made on full 8-cycle access blocks. Each cycle is defined by dram.v and consists of 4 fpga clocks.
|
||||
// During each access block, there can be either no videodata access, 1 videodata access, 2, 4 or 8 accesses.
|
||||
// All spare cycles can be used by CPU or other devices. If no device uses memory in the given cycle, refresh cycle is performed.
|
||||
//
|
||||
// In each access block, videodata accesses are spreaded all over the block so that CPU receives cycle
|
||||
// as fast as possible, until there is absolute need to fetch remaining video data.
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// | access block | 4 video accesses during block, no processor accesses. video accesses are done
|
||||
// | vid | vid | vid | vid | ref | ref | ref | ref | as soon as possible, spare cycles are refresh ones
|
||||
//
|
||||
// | access block | 4 video accesses during block, processor requests access every other cycle
|
||||
// | vid | prc | vid | prc | vid | prc | vid | prc |
|
||||
//
|
||||
// | access block | 4 video accesses, processor begins requesting cycles continously from second one
|
||||
// | vid | prc | prc | prc | prc | vid | vid | vid | so it is given cycles while there is such possibility. after that processor
|
||||
// can't access mem until the end of access block and stalls
|
||||
//
|
||||
// | access block | 8 video accesses, processor stalls, if it is requesting cycles
|
||||
// | vid | vid | vid | vid | vid | vid | vid | vid |
|
||||
//
|
||||
// | access block | 2 video accesses, single processor request, other cycles are refresh ones
|
||||
// | vid | vid | ref | ref | cpu | ref | ref | ref |
|
||||
//
|
||||
// | access block | 4 video accesses, single processor request, other cycles are refresh ones
|
||||
// | vid | vid | cpu | vid | vid | ref | ref | ref |
|
||||
//
|
||||
// access block begins at any dram cycle, then blocks video_go back-to-back
|
||||
//
|
||||
// key signals are video_go and XXX_req, sampled at the end of each dram cycle. Must be set to the module at c3 clock cycle.
|
||||
|
||||
// CPU can have either normal or lower access priority to the DRAM.
|
||||
// At the INT active (32 of 3.5MHz clocks) the priority is raised to normal, so that CPU won't miss its interrupt.
|
||||
// This should be considered if dummy RAM access used for waiting for the end of DMA operation instead of status bit polling.
|
||||
//
|
||||
// DRAM access priority:
|
||||
// Z80 normal Z80 low
|
||||
// - VIDEO - VIDEO
|
||||
// - CPU - TS
|
||||
// - TM - TM
|
||||
// - TS - DMA
|
||||
// - DMA - CPU
|
||||
|
||||
module arbiter
|
||||
(
|
||||
input wire clk,
|
||||
input wire c1,
|
||||
input wire c2,
|
||||
input wire c3,
|
||||
input wire cyc,
|
||||
|
||||
// dram.v interface
|
||||
output wire [21:0] dram_addr, // address for dram access
|
||||
output wire dram_req, // dram request
|
||||
output wire dram_rnw, // Read-NotWrite
|
||||
output wire [ 1:0] dram_bsel, // byte select: bsel[1] for wrdata[15:8], bsel[0] for wrdata[7:0]
|
||||
output wire [15:0] dram_wrdata, // data to be written
|
||||
|
||||
// video
|
||||
input wire [20:0] video_addr, // during access block, only when video_strobe==1
|
||||
input wire video_go, // start video access blocks
|
||||
input wire [ 4:0] video_bw, // [4:3] - total cycles: 11 = 8 / 01 = 4 / 00 = 2
|
||||
// [2:0] - need cycles
|
||||
output wire video_pre_next, // (c1)
|
||||
output wire video_next, // (c2) at this signal video_addr may be changed; it is one clock leading the video_strobe
|
||||
output wire video_strobe, // (c3) one-cycle strobe meaning that video_data is available
|
||||
output wire next_vid, // used for TM prefetch
|
||||
|
||||
// CPU
|
||||
input wire [20:0] cpu_addr,
|
||||
input wire [ 7:0] cpu_wrdata,
|
||||
input wire cpu_req,
|
||||
input wire cpu_rnw,
|
||||
input wire cpu_wrbsel,
|
||||
input wire cpu_csrom,
|
||||
output reg cpu_next, // next cycle is allowed to be used by CPU
|
||||
output reg cpu_strobe,
|
||||
output reg cpu_latch,
|
||||
output wire curr_cpu_o,
|
||||
|
||||
// DMA
|
||||
input wire [20:0] dma_addr,
|
||||
input wire [15:0] dma_wrdata,
|
||||
input wire dma_req,
|
||||
input wire dma_rnw,
|
||||
output wire dma_next,
|
||||
|
||||
// TS
|
||||
input wire [20:0] ts_addr,
|
||||
input wire ts_req,
|
||||
output wire ts_pre_next,
|
||||
output wire ts_next,
|
||||
|
||||
// TM
|
||||
input wire [20:0] tm_addr,
|
||||
input wire tm_req,
|
||||
output wire tm_next,
|
||||
|
||||
// ROM loader
|
||||
input wire loader_clk,
|
||||
input wire [15:0] loader_addr,
|
||||
input wire [7:0] loader_data,
|
||||
input wire loader_wr
|
||||
);
|
||||
|
||||
localparam CYCLES = 6;
|
||||
|
||||
localparam CYC_CPU = 6'b000001;
|
||||
localparam CYC_VID = 6'b000010;
|
||||
localparam CYC_TS = 6'b000100;
|
||||
localparam CYC_TM = 6'b001000;
|
||||
localparam CYC_DMA = 6'b010000;
|
||||
localparam CYC_LOADER = 6'b100000;
|
||||
localparam CYC_FREE = 6'b000000;
|
||||
|
||||
localparam CPU = 0;
|
||||
localparam VIDEO = 1;
|
||||
localparam TS = 2;
|
||||
localparam TM = 3;
|
||||
localparam DMA = 4;
|
||||
localparam LOADER = 5;
|
||||
|
||||
reg [CYCLES-1:0] curr_cycle; // type of the cycle in progress
|
||||
reg [CYCLES-1:0] next_cycle; // type of the next cycle
|
||||
|
||||
reg [2:0] blk_rem = 0; // remaining accesses in a block (7..0)
|
||||
reg [2:0] vid_rem = 0; // remaining video accesses in block
|
||||
reg stall = 0;
|
||||
|
||||
wire dev_over_cpu = 0; // can be used to rise devices priority over CPU
|
||||
|
||||
wire next_cpu = next_cycle[CPU];
|
||||
assign next_vid = next_cycle[VIDEO];
|
||||
wire next_ts = next_cycle[TS];
|
||||
wire next_tm = next_cycle[TM];
|
||||
wire next_dma = next_cycle[DMA];
|
||||
wire next_loader = next_cycle[LOADER];
|
||||
|
||||
wire curr_cpu = curr_cycle[CPU];
|
||||
wire curr_vid = curr_cycle[VIDEO];
|
||||
wire curr_ts = curr_cycle[TS];
|
||||
wire curr_tm = curr_cycle[TM];
|
||||
wire curr_dma = curr_cycle[DMA];
|
||||
wire curr_loader = curr_cycle[LOADER];
|
||||
|
||||
assign curr_cpu_o = curr_cpu;
|
||||
|
||||
|
||||
// track blk_rem counter:
|
||||
// how many cycles left to the end of block (7..0)
|
||||
wire video_start = ~|blk_rem;
|
||||
wire [2:0] blk_nrem = (video_start && video_go) ? {video_bw[4:3], 1'b1} : (video_start ? 3'd0 : (blk_rem - 3'd1));
|
||||
wire bw_full = ~|{video_bw[4] & video_bw[2], video_bw[3] & video_bw[1], video_bw[0]}; // stall when 000/00/0
|
||||
wire video_only = stall || (vid_rem == blk_rem);
|
||||
wire video_idle = ~|vid_rem;
|
||||
|
||||
always @(posedge clk) if (c3)
|
||||
begin
|
||||
blk_rem <= blk_nrem;
|
||||
|
||||
if (video_start)
|
||||
stall <= bw_full & video_go;
|
||||
end
|
||||
|
||||
// track vid_rem counter
|
||||
// how many video cycles left to the end of block (7..0)
|
||||
wire [2:0] vidmax = {video_bw[2:0]}; // number of cycles for video access
|
||||
wire [2:0] vid_nrem_next = video_idle ? 3'd0 : (vid_rem - 3'd1);
|
||||
wire [2:0] vid_nrem_start = (cpu_req && !dev_over_cpu) ? vidmax : (vidmax - 3'd1);
|
||||
wire [2:0] vid_nrem = (video_go && video_start) ? vid_nrem_start : (next_vid ? vid_nrem_next : vid_rem);
|
||||
|
||||
always @(posedge clk) if (c3)
|
||||
vid_rem <= vid_nrem;
|
||||
|
||||
reg loader_wr0;
|
||||
reg [7:0] loader_data0;
|
||||
always @(posedge loader_clk) begin
|
||||
if (loader_wr) begin
|
||||
loader_wr0 <= 1'd1;
|
||||
loader_data0 <= loader_data;
|
||||
end
|
||||
else if (cyc) begin
|
||||
loader_wr0 <= 1'd0;
|
||||
end
|
||||
end
|
||||
|
||||
// next cycle decision
|
||||
wire [CYCLES-1:0] cyc_dev = tm_req ? CYC_TM : (ts_req ? CYC_TS : CYC_DMA);
|
||||
wire dev_req = ts_req || tm_req || dma_req;
|
||||
|
||||
always @*
|
||||
if (loader_wr0) begin
|
||||
cpu_next = 1'b0;
|
||||
next_cycle = CYC_LOADER;
|
||||
end
|
||||
else
|
||||
if (video_start) // video burst start
|
||||
if (video_go) // video active
|
||||
begin
|
||||
cpu_next = dev_over_cpu ? 1'b0 : !bw_full;
|
||||
next_cycle = dev_over_cpu ? CYC_VID : (bw_full ? CYC_VID : (cpu_req ? CYC_CPU : CYC_VID));
|
||||
end
|
||||
|
||||
else // video idle
|
||||
begin
|
||||
cpu_next = !dev_over_cpu;
|
||||
next_cycle = dev_over_cpu ? cyc_dev : (cpu_req ? CYC_CPU : (dev_req ? cyc_dev : CYC_FREE));
|
||||
end
|
||||
|
||||
else // video burst in progress
|
||||
begin
|
||||
cpu_next = dev_over_cpu ? 1'b0 : !video_only;
|
||||
next_cycle = video_only ? CYC_VID : (dev_over_cpu ? cyc_dev : (cpu_req ? CYC_CPU : (!video_idle ? CYC_VID : (dev_req ? cyc_dev : CYC_FREE))));
|
||||
end
|
||||
|
||||
always @(posedge clk) if (c3)
|
||||
curr_cycle <= next_cycle;
|
||||
|
||||
|
||||
// DRAM interface
|
||||
assign dram_wrdata = curr_loader? {2{loader_data0}} : curr_dma ? dma_wrdata : {2{cpu_wrdata[7:0]}}; // write data has to be clocked at c0 in dram.v
|
||||
assign dram_bsel[1:0] = next_loader? {loader_addr[0], ~loader_addr[0]} : next_dma ? 2'b11 : {cpu_wrbsel, ~cpu_wrbsel};
|
||||
assign dram_req = |next_cycle;
|
||||
assign dram_rnw = next_loader? 1'b0 : next_cpu ? cpu_rnw : (next_dma ? dma_rnw : 1'b1);
|
||||
assign dram_addr = {22{next_loader}} & { 1'b1, 6'b000000, loader_addr[15:1] }
|
||||
| {22{next_cpu}} & { cpu_csrom, {6{~cpu_csrom}} & cpu_addr[20:15], cpu_addr[14:0] }
|
||||
| {22{next_vid}} & { 1'b0, video_addr }
|
||||
| {22{next_ts}} & { 1'b0, ts_addr }
|
||||
| {22{next_tm}} & { 1'b0, tm_addr }
|
||||
| {22{next_dma}} & { 1'b0, dma_addr };
|
||||
|
||||
reg cpu_rnw_r;
|
||||
always @(posedge clk) if (c3)
|
||||
cpu_rnw_r <= cpu_rnw;
|
||||
|
||||
// read strobes generation for video and cpu
|
||||
always @(posedge clk)
|
||||
if (c1)
|
||||
begin
|
||||
cpu_strobe <= curr_cpu && cpu_rnw_r;
|
||||
cpu_latch <= curr_cpu && cpu_rnw_r;
|
||||
end
|
||||
else if (c2)
|
||||
cpu_strobe <= 1'b0;
|
||||
else if (c3)
|
||||
cpu_latch <= 1'b0;
|
||||
|
||||
assign video_pre_next = curr_vid & c1;
|
||||
assign video_next = curr_vid & c2;
|
||||
assign video_strobe = curr_vid && c3;
|
||||
|
||||
assign ts_pre_next = curr_ts & c1;
|
||||
assign ts_next = curr_ts & c2;
|
||||
|
||||
assign tm_next = curr_tm & c2;
|
||||
|
||||
assign dma_next = curr_dma & c2;
|
||||
|
||||
endmodule
|
@ -1,263 +0,0 @@
|
||||
|
||||
// PentEvo project (c) NedoPC 2008-2011
|
||||
//
|
||||
// DRAM arbiter. Shares DRAM between CPU, video data fetcher and other devices
|
||||
//
|
||||
|
||||
// Arbitration is made on full 8-cycle access blocks. Each cycle is defined by dram.v and consists of 4 fpga clocks.
|
||||
// During each access block, there can be either no videodata access, 1 videodata access, 2, 4 or 8 accesses.
|
||||
// All spare cycles can be used by CPU or other devices. If no device uses memory in the given cycle, refresh cycle is performed.
|
||||
//
|
||||
// In each access block, videodata accesses are spreaded all over the block so that CPU receives cycle
|
||||
// as fast as possible, until there is absolute need to fetch remaining video data.
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// | access block | 4 video accesses during block, no processor accesses. video accesses are done
|
||||
// | vid | vid | vid | vid | ref | ref | ref | ref | as soon as possible, spare cycles are refresh ones
|
||||
//
|
||||
// | access block | 4 video accesses during block, processor requests access every other cycle
|
||||
// | vid | prc | vid | prc | vid | prc | vid | prc |
|
||||
//
|
||||
// | access block | 4 video accesses, processor begins requesting cycles continously from second one
|
||||
// | vid | prc | prc | prc | prc | vid | vid | vid | so it is given cycles while there is such possibility. after that processor
|
||||
// can't access mem until the end of access block and stalls
|
||||
//
|
||||
// | access block | 8 video accesses, processor stalls, if it is requesting cycles
|
||||
// | vid | vid | vid | vid | vid | vid | vid | vid |
|
||||
//
|
||||
// | access block | 2 video accesses, single processor request, other cycles are refresh ones
|
||||
// | vid | vid | ref | ref | cpu | ref | ref | ref |
|
||||
//
|
||||
// | access block | 4 video accesses, single processor request, other cycles are refresh ones
|
||||
// | vid | vid | cpu | vid | vid | ref | ref | ref |
|
||||
//
|
||||
// access block begins at any dram cycle, then blocks go back-to-back
|
||||
//
|
||||
// key signals are go and XXX_req, sampled at the end of each dram cycle. Must be set to the module at c3 clock cycle.
|
||||
|
||||
// CPU can have either normal or lower access priority to the DRAM.
|
||||
// At the INT active (32 of 3.5MHz clocks) the priority is raised to normal, so that CPU won't miss its interrupt.
|
||||
// This should be considered if dummy RAM access used for waiting for the end of DMA operation instead of status bit polling.
|
||||
//
|
||||
// DRAM access priority:
|
||||
// Z80 normal Z80 low
|
||||
// - VIDEO - VIDEO
|
||||
// - CPU - TS
|
||||
// - TM - TM
|
||||
// - TS - DMA
|
||||
// - DMA - CPU
|
||||
|
||||
|
||||
module arbiter
|
||||
(
|
||||
|
||||
input clk,
|
||||
input c0,
|
||||
input c1,
|
||||
input c2,
|
||||
input c3,
|
||||
input cyc,
|
||||
|
||||
// dram.v interface
|
||||
output [21:0] dram_addr, // address for dram access
|
||||
output dram_req, // dram request
|
||||
output dram_rnw, // Read-NotWrite
|
||||
output [ 1:0] dram_bsel, // byte select: bsel[1] for wrdata[15:8], bsel[0] for wrdata[7:0]
|
||||
output [15:0] dram_wrdata, // data to be written
|
||||
|
||||
// video
|
||||
input [20:0] video_addr, // during access block, only when video_strobe==1
|
||||
input go, // start video access blocks
|
||||
input [ 4:0] video_bw, // [4:3] - total cycles: 11 = 8 / 01 = 4 / 00 = 2
|
||||
// [2:0] - need cycles
|
||||
output video_pre_next, // (c1)
|
||||
output video_next, // (c2) at this signal video_addr may be changed; it is one clock leading the video_strobe
|
||||
output video_strobe, // (c3) one-cycle strobe meaning that video_data is available
|
||||
output video_next_strobe, // (c3) one-cycle strobe meaning that video_data is available
|
||||
output next_vid, // used for TM prefetch
|
||||
|
||||
// CPU
|
||||
input [20:0] cpu_addr,
|
||||
input [ 7:0] cpu_wrdata,
|
||||
input cpu_req,
|
||||
input cpu_rnw,
|
||||
input cpu_csrom,
|
||||
input cpu_wrbsel,
|
||||
output reg cpu_next, // next cycle is allowed to be used by CPU
|
||||
output reg cpu_strobe, // c2 strobe
|
||||
output reg cpu_latch, // c2-c3 strobe
|
||||
output curr_cpu_o,
|
||||
|
||||
// DMA
|
||||
input [20:0] dma_addr,
|
||||
input [15:0] dma_wrdata,
|
||||
input dma_req,
|
||||
input dma_rnw,
|
||||
output dma_next,
|
||||
|
||||
// TS
|
||||
input [20:0] ts_addr,
|
||||
input ts_req,
|
||||
output ts_pre_next,
|
||||
output ts_next,
|
||||
|
||||
// TM
|
||||
input [20:0] tm_addr,
|
||||
input tm_req,
|
||||
output tm_next,
|
||||
|
||||
// ROM loader
|
||||
input loader_clk,
|
||||
input [15:0] loader_addr,
|
||||
input [7:0] loader_data,
|
||||
input loader_wr
|
||||
);
|
||||
|
||||
assign curr_cpu_o = curr_cpu;
|
||||
|
||||
localparam CYCLES = 6;
|
||||
|
||||
localparam CYC_CPU = 6'b000001;
|
||||
localparam CYC_VID = 6'b000010;
|
||||
localparam CYC_TS = 6'b000100;
|
||||
localparam CYC_TM = 6'b001000;
|
||||
localparam CYC_DMA = 6'b010000;
|
||||
localparam CYC_LOADER = 6'b100000;
|
||||
localparam CYC_FREE = 6'b000000;
|
||||
|
||||
localparam CPU = 0;
|
||||
localparam VIDEO = 1;
|
||||
localparam TS = 2;
|
||||
localparam TM = 3;
|
||||
localparam DMA = 4;
|
||||
localparam LOADER = 5;
|
||||
|
||||
reg [CYCLES-1:0] curr_cycle; // type of the cycle in progress
|
||||
reg [CYCLES-1:0] next_cycle; // type of the next cycle
|
||||
|
||||
wire next_cpu = next_cycle[CPU];
|
||||
assign next_vid = next_cycle[VIDEO];
|
||||
wire next_ts = next_cycle[TS];
|
||||
wire next_tm = next_cycle[TM];
|
||||
wire next_dma = next_cycle[DMA];
|
||||
wire next_loader = next_cycle[LOADER];
|
||||
|
||||
wire curr_cpu = curr_cycle[CPU];
|
||||
wire curr_vid = curr_cycle[VIDEO];
|
||||
wire curr_ts = curr_cycle[TS];
|
||||
wire curr_tm = curr_cycle[TM];
|
||||
wire curr_dma = curr_cycle[DMA];
|
||||
wire curr_loader = curr_cycle[LOADER];
|
||||
|
||||
|
||||
// track blk_rem counter:
|
||||
// how many cycles left to the end of block (7..0)
|
||||
wire [2:0] blk_nrem = (video_start && go) ? {video_bw[4:3], 1'b1} : (video_start ? 3'd0 : (blk_rem - 3'd1));
|
||||
wire bw_full = ~|{video_bw[4] & video_bw[2], video_bw[3] & video_bw[1], video_bw[0]}; // stall when 000/00/0
|
||||
wire video_start = ~|blk_rem;
|
||||
wire video_only = stall || (vid_rem == blk_rem);
|
||||
wire video_idle = ~|vid_rem;
|
||||
|
||||
reg [2:0] blk_rem; // remaining accesses in a block (7..0)
|
||||
reg stall;
|
||||
always @(posedge clk) begin
|
||||
if (c3) begin
|
||||
blk_rem <= blk_nrem;
|
||||
if (video_start) stall <= bw_full & go;
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
// track vid_rem counter
|
||||
// how many video cycles left to the end of block (7..0)
|
||||
wire [2:0] vid_nrem = (go && video_start) ? vid_nrem_start : (next_vid ? vid_nrem_next : vid_rem);
|
||||
wire [2:0] vid_nrem_start = (cpu_req && !dev_over_cpu) ? vidmax : (vidmax - 3'd1);
|
||||
wire [2:0] vid_nrem_next = video_idle ? 3'd0 : (vid_rem - 3'd1);
|
||||
wire [2:0] vidmax = {video_bw[2:0]}; // number of cycles for video access
|
||||
|
||||
reg [2:0] vid_rem; // remaining video accesses in block
|
||||
always @(posedge clk) if (c3) vid_rem <= vid_nrem;
|
||||
|
||||
|
||||
reg loader_wr0;
|
||||
reg [7:0] loader_data0;
|
||||
always @(posedge loader_clk) begin
|
||||
if (loader_wr) begin
|
||||
loader_wr0 <= 1'd1;
|
||||
loader_data0 <= loader_data;
|
||||
end
|
||||
else if (cyc) begin
|
||||
loader_wr0 <= 1'd0;
|
||||
end
|
||||
end
|
||||
|
||||
// next cycle decision
|
||||
wire [CYCLES-1:0] cyc_dev = tm_req ? CYC_TM : (ts_req ? CYC_TS : CYC_DMA);
|
||||
wire dev_req = ts_req || tm_req || dma_req;
|
||||
// wire dev_over_cpu = (((ts_req || tm_req) && ts_z80_lp) || (dma_req && dma_z80_lp)) && int_n; // CPU gets higher priority to acknowledge the INT
|
||||
wire dev_over_cpu = 0;
|
||||
|
||||
always @* begin
|
||||
if (loader_wr0) begin
|
||||
cpu_next = 1'b0;
|
||||
next_cycle = CYC_LOADER;
|
||||
end
|
||||
else if (video_start) begin // video burst start
|
||||
if (go) begin // video active line - 38us-ON, 26us-ON
|
||||
cpu_next = dev_over_cpu ? 1'b0 : !bw_full;
|
||||
next_cycle = dev_over_cpu ? CYC_VID : (bw_full ? CYC_VID : (cpu_req ? CYC_CPU : CYC_VID));
|
||||
end
|
||||
else begin // video idle
|
||||
cpu_next = !dev_over_cpu;
|
||||
next_cycle = dev_over_cpu ? cyc_dev : (cpu_req ? CYC_CPU : (dev_req ? cyc_dev : CYC_FREE));
|
||||
end
|
||||
end
|
||||
else begin // video burst in progress
|
||||
cpu_next = dev_over_cpu ? 1'b0 : !video_only;
|
||||
next_cycle = video_only ? CYC_VID : (dev_over_cpu ? cyc_dev : (cpu_req ? CYC_CPU : (!video_idle ? CYC_VID : (dev_req ? cyc_dev : CYC_FREE))));
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge clk) if (c3) curr_cycle <= next_cycle;
|
||||
|
||||
// DRAM interface
|
||||
assign dram_wrdata= curr_loader? {loader_data0,loader_data0} : curr_dma ? dma_wrdata : {cpu_wrdata,cpu_wrdata}; // write data has to be clocked at c0 in dram.v
|
||||
assign dram_bsel = next_loader? {loader_addr[0], ~loader_addr[0]} : next_dma ? 2'b11 : {cpu_wrbsel, ~cpu_wrbsel};
|
||||
assign dram_req = |next_cycle;
|
||||
assign dram_rnw = next_loader? 1'b0 : next_cpu ? cpu_rnw : ~next_dma | dma_rnw;
|
||||
assign dram_addr = {22{next_loader}} & { 1'b1, 6'b000000, loader_addr[15:1] }
|
||||
| {22{next_cpu}} & { cpu_csrom, {6{~cpu_csrom}} & cpu_addr[20:15], cpu_addr[14:0] }
|
||||
| {22{next_vid}} & { 1'b0, video_addr }
|
||||
| {22{next_ts }} & { 1'b0, ts_addr }
|
||||
| {22{next_tm }} & { 1'b0, tm_addr }
|
||||
| {22{next_dma}} & { 1'b0, dma_addr };
|
||||
|
||||
reg cpu_rnw_r;
|
||||
always @(posedge clk) if (c3) cpu_rnw_r <= cpu_rnw;
|
||||
|
||||
|
||||
// generation of read strobes: for video and cpu
|
||||
always @(posedge clk) begin
|
||||
if (c1) begin
|
||||
cpu_strobe <= curr_cpu && cpu_rnw_r;
|
||||
cpu_latch <= curr_cpu && cpu_rnw_r;
|
||||
end
|
||||
else if (c2) cpu_strobe <= 1'b0;
|
||||
else if (c3) cpu_latch <= 1'b0;
|
||||
end
|
||||
|
||||
assign video_pre_next = curr_vid & c1;
|
||||
assign video_next = curr_vid & c2;
|
||||
assign video_strobe = curr_vid && c3;
|
||||
assign video_next_strobe = next_vid && c3;
|
||||
|
||||
assign ts_pre_next = curr_ts & c1;
|
||||
assign ts_next = curr_ts & c2;
|
||||
|
||||
assign tm_next = curr_tm & c2;
|
||||
|
||||
assign dma_next = curr_dma & c2;
|
||||
|
||||
|
||||
endmodule
|
BIN
rtl/periph/CMOS.bin
Normal file
BIN
rtl/periph/CMOS.bin
Normal file
Binary file not shown.
21
rtl/periph/CMOS.mif
Normal file
21
rtl/periph/CMOS.mif
Normal file
@ -0,0 +1,21 @@
|
||||
-- http://srecord.sourceforge.net/
|
||||
--
|
||||
-- Generated automatically by srec_cat -o --mif
|
||||
--
|
||||
DEPTH = 256;
|
||||
WIDTH = 8;
|
||||
ADDRESS_RADIX = HEX;
|
||||
DATA_RADIX = HEX;
|
||||
CONTENT BEGIN
|
||||
0000: 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 AA 00 00 00 00 00 00;
|
||||
0018: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00;
|
||||
0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00;
|
||||
0048: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00;
|
||||
0060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00;
|
||||
0078: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00;
|
||||
0090: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00;
|
||||
00A8: 00 00 00 00 00 00 00 00 00 00 00 01 03 00 00 02 01 00 00 00 02 00 00 00;
|
||||
00C0: 00 00 00 00 00 00 00 00 42 08 84 10 C6 18 08 21 4A 29 8C 31 CE 39 21 04;
|
||||
00D8: 63 0C A5 14 E7 1C 29 25 6B 2D AD 35 EF 3D 78 7B 00 00 00 00 00 00 00 00;
|
||||
00F0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00;
|
||||
END;
|
@ -59,17 +59,17 @@ always @(*) begin
|
||||
8'h0c : Dout <= c_reg;
|
||||
8'h0d : Dout <= 8'b10000000;
|
||||
|
||||
8'hb1 : Dout <= CMOSCfg[7:6]; // CPU Speed
|
||||
8'hb2 : Dout <= 0; // Boot device
|
||||
8'hb3 : Dout <= CMOSCfg[8]; // CPU Cache
|
||||
8'hb4 : Dout <= CMOSCfg[13:11]; // F11
|
||||
8'hb5 : Dout <= CMOSCfg[15:14]; // F11 bank
|
||||
8'hb6 : Dout <= CMOSCfg[18:16]; // Shift+F11
|
||||
8'hb7 : Dout <= CMOSCfg[20:19]; // Shift+F11 bank
|
||||
8'hb8 : Dout <= CMOSCfg[10:9]; // #7FFD
|
||||
8'hb9 : Dout <= CMOSCfg[23:21]; // ZX Palette
|
||||
8'hba : Dout <= CMOSCfg[24]; // NGS Reset
|
||||
8'hbb : Dout <= CMOSCfg[27:25]; // INT offset
|
||||
// 8'hb1 : Dout <= CMOSCfg[7:6]; // CPU Speed
|
||||
// 8'hb2 : Dout <= 0; // Boot device
|
||||
// 8'hb3 : Dout <= CMOSCfg[8]; // CPU Cache
|
||||
// 8'hb4 : Dout <= CMOSCfg[13:11]; // F11
|
||||
// 8'hb5 : Dout <= CMOSCfg[15:14]; // F11 bank
|
||||
// 8'hb6 : Dout <= CMOSCfg[18:16]; // Shift+F11
|
||||
// 8'hb7 : Dout <= CMOSCfg[20:19]; // Shift+F11 bank
|
||||
// 8'hb8 : Dout <= CMOSCfg[10:9]; // #7FFD
|
||||
// 8'hb9 : Dout <= CMOSCfg[23:21]; // ZX Palette
|
||||
// 8'hba : Dout <= CMOSCfg[24]; // NGS Reset
|
||||
// 8'hbb : Dout <= CMOSCfg[27:25]; // INT offset
|
||||
|
||||
8'hf0 : Dout <= KEYSCANCODE;
|
||||
default: Dout <= CMOS_Dout;
|
||||
@ -233,7 +233,7 @@ always @(posedge CLK) begin
|
||||
end
|
||||
|
||||
// 50 Bytes of General Purpose RAM
|
||||
dpram #(.DATAWIDTH(8), .ADDRWIDTH(8), .MEM_INIT_FILE("rtl/rtc/CMOS.mif")) CMOS
|
||||
dpram #(.DATAWIDTH(8), .ADDRWIDTH(8), .MEM_INIT_FILE("rtl/periph/CMOS.mif")) CMOS
|
||||
(
|
||||
.clock (CLK),
|
||||
.address_a (A),
|
60
rtl/periph/vdac.v
Normal file
60
rtl/periph/vdac.v
Normal file
@ -0,0 +1,60 @@
|
||||
module vdac
|
||||
(
|
||||
input wire mode,
|
||||
|
||||
input wire [4:0] o_r, // input from FPGA
|
||||
input wire [4:0] o_g,
|
||||
input wire [4:0] o_b,
|
||||
|
||||
output wire [7:0] v_r, // output to VDAC
|
||||
output wire [7:0] v_g,
|
||||
output wire [7:0] v_b
|
||||
);
|
||||
|
||||
vdac_lut vdac_lut_r (.mode(mode), .in(o_r), .out(v_r));
|
||||
vdac_lut vdac_lut_g (.mode(mode), .in(o_g), .out(v_g));
|
||||
vdac_lut vdac_lut_b (.mode(mode), .in(o_b), .out(v_b));
|
||||
|
||||
endmodule
|
||||
|
||||
module vdac_lut
|
||||
(
|
||||
input wire mode,
|
||||
input wire [4:0] in,
|
||||
output wire [7:0] out
|
||||
);
|
||||
|
||||
reg [7:0] lut;
|
||||
assign out = mode ? {in, 3'b0} : lut;
|
||||
|
||||
always @*
|
||||
case (in)
|
||||
5'd0: lut = 8'd0;
|
||||
5'd1: lut = 8'd10;
|
||||
5'd2: lut = 8'd21;
|
||||
5'd3: lut = 8'd31;
|
||||
5'd4: lut = 8'd42;
|
||||
5'd5: lut = 8'd53;
|
||||
5'd6: lut = 8'd63;
|
||||
5'd7: lut = 8'd74;
|
||||
5'd8: lut = 8'd85;
|
||||
5'd9: lut = 8'd95;
|
||||
5'd10: lut = 8'd106;
|
||||
5'd11: lut = 8'd117;
|
||||
5'd12: lut = 8'd127;
|
||||
5'd13: lut = 8'd138;
|
||||
5'd14: lut = 8'd149;
|
||||
5'd15: lut = 8'd159;
|
||||
5'd16: lut = 8'd170;
|
||||
5'd17: lut = 8'd181;
|
||||
5'd18: lut = 8'd191;
|
||||
5'd19: lut = 8'd202;
|
||||
5'd20: lut = 8'd213;
|
||||
5'd21: lut = 8'd223;
|
||||
5'd22: lut = 8'd234;
|
||||
5'd23: lut = 8'd245;
|
||||
5'd24: lut = 8'd255;
|
||||
default: lut = 8'd255;
|
||||
endcase
|
||||
|
||||
endmodule
|
BIN
rtl/rtc/CMOS.bin
BIN
rtl/rtc/CMOS.bin
Binary file not shown.
@ -1,71 +0,0 @@
|
||||
-- Copyright (C) 2017 Intel Corporation. All rights reserved.
|
||||
-- Your use of Intel Corporation's design tools, logic functions
|
||||
-- and other software and tools, and its AMPP partner logic
|
||||
-- functions, and any output files from any of the foregoing
|
||||
-- (including device programming or simulation files), and any
|
||||
-- associated documentation or information are expressly subject
|
||||
-- to the terms and conditions of the Intel Program License
|
||||
-- Subscription Agreement, the Intel Quartus Prime License Agreement,
|
||||
-- the Intel MegaCore Function License Agreement, or other
|
||||
-- applicable license agreement, including, without limitation,
|
||||
-- that your use is for the sole purpose of programming logic
|
||||
-- devices manufactured by Intel and sold by Intel or its
|
||||
-- authorized distributors. Please refer to the applicable
|
||||
-- agreement for further details.
|
||||
|
||||
-- Quartus Prime generated Memory Initialization File (.mif)
|
||||
|
||||
WIDTH=8;
|
||||
DEPTH=256;
|
||||
|
||||
ADDRESS_RADIX=HEX;
|
||||
DATA_RADIX=HEX;
|
||||
|
||||
CONTENT BEGIN
|
||||
[000..010] : 00;
|
||||
011 : AA;
|
||||
[012..0B0] : 00;
|
||||
0B1 : 01;
|
||||
0B2 : 00;
|
||||
0B3 : 01;
|
||||
0B4 : 03;
|
||||
[0B5..0B7] : 00;
|
||||
0B8 : 01;
|
||||
[0B9..0BA] : 00;
|
||||
0BB : 02;
|
||||
[0BC..0CD] : FF;
|
||||
[0CE..0CF] : 00;
|
||||
0D0 : 42;
|
||||
0D1 : 08;
|
||||
0D2 : 84;
|
||||
0D3 : 10;
|
||||
0D4 : C6;
|
||||
0D5 : 18;
|
||||
0D6 : 08;
|
||||
0D7 : 21;
|
||||
0D8 : 4A;
|
||||
0D9 : 29;
|
||||
0DA : 8C;
|
||||
0DB : 31;
|
||||
0DC : CE;
|
||||
0DD : 39;
|
||||
0DE : 21;
|
||||
0DF : 04;
|
||||
0E0 : 63;
|
||||
0E1 : 0C;
|
||||
0E2 : A5;
|
||||
0E3 : 14;
|
||||
0E4 : E7;
|
||||
0E5 : 1C;
|
||||
0E6 : 29;
|
||||
0E7 : 25;
|
||||
0E8 : 6B;
|
||||
0E9 : 2D;
|
||||
0EA : AD;
|
||||
0EB : 35;
|
||||
0EC : EF;
|
||||
0ED : 3D;
|
||||
0EE : 6B;
|
||||
0EF : A2;
|
||||
[0F0..0FF] : 00;
|
||||
END;
|
88
rtl/spi.v
88
rtl/spi.v
@ -1,88 +0,0 @@
|
||||
// part of NeoGS project (c) 2007-2008 NedoPC
|
||||
//
|
||||
|
||||
// SPI mode 0 8-bit master module
|
||||
//
|
||||
// short diagram for speed=0 (Fclk/Fspi=2, no rdy shown)
|
||||
//
|
||||
// clk: ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ (positive edges)
|
||||
// counter: 00|00|00|10|11|12|13|14|15|16|17|18|19|1A|1B|1C|1D|1E|1F|00|00|00 // internal!
|
||||
// sck: ___________/``\__/``\__/``\__/``\__/``\__/``\__/``\__/``\_______
|
||||
// sdo: --------< do7 | do6 | do5 | do4 | do3 | do2 | do1 | do0 >-------
|
||||
// sdi: --------< di7 | di6 | di5 | di4 | di3 | di2 | di1 | di0 >-------
|
||||
// bsync: ________/`````\_________________________________________________
|
||||
// start: _____/``\_______________________________________________________
|
||||
// din: -----<IN>-------------------------------------------------------
|
||||
// dout: old old old old old old old old old old old old old | new new new
|
||||
//
|
||||
// data on sdo must be latched by slave on rising sck edge. data on sdo changes on falling edge of sck
|
||||
//
|
||||
// data from sdi is latched by master on positive edge of sck, while slave changes it on falling edge.
|
||||
// WARNING: slave must emit valid di7 bit BEFORE first pulse on sck!
|
||||
//
|
||||
// start is synchronous pulse, which starts all transfer and also latches din data on the same clk edge
|
||||
// as it is registered high. start can be given anytime (only when speed=0),
|
||||
// so it is functioning then as synchronous reset. when speed!=0, there is global enable for majority of
|
||||
// flipflops in the module, so start can't be accepted at any time
|
||||
//
|
||||
// dout updates with freshly received data at the clk edge in which sck goes high for the last time, thus
|
||||
// latching last bit on sdi.
|
||||
//
|
||||
// sdo emits last bit shifted out after the transfer end
|
||||
|
||||
module spi
|
||||
(
|
||||
// SPI wires
|
||||
input clk, // system clock
|
||||
output sck, // SCK
|
||||
output reg sdo, // MOSI
|
||||
input sdi, // MISO
|
||||
|
||||
// DMA interface
|
||||
input dma_req,
|
||||
input [7:0] dma_din,
|
||||
|
||||
// Z80 interface
|
||||
input cpu_req,
|
||||
input [7:0] cpu_din,
|
||||
|
||||
// output
|
||||
output start, // start strobe, 1 clock length
|
||||
output reg [7:0] dout
|
||||
);
|
||||
|
||||
assign sck = counter[0];
|
||||
assign start = req && rdy;
|
||||
|
||||
wire [7:0] din = dma_req ? dma_din : cpu_din;
|
||||
wire rdy = counter[4]; // 0 - transmission in progress
|
||||
wire req = cpu_req || dma_req;
|
||||
|
||||
reg [4:0] counter;
|
||||
always @(posedge clk) begin
|
||||
reg [7:0] shift;
|
||||
|
||||
if (start) begin
|
||||
counter <= 5'b0;
|
||||
sdo <= din[7];
|
||||
shift[7:1] <= din[6:0];
|
||||
end
|
||||
else if (!rdy) begin
|
||||
counter <= counter + 5'd1;
|
||||
|
||||
// shift in (rising edge of SCK)
|
||||
if (!sck) begin
|
||||
shift[0] <= sdi;
|
||||
|
||||
if (&counter[3:1]) dout <= {shift[7:1], sdi};
|
||||
end
|
||||
|
||||
// shift out (falling edge of sck)
|
||||
if (sck) begin
|
||||
sdo <= shift[7];
|
||||
shift[7:1] <= shift[6:0]; // last bit remains after end of exchange
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
BIN
rtl/tsconf.rom
BIN
rtl/tsconf.rom
Binary file not shown.
1971
rtl/tsconf.v
1971
rtl/tsconf.v
File diff suppressed because it is too large
Load Diff
28
rtl/tune.v
Normal file
28
rtl/tune.v
Normal file
@ -0,0 +1,28 @@
|
||||
`timescale 1ns/100ps
|
||||
|
||||
`ifdef MODEL_TECH
|
||||
`define SIMULATE
|
||||
`endif
|
||||
|
||||
//`define DRAMMEM_VERBOSE
|
||||
//`define FETCH_VERBOSE
|
||||
|
||||
// `define FREE_IORQ // for non-blocked by internal ports !IORQ
|
||||
|
||||
// `define IDE_HDD // for IDE HDD
|
||||
`define IDE_VDAC // for VideoDAC instead of IDE
|
||||
// `define IDE_VDAC2 // for VideoDAC2 instead of IDE
|
||||
|
||||
`define XTR_FEAT // extra features, in only IDEless version
|
||||
|
||||
// `define SD_CARD2 // for second SD Card
|
||||
|
||||
// `define AUTO_INT // auto-incremented Frame Interrpt
|
||||
|
||||
// `define FDR // FDD Ripper version (use with DISABLE_TSU)
|
||||
|
||||
// `define DISABLE_TSU // disable TSU
|
||||
|
||||
// `define PENT_312 // for Pentagon 71680 tacts emulation with 312 video lines
|
||||
|
||||
`define KEMPSTON_8BIT // 8-bit enhanced Kempston Joystick interface
|
@ -1,33 +1,35 @@
|
||||
// This module fetches video data from DRAM
|
||||
|
||||
`include "tune.v"
|
||||
|
||||
module video_fetch
|
||||
(
|
||||
// clocks
|
||||
input wire clk,
|
||||
// clocks
|
||||
input wire clk,
|
||||
|
||||
// control
|
||||
input wire [3:0] f_sel,
|
||||
input wire [1:0] b_sel,
|
||||
input wire fetch_stb,
|
||||
// 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,
|
||||
// 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
|
||||
// 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 (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;
|
||||
always @(posedge clk) if (fetch_stb)
|
||||
fetch_data <= fetch_temp;
|
||||
|
||||
endmodule
|
||||
|
@ -1,235 +1,230 @@
|
||||
|
||||
// This module decodes video modes
|
||||
|
||||
`include "tune.v"
|
||||
|
||||
module video_mode
|
||||
(
|
||||
// clocks
|
||||
input wire clk, f1, c3,
|
||||
// clocks
|
||||
input wire clk, f1, c3,
|
||||
|
||||
// video config
|
||||
input wire [7:0] vpage,
|
||||
input wire [7:0] vconf,
|
||||
input wire ts_rres_ext,
|
||||
// video config
|
||||
input wire [7:0] vpage,
|
||||
input wire [7:0] vconf,
|
||||
input wire ts_rres_ext,
|
||||
input wire v60hz,
|
||||
|
||||
// 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 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 data
|
||||
input wire [15:0] txt_char,
|
||||
|
||||
// video counters
|
||||
input wire [7:0] cnt_col,
|
||||
input wire [8:0] cnt_row,
|
||||
input wire cptr,
|
||||
// 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
|
||||
// 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];
|
||||
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;
|
||||
// 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
|
||||
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;
|
||||
// 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 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];
|
||||
|
||||
// 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];
|
||||
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
|
||||
|
||||
// fetch selectors
|
||||
// Attention: counter is already incremented at the time of video data fetching!
|
||||
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
|
||||
|
||||
// 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};
|
||||
// X offset
|
||||
assign x_offs_mode = {vmod == M_XC ? {gx_offs[8:1], 1'b0} : {1'b0, gx_offs[8:1]}, gx_offs[0]};
|
||||
|
||||
// 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];
|
||||
// DRAM bandwidth usage
|
||||
localparam BW2 = 2'b00;
|
||||
localparam BW4 = 2'b01;
|
||||
localparam BW8 = 2'b11;
|
||||
|
||||
assign fetch_bsl = (vmod == M_TX) ? f_txt_bsl[cnt_col[1:0]] : 2'b10;
|
||||
localparam BU1 = 3'b001;
|
||||
localparam BU2 = 3'b010;
|
||||
localparam BU4 = 3'b100;
|
||||
|
||||
// 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];
|
||||
// [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];
|
||||
|
||||
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
|
||||
// pixelrate
|
||||
wire [3:0] pixrate = 4'b1000; // change these if you change the modes indexes!
|
||||
assign tv_hires = pixrate[vmod];
|
||||
|
||||
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
|
||||
// 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];
|
||||
|
||||
// X offset
|
||||
assign x_offs_mode = {vmod == M_XC ? {gx_offs[8:1], 1'b0} : {1'b0, gx_offs[8:1]}, gx_offs[0]};
|
||||
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
|
||||
|
||||
// DRAM bandwidth usage
|
||||
localparam BW2 = 2'b00;
|
||||
localparam BW4 = 2'b01;
|
||||
localparam BW8 = 2'b11;
|
||||
`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)
|
||||
|
||||
localparam BU1 = 3'b001;
|
||||
localparam BU2 = 3'b010;
|
||||
localparam BU4 = 3'b100;
|
||||
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)
|
||||
|
||||
// [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];
|
||||
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
|
||||
|
||||
// pixelrate
|
||||
wire [3:0] pixrate = 4'b1000; // change these if you change the modes indexes!
|
||||
assign tv_hires = pixrate[vmod];
|
||||
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];
|
||||
|
||||
// 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];
|
||||
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};
|
||||
|
||||
// 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];
|
||||
// 16c
|
||||
wire [20:0] addr_16c = {vpage[7:3], cnt_row, cnt_col[6:0]};
|
||||
|
||||
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)
|
||||
// 256c
|
||||
wire [20:0] addr_256c = {vpage[7:4], cnt_row, cnt_col[7: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];
|
||||
|
||||
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];
|
||||
|
||||
// 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]
|
||||
// Textmode
|
||||
wire [13:0] addr_tx[0:3];
|
||||
wire [20:0] addr_text = {vpage[7:1], addr_tx[cnt_col[1:0]]};
|
||||
assign addr_tx[0] = {vpage[0], cnt_row[8:3], 1'b0, cnt_col[7:2]}; // char codes, data[15:0]
|
||||
assign addr_tx[1] = {vpage[0], cnt_row[8:3], 1'b1, cnt_col[7:2]}; // char attributes, data[31:16]
|
||||
assign addr_tx[2] = {~vpage[0], 3'b000, (txt_char[7:0]), cnt_row[2:1]}; // char0 graphics, data[7:0]
|
||||
assign addr_tx[3] = {~vpage[0], 3'b000, (txt_char[15:8]), cnt_row[2:1]}; // char1 graphics, data[15:8]
|
||||
|
||||
// videomode addresses
|
||||
wire [20:0] v_addr[0:3];
|
||||
assign v_addr[M_ZX] = addr_zx;
|
||||
assign v_addr[M_HC] = addr_16c;
|
||||
assign v_addr[M_XC] = addr_256c;
|
||||
assign v_addr[M_TX] = addr_text;
|
||||
assign video_addr = v_addr[vmod];
|
||||
|
||||
endmodule
|
||||
|
@ -2,59 +2,181 @@
|
||||
// This module generates video for DAC
|
||||
// (c)2015 TSL
|
||||
|
||||
`include "tune.v"
|
||||
|
||||
module video_out
|
||||
(
|
||||
// clocks
|
||||
input wire clk, c3,
|
||||
// clocks
|
||||
input wire clk, c3,
|
||||
|
||||
// video controls
|
||||
input wire tv_blank,
|
||||
input wire [1:0] plex_sel_in,
|
||||
// video controls
|
||||
input wire vga_on,
|
||||
input wire tv_blank,
|
||||
input wire vga_blank,
|
||||
input wire vga_line,
|
||||
input wire [1:0] plex_sel_in,
|
||||
|
||||
// mode controls
|
||||
input wire tv_hires,
|
||||
input wire [3:0] palsel,
|
||||
// mode controls
|
||||
input wire tv_hires,
|
||||
input wire vga_hires,
|
||||
input wire [3:0] palsel,
|
||||
|
||||
// Z80 pins
|
||||
input wire [15:0] cram_data_in,
|
||||
input wire [7:0] cram_addr_in,
|
||||
input wire cram_we,
|
||||
// Z80 pins
|
||||
input wire [15:0] cram_data_in,
|
||||
input wire [7:0] cram_addr_in,
|
||||
input wire cram_we,
|
||||
|
||||
// video data
|
||||
input wire [7:0] vplex_in,
|
||||
output wire [7:0] vred,
|
||||
output wire [7:0] vgrn,
|
||||
output wire [7:0] vblu,
|
||||
output wire vdac_mode
|
||||
// video data
|
||||
input wire [7:0] vplex_in,
|
||||
input wire [7:0] vgaplex,
|
||||
output wire [1:0] vred,
|
||||
output wire [1:0] vgrn,
|
||||
output wire [1:0] vblu,
|
||||
output wire [4:0] vred_raw,
|
||||
output wire [4:0] vgrn_raw,
|
||||
output wire [4:0] vblu_raw,
|
||||
output wire vdac_mode
|
||||
);
|
||||
|
||||
wire [14:0] vpix;
|
||||
wire [15:0] vpixel;
|
||||
wire [1:0] phase;
|
||||
wire [7:0] pwm[0:7];
|
||||
|
||||
reg [7:0] vplex;
|
||||
always @(posedge clk) if (c3) vplex <= vplex_in;
|
||||
reg blank1; // GOVNOKOD!!!!!!!!!!!!!!!!!!!!!
|
||||
|
||||
wire [7:0] vdata = tv_hires ? {palsel, plex_sel_in[1] ? vplex[3:0] : vplex[7:4]} : vplex;
|
||||
assign vred_raw = vpix[14:10];
|
||||
assign vgrn_raw = vpix[9:5];
|
||||
assign vblu_raw = vpix[4:0];
|
||||
assign vdac_mode = vpixel[15];
|
||||
|
||||
// TV/VGA mux
|
||||
reg [7:0] vplex;
|
||||
always @(posedge clk) if (c3)
|
||||
vplex <= vplex_in;
|
||||
|
||||
wire [7:0] plex = vga_on ? vgaplex : vplex;
|
||||
wire hires = vga_on ? vga_hires : tv_hires;
|
||||
wire plex_sel = vga_on ? plex_sel_in[0] : plex_sel_in[1];
|
||||
wire [7:0] vdata = hires ? {palsel, plex_sel ? plex[3:0] : plex[7:4]} : plex;
|
||||
wire blank = vga_on ? vga_blank : tv_blank;
|
||||
|
||||
assign vpix = blank1 ? 15'b0 : vpixel[14:0];
|
||||
// assign vpix = blank1 ? 15'b0 : (vpixel[14:0] & 15'b111001110011100); // test for 373 colors
|
||||
// assign vpix = blank1 ? 15'b0 : (vpixel[14:0] & 15'b110001100011000); // test for 64 colors
|
||||
|
||||
// GOVNOKOD!!!!!!!!!!!!!!!!!!!!!
|
||||
always @(posedge clk)
|
||||
begin
|
||||
blank1 <= blank;
|
||||
end
|
||||
|
||||
// color components extraction
|
||||
wire [1:0] cred = vpix[14:13];
|
||||
wire [2:0] ired = vpix[12:10];
|
||||
wire [1:0] cgrn = vpix[ 9: 8];
|
||||
wire [2:0] igrn = vpix[ 7: 5];
|
||||
wire [1:0] cblu = vpix[ 4: 3];
|
||||
wire [2:0] iblu = vpix[ 2: 0];
|
||||
|
||||
// prepare and clocking two phases of output
|
||||
reg [1:0] red0;
|
||||
reg [1:0] grn0;
|
||||
reg [1:0] blu0;
|
||||
reg [1:0] red1;
|
||||
reg [1:0] grn1;
|
||||
reg [1:0] blu1;
|
||||
|
||||
always @(posedge clk)
|
||||
begin
|
||||
red0 <= (!pwm[ired][{phase, 1'b0}] | &cred) ? cred : (cred + 2'b1);
|
||||
grn0 <= (!pwm[igrn][{phase, 1'b0}] | &cgrn) ? cgrn : (cgrn + 2'b1);
|
||||
blu0 <= (!pwm[iblu][{phase, 1'b0}] | &cblu) ? cblu : (cblu + 2'b1);
|
||||
red1 <= (!pwm[ired][{phase, 1'b1}] | &cred) ? cred : (cred + 2'b1);
|
||||
grn1 <= (!pwm[igrn][{phase, 1'b1}] | &cgrn) ? cgrn : (cgrn + 2'b1);
|
||||
blu1 <= (!pwm[iblu][{phase, 1'b1}] | &cblu) ? cblu : (cblu + 2'b1);
|
||||
end
|
||||
|
||||
`ifdef IDE_VDAC
|
||||
// no PWM
|
||||
assign vred = cred;
|
||||
assign vgrn = cgrn;
|
||||
assign vblu = cblu;
|
||||
`elsif IDE_VDAC2
|
||||
// no PWM
|
||||
assign vred = cred;
|
||||
assign vgrn = cgrn;
|
||||
assign vblu = cblu;
|
||||
`else
|
||||
// output muxing for 56MHz PWM resolution
|
||||
assign vred = clk ? red1 : red0;
|
||||
assign vgrn = clk ? grn1 : grn0;
|
||||
assign vblu = clk ? blu1 : blu0;
|
||||
`endif
|
||||
|
||||
// PWM phase
|
||||
reg [1:0] ph;
|
||||
always @(posedge clk)
|
||||
ph <= ph + 2'b1;
|
||||
|
||||
assign phase = {vga_on ? vga_line : ph[1], ph[0]};
|
||||
|
||||
// PWM
|
||||
assign pwm[0] = 8'b00000000;
|
||||
assign pwm[1] = 8'b00000001;
|
||||
assign pwm[2] = 8'b01000001;
|
||||
assign pwm[3] = 8'b01000101;
|
||||
assign pwm[4] = 8'b10100101;
|
||||
assign pwm[5] = 8'b10100111;
|
||||
assign pwm[6] = 8'b11010111;
|
||||
assign pwm[7] = 8'b11011111;
|
||||
|
||||
// CRAM
|
||||
wire [15:0] vpixel;
|
||||
dpram #(.DATAWIDTH(16), .ADDRWIDTH(8), .MEM_INIT_FILE("rtl/video/video_cram.mif")) video_cram
|
||||
(
|
||||
.clock (clk),
|
||||
.address_a(cram_addr_in),
|
||||
.data_a (cram_data_in),
|
||||
.wren_a (cram_we),
|
||||
.address_b(vdata),
|
||||
.q_b (vpixel)
|
||||
);
|
||||
|
||||
reg blank;
|
||||
always @(posedge clk) blank <= tv_blank;
|
||||
|
||||
wire [14:0] vpix = blank ? 15'b0 : vpixel[14:0];
|
||||
|
||||
assign vred = {vpix[14:10], vpix[14:12]};
|
||||
assign vgrn = {vpix[ 9: 5], vpix[ 9: 7]};
|
||||
assign vblu = {vpix[ 4: 0], vpix[ 4: 2]};
|
||||
assign vdac_mode = vpixel[15];
|
||||
dpram #(.DATAWIDTH(16), .ADDRWIDTH(8), .MEM_INIT_FILE("rtl/video/video_cram.mif")) video_cram
|
||||
(
|
||||
.clock (clk),
|
||||
.address_a(cram_addr_in),
|
||||
.data_a (cram_data_in),
|
||||
.wren_a (cram_we),
|
||||
.address_b(vdata),
|
||||
.q_b (vpixel)
|
||||
);
|
||||
/*
|
||||
altdpram video_cram
|
||||
(
|
||||
.inclock (clk),
|
||||
.data (cram_data_in),
|
||||
.rdaddress (vdata),
|
||||
.wraddress (cram_addr_in),
|
||||
.wren (cram_we),
|
||||
.q (vpixel),
|
||||
.aclr (1'b0),
|
||||
.byteena (1'b1),
|
||||
.inclocken (1'b1),
|
||||
.outclock (1'b1),
|
||||
.outclocken (1'b1),
|
||||
.rdaddressstall (1'b0),
|
||||
.rden (1'b1),
|
||||
.wraddressstall (1'b0)
|
||||
);
|
||||
|
||||
defparam
|
||||
video_cram.indata_aclr = "OFF",
|
||||
video_cram.indata_reg = "INCLOCK",
|
||||
video_cram.intended_device_family = "ACEX1K",
|
||||
video_cram.lpm_file = "../video/mem/video_cram.mif",
|
||||
video_cram.lpm_type = "altdpram",
|
||||
video_cram.outdata_aclr = "OFF",
|
||||
video_cram.outdata_reg = "UNREGISTERED",
|
||||
video_cram.rdaddress_aclr = "OFF",
|
||||
video_cram.rdaddress_reg = "INCLOCK",
|
||||
video_cram.rdcontrol_aclr = "OFF",
|
||||
video_cram.rdcontrol_reg = "UNREGISTERED",
|
||||
video_cram.width = 16,
|
||||
video_cram.widthad = 8,
|
||||
video_cram.wraddress_aclr = "OFF",
|
||||
video_cram.wraddress_reg = "INCLOCK",
|
||||
video_cram.wrcontrol_aclr = "OFF",
|
||||
video_cram.wrcontrol_reg = "INCLOCK";
|
||||
*/
|
||||
endmodule
|
||||
|
@ -1,149 +1,166 @@
|
||||
// This module latches all port parameters for video from Z80
|
||||
|
||||
`include "tune.v"
|
||||
|
||||
module video_ports
|
||||
(
|
||||
// clocks
|
||||
input wire clk,
|
||||
// clocks
|
||||
input wire clk,
|
||||
|
||||
input wire [ 7:0] d,
|
||||
input wire res,
|
||||
input wire int_start,
|
||||
input wire line_start_s,
|
||||
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,
|
||||
// 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
|
||||
// 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;
|
||||
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;
|
||||
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
|
||||
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
|
||||
|
||||
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 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;
|
||||
|
||||
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;
|
||||
else if (vint_begh_wr)
|
||||
begin
|
||||
vint_beg[8] <= d[0];
|
||||
vint_inc <= d[7:4];
|
||||
end
|
||||
|
||||
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
|
||||
else if (int_start)
|
||||
vint_beg <= vint_beg_next;
|
||||
|
||||
// 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
|
||||
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
|
||||
|
||||
endmodule
|
||||
else
|
||||
begin
|
||||
if (zborder_wr ) border <= {palsel[3:0], 1'b0, d[2:0]};
|
||||
if (border_wr ) border <= d;
|
||||
if (gy_offsl_wr ) gy_offs[7:0] <= d;
|
||||
if (gy_offsh_wr ) gy_offs[8] <= d[0];
|
||||
if (t0y_offsl_wr) t0y_offs[7:0] <= d;
|
||||
if (t0y_offsh_wr) t0y_offs[8] <= d[0];
|
||||
if (t1y_offsl_wr) t1y_offs[7:0] <= d;
|
||||
if (t1y_offsh_wr) t1y_offs[8] <= d[0];
|
||||
if (tsconf_wr ) tsconf <= d;
|
||||
if (tmpage_wr ) tmpage <= d;
|
||||
if (sgpage_wr ) sgpage <= d;
|
||||
if (hint_beg_wr ) hint_beg <= d;
|
||||
|
||||
if (zvpage_wr ) vpage_r <= {6'b000001, d[3], 1'b1};
|
||||
if (vpage_wr ) vpage_r <= d;
|
||||
if (vconf_wr ) vconf_r <= d;
|
||||
if (gx_offsl_wr ) gx_offs_r[7:0] <= d;
|
||||
if (gx_offsh_wr ) gx_offs_r[8] <= d[0];
|
||||
if (palsel_wr ) palsel_r <= d;
|
||||
if (t0x_offsl_wr) t0x_offs_r[7:0] <= d;
|
||||
if (t0x_offsh_wr) t0x_offs_r[8] <= d[0];
|
||||
if (t1x_offsl_wr) t1x_offs_r[7:0] <= d;
|
||||
if (t1x_offsh_wr) t1x_offs_r[8] <= d[0];
|
||||
if (t0gpage_wr ) t0gpage_r <= d;
|
||||
if (t1gpage_wr ) t1gpage_r <= d;
|
||||
end
|
||||
|
||||
// latching regs at line start, delaying hires for 1 line
|
||||
always @(posedge clk or posedge res)
|
||||
if (res)
|
||||
begin
|
||||
vpage <= 8'h05;
|
||||
`ifdef FORCE_TEXT_MODE
|
||||
vconf <= 8'h83;
|
||||
`else
|
||||
vconf <= 8'h00;
|
||||
`endif
|
||||
gx_offs <= 9'b0;
|
||||
palsel <= 8'h0F;
|
||||
end
|
||||
|
||||
else if (zvpage_wr)
|
||||
vpage <= {6'b000001, d[3], 1'b1};
|
||||
|
||||
else if (line_start_s)
|
||||
begin
|
||||
vpage <= vpage_r;
|
||||
`ifndef FORCE_TEXT_MODE
|
||||
vconf <= vconf_r;
|
||||
`endif
|
||||
gx_offs <= gx_offs_r;
|
||||
palsel <= palsel_r;
|
||||
t0x_offs <= t0x_offs_r;
|
||||
t1x_offs <= t1x_offs_r;
|
||||
t0gpage <= t0gpage_r;
|
||||
t1gpage <= t1gpage_r;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
@ -1,84 +1,87 @@
|
||||
// This module renders video data for output
|
||||
|
||||
`include "tune.v"
|
||||
|
||||
module video_render
|
||||
(
|
||||
// clocks
|
||||
input wire clk, c1,
|
||||
// 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,
|
||||
// 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,
|
||||
// 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
|
||||
// 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;
|
||||
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]};
|
||||
reg [3:0] temp;
|
||||
|
||||
// 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]};
|
||||
// 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]};
|
||||
|
||||
// 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]]};
|
||||
// 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]};
|
||||
|
||||
// 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]];
|
||||
// 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]]};
|
||||
|
||||
// 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
|
||||
// 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]];
|
||||
|
||||
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;
|
||||
// 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
|
||||
|
||||
// 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
|
||||
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;
|
||||
|
||||
reg [3:0] temp;
|
||||
always @(posedge clk) if (c1) temp <= video[3:0];
|
||||
// video plex muxer
|
||||
wire tsu_visible = (|tsdata_in[3:0] && !notsu);
|
||||
wire gfx_visible = (pixv[render_mode] && !nogfx);
|
||||
wire [7:0] video1 = tsu_visible ? tsdata_in : (nogfx ? border_in : pix[render_mode]);
|
||||
wire [7:0] video2 = gfx_visible ? pix[render_mode] : (tsu_visible ? tsdata_in : border_in);
|
||||
wire [7:0] video = hvpix ? (gfxovr ? video2 : video1) : ((hvtspix && tsu_visible) ? tsdata_in : border_in);
|
||||
assign vplex_out = hires ? {temp, video[3:0]} : video; // in hi-res plex contains two pixels 4 bits each
|
||||
|
||||
always @(posedge clk) if (c1)
|
||||
temp <= video[3:0];
|
||||
|
||||
endmodule
|
||||
|
||||
|
@ -1,169 +1,243 @@
|
||||
`include "tune.v"
|
||||
|
||||
// This module generates all video raster signals
|
||||
|
||||
// This module generates video raster signals
|
||||
|
||||
module video_sync
|
||||
(
|
||||
// clocks
|
||||
input wire clk, f1, c0, c1, c3, pix_stb,
|
||||
// clocks
|
||||
input wire clk, f1, c0, 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 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 syncs
|
||||
output reg hsync,
|
||||
output reg vsync,
|
||||
output reg csync,
|
||||
|
||||
// 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 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 [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,
|
||||
// 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,
|
||||
// DRAM
|
||||
input wire video_pre_next,
|
||||
output reg video_go = 0,
|
||||
|
||||
// ZX controls
|
||||
input wire y_offs_wr,
|
||||
output wire int_start
|
||||
// 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 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;
|
||||
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
|
||||
|
||||
// counters
|
||||
reg [8:0] hcount = 0;
|
||||
reg [8:0] vcount = 0;
|
||||
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;
|
||||
|
||||
// horizontal TV (7 MHz)
|
||||
always @(posedge clk) if (c3) hcount <= line_start ? 9'b0 : hcount + 9'b1;
|
||||
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;
|
||||
|
||||
// vertical TV (15.625 kHz)
|
||||
always @(posedge clk) if (line_start_s) vcount <= (vcount == (VPERIOD - 1)) ? 9'b0 : vcount + 9'b1;
|
||||
`ifdef PENT_312
|
||||
assign hcnt = hcount[4:0];
|
||||
assign upper8 = vcount < 8;
|
||||
`endif
|
||||
|
||||
// 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
|
||||
reg [8:0] hcount = 0;
|
||||
reg [8:0] vcount = 0;
|
||||
reg [8:0] cnt_out = 0;
|
||||
reg vga_hblank = 0;
|
||||
reg vga_vblank = 0;
|
||||
|
||||
// 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
|
||||
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;
|
||||
|
||||
// pixel counter
|
||||
always @(posedge clk) if (pix_stb) scnt <= pix_start ? 4'b0 : scnt + 4'b1; // f1 or c3
|
||||
// horizontal TV (7 MHz)
|
||||
always @(posedge clk) if (c3)
|
||||
hcount <= line_start ? 9'b0 : hcount + 9'b1;
|
||||
|
||||
// TS-line counter
|
||||
assign ts_raddr = hcount - hpix_beg_ts;
|
||||
// vertical TV (15.625 kHz)
|
||||
always @(posedge clk) if (line_start_s)
|
||||
vcount <= (vcount == (vperiod - 1)) ? 9'b0 : vcount + 9'b1;
|
||||
|
||||
always @(posedge clk) if (ts_start_coarse) lcount <= vcount - vpix_beg_ts + 9'b1;
|
||||
// horizontal VGA (14MHz)
|
||||
always @(posedge clk) if (f1)
|
||||
cnt_out <= vga_pix_start && c3 ? 9'b0 : cnt_out + 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
|
||||
// column address for DRAM
|
||||
always @(posedge clk)
|
||||
begin
|
||||
if (line_start2)
|
||||
begin
|
||||
cnt_col <= cstart;
|
||||
cptr <= 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
|
||||
else if (video_pre_next)
|
||||
begin
|
||||
cnt_col <= cnt_col + 8'b1;
|
||||
cptr <= ~cptr;
|
||||
end
|
||||
end
|
||||
|
||||
// sync strobes
|
||||
wire hs = (hcount >= HSYNC_BEG) && (hcount < HSYNC_END);
|
||||
wire vs = (vcount >= VSYNC_BEG) && (vcount < VSYNC_END);
|
||||
// row address for DRAM
|
||||
reg y_offs_wr_r;
|
||||
|
||||
assign tv_hblank = (hcount > HBLNK_BEG) && (hcount <= HBLNK_END);
|
||||
assign tv_vblank = (vcount >= VBLNK_BEG) && (vcount < VBLNK_END);
|
||||
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;
|
||||
|
||||
assign hvpix = hpix && vpix;
|
||||
// pixel counter
|
||||
always @(posedge clk) if (pix_stb) // f1 or c3
|
||||
scnt <= pix_start ? 4'b0 : scnt + 4'b1;
|
||||
|
||||
assign hpix = (hcount >= hpix_beg) && (hcount < hpix_end);
|
||||
// TS-line counter
|
||||
assign ts_raddr = hcount - hpix_beg_ts;
|
||||
|
||||
assign vpix = (vcount >= vpix_beg) && (vcount < vpix_end);
|
||||
always @(posedge clk)
|
||||
if (ts_start_coarse)
|
||||
lcount <= vcount - vpix_beg_ts + 9'b1;
|
||||
|
||||
assign hvtspix = htspix && vtspix;
|
||||
wire htspix = (hcount >= hpix_beg_ts) && (hcount < hpix_end_ts);
|
||||
wire vtspix = (vcount >= vpix_beg_ts) && (vcount < vpix_end_ts);
|
||||
// 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;
|
||||
|
||||
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
|
||||
// FLASH generator
|
||||
reg [4:0] flash_ctr;
|
||||
assign frame = flash_ctr[0];
|
||||
assign flash = flash_ctr[4];
|
||||
|
||||
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 (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
|
||||
|
||||
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;
|
||||
// sync strobes
|
||||
wire vga_hblank1 = (cnt_out > 9'd359);
|
||||
always @(posedge clk) if (f1) // fix me - bydlocode !!!
|
||||
vga_hblank <= vga_hblank1;
|
||||
|
||||
always @(posedge clk) begin
|
||||
hsync <= hs;
|
||||
vsync <= vs;
|
||||
end
|
||||
assign hvpix = hpix && vpix;
|
||||
assign hpix = (hcount >= hpix_beg) && (hcount < hpix_end);
|
||||
assign vpix = (vcount >= vpix_beg) && (vcount < vpix_end);
|
||||
|
||||
wire htspix = (hcount >= hpix_beg_ts) && (hcount < hpix_end_ts);
|
||||
wire vtspix = (vcount >= vpix_beg_ts) && (vcount < vpix_end_ts);
|
||||
assign hvtspix = htspix && vtspix;
|
||||
|
||||
assign v_ts = (vcount >= (vpix_beg_ts - 1)) && (vcount < (vpix_end_ts - 1)); // vertical TS window
|
||||
assign v_pf = (vcount >= (vpix_beg_ts - 17)) && (vcount < (vpix_end_ts - 9)); // vertical tilemap prefetch window
|
||||
|
||||
always @(posedge clk)
|
||||
video_go <= (hcount >= (hpix_beg - go_offs - x_offs)) && (hcount < (hpix_end - go_offs - x_offs + 4)) && vpix && !nogfx;
|
||||
|
||||
always @(posedge clk) if (line_start_s) // fix me - bydlocode !!!
|
||||
vga_vblank <= tv_vblank;
|
||||
|
||||
always @(posedge clk)
|
||||
begin
|
||||
hsync <= vga_on ? hs_vga : hs;
|
||||
vsync <= vs;
|
||||
csync <= ~(vs ^ hs);
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,3 +1,4 @@
|
||||
`include "tune.v"
|
||||
|
||||
// This is the Tile Sprite Processing Unit
|
||||
|
||||
@ -15,369 +16,444 @@
|
||||
|
||||
module video_ts
|
||||
(
|
||||
// clocks
|
||||
input wire clk,
|
||||
|
||||
// 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 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,
|
||||
|
||||
// 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,
|
||||
|
||||
// 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
|
||||
|
||||
// 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
|
||||
// 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];
|
||||
|
||||
// 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];
|
||||
|
||||
// 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;
|
||||
|
||||
// Layer selectors control
|
||||
reg [LAYERS-1:0] layer_active;
|
||||
reg [LAYERS-1:0] layer_skip;
|
||||
|
||||
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];
|
||||
|
||||
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;
|
||||
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;
|
||||
|
||||
reg [LAYERS-1:0] layer_active;
|
||||
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};
|
||||
|
||||
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;
|
||||
|
||||
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 ---
|
||||
// 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]);
|
||||
|
||||
// --- 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;
|
||||
|
||||
// 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;
|
||||
|
||||
// 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];
|
||||
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};
|
||||
|
||||
// internal layers control
|
||||
wire tm_end = tm_x == (t1_en ? 5'd16 : 5'd8);
|
||||
wire tm_next = dram_next && tmap;
|
||||
// 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;
|
||||
|
||||
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};
|
||||
// --- Tiles ---
|
||||
// layer parameter selectors
|
||||
reg [1:0] t_layer;
|
||||
reg [5:0] tx;
|
||||
|
||||
// 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;
|
||||
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};
|
||||
|
||||
// --- Tiles ---
|
||||
// TMB control
|
||||
wire [8:0] tmb_raddr = {t_line[4:3], tx + tx_offs[8:3], ~t_sel};
|
||||
|
||||
// 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];
|
||||
// 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];
|
||||
|
||||
// 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};
|
||||
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};
|
||||
|
||||
// TMB control
|
||||
wire [8:0] tmb_raddr = {t_line[4:3], tx + tx_offs[8:3], ~t_sel};
|
||||
// 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
|
||||
|
||||
// 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];
|
||||
localparam TM_PRE_VALID = 2'b01;
|
||||
localparam TM_VALID = 2'b10;
|
||||
|
||||
// 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] tm_valid_r;
|
||||
wire tm_valid = tm_valid_r[1];
|
||||
wire tm_pre_valid = tm_valid_r[0];
|
||||
|
||||
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};
|
||||
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;
|
||||
|
||||
// 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
|
||||
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;
|
||||
|
||||
localparam TM_PRE_VALID = 2'b01;
|
||||
localparam TM_VALID = 2'b10;
|
||||
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;
|
||||
|
||||
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);
|
||||
// tile Y geometry
|
||||
assign t_line = line[4:0] + ty_offs;
|
||||
|
||||
wire tm_pre_valid = tm_valid_r[0];
|
||||
wire tm_valid = tm_valid_r[1];
|
||||
// --- Sprites ---
|
||||
// sprite descriptor fields
|
||||
// R0
|
||||
wire [15:0] sfile_rdata;
|
||||
|
||||
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;
|
||||
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];
|
||||
|
||||
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;
|
||||
// TSR control
|
||||
wire [5:0] sprites_addr = s_tnum[5:0];
|
||||
|
||||
// tile Y geometry
|
||||
wire [4:0] t_line = line[4:0] + ty_offs;
|
||||
// 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];
|
||||
|
||||
// --- Sprites ---
|
||||
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}};
|
||||
|
||||
// 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];
|
||||
always @(posedge clk)
|
||||
sprites_last_r <= sreg == 8'd255;
|
||||
|
||||
// TSR control
|
||||
reg [8:0] sprites_x;
|
||||
reg [2:0] sprites_xs;
|
||||
reg sprites_xf;
|
||||
wire [5:0] sprites_addr = s_tnum[5:0];
|
||||
always @(posedge clk)
|
||||
if (start)
|
||||
s_layer <= 3'b1;
|
||||
else if (s_layer_end)
|
||||
s_layer <= {s_layer[1:0], 1'b0};
|
||||
|
||||
// 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;
|
||||
// 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
|
||||
|
||||
reg sprites_last_r;
|
||||
always @(posedge clk) sprites_last_r <= sreg == 8'd255;
|
||||
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
|
||||
|
||||
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};
|
||||
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;
|
||||
|
||||
// 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
|
||||
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;
|
||||
|
||||
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;
|
||||
// sprite Y geometry
|
||||
reg [5:0] s_bmline_offset_r;
|
||||
|
||||
wire sprite_go = sr2_valid && sprites && tsr_rdy; // kick to renderer
|
||||
wire spr_valid = s_visible && s_act;
|
||||
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 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 [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];
|
||||
|
||||
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;
|
||||
// SFile control
|
||||
reg [8:0] sprites_x;
|
||||
reg [2:0] sprites_xs;
|
||||
reg sprites_xf;
|
||||
|
||||
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;
|
||||
always @(posedge clk)
|
||||
begin
|
||||
if (sr0_valid)
|
||||
begin
|
||||
s_leap_r <= s_leap;
|
||||
s_bmline_offset_r <= s_bmline_offset;
|
||||
end
|
||||
|
||||
// SFile control
|
||||
reg [5:0] s_bmline_offset_r;
|
||||
reg s_leap_r;
|
||||
if (sr1_valid)
|
||||
begin
|
||||
sprites_x <= s_xcrd;
|
||||
sprites_xs <= s_xsz;
|
||||
sprites_xf <= s_xflp;
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (sr0_valid)
|
||||
begin
|
||||
s_leap_r <= s_leap;
|
||||
s_bmline_offset_r <= s_bmline_offset;
|
||||
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)
|
||||
);
|
||||
|
||||
if (sr1_valid)
|
||||
begin
|
||||
sprites_x <= s_xcrd;
|
||||
sprites_xs <= s_xsz;
|
||||
sprites_xf <= s_xflp;
|
||||
end
|
||||
end
|
||||
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)
|
||||
);
|
||||
|
||||
// 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
|
||||
(
|
||||
.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)
|
||||
);
|
||||
defparam
|
||||
video_tmbuf.indata_aclr = "OFF",
|
||||
video_tmbuf.indata_reg = "INCLOCK",
|
||||
video_tmbuf.intended_device_family = "ACEX1K",
|
||||
video_tmbuf.lpm_type = "altdpram",
|
||||
video_tmbuf.outdata_aclr = "OFF",
|
||||
video_tmbuf.outdata_reg = "OUTCLOCK",
|
||||
video_tmbuf.rdaddress_aclr = "OFF",
|
||||
video_tmbuf.rdaddress_reg = "UNREGISTERED",
|
||||
video_tmbuf.rdcontrol_aclr = "OFF",
|
||||
video_tmbuf.rdcontrol_reg = "UNREGISTERED",
|
||||
video_tmbuf.width = 16,
|
||||
video_tmbuf.widthad = 9,
|
||||
video_tmbuf.wraddress_aclr = "OFF",
|
||||
video_tmbuf.wraddress_reg = "INCLOCK",
|
||||
video_tmbuf.wrcontrol_aclr = "OFF",
|
||||
video_tmbuf.wrcontrol_reg = "INCLOCK";
|
||||
*/
|
||||
// TS renderer interface
|
||||
assign tsr_go = sprite_go || tile_go;
|
||||
assign tsr_x = sprites ? sprites_x : tile_x;
|
||||
assign tsr_xs = sprites ? sprites_xs : 3'd0;
|
||||
assign tsr_xf = sprites ? sprites_xf : t_xflp;
|
||||
assign tsr_page = sprites ? sgpage : tile_page;
|
||||
assign tsr_line = sprites ? sprites_line : tile_line;
|
||||
assign tsr_addr = sprites ? sprites_addr : tile_addr;
|
||||
assign tsr_pal = sprites ? s_pal : tile_pal;
|
||||
|
||||
endmodule
|
||||
|
@ -1,3 +1,4 @@
|
||||
`include "tune.v"
|
||||
|
||||
// This module renders pixels into TS-line for tiles/sprites
|
||||
// Task execution is initiated by 'tsr_go' (one 'clk' period strobe).
|
||||
@ -17,134 +18,133 @@
|
||||
|
||||
module video_ts_render
|
||||
(
|
||||
// clocks
|
||||
input wire clk,
|
||||
// clocks
|
||||
input wire clk,
|
||||
|
||||
// controls
|
||||
input wire reset, // line start strobe, inits the machine
|
||||
// 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 [ 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
|
||||
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,
|
||||
// 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 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;
|
||||
|
||||
// DRAM request
|
||||
assign dram_req = tsr_go || !mem_rdy;
|
||||
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
|
||||
|
||||
|
||||
// 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
|
||||
// TS-line address
|
||||
reg flip_r;
|
||||
|
||||
reg [20:0] addr_reg;
|
||||
always @(posedge clk) addr_reg <= dram_addr;
|
||||
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;
|
||||
|
||||
// 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];
|
||||
|
||||
always @(posedge clk)
|
||||
if (tsr_rld_stb)
|
||||
begin
|
||||
pal_r <= pal_d;
|
||||
flip_r <= flip_d;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
140
rtl/z80/zclock.v
Normal file
140
rtl/z80/zclock.v
Normal file
@ -0,0 +1,140 @@
|
||||
// PentEvo project (c) NedoPC 2008-2011
|
||||
//
|
||||
// Z80 clocking module, also contains some wait-stating when 14MHz
|
||||
//
|
||||
// IDEAL:
|
||||
// clk _/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\
|
||||
// | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
|
||||
// zclk /```\___/```\___/```\___/```````\_______/```````\_______/```````````````\_______________/```````````````\_______________/`
|
||||
// | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
|
||||
// zpos `\___/```\___/```\___/```\___________/```\___________/```\___________________________/```\___________________________/```\
|
||||
// | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
|
||||
// zneg _/```\___/```\___/```\_______/```\___________/```\___________________/```\___________________________/```\________________
|
||||
|
||||
// clock phasing:
|
||||
// c3 must be zpos for 7mhz, therefore c1 - zneg
|
||||
// for 3.5 mhz, c3 is both zpos and zneg (alternating)
|
||||
|
||||
|
||||
// 14MHz rulez:
|
||||
// 1. do variable stalls for memory access.
|
||||
// 2. do fallback on 7mhz for external IO accesses
|
||||
// 3. clock switch 14-7-3.5 only at RFSH
|
||||
|
||||
`include "tune.v"
|
||||
|
||||
module zclock
|
||||
(
|
||||
input clk,
|
||||
output reg zclk_out = 0, // generated Z80 clock, passed through inverter externally
|
||||
input c0, c2,
|
||||
|
||||
input wire iorq_s,
|
||||
input wire external_port,
|
||||
|
||||
output reg zpos,
|
||||
output reg zneg,
|
||||
|
||||
// stall enables and triggers
|
||||
input wire cpu_stall,
|
||||
input wire ide_stall,
|
||||
input wire dos_on,
|
||||
input wire vdos_off,
|
||||
|
||||
`ifdef PENT_312
|
||||
input wire boost_start,
|
||||
input wire [4:0] hcnt,
|
||||
input wire upper8,
|
||||
`endif
|
||||
|
||||
input [1:0] turbo // 2'b00 - 3.5 MHz
|
||||
// 2'b01 - 7.0 MHz
|
||||
// 2'b1x - 14.0 MHz
|
||||
);
|
||||
|
||||
`ifdef PENT_312
|
||||
// Turbo-boost for Pentagon 71680 tacts emulation with 312 video lines
|
||||
wire [1:0] turbo_int = (turbo == 2'b00) ? (t_boost ? 2'b01 : 2'b00) : turbo;
|
||||
reg t_boost = 0;
|
||||
reg [4:0] hcnt_r = 0;
|
||||
always @(posedge clk)
|
||||
if (boost_start && !t_boost)
|
||||
begin
|
||||
t_boost <= 1'b1;
|
||||
hcnt_r <= hcnt;
|
||||
end
|
||||
else if (t_boost && !upper8 && (hcnt_r == hcnt))
|
||||
t_boost <= 1'b0;
|
||||
`else
|
||||
wire [1:0] turbo_int = turbo;
|
||||
`endif
|
||||
|
||||
// wait generator
|
||||
reg [3:0] stall_count = 0;
|
||||
|
||||
wire dos_stall = dos_on || vdos_off;
|
||||
wire io_stall = iorq_s && external_port && turbo_int[1];
|
||||
wire stall_start = dos_stall || io_stall;
|
||||
wire stall_count_end = stall_count[3];
|
||||
wire dos_io_stall = stall_start || !stall_count_end;
|
||||
|
||||
always @(posedge clk)
|
||||
if (stall_start)
|
||||
begin
|
||||
if (dos_stall)
|
||||
stall_count <= 4'd4; // 4 tacts 28MHz (1 tact 7MHz)
|
||||
else if (io_stall)
|
||||
stall_count <= 4'd0; // 8 tacts 28MHz (1 tact 3.5MHz)
|
||||
end
|
||||
else if (!stall_count_end)
|
||||
stall_count <= stall_count + 3'd1;
|
||||
|
||||
// Z80 clocking pre-strobes
|
||||
reg clk14_src = 0; // source for 14MHz clock
|
||||
reg c2_cnt = 0;
|
||||
|
||||
wire stall = cpu_stall || dos_io_stall || ide_stall;
|
||||
|
||||
wire pre_zpos_140 = clk14_src;
|
||||
wire pre_zneg_140 = ~clk14_src;
|
||||
|
||||
wire pre_zpos_70 = c2;
|
||||
wire pre_zneg_70 = c0;
|
||||
|
||||
wire pre_zpos_35 = c2_cnt && c2;
|
||||
wire pre_zneg_35 = !c2_cnt && c2;
|
||||
|
||||
wire pre_zpos = turbo_int[1] ? pre_zpos_140 : (turbo_int[0] ? pre_zpos_70 : pre_zpos_35);
|
||||
wire pre_zneg = turbo_int[1] ? pre_zneg_140 : (turbo_int[0] ? pre_zneg_70 : pre_zneg_35);
|
||||
|
||||
always @(posedge clk)
|
||||
if (!stall)
|
||||
clk14_src <= ~clk14_src;
|
||||
|
||||
always @(posedge clk) if (c2)
|
||||
c2_cnt <= ~c2_cnt;
|
||||
|
||||
// Z80 clocking strobes
|
||||
always @(posedge clk)
|
||||
begin
|
||||
zpos <= !stall && pre_zpos && zclk_out;
|
||||
zneg <= !stall && pre_zneg && !zclk_out;
|
||||
end
|
||||
|
||||
// make Z80 clock: account for external inversion and make some leading of clock
|
||||
// 9.5 ns propagation delay: from clk posedge to zclk returned back any edge
|
||||
// (1/28)/2=17.9ns half a clock lead
|
||||
// 2.6ns lag because of non-output register emitting of zclk_out
|
||||
// total: 5.8 ns lead of any edge of zclk relative to posedge of clk => ACCOUNT FOR THIS WHEN DOING INTER-CLOCK DATA TRANSFERS
|
||||
|
||||
// Z80 clocking
|
||||
always @(negedge clk)
|
||||
begin
|
||||
if (zpos)
|
||||
zclk_out <= 1'b0;
|
||||
|
||||
if (zneg)
|
||||
zclk_out <= 1'b1;
|
||||
end
|
||||
|
||||
endmodule
|
136
rtl/z80/zint.v
Normal file
136
rtl/z80/zint.v
Normal file
@ -0,0 +1,136 @@
|
||||
|
||||
`include "tune.v"
|
||||
|
||||
module zint
|
||||
(
|
||||
input wire clk,
|
||||
input wire zpos,
|
||||
input wire res,
|
||||
input wire wait_n,
|
||||
input wire int_start_frm,
|
||||
input wire int_start_lin,
|
||||
input wire int_start_dma,
|
||||
input wire int_start_wtp,
|
||||
input wire vdos, // pre_vdos
|
||||
input wire intack,
|
||||
`ifdef PENT_312
|
||||
output wire boost_start,
|
||||
`endif
|
||||
|
||||
input wire [7:0] intmask,
|
||||
output wire [7:0] im2vect,
|
||||
|
||||
output wire int_n
|
||||
);
|
||||
|
||||
// In VDOS INTs are focibly disabled.
|
||||
// For Frame, Line INT its generation is blocked, it will be lost.
|
||||
// For DMA INT only its output is blocked, so DMA ISR will will be processed as soon as returned from VDOS.
|
||||
|
||||
reg [1:0] int_sel = 0;
|
||||
reg int_frm;
|
||||
reg int_dma;
|
||||
reg int_lin;
|
||||
reg int_wtp;
|
||||
reg intack_r;
|
||||
wire intctr_fin;
|
||||
|
||||
localparam INTFRM = 2'b00;
|
||||
localparam INTLIN = 2'b01;
|
||||
localparam INTDMA = 2'b10;
|
||||
localparam INTWTP = 2'b11;
|
||||
|
||||
wire [7:0] vect [0:3];
|
||||
assign vect[INTFRM] = 8'hFF;
|
||||
assign vect[INTLIN] = 8'hFD;
|
||||
assign vect[INTDMA] = 8'hFB;
|
||||
assign vect[INTWTP] = 8'hF9;
|
||||
|
||||
assign im2vect = {vect[int_sel]};
|
||||
|
||||
wire int_all = (int_frm || int_lin || int_dma || int_wtp) && !vdos;
|
||||
assign int_n = int_all ? 1'b0 : 1'b1;
|
||||
|
||||
wire dis_int_frm = !intmask[0];
|
||||
wire dis_int_lin = !intmask[1];
|
||||
wire dis_int_dma = !intmask[2];
|
||||
wire dis_int_wtp = !intmask[3];
|
||||
|
||||
`ifdef PENT_312
|
||||
assign boost_start = intack_s || intctr_fin_s;
|
||||
|
||||
wire intctr_fin_s = !intctr_fin_r && intctr_fin;
|
||||
reg intctr_fin_r;
|
||||
always @(posedge clk)
|
||||
intctr_fin_r <= intctr_fin;
|
||||
`endif
|
||||
|
||||
wire intack_s = intack && !intack_r;
|
||||
always @(posedge clk)
|
||||
intack_r <= intack;
|
||||
|
||||
// ~INT source latch
|
||||
always @(posedge clk)
|
||||
if (intack_s)
|
||||
begin
|
||||
if (int_frm)
|
||||
int_sel <= INTFRM; // priority 0
|
||||
else if (int_lin)
|
||||
int_sel <= INTLIN; // priority 1
|
||||
else if (int_dma)
|
||||
int_sel <= INTDMA; // priority 2
|
||||
else if (int_wtp)
|
||||
int_sel <= INTWTP; // priority 3
|
||||
end
|
||||
|
||||
// ~INT generating
|
||||
always @(posedge clk)
|
||||
if (res || dis_int_frm)
|
||||
int_frm <= 1'b0;
|
||||
else if (int_start_frm)
|
||||
int_frm <= 1'b1;
|
||||
else if (intack_s || intctr_fin) // priority 0
|
||||
int_frm <= 1'b0;
|
||||
|
||||
always @(posedge clk)
|
||||
if (res || dis_int_lin)
|
||||
int_lin <= 1'b0;
|
||||
else if (int_start_lin)
|
||||
int_lin <= 1'b1;
|
||||
else if (intack_s && !int_frm) // priority 1
|
||||
int_lin <= 1'b0;
|
||||
|
||||
always @(posedge clk)
|
||||
if (res || dis_int_dma)
|
||||
int_dma <= 1'b0;
|
||||
else if (int_start_dma)
|
||||
int_dma <= 1'b1;
|
||||
else if (intack_s && !int_frm && !int_lin) // priority 2
|
||||
int_dma <= 1'b0;
|
||||
|
||||
always @(posedge clk)
|
||||
if (res || dis_int_wtp)
|
||||
int_wtp <= 1'b0;
|
||||
else if (int_start_wtp)
|
||||
int_wtp <= 1'b1;
|
||||
else if (intack_s && !int_frm && !int_lin && !int_dma) // priority 3
|
||||
int_wtp <= 1'b0;
|
||||
|
||||
// ~WAIT resync
|
||||
reg wait_r;
|
||||
always @(posedge clk)
|
||||
wait_r <= !wait_n;
|
||||
|
||||
// ~INT counter
|
||||
reg [5:0] intctr;
|
||||
assign intctr_fin = intctr[5]; // 32 clks
|
||||
|
||||
always @(posedge clk, posedge int_start_frm)
|
||||
begin
|
||||
if (int_start_frm)
|
||||
intctr <= 1'b0;
|
||||
else if (zpos && !intctr_fin && !wait_r && !vdos)
|
||||
intctr <= intctr + 1'b1;
|
||||
end
|
||||
|
||||
endmodule
|
62
rtl/z80/zmaps.v
Normal file
62
rtl/z80/zmaps.v
Normal file
@ -0,0 +1,62 @@
|
||||
|
||||
// This module maps z80 memory accesses into FPGA RAM and ports
|
||||
|
||||
`include "tune.v"
|
||||
|
||||
module zmaps
|
||||
(
|
||||
// Z80 controls
|
||||
input wire clk,
|
||||
input wire memwr_s,
|
||||
input wire [15:0] a,
|
||||
input wire [7:0] d,
|
||||
|
||||
// config data
|
||||
input wire [4:0] fmaddr,
|
||||
|
||||
// FPRAM data
|
||||
output wire [15:0] zmd,
|
||||
output wire [7:0] zma,
|
||||
|
||||
// DMA
|
||||
input wire [15:0] dma_data,
|
||||
input wire [7:0] dma_wraddr,
|
||||
input wire dma_cram_we,
|
||||
input wire dma_sfile_we,
|
||||
|
||||
// write strobes
|
||||
output wire cram_we,
|
||||
output wire sfile_we,
|
||||
output wire regs_we
|
||||
);
|
||||
|
||||
// addresses of files withing zmaps
|
||||
localparam CRAM = 3'b000;
|
||||
localparam SFIL = 3'b001;
|
||||
localparam REGS = 4'b0100;
|
||||
|
||||
// DMA
|
||||
wire dma_req = dma_cram_we || dma_sfile_we;
|
||||
|
||||
// control signals
|
||||
wire hit = (a[15:12] == fmaddr[3:0]) && fmaddr[4] && memwr_s;
|
||||
wire cram_hit = (a[11:9] == CRAM) && hit;
|
||||
wire sfile_hit = (a[11:9] == SFIL) && hit;
|
||||
|
||||
// write enables
|
||||
wire lower_byte_we = (cram_hit || sfile_hit) && !a[0];
|
||||
assign cram_we = dma_req ? dma_cram_we : cram_hit && a[0];
|
||||
assign sfile_we = dma_req ? dma_sfile_we : sfile_hit && a[0];
|
||||
assign regs_we = (a[11:8] == REGS) && hit;
|
||||
|
||||
// LSB fetching
|
||||
reg [7:0] lower_byte;
|
||||
|
||||
assign zma = dma_req ? dma_wraddr : a[8:1];
|
||||
assign zmd = dma_req ? dma_data : {d, lower_byte};
|
||||
|
||||
always @(posedge clk)
|
||||
if (lower_byte_we)
|
||||
lower_byte <= d;
|
||||
|
||||
endmodule
|
321
rtl/z80/zmem.v
Normal file
321
rtl/z80/zmem.v
Normal file
@ -0,0 +1,321 @@
|
||||
`include "tune.v"
|
||||
|
||||
// PentEvo project (c) NedoPC 2008-2009
|
||||
//
|
||||
// Z80 memory manager: routes ROM/RAM accesses, makes wait-states for 14MHz or stall condition, etc.
|
||||
//
|
||||
//
|
||||
// clk _/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\
|
||||
// | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
|
||||
// zclk /```\___/```\___/```\___/```````\_______/```````\_______/```````````````\_______________/```````````````\_______________/`
|
||||
// | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
|
||||
// zpos `\___/```\___/```\___/```\___________/```\___________/```\___________________________/```\___________________________/```\
|
||||
// | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
|
||||
// zneg _/```\___/```\___/```\_______/```\___________/```\___________________/```\___________________________/```\________________
|
||||
|
||||
module zmem
|
||||
(
|
||||
input wire clk,
|
||||
input wire c1, c2, c3,
|
||||
input wire zneg, // strobes which show positive and negative edges of zclk
|
||||
|
||||
// Z80
|
||||
input wire rst,
|
||||
input wire [15:0] za,
|
||||
output wire [ 7:0] zd_out, // output to Z80 bus
|
||||
output wire zd_ena, // output to Z80 bus enable
|
||||
|
||||
input wire opfetch,
|
||||
input wire opfetch_s,
|
||||
input wire memrd,
|
||||
input wire memwr,
|
||||
input wire memwr_s,
|
||||
|
||||
input wire [ 1:0] turbo, // 2'b00 - 3.5,
|
||||
// 2'b01 - 7.0,
|
||||
// 2'b1x - 14.0
|
||||
input wire [3:0] cache_en,
|
||||
input wire [3:0] memconf,
|
||||
input wire [31:0] xt_page,
|
||||
|
||||
output wire [4:0] rompg,
|
||||
output wire csrom,
|
||||
output wire romoe_n,
|
||||
output wire romwe_n,
|
||||
|
||||
output wire dos,
|
||||
output wire dos_on,
|
||||
output wire dos_off,
|
||||
output wire vdos,
|
||||
output reg pre_vdos,
|
||||
input wire vdos_on,
|
||||
input wire vdos_off,
|
||||
|
||||
// DRAM
|
||||
output wire cpu_req,
|
||||
output wire [20:0] cpu_addr,
|
||||
output wire cpu_wrbsel,
|
||||
input wire [15:0] cpu_rddata,
|
||||
input wire cpu_next,
|
||||
input wire cpu_strobe,
|
||||
input wire cpu_latch,
|
||||
output wire cpu_stall // for zclock
|
||||
);
|
||||
|
||||
// controls
|
||||
wire rom128 = memconf[0];
|
||||
wire w0_we = memconf[1];
|
||||
wire w0_map_n = memconf[2];
|
||||
wire w0_ram = memconf[3];
|
||||
|
||||
// pager
|
||||
wire [7:0] xtpage[0:3];
|
||||
assign xtpage[0] = vdos ? 8'hFF : {xt_page[7:2], w0_map_n ? xt_page[1:0] : {~dos, rom128}};
|
||||
assign xtpage[1] = xt_page[15:8];
|
||||
assign xtpage[2] = xt_page[23:16];
|
||||
assign xtpage[3] = xt_page[31:24];
|
||||
|
||||
wire [1:0] win = za[15:14];
|
||||
wire win0 = ~|win;
|
||||
wire ramwr_en = !win0 || w0_we || vdos;
|
||||
wire rom_n_ram = win0 && !w0_ram && !vdos;
|
||||
wire [7:0] page = xtpage[win];
|
||||
|
||||
// DOS signal control
|
||||
reg dos_r;
|
||||
|
||||
assign dos_on = win0 && opfetch_s && (za[13:8]==6'h3D) && rom128 && !w0_map_n;
|
||||
assign dos_off = !win0 && opfetch_s && !vdos;
|
||||
assign dos = (dos_on || dos_off) ^^ dos_r; // to make dos appear 1 clock earlier than dos_r
|
||||
|
||||
always @(posedge clk)
|
||||
if (rst)
|
||||
dos_r <= 1'b0;
|
||||
|
||||
else if (dos_off)
|
||||
dos_r <= 1'b0;
|
||||
else if (dos_on)
|
||||
dos_r <= 1'b1;
|
||||
|
||||
// VDOS signal control
|
||||
// vdos switching is delayed till next opfetch due to INIR that writes right after iord cycle
|
||||
|
||||
reg vdos_r;
|
||||
|
||||
assign vdos = opfetch ? pre_vdos : vdos_r; // vdos appears as soon as first opfetch
|
||||
|
||||
always @(posedge clk)
|
||||
if (rst || vdos_off)
|
||||
begin
|
||||
pre_vdos <= 1'b0;
|
||||
vdos_r <= 1'b0;
|
||||
end
|
||||
else if (vdos_on)
|
||||
pre_vdos <= 1'b1;
|
||||
else if (opfetch_s)
|
||||
vdos_r <= pre_vdos;
|
||||
|
||||
// RAM
|
||||
wire cache_hit_en;
|
||||
assign zd_ena = !rom_n_ram && memrd;
|
||||
wire ramreq = ((memrd && !cache_hit_en) || (memwr && ramwr_en));
|
||||
|
||||
// address, data in and data out
|
||||
wire [15:0] cache_d;
|
||||
wire cache_v;
|
||||
|
||||
assign cpu_wrbsel = za[0];
|
||||
assign cpu_addr[20:0] = {page, za[13:1]};
|
||||
wire [15:0] mem_d = cpu_latch ? cpu_rddata : cache_d;
|
||||
assign zd_out = ~cpu_wrbsel ? mem_d[7:0] : mem_d[15:8];
|
||||
|
||||
// Z80 controls
|
||||
|
||||
// 7/3.5MHz support
|
||||
reg ramreq_r;
|
||||
reg pre_ramreq_r;
|
||||
reg pending_cpu_req;
|
||||
reg stall14_cycrd;
|
||||
reg stall14_fin;
|
||||
|
||||
wire dram_beg = ramreq && !pre_ramreq_r && zneg;
|
||||
wire cpureq_357 = ramreq && !ramreq_r;
|
||||
wire cpureq_14 = dram_beg || pending_cpu_req;
|
||||
wire stall357 = cpureq_357 && !cpu_next;
|
||||
wire stall14_ini = dram_beg && (!cpu_next || opfetch || memrd); // no wait at all in write cycles, if next dram cycle is available
|
||||
wire stall14_cyc = memrd ? stall14_cycrd : !cpu_next;
|
||||
wire stall14 = stall14_ini || stall14_cyc || stall14_fin;
|
||||
|
||||
wire turbo14 = turbo[1];
|
||||
assign cpu_req = turbo14 ? cpureq_14 : cpureq_357;
|
||||
assign cpu_stall = turbo14 ? stall14 : stall357;
|
||||
|
||||
// 14MHz support
|
||||
// wait tables:
|
||||
//
|
||||
// M1 opcode fetch, dram_beg concurs with:
|
||||
// c3: +3
|
||||
// c2: +4
|
||||
// c1: +5
|
||||
// c0: +6
|
||||
//
|
||||
// memory read, dram_beg concurs with:
|
||||
// c3: +2
|
||||
// c2: +3
|
||||
// c1: +4
|
||||
// c0: +5
|
||||
//
|
||||
// memory write: no wait
|
||||
//
|
||||
// special case: if dram_beg pulses 1 when cpu_next is 0,
|
||||
// unconditional wait has to be performed until cpu_next is 1, and
|
||||
// then wait as if dram_beg would concur with c0
|
||||
|
||||
// memrd, opfetch - wait till c3 && cpu_next,
|
||||
// memwr - wait till cpu_next
|
||||
|
||||
always @(posedge clk)
|
||||
if (c3 && !cpu_stall)
|
||||
ramreq_r <= ramreq;
|
||||
|
||||
always @(posedge clk)
|
||||
if (zneg)
|
||||
pre_ramreq_r <= ramreq;
|
||||
|
||||
always @(posedge clk)
|
||||
if (rst)
|
||||
pending_cpu_req <= 1'b0;
|
||||
else if (cpu_next && c3)
|
||||
pending_cpu_req <= 1'b0;
|
||||
else if (dram_beg)
|
||||
pending_cpu_req <= 1'b1;
|
||||
|
||||
always @(posedge clk)
|
||||
if (rst)
|
||||
stall14_cycrd <= 1'b0;
|
||||
else if (cpu_next && c3)
|
||||
stall14_cycrd <= 1'b0;
|
||||
else if (dram_beg && (!c3 || !cpu_next) && (opfetch || memrd))
|
||||
stall14_cycrd <= 1'b1;
|
||||
|
||||
always @(posedge clk)
|
||||
if (rst)
|
||||
stall14_fin <= 1'b0;
|
||||
else if (stall14_fin && ((opfetch && c1) || (memrd && c2)))
|
||||
stall14_fin <= 1'b0;
|
||||
else if (cpu_next && c3 && cpu_req && (opfetch || memrd))
|
||||
stall14_fin <= 1'b1;
|
||||
|
||||
// cache
|
||||
wire [12:0] cache_a;
|
||||
wire [12:0] cpu_hi_addr = {page[7:0], za[13:9]};
|
||||
// wire cache_hit = (ch_addr[7:2] != 6'b011100) && (cpu_hi_addr == cache_a) && cache_v; // debug for BM
|
||||
wire cache_hit = (cpu_hi_addr == cache_a) && cache_v; // asynchronous signal meaning that address requested by CPU is cached and valid
|
||||
assign cache_hit_en = cache_hit && cache_en[win];
|
||||
wire cache_inv = cache_hit && memwr_s && ramwr_en; // cache invalidation should be only performed if write happens to cached address
|
||||
|
||||
wire [7:0] ch_addr = cpu_addr[7:0];
|
||||
// wire [14:0] cpu_hi_addr = {page[7:0], za[13:7]};
|
||||
// wire [14:0] cache_a;
|
||||
// wire [7:0] ch_addr = {2'b0, cpu_addr[5:0]};
|
||||
|
||||
dpram #(.DATAWIDTH(16), .ADDRWIDTH(8)) cache_data
|
||||
(
|
||||
.clock(clk),
|
||||
.address_a(ch_addr),
|
||||
.data_a(cpu_rddata),
|
||||
.wren_a(cpu_strobe),
|
||||
.address_b(ch_addr),
|
||||
.q_b(cache_d)
|
||||
);
|
||||
|
||||
dpram #(.DATAWIDTH(14), .ADDRWIDTH(8)) cache_addr
|
||||
(
|
||||
.clock(clk),
|
||||
.address_a(ch_addr),
|
||||
.data_a({!cache_inv, cpu_hi_addr}),
|
||||
.wren_a(cpu_strobe || cache_inv),
|
||||
.address_b(ch_addr),
|
||||
.q_b({cache_v, cache_a})
|
||||
);
|
||||
/*
|
||||
altdpram cache_data
|
||||
(
|
||||
.inclock (clk),
|
||||
.outclock (clk),
|
||||
.data (cpu_rddata),
|
||||
.rdaddress (ch_addr),
|
||||
.wraddress (ch_addr),
|
||||
.wren (cpu_strobe),
|
||||
.q (cache_d),
|
||||
.aclr (1'b0),
|
||||
.byteena (1'b1),
|
||||
.inclocken (1'b1),
|
||||
.outclocken (1'b1),
|
||||
.rdaddressstall (1'b0),
|
||||
.rden (1'b1),
|
||||
.wraddressstall (1'b0)
|
||||
);
|
||||
|
||||
defparam
|
||||
cache_data.indata_aclr = "OFF",
|
||||
cache_data.indata_reg = "INCLOCK",
|
||||
cache_data.intended_device_family = "ACEX1K",
|
||||
cache_data.lpm_type = "altdpram",
|
||||
cache_data.outdata_aclr = "OFF",
|
||||
cache_data.outdata_reg = "OUTCLOCK",
|
||||
cache_data.rdaddress_aclr = "OFF",
|
||||
cache_data.rdaddress_reg = "UNREGISTERED",
|
||||
cache_data.rdcontrol_aclr = "OFF",
|
||||
cache_data.rdcontrol_reg = "UNREGISTERED",
|
||||
cache_data.width = 16,
|
||||
cache_data.widthad = 8,
|
||||
cache_data.wraddress_aclr = "OFF",
|
||||
cache_data.wraddress_reg = "INCLOCK",
|
||||
cache_data.wrcontrol_aclr = "OFF",
|
||||
cache_data.wrcontrol_reg = "INCLOCK";
|
||||
|
||||
altdpram cache_addr
|
||||
(
|
||||
.inclock (clk),
|
||||
.outclock (clk),
|
||||
.data ({!cache_inv, cpu_hi_addr}),
|
||||
.rdaddress (ch_addr),
|
||||
.wraddress (ch_addr),
|
||||
.wren (cpu_strobe || cache_inv),
|
||||
.q ({cache_v, cache_a}),
|
||||
.aclr (1'b0),
|
||||
.byteena (1'b1),
|
||||
.inclocken (1'b1),
|
||||
.outclocken (1'b1),
|
||||
.rdaddressstall (1'b0),
|
||||
.rden (1'b1),
|
||||
.wraddressstall (1'b0)
|
||||
);
|
||||
|
||||
defparam
|
||||
cache_addr.indata_aclr = "OFF",
|
||||
cache_addr.indata_reg = "INCLOCK",
|
||||
cache_addr.intended_device_family = "ACEX1K",
|
||||
cache_addr.lpm_type = "altdpram",
|
||||
cache_addr.outdata_aclr = "OFF",
|
||||
cache_addr.outdata_reg = "OUTCLOCK",
|
||||
cache_addr.rdaddress_aclr = "OFF",
|
||||
cache_addr.rdaddress_reg = "UNREGISTERED",
|
||||
cache_addr.rdcontrol_aclr = "OFF",
|
||||
cache_addr.rdcontrol_reg = "UNREGISTERED",
|
||||
cache_addr.width = 14,
|
||||
cache_addr.widthad = 8,
|
||||
cache_addr.wraddress_aclr = "OFF",
|
||||
cache_addr.wraddress_reg = "INCLOCK",
|
||||
cache_addr.wrcontrol_aclr = "OFF",
|
||||
cache_addr.wrcontrol_reg = "INCLOCK";
|
||||
*/
|
||||
|
||||
// ROM chip
|
||||
assign csrom = rom_n_ram;
|
||||
assign romoe_n = !memrd;
|
||||
assign romwe_n = !(memwr && w0_we);
|
||||
assign rompg = xtpage[0][4:0];
|
||||
|
||||
endmodule
|
746
rtl/z80/zports.v
Normal file
746
rtl/z80/zports.v
Normal file
@ -0,0 +1,746 @@
|
||||
|
||||
// PentEvo project (c) NedoPC 2008-2010
|
||||
|
||||
`include "tune.v"
|
||||
|
||||
module zports
|
||||
(
|
||||
input wire zclk, // z80 clock
|
||||
input wire clk,
|
||||
|
||||
input wire [ 7:0] din,
|
||||
output reg [ 7:0] dout,
|
||||
output wire dataout,
|
||||
input wire [15:0] a,
|
||||
|
||||
input wire rst, // system reset
|
||||
input wire opfetch,
|
||||
|
||||
input wire rd,
|
||||
input wire wr,
|
||||
input wire rdwr,
|
||||
|
||||
input wire iorq,
|
||||
input wire iorq_s,
|
||||
input wire iord,
|
||||
input wire iord_s,
|
||||
input wire iowr,
|
||||
input wire iowr_s,
|
||||
input wire iordwr,
|
||||
input wire iordwr_s,
|
||||
|
||||
output wire porthit, // when internal port hit occurs, this is 1, else 0; used for iorq1_n iorq2_n on zxbus
|
||||
output wire external_port, // asserts for AY and VG93 accesses
|
||||
|
||||
output wire zborder_wr,
|
||||
output wire border_wr,
|
||||
output wire zvpage_wr,
|
||||
output wire vpage_wr,
|
||||
output wire vconf_wr,
|
||||
output wire gx_offsl_wr,
|
||||
output wire gx_offsh_wr,
|
||||
output wire gy_offsl_wr,
|
||||
output wire gy_offsh_wr,
|
||||
output wire t0x_offsl_wr,
|
||||
output wire t0x_offsh_wr,
|
||||
output wire t0y_offsl_wr,
|
||||
output wire t0y_offsh_wr,
|
||||
output wire t1x_offsl_wr,
|
||||
output wire t1x_offsh_wr,
|
||||
output wire t1y_offsl_wr,
|
||||
output wire t1y_offsh_wr,
|
||||
output wire tsconf_wr,
|
||||
output wire palsel_wr,
|
||||
output wire tmpage_wr,
|
||||
output wire t0gpage_wr,
|
||||
output wire t1gpage_wr,
|
||||
output wire sgpage_wr,
|
||||
output wire hint_beg_wr,
|
||||
output wire vint_begl_wr,
|
||||
output wire vint_begh_wr,
|
||||
|
||||
output wire [31:0] xt_page,
|
||||
|
||||
output reg [4:0] fmaddr,
|
||||
input wire regs_we,
|
||||
|
||||
output reg [7:0] sysconf,
|
||||
output reg [7:0] memconf,
|
||||
output reg [3:0] cacheconf,
|
||||
input wire cfg_floppy_swap,
|
||||
output reg [7:0] fddvirt,
|
||||
|
||||
`ifdef FDR
|
||||
output reg fdr_en,
|
||||
output wire fdr_cnt_lat,
|
||||
input wire [18:0] fdr_cnt,
|
||||
|
||||
output wire [9:0] dmaport_wr,
|
||||
`else
|
||||
output wire [8:0] dmaport_wr,
|
||||
`endif
|
||||
input wire dma_act,
|
||||
output reg [1:0] dmawpdev,
|
||||
|
||||
|
||||
output reg [7:0] intmask,
|
||||
|
||||
input wire dos,
|
||||
input wire vdos,
|
||||
output wire vdos_on,
|
||||
output wire vdos_off,
|
||||
|
||||
output wire ay_bdir,
|
||||
output wire ay_bc1,
|
||||
output wire covox_wr,
|
||||
output wire beeper_wr,
|
||||
|
||||
input wire tape_read,
|
||||
|
||||
`ifdef IDE_HDD
|
||||
// IDE interface
|
||||
input wire [15:0] ide_in,
|
||||
output wire [15:0] ide_out,
|
||||
output wire ide_cs0_n,
|
||||
output wire ide_cs1_n,
|
||||
output wire ide_req,
|
||||
input wire ide_stb,
|
||||
input wire ide_ready,
|
||||
output reg ide_stall,
|
||||
`endif
|
||||
|
||||
input wire [ 4:0] keys_in, // keys (port FE)
|
||||
input wire [ 7:0] mus_in, // mouse (xxDF)
|
||||
|
||||
`ifdef KEMPSTON_8BIT
|
||||
input wire [ 7:0] kj_in,
|
||||
`else
|
||||
input wire [ 4:0] kj_in,
|
||||
`endif
|
||||
|
||||
input wire vg_intrq,
|
||||
input wire vg_drq, // from vg93 module - drq + irq read
|
||||
output wire vg_cs_n,
|
||||
output wire vg_wrFF,
|
||||
output wire [1:0] drive_sel, // disk drive selection
|
||||
|
||||
// SPI
|
||||
output wire sdcs_n,
|
||||
output wire sd2cs_n,
|
||||
`ifdef IDE_VDAC2
|
||||
output wire ftcs_n,
|
||||
`ifdef ESP32_SPI
|
||||
output wire espcs_n,
|
||||
`endif
|
||||
`endif
|
||||
output reg spi_mode,
|
||||
output wire sd_start,
|
||||
output wire [ 7:0] sd_datain,
|
||||
input wire [ 7:0] sd_dataout,
|
||||
|
||||
// WAIT-ports related
|
||||
output reg [ 7:0] wait_addr,
|
||||
output wire wait_start_gluclock, // begin wait from some ports
|
||||
output wire wait_start_comport, //
|
||||
output reg [ 7:0] wait_write,
|
||||
input wire [ 7:0] wait_read
|
||||
);
|
||||
|
||||
//#nnAF
|
||||
localparam VCONF = 8'h00;
|
||||
localparam VPAGE = 8'h01;
|
||||
localparam GXOFFSL = 8'h02;
|
||||
localparam GXOFFSH = 8'h03;
|
||||
localparam GYOFFSL = 8'h04;
|
||||
localparam GYOFFSH = 8'h05;
|
||||
localparam TSCONF = 8'h06;
|
||||
localparam PALSEL = 8'h07;
|
||||
localparam XBORDER = 8'h0F;
|
||||
|
||||
localparam T0XOFFSL = 8'h40;
|
||||
localparam T0XOFFSH = 8'h41;
|
||||
localparam T0YOFFSL = 8'h42;
|
||||
localparam T0YOFFSH = 8'h43;
|
||||
localparam T1XOFFSL = 8'h44;
|
||||
localparam T1XOFFSH = 8'h45;
|
||||
localparam T1YOFFSL = 8'h46;
|
||||
localparam T1YOFFSH = 8'h47;
|
||||
|
||||
localparam RAMPAGE = 8'h10; // this covers #10-#13
|
||||
localparam FMADDR = 8'h15;
|
||||
localparam TMPAGE = 8'h16;
|
||||
localparam T0GPAGE = 8'h17;
|
||||
localparam T1GPAGE = 8'h18;
|
||||
localparam SGPAGE = 8'h19;
|
||||
localparam DMASADDRL = 8'h1A;
|
||||
localparam DMASADDRH = 8'h1B;
|
||||
localparam DMASADDRX = 8'h1C;
|
||||
localparam DMADADDRL = 8'h1D;
|
||||
localparam DMADADDRH = 8'h1E;
|
||||
localparam DMADADDRX = 8'h1F;
|
||||
|
||||
localparam SYSCONF = 8'h20;
|
||||
localparam MEMCONF = 8'h21;
|
||||
localparam HSINT = 8'h22;
|
||||
localparam VSINTL = 8'h23;
|
||||
localparam VSINTH = 8'h24;
|
||||
localparam DMAWPD = 8'h25;
|
||||
localparam DMALEN = 8'h26;
|
||||
localparam DMACTRL = 8'h27;
|
||||
localparam DMANUM = 8'h28;
|
||||
localparam FDDVIRT = 8'h29;
|
||||
localparam INTMASK = 8'h2A;
|
||||
localparam CACHECONF = 8'h2B;
|
||||
localparam DMAWPA = 8'h2D;
|
||||
|
||||
localparam XSTAT = 8'h00;
|
||||
localparam DMASTAT = 8'h27;
|
||||
|
||||
`ifdef FDR
|
||||
localparam DMANUMH = 8'h2C;
|
||||
localparam FRCTRL = 8'h30;
|
||||
localparam FRCNT0 = 8'h30;
|
||||
localparam FRCNT1 = 8'h31;
|
||||
localparam FRCNT2 = 8'h32;
|
||||
`endif
|
||||
|
||||
`ifdef FDR
|
||||
localparam FDR_VER = 1'b1;
|
||||
`else
|
||||
localparam FDR_VER = 1'b0;
|
||||
`endif
|
||||
|
||||
`ifdef IDE_VDAC
|
||||
localparam VDAC_VER = 3'h3;
|
||||
`elsif IDE_VDAC2
|
||||
localparam VDAC_VER = 3'h7;
|
||||
`else
|
||||
localparam VDAC_VER = 3'h0;
|
||||
`endif
|
||||
|
||||
localparam PORTFE = 8'hFE;
|
||||
localparam PORTFD = 8'hFD;
|
||||
localparam PORTXT = 8'hAF;
|
||||
localparam PORTF7 = 8'hF7;
|
||||
localparam COVOX = 8'hFB;
|
||||
|
||||
`ifdef IDE_HDD
|
||||
localparam NIDE10 = 8'h10;
|
||||
localparam NIDE11 = 8'h11;
|
||||
localparam NIDE30 = 8'h30;
|
||||
localparam NIDE50 = 8'h50;
|
||||
localparam NIDE70 = 8'h70;
|
||||
localparam NIDE90 = 8'h90;
|
||||
localparam NIDEB0 = 8'hB0;
|
||||
localparam NIDED0 = 8'hD0;
|
||||
localparam NIDEF0 = 8'hF0;
|
||||
localparam NIDE08 = 8'h08;
|
||||
localparam NIDE28 = 8'h28;
|
||||
localparam NIDE48 = 8'h48;
|
||||
localparam NIDE68 = 8'h68;
|
||||
localparam NIDE88 = 8'h88;
|
||||
localparam NIDEA8 = 8'hA8;
|
||||
localparam NIDEC8 = 8'hC8;
|
||||
localparam NIDEE8 = 8'hE8;
|
||||
`endif
|
||||
|
||||
localparam VGCOM = 8'h1F;
|
||||
localparam VGTRK = 8'h3F;
|
||||
localparam VGSEC = 8'h5F;
|
||||
localparam VGDAT = 8'h7F;
|
||||
localparam VGSYS = 8'hFF;
|
||||
|
||||
localparam KJOY = 8'h1F;
|
||||
localparam KMOUSE = 8'hDF;
|
||||
|
||||
localparam SDCFG = 8'h77;
|
||||
localparam SDDAT = 8'h57;
|
||||
|
||||
localparam COMPORT = 8'hEF; // F8EF..FFEF - rs232 ports
|
||||
|
||||
reg [3:0] spi_cs_n;
|
||||
reg pwr_up_reg;
|
||||
reg [7:0] rampage[0:3];
|
||||
wire gluclock_on;
|
||||
wire p7ffd_wr;
|
||||
|
||||
assign sdcs_n = spi_cs_n[0];
|
||||
assign sd2cs_n = spi_cs_n[2];
|
||||
`ifdef IDE_VDAC2
|
||||
assign ftcs_n = spi_cs_n[1];
|
||||
`ifdef ESP32_SPI
|
||||
assign espcs_n = spi_cs_n[3];
|
||||
`endif
|
||||
`endif
|
||||
|
||||
wire open_vg;
|
||||
wire [7:0] loa = a[7:0];
|
||||
wire [7:0] hoa = regs_we ? a[7:0] : a[15:8];
|
||||
|
||||
wire vg_port = (loa==VGCOM) || (loa==VGTRK) || (loa==VGSEC) || (loa==VGDAT);
|
||||
wire vgsys_port = (loa==VGSYS);
|
||||
|
||||
assign porthit = ((loa==PORTFE) || (loa==PORTXT) || (loa==PORTFD) || (loa==COVOX)) || ((loa==PORTF7) && !dos)
|
||||
`ifdef IDE_HDD
|
||||
|| ide_all
|
||||
`endif
|
||||
|| ((vg_port || vgsys_port) && (dos || open_vg)) || ((loa==KJOY) && !dos && !open_vg) || (loa==KMOUSE) || ((loa==SDCFG) || (loa==SDDAT)) || (loa==COMPORT);
|
||||
|
||||
`ifdef IDE_HDD
|
||||
wire ide_all = ide_even || ide_port11;
|
||||
wire ide_even = (loa[2:0] == 3'b000) && (loa[3] != loa[4]); // even ports
|
||||
wire ide_port11 = (loa==NIDE11); // 11
|
||||
wire ide_port10 = (loa==NIDE10); // 10
|
||||
wire ide_portc8 = (loa==NIDEC8); // C8
|
||||
`endif
|
||||
|
||||
assign external_port = ((loa==PORTFD) && a[15]) // AY
|
||||
|| (((loa==VGCOM) || (loa==VGTRK) || (loa==VGSEC) || (loa==VGDAT)) && (dos || open_vg));
|
||||
|
||||
assign dataout = porthit && iord && (~external_port);
|
||||
|
||||
// zclk-synchronous strobes
|
||||
reg iowr_reg;
|
||||
reg iord_reg;
|
||||
reg port_wr;
|
||||
reg port_rd;
|
||||
|
||||
always @(posedge zclk)
|
||||
begin
|
||||
iowr_reg <= iowr;
|
||||
iord_reg <= iord;
|
||||
|
||||
if (!iowr_reg && iowr)
|
||||
port_wr <= 1'b1;
|
||||
else
|
||||
port_wr <= 1'b0;
|
||||
|
||||
if (!iord_reg && iord)
|
||||
port_rd <= 1'b1;
|
||||
else
|
||||
port_rd <= 1'b0;
|
||||
end
|
||||
|
||||
// reading ports
|
||||
always @*
|
||||
begin
|
||||
case (loa)
|
||||
PORTFE:
|
||||
dout = {1'b1, tape_read, 1'b1, keys_in};
|
||||
|
||||
`ifdef IDE_HDD
|
||||
NIDE10,NIDE30,NIDE50,NIDE70,NIDE90,NIDEB0,NIDED0,NIDEF0,NIDE08,NIDE28,NIDE48,NIDE68,NIDE88,NIDEA8,NIDEC8,NIDEE8:
|
||||
dout = iderdeven;
|
||||
NIDE11:
|
||||
dout = iderdodd;
|
||||
`endif
|
||||
|
||||
PORTXT:
|
||||
begin
|
||||
case (hoa)
|
||||
XSTAT:
|
||||
dout = {1'b0, pwr_up_reg, FDR_VER, 2'b0, VDAC_VER};
|
||||
|
||||
DMASTAT:
|
||||
dout = {dma_act, 7'b0};
|
||||
|
||||
RAMPAGE + 8'd2, RAMPAGE + 8'd3:
|
||||
dout = rampage[hoa[1:0]];
|
||||
|
||||
`ifdef FDR
|
||||
FRCNT0:
|
||||
dout = fdr_cnt[7:0];
|
||||
|
||||
FRCNT1:
|
||||
dout = fdr_cnt[15:8];
|
||||
|
||||
FRCNT2:
|
||||
dout = {5'b0, fdr_cnt[18:16]};
|
||||
`endif
|
||||
default:
|
||||
dout = 8'hFF;
|
||||
|
||||
endcase
|
||||
end
|
||||
|
||||
VGSYS:
|
||||
dout = {vg_intrq, vg_drq, 6'b111111};
|
||||
|
||||
KJOY:
|
||||
`ifdef KEMPSTON_8BIT
|
||||
dout = kj_in;
|
||||
`else
|
||||
dout = {3'b000, kj_in};
|
||||
`endif
|
||||
|
||||
KMOUSE:
|
||||
dout = mus_in;
|
||||
|
||||
SDCFG:
|
||||
dout = 8'h00; // always SD inserted, SD is in R/W mode
|
||||
SDDAT:
|
||||
dout = sd_dataout;
|
||||
|
||||
PORTF7:
|
||||
begin
|
||||
if (!a[14] && (a[8] ^ dos) && gluclock_on) // $BFF7 - data i/o
|
||||
dout = wait_read;
|
||||
// dout = 8'h55;
|
||||
else // any other $xxF7 port
|
||||
dout = 8'hFF;
|
||||
end
|
||||
|
||||
COMPORT:
|
||||
begin
|
||||
dout = wait_read; // $F8EF..$FFEF
|
||||
end
|
||||
|
||||
default:
|
||||
dout = 8'hFF;
|
||||
endcase
|
||||
end
|
||||
|
||||
// power-up
|
||||
// This bit is loaded as 1 while FPGA is configured and automatically reset to 0 after STATUS port reading
|
||||
reg pwr_up = 1'b1;
|
||||
always @(posedge clk)
|
||||
if (iord_s & (loa == PORTXT) & (hoa == XSTAT))
|
||||
begin
|
||||
pwr_up_reg <= pwr_up;
|
||||
pwr_up <= 1'b0;
|
||||
end
|
||||
|
||||
wire portfe_wr = (loa==PORTFE) && iowr_s;
|
||||
assign beeper_wr = portfe_wr;
|
||||
assign covox_wr = (loa==COVOX) && iowr_s;
|
||||
wire portxt_wr = ((loa==PORTXT) && iowr_s) || regs_we;
|
||||
wire portxt_rd = (loa==PORTXT) && iord_s;
|
||||
|
||||
assign xt_page = {rampage[3], rampage[2], rampage[1], rampage[0]};
|
||||
|
||||
// writing ports
|
||||
assign dmaport_wr[0] = portxt_wr && (hoa == DMASADDRL);
|
||||
assign dmaport_wr[1] = portxt_wr && (hoa == DMASADDRH);
|
||||
assign dmaport_wr[2] = portxt_wr && (hoa == DMASADDRX);
|
||||
assign dmaport_wr[3] = portxt_wr && (hoa == DMADADDRL);
|
||||
assign dmaport_wr[4] = portxt_wr && (hoa == DMADADDRH);
|
||||
assign dmaport_wr[5] = portxt_wr && (hoa == DMADADDRX);
|
||||
assign dmaport_wr[6] = portxt_wr && (hoa == DMALEN);
|
||||
assign dmaport_wr[7] = portxt_wr && (hoa == DMACTRL);
|
||||
assign dmaport_wr[8] = portxt_wr && (hoa == DMANUM);
|
||||
`ifdef FDR
|
||||
assign dmaport_wr[9] = portxt_wr && (hoa == DMANUMH);
|
||||
`endif
|
||||
|
||||
assign zborder_wr = portfe_wr;
|
||||
assign border_wr = (portxt_wr && (hoa == XBORDER));
|
||||
assign zvpage_wr = p7ffd_wr;
|
||||
assign vpage_wr = (portxt_wr && (hoa == VPAGE ));
|
||||
assign vconf_wr = (portxt_wr && (hoa == VCONF ));
|
||||
assign gx_offsl_wr = (portxt_wr && (hoa == GXOFFSL));
|
||||
assign gx_offsh_wr = (portxt_wr && (hoa == GXOFFSH));
|
||||
assign gy_offsl_wr = (portxt_wr && (hoa == GYOFFSL));
|
||||
assign gy_offsh_wr = (portxt_wr && (hoa == GYOFFSH));
|
||||
assign t0x_offsl_wr = (portxt_wr && (hoa == T0XOFFSL));
|
||||
assign t0x_offsh_wr = (portxt_wr && (hoa == T0XOFFSH));
|
||||
assign t0y_offsl_wr = (portxt_wr && (hoa == T0YOFFSL));
|
||||
assign t0y_offsh_wr = (portxt_wr && (hoa == T0YOFFSH));
|
||||
assign t1x_offsl_wr = (portxt_wr && (hoa == T1XOFFSL));
|
||||
assign t1x_offsh_wr = (portxt_wr && (hoa == T1XOFFSH));
|
||||
assign t1y_offsl_wr = (portxt_wr && (hoa == T1YOFFSL));
|
||||
assign t1y_offsh_wr = (portxt_wr && (hoa == T1YOFFSH));
|
||||
assign tsconf_wr = (portxt_wr && (hoa == TSCONF));
|
||||
assign palsel_wr = (portxt_wr && (hoa == PALSEL));
|
||||
assign tmpage_wr = (portxt_wr && (hoa == TMPAGE));
|
||||
assign t0gpage_wr = (portxt_wr && (hoa == T0GPAGE));
|
||||
assign t1gpage_wr = (portxt_wr && (hoa == T1GPAGE));
|
||||
assign sgpage_wr = (portxt_wr && (hoa == SGPAGE));
|
||||
assign hint_beg_wr = (portxt_wr && (hoa == HSINT ));
|
||||
assign vint_begl_wr = (portxt_wr && (hoa == VSINTL));
|
||||
assign vint_begh_wr = (portxt_wr && (hoa == VSINTH));
|
||||
`ifdef FDR
|
||||
assign fdr_cnt_lat = (portxt_rd && (hoa == FRCNT0));
|
||||
`endif
|
||||
|
||||
reg m1_lock128;
|
||||
|
||||
wire lock128_2 = memconf[7:6] == 2'b10; // mode 2
|
||||
wire lock128_3 = memconf[7:6] == 2'b11; // mode 3
|
||||
wire lock128 = lock128_3 ? 1'b0 : (lock128_2 ? m1_lock128 : memconf[6]);
|
||||
|
||||
always @(posedge clk) if (opfetch)
|
||||
m1_lock128 <= !(din[7] ^ din[6]);
|
||||
|
||||
always @(posedge clk or posedge rst)
|
||||
if (rst)
|
||||
begin
|
||||
fmaddr[4] <= 1'b0;
|
||||
intmask <= 8'b1;
|
||||
fddvirt <= 8'b0;
|
||||
sysconf <= 8'h00; // 3.5 MHz
|
||||
memconf <= 8'h04; // no map
|
||||
cacheconf <= 4'h0; // no cache
|
||||
|
||||
rampage[0] <= 8'h00;
|
||||
rampage[1] <= 8'h05;
|
||||
rampage[2] <= 8'h02;
|
||||
rampage[3] <= 8'h00;
|
||||
|
||||
`ifdef FDR
|
||||
fdr_en <= 1'b0;
|
||||
`endif
|
||||
end
|
||||
else // if (rst)
|
||||
begin
|
||||
if (p7ffd_wr)
|
||||
begin
|
||||
memconf[0] <= din[4];
|
||||
rampage[3] <= {2'b0, lock128_3 ? {din[5], din[7:6]} : ({1'b0, lock128 ? 2'b0 : din[7:6]}), din[2:0]};
|
||||
end
|
||||
|
||||
else if (portxt_wr)
|
||||
begin
|
||||
if (hoa[7:2] == RAMPAGE[7:2])
|
||||
rampage[hoa[1:0]] <= din;
|
||||
|
||||
if (hoa == FMADDR)
|
||||
fmaddr <= din[4:0];
|
||||
|
||||
if (hoa == SYSCONF)
|
||||
begin
|
||||
sysconf <= din;
|
||||
cacheconf <= {4{din[2]}};
|
||||
end
|
||||
|
||||
if (hoa == DMAWPD)
|
||||
dmawpdev <= din[1:0];
|
||||
|
||||
if (hoa == CACHECONF)
|
||||
cacheconf <= din[3:0];
|
||||
|
||||
if (hoa == MEMCONF)
|
||||
memconf <= din;
|
||||
|
||||
if (hoa == FDDVIRT)
|
||||
fddvirt <= din;
|
||||
|
||||
`ifdef FDR
|
||||
if (hoa == FRCTRL)
|
||||
fdr_en <= din[0];
|
||||
`endif
|
||||
|
||||
if (hoa == INTMASK)
|
||||
intmask <= din;
|
||||
end
|
||||
end
|
||||
|
||||
// 7FFD port
|
||||
reg lock48;
|
||||
|
||||
assign p7ffd_wr = !a[15] && (loa==PORTFD) && iowr_s && !lock48;
|
||||
|
||||
always @(posedge clk or posedge rst)
|
||||
if (rst)
|
||||
lock48 <= 1'b0;
|
||||
else if (p7ffd_wr && !lock128_3)
|
||||
lock48 <= din[5];
|
||||
|
||||
// AY control
|
||||
wire ay_hit = (loa==PORTFD) & a[15];
|
||||
assign ay_bc1 = ay_hit & a[14] & iordwr;
|
||||
assign ay_bdir = ay_hit & iowr;
|
||||
|
||||
// VG93
|
||||
reg [1:0] drive_sel_raw;
|
||||
|
||||
wire [3:0] fddvrt = fddvirt[3:0];
|
||||
wire virt_vg = fddvrt[drive_sel_raw];
|
||||
assign open_vg = fddvirt[7];
|
||||
assign drive_sel = {drive_sel_raw[1], drive_sel_raw[0] ^ cfg_floppy_swap};
|
||||
|
||||
wire vg_wen = (dos || open_vg) && !vdos && !virt_vg;
|
||||
assign vg_cs_n = !(iordwr && vg_port && vg_wen);
|
||||
assign vg_wrFF = iowr_s && vgsys_port && vg_wen;
|
||||
wire vg_wrDS = iowr_s && vgsys_port && (dos || open_vg);
|
||||
|
||||
assign vdos_on = iordwr_s && (vg_port || vgsys_port) && dos && !vdos && virt_vg;
|
||||
assign vdos_off = iordwr_s && vg_port && vdos;
|
||||
|
||||
// write drive number
|
||||
always @(posedge clk)
|
||||
if (vg_wrDS)
|
||||
drive_sel_raw <= din;
|
||||
|
||||
// SD card (Z-controller compatible)
|
||||
wire sdcfg_wr;
|
||||
wire sddat_wr;
|
||||
wire sddat_rd;
|
||||
|
||||
assign sdcfg_wr = (loa==SDCFG) && iowr_s;
|
||||
assign sddat_wr = (loa==SDDAT) && iowr_s;
|
||||
assign sddat_rd = (loa==SDDAT) && iord_s;
|
||||
|
||||
// SDCFG write - sdcs_n control
|
||||
always @(posedge clk or posedge rst)
|
||||
if (rst)
|
||||
begin
|
||||
spi_cs_n <= 4'b1111;
|
||||
spi_mode <= 1'b0;
|
||||
end
|
||||
else if (sdcfg_wr)
|
||||
begin
|
||||
spi_cs_n <= {~din[4:2], din[1]};
|
||||
// spi_mode <= din[7];
|
||||
end
|
||||
|
||||
// start signal for SPI module with resyncing to fclk
|
||||
assign sd_start = sddat_wr || sddat_rd;
|
||||
|
||||
// data for SPI module
|
||||
assign sd_datain = wr ? din : 8'hFF;
|
||||
|
||||
// xxF7
|
||||
wire portf7_wr = ((loa==PORTF7) && (a[8]==1'b1) && port_wr && (!dos || vdos));
|
||||
wire portf7_rd = ((loa==PORTF7) && (a[8]==1'b1) && port_rd && (!dos || vdos));
|
||||
|
||||
// EFF7 port
|
||||
reg [7:0] peff7;
|
||||
always @(posedge clk or posedge rst)
|
||||
if (rst)
|
||||
peff7 <= 8'h00;
|
||||
else if (!a[12] && portf7_wr && !dos) // #EEF7 in dos is not accessible
|
||||
peff7 <= din;
|
||||
|
||||
// gluclock ports
|
||||
assign gluclock_on = peff7[7] || dos; // in dos mode EEF7 is not accessible, gluclock access is ON in dos mode.
|
||||
|
||||
// comports
|
||||
wire comport_wr = ((loa == COMPORT) && port_wr);
|
||||
wire comport_rd = ((loa == COMPORT) && port_rd);
|
||||
|
||||
// write to wait registers
|
||||
always @(posedge zclk)
|
||||
begin
|
||||
// gluclocks
|
||||
if (gluclock_on && portf7_wr)
|
||||
begin
|
||||
if (!a[14]) // $BFF7 - data reg
|
||||
wait_write <= din;
|
||||
|
||||
if (!a[13]) // $DFF7 - addr reg
|
||||
wait_addr <= din;
|
||||
end
|
||||
|
||||
// com ports
|
||||
if (comport_wr) // $xxEF
|
||||
wait_write <= din;
|
||||
|
||||
if (comport_wr || comport_rd)
|
||||
wait_addr <= a[15:8];
|
||||
|
||||
if ((loa==PORTXT) && (hoa == DMAWPA))
|
||||
wait_addr <= din;
|
||||
end
|
||||
|
||||
// wait from wait registers
|
||||
assign wait_start_gluclock = (gluclock_on && !a[14] && (portf7_rd || portf7_wr)); // $BFF7 - gluclock r/w
|
||||
assign wait_start_comport = (comport_rd || comport_wr);
|
||||
|
||||
`ifdef IDE_HDD
|
||||
// IDE ports
|
||||
// do NOT generate IDE write, if neither of ide_wrhi|lo latches set and writing to NIDE10
|
||||
wire ide_cs0 = ide_even && !ide_portc8;
|
||||
wire ide_cs1 = ide_portc8;
|
||||
wire ide_rd = rd && !(ide_rd_latch && ide_port10);
|
||||
wire ide_wr = wr && !(!ide_wrlo_latch && !ide_wrhi_latch && ide_port10);
|
||||
assign ide_req = iorq_s && ide_even && (ide_rd || ide_wr);
|
||||
assign ide_cs0_n = !ide_cs0;
|
||||
assign ide_cs1_n = !ide_cs1;
|
||||
|
||||
always @(posedge clk)
|
||||
if (ide_req)
|
||||
ide_stall <= 1'b1;
|
||||
else if (ide_ready)
|
||||
ide_stall <= 1'b0;
|
||||
|
||||
// control read & write triggers, which allow nemo-divide mod to work.
|
||||
// read trigger:
|
||||
reg ide_rd_trig; // nemo-divide read trigger
|
||||
always @(posedge zclk)
|
||||
begin
|
||||
if (ide_port10 && port_rd && !ide_rd_trig)
|
||||
ide_rd_trig <= 1'b1;
|
||||
else if (ide_all && (port_rd || port_wr))
|
||||
ide_rd_trig <= 1'b0;
|
||||
end
|
||||
|
||||
// two triggers for write sequence
|
||||
reg ide_wrlo_trig, ide_wrhi_trig; // nemo-divide write triggers
|
||||
always @(posedge zclk)
|
||||
if (ide_all && (port_rd || port_wr))
|
||||
begin
|
||||
if (ide_port11 && port_wr)
|
||||
ide_wrhi_trig <= 1'b1;
|
||||
else
|
||||
ide_wrhi_trig <= 1'b0;
|
||||
|
||||
if (ide_port10 && port_wr && !ide_wrhi_trig && !ide_wrlo_trig)
|
||||
ide_wrlo_trig <= 1'b1;
|
||||
else
|
||||
ide_wrlo_trig <= 1'b0;
|
||||
end
|
||||
|
||||
// normal read: #10(low), #11(high)
|
||||
// divide read: #10(low), #10(high)
|
||||
//
|
||||
// normal write: #11(high), #10(low)
|
||||
// divide write: #10(low), #10(high)
|
||||
|
||||
reg [15:0] idewrreg; // write register, either low or high part is pre-written here,
|
||||
// while other part is out directly from Z80 bus
|
||||
always @(posedge zclk)
|
||||
begin
|
||||
if (port_wr && ide_port11)
|
||||
idewrreg[15:8] <= din;
|
||||
|
||||
if (port_wr && ide_port10 && !ide_wrlo_trig)
|
||||
idewrreg[ 7:0] <= din;
|
||||
end
|
||||
|
||||
// generate read cycles for IDE as usual, except for reading #10
|
||||
// instead of #11 for high byte (nemo-divide). I use additional latch
|
||||
// since 'ide_rd_trig' clears during second Z80 IO read cycle to #10
|
||||
reg ide_rd_latch; // to save state of trigger during read cycle
|
||||
always @*
|
||||
if (!rd)
|
||||
ide_rd_latch <= ide_rd_trig;
|
||||
|
||||
reg ide_wrlo_latch, ide_wrhi_latch; // save state during write cycles
|
||||
always @*
|
||||
if (!wr)
|
||||
begin
|
||||
ide_wrlo_latch <= ide_wrlo_trig; // same for write triggers
|
||||
ide_wrhi_latch <= ide_wrhi_trig;
|
||||
end
|
||||
|
||||
// data read by Z80 from IDE
|
||||
wire idein_lo_rd = port_rd && ide_port10 && (!ide_rd_trig); // while high part is remembered here
|
||||
wire [7:0] iderdodd = iderdreg[15:8]; // read data from "odd" port (#11)
|
||||
wire [7:0] iderdeven = (ide_rd_latch && ide_port10) ? iderdreg[15:8] : iderdreg[7:0]; // to control read data from "even" ide ports (all except #11)
|
||||
// wire [7:0] iderdeven = (ide_rd_latch && ide_port10) ? idehiin[7:0] : ide_in[7:0]; // to control read data from "even" ide ports (all except #11)
|
||||
|
||||
reg [15:0] iderdreg;
|
||||
// reg [7:0] idehiin; // IDE high part read register: low part is read directly to Z80 bus,
|
||||
always @(posedge clk)
|
||||
if (ide_stb)
|
||||
iderdreg <= ide_in;
|
||||
// if (idein_lo_rd)
|
||||
// idehiin <= ide_in[15:8];
|
||||
|
||||
// data written to IDE from Z80
|
||||
wire [7:0] ideout1 = ide_wrhi_latch ? idewrreg[15:8] : din[ 7:0];
|
||||
wire [7:0] ideout0 = ide_wrlo_latch ? idewrreg[ 7:0] : din[ 7:0];
|
||||
assign ide_out = {ideout1, ideout0};
|
||||
`endif
|
||||
|
||||
endmodule
|
99
rtl/z80/zsignals.v
Normal file
99
rtl/z80/zsignals.v
Normal file
@ -0,0 +1,99 @@
|
||||
|
||||
// Decoding and strobing of z80 signals
|
||||
|
||||
`include "tune.v"
|
||||
|
||||
module zsignals
|
||||
(
|
||||
// clocks
|
||||
input wire clk,
|
||||
input wire zpos,
|
||||
|
||||
// z80 interface input
|
||||
input wire rst_n,
|
||||
input wire iorq_n,
|
||||
input wire mreq_n,
|
||||
input wire m1_n,
|
||||
input wire rfsh_n,
|
||||
input wire rd_n,
|
||||
input wire wr_n,
|
||||
|
||||
// Z80 signals
|
||||
output wire rst,
|
||||
output wire m1,
|
||||
output wire rfsh,
|
||||
output wire rd,
|
||||
output wire wr,
|
||||
output wire iorq,
|
||||
output wire mreq,
|
||||
output wire rdwr,
|
||||
output wire iord,
|
||||
output wire iowr,
|
||||
output wire iordwr,
|
||||
output wire memrd,
|
||||
output wire memwr,
|
||||
output wire memrw,
|
||||
output wire opfetch,
|
||||
output wire intack,
|
||||
|
||||
// Z80 signals strobes, at fclk
|
||||
output wire iorq_s,
|
||||
output wire mreq_s,
|
||||
output wire iord_s,
|
||||
output wire iowr_s,
|
||||
output wire iordwr_s,
|
||||
output wire memrd_s,
|
||||
output wire memwr_s,
|
||||
output wire memrw_s,
|
||||
output wire opfetch_s
|
||||
);
|
||||
|
||||
reg [1:0] iorq_r = 0, mreq_r = 0;
|
||||
|
||||
// invertors
|
||||
assign rst = !rst_n;
|
||||
assign m1 = !m1_n;
|
||||
assign rfsh = !rfsh_n;
|
||||
assign rd = !rd_n;
|
||||
assign wr = !wr_n;
|
||||
|
||||
// requests
|
||||
assign iorq = !iorq_n && m1_n; // this is masked by ~M1 to avoid port decoding on INT ack
|
||||
assign mreq = !mreq_n && rfsh_n; // this is masked by ~RFSH to ignore refresh cycles as memory requests
|
||||
|
||||
// combined
|
||||
assign rdwr = rd || wr;
|
||||
assign iord = iorq && rd;
|
||||
assign iowr = iorq && wr;
|
||||
assign iordwr = iorq && rdwr;
|
||||
assign memrd = mreq && rd;
|
||||
assign memwr = mreq && !rd;
|
||||
assign memrw = mreq && rdwr;
|
||||
assign opfetch = memrd && m1;
|
||||
assign intack = !iorq_n && m1; // NOT masked by M1
|
||||
|
||||
// strobed
|
||||
assign iorq_s = iorq_r[0] && !iorq_r[1];
|
||||
assign mreq_s = mreq_r[0] && !mreq_r[1];
|
||||
assign iord_s = iorq_s && rd;
|
||||
assign iowr_s = iorq_s && wr;
|
||||
assign iordwr_s = iorq_s && rdwr;
|
||||
assign memrd_s = mreq_s && rd;
|
||||
assign memwr_s = mreq_s && !rd;
|
||||
assign memrw_s = mreq_s && rdwr;
|
||||
assign opfetch_s = memrd_s && m1;
|
||||
|
||||
// latch inputs on FPGA clock
|
||||
always @(posedge clk) if (zpos)
|
||||
begin
|
||||
iorq_r[0] <= iorq;
|
||||
mreq_r[0] <= mreq;
|
||||
end
|
||||
|
||||
always @(posedge clk)
|
||||
begin
|
||||
iorq_r[1] <= iorq_r[0];
|
||||
mreq_r[1] <= mreq_r[0];
|
||||
end
|
||||
|
||||
endmodule
|
Reference in New Issue
Block a user