diff --git a/MacPlus.sv b/MacPlus.sv index 4fee853..0f8922d 100644 --- a/MacPlus.sv +++ b/MacPlus.sv @@ -58,6 +58,11 @@ module emu // hint: supply 2'b00 to let the system control the LED. output [1:0] LED_POWER, output [1:0] LED_DISK, + + // I/O board button press simulation (active high) + // b[1]: user button + // b[0]: osd button + output [1:0] BUTTONS, output [15:0] AUDIO_L, output [15:0] AUDIO_R, @@ -67,7 +72,7 @@ module emu //ADC inout [3:0] ADC_BUS, - // SD-SPI + //SD-SPI output SD_SCK, output SD_MOSI, input SD_MISO, @@ -110,10 +115,10 @@ module emu // Open-drain User port. // 0 - D+/RX // 1 - D-/TX - // 2..5 - USR1..USR4 + // 2..6 - USR2..USR6 // Set USER_OUT to 1 to read from USER_IN. - input [5:0] USER_IN, - output [5:0] USER_OUT, + input [6:0] USER_IN, + output [6:0] USER_OUT, input OSD_STATUS ); @@ -127,6 +132,7 @@ assign {SD_SCK, SD_MOSI, SD_CS} = 'Z; assign LED_USER = dio_download || (disk_act ^ |diskMotor); assign LED_DISK = 0; assign LED_POWER = 0; +assign BUTTONS = 0; assign VIDEO_ARX = status[8] ? 8'd16 : 8'd4; assign VIDEO_ARY = status[8] ? 8'd9 : 8'd3; diff --git a/sys/hdmi_config.sv b/sys/hdmi_config.sv index 8cbad8b..775a560 100644 --- a/sys/hdmi_config.sv +++ b/sys/hdmi_config.sv @@ -2,12 +2,14 @@ module hdmi_config ( // Host Side - input iCLK, - input iRST_N, + input iCLK, + input iRST_N, input dvi_mode, input audio_96k, - input hdmi_limited, + input [1:0] limited, + input ypbpr, + output reg done, // I2C Side @@ -26,13 +28,17 @@ i2c #(50_000_000, 20_000) i2c_av ( .CLK(iCLK), - .I2C_SCL(I2C_SCL), // I2C CLOCK - .I2C_SDA(I2C_SDA), // I2C DATA + .I2C_SCL(I2C_SCL), // I2C CLOCK + .I2C_SDA(I2C_SDA), // I2C DATA - .I2C_DATA({8'h72,init_data[LUT_INDEX]}), // DATA:[SLAVE_ADDR,SUB_ADDR,DATA]. 0x72 is the Slave Address of the ADV7513 chip! - .START(mI2C_GO), // START transfer - .END(mI2C_END), // END transfer - .ACK(mI2C_ACK) // ACK + .I2C_ADDR('h39), // 0x39 is the Slave Address of the ADV7513 chip! + .I2C_WLEN(1), + .I2C_WDATA1(init_data[LUT_INDEX][15:8]), // SUB_ADDR + .I2C_WDATA2(init_data[LUT_INDEX][7:0]), // DATA + .START(mI2C_GO), // START transfer + .READ(0), + .END(mI2C_END), // END transfer + .ACK(mI2C_ACK) // ACK ); ////////////////////// Config Control //////////////////////////// @@ -105,34 +111,32 @@ wire [15:0] init_data[82] = {8'h17, 8'b01100010}, // Aspect ratio 16:9 [1]=1, 4:3 [1]=0 - {8'h18, hdmi_limited, // CSC enable [7]. 0 - Off. 1 - On. - 7'h0D}, // CSC Scaling Factors and Coefficients for RGB Full->Limited. - {8'h19, 8'hBC}, // Taken from table in ADV7513 Programming Guide. - {8'h1A, 8'h00}, // CSC Channel A. - {8'h1B, 8'h00}, - {8'h1C, 8'h00}, - {8'h1D, 8'h00}, - {8'h1E, 8'h01}, + {8'h18, ypbpr ? 8'h88 : limited[0] ? 8'h8D : limited[1] ? 8'h8E : 8'h00}, // CSC Scaling Factors and Coefficients for RGB Full->Limited. + {8'h19, ypbpr ? 8'h2E : limited[0] ? 8'hBC : 8'hFE}, // Taken from table in ADV7513 Programming Guide. + {8'h1A, ypbpr ? 8'h18 : 8'h00}, // CSC Channel A. + {8'h1B, ypbpr ? 8'h93 : 8'h00}, + {8'h1C, ypbpr ? 8'h1F : 8'h00}, + {8'h1D, ypbpr ? 8'h3F : 8'h00}, + {8'h1E, ypbpr ? 8'h08 : 8'h01}, {8'h1F, 8'h00}, - - {8'h20, 8'h00}, // CSC Channel B. - {8'h21, 8'h00}, - {8'h22, 8'h0D}, - {8'h23, 8'hBC}, - {8'h24, 8'h00}, - {8'h25, 8'h00}, - {8'h26, 8'h01}, + + {8'h20, ypbpr ? 8'h03 : 8'h00}, // CSC Channel B. + {8'h21, ypbpr ? 8'h67 : 8'h00}, + {8'h22, ypbpr ? 8'h0B : limited[0] ? 8'h0D : 8'h0E}, + {8'h23, ypbpr ? 8'h71 : limited[0] ? 8'hBC : 8'hFE}, + {8'h24, ypbpr ? 8'h01 : 8'h00}, + {8'h25, ypbpr ? 8'h28 : 8'h00}, + {8'h26, ypbpr ? 8'h00 : 8'h01}, {8'h27, 8'h00}, - - {8'h28, 8'h00}, // CSC Channel C. - {8'h29, 8'h00}, - {8'h2A, 8'h00}, - {8'h2B, 8'h00}, - {8'h2C, 8'h0D}, - {8'h2D, 8'hBC}, - {8'h2E, 8'h01}, + + {8'h28, ypbpr ? 8'h1E : 8'h00}, // CSC Channel C. + {8'h29, ypbpr ? 8'h21 : 8'h00}, + {8'h2A, ypbpr ? 8'h19 : 8'h00}, + {8'h2B, ypbpr ? 8'hB2 : 8'h00}, + {8'h2C, ypbpr ? 8'h08 : limited[0] ? 8'h0D : 8'h0E}, + {8'h2D, ypbpr ? 8'h2D : limited[0] ? 8'hBC : 8'hFE}, + {8'h2E, ypbpr ? 8'h08 : 8'h01}, {8'h2F, 8'h00}, - {8'h3B, 8'b0000_0000}, // Pixel repetition [6:5] b00 AUTO. [4:3] b00 x1 mult of input clock. [2:1] b00 x1 pixel rep to send to HDMI Rx. @@ -152,7 +156,7 @@ wire [15:0] init_data[82] = {8'h57, 1'b0, // [7] IT Content. 0 - No. 1 - Yes (type set in register h59). 3'b000, // [6:4] Color space (ignored for RGB) - hdmi_limited ? 2'b01 : 2'b10, // [3:2] RGB Quantization range + (ypbpr | limited) ? 2'b01 : 2'b10, // [3:2] RGB Quantization range 2'b00}, // [1:0] Non-Uniform Scaled: 00 - None. 01 - Horiz. 10 - Vert. 11 - Both. 16'h7301, diff --git a/sys/hps_io.v b/sys/hps_io.v index 013ac75..d4d87cb 100644 --- a/sys/hps_io.v +++ b/sys/hps_io.v @@ -1,10 +1,8 @@ // // hps_io.v // -// mist_io-like module for MiSTer -// // Copyright (c) 2014 Till Harbaum -// Copyright (c) 2017,2018 Sorgelig +// Copyright (c) 2017-2019 Alexey Melnikov // // This source file is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published @@ -83,16 +81,21 @@ module hps_io #(parameter STRLEN=0, PS2DIV=0, WIDE=0, VDNUM=1, PS2WE=0) output reg [DW:0] sd_buff_dout, input [DW:0] sd_buff_din, output reg sd_buff_wr, + input [15:0] sd_req_type, // ARM -> FPGA download output reg ioctl_download = 0, // signal indicating an active download output reg [7:0] ioctl_index, // menu index used to upload the file output reg ioctl_wr, - output reg [24:0] ioctl_addr, // in WIDE mode address will be incremented by 2 + output reg [26:0] ioctl_addr, // in WIDE mode address will be incremented by 2 output reg [DW:0] ioctl_dout, output reg [31:0] ioctl_file_ext, input ioctl_wait, + // [15]: 0 - unset, 1 - set. [1:0]: 0 - none, 1 - 32MB, 2 - 64MB, 3 - 128MB + // [14]: debug mode: [8]: 1 - phase up, 0 - phase down. [7:0]: amount of shift. + output reg [15:0] sdram_sz, + // RTC MSM6242B layout output reg [64:0] RTC, @@ -199,7 +202,7 @@ always @(posedge clk_vid) begin if(old_vs & ~vs) begin vid_int <= {vid_int[0],f1}; - if(~f1) begin + if(~f1) begin if(hcnt && vcnt) begin old_vmode <= new_vmode; @@ -390,6 +393,7 @@ always@(posedge clk_sys) begin 1: io_dout <= sd_cmd; 2: io_dout <= sd_lba[15:0]; 3: io_dout <= sd_lba[31:16]; + 4: io_dout <= sd_req_type; endcase // send SD config IO -> FPGA @@ -486,6 +490,9 @@ always@(posedge clk_sys) begin //menu mask 'h2E: if(byte_cnt == 1) io_dout <= status_menumask; + + //sdram size set + 'h31: if(byte_cnt == 1) sdram_sz <= io_din; endcase end end @@ -571,7 +578,7 @@ always@(posedge clk_sys) begin reg [15:0] cmd; reg [2:0] cnt; reg has_cmd; - reg [24:0] addr; + reg [26:0] addr; reg wr; ioctl_wr <= wr; @@ -769,3 +776,91 @@ always@(posedge clk_sys) begin end endmodule + +// +// Phase shift helper module for better 64MB/128MB modules support. +// +// Copyright (c) 2019 Alexey Melnikov +// + +module phase_shift #(parameter M32MB=0, M64MB=0, M128MB=0) +( + input reset, + + input clk, + input pll_locked, + + output reg phase_en, + output reg updn, + input phase_done, + + input [15:0] sdram_sz, + output reg ready +); + +localparam ph32 = ($signed(M32MB ) >= 0) ? M32MB : (0 - M32MB); +localparam ph64 = ($signed(M64MB ) >= 0) ? M64MB : (0 - M64MB); +localparam ph128 = ($signed(M128MB) >= 0) ? M128MB : (0 - M128MB); + +localparam up32 = ($signed(M32MB ) >= 0) ? 1'b1 : 1'b0; +localparam up64 = ($signed(M64MB ) >= 0) ? 1'b1 : 1'b0; +localparam up128 = ($signed(M128MB) >= 0) ? 1'b1 : 1'b0; + +always @(posedge clk, posedge reset) begin + reg [2:0] state = 0; + reg [7:0] cnt; + reg [8:0] ph; + + if(reset) begin + state <= 0; + ready <= 0; + end + else begin + case(state) + 0: begin + ready <= 0; + if(pll_locked) state <= state + 1'd1; + end + 1: if(sdram_sz[15]) begin + cnt <= 0; + if(sdram_sz[14]) ph <= sdram_sz[8:0]; + else begin + case(sdram_sz[1:0]) + 0: ph <= 0; + 1: ph <= {up32[0],ph32[7:0]}; + 2: ph <= {up64[0],ph64[7:0]}; + 3: ph <= {up128[0],ph128[7:0]}; + endcase + end + state <= state + 1'd1; + end + 2: if(ph[7:0]) begin + ph[7:0] <= ph[7:0] - 1'd1; + updn <= ph[8]; + state <= state + 1'd1; + end + else begin + state <= 6; + end + 3: begin + phase_en <= 1; + state <= state + 1'd1; + end + 4: if(~phase_done) begin + phase_en <= 0; + state <= state + 1'd1; + end + 5: if(phase_done) begin + cnt <= cnt + 1'd1; + if(cnt == ph[7:0]) state <= state + 1'd1; + else state <= 3; + end + 6: begin + ready <= 1; + if(!sdram_sz[15]) state <= 0; + end + endcase + end +end + +endmodule diff --git a/sys/i2c.v b/sys/i2c.v index ace6293..d6d59d9 100644 --- a/sys/i2c.v +++ b/sys/i2c.v @@ -4,7 +4,12 @@ module i2c input CLK, input START, - input [23:0] I2C_DATA, + input READ, + input [6:0] I2C_ADDR, + input I2C_WLEN, // 0 - one byte, 1 - two bytes + input [7:0] I2C_WDATA1, + input [7:0] I2C_WDATA2, + output [7:0] I2C_RDATA, output reg END = 1, output reg ACK = 0, @@ -18,51 +23,73 @@ module i2c parameter CLK_Freq = 50_000_000; // 50 MHz parameter I2C_Freq = 400_000; // 400 KHz -reg I2C_CLOCK; -always@(negedge CLK) begin - integer mI2C_CLK_DIV = 0; - if(mI2C_CLK_DIV < (CLK_Freq/I2C_Freq)) begin - mI2C_CLK_DIV <= mI2C_CLK_DIV + 1; - end else begin - mI2C_CLK_DIV <= 0; - I2C_CLOCK <= ~I2C_CLOCK; +localparam I2C_FreqX2 = I2C_Freq*2; + +reg I2C_CLOCK; +reg [31:0] cnt; +wire [31:0] cnt_next = cnt + I2C_FreqX2; + +always @(posedge CLK) begin + cnt <= cnt_next; + if(cnt_next >= CLK_Freq) begin + cnt <= cnt_next - CLK_Freq; + I2C_CLOCK <= ~I2C_CLOCK; end end assign I2C_SCL = SCLK | I2C_CLOCK; -assign I2C_SDA = SDO ? 1'bz : 1'b0; +assign I2C_SDA = SDO[3] ? 1'bz : 1'b0; -reg SCLK = 1, SDO = 1; +reg SCLK = 1; +reg [3:0] SDO = 4'b1111; +reg [0:7] rdata; + +assign I2C_RDATA = rdata; always @(posedge CLK) begin reg old_clk; reg old_st; + reg rd,len; reg [5:0] SD_COUNTER = 'b111111; reg [0:31] SD; old_clk <= I2C_CLOCK; old_st <= START; + + // delay to make sure SDA changed while SCL is stabilized at low + if(old_clk && ~I2C_CLOCK && ~SD_COUNTER[5]) SDO[0] <= SD[SD_COUNTER[4:0]]; + SDO[3:1] <= SDO[2:0]; if(~old_st && START) begin SCLK <= 1; - SDO <= 1; + SDO <= 4'b1111; ACK <= 0; END <= 0; - SD <= {2'b10, I2C_DATA[23:16], 1'b1, I2C_DATA[15:8], 1'b1, I2C_DATA[7:0], 4'b1011}; + rd <= READ; + len <= I2C_WLEN; + if(READ) SD <= {2'b10, I2C_ADDR, 1'b1, 1'b1, 8'b11111111, 1'b0, 3'b011, 9'b111111111}; + else SD <= {2'b10, I2C_ADDR, 1'b0, 1'b1, I2C_WDATA1, 1'b1, I2C_WDATA2, 4'b1011}; SD_COUNTER <= 0; end else begin if(~old_clk && I2C_CLOCK && ~&SD_COUNTER) begin SD_COUNTER <= SD_COUNTER + 6'd1; case(SD_COUNTER) - 01: SCLK <= 0; - 10,19,28: ACK <= ACK | I2C_SDA; - 29: SCLK <= 1; - 32: END <= 1; + 01: SCLK <= 0; + 10: ACK <= ACK | I2C_SDA; + 19: if(~rd) begin + ACK <= ACK | I2C_SDA; + if(~len) SD_COUNTER <= 29; + end + 20: if(rd) SCLK <= 1; + 23: if(rd) END <= 1; + 28: if(~rd) ACK <= ACK | I2C_SDA; + 29: if(~rd) SCLK <= 1; + 32: if(~rd) END <= 1; endcase - end - if(old_clk && ~I2C_CLOCK && ~SD_COUNTER[5]) SDO <= SD[SD_COUNTER[4:0]]; + if(SD_COUNTER >= 11 && SD_COUNTER <= 18) rdata[SD_COUNTER[4:0]-11] <= I2C_SDA; + end end end diff --git a/sys/mcp23009.sv b/sys/mcp23009.sv new file mode 100644 index 0000000..40cbf5e --- /dev/null +++ b/sys/mcp23009.sv @@ -0,0 +1,113 @@ +// +// MCP23009 +// (C) 2019 Alexey Melnikov +// +module mcp23009 +( + input clk, + + output reg [2:0] btn, + input [2:0] led, + output reg sd_cd, + + output scl, + inout sda +); + + +reg start = 0; +wire ready; +wire error; +reg rw; +wire [7:0] dout; +reg [15:0] din; + +i2c #(50_000_000, 500_000) i2c +( + .CLK(clk), + .START(start), + .READ(rw), + .I2C_ADDR('h20), + .I2C_WLEN(1), + .I2C_WDATA1(din[15:8]), + .I2C_WDATA2(din[7:0]), + .I2C_RDATA(dout), + .END(ready), + .ACK(error), + .I2C_SCL(scl), + .I2C_SDA(sda) +); + +always@(posedge clk) begin + reg [3:0] idx = 0; + reg [1:0] state = 0; + reg [15:0] timeout = 0; + + if(~&timeout) begin + timeout <= timeout + 1'd1; + start <= 0; + state <= 0; + idx <= 0; + btn <= 0; + rw <= 0; + sd_cd <= 1; + end + else begin + if(~&init_data[idx]) begin + case(state) + 0: begin + start <= 1; + state <= 1; + din <= init_data[idx]; + end + 1: if(~ready) state <= 2; + 2: begin + start <= 0; + if(ready) begin + state <= 0; + if(!error) idx <= idx + 1'd1; + end + end + endcase + end + else begin + case(state) + 0: begin + start <= 1; + state <= 1; + din <= {8'h09,5'b00000,led}; + end + 1: if(~ready) state <= 2; + 2: begin + start <= 0; + if(ready) begin + state <= 0; + rw <= 0; + if(!error) begin + if(rw) {sd_cd, btn} <= {dout[7], dout[5:3]}; + rw <= ~rw; + end + end + end + endcase + end + end +end + +wire [15:0] init_data[12] = +'{ + 16'h00F8, + 16'h0138, + 16'h0200, + 16'h0300, + 16'h0400, + 16'h0524, + 16'h06FF, + 16'h0700, + 16'h0800, + 16'h0900, + 16'h0A00, + 16'hFFFF +}; + +endmodule diff --git a/sys/osd.v b/sys/osd.v index 5c1fb04..b564a26 100644 --- a/sys/osd.v +++ b/sys/osd.v @@ -4,16 +4,20 @@ module osd ( input clk_sys, - input io_osd, input io_strobe, input [15:0] io_din, input clk_video, input [23:0] din, - output [23:0] dout, input de_in, + input vs_in, + input hs_in, + output [23:0] dout, output reg de_out, + output reg vs_out, + output reg hs_out, + output reg osd_status ); @@ -143,6 +147,7 @@ always @(posedge clk_video) begin reg [21:0] osd_hcnt; reg osd_de1,osd_de2; reg [1:0] osd_en; + reg f1; if(ce_pix) begin @@ -168,28 +173,31 @@ always @(posedge clk_video) begin if(h_cnt > {dsp_width, 2'b00}) begin v_cnt <= 1; + f1 <= ~f1; // skip every other frame for interlace compatibility. + if(~f1) begin - osd_en <= (osd_en << 1) | osd_enable; - if(~osd_enable) osd_en <= 0; + osd_en <= (osd_en << 1) | osd_enable; + if(~osd_enable) osd_en <= 0; - if(v_cnt_below320) begin - multiscan <= 0; - v_osd_start <= info ? infoy : v_osd_start_320; - end - else if(v_cnt_below640) begin - multiscan <= 1; - v_osd_start <= info ? (infoy<<1) : v_osd_start_640; - end - else if(v_cnt_below960) begin - multiscan <= 2; - v_osd_start <= info ? (infoy + (infoy << 1)) : v_osd_start_960; - end - else begin - multiscan <= 3; - v_osd_start <= info ? (infoy<<2) : v_osd_start_other; + if(v_cnt_below320) begin + multiscan <= 0; + v_osd_start <= info ? infoy : v_osd_start_320; + end + else if(v_cnt_below640) begin + multiscan <= 1; + v_osd_start <= info ? (infoy<<1) : v_osd_start_640; + end + else if(v_cnt_below960) begin + multiscan <= 2; + v_osd_start <= info ? (infoy + (infoy << 1)) : v_osd_start_960; + end + else begin + multiscan <= 3; + v_osd_start <= info ? (infoy<<2) : v_osd_start_other; + end end end - + osd_div <= osd_div + 1'd1; if(osd_div == multiscan) begin osd_div <= 0; @@ -208,19 +216,30 @@ end reg [23:0] rdout; assign dout = rdout; -reg [23:0] osd_rdout, normal_rdout; -reg osd_mux; -reg de_dly; - always @(posedge clk_video) begin - normal_rdout <= din; - osd_rdout <= {{osd_pixel, osd_pixel, OSD_COLOR[2], din[23:19]},// 23:16 - {osd_pixel, osd_pixel, OSD_COLOR[1], din[15:11]},// 15:8 - {osd_pixel, osd_pixel, OSD_COLOR[0], din[7:3]}}; // 7:0 + reg [23:0] ordout1, nrdout1, rdout2, rdout3; + reg de1,de2,de3; + reg osd_mux; + reg vs1,vs2,vs3; + reg hs1,hs2,hs3; + + nrdout1 <= din; + ordout1 <= {{osd_pixel, osd_pixel, OSD_COLOR[2], din[23:19]},// 23:16 + {osd_pixel, osd_pixel, OSD_COLOR[1], din[15:11]},// 15:8 + {osd_pixel, osd_pixel, OSD_COLOR[0], din[7:3]}}; // 7:0 + osd_mux <= ~osd_de[2]; - rdout <= osd_mux ? normal_rdout : osd_rdout; - de_dly <= de_in; - de_out <= de_dly; + rdout2 <= osd_mux ? nrdout1 : ordout1; + rdout3 <= rdout2; + + de1 <= de_in; de2 <= de1; de3 <= de2; + hs1 <= hs_in; hs2 <= hs1; hs3 <= hs2; + vs1 <= vs_in; vs2 <= vs1; vs3 <= vs2; + + rdout <= rdout3; + de_out <= de3; + hs_out <= hs3; + vs_out <= vs3; end endmodule diff --git a/sys/scanlines.v b/sys/scanlines.v index 96aa6e3..59d29bd 100644 --- a/sys/scanlines.v +++ b/sys/scanlines.v @@ -1,52 +1,67 @@ module scanlines #(parameter v2=0) ( - input clk, + input clk, input [1:0] scanlines, input [23:0] din, + input hs_in,vs_in, + input de_in, + output reg [23:0] dout, - input hs,vs + output reg hs_out,vs_out, + output reg de_out ); reg [1:0] scanline; always @(posedge clk) begin reg old_hs, old_vs; - old_hs <= hs; - old_vs <= vs; + old_hs <= hs_in; + old_vs <= vs_in; - if(old_hs && ~hs) begin + if(old_hs && ~hs_in) begin if(v2) begin scanline <= scanline + 1'd1; if (scanline == scanlines) scanline <= 0; end else scanline <= scanline ^ scanlines; end - if(old_vs && ~vs) scanline <= 0; + if(old_vs && ~vs_in) scanline <= 0; end wire [7:0] r,g,b; assign {r,g,b} = din; +reg [23:0] d; always @(*) begin case(scanline) 1: // reduce 25% = 1/2 + 1/4 - dout = {{1'b0, r[7:1]} + {2'b00, r[7:2]}, - {1'b0, g[7:1]} + {2'b00, g[7:2]}, - {1'b0, b[7:1]} + {2'b00, b[7:2]}}; + d = {{1'b0, r[7:1]} + {2'b00, r[7:2]}, + {1'b0, g[7:1]} + {2'b00, g[7:2]}, + {1'b0, b[7:1]} + {2'b00, b[7:2]}}; 2: // reduce 50% = 1/2 - dout = {{1'b0, r[7:1]}, - {1'b0, g[7:1]}, - {1'b0, b[7:1]}}; + d = {{1'b0, r[7:1]}, + {1'b0, g[7:1]}, + {1'b0, b[7:1]}}; 3: // reduce 75% = 1/4 - dout = {{2'b00, r[7:2]}, - {2'b00, g[7:2]}, - {2'b00, b[7:2]}}; + d = {{2'b00, r[7:2]}, + {2'b00, g[7:2]}, + {2'b00, b[7:2]}}; - default: dout = {r,g,b}; + default: d = {r,g,b}; endcase end +always @(posedge clk) begin + reg [23:0] dout1, dout2; + reg de1,de2,vs1,vs2,hs1,hs2; + + dout <= dout2; dout2 <= dout1; dout1 <= d; + vs_out <= vs2; vs2 <= vs1; vs1 <= vs_in; + hs_out <= hs2; hs2 <= hs1; hs1 <= hs_in; + de_out <= de2; de2 <= de1; de1 <= de_in; +end + endmodule diff --git a/sys/sys.qip b/sys/sys.qip index a67123e..6a5d6b6 100644 --- a/sys/sys.qip +++ b/sys/sys.qip @@ -19,6 +19,7 @@ set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) a set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) ltc2308.sv ] set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) sigma_delta_dac.v ] set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) hdmi_config.sv ] +set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) mcp23009.sv ] set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) sysmem.sv ] set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) sd_card.v ] set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) hps_io.v ] diff --git a/sys/sys.tcl b/sys/sys.tcl index d976d0e..0be58d1 100644 --- a/sys/sys.tcl +++ b/sys/sys.tcl @@ -19,16 +19,23 @@ set_location_assignment PIN_AD4 -to ADC_SDO #============================================================ # ARDUINO #============================================================ -set_location_assignment PIN_AG9 -to ARDUINO_IO[3] -set_location_assignment PIN_U14 -to ARDUINO_IO[4] -set_location_assignment PIN_U13 -to ARDUINO_IO[5] set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to ARDUINO_IO[*] set_instance_assignment -name WEAK_PULL_UP_RESISTOR ON -to ARDUINO_IO[*] set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to ARDUINO_IO[*] +#============================================================ +# I2C LEDS/BUTTONS +#============================================================ +set_location_assignment PIN_U14 -to IO_SCL +set_location_assignment PIN_AG9 -to IO_SDA +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to IO_S* +set_instance_assignment -name WEAK_PULL_UP_RESISTOR ON -to IO_S* +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to IO_S* + #============================================================ # USER PORT #============================================================ +set_location_assignment PIN_AF17 -to USER_IO[6] set_location_assignment PIN_AF15 -to USER_IO[5] set_location_assignment PIN_AG16 -to USER_IO[4] set_location_assignment PIN_AH11 -to USER_IO[3] @@ -43,9 +50,7 @@ set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to USER_IO # SDIO_CD or SPDIF_OUT #============================================================ set_location_assignment PIN_AH7 -to SDCD_SPDIF - set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDCD_SPDIF - set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDCD_SPDIF set_instance_assignment -name WEAK_PULL_UP_RESISTOR ON -to SDCD_SPDIF @@ -67,7 +72,6 @@ set_location_assignment PIN_AD17 -to SDRAM_A[11] set_location_assignment PIN_D12 -to SDRAM_A[12] set_location_assignment PIN_Y17 -to SDRAM_BA[0] set_location_assignment PIN_AB25 -to SDRAM_BA[1] - set_location_assignment PIN_E8 -to SDRAM_DQ[0] set_location_assignment PIN_V12 -to SDRAM_DQ[1] set_location_assignment PIN_D11 -to SDRAM_DQ[2] @@ -86,10 +90,8 @@ set_location_assignment PIN_AF4 -to SDRAM_DQ[14] set_location_assignment PIN_AH3 -to SDRAM_DQ[15] set_location_assignment PIN_AG13 -to SDRAM_DQML set_location_assignment PIN_AF13 -to SDRAM_DQMH - set_location_assignment PIN_AD20 -to SDRAM_CLK set_location_assignment PIN_AG10 -to SDRAM_CKE - set_location_assignment PIN_AA19 -to SDRAM_nWE set_location_assignment PIN_AA18 -to SDRAM_nCAS set_location_assignment PIN_Y18 -to SDRAM_nCS @@ -106,18 +108,15 @@ set_instance_assignment -name FAST_OUTPUT_ENABLE_REGISTER ON -to SDRAM_DQ[*] set_instance_assignment -name ALLOW_SYNCH_CTRL_USAGE OFF -to *|SDRAM_* #============================================================ -# I/O #2 +# SPI SD #============================================================ -set_location_assignment PIN_AG8 -to BTNLED[0] -set_location_assignment PIN_AH8 -to BTNLED[1] -set_location_assignment PIN_AF17 -to BTNLED[2] -set_location_assignment PIN_AE15 -to BTNLED[3] - -set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to BTNLED[*] -set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to BTNLED[*] -set_instance_assignment -name FAST_OUTPUT_ENABLE_REGISTER ON -to BTNLED[*] -set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to BTNLED[*] -set_instance_assignment -name WEAK_PULL_UP_RESISTOR ON -to BTNLED[*] +set_location_assignment PIN_AE15 -to SD_SPI_CS +set_location_assignment PIN_AH8 -to SD_SPI_MISO +set_location_assignment PIN_AG8 -to SD_SPI_CLK +set_location_assignment PIN_U13 -to SD_SPI_MOSI +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SD_SPI* +set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SD_SPI* +set_instance_assignment -name WEAK_PULL_UP_RESISTOR ON -to SD_SPI* #============================================================ @@ -246,6 +245,7 @@ set_location_assignment PIN_W20 -to SW[3] set_instance_assignment -name HPS_LOCATION HPSINTERFACEPERIPHERALSPIMASTER_X52_Y72_N111 -entity sys_top -to spi set_instance_assignment -name HPS_LOCATION HPSINTERFACEPERIPHERALUART_X52_Y67_N111 -entity sys_top -to uart +set_location_assignment FRACTIONALPLL_X89_Y1_N0 -to emu:emu|pll:pll|pll_0002:pll_inst|altera_pll:altera_pll_i|altera_cyclonev_pll:cyclonev_pll|altera_cyclonev_pll_base:fpll_0|fpll set_global_assignment -name PRE_FLOW_SCRIPT_FILE "quartus_sh:sys/build_id.tcl" diff --git a/sys/sys_top.sdc b/sys/sys_top.sdc index c253d88..90d943d 100644 --- a/sys/sys_top.sdc +++ b/sys/sys_top.sdc @@ -3,7 +3,7 @@ create_clock -period "50.0 MHz" [get_ports FPGA_CLK1_50] create_clock -period "50.0 MHz" [get_ports FPGA_CLK2_50] create_clock -period "50.0 MHz" [get_ports FPGA_CLK3_50] create_clock -period "100.0 MHz" [get_pins -compatibility_mode *|h2f_user0_clk] -create_clock -period 10.0 [get_pins -compatibility_mode spi|sclk_out] -name spi_sck +create_clock -period "100.0 MHz" [get_pins -compatibility_mode spi|sclk_out] -name spi_sck derive_pll_clocks @@ -14,25 +14,24 @@ create_generated_clock -source [get_pins -compatibility_mode {pll_hdmi|pll_hdmi_ derive_clock_uncertainty # Decouple different clock groups (to simplify routing) -set_clock_groups -asynchronous \ +set_clock_groups -exclusive \ -group [get_clocks { *|pll|pll_inst|altera_pll_i|*[*].*|divclk}] \ -group [get_clocks { pll_hdmi|pll_hdmi_inst|altera_pll_i|*[0].*|divclk}] \ -group [get_clocks { *|h2f_user0_clk}] \ - -group [get_clocks { FPGA_CLK1_50 FPGA_CLK2_50 FPGA_CLK3_50}] + -group [get_clocks { FPGA_CLK1_50 }] \ + -group [get_clocks { FPGA_CLK2_50 }] \ + -group [get_clocks { FPGA_CLK3_50 }] -set_output_delay -max -clock HDMI_CLK 2.0ns [get_ports {HDMI_TX_D[*] HDMI_TX_DE HDMI_TX_HS HDMI_TX_VS}] -set_output_delay -min -clock HDMI_CLK -1.5ns [get_ports {HDMI_TX_D[*] HDMI_TX_DE HDMI_TX_HS HDMI_TX_VS}] +set_output_delay -max -clock HDMI_CLK 4.0ns [get_ports {HDMI_TX_D[*] HDMI_TX_DE HDMI_TX_HS HDMI_TX_VS}] +set_output_delay -min -clock HDMI_CLK 3.0ns [get_ports {HDMI_TX_D[*] HDMI_TX_DE HDMI_TX_HS HDMI_TX_VS}] -set_false_path -from {*} -to [get_registers {wcalc[*] hcalc[*]}] - - -# Put constraints on input ports -set_false_path -from [get_ports {KEY*}] -to * -set_false_path -from [get_ports {BTN_*}] -to * - -# Put constraints on output ports -set_false_path -from * -to [get_ports {LED_*}] -set_false_path -from * -to [get_ports {VGA_*}] -set_false_path -from * -to [get_ports {AUDIO_SPDIF}] -set_false_path -from * -to [get_ports {AUDIO_L}] -set_false_path -from * -to [get_ports {AUDIO_R}] +set_false_path -from [get_ports {KEY*}] +set_false_path -from [get_ports {BTN_*}] +set_false_path -to [get_ports {LED_*}] +set_false_path -to [get_ports {VGA_*}] +set_false_path -to [get_ports {AUDIO_SPDIF}] +set_false_path -to [get_ports {AUDIO_L}] +set_false_path -to [get_ports {AUDIO_R}] +set_false_path -to {cfg[*]} +set_false_path -from {cfg[*]} +set_false_path -to {wcalc[*] hcalc[*]} diff --git a/sys/sys_top.v b/sys/sys_top.v index 5d0a8bb..d1572ed 100644 --- a/sys/sys_top.v +++ b/sys/sys_top.v @@ -1,7 +1,7 @@ //============================================================================ // // MiSTer hardware abstraction module -// (c)2017-2019 Sorgelig +// (c)2017-2019 Alexey Melnikov // // 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 @@ -96,8 +96,14 @@ module sys_top `endif ////////// I/O ALT ///////// - inout [3:0] BTNLED, + output SD_SPI_CS, + input SD_SPI_MISO, + output SD_SPI_CLK, + output SD_SPI_MOSI, + inout SDCD_SPDIF, + output IO_SCL, + inout IO_SDA, ////////// ADC ////////////// output ADC_SCK, @@ -115,21 +121,30 @@ module sys_top output [7:0] LED, ///////// USER IO /////////// - inout [5:0] USER_IO + inout [6:0] USER_IO ); ////////////////////// Secondary SD /////////////////////////////////// -`ifndef DUAL_SDRAM - wire SD_CS, SD_CLK, SD_MOSI, SD_MISO; +wire sd_miso; +wire SD_CS, SD_CLK, SD_MOSI, SD_MISO; +`ifndef DUAL_SDRAM assign SDIO_DAT[2:1]= 2'bZZ; assign SDIO_DAT[3] = SW[3] ? 1'bZ : SD_CS; assign SDIO_CLK = SW[3] ? 1'bZ : SD_CLK; assign SDIO_CMD = SW[3] ? 1'bZ : SD_MOSI; - assign SD_MISO = SW[3] ? 1'b1 : SDIO_DAT[0]; + assign sd_miso = SW[3] ? 1'b1 : SDIO_DAT[0]; + assign SD_SPI_CS = mcp_sdcd ? ((~VGA_EN & sog & ~cs1) ? 1'b1 : 1'bZ) : SD_CS; +`else + assign sd_miso = 1'b1; + assign SD_SPI_CS = mcp_sdcd ? 1'bZ : SD_CS; `endif +assign SD_SPI_CLK = mcp_sdcd ? 1'bZ : SD_CLK; +assign SD_SPI_MOSI = mcp_sdcd ? 1'bZ : SD_MOSI; +assign SD_MISO = mcp_sdcd ? sd_miso : SD_SPI_MISO; + ////////////////////// LEDs/Buttons /////////////////////////////////// reg [7:0] led_overtake = 0; @@ -149,33 +164,27 @@ wire led_locked; //LEDs on main board assign LED = (led_overtake & led_state) | (~led_overtake & {1'b0,led_locked,1'b0, ~led_p, 1'b0, ~led_d, 1'b0, ~led_u}); -reg [3:0] btnled = 3'bZZZ; -reg btn_r = 0, btn_o = 0, btn_u = 0; -always @(posedge FPGA_CLK2_50) begin - reg [12:0] cnt; +wire btn_r, btn_o, btn_u; +`ifdef DUAL_SDRAM + assign {btn_r,btn_o,btn_u} = {mcp_btn[1],mcp_btn[2],mcp_btn[0]}; +`else + assign {btn_r,btn_o,btn_u} = ~{BTN_RESET,BTN_OSD,BTN_USER} | {mcp_btn[1],mcp_btn[2],mcp_btn[0]}; +`endif - if(SW[3]) begin - cnt <= cnt + 1'd1; - if(~&cnt[12:8]) btnled <= ~{1'b0,led_p,led_d,led_u}; - else begin - if(~cnt[7]) btnled <= 0; - else btnled <= 4'b0ZZZ; - if(&cnt) {btn_r,btn_o,btn_u} <= ~BTNLED[2:0]; - end - end - else begin - cnt <= 0; - `ifdef DUAL_SDRAM - {btn_r,btn_o,btn_u} <= 0; - btnled <= 4'bZZZZ; - `else - {btn_r,btn_o,btn_u} <= ~{BTN_RESET,BTN_OSD,BTN_USER}; - btnled <= {(~VGA_EN & sog & ~(vs1 ^ hs1)) ? 1'b1 : 1'bZ, 3'bZZZ}; - `endif - end -end +wire [2:0] mcp_btn; +wire mcp_sdcd; +mcp23009 mcp23009 +( + .clk(FPGA_CLK2_50), + + .btn(mcp_btn), + .led({led_p, led_d, led_u}), + .sd_cd(mcp_sdcd), + + .scl(IO_SCL), + .sda(IO_SDA) +); -assign BTNLED = btnled; reg btn_user, btn_osd; always @(posedge FPGA_CLK2_50) begin @@ -197,12 +206,11 @@ always @(posedge FPGA_CLK2_50) begin end end - ///////////////////////// 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_in = {1'b0, btn_user | btn[1], btn_osd | btn[0], SW[3], 8'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. @@ -238,7 +246,11 @@ always @(posedge clk_sys) begin gp_outd <= gp_out; end -wire [7:0] core_type = 'hA4; // A4 - generic core. +`ifdef DUAL_SDRAM + wire [7:0] core_type = 'hA8; // generic core, dual SDRAM. +`else + wire [7:0] core_type = 'hA4; // generic core. +`endif // HPS will not communicate to core if magic is different wire [31:0] core_magic = {24'h5CA623, core_type}; @@ -252,17 +264,18 @@ cyclonev_hps_interface_mpu_general_purpose h2f_gp reg [15:0] cfg; -reg cfg_got = 0; -reg cfg_set = 0; -wire hdmi_limited = cfg[8]; -wire dvi_mode = cfg[7]; -wire audio_96k = cfg[6]; +reg cfg_got = 0; +reg cfg_set = 0; +wire [1:0] hdmi_limited = {cfg[11],cfg[8]}; +wire direct_video = cfg[10]; +wire dvi_mode = cfg[7]; +wire audio_96k = cfg[6]; +wire csync_en = cfg[3]; +wire ypbpr_en = cfg[5]; +wire io_osd_vga = io_ss1 & ~io_ss2; `ifndef DUAL_SDRAM - wire sog = cfg[9]; - wire ypbpr_en = cfg[5]; - wire csync = cfg[3]; - wire vga_scaler= cfg[2]; - wire io_osd_vga= io_ss1 & ~io_ss2; + wire sog = cfg[9]; + wire vga_scaler = cfg[2]; `endif reg cfg_custom_t = 0; @@ -431,7 +444,7 @@ always @(posedge FPGA_CLK2_50) begin end wire clk_100m; -wire clk_hdmi = ~HDMI_TX_CLK; // Internal HDMI clock, inverted in relation to external clock +wire clk_hdmi = ~hdmi_clk_out; // Internal HDMI clock, inverted in relation to external clock wire clk_audio = FPGA_CLK3_50; wire clk_pal = FPGA_CLK3_50; @@ -496,6 +509,9 @@ wire [127:0] vbuf_writedata; wire [15:0] vbuf_byteenable; wire vbuf_write; +wire [23:0] hdmi_data; +wire hdmi_vs, hdmi_hs, hdmi_de; + ascal #( .RAMBASE(32'h20000000), @@ -513,10 +529,10 @@ ascal .i_r (r_out), .i_g (g_out), .i_b (b_out), - .i_hs (hs), - .i_vs (vs), + .i_hs (hs_fix), + .i_vs (vs_fix), .i_fl (f1), - .i_de (de), + .i_de (de_emu), .iauto (1), .himin (0), .himax (0), @@ -528,8 +544,8 @@ ascal .o_r (hdmi_data[23:16]), .o_g (hdmi_data[15:8]), .o_b (hdmi_data[7:0]), - .o_hs (HDMI_TX_HS), - .o_vs (HDMI_TX_VS), + .o_hs (hdmi_hs), + .o_vs (hdmi_vs), .o_de (hdmi_de), .o_lltune (lltune), .htotal (WIDTH + HFP + HBP + HS), @@ -687,13 +703,14 @@ fbpal fbpal ///////////////////////// HDMI output ///////////////////////////////// +wire hdmi_clk_out; 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) + .outclk_0(hdmi_clk_out) ); //1920x1080@60 PCLK=148.5MHz CEA @@ -772,24 +789,30 @@ hdmi_config hdmi_config .dvi_mode(dvi_mode), .audio_96k(audio_96k), - .hdmi_limited(hdmi_limited) + .limited(hdmi_limited), + .ypbpr(ypbpr_en & direct_video) ); -wire [23:0] hdmi_data; wire [23:0] hdmi_data_sl; -wire hdmi_de; - +wire hdmi_de_sl, hdmi_vs_sl, hdmi_hs_sl; scanlines #(1) HDMI_scanlines ( .clk(clk_hdmi), .scanlines(scanlines), .din(hdmi_data), + .hs_in(hdmi_hs), + .vs_in(hdmi_vs), + .de_in(hdmi_de), + .dout(hdmi_data_sl), - .hs(HDMI_TX_HS), - .vs(HDMI_TX_VS) + .hs_out(hdmi_hs_sl), + .vs_out(hdmi_vs_sl), + .de_out(hdmi_de_sl) ); +wire [23:0] hdmi_data_osd; +wire hdmi_de_osd, hdmi_vs_osd, hdmi_hs_osd; osd hdmi_osd ( .clk_sys(clk_sys), @@ -800,59 +823,128 @@ osd hdmi_osd .clk_video(clk_hdmi), .din(hdmi_data_sl), - .dout(HDMI_TX_D), - .de_in(hdmi_de), - .de_out(HDMI_TX_DE), + .hs_in(hdmi_hs_sl), + .vs_in(hdmi_vs_sl), + .de_in(hdmi_de_sl), + + .dout(hdmi_data_osd), + .hs_out(hdmi_hs_osd), + .vs_out(hdmi_vs_osd), + .de_out(hdmi_de_osd), .osd_status(osd_status) ); +reg [23:0] dv_data; +reg dv_hs, dv_vs, dv_de; +always @(negedge clk_vid) begin + reg [23:0] dv_d1, dv_d2; + reg dv_de1, dv_de2, dv_hs1, dv_hs2, dv_vs1, dv_vs2; + reg [12:0] vsz, vcnt; + reg old_hs, old_vs; + reg vde; + reg [3:0] hss; + + if(ce_pix) begin + hss <= (hss << 1) | vga_hs_osd; + + old_hs <= vga_hs_osd; + if(~old_hs && vga_hs_osd) begin + old_vs <= vga_vs_osd; + if(~&vcnt) vcnt <= vcnt + 1'd1; + if(~old_vs & vga_vs_osd & ~f1) vsz <= vcnt; + if(old_vs & ~vga_vs_osd) vcnt <= 0; + + if(vcnt == 1) vde <= 1; + if(vcnt == vsz - 3) vde <= 0; + end + + dv_de1 <= !{hss,vga_hs_osd} && vde; + dv_hs1 <= csync_en ? vga_cs_osd : vga_hs_osd; + dv_vs1 <= vga_vs_osd; + end + + dv_d1 <= vga_data_osd; + dv_d2 <= dv_d1; + dv_de2 <= dv_de1; + dv_hs2 <= dv_hs1; + dv_vs2 <= dv_vs1; + + dv_data<= dv_d2; + dv_de <= dv_de2; + dv_hs <= dv_hs2; + dv_vs <= dv_vs2; +end + +assign HDMI_TX_CLK = direct_video ? clk_vid : hdmi_clk_out; +assign HDMI_TX_HS = direct_video ? dv_hs : hdmi_hs_osd; +assign HDMI_TX_VS = direct_video ? dv_vs : hdmi_vs_osd; +assign HDMI_TX_DE = direct_video ? dv_de : hdmi_de_osd; +assign HDMI_TX_D = direct_video ? dv_data : hdmi_data_osd; + ///////////////////////// VGA output ////////////////////////////////// +wire [23:0] vga_data_sl; +wire vga_de_sl, vga_vs_sl, vga_hs_sl; +scanlines #(0) VGA_scanlines +( + .clk(clk_vid), + + .scanlines(scanlines), + .din(de_emu ? {r_out, g_out, b_out} : 24'd0), + .hs_in(hs_fix), + .vs_in(vs_fix), + .de_in(de_emu), + + .dout(vga_data_sl), + .hs_out(vga_hs_sl), + .vs_out(vga_vs_sl), + .de_out(vga_de_sl) +); + +wire [23:0] vga_data_osd; +wire vga_vs_osd, vga_hs_osd; +osd vga_osd +( + .clk_sys(clk_sys), + + .io_osd(io_osd_vga), + .io_strobe(io_strobe), + .io_din(io_din), + + .clk_video(clk_vid), + .din(vga_data_sl), + .hs_in(vga_hs_sl), + .vs_in(vga_vs_sl), + .de_in(vga_de_sl), + + .dout(vga_data_osd), + .hs_out(vga_hs_osd), + .vs_out(vga_vs_osd) +); + +wire vga_cs_osd; +csync csync_vga(clk_vid, vga_hs_osd, vga_vs_osd, vga_cs_osd); + `ifndef DUAL_SDRAM - wire [23:0] vga_data_sl; - - scanlines #(0) VGA_scanlines - ( - .clk(clk_vid), - - .scanlines(scanlines), - .din(de ? {r_out, g_out, b_out} : 24'd0), - .dout(vga_data_sl), - .hs(hs1), - .vs(vs1) - ); - - osd vga_osd - ( - .clk_sys(clk_sys), - - .io_osd(io_osd_vga), - .io_strobe(io_strobe), - .io_din(io_din), - - .clk_video(clk_vid), - .din(vga_data_sl), - .dout(vga_q), - .de_in(de) - ); - - wire [23:0] vga_q; wire [23:0] vga_o; - vga_out vga_out ( - .ypbpr_full(1), + .ypbpr_full(0), .ypbpr_en(ypbpr_en), .dout(vga_o), - .din(vga_scaler ? {24{HDMI_TX_DE}} & HDMI_TX_D : vga_q) + .din(vga_scaler ? {24{hdmi_de_osd}} & hdmi_data_osd : vga_data_osd) ); - wire vs1 = vga_scaler ? HDMI_TX_VS : vs; - wire hs1 = vga_scaler ? HDMI_TX_HS : hs; + wire hdmi_cs_osd; + csync csync_hdmi(clk_hdmi, hdmi_hs_osd, hdmi_vs_osd, hdmi_cs_osd); - assign VGA_VS = (VGA_EN | SW[3]) ? 1'bZ : csync ? 1'b1 : ~vs1; - assign VGA_HS = (VGA_EN | SW[3]) ? 1'bZ : csync ? ~(vs1 ^ hs1) : ~hs1; + wire vs1 = vga_scaler ? hdmi_vs_osd : vga_vs_osd; + wire hs1 = vga_scaler ? hdmi_hs_osd : vga_hs_osd; + wire cs1 = vga_scaler ? hdmi_cs_osd : vga_cs_osd; + + assign VGA_VS = (VGA_EN | SW[3]) ? 1'bZ : csync_en ? 1'b1 : ~vs1; + assign VGA_HS = (VGA_EN | SW[3]) ? 1'bZ : csync_en ? ~cs1 : ~hs1; assign VGA_R = (VGA_EN | SW[3]) ? 6'bZZZZZZ : vga_o[23:18]; assign VGA_G = (VGA_EN | SW[3]) ? 6'bZZZZZZ : vga_o[15:10]; assign VGA_B = (VGA_EN | SW[3]) ? 6'bZZZZZZ : vga_o[7:2]; @@ -860,7 +952,7 @@ osd hdmi_osd ///////////////////////// Audio output //////////////////////////////// -assign SDCD_SPDIF =(SW[3] & spdif) ? 1'b0 : 1'bZ; +assign SDCD_SPDIF =(SW[3] & ~spdif) ? 1'b0 : 1'bZ; `ifndef DUAL_SDRAM wire anl,anr; @@ -962,6 +1054,7 @@ assign USER_IO[2] = !(SW[1] ? HDMI_I2S : user_out[2]) ? 1'b0 : 1'bZ; assign USER_IO[3] = !user_out[3] ? 1'b0 : 1'bZ; assign USER_IO[4] = !(SW[1] ? HDMI_SCLK : user_out[4]) ? 1'b0 : 1'bZ; assign USER_IO[5] = !(SW[1] ? HDMI_LRCLK : user_out[5]) ? 1'b0 : 1'bZ; +assign USER_IO[6] = !user_out[6] ? 1'b0 : 1'bZ; assign user_in[0] = USER_IO[0]; assign user_in[1] = USER_IO[1]; @@ -969,6 +1062,7 @@ assign user_in[2] = SW[1] | USER_IO[2]; assign user_in[3] = USER_IO[3]; assign user_in[4] = SW[1] | USER_IO[4]; assign user_in[5] = SW[1] | USER_IO[5]; +assign user_in[6] = USER_IO[6]; /////////////////// User module connection //////////////////////////// @@ -977,7 +1071,7 @@ wire [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, f1; +wire vs_fix, hs_fix, de_emu, f1; wire [1:0] scanlines; wire clk_sys, clk_vid, ce_pix; @@ -995,10 +1089,11 @@ wire ram_write; wire led_user; wire [1:0] led_power; wire [1:0] led_disk; +wire [1:0] btn; wire vs_emu, hs_emu; -sync_fix sync_v(clk_vid, vs_emu, vs); -sync_fix sync_h(clk_vid, hs_emu, hs); +sync_fix sync_v(clk_vid, vs_emu, vs_fix); +sync_fix sync_h(clk_vid, hs_emu, hs_fix); wire uart_dtr; wire uart_dsr; @@ -1008,13 +1103,13 @@ wire uart_rxd; wire uart_txd; wire osd_status; -wire [5:0] user_out, user_in; +wire [6:0] user_out, user_in; emu emu ( - .CLK_50M(FPGA_CLK3_50), + .CLK_50M(FPGA_CLK2_50), .RESET(reset), - .HPS_BUS({f1, HDMI_TX_VS, clk_100m, clk_vid, ce_pix, de, hs, vs, io_wait, clk_sys, io_fpga, io_uio, io_strobe, io_wide, io_din, io_dout}), + .HPS_BUS({f1, HDMI_TX_VS, clk_100m, clk_vid, ce_pix, de_emu, hs_fix, vs_fix, io_wait, clk_sys, io_fpga, io_uio, io_strobe, io_wide, io_din, io_dout}), .CLK_VIDEO(clk_vid), .CE_PIXEL(ce_pix), @@ -1024,13 +1119,14 @@ emu emu .VGA_B(b_out), .VGA_HS(hs_emu), .VGA_VS(vs_emu), - .VGA_DE(de), + .VGA_DE(de_emu), .VGA_F1(f1), .VGA_SL(scanlines), .LED_USER(led_user), .LED_POWER(led_power), .LED_DISK(led_disk), + .BUTTONS(btn), .VIDEO_ARX(ARX), .VIDEO_ARY(ARY), @@ -1075,12 +1171,16 @@ emu emu .SDRAM2_nCAS(SDRAM2_nCAS), .SDRAM2_CLK(SDRAM2_CLK), .SDRAM2_EN(SW[3]), -`else +`endif + .SD_SCK(SD_CLK), .SD_MOSI(SD_MOSI), .SD_MISO(SD_MISO), .SD_CS(SD_CS), - .SD_CD(SW[0] ? VGA_HS : SW[3] ? 1'b1 : SDCD_SPDIF ), +`ifdef DUAL_SDRAM + .SD_CD(mcp_sdcd), +`else + .SD_CD(mcp_sdcd & (SW[0] ? VGA_HS : (SW[3] | SDCD_SPDIF))), `endif .UART_CTS(uart_rts), @@ -1178,3 +1278,45 @@ always @(posedge clk) begin end endmodule + +///////////////////////////////////////////////////////////////////// + +// CSync generation +// Shifts HSync left by 1 HSync period during VSync + +module csync +( + input clk, + input hsync, + input vsync, + + output csync +); + +assign csync = (csync_vs ^ csync_hs); + +reg csync_hs, csync_vs; +always @(posedge clk) begin + reg prev_hs; + reg [15:0] h_cnt, line_len, hs_len; + + // Count line/Hsync length + h_cnt <= h_cnt + 1'd1; + + prev_hs <= hsync; + if (prev_hs ^ hsync) begin + h_cnt <= 0; + if (hsync) begin + line_len <= h_cnt - hs_len; + csync_hs <= 0; + end + else hs_len <= h_cnt; + end + + if (~vsync) csync_hs <= hsync; + else if(h_cnt == line_len) csync_hs <= 1; + + csync_vs <= vsync; +end + +endmodule diff --git a/sys/video_cleaner.sv b/sys/video_cleaner.sv index f9f23d2..b0acbc3 100644 --- a/sys/video_cleaner.sv +++ b/sys/video_cleaner.sv @@ -23,6 +23,9 @@ module video_cleaner input HBlank, input VBlank, + //optional de + input DE_in, + // video output signals output reg [7:0] VGA_R, output reg [7:0] VGA_G, @@ -33,7 +36,10 @@ module video_cleaner // optional aligned blank output reg HBlank_out, - output reg VBlank_out + output reg VBlank_out, + + // optional aligned de + output reg DE_out ); wire hs, vs; @@ -49,11 +55,13 @@ always @(posedge clk_vid) begin if(ce_pix) begin HBlank_out <= hbl; - VGA_VS <= vs; VGA_HS <= hs; + if(~VGA_HS & hs) VGA_VS <= vs; + VGA_R <= R; VGA_G <= G; VGA_B <= B; + DE_out <= DE_in; if(HBlank_out & ~hbl) VBlank_out <= vbl; end