mirror of
https://github.com/MiSTer-devel/MacPlus_MiSTer.git
synced 2025-02-20 05:29:03 +00:00
947 lines
21 KiB
Verilog
947 lines
21 KiB
Verilog
//============================================================================
|
|
//
|
|
// MiSTer hardware abstraction module
|
|
// (c)2017,2018 Sorgelig
|
|
//
|
|
// This program is free software; you can redistribute it and/or modify it
|
|
// under the terms of the GNU General Public License as published by the Free
|
|
// Software Foundation; either version 2 of the License, or (at your option)
|
|
// any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful, but WITHOUT
|
|
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
// more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License along
|
|
// with this program; if not, write to the Free Software Foundation, Inc.,
|
|
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
//
|
|
//============================================================================
|
|
|
|
module sys_top
|
|
(
|
|
/////////// CLOCK //////////
|
|
input FPGA_CLK1_50,
|
|
input FPGA_CLK2_50,
|
|
input FPGA_CLK3_50,
|
|
|
|
//////////// VGA ///////////
|
|
output [5:0] VGA_R,
|
|
output [5:0] VGA_G,
|
|
output [5:0] VGA_B,
|
|
inout VGA_HS, // VGA_HS is secondary SD card detect when VGA_EN = 1 (inactive)
|
|
output VGA_VS,
|
|
input VGA_EN, // active low
|
|
|
|
/////////// AUDIO //////////
|
|
output AUDIO_L,
|
|
output AUDIO_R,
|
|
output AUDIO_SPDIF,
|
|
|
|
//////////// HDMI //////////
|
|
output HDMI_I2C_SCL,
|
|
inout HDMI_I2C_SDA,
|
|
|
|
output HDMI_MCLK,
|
|
output HDMI_SCLK,
|
|
output HDMI_LRCLK,
|
|
output HDMI_I2S,
|
|
|
|
output HDMI_TX_CLK,
|
|
output HDMI_TX_DE,
|
|
output [23:0] HDMI_TX_D,
|
|
output HDMI_TX_HS,
|
|
output HDMI_TX_VS,
|
|
|
|
input HDMI_TX_INT,
|
|
|
|
//////////// SDR ///////////
|
|
output [12:0] SDRAM_A,
|
|
inout [15:0] SDRAM_DQ,
|
|
output SDRAM_DQML,
|
|
output SDRAM_DQMH,
|
|
output SDRAM_nWE,
|
|
output SDRAM_nCAS,
|
|
output SDRAM_nRAS,
|
|
output SDRAM_nCS,
|
|
output [1:0] SDRAM_BA,
|
|
output SDRAM_CLK,
|
|
output SDRAM_CKE,
|
|
|
|
//////////// I/O ///////////
|
|
output LED_USER,
|
|
output LED_HDD,
|
|
output LED_POWER,
|
|
input BTN_USER,
|
|
input BTN_OSD,
|
|
input BTN_RESET,
|
|
|
|
//////////// SDIO ///////////
|
|
inout [3:0] SDIO_DAT,
|
|
inout SDIO_CMD,
|
|
output SDIO_CLK,
|
|
input SDIO_CD,
|
|
|
|
////////// MB KEY ///////////
|
|
input [1:0] KEY,
|
|
|
|
////////// MB SWITCH ////////
|
|
input [3:0] SW,
|
|
|
|
////////// MB LED ///////////
|
|
output [7:0] LED
|
|
);
|
|
|
|
|
|
assign SDIO_DAT[2:1] = 2'bZZ;
|
|
|
|
|
|
////////////////////////// LEDs ///////////////////////////////////////
|
|
|
|
reg [7:0] led_overtake = 0;
|
|
reg [7:0] led_state = 0;
|
|
|
|
wire led_p = led_power[1] ? ~led_power[0] : 1'b0;
|
|
wire led_d = led_disk[1] ? ~led_disk[0] : ~(led_disk[0] | gp_out[29]);
|
|
wire led_u = ~led_user;
|
|
|
|
assign LED_POWER = led_p ? 1'bZ : 1'b0;
|
|
assign LED_HDD = led_d ? 1'bZ : 1'b0;
|
|
assign LED_USER = led_u ? 1'bZ : 1'b0;
|
|
|
|
//LEDs on main board
|
|
assign LED = (led_overtake & led_state) | (~led_overtake & {3'b000, ~led_p, 1'b0, ~led_d, 1'b0, ~led_u});
|
|
|
|
|
|
////////////////////////// Buttons ///////////////////////////////////
|
|
reg btn_user, btn_osd;
|
|
always @(posedge FPGA_CLK2_50) begin
|
|
integer div;
|
|
reg [7:0] deb_user;
|
|
reg [7:0] deb_osd;
|
|
|
|
div <= div + 1'b1;
|
|
if(div > 100000) div <= 0;
|
|
|
|
if(!div) begin
|
|
deb_user <= {deb_user[6:0], ~(BTN_USER & KEY[1])};
|
|
if(&deb_user) btn_user <= 1;
|
|
if(!deb_user) btn_user <= 0;
|
|
|
|
deb_osd <= {deb_osd[6:0], ~(BTN_OSD & KEY[0])};
|
|
if(&deb_osd) btn_osd <= 1;
|
|
if(!deb_osd) btn_osd <= 0;
|
|
end
|
|
end
|
|
|
|
reg btn_reset = 1;
|
|
always @(posedge FPGA_CLK2_50) btn_reset <= BTN_RESET;
|
|
|
|
|
|
///////////////////////// HPS I/O /////////////////////////////////////
|
|
|
|
// gp_in[31] = 0 - quick flag that FPGA is initialized (HPS reads 1 when FPGA is not in user mode)
|
|
// used to avoid lockups while JTAG loading
|
|
wire [31:0] gp_in = {1'b0, btn_user, btn_osd, 9'd0, io_ver, io_ack, io_wide, io_dout};
|
|
wire [31:0] gp_out;
|
|
|
|
wire [1:0] io_ver = 1; // 0 - standard MiST I/O (for quick porting of complex MiST cores). 1 - optimized HPS I/O. 2,3 - reserved for future.
|
|
wire io_wait;
|
|
wire io_wide;
|
|
wire [15:0] io_dout;
|
|
wire [15:0] io_din = gp_outr[15:0];
|
|
wire io_clk = gp_outr[17];
|
|
wire io_fpga = gp_outr[18];
|
|
wire io_osd = gp_outr[19];
|
|
wire io_uio = gp_outr[20];
|
|
//wire io_sdd = gp_outr[21]; // used only in ST core
|
|
|
|
reg io_ack;
|
|
reg rack;
|
|
wire io_strobe = ~rack & io_clk;
|
|
|
|
always @(posedge clk_sys) begin
|
|
if(~io_wait | io_strobe) begin
|
|
rack <= io_clk;
|
|
io_ack <= rack;
|
|
end
|
|
end
|
|
|
|
reg [31:0] gp_outr;
|
|
always @(posedge clk_sys) begin
|
|
reg [31:0] gp_outd;
|
|
gp_outr <= gp_outd;
|
|
gp_outd <= gp_out;
|
|
end
|
|
|
|
wire [7:0] core_type = 'hA4; // A4 - generic core.
|
|
|
|
// HPS will not communicate to core if magic is different
|
|
wire [31:0] core_magic = {24'h5CA623, core_type};
|
|
|
|
cyclonev_hps_interface_mpu_general_purpose h2f_gp
|
|
(
|
|
.gp_in({~gp_out[31] ? core_magic : gp_in}),
|
|
.gp_out(gp_out)
|
|
);
|
|
|
|
|
|
reg [15:0] cfg;
|
|
|
|
reg cfg_got = 0;
|
|
reg cfg_set = 0;
|
|
//wire [2:0] hdmi_res = cfg[10:8];
|
|
wire dvi_mode = cfg[7];
|
|
wire audio_96k = cfg[6];
|
|
wire ypbpr_en = cfg[5];
|
|
wire csync = cfg[3];
|
|
`ifndef LITE
|
|
wire vga_scaler= cfg[2];
|
|
`endif
|
|
|
|
reg cfg_custom_t = 0;
|
|
reg [5:0] cfg_custom_p1;
|
|
reg [31:0] cfg_custom_p2;
|
|
|
|
reg [4:0] vol_att = 0;
|
|
|
|
reg vip_newcfg = 0;
|
|
always@(posedge clk_sys) begin
|
|
reg [7:0] cmd;
|
|
reg has_cmd;
|
|
reg old_strobe;
|
|
reg [7:0] cnt = 0;
|
|
|
|
old_strobe <= io_strobe;
|
|
|
|
if(~io_uio) has_cmd <= 0;
|
|
else
|
|
if(~old_strobe & io_strobe) begin
|
|
if(!has_cmd) begin
|
|
has_cmd <= 1;
|
|
cmd <= io_din[7:0];
|
|
cnt <= 0;
|
|
end
|
|
else begin
|
|
if(cmd == 1) begin
|
|
cfg <= io_din;
|
|
cfg_set <= 1;
|
|
end
|
|
if(cmd == 'h20) begin
|
|
cfg_set <= 0;
|
|
cnt <= cnt + 1'd1;
|
|
if(cnt<8) begin
|
|
if(!cnt) vip_newcfg <= ~cfg_ready;
|
|
case(cnt)
|
|
0: if(WIDTH != io_din[11:0]) begin WIDTH <= io_din[11:0]; vip_newcfg <= 1; end
|
|
1: if(HFP != io_din[11:0]) begin HFP <= io_din[11:0]; vip_newcfg <= 1; end
|
|
2: if(HS != io_din[11:0]) begin HS <= io_din[11:0]; vip_newcfg <= 1; end
|
|
3: if(HBP != io_din[11:0]) begin HBP <= io_din[11:0]; vip_newcfg <= 1; end
|
|
4: if(HEIGHT != io_din[11:0]) begin HEIGHT <= io_din[11:0]; vip_newcfg <= 1; end
|
|
5: if(VFP != io_din[11:0]) begin VFP <= io_din[11:0]; vip_newcfg <= 1; end
|
|
6: if(VS != io_din[11:0]) begin VS <= io_din[11:0]; vip_newcfg <= 1; end
|
|
7: if(VBP != io_din[11:0]) begin VBP <= io_din[11:0]; vip_newcfg <= 1; end
|
|
endcase
|
|
if(cnt == 1) begin
|
|
cfg_custom_p1 <= 0;
|
|
cfg_custom_p2 <= 0;
|
|
cfg_custom_t <= ~cfg_custom_t;
|
|
end
|
|
end
|
|
else begin
|
|
if(cnt[1:0]==0) cfg_custom_p1 <= io_din[5:0];
|
|
if(cnt[1:0]==1) cfg_custom_p2[15:0] <= io_din;
|
|
if(cnt[1:0]==2) begin
|
|
cfg_custom_p2[31:16] <= io_din;
|
|
cfg_custom_t <= ~cfg_custom_t;
|
|
cnt[1:0] <= 0;
|
|
end
|
|
end
|
|
end
|
|
if(cmd == 'h25) {led_overtake, led_state} <= io_din;
|
|
if(cmd == 'h26) vol_att <= io_din[4:0];
|
|
if(cmd == 'h27) VSET <= io_din[11:0];
|
|
end
|
|
end
|
|
end
|
|
|
|
always @(posedge clk_sys) begin
|
|
reg vsd, vsd2;
|
|
if(~cfg_ready || ~cfg_set) cfg_got <= cfg_set;
|
|
else begin
|
|
vsd <= HDMI_TX_VS;
|
|
vsd2 <= vsd;
|
|
if(~vsd2 & vsd) cfg_got <= cfg_set;
|
|
end
|
|
end
|
|
|
|
/////////////////////////// RESET ///////////////////////////////////
|
|
|
|
reg reset_req = 0;
|
|
always @(posedge FPGA_CLK2_50) begin
|
|
reg [1:0] resetd, resetd2;
|
|
reg old_reset;
|
|
|
|
//latch the reset
|
|
old_reset <= reset;
|
|
if(~old_reset & reset) reset_req <= 1;
|
|
|
|
//special combination to set/clear the reset
|
|
//preventing of accidental reset control
|
|
if(resetd==1) reset_req <= 1;
|
|
if(resetd==2 && resetd2==0) reset_req <= 0;
|
|
|
|
resetd <= gp_out[31:30];
|
|
resetd2 <= resetd;
|
|
end
|
|
|
|
wire clk_ctl;
|
|
|
|
///////////////////////// VIP version ///////////////////////////////
|
|
|
|
wire iHdmiClk = ~HDMI_TX_CLK; // Internal HDMI clock, inverted in relation to external clock
|
|
|
|
`ifndef LITE
|
|
|
|
wire reset;
|
|
vip vip
|
|
(
|
|
//Reset/Clock
|
|
.reset_reset_req(reset_req | ~cfg_ready),
|
|
.reset_reset(reset),
|
|
.reset_reset_vip(0),
|
|
|
|
//DE10-nano has no reset signal on GPIO, so core has to emulate cold reset button.
|
|
.reset_cold_req(~btn_reset),
|
|
.reset_warm_req(0),
|
|
|
|
//control
|
|
.ctl_address(ctl_address),
|
|
.ctl_write(ctl_write),
|
|
.ctl_writedata(ctl_writedata),
|
|
.ctl_waitrequest(ctl_waitrequest),
|
|
.ctl_clock(clk_ctl),
|
|
.ctl_reset(ctl_reset),
|
|
|
|
//64-bit DDR3 RAM access
|
|
.ramclk1_clk(ram_clk),
|
|
.ram1_address(ram_address),
|
|
.ram1_burstcount(ram_burstcount),
|
|
.ram1_waitrequest(ram_waitrequest),
|
|
.ram1_readdata(ram_readdata),
|
|
.ram1_readdatavalid(ram_readdatavalid),
|
|
.ram1_read(ram_read),
|
|
.ram1_writedata(ram_writedata),
|
|
.ram1_byteenable(ram_byteenable),
|
|
.ram1_write(ram_write),
|
|
|
|
//Spare 64-bit DDR3 RAM access
|
|
//currently unused
|
|
//can combine with ram1 to make a wider RAM bus (although will increase the latency)
|
|
.ramclk2_clk(0),
|
|
.ram2_address(0),
|
|
.ram2_burstcount(0),
|
|
.ram2_waitrequest(),
|
|
.ram2_readdata(),
|
|
.ram2_readdatavalid(),
|
|
.ram2_read(0),
|
|
.ram2_writedata(0),
|
|
.ram2_byteenable(0),
|
|
.ram2_write(0),
|
|
|
|
//Video input
|
|
.in_clk(clk_vid),
|
|
.in_data({r_out, g_out, b_out}),
|
|
.in_de(de),
|
|
.in_v_sync(vs),
|
|
.in_h_sync(hs),
|
|
.in_ce(ce_pix),
|
|
.in_f(0),
|
|
|
|
//HDMI output
|
|
.hdmi_clk(iHdmiClk),
|
|
.hdmi_data(hdmi_data),
|
|
.hdmi_de(hdmi_de),
|
|
.hdmi_v_sync(HDMI_TX_VS),
|
|
.hdmi_h_sync(HDMI_TX_HS)
|
|
);
|
|
|
|
wire [8:0] ctl_address;
|
|
wire ctl_write;
|
|
wire [31:0] ctl_writedata;
|
|
wire ctl_waitrequest;
|
|
wire ctl_reset;
|
|
wire [7:0] ARX, ARY;
|
|
|
|
vip_config vip_config
|
|
(
|
|
.clk(clk_ctl),
|
|
.reset(ctl_reset),
|
|
|
|
.ARX(ARX),
|
|
.ARY(ARY),
|
|
.CFG_SET(vip_newcfg & cfg_got),
|
|
|
|
.WIDTH(WIDTH),
|
|
.HFP(HFP),
|
|
.HBP(HBP),
|
|
.HS(HS),
|
|
.HEIGHT(HEIGHT),
|
|
.VFP(VFP),
|
|
.VBP(VBP),
|
|
.VS(VS),
|
|
.VSET(VSET),
|
|
|
|
.address(ctl_address),
|
|
.write(ctl_write),
|
|
.writedata(ctl_writedata),
|
|
.waitrequest(ctl_waitrequest)
|
|
);
|
|
`endif
|
|
|
|
|
|
///////////////////////// Lite version ////////////////////////////////
|
|
|
|
`ifdef LITE
|
|
|
|
wire [11:0] x;
|
|
wire [11:0] y;
|
|
|
|
sync_vg #(.X_BITS(12), .Y_BITS(12)) sync_vg
|
|
(
|
|
.clk(iHdmiClk),
|
|
.reset(reset),
|
|
.v_total(HEIGHT+VFP+VBP+VS),
|
|
.v_fp(VFP),
|
|
.v_bp(VBP),
|
|
.v_sync(VS),
|
|
.h_total(WIDTH+HFP+HBP+HS),
|
|
.h_fp(HFP),
|
|
.h_bp(HBP),
|
|
.h_sync(HS),
|
|
.hv_offset(0),
|
|
.vde_out(vde),
|
|
.hde_out(hde),
|
|
.vs_out(vs_hdmi),
|
|
.v_count_out(),
|
|
.h_count_out(),
|
|
.x_out(x),
|
|
.y_out(y),
|
|
.hs_out(hs_hdmi)
|
|
);
|
|
|
|
wire vde, hde;
|
|
wire vs_hdmi;
|
|
wire hs_hdmi;
|
|
|
|
/*
|
|
|
|
pattern_vg
|
|
#(
|
|
.B(8), // Bits per channel
|
|
.X_BITS(12),
|
|
.Y_BITS(12),
|
|
.FRACTIONAL_BITS(12) // Number of fractional bits for ramp pattern
|
|
)
|
|
pattern_vg
|
|
(
|
|
.reset(reset),
|
|
.clk_in(iHdmiClk),
|
|
.x(x),
|
|
.y(y),
|
|
.vn_in(vs_hdmi),
|
|
.hn_in(hs_hdmi),
|
|
.dn_in(vde & hde),
|
|
.r_in(0),
|
|
.g_in(0),
|
|
.b_in(0),
|
|
.vn_out(HDMI_TX_VS),
|
|
.hn_out(HDMI_TX_HS),
|
|
.den_out(HDMI_TX_DE),
|
|
.r_out(hdmi_data[23:16]),
|
|
.g_out(hdmi_data[15:8]),
|
|
.b_out(hdmi_data[7:0]),
|
|
.total_active_pix(WIDTH),
|
|
.total_active_lines(HEIGHT),
|
|
.pattern(4),
|
|
.ramp_step(20'h0333)
|
|
);
|
|
*/
|
|
|
|
wire reset;
|
|
sysmem_lite sysmem
|
|
(
|
|
//Reset/Clock
|
|
.reset_reset_req(reset_req),
|
|
.reset_reset(reset),
|
|
.ctl_clock(clk_ctl),
|
|
|
|
//DE10-nano has no reset signal on GPIO, so core has to emulate cold reset button.
|
|
.reset_cold_req(~btn_reset),
|
|
.reset_warm_req(0),
|
|
|
|
//64-bit DDR3 RAM access
|
|
.ramclk1_clk(ram_clk),
|
|
.ram1_address(ram_address),
|
|
.ram1_burstcount(ram_burstcount),
|
|
.ram1_waitrequest(ram_waitrequest),
|
|
.ram1_readdata(ram_readdata),
|
|
.ram1_readdatavalid(ram_readdatavalid),
|
|
.ram1_read(ram_read),
|
|
.ram1_writedata(ram_writedata),
|
|
.ram1_byteenable(ram_byteenable),
|
|
.ram1_write(ram_write),
|
|
|
|
//Spare 64-bit DDR3 RAM access
|
|
//currently unused
|
|
//can combine with ram1 to make a wider RAM bus (although will increase the latency)
|
|
.ramclk2_clk(0),
|
|
.ram2_address(0),
|
|
.ram2_burstcount(0),
|
|
.ram2_waitrequest(),
|
|
.ram2_readdata(),
|
|
.ram2_readdatavalid(),
|
|
.ram2_read(0),
|
|
.ram2_writedata(0),
|
|
.ram2_byteenable(0),
|
|
.ram2_write(0),
|
|
|
|
// HDMI frame buffer
|
|
.vbuf_clk(clk_ctl),
|
|
.vbuf_address(vbuf_address),
|
|
.vbuf_burstcount(vbuf_burstcount),
|
|
.vbuf_waitrequest(vbuf_waitrequest),
|
|
.vbuf_writedata(vbuf_writedata),
|
|
.vbuf_byteenable(vbuf_byteenable),
|
|
.vbuf_write(vbuf_write),
|
|
.vbuf_readdata(vbuf_readdata),
|
|
.vbuf_readdatavalid(vbuf_readdatavalid),
|
|
.vbuf_read(vbuf_read)
|
|
);
|
|
|
|
wire [27:0] vbuf_address;
|
|
wire [7:0] vbuf_burstcount;
|
|
wire vbuf_waitrequest;
|
|
wire [127:0] vbuf_readdata;
|
|
wire vbuf_readdatavalid;
|
|
wire vbuf_read;
|
|
wire [127:0] vbuf_writedata;
|
|
wire [15:0] vbuf_byteenable;
|
|
wire vbuf_write;
|
|
|
|
assign HDMI_TX_VS = vs_hdmi;
|
|
assign HDMI_TX_HS = hs_hdmi;
|
|
|
|
hdmi_lite hdmi_lite
|
|
(
|
|
.reset(reset),
|
|
|
|
.clk_video(clk_vid),
|
|
.ce_pixel(ce_pix),
|
|
.video_vs(vs),
|
|
.video_de(de),
|
|
.video_d({r_out,g_out,b_out}),
|
|
|
|
.clk_hdmi(HDMI_TX_CLK),
|
|
.hdmi_hde(hde),
|
|
.hdmi_vde(vde),
|
|
.hdmi_d(hdmi_data),
|
|
.hdmi_de(hdmi_de),
|
|
|
|
.screen_w(WIDTH),
|
|
.screen_h(HEIGHT),
|
|
.quadbuf(1),
|
|
.scale_x(0),
|
|
.scale_y(0),
|
|
.scale_auto(1),
|
|
|
|
.clk_vbuf(clk_ctl),
|
|
.vbuf_address(vbuf_address),
|
|
.vbuf_burstcount(vbuf_burstcount),
|
|
.vbuf_waitrequest(vbuf_waitrequest),
|
|
.vbuf_writedata(vbuf_writedata),
|
|
.vbuf_byteenable(vbuf_byteenable),
|
|
.vbuf_write(vbuf_write),
|
|
.vbuf_readdata(vbuf_readdata),
|
|
.vbuf_readdatavalid(vbuf_readdatavalid),
|
|
.vbuf_read(vbuf_read)
|
|
);
|
|
|
|
`endif
|
|
|
|
|
|
///////////////////////// HDMI output /////////////////////////////////
|
|
|
|
pll_hdmi pll_hdmi
|
|
(
|
|
.refclk(FPGA_CLK1_50),
|
|
.rst(reset_req),
|
|
.reconfig_to_pll(reconfig_to_pll),
|
|
.reconfig_from_pll(reconfig_from_pll),
|
|
.outclk_0(HDMI_TX_CLK)
|
|
);
|
|
|
|
//1920x1080@60 PCLK=148.5MHz CEA
|
|
reg [11:0] WIDTH = 1920;
|
|
reg [11:0] HFP = 88;
|
|
reg [11:0] HS = 48;
|
|
reg [11:0] HBP = 148;
|
|
reg [11:0] HEIGHT = 1080;
|
|
reg [11:0] VFP = 4;
|
|
reg [11:0] VS = 5;
|
|
reg [11:0] VBP = 36;
|
|
reg [11:0] VSET = 0;
|
|
|
|
wire [63:0] reconfig_to_pll;
|
|
wire [63:0] reconfig_from_pll;
|
|
wire cfg_waitrequest;
|
|
reg cfg_write;
|
|
reg [5:0] cfg_address;
|
|
reg [31:0] cfg_data;
|
|
|
|
pll_hdmi_cfg pll_hdmi_cfg
|
|
(
|
|
.mgmt_clk(FPGA_CLK1_50),
|
|
.mgmt_reset(reset_req),
|
|
.mgmt_waitrequest(cfg_waitrequest),
|
|
.mgmt_read(0),
|
|
.mgmt_readdata(),
|
|
.mgmt_write(cfg_write),
|
|
.mgmt_address(cfg_address),
|
|
.mgmt_writedata(cfg_data),
|
|
.reconfig_to_pll(reconfig_to_pll),
|
|
.reconfig_from_pll(reconfig_from_pll)
|
|
);
|
|
|
|
reg cfg_ready = 0;
|
|
|
|
always @(posedge FPGA_CLK1_50) begin
|
|
reg gotd = 0, gotd2 = 0;
|
|
reg custd = 0, custd2 = 0;
|
|
reg old_wait = 0;
|
|
|
|
gotd <= cfg_got;
|
|
gotd2 <= gotd;
|
|
|
|
cfg_write <= 0;
|
|
|
|
custd <= cfg_custom_t;
|
|
custd2 <= custd;
|
|
if(custd2 != custd & ~gotd) begin
|
|
cfg_address <= cfg_custom_p1;
|
|
cfg_data <= cfg_custom_p2;
|
|
cfg_write <= 1;
|
|
end
|
|
|
|
if(~gotd2 & gotd) begin
|
|
cfg_address <= 2;
|
|
cfg_data <= 0;
|
|
cfg_write <= 1;
|
|
end
|
|
|
|
old_wait <= cfg_waitrequest;
|
|
if(old_wait & ~cfg_waitrequest & gotd) cfg_ready <= 1;
|
|
end
|
|
|
|
hdmi_config hdmi_config
|
|
(
|
|
.iCLK(FPGA_CLK1_50),
|
|
.iRST_N(cfg_ready & ~HDMI_TX_INT),
|
|
|
|
.I2C_SCL(HDMI_I2C_SCL),
|
|
.I2C_SDA(HDMI_I2C_SDA),
|
|
|
|
.dvi_mode(dvi_mode),
|
|
.audio_96k(audio_96k)
|
|
);
|
|
|
|
wire [23:0] hdmi_data;
|
|
wire hdmi_de;
|
|
|
|
osd hdmi_osd
|
|
(
|
|
.clk_sys(clk_sys),
|
|
|
|
.io_osd(io_osd),
|
|
.io_strobe(io_strobe),
|
|
.io_din(io_din),
|
|
|
|
.clk_video(iHdmiClk),
|
|
.din(hdmi_data),
|
|
.dout(HDMI_TX_D),
|
|
.de_in(hdmi_de),
|
|
.de_out(HDMI_TX_DE)
|
|
);
|
|
|
|
assign HDMI_MCLK = 0;
|
|
i2s i2s
|
|
(
|
|
.reset(~cfg_ready),
|
|
.clk_sys(FPGA_CLK3_50),
|
|
.half_rate(~audio_96k),
|
|
|
|
.sclk(HDMI_SCLK),
|
|
.lrclk(HDMI_LRCLK),
|
|
.sdata(HDMI_I2S),
|
|
|
|
//Could inverse the MSB but it will shift 0 level to -MAX level
|
|
.left_chan (audio_l >> !audio_s),
|
|
.right_chan(audio_r >> !audio_s)
|
|
);
|
|
|
|
|
|
///////////////////////// VGA output //////////////////////////////////
|
|
|
|
wire [23:0] vga_q;
|
|
osd vga_osd
|
|
(
|
|
.clk_sys(clk_sys),
|
|
|
|
.io_osd(io_osd),
|
|
.io_strobe(io_strobe),
|
|
.io_din(io_din),
|
|
|
|
.clk_video(clk_vid),
|
|
.din(de ? {r_out, g_out, b_out} : 24'd0),
|
|
.dout(vga_q),
|
|
.de_in(de)
|
|
);
|
|
|
|
wire [23:0] vga_o;
|
|
|
|
vga_out vga_out
|
|
(
|
|
.ypbpr_full(1),
|
|
.ypbpr_en(ypbpr_en),
|
|
.dout(vga_o),
|
|
`ifdef LITE
|
|
.din(vga_q)
|
|
`else
|
|
.din(vga_scaler ? HDMI_TX_D : vga_q)
|
|
`endif
|
|
);
|
|
|
|
`ifdef LITE
|
|
wire vs1 = vs;
|
|
wire hs1 = hs;
|
|
`else
|
|
wire vs1 = vga_scaler ? HDMI_TX_VS : vs;
|
|
wire hs1 = vga_scaler ? HDMI_TX_HS : hs;
|
|
`endif
|
|
|
|
assign VGA_VS = VGA_EN ? 1'bZ : csync ? 1'b1 : ~vs1;
|
|
assign VGA_HS = VGA_EN ? 1'bZ : csync ? ~(vs1 ^ hs1) : ~hs1;
|
|
assign VGA_R = VGA_EN ? 6'bZZZZZZ : vga_o[23:18];
|
|
assign VGA_G = VGA_EN ? 6'bZZZZZZ : vga_o[15:10];
|
|
assign VGA_B = VGA_EN ? 6'bZZZZZZ : vga_o[7:2];
|
|
|
|
|
|
///////////////////////// Audio output ////////////////////////////////
|
|
|
|
wire al, ar, aspdif;
|
|
|
|
sigma_delta_dac #(15) dac_l
|
|
(
|
|
.CLK(FPGA_CLK3_50),
|
|
.RESET(reset),
|
|
.DACin({audio_l[15] ^ audio_s, audio_l[14:0]}),
|
|
.DACout(al)
|
|
);
|
|
|
|
sigma_delta_dac #(15) dac_r
|
|
(
|
|
.CLK(FPGA_CLK3_50),
|
|
.RESET(reset),
|
|
.DACin({audio_r[15] ^ audio_s, audio_r[14:0]}),
|
|
.DACout(ar)
|
|
);
|
|
|
|
spdif toslink
|
|
(
|
|
.clk_i(FPGA_CLK3_50),
|
|
|
|
.rst_i(reset),
|
|
.half_rate(0),
|
|
|
|
.audio_l(audio_l >> !audio_s),
|
|
.audio_r(audio_r >> !audio_s),
|
|
|
|
.spdif_o(aspdif)
|
|
);
|
|
|
|
assign AUDIO_SPDIF = SW[0] ? HDMI_LRCLK : aspdif;
|
|
assign AUDIO_R = SW[0] ? HDMI_I2S : ar;
|
|
assign AUDIO_L = SW[0] ? HDMI_SCLK : al;
|
|
|
|
reg [15:0] audio_l;
|
|
reg [15:0] audio_r;
|
|
|
|
always @(posedge FPGA_CLK3_50) begin
|
|
reg signed [15:0] al;
|
|
reg signed [15:0] ar;
|
|
|
|
case({audio_s,audio_mix})
|
|
'b000: al <= audio_ls;
|
|
'b001: al <= audio_ls - (audio_ls >> 3) + (audio_rs >> 3);
|
|
'b010: al <= audio_ls - (audio_ls >> 2) + (audio_rs >> 2);
|
|
'b011: al <= (audio_ls >> 1) + (audio_rs >> 1);
|
|
'b100: al <= audio_ls;
|
|
'b101: al <= audio_ls - (audio_ls >>> 3) + (audio_rs >>> 3);
|
|
'b110: al <= audio_ls - (audio_ls >>> 2) + (audio_rs >>> 2);
|
|
'b111: al <= (audio_ls >>> 1) + (audio_rs >>> 1);
|
|
endcase
|
|
|
|
case({audio_s,audio_mix})
|
|
'b000: ar <= audio_rs;
|
|
'b001: ar <= audio_rs - (audio_rs >> 3) + (audio_ls >> 3);
|
|
'b010: ar <= audio_rs - (audio_rs >> 2) + (audio_ls >> 2);
|
|
'b011: ar <= (audio_rs >> 1) + (audio_ls >> 1);
|
|
'b100: ar <= audio_rs;
|
|
'b101: ar <= audio_rs - (audio_rs >>> 3) + (audio_ls >>> 3);
|
|
'b110: ar <= audio_rs - (audio_rs >>> 2) + (audio_ls >>> 2);
|
|
'b111: ar <= (audio_rs >>> 1) + (audio_ls >>> 1);
|
|
endcase
|
|
|
|
if(vol_att[4]) begin
|
|
audio_l <= 0;
|
|
audio_r <= 0;
|
|
end
|
|
else
|
|
if(audio_s) begin
|
|
audio_l <= al >>> vol_att[3:0];
|
|
audio_r <= ar >>> vol_att[3:0];
|
|
end
|
|
else
|
|
begin
|
|
audio_l <= al >> vol_att[3:0];
|
|
audio_r <= ar >> vol_att[3:0];
|
|
end
|
|
end
|
|
|
|
/////////////////// User module connection ////////////////////////////
|
|
|
|
wire signed [15:0] audio_ls, audio_rs;
|
|
wire audio_s;
|
|
wire [1:0] audio_mix;
|
|
wire [7:0] r_out, g_out, b_out;
|
|
wire vs, hs, de;
|
|
wire clk_sys, clk_vid, ce_pix;
|
|
|
|
wire ram_clk;
|
|
wire [28:0] ram_address;
|
|
wire [7:0] ram_burstcount;
|
|
wire ram_waitrequest;
|
|
wire [63:0] ram_readdata;
|
|
wire ram_readdatavalid;
|
|
wire ram_read;
|
|
wire [63:0] ram_writedata;
|
|
wire [7:0] ram_byteenable;
|
|
wire ram_write;
|
|
|
|
wire led_user;
|
|
wire [1:0] led_power;
|
|
wire [1:0] led_disk;
|
|
|
|
wire vs_emu, hs_emu;
|
|
sync_fix sync_v(FPGA_CLK3_50, vs_emu, vs);
|
|
sync_fix sync_h(FPGA_CLK3_50, hs_emu, hs);
|
|
|
|
emu emu
|
|
(
|
|
.CLK_50M(FPGA_CLK3_50),
|
|
.RESET(reset),
|
|
.HPS_BUS({HDMI_TX_VS, clk_ctl, clk_vid, ce_pix, de, hs, vs, io_wait, clk_sys, io_fpga, io_uio, io_strobe, io_wide, io_din, io_dout}),
|
|
|
|
.CLK_VIDEO(clk_vid),
|
|
.CE_PIXEL(ce_pix),
|
|
|
|
.VGA_R(r_out),
|
|
.VGA_G(g_out),
|
|
.VGA_B(b_out),
|
|
.VGA_HS(hs_emu),
|
|
.VGA_VS(vs_emu),
|
|
.VGA_DE(de),
|
|
|
|
.LED_USER(led_user),
|
|
.LED_POWER(led_power),
|
|
.LED_DISK(led_disk),
|
|
|
|
`ifndef LITE
|
|
.VIDEO_ARX(ARX),
|
|
.VIDEO_ARY(ARY),
|
|
`endif
|
|
|
|
.AUDIO_L(audio_ls),
|
|
.AUDIO_R(audio_rs),
|
|
.AUDIO_S(audio_s),
|
|
.AUDIO_MIX(audio_mix),
|
|
.TAPE_IN(0),
|
|
|
|
// SCK -> CLK
|
|
// MOSI -> CMD
|
|
// MISO <- DAT0
|
|
// Z -> DAT1
|
|
// Z -> DAT2
|
|
// CS -> DAT3
|
|
.SD_SCK(SDIO_CLK),
|
|
.SD_MOSI(SDIO_CMD),
|
|
.SD_MISO(SDIO_DAT[0]),
|
|
.SD_CS(SDIO_DAT[3]),
|
|
.SD_CD(VGA_EN ? VGA_HS : SDIO_CD),
|
|
|
|
.DDRAM_CLK(ram_clk),
|
|
.DDRAM_ADDR(ram_address),
|
|
.DDRAM_BURSTCNT(ram_burstcount),
|
|
.DDRAM_BUSY(ram_waitrequest),
|
|
.DDRAM_DOUT(ram_readdata),
|
|
.DDRAM_DOUT_READY(ram_readdatavalid),
|
|
.DDRAM_RD(ram_read),
|
|
.DDRAM_DIN(ram_writedata),
|
|
.DDRAM_BE(ram_byteenable),
|
|
.DDRAM_WE(ram_write),
|
|
|
|
.SDRAM_DQ(SDRAM_DQ),
|
|
.SDRAM_A(SDRAM_A),
|
|
.SDRAM_DQML(SDRAM_DQML),
|
|
.SDRAM_DQMH(SDRAM_DQMH),
|
|
.SDRAM_BA(SDRAM_BA),
|
|
.SDRAM_nCS(SDRAM_nCS),
|
|
.SDRAM_nWE(SDRAM_nWE),
|
|
.SDRAM_nRAS(SDRAM_nRAS),
|
|
.SDRAM_nCAS(SDRAM_nCAS),
|
|
.SDRAM_CLK(SDRAM_CLK),
|
|
.SDRAM_CKE(SDRAM_CKE)
|
|
);
|
|
|
|
endmodule
|
|
|
|
module sync_fix
|
|
(
|
|
input clk,
|
|
|
|
input sync_in,
|
|
output sync_out
|
|
);
|
|
|
|
assign sync_out = sync_in ^ pol;
|
|
|
|
reg pol;
|
|
always @(posedge clk) begin
|
|
integer pos = 0, neg = 0, cnt = 0;
|
|
reg s1,s2;
|
|
|
|
s1 <= sync_in;
|
|
s2 <= s1;
|
|
|
|
if(~s2 & s1) neg <= cnt;
|
|
if(s2 & ~s1) pos <= cnt;
|
|
|
|
cnt <= cnt + 1;
|
|
if(s2 != s1) cnt <= 0;
|
|
|
|
pol <= pos > neg;
|
|
end
|
|
|
|
endmodule
|