From bec46eb3abc03e99cd27e00efaa5faac9d1dcd3b Mon Sep 17 00:00:00 2001 From: sorgelig Date: Fri, 10 Sep 2021 19:56:09 +0800 Subject: [PATCH] Update sys. --- SMS.sv | 24 +- sys/ascal.vhd | 62 +-- sys/gamma_corr.sv | 4 +- sys/{hps_io.v => hps_io.sv} | 139 ++++--- sys/osd.v | 2 +- sys/sd_card.sv | 798 ++++++++++++++++-------------------- sys/sys.qip | 3 +- sys/sys_top.sdc | 2 + sys/sys_top.v | 195 ++++----- sys/vga_out.sv | 41 +- sys/video_freak.sv | 143 +++++-- sys/video_freezer.sv | 143 +++++++ sys/video_mixer.sv | 59 ++- 13 files changed, 910 insertions(+), 705 deletions(-) rename sys/{hps_io.v => hps_io.sv} (89%) create mode 100644 sys/video_freezer.sv diff --git a/SMS.sv b/SMS.sv index 7820ee8..f622786 100644 --- a/SMS.sv +++ b/SMS.sv @@ -55,8 +55,9 @@ module emu input [11:0] HDMI_WIDTH, input [11:0] HDMI_HEIGHT, + output HDMI_FREEZE, -`ifdef USE_FB +`ifdef MISTER_FB // Use framebuffer in DDRAM (USE_FB=1 in qsf) // FB_FORMAT: // [2:0] : 011=8bpp(palette) 100=16bpp 101=24bpp 110=32bpp @@ -74,6 +75,7 @@ module emu input FB_LL, output FB_FORCE_BLANK, +`ifdef MISTER_FB_PALETTE // Palette control for 8bit modes. // Ignored for other video modes. output FB_PAL_CLK, @@ -81,6 +83,7 @@ module emu output [23:0] FB_PAL_DOUT, input [23:0] FB_PAL_DIN, output FB_PAL_WR, +`endif `endif output LED_USER, // 1 - ON, 0 - OFF. @@ -112,7 +115,6 @@ module emu output SD_CS, input SD_CD, -`ifdef USE_DDRAM //High latency DDR3 RAM interface //Use for non-critical time purposes output DDRAM_CLK, @@ -125,9 +127,7 @@ module emu output [63:0] DDRAM_DIN, output [7:0] DDRAM_BE, output DDRAM_WE, -`endif -`ifdef USE_SDRAM //SDRAM interface with lower latency output SDRAM_CLK, output SDRAM_CKE, @@ -140,10 +140,10 @@ module emu output SDRAM_nCAS, output SDRAM_nRAS, output SDRAM_nWE, -`endif -`ifdef DUAL_SDRAM +`ifdef MISTER_DUAL_SDRAM //Secondary SDRAM + //Set all output SDRAM_* signals to Z ASAP if SDRAM2_EN is 0 input SDRAM2_EN, output SDRAM2_CLK, output [12:0] SDRAM2_A, @@ -173,6 +173,7 @@ module emu input OSD_STATUS ); + assign ADC_BUS = 'Z; assign VGA_F1 = 0; @@ -186,6 +187,7 @@ assign LED_DISK = 0; assign LED_POWER = 0; assign BUTTONS = 0; assign VGA_SCALER= 0; +assign HDMI_FREEZE = 0; reg en216p; always @(posedge CLK_VIDEO) en216p <= ((HDMI_WIDTH == 1920) && (HDMI_HEIGHT == 1080) && !forced_scandoubler && !scale); @@ -321,13 +323,11 @@ wire [21:0] gamma_bus; wire [24:0] ps2_mouse; -hps_io #(.STRLEN($size(CONF_STR)>>3), .WIDE(0)) hps_io +hps_io #(.CONF_STR(CONF_STR), .WIDE(0)) hps_io ( .clk_sys(clk_sys), .HPS_BUS(HPS_BUS), - .conf_str(CONF_STR), - .joystick_0(joy_0), .joystick_1(joy_1), .joystick_2(joy_2), @@ -354,16 +354,15 @@ hps_io #(.STRLEN($size(CONF_STR)>>3), .WIDE(0)) hps_io .ioctl_download(ioctl_download), .ioctl_index(ioctl_index), - .sd_conf(0), .ioctl_wait(ioctl_wait), - .sd_lba(sd_lba), + .sd_lba('{sd_lba}), .sd_rd(sd_rd), .sd_wr(sd_wr), .sd_ack(sd_ack), .sd_buff_addr(sd_buff_addr), .sd_buff_dout(sd_buff_dout), - .sd_buff_din(sd_buff_din), + .sd_buff_din('{sd_buff_din}), .sd_buff_wr(sd_buff_wr), .img_mounted(img_mounted), .img_readonly(img_readonly), @@ -858,6 +857,7 @@ video_mixer #(.HALF_DEPTH(1), .LINE_LENGTH(300), .GAMMA(1)) video_mixer .*, .scandoubler(scale || forced_scandoubler), .hq2x(scale==1), + .freeze_sync(), .VGA_DE(vga_de), .R((gun_en & gun_target) ? 8'd255 : {2{color[3:0]}}), diff --git a/sys/ascal.vhd b/sys/ascal.vhd index a65ccc1..f157e9f 100644 --- a/sys/ascal.vhd +++ b/sys/ascal.vhd @@ -382,8 +382,9 @@ ARCHITECTURE rtl OF ascal IS SIGNAL avl_o_vs_sync,avl_o_vs : std_logic; SIGNAL avl_fb_ena : std_logic; - FUNCTION buf_next(a,b : natural RANGE 0 TO 2) RETURN natural IS + FUNCTION buf_next(a,b : natural RANGE 0 TO 2; freeze : std_logic := '0') RETURN natural IS BEGIN + IF (freeze='1') THEN RETURN a; END IF; IF (a=0 AND b=1) OR (a=1 AND b=0) THEN RETURN 2; END IF; IF (a=1 AND b=2) OR (a=2 AND b=1) THEN RETURN 0; END IF; RETURN 1; @@ -400,6 +401,7 @@ ARCHITECTURE rtl OF ascal IS ---------------------------------------------------------- -- Output SIGNAL o_run : std_logic; + SIGNAL o_freeze : std_logic; SIGNAL o_mode,o_hmode,o_vmode : unsigned(4 DOWNTO 0); SIGNAL o_format : unsigned(5 DOWNTO 0); SIGNAL o_fb_pal_dr : unsigned(23 DOWNTO 0); @@ -1730,28 +1732,61 @@ BEGIN -- Triple buffering. -- For intelaced video, half frames are updated independently -- Input : Toggle buffer at end of input frame + o_freeze <= freeze; o_inter <=i_inter; -- o_iendframe0<=i_endframe0; -- o_iendframe02<=o_iendframe0; IF o_iendframe0='1' AND o_iendframe02='0' THEN - o_ibuf0<=buf_next(o_ibuf0,o_obuf0); + o_ibuf0<=buf_next(o_ibuf0,o_obuf0,o_freeze); o_bufup0<='1'; END IF; o_iendframe1<=i_endframe1; -- o_iendframe12<=o_iendframe1; IF o_iendframe1='1' AND o_iendframe12='0' THEN - o_ibuf1<=buf_next(o_ibuf1,o_obuf1); + o_ibuf1<=buf_next(o_ibuf1,o_obuf1,o_freeze); o_bufup1<='1'; END IF; + -- Output : Change framebuffer, and image properties, at VS falling edge + IF o_vsv(1)='1' AND o_vsv(0)='0' AND o_bufup0='1' THEN + o_obuf0<=buf_next(o_obuf0,o_ibuf0,o_freeze); + o_bufup0<='0'; + END IF; IF o_vsv(1)='1' AND o_vsv(0)='0' AND o_bufup1='1' THEN - o_obuf1<=buf_next(o_obuf1,o_ibuf1); + o_obuf1<=buf_next(o_obuf1,o_ibuf1,o_freeze); o_bufup1<='0'; o_ihsize<=i_hrsize; -- o_ivsize<=i_vrsize; -- o_hdown<=i_hdown; -- o_vdown<=i_vdown; -- END IF; + + -- Simultaneous change of input and output framebuffers + IF o_vsv(1)='1' AND o_vsv(0)='0' AND + o_iendframe0='1' AND o_iendframe02='0' THEN + o_bufup0<='0'; + o_obuf0<=o_ibuf0; + END IF; + IF o_vsv(1)='1' AND o_vsv(0)='0' AND + o_iendframe1='1' AND o_iendframe12='0' THEN + o_bufup1<='0'; + o_obuf1<=o_ibuf1; + END IF; + + -- Non-interlaced, use same buffer for even and odd lines + IF o_inter='0' THEN + o_ibuf1<=o_ibuf0; + o_obuf1<=o_obuf0; + END IF; + + -- Triple buffer disabled + IF o_mode(3)='0' THEN + o_obuf0<=0; + o_obuf1<=0; + o_ibuf0<=0; + o_ibuf1<=0; + END IF; + -- Framebuffer mode. IF o_fb_ena='1' THEN o_ihsize<=o_fb_hsize; @@ -1771,25 +1806,6 @@ BEGIN o_stride<=to_unsigned(o_ihsize_temp2,14); o_stride(NB_BURST-1 DOWNTO 0)<=(OTHERS =>'0'); END IF; - - IF o_vsv(1)='1' AND o_vsv(0)='0' AND o_bufup0='1' THEN - o_obuf0<=buf_next(o_obuf0,o_ibuf0); - o_bufup0<='0'; - END IF; - - IF o_inter='0' THEN - o_ibuf1<=o_ibuf0; - o_obuf1<=o_obuf0; - END IF; - - -- Triple buffer disabled - IF o_mode(3)='0' THEN - o_obuf0<=0; - o_obuf1<=0; - o_ibuf0<=0; - o_ibuf1<=0; - END IF; - ------------------------------------------------------ o_hmode<=o_mode; IF o_hdown='1' AND DOWNSCALE THEN diff --git a/sys/gamma_corr.sv b/sys/gamma_corr.sv index 7fd9368..321b83f 100644 --- a/sys/gamma_corr.sv +++ b/sys/gamma_corr.sv @@ -32,8 +32,10 @@ always @(posedge clk_vid) begin reg [7:0] R_gamma, G_gamma; reg hs,vs,hb,vb; reg [1:0] ctr = 0; + reg old_ce; - if(ce_pix) begin + old_ce <= ce_pix; + if(~old_ce & ce_pix) begin {R_in,G_in,B_in} <= RGB_in; hs <= HSync; vs <= VSync; hb <= HBlank; vb <= VBlank; diff --git a/sys/hps_io.v b/sys/hps_io.sv similarity index 89% rename from sys/hps_io.v rename to sys/hps_io.sv index 9431c95..735516c 100644 --- a/sys/hps_io.v +++ b/sys/hps_io.sv @@ -24,15 +24,14 @@ // Use buffer to access SD card. It's time-critical part. // // WIDE=1 for 16 bit file I/O -// VDNUM 1-4 -module hps_io #(parameter STRLEN=0, PS2DIV=0, WIDE=0, VDNUM=1, PS2WE=0) +// VDNUM 1..4 +// BLKSZ 0..7: 0 = 128, 1 = 256, 2 = 512(default), .. 7 = 16384 +// +module hps_io #(parameter CONF_STR, CONF_STR_BRAM=1, PS2DIV=0, WIDE=0, VDNUM=1, BLKSZ=2, PS2WE=0) ( input clk_sys, inout [45:0] HPS_BUS, - // parameter STRLEN and the actual length of conf_str have to match - input [(8*STRLEN)-1:0] conf_str, - // buttons up to 32 output reg [31:0] joystick_0, output reg [31:0] joystick_1, @@ -86,22 +85,17 @@ module hps_io #(parameter STRLEN=0, PS2DIV=0, WIDE=0, VDNUM=1, PS2WE=0) output reg [63:0] img_size, // size of image in bytes. valid only for active bit in img_mounted // SD block level access - input [31:0] sd_lba, - input [VD:0] sd_rd, // only single sd_rd can be active at any given time - input [VD:0] sd_wr, // only single sd_wr can be active at any given time - output reg sd_ack, - - // do not use in new projects. - // CID and CSD are fake except CSD image size field. - input sd_conf, - output reg sd_ack_conf, + input [31:0] sd_lba[VDNUM], + input [5:0] sd_blk_cnt[VDNUM], // number of blocks-1, total size ((sd_blk_cnt+1)*(1<<(BLKSZ+7))) must be <= 16384! + input [VD:0] sd_rd, + input [VD:0] sd_wr, + output reg [VD:0] sd_ack, // SD byte level access. Signals for 2-PORT altsyncram. output reg [AW:0] sd_buff_addr, output reg [DW:0] sd_buff_dout, - input [DW:0] sd_buff_din, + input [DW:0] sd_buff_din[VDNUM], output reg sd_buff_wr, - input [15:0] sd_req_type, // ARM -> FPGA download output reg ioctl_download = 0, // signal indicating an active download @@ -110,6 +104,7 @@ module hps_io #(parameter STRLEN=0, PS2DIV=0, WIDE=0, VDNUM=1, PS2WE=0) output reg [26:0] ioctl_addr, // in WIDE mode address will be incremented by 2 output reg [DW:0] ioctl_dout, output reg ioctl_upload = 0, // signal indicating an active upload + input ioctl_upload_req, input [DW:0] ioctl_din, output reg ioctl_rd, output reg [31:0] ioctl_file_ext, @@ -161,10 +156,8 @@ module hps_io #(parameter STRLEN=0, PS2DIV=0, WIDE=0, VDNUM=1, PS2WE=0) assign EXT_BUS[31:16] = HPS_BUS[31:16]; assign EXT_BUS[35:33] = HPS_BUS[35:33]; -localparam MAX_W = $clog2((512 > (STRLEN+1)) ? 512 : (STRLEN+1))-1; - localparam DW = (WIDE) ? 15 : 7; -localparam AW = (WIDE) ? 7 : 8; +localparam AW = (WIDE) ? 12 : 13; localparam VD = VDNUM-1; wire io_strobe= HPS_BUS[33]; @@ -187,22 +180,18 @@ assign forced_scandoubler = cfg[4]; //cfg[5] - ypbpr handled in sys_top assign direct_video = cfg[10]; -// command byte read by the io controller -wire [15:0] sd_cmd = -{ - 2'b00, - (VDNUM>=4) ? sd_wr[3] : 1'b0, - (VDNUM>=3) ? sd_wr[2] : 1'b0, - (VDNUM>=2) ? sd_wr[1] : 1'b0, +reg [3:0] sdn; +reg [3:0] sd_rrb = 0; +always_comb begin + int n, i; - (VDNUM>=4) ? sd_rd[3] : 1'b0, - (VDNUM>=3) ? sd_rd[2] : 1'b0, - (VDNUM>=2) ? sd_rd[1] : 1'b0, - - 4'h5, sd_conf, 1'b1, - sd_wr[0], - sd_rd[0] -}; + sdn = 0; + for(i = VDNUM - 1; i >= 0; i = i - 1) begin + n = i + sd_rrb; + if(n >= VDNUM) n = n - VDNUM; + if(sd_wr[n] | sd_rd[n]) sdn = n[3:0]; + end +end ///////////////////////////////////////////////////////// @@ -226,6 +215,19 @@ video_calc video_calc ///////////////////////////////////////////////////////// +localparam STRLEN = $size(CONF_STR)>>3; +localparam MAX_W = $clog2((32 > (STRLEN+2)) ? 32 : (STRLEN+2))-1; + +wire [7:0] conf_byte; +generate + if(CONF_STR_BRAM) begin + confstr_rom #(CONF_STR, STRLEN) confstr_rom(.*, .conf_addr(byte_cnt - 1'd1)); + end + else begin + assign conf_byte = CONF_STR[{(STRLEN - byte_cnt),3'b000} +:8]; + end +endgenerate + assign gamma_bus[20:0] = {clk_sys, gamma_en, gamma_wr, gamma_wr_addr, gamma_value}; reg gamma_en; reg gamma_wr; @@ -237,6 +239,8 @@ wire pressed = (ps2_key_raw[15:8] != 8'hf0); wire extended = (~pressed ? (ps2_key_raw[23:16] == 8'he0) : (ps2_key_raw[15:8] == 8'he0)); reg [MAX_W:0] byte_cnt; +reg [3:0] sdn_ack; +wire [15:0] disk = 16'd1 << io_din[11:8]; always@(posedge clk_sys) begin : uio_block reg [15:0] cmd; @@ -247,16 +251,22 @@ always@(posedge clk_sys) begin : uio_block reg [3:0] stflg = 0; reg [63:0] status_req; reg old_status_set = 0; + reg old_upload_req = 0; + reg upload_req = 0; reg old_info = 0; reg [7:0] info_n = 0; reg [15:0] tmp1; reg [7:0] tmp2; + reg [3:0] sdn_r; old_status_set <= status_set; if(~old_status_set & status_set) begin stflg <= stflg + 1'd1; status_req <= status_in; end + + old_upload_req <= ioctl_upload_req; + if(~old_upload_req & ioctl_upload_req) upload_req <= 1; old_info <= info_req; if(~old_info & info_req) info_n <= info; @@ -282,7 +292,6 @@ always@(posedge clk_sys) begin : uio_block cmd <= 0; byte_cnt <= 0; sd_ack <= 0; - sd_ack_conf <= 0; io_dout <= 0; ps2skip <= 0; img_mounted <= 0; @@ -295,23 +304,24 @@ always@(posedge clk_sys) begin : uio_block if(byte_cnt == 0) begin cmd <= io_din; - case(io_din) - 'h19: sd_ack_conf <= 1; - 'h17, - 'h18: sd_ack <= 1; - 'h29: io_dout <= {4'hA, stflg}; - 'h2B: io_dout <= 1; - 'h2F: io_dout <= 1; - 'h32: io_dout <= gamma_bus[21]; - 'h36: begin io_dout <= info_n; info_n <= 0; end - 'h39: io_dout <= 1; + casex(io_din) + 'h16: begin io_dout <= {1'b1, sd_blk_cnt[sdn], BLKSZ[2:0], sdn, sd_wr[sdn], sd_rd[sdn]}; sdn_r <= sdn; end + 'h0X17, + 'h0X18: begin sd_ack <= disk[VD:0]; sdn_ack <= io_din[11:8]; end + 'h29: io_dout <= {4'hA, stflg}; + 'h2B: io_dout <= 1; + 'h2F: io_dout <= 1; + 'h32: io_dout <= gamma_bus[21]; + 'h36: begin io_dout <= info_n; info_n <= 0; end + 'h39: io_dout <= 1; + 'h3C: if(upload_req) begin io_dout <= 1; upload_req <= 0; end endcase sd_buff_addr <= 0; if(io_din == 5) ps2_key_raw <= 0; end else begin - case(cmd) + casex(cmd) // buttons and switches 'h01: cfg <= io_din; 'h02: if(byte_cnt==1) joystick_0[15:0] <= io_din; else joystick_0[31:16] <= io_din; @@ -353,34 +363,28 @@ always@(posedge clk_sys) begin : uio_block end // reading config string, returning a byte from string - 'h14: if(byte_cnt < STRLEN + 1) io_dout[7:0] <= conf_str[(STRLEN - byte_cnt)<<3 +:8]; + 'h14: if(byte_cnt <= STRLEN) io_dout[7:0] <= conf_byte; // reading sd card status - 'h16: if(!byte_cnt[MAX_W:3]) begin - case(byte_cnt[2:0]) - 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; + 'h16: if(!byte_cnt[MAX_W:2]) begin + case(byte_cnt[1:0]) + 1: sd_rrb <= (sd_rrb == VD) ? 4'd0 : (sd_rrb + 1'd1); + 2: io_dout <= sd_lba[sdn_r][15:0]; + 3: io_dout <= sd_lba[sdn_r][31:16]; endcase end - // send SD config IO -> FPGA - // flag that download begins - // sd card knows data is config if sd_dout_strobe is asserted - // with sd_ack still being inactive (low) - 'h19, // send sector IO -> FPGA // flag that download begins - 'h17: begin + 'h0X17: begin sd_buff_dout <= io_din[DW:0]; b_wr <= 1; end // reading sd card write data - 'h18: begin + 'h0X18: begin if(~&sd_buff_addr) sd_buff_addr <= sd_buff_addr + 1'b1; - io_dout <= sd_buff_din; + io_dout <= sd_buff_din[sdn_ack]; end // joystick analog @@ -936,3 +940,16 @@ always @(posedge clk_100) begin end endmodule + +module confstr_rom #(parameter CONF_STR, STRLEN) +( + input clk_sys, + input [$clog2(STRLEN+1)-1:0] conf_addr, + output reg [7:0] conf_byte +); + +wire [7:0] rom[STRLEN]; +initial for(int i = 0; i < STRLEN; i++) rom[i] = CONF_STR[((STRLEN-i)*8)-1 -:8]; +always @ (posedge clk_sys) conf_byte <= rom[conf_addr]; + +endmodule diff --git a/sys/osd.v b/sys/osd.v index a4fbdde..782fc81 100644 --- a/sys/osd.v +++ b/sys/osd.v @@ -72,7 +72,7 @@ always@(posedge clk_sys) begin // command 0x40: OSDCMDENABLE, OSDCMDDISABLE if(io_din[7:4] == 4) begin if(!io_din[0]) {osd_status,highres} <= 0; - else {osd_status,info} <= {~io_din[2],io_din[2]}; + else {osd_status,info} <= {~io_din[2] & ~io_din[3],io_din[2]}; bcnt <= 0; end // command 0x20: OSDCMDWRITE diff --git a/sys/sd_card.sv b/sys/sd_card.sv index a2aad7e..610c271 100644 --- a/sys/sd_card.sv +++ b/sys/sd_card.sv @@ -23,52 +23,55 @@ // // Made module syncrhronous. Total code refactoring. (Sorgelig) -// clk_spi must be at least 4 x sck for proper work. +// clk_spi must be at least 2 x sck for proper work. -module sd_card #(parameter WIDE = 0) +module sd_card #(parameter WIDE = 0, OCTAL=0) ( - input clk_sys, - input reset, + input clk_sys, + input reset, - input sdhc, - - output [31:0] sd_lba, - output reg sd_rd, - output reg sd_wr, - input sd_ack, - input sd_ack_conf, + input sdhc, + input img_mounted, + input [63:0] img_size, - input [AW:0] sd_buff_addr, - input [DW:0] sd_buff_dout, - output [DW:0] sd_buff_din, - input sd_buff_wr, + output reg [31:0] sd_lba, + output reg sd_rd, + output reg sd_wr, + input sd_ack, + + input [AW:0] sd_buff_addr, + input [DW:0] sd_buff_dout, + output [DW:0] sd_buff_din, + input sd_buff_wr, // SPI interface - input clk_spi, + input clk_spi, - input ss, - input sck, - input mosi, - output reg miso + input ss, + input sck, + input [SW:0] mosi, + output reg [SW:0] miso ); -localparam AW = WIDE ? 7 : 8; -localparam DW = WIDE ? 15 : 7; +localparam AW = WIDE ? 7 : 8; +localparam DW = WIDE ? 15 : 7; +localparam SZ = OCTAL ? 8 : 1; +localparam SW = SZ-1; -assign sd_lba = sdhc ? lba : {9'd0, lba[31:9]}; - -wire[31:0] OCR = { 1'b1, sdhc, 30'd0 }; // bit30 = 1 -> high capaciry card (sdhc) // bit31 = 0 -> card power up finished -wire [7:0] READ_DATA_TOKEN = 8'hfe; +wire [7:0] DATA_TOKEN_CMD25 = 8'hfc; +wire [7:0] STOP_TRAN = 8'hfd; +wire [7:0] DATA_TOKEN = 8'hfe; wire [7:0] WRITE_DATA_RESPONSE = 8'h05; // number of bytes to wait after a command before sending the reply -localparam NCR=3; +localparam NCR = 5+3; // 5 bytes are required (command length) localparam RD_STATE_IDLE = 0; -localparam RD_STATE_WAIT_IO = 1; -localparam RD_STATE_SEND_TOKEN = 2; -localparam RD_STATE_SEND_DATA = 3; -localparam RD_STATE_WAIT_M = 4; +localparam RD_STATE_START = 1; +localparam RD_STATE_WAIT_IO = 2; +localparam RD_STATE_SEND_TOKEN = 3; +localparam RD_STATE_SEND_DATA = 4; +localparam RD_STATE_WAIT_M = 5; localparam WR_STATE_IDLE = 0; localparam WR_STATE_EXP_DTOKEN = 1; @@ -78,460 +81,383 @@ localparam WR_STATE_RECV_CRC1 = 4; localparam WR_STATE_SEND_DRESP = 5; localparam WR_STATE_BUSY = 6; -sdbuf #(WIDE) buffer +localparam PREF_STATE_IDLE = 0; +localparam PREF_STATE_RD = 1; +localparam PREF_STATE_FINISH = 2; + +altsyncram sdbuf ( - .clock_a(clk_sys), - .address_a(sd_buff_addr), - .data_a(sd_buff_dout), - .wren_a(sd_ack & sd_buff_wr), - .q_a(sd_buff_din), + .clock0 (clk_sys), + .address_a ({sd_buf,sd_buff_addr}), + .data_a (sd_buff_dout), + .wren_a (sd_ack & sd_buff_wr), + .q_a (sd_buff_din), - .clock_b(clk_spi), - .address_b(buffer_ptr), - .data_b(buffer_din), - .wren_b(buffer_wr), - .q_b(buffer_dout) + .clock1 (clk_spi), + .address_b ({spi_buf,buffer_ptr}), + .data_b (buffer_din), + .wren_b (buffer_wr), + .q_b (buffer_dout), + + .aclr0(1'b0), + .aclr1(1'b0), + .addressstall_a(1'b0), + .addressstall_b(1'b0), + .byteena_a(1'b1), + .byteena_b(1'b1), + .clocken0(1'b1), + .clocken1(1'b1), + .clocken2(1'b1), + .clocken3(1'b1), + .eccstatus(), + .rden_a(1'b1), + .rden_b(1'b1) ); +defparam + sdbuf.numwords_a = 1<<(AW+3), + sdbuf.widthad_a = AW+3, + sdbuf.width_a = DW+1, + sdbuf.numwords_b = 2048, + sdbuf.widthad_b = 11, + sdbuf.width_b = 8, + sdbuf.address_reg_b = "CLOCK1", + sdbuf.clock_enable_input_a = "BYPASS", + sdbuf.clock_enable_input_b = "BYPASS", + sdbuf.clock_enable_output_a = "BYPASS", + sdbuf.clock_enable_output_b = "BYPASS", + sdbuf.indata_reg_b = "CLOCK1", + sdbuf.intended_device_family = "Cyclone V", + sdbuf.lpm_type = "altsyncram", + sdbuf.operation_mode = "BIDIR_DUAL_PORT", + sdbuf.outdata_aclr_a = "NONE", + sdbuf.outdata_aclr_b = "NONE", + sdbuf.outdata_reg_a = "UNREGISTERED", + sdbuf.outdata_reg_b = "UNREGISTERED", + sdbuf.power_up_uninitialized = "FALSE", + sdbuf.read_during_write_mode_port_a = "NEW_DATA_NO_NBE_READ", + sdbuf.read_during_write_mode_port_b = "NEW_DATA_NO_NBE_READ", + sdbuf.width_byteena_a = 1, + sdbuf.width_byteena_b = 1, + sdbuf.wrcontrol_wraddress_reg_b = "CLOCK1"; -sdbuf #(WIDE) conf -( - .clock_a(clk_sys), - .address_a(sd_buff_addr), - .data_a(sd_buff_dout), - .wren_a(sd_ack_conf & sd_buff_wr), +reg [26:0] csd_size; +reg csd_sdhc; +always @(posedge clk_sys) begin + if (img_mounted) begin + csd_sdhc <= sdhc; + if (sdhc) begin + csd_size[0] <= 0; + csd_size[22:1] <= img_size[40:19]; // in 512K units + csd_size[26:23] <= 0; + end + else begin + csd_size[2:0] <= 7; // C_SIZE_MULT + csd_size[14:3] <= 12'b101101101101; + csd_size[26:15] <= img_size[29:18]; // in 256K units ((2**(C_SIZE_MULT+2))*512) + end + end +end - .clock_b(clk_spi), - .address_b(buffer_ptr), - .q_b(config_dout) -); +wire [127:0] CSD = {1'b0,csd_sdhc,6'h00,8'h0e,8'h00,8'h32,8'h5b,8'h59,6'h00,csd_size,7'h7f,8'h80,8'h0a,8'h40,8'h40,8'hf1}; +wire [127:0] CID = {8'hcd,8'hc7,8'h00,8'h93,8'h6f,8'h2f,8'h73,8'h00,8'h00,8'h44,8'h32,8'h38,8'h34,8'h00,8'h00,8'h3e}; -reg [31:0] lba, new_lba; reg [8:0] buffer_ptr; reg [7:0] buffer_din; wire [7:0] buffer_dout; -wire [7:0] config_dout; reg buffer_wr; -always @(posedge clk_spi) begin - reg [2:0] read_state; - reg [2:0] write_state; - reg [6:0] sbuf; - reg cmd55; - reg [7:0] cmd; - reg [2:0] bit_cnt; - reg [3:0] byte_cnt; - reg [7:0] reply; - reg [7:0] reply0, reply1, reply2, reply3; - reg [3:0] reply_len; - reg tx_finish; - reg rx_finish; - reg old_sck; - reg synced; - reg [5:0] ack; - reg io_ack; - reg [4:0] idle_cnt = 0; - reg [2:0] wait_m_cnt; +reg [1:0] sd_buf, spi_buf; + +reg [6:0] sbuf; +reg [2:0] bit_cnt; + +wire last_bit = &bit_cnt || OCTAL; +wire [7:0] ibuf = OCTAL ? mosi : {sbuf,mosi[0]}; + +always @(posedge clk_spi) begin + reg [2:0] read_state; + reg [2:0] write_state; + reg [1:0] pref_state; + reg [5:0] cmd; + reg cmd55; + reg [39:0] reply; + reg [3:0] byte_cnt; + reg old_sck; + reg [2:0] ack; + reg [2:0] wait_m_cnt; + reg [31:0] arg; + + ack[1:0] <= {ack[0],sd_ack}; + if(ack[1] == ack[0]) ack[2] <= ack[1]; + + if(~ack[2] & ack[1]) {sd_rd,sd_wr} <= 0; + if( ack[2] & ~ack[1]) begin + sd_buf <= sd_buf + 1'd1; + sd_lba <= sd_lba + 1; + end - if(buffer_wr & ~&buffer_ptr) buffer_ptr <= buffer_ptr + 1'd1; buffer_wr <= 0; - ack <= {ack[4:0], sd_ack}; - if(ack[5:4] == 2'b10) io_ack <= 1; - if(ack[5:4] == 2'b01) {sd_rd,sd_wr} <= 0; - - old_sck <= sck; - - if(~ss) idle_cnt <= 31; - else if(~old_sck && sck && idle_cnt) idle_cnt <= idle_cnt - 1'd1; - - if(reset || !idle_cnt) begin + if(reset) begin bit_cnt <= 0; - byte_cnt <= 15; - synced <= 0; - miso <= 1; - sbuf <= 7'b1111111; - tx_finish <= 0; - rx_finish <= 0; + byte_cnt <= '1; + miso <= '1; + cmd <= 0; + sd_wr <= 0; + sd_rd <= 0; read_state <= RD_STATE_IDLE; write_state <= WR_STATE_IDLE; + pref_state <= PREF_STATE_IDLE; end + else begin - if(old_sck & ~sck & ~ss) begin - tx_finish <= 0; - miso <= 1; // default: send 1's (busy/wait) - - if(byte_cnt == 5+NCR) begin - miso <= reply[~bit_cnt]; - - if(bit_cnt == 7) begin - // these three commands all have a reply_len of 0 and will thus - // not send more than a single reply byte - - // CMD9: SEND_CSD - // CMD10: SEND_CID - if((cmd == 'h49) | (cmd == 'h4a)) - read_state <= RD_STATE_SEND_TOKEN; // jump directly to data transmission - - // CMD17/CMD18 - if((cmd == 'h51) | (cmd == 'h52)) begin - io_ack <= 0; - read_state <= RD_STATE_WAIT_IO; // start waiting for data from io controller - lba <= new_lba; - sd_rd <= 1; // trigger request to io controller - end + if(buffer_wr) begin + if(~&buffer_ptr) buffer_ptr <= buffer_ptr + 1'd1; + else begin + spi_buf <= spi_buf + 1'd1; + sd_wr <= 1; end end - else if((reply_len > 0) && (byte_cnt == 5+NCR+1)) miso <= reply0[~bit_cnt]; - else if((reply_len > 1) && (byte_cnt == 5+NCR+2)) miso <= reply1[~bit_cnt]; - else if((reply_len > 2) && (byte_cnt == 5+NCR+3)) miso <= reply2[~bit_cnt]; - else if((reply_len > 3) && (byte_cnt == 5+NCR+4)) miso <= reply3[~bit_cnt]; - else begin - if(byte_cnt > 5+NCR && read_state==RD_STATE_IDLE && write_state==WR_STATE_IDLE) tx_finish <= 1; - end - // ---------- read state machine processing ------------- - - case(read_state) - RD_STATE_IDLE: ; // do nothing - - - // waiting for io controller to return data - RD_STATE_WAIT_IO: begin - if(io_ack & (bit_cnt == 7)) read_state <= RD_STATE_SEND_TOKEN; - end - - // send data token - RD_STATE_SEND_TOKEN: begin - miso <= READ_DATA_TOKEN[~bit_cnt]; - - if(bit_cnt == 7) begin - read_state <= RD_STATE_SEND_DATA; // next: send data - buffer_ptr <= 0; - if(cmd == 'h49) buffer_ptr <= 16; + case(pref_state) + PREF_STATE_IDLE: + if(((sd_buf - spi_buf) <= 1) && (read_state != RD_STATE_IDLE) && (cmd == 17 || cmd == 18)) begin + sd_rd <= 1; + pref_state <= PREF_STATE_RD; end - end - // send data - RD_STATE_SEND_DATA: begin - - miso <= ((cmd == 'h49) | (cmd == 'h4A)) ? config_dout[~bit_cnt] : buffer_dout[~bit_cnt]; - - if(bit_cnt == 7) begin - - // sent 512 sector data bytes? - if((cmd == 'h51) & &buffer_ptr) read_state <= RD_STATE_IDLE; - else if((cmd == 'h52) & &buffer_ptr) begin - read_state <= RD_STATE_WAIT_M; - wait_m_cnt <= 0; - end - - // sent 16 cid/csd data bytes? - else if(((cmd == 'h49) | (cmd == 'h4a)) & (&buffer_ptr[3:0])) read_state <= RD_STATE_IDLE; - - // not done yet -> trigger read of next data byte - else buffer_ptr <= buffer_ptr + 1'd1; + PREF_STATE_RD: + if(read_state == RD_STATE_IDLE) begin + pref_state <= PREF_STATE_IDLE; end - end - - RD_STATE_WAIT_M: begin - if(bit_cnt == 7) begin - wait_m_cnt <= wait_m_cnt + 1'd1; - if(&wait_m_cnt) begin - lba <= lba + 1; - io_ack <= 0; - sd_rd <= 1; - read_state <= RD_STATE_WAIT_IO; - end + else if(ack[2] & ~ack[1]) begin + pref_state <= (cmd == 18) ? PREF_STATE_IDLE : PREF_STATE_FINISH; + end + + PREF_STATE_FINISH: + if(read_state == RD_STATE_IDLE) begin + pref_state <= PREF_STATE_IDLE; end - end endcase - // ------------------ write support ---------------------- - // send write data response - if(write_state == WR_STATE_SEND_DRESP) miso <= WRITE_DATA_RESPONSE[~bit_cnt]; - - // busy after write until the io controller sends ack - if(write_state == WR_STATE_BUSY) miso <= 0; - end - - if(~old_sck & sck & ~ss) begin - - if(synced) bit_cnt <= bit_cnt + 1'd1; - - // assemble byte - if(bit_cnt != 7) begin - sbuf[6:0] <= { sbuf[5:0], mosi }; - - // resync while waiting for token - if(write_state==WR_STATE_EXP_DTOKEN) begin - if(cmd == 'h58) begin - if({sbuf,mosi} == 8'hfe) begin - write_state <= WR_STATE_RECV_DATA; - buffer_ptr <= 0; - bit_cnt <= 0; - end - end - else begin - if({sbuf,mosi} == 8'hfc) begin - write_state <= WR_STATE_RECV_DATA; - buffer_ptr <= 0; - bit_cnt <= 0; - end - if({sbuf,mosi} == 8'hfd) begin - write_state <= WR_STATE_IDLE; - rx_finish <= 1; - bit_cnt <= 0; - end - end - end + old_sck <= sck; + if(ss) begin + bit_cnt <= 0; + byte_cnt <= '1; + miso <= '1; end - else begin - // finished reading one byte - // byte counter runs against 15 byte boundary - if(byte_cnt != 15) byte_cnt <= byte_cnt + 1'd1; + else if(old_sck & ~sck) begin + miso <= '1; // default: send 1's (busy/wait) + if(byte_cnt >= NCR) {miso,reply} <= {reply, {SZ{1'b1}}}; - // byte_cnt > 6 -> complete command received - // first byte of valid command is 01xxxxxx - // don't accept new commands once a write or read command has been accepted - if((byte_cnt > 5) & (write_state == WR_STATE_IDLE) & (read_state == RD_STATE_IDLE) && !rx_finish) begin - byte_cnt <= 0; - cmd <= { sbuf, mosi}; + // ---------- read state machine processing ------------- + case(read_state) + RD_STATE_IDLE: ; - // set cmd55 flag if previous command was 55 - cmd55 <= (cmd == 'h77); - end + RD_STATE_START: begin + if(byte_cnt == NCR && last_bit) read_state <= (cmd == 9 || cmd == 10) ? RD_STATE_SEND_TOKEN : RD_STATE_WAIT_IO; + end - if((byte_cnt > 5) & (read_state == RD_STATE_WAIT_M) && ({sbuf, mosi} == 8'h4c)) begin - byte_cnt <= 0; - rx_finish <= 0; - cmd <= {sbuf, mosi}; - read_state <= RD_STATE_IDLE; - end + // waiting for io controller to return data + RD_STATE_WAIT_IO: begin + if(sd_buf != spi_buf && last_bit) read_state <= RD_STATE_SEND_TOKEN; + end - // parse additional command bytes - if(byte_cnt == 0) new_lba[31:24] <= { sbuf, mosi}; - if(byte_cnt == 1) new_lba[23:16] <= { sbuf, mosi}; - if(byte_cnt == 2) new_lba[15:8] <= { sbuf, mosi}; - if(byte_cnt == 3) new_lba[7:0] <= { sbuf, mosi}; - - // last byte (crc) received, evaluate - if(byte_cnt == 4) begin - - // default: - reply <= 4; // illegal command - reply_len <= 0; // no extra reply bytes - rx_finish <= 1; - - case(cmd) - // CMD0: GO_IDLE_STATE - 'h40: reply <= 1; // ok, busy - - // CMD1: SEND_OP_COND - 'h41: reply <= 0; // ok, not busy - - // CMD8: SEND_IF_COND (V2 only) - 'h48: begin - reply <= 1; // ok, busy - - reply0 <= 'h00; - reply1 <= 'h00; - reply2 <= 'h01; - reply3 <= 'hAA; - reply_len <= 4; - end - - // CMD9: SEND_CSD - 'h49: reply <= 0; // ok - - // CMD10: SEND_CID - 'h4a: reply <= 0; // ok - - // CMD12: STOP_TRANSMISSION - 'h4c: reply <= 0; // ok - - // CMD13: SEND_STATUS - 'h4d: begin - reply <= 'h00; // ok - reply0 <='h00; - reply_len <= 1; - end - - // CMD16: SET_BLOCKLEN - 'h50: begin - // we only support a block size of 512 - if(new_lba == 512) reply <= 0; // ok - else reply <= 'h40; // parmeter error - end - - // CMD17: READ_SINGLE_BLOCK - 'h51: reply <= 0; // ok - - // CMD18: READ_MULTIPLE - 'h52: reply <= 0; // ok - // ACMD23: SET_WR_BLK_ERASE_COUNT - 'h57: reply <= 0; //ok - - // CMD24: WRITE_BLOCK - 'h58, - // CMD25: WRITE_MULTIPLE - 'h59: begin - reply <= 0; // ok - write_state <= WR_STATE_EXP_DTOKEN; // expect data token - rx_finish <=0; - lba <= new_lba; - end - - // ACMD41: APP_SEND_OP_COND - 'h69: if(cmd55) reply <= 0; // ok, not busy - - // CMD55: APP_COND - 'h77: reply <= 1; // ok, busy - - // CMD58: READ_OCR - 'h7a: begin - reply <= 0; // ok - - reply0 <= OCR[31:24]; // bit 30 = 1 -> high capacity card - reply1 <= OCR[23:16]; - reply2 <= OCR[15:8]; - reply3 <= OCR[7:0]; - reply_len <= 4; - end - - // CMD59: CRC_ON_OFF - 'h7b: reply <= 0; // ok - endcase - end - - // ---------- handle write ----------- - case(write_state) - // do nothing in idle state - WR_STATE_IDLE: ; - - // waiting for data token - WR_STATE_EXP_DTOKEN: begin - buffer_ptr <= 0; - if(cmd == 'h58) begin - if({sbuf,mosi} == 8'hfe) write_state <= WR_STATE_RECV_DATA; - end - else begin - if({sbuf,mosi} == 8'hfc) write_state <= WR_STATE_RECV_DATA; - if({sbuf,mosi} == 8'hfd) begin - write_state <= WR_STATE_IDLE; - rx_finish <= 1; - end + // send data token + RD_STATE_SEND_TOKEN: begin + miso <= DATA_TOKEN[~bit_cnt -:SZ]; + if(last_bit) begin + read_state <= RD_STATE_SEND_DATA; // next: send data + buffer_ptr <= 0; end end - // transfer 512 bytes - WR_STATE_RECV_DATA: begin - // push one byte into local buffer - buffer_wr <= 1; - buffer_din <= {sbuf, mosi}; + // send data + RD_STATE_SEND_DATA: begin - // all bytes written? - if(&buffer_ptr) write_state <= WR_STATE_RECV_CRC0; + miso <= (cmd == 9) ? CSD[{buffer_ptr[3:0],~bit_cnt} -:SZ] : (cmd == 10) ? CID[{buffer_ptr[3:0],~bit_cnt} -:SZ] : buffer_dout[~bit_cnt -:SZ]; + + if(last_bit) begin + + // sent 512 sector data bytes? + if(cmd == 17 && &buffer_ptr) read_state <= RD_STATE_IDLE; + else if(cmd == 18 && &buffer_ptr) begin + read_state <= RD_STATE_WAIT_M; + wait_m_cnt <= 0; + end + + // sent 16 cid/csd data bytes? + else if((cmd == 9 || cmd == 10) && &buffer_ptr[3:0]) read_state <= RD_STATE_IDLE; + + // not done yet -> trigger read of next data byte + else buffer_ptr <= buffer_ptr + 1'd1; + end end - // transfer 1st crc byte - WR_STATE_RECV_CRC0: - write_state <= WR_STATE_RECV_CRC1; + RD_STATE_WAIT_M: begin + if(last_bit) begin + wait_m_cnt <= wait_m_cnt + 1'd1; + if(&wait_m_cnt) begin + spi_buf <= spi_buf + 1'd1; + read_state <= RD_STATE_WAIT_IO; + end + end + end + endcase - // transfer 2nd crc byte - WR_STATE_RECV_CRC1: - write_state <= WR_STATE_SEND_DRESP; + // ------------------ write support ---------------------- + // send write data response + if(write_state == WR_STATE_SEND_DRESP) miso <= WRITE_DATA_RESPONSE[~bit_cnt -:SZ]; - // send data response - WR_STATE_SEND_DRESP: begin - write_state <= WR_STATE_BUSY; - io_ack <= 0; - sd_wr <= 1; + // busy after write until the io controller sends ack + if(write_state == WR_STATE_BUSY) miso <= 0; + end + else if(~old_sck & sck) begin + + sbuf[6:0] <= {sbuf[5:0],mosi[0]}; + bit_cnt <= bit_cnt + SZ[2:0]; + + if(last_bit) begin + // finished reading one byte + // byte counter runs against 15 byte boundary + if(~&byte_cnt) byte_cnt <= byte_cnt + 1'd1; + + // byte_cnt > 6 -> complete command received + // first byte of valid command is 01xxxxxx + // don't accept new commands once a write or read command has been accepted + if(byte_cnt > 5 && + ((write_state == WR_STATE_IDLE && read_state == RD_STATE_IDLE && ibuf[7:6] == 1) || + (read_state != RD_STATE_IDLE && ibuf == 8'h4c))) begin + byte_cnt <= 0; + cmd <= ibuf[5:0]; + cmd55 <= (cmd == 55); // set cmd55 flag if previous command was 55 + if(ibuf[5:0] == 12) read_state <= RD_STATE_IDLE; end - // wait for io controller to accept data - WR_STATE_BUSY: - if(io_ack) begin - if(cmd == 'h59) begin - write_state <= WR_STATE_EXP_DTOKEN; - lba <= lba + 1; + // parse additional command bytes + if(byte_cnt == 0) arg[31:24] <= ibuf; + if(byte_cnt == 1) arg[23:16] <= ibuf; + if(byte_cnt == 2) arg[15:8] <= ibuf; + if(byte_cnt == 3) arg[7:0] <= ibuf; + + // last byte (crc) received, evaluate + if(byte_cnt == 4) begin + + // default: + reply <= 40'h04FFFFFFFF; // illegal command + + case(cmd) + // CMD0: GO_IDLE_STATE + 0: reply[39:32] <= 1; // ok, busy + + // CMD1: SEND_OP_COND + 1: reply[39:32] <= 0; + + // CMD8: SEND_IF_COND (V2 only) + 8: reply <= 40'h01000001AA; // ok, busy + + // CMD9: SEND_CSD + 9, + // CMD10: SEND_CID + 10: begin + reply[39:32] <= 0; + read_state <= RD_STATE_START; + end + + // CMD12: STOP_TRANSMISSION + 12: reply[39:32] <= 0; + + // CMD13: SEND_STATUS + 13: reply[39:24] <= 16'h0000; + + // CMD16: SET_BLOCKLEN + 16: reply[39:32] <= (arg == 512) ? 8'h00 : 8'h40; // we only support a block size of 512 + + // CMD17: READ_SINGLE_BLOCK + 17, + // CMD18: READ_MULTIPLE + 18: begin + reply[39:32] <= 0; + read_state <= RD_STATE_START; + spi_buf <= 0; + sd_buf <= 0; + sd_lba <= csd_sdhc ? arg : {9'd0, arg[31:9]}; + end + + // ACMD23: SET_WR_BLK_ERASE_COUNT + 23: reply[39:32] <= 0; + + // CMD24: WRITE_BLOCK + 24, + // CMD25: WRITE_MULTIPLE + 25: begin + reply[39:32] <= 0; + write_state <= WR_STATE_EXP_DTOKEN; // expect data token + spi_buf <= 0; + sd_buf <= 0; + sd_lba <= csd_sdhc ? arg : {9'd0, arg[31:9]}; + end + + // ACMD41: APP_SEND_OP_COND + 41: if(cmd55) reply[39:32] <= 0; // ok, not busy + + // CMD55: APP_COND + 55: reply[39:32] <= 1; // ok, busy + + // CMD58: READ_OCR + 58: reply <= { 8'h00, 1'b1, csd_sdhc, 30'd0 }; // bit 30 = 1 -> high capacity card + + // CMD59: CRC_ON_OFF + 59: reply[39:32] <= 0; + endcase + end + + // ---------- handle write ----------- + case(write_state) + // do nothing in idle state + WR_STATE_IDLE: ; + + // waiting for data token + WR_STATE_EXP_DTOKEN: begin + buffer_ptr <= 0; + if(cmd == 24) begin + if(ibuf == DATA_TOKEN) write_state <= WR_STATE_RECV_DATA; end else begin - write_state <= WR_STATE_IDLE; - rx_finish <= 1; + if(ibuf == DATA_TOKEN_CMD25) write_state <= WR_STATE_RECV_DATA; + if(ibuf == STOP_TRAN) write_state <= WR_STATE_IDLE; end end - endcase - end - - // wait for first 0 bit until start counting bits - if(!synced && !mosi) begin - synced <= 1; - bit_cnt <= 1; // byte assembly prepare for next time loop - sbuf <= 7'b1111110; // byte assembly prepare for next time loop - rx_finish<= 0; - end else if (synced && tx_finish && rx_finish ) begin - synced <= 0; - bit_cnt <= 0; - rx_finish<= 0; + + // transfer 512 bytes + WR_STATE_RECV_DATA: begin + // push one byte into local buffer + buffer_wr <= 1; + buffer_din <= ibuf; + + // all bytes written? + if(&buffer_ptr) write_state <= WR_STATE_RECV_CRC0; + end + + // transfer 1st crc byte + WR_STATE_RECV_CRC0: + write_state <= WR_STATE_RECV_CRC1; + + // transfer 2nd crc byte + WR_STATE_RECV_CRC1: + write_state <= WR_STATE_SEND_DRESP; + + // send data response + WR_STATE_SEND_DRESP: + write_state <= WR_STATE_BUSY; + + // wait for io controller to accept data + WR_STATE_BUSY: + if(spi_buf == sd_buf) write_state <= (cmd == 25) ? WR_STATE_EXP_DTOKEN : WR_STATE_IDLE; + endcase + end end end end endmodule - -module sdbuf #(parameter WIDE) -( - input clock_a, - input [AW:0] address_a, - input [DW:0] data_a, - input wren_a, - output reg [DW:0] q_a, - - input clock_b, - input [8:0] address_b, - input [7:0] data_b, - input wren_b, - output reg [7:0] q_b -); - -localparam AW = WIDE ? 7 : 8; -localparam DW = WIDE ? 15 : 7; - -always@(posedge clock_a) begin - if(wren_a) begin - ram[address_a] <= data_a; - q_a <= data_a; - end - else begin - q_a <= ram[address_a]; - end -end - -generate - if(WIDE) begin - reg [1:0][7:0] ram[1<<8]; - always@(posedge clock_b) begin - if(wren_b) begin - ram[address_b[8:1]][address_b[0]] <= data_b; - q_b <= data_b; - end - else begin - q_b <= ram[address_b[8:1]][address_b[0]]; - end - end - end - else begin - reg [7:0] ram[1<<9]; - always@(posedge clock_b) begin - if(wren_b) begin - ram[address_b] <= data_b; - q_b <= data_b; - end - else begin - q_b <= ram[address_b]; - end - end - end -endgenerate - -endmodule diff --git a/sys/sys.qip b/sys/sys.qip index eeae907..2854eaf 100644 --- a/sys/sys.qip +++ b/sys/sys.qip @@ -11,6 +11,7 @@ set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) v set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) gamma_corr.sv ] set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) video_mixer.sv ] set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) video_freak.sv ] +set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) video_freezer.sv ] set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) arcade_video.v ] set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) osd.v ] set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) vga_out.sv ] @@ -29,4 +30,4 @@ set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) f set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) ddr_svc.sv ] set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) sysmem.sv ] set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) sd_card.sv ] -set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) hps_io.v ] +set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) hps_io.sv ] diff --git a/sys/sys_top.sdc b/sys/sys_top.sdc index 8187969..cf2d492 100644 --- a/sys/sys_top.sdc +++ b/sys/sys_top.sdc @@ -67,3 +67,5 @@ set_false_path -from {ascal|o_hdisp* ascal|o_vdisp*} set_false_path -from {ascal|o_htotal* ascal|o_vtotal*} set_false_path -from {ascal|o_hsstart* ascal|o_vsstart* ascal|o_hsend* ascal|o_vsend*} set_false_path -from {ascal|o_hsize* ascal|o_vsize*} + +set_false_path -from {mcp23009|sd_cd} diff --git a/sys/sys_top.v b/sys/sys_top.v index 8f0043c..dbf8a8a 100644 --- a/sys/sys_top.v +++ b/sys/sys_top.v @@ -19,18 +19,6 @@ // //============================================================================ -`ifndef ARCADE_SYS - `define USE_DDRAM - `define USE_SDRAM -`endif - -`ifndef USE_DDRAM - `ifdef USE_FB - `define USE_DDRAM - `endif -`endif - - module sys_top ( /////////// CLOCK ////////// @@ -68,7 +56,7 @@ module sys_top output SDRAM_CLK, output SDRAM_CKE, -`ifdef DUAL_SDRAM +`ifdef MISTER_DUAL_SDRAM ////////// SDR #2 ////////// output [12:0] SDRAM2_A, inout [15:0] SDRAM2_DQ, @@ -139,20 +127,14 @@ module sys_top ////////////////////// Secondary SD /////////////////////////////////// wire SD_CS, SD_CLK, SD_MOSI; -`ifdef ARCADE_SYS - assign SD_CS = 1'bZ; - assign SD_CLK = 1'bZ; - assign SD_MOSI = 1'bZ; +`ifndef MISTER_DUAL_SDRAM + wire sd_miso = SW[3] | SDIO_DAT[0]; `else - `ifndef DUAL_SDRAM - wire sd_miso = SW[3] | SDIO_DAT[0]; - `else - wire sd_miso = 1; - `endif - wire SD_MISO = mcp_sdcd ? sd_miso : SD_SPI_MISO; + wire sd_miso = 1; `endif +wire SD_MISO = mcp_sdcd ? sd_miso : SD_SPI_MISO; -`ifndef DUAL_SDRAM +`ifndef MISTER_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; @@ -175,7 +157,7 @@ wire led_d = led_disk[1] ? ~led_disk[0] : ~(led_disk[0] | gp_out[29]); wire led_u = ~led_user; wire led_locked; -`ifndef DUAL_SDRAM +`ifndef MISTER_DUAL_SDRAM assign LED_POWER = (SW[3] | led_p) ? 1'bZ : 1'b0; assign LED_HDD = (SW[3] | led_d) ? 1'bZ : 1'b0; assign LED_USER = (SW[3] | led_u) ? 1'bZ : 1'b0; @@ -185,7 +167,7 @@ wire led_locked; assign LED = (led_overtake & led_state) | (~led_overtake & {1'b0,led_locked,1'b0, ~led_p, 1'b0, ~led_d, 1'b0, ~led_u}); wire btn_r, btn_o, btn_u; -`ifdef DUAL_SDRAM +`ifdef MISTER_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]}; @@ -233,7 +215,7 @@ end 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. +wire [1:0] io_ver = 1; // 0 - obsolete. 1 - optimized HPS I/O. 2,3 - reserved for future. wire io_wait; wire io_wide; wire [15:0] io_dout; @@ -243,7 +225,7 @@ wire io_ss0 = gp_outr[18]; wire io_ss1 = gp_outr[19]; wire io_ss2 = gp_outr[20]; -`ifndef DEBUG_NOHDMI +`ifndef MISTER_DEBUG_NOHDMI wire io_osd_hdmi = io_ss1 & ~io_ss0; `endif @@ -268,7 +250,7 @@ always @(posedge clk_sys) begin gp_outd <= gp_out; end -`ifdef DUAL_SDRAM +`ifdef MISTER_DUAL_SDRAM wire [7:0] core_type = 'hA8; // generic core, dual SDRAM. `else wire [7:0] core_type = 'hA4; // generic core. @@ -290,7 +272,7 @@ reg cfg_set = 0; wire vga_fb = cfg[12] | vga_force_scaler; wire [1:0] hdmi_limited = {cfg[11],cfg[8]}; -`ifdef DEBUG_NOHDMI +`ifdef MISTER_DEBUG_NOHDMI wire direct_video = 1; `else wire direct_video = cfg[10]; @@ -301,7 +283,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 +`ifndef MISTER_DUAL_SDRAM wire sog = cfg[9]; wire vga_scaler = cfg[2] | vga_force_scaler; `endif @@ -310,7 +292,8 @@ reg cfg_custom_t = 0; reg [5:0] cfg_custom_p1; reg [31:0] cfg_custom_p2; -reg [4:0] vol_att = 0; +reg [4:0] vol_att; +initial vol_att = 5'b11111; reg [6:0] coef_addr; reg [8:0] coef_data; @@ -399,7 +382,7 @@ always@(posedge clk_sys) begin 6: if(VS != io_din[11:0]) VS <= io_din[11:0]; 7: if(VBP != io_din[11:0]) VBP <= io_din[11:0]; endcase -`ifndef DEBUG_NOHDMI +`ifndef MISTER_DEBUG_NOHDMI if(cnt == 1) begin cfg_custom_p1 <= 0; cfg_custom_p2 <= 0; @@ -481,9 +464,7 @@ end cyclonev_hps_interface_peripheral_uart uart ( - .ri(0) -`ifndef ARCADE_SYS - , + .ri(0), .dsr(uart_dsr), .dcd(uart_dsr), .dtr(uart_dtr), @@ -492,7 +473,6 @@ cyclonev_hps_interface_peripheral_uart uart .rts(uart_rts), .rxd(uart_rxd), .txd(uart_txd) -`endif ); wire aspi_sck,aspi_mosi,aspi_ss,aspi_miso; @@ -547,7 +527,6 @@ sysmem_lite sysmem //DE10-nano has no reset signal on GPIO, so core has to emulate cold reset button. .reset_hps_cold_req(btn_r), -`ifdef USE_DDRAM //64-bit DDR3 RAM access .ram1_clk(ram_clk), .ram1_address(ram_address), @@ -559,7 +538,6 @@ sysmem_lite sysmem .ram1_writedata(ram_writedata), .ram1_byteenable(ram_byteenable), .ram1_write(ram_write), -`endif //64-bit DDR3 RAM access .ram2_clk(clk_audio), @@ -641,15 +619,20 @@ wire vbuf_write; wire [23:0] hdmi_data; wire hdmi_vs, hdmi_hs, hdmi_de, hdmi_vbl; +wire freeze; -`ifndef DEBUG_NOHDMI +`ifndef MISTER_DEBUG_NOHDMI wire clk_hdmi = hdmi_clk_out; ascal #( .RAMBASE(32'h20000000), -`ifndef USE_FB +`ifndef MISTER_FB .PALETTE2("false"), +`else + `ifndef MISTER_FB_PALETTE + .PALETTE2("false"), + `endif `endif .N_DW(128), .N_AW(28) @@ -658,7 +641,7 @@ ascal ( .reset_na (~reset_req), .run (1), - .freeze (0), + .freeze (freeze), .i_clk (clk_ihdmi), .i_ce (ce_hpix), @@ -709,13 +692,15 @@ ascal .pal1_a (pal_a), .pal1_wr (pal_wr), -`ifdef USE_FB - .pal2_clk (fb_pal_clk), - .pal2_dw (fb_pal_d), - .pal2_dr (fb_pal_q), - .pal2_a (fb_pal_a), - .pal2_wr (fb_pal_wr), - .pal_n (fb_en), +`ifdef MISTER_FB + `ifdef MISTER_FB_PALETTE + .pal2_clk (fb_pal_clk), + .pal2_dw (fb_pal_d), + .pal2_dr (fb_pal_q), + .pal2_a (fb_pal_a), + .pal2_wr (fb_pal_wr), + .pal_n (fb_en), + `endif `endif .o_fb_ena (FB_EN), @@ -775,7 +760,7 @@ always @(posedge clk_sys) begin end end -`ifdef USE_FB +`ifdef MISTER_FB reg fb_vbl; always @(posedge clk_vid) fb_vbl <= hdmi_vbl; `endif @@ -899,7 +884,7 @@ always @(posedge clk_vid) begin vmax <= vmaxi; end -`ifndef DEBUG_NOHDMI +`ifndef MISTER_DEBUG_NOHDMI wire [15:0] lltune; pll_hdmi_adj pll_hdmi_adj ( @@ -942,7 +927,7 @@ end ///////////////////////// HDMI output ///////////////////////////////// -`ifndef DEBUG_NOHDMI +`ifndef MISTER_DEBUG_NOHDMI wire hdmi_clk_out; pll_hdmi pll_hdmi ( @@ -974,7 +959,7 @@ reg adj_write; reg [5:0] adj_address; reg [31:0] adj_data; -`ifndef DEBUG_NOHDMI +`ifndef MISTER_DEBUG_NOHDMI pll_cfg pll_cfg ( .mgmt_clk(FPGA_CLK1_50), @@ -1063,11 +1048,11 @@ cyclonev_hps_interface_peripheral_i2c hdmi_i2c .sda(HDMI_I2C_SDA) ); -`ifndef DEBUG_NOHDMI +`ifndef MISTER_DEBUG_NOHDMI wire [23:0] hdmi_data_sl; wire hdmi_de_sl, hdmi_vs_sl, hdmi_hs_sl; -`ifdef USE_FB +`ifdef MISTER_FB reg dis_output; always @(posedge clk_hdmi) begin reg dis; @@ -1115,10 +1100,6 @@ osd hdmi_osd .hs_out(hdmi_hs_osd), .vs_out(hdmi_vs_osd), .de_out(hdmi_de_osd) -`ifndef ARCADE_SYS - , - .osd_status(osd_status) -`endif ); `endif @@ -1167,7 +1148,7 @@ always @(posedge clk_vid) begin end wire hdmi_tx_clk; -`ifndef DEBUG_NOHDMI +`ifndef MISTER_DEBUG_NOHDMI cyclonev_clkselect hdmi_clk_sw ( .clkselect({1'b1, ~vga_fb & direct_video}), @@ -1257,6 +1238,7 @@ osd vga_osd .io_osd(io_osd_vga), .io_strobe(io_strobe), .io_din(io_din), + .osd_status(osd_status), .clk_video(clk_vid), .din(vga_data_sl), @@ -1272,7 +1254,7 @@ osd vga_osd wire vga_cs_osd; csync csync_vga(clk_vid, vga_hs_osd, vga_vs_osd, vga_cs_osd); -`ifndef DUAL_SDRAM +`ifndef MISTER_DUAL_SDRAM wire [23:0] vgas_o; wire vgas_hs, vgas_vs, vgas_cs; vga_out vga_scaler_out @@ -1343,7 +1325,7 @@ end assign SDCD_SPDIF =(SW[3] & ~spdif) ? 1'b0 : 1'bZ; -`ifndef DUAL_SDRAM +`ifndef MISTER_DUAL_SDRAM wire analog_l, analog_r; assign AUDIO_SPDIF = SW[3] ? 1'bZ : SW[0] ? HDMI_LRCLK : spdif; @@ -1390,7 +1372,7 @@ audio_out audio_out .i2s_bclk(HDMI_SCLK), .i2s_lrclk(HDMI_LRCLK), .i2s_data(HDMI_I2S), -`ifndef DUAL_SDRAM +`ifndef MISTER_DUAL_SDRAM .dac_l(analog_l), .dac_r(analog_r), `endif @@ -1457,18 +1439,16 @@ wire hvs_fix, hhs_fix, hde_emu; wire clk_vid, ce_pix, clk_ihdmi, ce_hpix; wire vga_force_scaler; -`ifdef USE_DDRAM - 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; -`endif +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; @@ -1480,10 +1460,6 @@ sync_fix sync_h(clk_vid, hs_emu, hs_fix); wire [6:0] user_out, user_in; -`ifndef USE_SDRAM -assign {SDRAM_DQ, SDRAM_A, SDRAM_BA, SDRAM_CLK, SDRAM_CKE, SDRAM_DQML, SDRAM_DQMH, SDRAM_nWE, SDRAM_nCAS, SDRAM_nRAS, SDRAM_nCS} = {39'bZ}; -`endif - assign clk_ihdmi= clk_vid; assign ce_hpix = ce_pix; assign hr_out = r_out; @@ -1493,19 +1469,14 @@ assign hhs_fix = hs_fix; assign hvs_fix = vs_fix; assign hde_emu = de_emu; -`ifdef ARCADE_SYS - assign audio_mix = 0; - assign {ADC_SCK, ADC_SDI, ADC_CONVST} = 0; - assign btn = 0; -`else - wire uart_dtr; - wire uart_dsr; - wire uart_cts; - wire uart_rts; - wire uart_rxd; - wire uart_txd; - wire osd_status; -`endif +wire uart_dtr; +wire uart_dsr; +wire uart_cts; +wire uart_rts; +wire uart_rxd; +wire uart_txd; + +wire osd_status; wire fb_en; wire [4:0] fb_fmt; @@ -1514,13 +1485,16 @@ wire [11:0] fb_height; wire [31:0] fb_base; wire [13:0] fb_stride; -`ifdef USE_FB - wire fb_pal_clk; - wire [7:0] fb_pal_a; - wire [23:0] fb_pal_d; - wire [23:0] fb_pal_q; - wire fb_pal_wr; - wire fb_force_blank; + +`ifdef MISTER_FB + `ifdef MISTER_FB_PALETTE + wire fb_pal_clk; + wire [7:0] fb_pal_a; + wire [23:0] fb_pal_d; + wire [23:0] fb_pal_q; + wire fb_pal_wr; + `endif + wire fb_force_blank; `else assign fb_en = 0; assign fb_fmt = 0; @@ -1550,6 +1524,7 @@ emu emu .HDMI_WIDTH(direct_video ? 12'd0 : hdmi_width), .HDMI_HEIGHT(direct_video ? 12'd0 : hdmi_height), + .HDMI_FREEZE(freeze), .CLK_VIDEO(clk_vid), .CE_PIXEL(ce_pix), @@ -1557,7 +1532,7 @@ emu emu .VIDEO_ARX(ARX), .VIDEO_ARY(ARY), -`ifdef USE_FB +`ifdef MISTER_FB .FB_EN(fb_en), .FB_FORMAT(fb_fmt), .FB_WIDTH(fb_width), @@ -1568,11 +1543,14 @@ emu emu .FB_LL(lowlat), .FB_FORCE_BLANK(fb_force_blank), +`ifdef MISTER_FB_PALETTE .FB_PAL_CLK (fb_pal_clk), .FB_PAL_ADDR(fb_pal_a), .FB_PAL_DOUT(fb_pal_d), .FB_PAL_DIN (fb_pal_q), .FB_PAL_WR (fb_pal_wr), +`endif + `endif .LED_USER(led_user), @@ -1583,13 +1561,10 @@ emu emu .AUDIO_L(audio_l), .AUDIO_R(audio_r), .AUDIO_S(audio_s), - -`ifndef ARCADE_SYS .AUDIO_MIX(audio_mix), - .ADC_BUS({ADC_SCK,ADC_SDO,ADC_SDI,ADC_CONVST}), -`endif -`ifdef USE_DDRAM + .ADC_BUS({ADC_SCK,ADC_SDO,ADC_SDI,ADC_CONVST}), + .DDRAM_CLK(ram_clk), .DDRAM_ADDR(ram_address), .DDRAM_BURSTCNT(ram_burstcount), @@ -1600,9 +1575,7 @@ emu emu .DDRAM_DIN(ram_writedata), .DDRAM_BE(ram_byteenable), .DDRAM_WE(ram_write), -`endif -`ifdef USE_SDRAM .SDRAM_DQ(SDRAM_DQ), .SDRAM_A(SDRAM_A), .SDRAM_DQML(SDRAM_DQML), @@ -1614,9 +1587,8 @@ emu emu .SDRAM_nCAS(SDRAM_nCAS), .SDRAM_CLK(SDRAM_CLK), .SDRAM_CKE(SDRAM_CKE), -`endif -`ifdef DUAL_SDRAM +`ifdef MISTER_DUAL_SDRAM .SDRAM2_DQ(SDRAM2_DQ), .SDRAM2_A(SDRAM2_A), .SDRAM2_BA(SDRAM2_BA), @@ -1628,14 +1600,14 @@ emu emu .SDRAM2_EN(SW[3]), `endif -`ifndef ARCADE_SYS .BUTTONS(btn), .OSD_STATUS(osd_status), + .SD_SCK(SD_CLK), .SD_MOSI(SD_MOSI), .SD_MISO(SD_MISO), .SD_CS(SD_CS), -`ifdef DUAL_SDRAM +`ifdef MISTER_DUAL_SDRAM .SD_CD(mcp_sdcd), `else .SD_CD(mcp_sdcd & (SW[0] ? VGA_HS : (SW[3] | SDCD_SPDIF))), @@ -1647,7 +1619,6 @@ emu emu .UART_TXD(uart_rxd), .UART_DTR(uart_dsr), .UART_DSR(uart_dtr), -`endif .USER_OUT(user_out), .USER_IN(user_in) diff --git a/sys/vga_out.sv b/sys/vga_out.sv index 43927b2..fe8172b 100644 --- a/sys/vga_out.sv +++ b/sys/vga_out.sv @@ -25,27 +25,44 @@ wire [5:0] blue = din[7:2]; // Pb = 128 - 0.148*R - 0.291*G + 0.439*B (Pb = -0.169*R - 0.331*G + 0.500*B) // Pr = 128 + 0.439*R - 0.368*G - 0.071*B (Pr = 0.500*R - 0.419*G - 0.081*B) -reg [18:0] y_2, pb_2, pr_2; reg [7:0] y, pb, pr; -reg [23:0] din2, din3; -reg hsync2, vsync2, csync2; +reg [23:0] rgb; always @(posedge clk) begin - y_2 <= 19'd04096 + ({red, 8'd0} + {red, 3'd0}) + ({green, 9'd0} + {green, 2'd0}) + ({blue, 6'd0} + {blue, 5'd0} + {blue, 2'd0}); - pb_2 <= 19'd32768 - ({red, 7'd0} + {red, 4'd0} + {red, 3'd0}) - ({green, 8'd0} + {green, 5'd0} + {green, 3'd0}) + ({blue, 8'd0} + {blue, 7'd0} + {blue, 6'd0}); - pr_2 <= 19'd32768 + ({red, 8'd0} + {red, 7'd0} + {red, 6'd0}) - ({green, 8'd0} + {green, 6'd0} + {green, 5'd0} + {green, 4'd0} + {green, 3'd0}) - ({blue, 6'd0} + {blue , 3'd0}); + reg [18:0] y_1r, pb_1r, pr_1r; + reg [18:0] y_1g, pb_1g, pr_1g; + reg [18:0] y_1b, pb_1b, pr_1b; + reg [18:0] y_2, pb_2, pr_2; + reg [23:0] din1, din2; + reg hsync2, vsync2, csync2; + reg hsync1, vsync1, csync1; + + y_1r <= 19'd04096 + ({red, 8'd0} + {red, 3'd0}); + pb_1r <= 19'd32768 - ({red, 7'd0} + {red, 4'd0} + {red, 3'd0}); + pr_1r <= 19'd32768 + ({red, 8'd0} + {red, 7'd0} + {red, 6'd0}); + + y_1g <= {green, 9'd0} + {green, 2'd0}; + pb_1g <= {green, 8'd0} + {green, 5'd0} + {green, 3'd0}; + pr_1g <= {green, 8'd0} + {green, 6'd0} + {green, 5'd0} + {green, 4'd0} + {green, 3'd0}; + + y_1b <= {blue, 6'd0} + {blue, 5'd0} + {blue, 2'd0}; + pb_1b <= {blue, 8'd0} + {blue, 7'd0} + {blue, 6'd0}; + pr_1b <= {blue, 6'd0} + {blue, 3'd0}; + + y_2 <= y_1r + y_1g + y_1b; + pb_2 <= pb_1r - pb_1g + pb_1b; + pr_2 <= pr_1r - pr_1g - pr_1b; y <= ( y_2[18] || !y_2[17:12]) ? 8'd16 : (y_2[17:8] > 235) ? 8'd235 : y_2[15:8]; pb <= (pb_2[18] || !pb_2[17:12]) ? 8'd16 : (&pb_2[17:12]) ? 8'd240 : pb_2[15:8]; pr <= (pr_2[18] || !pr_2[17:12]) ? 8'd16 : (&pr_2[17:12]) ? 8'd240 : pr_2[15:8]; - hsync_o <= hsync2; hsync2 <= hsync; - vsync_o <= vsync2; vsync2 <= vsync; - csync_o <= csync2; csync2 <= csync; + hsync_o <= hsync2; hsync2 <= hsync1; hsync1 <= hsync; + vsync_o <= vsync2; vsync2 <= vsync1; vsync1 <= vsync; + csync_o <= csync2; csync2 <= csync1; csync1 <= csync; - din2 <= din; - din3 <= din2; + rgb <= din2; din2 <= din1; din1 <= din; end -assign dout = ypbpr_en ? {pr, y, pb} : din3; +assign dout = ypbpr_en ? {pr, y, pb} : rgb; endmodule diff --git a/sys/video_freak.sv b/sys/video_freak.sv index e972962..18beb03 100644 --- a/sys/video_freak.sv +++ b/sys/video_freak.sv @@ -28,21 +28,29 @@ module video_freak input [11:0] ARX, input [11:0] ARY, input [11:0] CROP_SIZE, - input [4:0] CROP_OFF, - input [1:0] SCALE + input [4:0] CROP_OFF, // -16...+15 + input [2:0] SCALE //0 - normal, 1 - V-integer, 2 - HV-Integer-, 3 - HV-Integer+, 4 - HV-Integer ); +reg mul_start; +wire mul_run; +reg [11:0] mul_arg1, mul_arg2; +wire [23:0] mul_res; +sys_umul #(12,12) mul(CLK_VIDEO,mul_start,mul_run, mul_arg1,mul_arg2,mul_res); + reg vde; reg [11:0] arxo,aryo; reg [11:0] vsize; reg [11:0] hsize; always @(posedge CLK_VIDEO) begin - reg old_de, old_vs,vcalc,ovde; + reg old_de, old_vs,ovde; reg [11:0] vtot,vcpt,vcrop,voff; reg [11:0] hcpt; reg [11:0] vadj; - reg [23:0] ARXG,ARYG,arx,ary; + reg [23:0] ARXG,ARYG; + reg [11:0] arx,ary; + reg [1:0] vcalc; if (CE_PIXEL) begin old_de <= VGA_DE_IN; @@ -51,7 +59,7 @@ always @(posedge CLK_VIDEO) begin vcpt <= 0; vtot <= vcpt; vcalc <= 1; - vcrop <= ((CROP_SIZE >= vcpt) || !CROP_SIZE) ? 12'd0 : CROP_SIZE; + vcrop <= (CROP_SIZE >= vcpt) ? 12'd0 : CROP_SIZE; end if (VGA_DE_IN) hcpt <= hcpt + 1'd1; @@ -65,17 +73,36 @@ always @(posedge CLK_VIDEO) begin arx <= ARX; ary <= ARY; - vsize <= vcrop; + vsize <= vcrop ? vcrop : vtot; + + mul_start <= 0; if(!vcrop || !ary || !arx) begin - arxo <= arx[11:0]; - aryo <= ary[11:0]; - vsize <= vtot; + arxo <= arx; + aryo <= ary; end else if (vcalc) begin - ARXG <= arx * vtot; - ARYG <= ary * vcrop; - vcalc <= 0; + if(~mul_start & ~mul_run) begin + vcalc <= vcalc + 1'd1; + case(vcalc) + 1: begin + mul_arg1 <= arx; + mul_arg2 <= vtot; + mul_start <= 1; + end + + 2: begin + ARXG <= mul_res; + mul_arg1 <= ary; + mul_arg2 <= vcrop; + mul_start <= 1; + end + + 3: begin + ARYG <= mul_res; + end + endcase + end end else if (ARXG[23] | ARYG[23]) begin arxo <= ARXG[23:12]; @@ -94,6 +121,42 @@ end assign VGA_DE = vde & VGA_DE_IN; +video_scale_int scale +( + .CLK_VIDEO(CLK_VIDEO), + .HDMI_WIDTH(HDMI_WIDTH), + .HDMI_HEIGHT(HDMI_HEIGHT), + .SCALE(SCALE), + .hsize(hsize), + .vsize(vsize), + .arx_i(arxo), + .ary_i(aryo), + .arx_o(VIDEO_ARX), + .ary_o(VIDEO_ARY) +); + +endmodule + + +module video_scale_int +( + input CLK_VIDEO, + + input [11:0] HDMI_WIDTH, + input [11:0] HDMI_HEIGHT, + + input [2:0] SCALE, + + input [11:0] hsize, + input [11:0] vsize, + + input [11:0] arx_i, + input [11:0] ary_i, + + output reg [12:0] arx_o, + output reg [12:0] ary_o +); + reg div_start; wire div_run; reg [23:0] div_num; @@ -110,16 +173,17 @@ sys_umul #(12,12) mul(CLK_VIDEO,mul_start,mul_run, mul_arg1,mul_arg2,mul_res); wire [11:0] wideres = mul_res[11:0] + hsize; always @(posedge CLK_VIDEO) begin - reg [11:0] oheight; + reg [11:0] oheight,wres; reg [12:0] arxf,aryf; reg [3:0] cnt; + reg narrow; div_start <= 0; mul_start <= 0; - if (!SCALE || !aryo || !arxo) begin - arxf <= arxo; - aryf <= aryo; + if (!SCALE || (!ary_i && arx_i)) begin + arxf <= arx_i; + aryf <= ary_i; end else if(~div_start & ~div_run & ~mul_start & ~mul_run) begin cnt <= cnt + 1'd1; @@ -133,8 +197,8 @@ always @(posedge CLK_VIDEO) begin 1: if(!div_res[11:0]) begin // screen resolution is lower than video resolution. // Integer scaling is impossible. - arxf <= arxo; - aryf <= aryo; + arxf <= arx_i; + aryf <= ary_i; cnt <= 0; end else begin @@ -145,51 +209,70 @@ always @(posedge CLK_VIDEO) begin 2: begin oheight <= mul_res[11:0]; + if(!ary_i) begin + cnt <= 8; + end + end + + 3: begin mul_arg1 <= mul_res[11:0]; - mul_arg2 <= arxo; + mul_arg2 <= arx_i; mul_start <= 1; end - 3: begin + 4: begin div_num <= mul_res; - div_den <= aryo; + div_den <= ary_i; div_start <= 1; end - 4: begin + 5: begin div_num <= div_res; div_den <= hsize; div_start <= 1; end - 5: begin + 6: begin mul_arg1 <= hsize; mul_arg2 <= div_res[11:0] ? div_res[11:0] : 12'd1; mul_start <= 1; end - 6: if(mul_res <= HDMI_WIDTH) cnt <= 8; - else begin + 7: if(mul_res <= HDMI_WIDTH) begin + cnt <= 10; + end + + 8: begin div_num <= HDMI_WIDTH; div_den <= hsize; div_start <= 1; end - 7: begin + 9: begin mul_arg1 <= hsize; mul_arg2 <= div_res[11:0] ? div_res[11:0] : 12'd1; mul_start <= 1; end - 8: begin - arxf <= {1'b1, ~SCALE[1] ? div_num[11:0] : (SCALE[0] && (wideres <= HDMI_WIDTH)) ? wideres : mul_res[11:0]}; + 10: begin + narrow <= ((div_num[11:0] - mul_res[11:0]) <= (wideres - div_num[11:0])) || (wideres > HDMI_WIDTH); + wres <= wideres; + end + + 11: begin + case(SCALE) + 2: arxf <= {1'b1, mul_res[11:0]}; + 3: arxf <= {1'b1, (wres > HDMI_WIDTH) ? mul_res[11:0] : wres}; + 4: arxf <= {1'b1, narrow ? mul_res[11:0] : wres}; + default: arxf <= {1'b1, div_num[11:0]}; + endcase aryf <= {1'b1, oheight}; end endcase end - VIDEO_ARX <= arxf; - VIDEO_ARY <= aryf; + arx_o <= arxf; + ary_o <= aryf; end endmodule diff --git a/sys/video_freezer.sv b/sys/video_freezer.sv new file mode 100644 index 0000000..24d2c65 --- /dev/null +++ b/sys/video_freezer.sv @@ -0,0 +1,143 @@ +// +// video freeze with sync +// (C) 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 +// 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 video_freezer +( + input clk, + + output sync, + input freeze, + + input hs_in, + input vs_in, + input hbl_in, + input vbl_in, + + output hs_out, + output vs_out, + output hbl_out, + output vbl_out +); + +sync_lock #(33) vs_lock +( + .clk(clk), + .sync_in(vs_in), + .sync_out(vs_out), + .de_in(vbl_in), + .de_out(vbl_out), + .freeze(freeze) +); + +wire sync_pt; +sync_lock #(21) hs_lock +( + .clk(clk), + .sync_in(hs_in), + .sync_out(hs_out), + .de_in(hbl_in), + .de_out(hbl_out), + .freeze(freeze), + .sync_pt(sync_pt) +); + +reg sync_o; +always @(posedge clk) begin + reg old_hs, old_vs; + reg vs_sync; + + old_vs <= vs_out; + + if(~old_vs & vs_out) vs_sync <= 1; + if(sync_pt & vs_sync) begin + vs_sync <= 0; + sync_o <= ~sync_o; + end +end + +assign sync = sync_o; + +endmodule + + +module sync_lock #(parameter WIDTH) +( + input clk, + + input sync_in, + input de_in, + + output sync_out, + output de_out, + + input freeze, + output sync_pt, + output valid +); + +reg [WIDTH-1:0] f_len, s_len, de_start, de_end; +reg sync_valid; + +reg old_sync; +always @(posedge clk) old_sync <= sync_in; + +always @(posedge clk) begin + reg [WIDTH-1:0] cnti; + reg f_valid; + reg old_de; + + cnti <= cnti + 1'd1; + if(~old_sync & sync_in) begin + if(sync_valid) f_len <= cnti; + f_valid <= 1; + sync_valid <= f_valid; + cnti <= 0; + end + + if(old_sync & ~sync_in & sync_valid) s_len <= cnti; + + old_de <= de_in; + if(~old_de & de_in & sync_valid) de_start <= cnti; + if(old_de & ~de_in & sync_valid) de_end <= cnti; + + if(freeze) {f_valid, sync_valid} <= 0; +end + +reg sync_o, de_o, sync_o_pre; +always @(posedge clk) begin + reg [WIDTH-1:0] cnto; + + cnto <= cnto + 1'd1; + if(old_sync & ~sync_in & sync_valid) cnto <= s_len + 2'd2; + if(cnto == f_len) cnto <= 0; + + sync_o_pre <= (cnto == (s_len>>1)); // middle in sync + if(cnto == f_len) sync_o <= 1; + if(cnto == s_len) sync_o <= 0; + if(cnto == de_start) de_o <= 1; + if(cnto == de_end) de_o <= 0; +end + +assign sync_out = freeze ? sync_o : sync_in; +assign valid = sync_valid; +assign sync_pt = sync_o_pre; +assign de_out = freeze ? de_o : de_in; + +endmodule diff --git a/sys/video_mixer.sv b/sys/video_mixer.sv index 93b106e..e53e1c0 100644 --- a/sys/video_mixer.sv +++ b/sys/video_mixer.sv @@ -10,10 +10,7 @@ `timescale 1ns / 1ps // -// LINE_LENGTH: Length of display line in pixels -// Usually it's length from HSync to HSync. -// May be less if line_start is used. -// +// LINE_LENGTH: Length of display line in pixels when HBlank = 0; // HALF_DEPTH: If =1 then color dept is 4 bits per component // // altera message_off 10720 @@ -47,6 +44,12 @@ module video_mixer input HBlank, input VBlank, + // Freeze engine + // HDMI: displays last frame + // VGA: black screen with HSync and VSync + input HDMI_FREEZE, + output freeze_sync, + // video output signals output reg [7:0] VGA_R, output reg [7:0] VGA_G, @@ -60,19 +63,43 @@ localparam DWIDTH = HALF_DEPTH ? 3 : 7; localparam DWIDTH_SD = GAMMA ? 7 : DWIDTH; localparam HALF_DEPTH_SD = GAMMA ? 0 : HALF_DEPTH; +wire frz_hs, frz_vs; +wire frz_hbl, frz_vbl; +video_freezer freezer +( + .clk(CLK_VIDEO), + .freeze(HDMI_FREEZE), + .hs_in(HSync), + .vs_in(VSync), + .hbl_in(HBlank), + .vbl_in(VBlank), + .sync(freeze_sync), + .hs_out(frz_hs), + .vs_out(frz_vs), + .hbl_out(frz_hbl), + .vbl_out(frz_vbl) +); + +reg frz; +always @(posedge CLK_VIDEO) begin + reg frz1; + + frz1 <= HDMI_FREEZE; + frz <= frz1; +end + generate if(GAMMA && HALF_DEPTH) begin - wire [7:0] R_in = {R,R}; - wire [7:0] G_in = {G,G}; - wire [7:0] B_in = {B,B}; + wire [7:0] R_in = frz ? 8'd0 : {R,R}; + wire [7:0] G_in = frz ? 8'd0 : {G,G}; + wire [7:0] B_in = frz ? 8'd0 : {B,B}; end else begin - wire [DWIDTH:0] R_in = R; - wire [DWIDTH:0] G_in = G; - wire [DWIDTH:0] B_in = B; + wire [DWIDTH:0] R_in = frz ? 1'd0 : R; + wire [DWIDTH:0] G_in = frz ? 1'd0 : G; + wire [DWIDTH:0] B_in = frz ? 1'd0 : B; end endgenerate - wire hs_g, vs_g; wire hb_g, vb_g; wire [DWIDTH_SD:0] R_gamma, G_gamma, B_gamma; @@ -90,10 +117,10 @@ generate .gamma_wr_addr(gamma_bus[17:8]), .gamma_value(gamma_bus[7:0]), - .HSync(HSync), - .VSync(VSync), - .HBlank(HBlank), - .VBlank(VBlank), + .HSync(frz_hs), + .VSync(frz_vs), + .HBlank(frz_hbl), + .VBlank(frz_vbl), .RGB_in({R_in,G_in,B_in}), .HSync_out(hs_g), @@ -105,7 +132,7 @@ generate end else begin assign gamma_bus[21] = 0; assign {R_gamma,G_gamma,B_gamma} = {R_in,G_in,B_in}; - assign {hs_g, vs_g, hb_g, vb_g} = {HSync, VSync, HBlank, VBlank}; + assign {hs_g, vs_g, hb_g, vb_g} = {frz_hs, frz_vs, frz_hbl, frz_vbl}; end endgenerate