commit 506acd3cfdd5d01a4fefd18ee2fbe1a6d5d9190d Author: Bartosz Stebel Date: Wed Feb 25 21:38:13 2015 +0100 first commit such china, very ram diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e33874e --- /dev/null +++ b/.gitignore @@ -0,0 +1,66 @@ +# Created by https://www.gitignore.io + +### XilinxISE ### +# intermediate build files +*.bgn +*.bit +*.bld +*.cmd_log +*.drc +*.ll +*.lso +*.msd +*.msk +*.ncd +*.ngc +*.ngd +*.ngr +*.pad +*.par +*.pcf +*.prj +*.ptwx +*.rbb +*.rbd +*.stx +*.syr +*.twr +*.twx +*.unroutes +*.ut +*.xpi +*.xst +*_bitgen.xwbt +*_envsettings.html +*_map.map +*_map.mrp +*_map.ngm +*_map.xrpt +*_ngdbuild.xrpt +*_pad.csv +*_pad.txt +*_par.xrpt +*_summary.html +*_summary.xml +*_usage.xml +*_xst.xrpt + +# project-wide generated files +*.gise +par_usage_statistics.html +usage_statistics_webtalk.html +webtalk.log +webtalk_pn.xml + +# generated folders +iseconfig/ +xlnx_auto_0_xdb/ +xst/ +_ngo/ +_xmsgs/ + +#coregen +ipcore_dir/* +!ipcore_dir/*.xco +!ipcore_dir/*.cgp + diff --git a/XC6SLX9.ucf b/XC6SLX9.ucf new file mode 100755 index 0000000..95b95c4 --- /dev/null +++ b/XC6SLX9.ucf @@ -0,0 +1,125 @@ +#CLOCK +#NET "clk24m" LOC = "P56"; +NET "clk50m" LOC = "P55"; + +##FLASH +#NET "cclk" LOC = "P70"; +#NET "flash_cs_n" LOC = "P38"; +#NET "flash_d0" LOC = "P64"; +#NET "flash_d1" LOC = "P65"; +#NET "flash_d2" LOC = "P62"; +#NET "flash_d3" LOC = "P61"; +##IO_A +NET "uart_rx_pin" LOC = "P123"; #A1 +NET "uart_tx_pin" LOC = "P121"; #A2 +#NET "IO_A3" LOC = "P120"; +#NET "IO_A4" LOC = "P119"; +NET "IO_A5" LOC = "P118"; +#NET "IO_A6" LOC = "P117"; +#NET "IO_A7" LOC = "P116"; +#NET "IO_A8" LOC = "P115"; +#NET "IO_A9" LOC = "P114"; +#NET "IO_A10" LOC = "P112"; +#NET "IO_A11" LOC = "P111"; +#NET "IO_A12" LOC = "P105"; +#NET "IO_A13" LOC = "P104"; +#NET "IO_A14" LOC = "P102"; +#NET "IO_A15" LOC = "P101"; +#NET "IO_A16" LOC = "P100"; +#NET "IO_A17" LOC = "P99" ; +#NET "IO_A18" LOC = "P98" ; +#NET "IO_A19" LOC = "P97" ; +#NET "IO_A20" LOC = "P95" ; +#NET "IO_A21" LOC = "P94" ; +#NET "IO_A22" LOC = "P93" ; +#NET "IO_A23" LOC = "P92" ; +#NET "IO_A24" LOC = "P88" ; +#NET "IO_A25" LOC = "P87" ; +#NET "IO_A26" LOC = "P85" ; +#NET "IO_A27" LOC = "P84" ; +#NET "IO_A28" LOC = "P83" ; +#NET "IO_A29" LOC = "P82" ; +#NET "IO_A30" LOC = "P81" ; +#NET "IO_A31" LOC = "P80" ; +#NET "IO_A32" LOC = "P79" ; +#NET "IO_A33" LOC = "P78" ; +#NET "IO_A34" LOC = "P75" ; +#NET "IO_A35" LOC = "P74" ; +#NET "IO_A36" LOC = "P67" ; +#NET "IO_A37" LOC = "P66" ; +#NET "IO_A38" LOC = "P59" ; +#NET "IO_A39" LOC = "P58" ; +#NET "IO_A40" LOC = "P57" ; +##IO_B +#NET "IO_B1" LOC = "P124";# KEY1 +NET "reset_n" LOC = "P126"; #LCD_RS, KEY0 //B2 +#NET "IO_B3" LOC = "P127";#LCD_RW, LED0 +#NET "IO_B4" LOC = "P131";#LCD_E , LED1 +#NET "IO_B5" LOC = "P132";#LCD_D0, SEG0 +#NET "IO_B6" LOC = "P133";#LCD_D1, SEG1 +#NET "IO_B7" LOC = "P134";#LCD_D2, SEG2 +#NET "IO_B8" LOC = "P137";#LCD_D3, SEG3 +#NET "IO_B9" LOC = "P138";#LCD_D4, SEG4 +#NET "IO_B10" LOC = "P139";#LCD_D5, SEG5 +#NET "IO_B11" LOC = "P140";#LCD_D6, SEG6 +#NET "IO_B12" LOC = "P141";#LCD_D7, SEG7 +#SDRAM +NET "sdram_clk" LOC = "P143"; +NET "sdram_cke" LOC = "P144"; +NET "sdram_cs_n" LOC = "P48" ; +NET "sdram_ras_n" LOC = "P50" ; +NET "sdram_cas_n" LOC = "P51" ; +NET "sdram_we_n" LOC = "P35" ; +NET "sdram_dqm[1]" LOC = "P142"; +NET "sdram_dqm[0]" LOC = "P34" ; +NET "sdram_ba[1]" LOC = "P46" ; +NET "sdram_ba[0]" LOC = "P47" ; +NET "sdram_addr[12]" LOC = "P1" ; +NET "sdram_addr[11]" LOC = "P2" ; +NET "sdram_addr[10]" LOC = "P45" ; +NET "sdram_addr[9]" LOC = "P5" ; +NET "sdram_addr[8]" LOC = "P6" ; +NET "sdram_addr[7]" LOC = "P7" ; +NET "sdram_addr[6]" LOC = "P8" ; +NET "sdram_addr[5]" LOC = "P9" ; +NET "sdram_addr[4]" LOC = "P10" ; +NET "sdram_addr[3]" LOC = "P40" ; +NET "sdram_addr[2]" LOC = "P41" ; +NET "sdram_addr[1]" LOC = "P43" ; +NET "sdram_addr[0]" LOC = "P44" ; +NET "sdram_dq[15]" LOC = "P22" ; +NET "sdram_dq[14]" LOC = "P21" ; +NET "sdram_dq[13]" LOC = "P17" ; +NET "sdram_dq[12]" LOC = "P16" ; +NET "sdram_dq[11]" LOC = "P15" ; +NET "sdram_dq[10]" LOC = "P14" ; +NET "sdram_dq[9]" LOC = "P12" ; +NET "sdram_dq[8]" LOC = "P11" ; +NET "sdram_dq[7]" LOC = "P33" ; +NET "sdram_dq[6]" LOC = "P32" ; +NET "sdram_dq[5]" LOC = "P30" ; +NET "sdram_dq[4]" LOC = "P29" ; +NET "sdram_dq[3]" LOC = "P27" ; +NET "sdram_dq[2]" LOC = "P26" ; +NET "sdram_dq[1]" LOC = "P24" ; +NET "sdram_dq[0]" LOC = "P23" ; +#Created by Constraints Editor (xc6slx9-tqg144-2) - 2015/02/24 +#NET "clk50m" TNM_NET = clk50m; +#TIMESPEC TS_clk50m = PERIOD "clk50m" 50 MHz HIGH 50%; + +NET "clk50m" TNM_NET = "TNM_CLK50M"; +TIMESPEC "TS_CLK50M" = PERIOD "TNM_CLK50M" 20 ns HIGH 50% PHASE 0; + +NET "sdram_dq[*]" TNM = SDRAM_PIN_GROUP; +NET "sdram_addr[*]" TNM = SDRAM_PIN_GROUP; +NET "sdram_ba[*]" TNM = SDRAM_PIN_GROUP; +NET "sdram_dqm[*]" TNM = SDRAM_PIN_GROUP; +NET "sdram_we_n" TNM = SDRAM_PIN_GROUP; +NET "sdram_cas_n" TNM = SDRAM_PIN_GROUP; +NET "sdram_ras_n" TNM = SDRAM_PIN_GROUP; +NET "sdram_cs_n" TNM = SDRAM_PIN_GROUP; +NET "sdram_cke" TNM = SDRAM_PIN_GROUP; +NET "sdram_clk" TNM = SDRAM_PIN_GROUP; + +NET "sdram_dq[*]" OFFSET = IN 4ns VALID 3ns BEFORE "clk50m"; +TIMEGRP SDRAM_PIN_GROUP OFFSET = OUT AFTER "clk50m" REFERENCE_PIN "sdram_clk" RISING; diff --git a/ipcore_dir/clock_pll.xco b/ipcore_dir/clock_pll.xco new file mode 100644 index 0000000..3ffabda --- /dev/null +++ b/ipcore_dir/clock_pll.xco @@ -0,0 +1,269 @@ +############################################################## +# +# Xilinx Core Generator version 14.7 +# Date: Wed Feb 25 16:27:25 2015 +# +############################################################## +# +# This file contains the customisation parameters for a +# Xilinx CORE Generator IP GUI. It is strongly recommended +# that you do not manually alter this file as it may cause +# unexpected and unsupported behavior. +# +############################################################## +# +# Generated from component: xilinx.com:ip:clk_wiz:3.6 +# +############################################################## +# +# BEGIN Project Options +SET addpads = false +SET asysymbol = true +SET busformat = BusFormatAngleBracketNotRipped +SET createndf = false +SET designentry = Verilog +SET device = xc6slx9 +SET devicefamily = spartan6 +SET flowvendor = Other +SET formalverification = false +SET foundationsym = false +SET implementationfiletype = Ngc +SET package = tqg144 +SET removerpms = false +SET simulationfiles = Behavioral +SET speedgrade = -2 +SET verilogsim = true +SET vhdlsim = false +# END Project Options +# BEGIN Select +SELECT Clocking_Wizard xilinx.com:ip:clk_wiz:3.6 +# END Select +# BEGIN Parameters +CSET calc_done=DONE +CSET clk_in_sel_port=CLK_IN_SEL +CSET clk_out1_port=clk125 +CSET clk_out1_use_fine_ps_gui=false +CSET clk_out2_port=clk125_ram +CSET clk_out2_use_fine_ps_gui=false +CSET clk_out3_port=CLK_OUT3 +CSET clk_out3_use_fine_ps_gui=false +CSET clk_out4_port=CLK_OUT4 +CSET clk_out4_use_fine_ps_gui=false +CSET clk_out5_port=CLK_OUT5 +CSET clk_out5_use_fine_ps_gui=false +CSET clk_out6_port=CLK_OUT6 +CSET clk_out6_use_fine_ps_gui=false +CSET clk_out7_port=CLK_OUT7 +CSET clk_out7_use_fine_ps_gui=false +CSET clk_valid_port=CLK_VALID +CSET clkfb_in_n_port=CLKFB_IN_N +CSET clkfb_in_p_port=CLKFB_IN_P +CSET clkfb_in_port=CLKFB_IN +CSET clkfb_in_signaling=SINGLE +CSET clkfb_out_n_port=CLKFB_OUT_N +CSET clkfb_out_p_port=CLKFB_OUT_P +CSET clkfb_out_port=CLKFB_OUT +CSET clkfb_stopped_port=CLKFB_STOPPED +CSET clkin1_jitter_ps=200.0 +CSET clkin1_ui_jitter=0.010 +CSET clkin2_jitter_ps=100.0 +CSET clkin2_ui_jitter=0.010 +CSET clkout1_drives=BUFG +CSET clkout1_requested_duty_cycle=50.000 +CSET clkout1_requested_out_freq=125.000 +CSET clkout1_requested_phase=0.000 +CSET clkout2_drives=BUFG +CSET clkout2_requested_duty_cycle=50.000 +CSET clkout2_requested_out_freq=125.000 +CSET clkout2_requested_phase=225.000 +CSET clkout2_used=true +CSET clkout3_drives=BUFG +CSET clkout3_requested_duty_cycle=50.000 +CSET clkout3_requested_out_freq=100.000 +CSET clkout3_requested_phase=0.000 +CSET clkout3_used=false +CSET clkout4_drives=BUFG +CSET clkout4_requested_duty_cycle=50.000 +CSET clkout4_requested_out_freq=100.000 +CSET clkout4_requested_phase=0.000 +CSET clkout4_used=false +CSET clkout5_drives=BUFG +CSET clkout5_requested_duty_cycle=50.000 +CSET clkout5_requested_out_freq=100.000 +CSET clkout5_requested_phase=0.000 +CSET clkout5_used=false +CSET clkout6_drives=BUFG +CSET clkout6_requested_duty_cycle=50.000 +CSET clkout6_requested_out_freq=100.000 +CSET clkout6_requested_phase=0.000 +CSET clkout6_used=false +CSET clkout7_drives=BUFG +CSET clkout7_requested_duty_cycle=50.000 +CSET clkout7_requested_out_freq=100.000 +CSET clkout7_requested_phase=0.000 +CSET clkout7_used=false +CSET clock_mgr_type=AUTO +CSET component_name=clock_pll +CSET daddr_port=DADDR +CSET dclk_port=DCLK +CSET dcm_clk_feedback=1X +CSET dcm_clk_out1_port=CLKFX +CSET dcm_clk_out2_port=CLKFX180 +CSET dcm_clk_out3_port=CLK0 +CSET dcm_clk_out4_port=CLK0 +CSET dcm_clk_out5_port=CLK0 +CSET dcm_clk_out6_port=CLK0 +CSET dcm_clkdv_divide=2.0 +CSET dcm_clkfx_divide=2 +CSET dcm_clkfx_multiply=5 +CSET dcm_clkgen_clk_out1_port=CLKFX +CSET dcm_clkgen_clk_out2_port=CLKFX +CSET dcm_clkgen_clk_out3_port=CLKFX +CSET dcm_clkgen_clkfx_divide=1 +CSET dcm_clkgen_clkfx_md_max=0.000 +CSET dcm_clkgen_clkfx_multiply=4 +CSET dcm_clkgen_clkfxdv_divide=2 +CSET dcm_clkgen_clkin_period=10.000 +CSET dcm_clkgen_notes=None +CSET dcm_clkgen_spread_spectrum=NONE +CSET dcm_clkgen_startup_wait=false +CSET dcm_clkin_divide_by_2=false +CSET dcm_clkin_period=20.000 +CSET dcm_clkout_phase_shift=NONE +CSET dcm_deskew_adjust=SYSTEM_SYNCHRONOUS +CSET dcm_notes=None +CSET dcm_phase_shift=0 +CSET dcm_pll_cascade=NONE +CSET dcm_startup_wait=false +CSET den_port=DEN +CSET din_port=DIN +CSET dout_port=DOUT +CSET drdy_port=DRDY +CSET dwe_port=DWE +CSET feedback_source=FDBK_AUTO +CSET in_freq_units=Units_MHz +CSET in_jitter_units=Units_UI +CSET input_clk_stopped_port=INPUT_CLK_STOPPED +CSET jitter_options=UI +CSET jitter_sel=No_Jitter +CSET locked_port=LOCKED +CSET mmcm_bandwidth=OPTIMIZED +CSET mmcm_clkfbout_mult_f=4.000 +CSET mmcm_clkfbout_phase=0.000 +CSET mmcm_clkfbout_use_fine_ps=false +CSET mmcm_clkin1_period=10.000 +CSET mmcm_clkin2_period=10.000 +CSET mmcm_clkout0_divide_f=4.000 +CSET mmcm_clkout0_duty_cycle=0.500 +CSET mmcm_clkout0_phase=0.000 +CSET mmcm_clkout0_use_fine_ps=false +CSET mmcm_clkout1_divide=1 +CSET mmcm_clkout1_duty_cycle=0.500 +CSET mmcm_clkout1_phase=0.000 +CSET mmcm_clkout1_use_fine_ps=false +CSET mmcm_clkout2_divide=1 +CSET mmcm_clkout2_duty_cycle=0.500 +CSET mmcm_clkout2_phase=0.000 +CSET mmcm_clkout2_use_fine_ps=false +CSET mmcm_clkout3_divide=1 +CSET mmcm_clkout3_duty_cycle=0.500 +CSET mmcm_clkout3_phase=0.000 +CSET mmcm_clkout3_use_fine_ps=false +CSET mmcm_clkout4_cascade=false +CSET mmcm_clkout4_divide=1 +CSET mmcm_clkout4_duty_cycle=0.500 +CSET mmcm_clkout4_phase=0.000 +CSET mmcm_clkout4_use_fine_ps=false +CSET mmcm_clkout5_divide=1 +CSET mmcm_clkout5_duty_cycle=0.500 +CSET mmcm_clkout5_phase=0.000 +CSET mmcm_clkout5_use_fine_ps=false +CSET mmcm_clkout6_divide=1 +CSET mmcm_clkout6_duty_cycle=0.500 +CSET mmcm_clkout6_phase=0.000 +CSET mmcm_clkout6_use_fine_ps=false +CSET mmcm_clock_hold=false +CSET mmcm_compensation=ZHOLD +CSET mmcm_divclk_divide=1 +CSET mmcm_notes=None +CSET mmcm_ref_jitter1=0.010 +CSET mmcm_ref_jitter2=0.010 +CSET mmcm_startup_wait=false +CSET num_out_clks=2 +CSET override_dcm=false +CSET override_dcm_clkgen=false +CSET override_mmcm=false +CSET override_pll=false +CSET platform=lin +CSET pll_bandwidth=OPTIMIZED +CSET pll_clk_feedback=CLKFBOUT +CSET pll_clkfbout_mult=10 +CSET pll_clkfbout_phase=0.000 +CSET pll_clkin_period=20.000 +CSET pll_clkout0_divide=4 +CSET pll_clkout0_duty_cycle=0.500 +CSET pll_clkout0_phase=0.000 +CSET pll_clkout1_divide=4 +CSET pll_clkout1_duty_cycle=0.500 +CSET pll_clkout1_phase=225.000 +CSET pll_clkout2_divide=1 +CSET pll_clkout2_duty_cycle=0.500 +CSET pll_clkout2_phase=0.000 +CSET pll_clkout3_divide=1 +CSET pll_clkout3_duty_cycle=0.500 +CSET pll_clkout3_phase=0.000 +CSET pll_clkout4_divide=1 +CSET pll_clkout4_duty_cycle=0.500 +CSET pll_clkout4_phase=0.000 +CSET pll_clkout5_divide=1 +CSET pll_clkout5_duty_cycle=0.500 +CSET pll_clkout5_phase=0.000 +CSET pll_compensation=SYSTEM_SYNCHRONOUS +CSET pll_divclk_divide=1 +CSET pll_notes=None +CSET pll_ref_jitter=0.010 +CSET power_down_port=POWER_DOWN +CSET prim_in_freq=50.000 +CSET prim_in_jitter=0.010 +CSET prim_source=Single_ended_clock_capable_pin +CSET primary_port=clkin +CSET primitive=MMCM +CSET primtype_sel=PLL_BASE +CSET psclk_port=PSCLK +CSET psdone_port=PSDONE +CSET psen_port=PSEN +CSET psincdec_port=PSINCDEC +CSET relative_inclk=REL_PRIMARY +CSET reset_port=reset +CSET secondary_in_freq=100.000 +CSET secondary_in_jitter=0.010 +CSET secondary_port=CLK_IN2 +CSET secondary_source=Single_ended_clock_capable_pin +CSET ss_mod_freq=250 +CSET ss_mode=CENTER_HIGH +CSET status_port=STATUS +CSET summary_strings=empty +CSET use_clk_valid=false +CSET use_clkfb_stopped=false +CSET use_dyn_phase_shift=false +CSET use_dyn_reconfig=false +CSET use_freeze=false +CSET use_freq_synth=true +CSET use_inclk_stopped=false +CSET use_inclk_switchover=false +CSET use_locked=false +CSET use_max_i_jitter=false +CSET use_min_o_jitter=false +CSET use_min_power=false +CSET use_phase_alignment=true +CSET use_power_down=false +CSET use_reset=true +CSET use_spread_spectrum=false +CSET use_spread_spectrum_1=false +CSET use_status=false +# END Parameters +# BEGIN Extra information +MISC pkg_timestamp=2012-05-10T12:44:55Z +# END Extra information +GENERATE +# CRC: 7ce18b82 diff --git a/ipcore_dir/coregen.cgp b/ipcore_dir/coregen.cgp new file mode 100644 index 0000000..d58f8d7 --- /dev/null +++ b/ipcore_dir/coregen.cgp @@ -0,0 +1,9 @@ +SET busformat = BusFormatAngleBracketNotRipped +SET designentry = Verilog +SET device = xc6slx9 +SET devicefamily = spartan6 +SET flowvendor = Other +SET package = tqg144 +SET speedgrade = -2 +SET verilogsim = true +SET vhdlsim = false diff --git a/ledmatrix.xise b/ledmatrix.xise new file mode 100644 index 0000000..141196c --- /dev/null +++ b/ledmatrix.xise @@ -0,0 +1,387 @@ + + + +
+ + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/sdram_ctrl.v b/sdram_ctrl.v new file mode 100644 index 0000000..00e7fae --- /dev/null +++ b/sdram_ctrl.v @@ -0,0 +1,787 @@ +module sdram_ctrl # + ( + parameter COL_WIDTH = 8 ,//2^8 = 256 addresses in each colum + parameter ROW_WIDTH = 12 ,//2^12 = 4096 addresses in each bank + parameter BANK_WIDTH = 2 ,//2^2 = 4 banks in a single chip + parameter DQ_WIDTH = 8 ,//8 bit Data Bus for one chip + parameter [12:0] SDRAM_MR = 13'h0037 //Full Page Burst,Latency=3,Burst Read and Burst Write,Standard mode + ) + ( + clk ,//The main clock of the control system + rst_n,//A low voltage may bring the control system to an oringinal state,but the data in SDRAM may be damaged + + user_command_req ,//The user want to send a read/write command,active HIGH + user_command_gnt ,//The state machine have accept the user's read/write command + user_rd0_wr1 ,//HIGH voltage means read and a low means write,synchronous to "user_command_req" + user_burst_length,//Express the read/write lenghth of each command,synchronous to "user_command_req" + user_start_addr ,//the user's read/write address,synchronous to "user_command_req" + Tx_fifo_rd_en ,//used in the user's write command,this port is synchronous to "clk" + Tx_fifo_rd_data ,//the user write data to the fifo,synchronous to "clk" + + sdram_cke , + sdram_cs_n , + sdram_ras_n , + sdram_cas_n , + sdram_we_n , + sdram_ba , + sdram_addr , + sdram_dq_out_en, + sdram_dqm , + sdram_dq_out , + sdram_dq_in , + + sdram_data_valid,//tell the user that valid read data is coming,active HIGH + sdram_rd_data //synchronous to sdram_data_valid + ); + + //1.本模块(sdram_ctrl.v)是SDRAM的核心控制逻辑,以clk作为参考时钟。另一个模块(sdram_io.v)主要是对SDRAM的IO控制接口的时序 + //做相位调整。相位的具体偏差范围跟FPGA内布线后各信号的延迟、PCB的走线情况以及SDRAM的参数有关,用户可以根据实际情况作调整。 + + //2.当user_command_req被拉高时,表示用户需要执行一个读或者写命令。user_command_req信号应该一直持续有效至 + //user_command_gnt有效。此模块会在user_command_gnt有效时采样user_rd0_wr1,user_DQM,user_burst_length, + //user_start_addr,以决定接下来产生什么样的SDRAM操作。 + + //3.当SDRAM忙于在初始化时或是执行用户的命令或是在做自刷新时,不会理睬用户发来的任何命令。只有当user_command_gnt有效 + //有效时,才表示此模块已经接受用户的读/写请求。 + + //4.如果用户发起的是读操作,则user_rd0_wr1在user_command_req有效时,是低电平。写操作反之。 + + //5.user_burst_length表示的是对SDRAM的突发读写的长度。如果是0,表示突发长度为1,如果是511,表示突发长度 + //是512,以此类推。 + + //6.SDRAM的突发读写的最大长度是2^COL_WIDTH(2的COL_WIDTH次方)。在突发读写的时候,一定要特别留意突发的地址范围不要出现越界。 + //越界是指在一次突发中,突发的起始地址和结束地址处于不同的ROW中。如果出现越界,那么实际突发地址会回滚至当前页的起始地址, + //而不是下一个页的起始地址。 + + //7.user_start_addr指的是本次操作中起始地址。 + + //8.对于写操作,用户需要先将待写入SDRAM的数据按顺序写入Tx_fifo中。Tx_fifo由外部模块提供,本模块仅仅负责从Tx_fifo中读数。 + //如果用户那边的速度做够快,也可以先发起写操作,再将待写入的数据存入fifo。因为此模块在接收到用户的命令后,至少需要等待6 + //个时钟周期才可能访问fifo中的内容。此fifo的深度默认为1个Page的数据。 + + //9.建议在每一次突发写之前,先将fifo清空,然后在将数字序列写入fifo。 + + //10.如果是读操作,用户在发送完命令后,还需检查sdram_data_valid信号。当sdram_data_valid有效时,表示从 + //SDRAM中读出的数据已经返回。如果突发长度为n,则sdram_data_valid会持续有效n个时钟周期。sdram_rd_data也会 + //随着时钟周期的推移而变化,它表示的是从SDRAM中读出的数据。第1个数据对应着突发的起始地址的数据,第n个数 + //据对应着突发的结束地址的数据。 + + //11.clk的最大时钟频率不能超过SDRAM器件本身的参考频率。如果用户考虑改变clk的频率,有一个参数需要注意, + //就是控制SDRAM每次自刷新的间隔时间。当clk的频率是100MHz时,SDRAM会在每64ms内刷新8192次。如果频率变小了, + //刷新的速率必然会变慢,如果慢到了器件所规定的最慢刷新频率,那么SDRAM内部的数据将会损坏。这时,用户可以 + //修改Refresh_Period的值以提高SDRAM的刷新速率。 + + input clk; + input rst_n; + + input user_command_req; + output user_command_gnt; + input user_rd0_wr1; + input [COL_WIDTH-1:0] user_burst_length; + input [BANK_WIDTH+ROW_WIDTH+COL_WIDTH-1 : 0] user_start_addr; + output Tx_fifo_rd_en; + input [DQ_WIDTH/8+DQ_WIDTH-1 :0 ] Tx_fifo_rd_data; + + output sdram_cke; + output sdram_cs_n; + output sdram_ras_n; + output sdram_cas_n; + output sdram_we_n; + output [BANK_WIDTH-1 : 0] sdram_ba; + output [ROW_WIDTH-1 : 0] sdram_addr; + output sdram_dq_out_en; + output [DQ_WIDTH/8-1: 0] sdram_dqm; + output [DQ_WIDTH-1 : 0] sdram_dq_out; + input [DQ_WIDTH-1 : 0] sdram_dq_in; + + output sdram_data_valid; + output [DQ_WIDTH-1 : 0] sdram_rd_data; + + parameter [9:0] + Refresh_Period = 10'd781;//when clk is 100MHz,8192 Refresh cycles happens very 64ms + + reg [9:0] Refresh_cnt; + always @ (posedge clk)//account for Refresh_INT + begin + if(!rst_n) + Refresh_cnt <= 10'd0; + else if(Refresh_cnt != Refresh_Period) + Refresh_cnt <= Refresh_cnt + 1'b1; + else + Refresh_cnt <= 10'd0; + end + + reg Refresh_INT; + wire Refresh_INT_clear; + always @ (posedge clk)//A refresh command should be excuted when Refresh_INT is High + begin + if(!rst_n) + Refresh_INT <= 1'b0; + else if(Refresh_cnt == Refresh_Period) + Refresh_INT <= 1'b1; + else if(Refresh_INT_clear) + Refresh_INT <= 1'b0; + end + + wire user_INT; + assign user_INT = user_command_req;//A read/write command should be excuted when user_INT is High + + reg user_command_gnt; + + reg user_rd0_wr1_buf; + reg [COL_WIDTH-1:0] user_burst_length_buf; + reg [BANK_WIDTH+ROW_WIDTH+COL_WIDTH-1 : 0] user_start_addr_buf; + always @ (posedge clk) + begin + if(!rst_n) + begin + user_rd0_wr1_buf <= 1'b0; + user_burst_length_buf <= 1'b0; + user_start_addr_buf <= 1'b0; + end + else if(user_command_gnt) + begin + user_rd0_wr1_buf <= user_rd0_wr1; + user_burst_length_buf <= user_burst_length; + user_start_addr_buf <= user_start_addr; + end + end + + parameter [3:0] + Initialize = 4'b0001, + Wait_Interrupt = 4'b0010, + Response_Refresh_INT = 4'b0100, + Response_user_INT = 4'b1000; + + reg [3:0] SDRAM_state; + reg Initialize_done; + reg Response_Refresh_INT_done; + reg Response_user_INT_done; + always @ (posedge clk)//SDRAM state machine + begin + if(!rst_n) + SDRAM_state <= Initialize; + else + case(SDRAM_state) + Initialize : + if(Initialize_done) + SDRAM_state <= Wait_Interrupt; + Wait_Interrupt : + if(Refresh_INT) + SDRAM_state <= Response_Refresh_INT; + else if(user_INT) + SDRAM_state <= Response_user_INT; + else + SDRAM_state <= Wait_Interrupt; + Response_Refresh_INT : + if(Response_Refresh_INT_done) + SDRAM_state <= Wait_Interrupt; + else + SDRAM_state <= Response_Refresh_INT; + Response_user_INT : + if(Response_user_INT_done) + SDRAM_state <= Wait_Interrupt; + default: + SDRAM_state <= Initialize; + endcase + end + + parameter + tRP_period = 8'd2,//3 clock period + tRC_period = 8'd11,//12 clock period + tMRD_period = 8'd1,//2 clock period + tRCD_period = 8'd2;//3 clock period + + reg [COL_WIDTH-1:0] Delay_cnt; + reg cnt_overflow; + + parameter [9:0] + Initialize_NOP_Command = 10'b00_0000_0001, + Initialize_Precharge_All_Bank = 10'b00_0000_0010, + Initialize_Precharge_tRP = 10'b00_0000_0100, + Initialize_Auto_Refresh_Command1 = 10'b00_0000_1000, + Initialize_Auto_Refresh_tRC1 = 10'b00_0001_0000, + Initialize_Auto_Refresh_Command2 = 10'b00_0010_0000, + Initialize_Auto_Refresh_tRC2 = 10'b00_0100_0000, + Load_Mode_Register_Command = 10'b00_1000_0000, + Load_Mode_Register_tMRD = 10'b01_0000_0000, + Initialize_Finish = 10'b10_0000_0000; + + reg [9:0] Initialize_state; + always @ (posedge clk)//Initialize state machine + begin + if(!rst_n) + Initialize_state <= Initialize_NOP_Command; + else if(SDRAM_state == Initialize) + case(Initialize_state) + Initialize_NOP_Command ://A NOP Command before Precharge + Initialize_state <= Initialize_Precharge_All_Bank; + Initialize_Precharge_All_Bank ://Precharge Command,all banks + Initialize_state <= Initialize_Precharge_tRP; + Initialize_Precharge_tRP ://tRP period,with NOP Command + if(cnt_overflow) + Initialize_state <= Initialize_Auto_Refresh_Command1; + Initialize_Auto_Refresh_Command1 ://The Frist Auto Refresh Command + Initialize_state <= Initialize_Auto_Refresh_tRC1; + Initialize_Auto_Refresh_tRC1 ://tRC period,with NOP Command + if(cnt_overflow) + Initialize_state <= Initialize_Auto_Refresh_Command2; + Initialize_Auto_Refresh_Command2 ://The Second Auto Refresh Command + Initialize_state <= Initialize_Auto_Refresh_tRC2; + Initialize_Auto_Refresh_tRC2 ://tRC period,with NOP Command + if(cnt_overflow) + Initialize_state <= Load_Mode_Register_Command; + Load_Mode_Register_Command ://Load Mode Register + Initialize_state <= Load_Mode_Register_tMRD; + Load_Mode_Register_tMRD ://tMRD period,with NOP Command + if(cnt_overflow) + Initialize_state <= Initialize_Finish; + Initialize_Finish : ; + default: + Initialize_state <= Initialize_NOP_Command; + endcase + else + Initialize_state <= Initialize_NOP_Command; + end + + always @ (posedge clk) + begin + if(!rst_n) + Initialize_done <= 1'b0; + else if(Initialize_state==Initialize_Finish) + Initialize_done <= 1'b1; + else + Initialize_done <= 1'b0; + end + + parameter [3:0] + Refresh_NOP_Command = 4'b0001, + Refresh_Auto_Refresh_Command = 4'b0010, + Refresh_Auto_Refresh_tRC = 4'b0100, + Refresh_Finish = 4'b1000; + + reg [3:0] Refresh_Response_state; + always @ (posedge clk)//Refresh response state machine + begin + if(!rst_n) + Refresh_Response_state <= Refresh_NOP_Command; + else if(SDRAM_state == Response_Refresh_INT) + case(Refresh_Response_state) + Refresh_NOP_Command ://Exit Power-Down state(if it's in) with NOP Command + Refresh_Response_state <= Refresh_Auto_Refresh_Command; + Refresh_Auto_Refresh_Command ://Auto Refresh Command + Refresh_Response_state <= Refresh_Auto_Refresh_tRC; + Refresh_Auto_Refresh_tRC ://tRC period,with NOP Command + if(cnt_overflow) + Refresh_Response_state <= Refresh_Finish; + Refresh_Finish : ; + default: + Refresh_Response_state <= Refresh_NOP_Command; + endcase + else + Refresh_Response_state <= Refresh_NOP_Command; + end + + always @ (posedge clk) + begin + if(!rst_n) + Response_Refresh_INT_done <= 1'b0; + else if(Refresh_Response_state==Refresh_Auto_Refresh_tRC&&cnt_overflow) + Response_Refresh_INT_done <= 1'b1; + else + Response_Refresh_INT_done <= 1'b0; + end + + assign Refresh_INT_clear = (Refresh_Response_state==Refresh_Auto_Refresh_Command); + + parameter [6:0] + user_Response_start_NOP = 7'b0000001, + user_Response_Bank_activation = 7'b0000010, + user_Response_tRCD = 7'b0000100, + user_Response_Column_Selection = 7'b0001000, + user_Response_wait_Precharge1 = 7'b0010000, + user_Response_wait_Precharge2 = 7'b0100000, + user_Response_end_NOP = 7'b1000000; + + reg [6:0] user_Response_state; + always @ (posedge clk)//user response state machine + begin + if(!rst_n) + user_Response_state <= user_Response_start_NOP; + else if(SDRAM_state == Response_user_INT) + case(user_Response_state) + user_Response_start_NOP ://Exit Power-Down state with NOP Command + user_Response_state <= user_Response_Bank_activation; + user_Response_Bank_activation ://Bank/Row activation + user_Response_state <= user_Response_tRCD; + user_Response_tRCD ://tRCD period,with NOP Command + if(cnt_overflow) + user_Response_state <= user_Response_Column_Selection; + user_Response_Column_Selection ://Column Selection + user_Response_state <= user_Response_wait_Precharge1; + user_Response_wait_Precharge1://Wait to Precharge, this state only generate precharge for burst read + if(cnt_overflow) + begin + if(!user_rd0_wr1_buf)//if is read busrt + user_Response_state <= user_Response_end_NOP; + else//write busrt + user_Response_state <= user_Response_wait_Precharge2; + end + user_Response_wait_Precharge2://This state is special for the precharge of busrt write + user_Response_state <= user_Response_end_NOP; + user_Response_end_NOP : ; + default : + user_Response_state <= user_Response_start_NOP; + endcase + else + user_Response_state <= user_Response_start_NOP; + end + + always @ (posedge clk) + begin + if(!rst_n) + Response_user_INT_done <= 1'b0; + else if(user_Response_state==user_Response_end_NOP&&SDRAM_state == Response_user_INT) + Response_user_INT_done <= 1'b1; + else + Response_user_INT_done <= 1'b0; + end + + always @ (posedge clk) + begin + if(!rst_n) + user_command_gnt <= 1'b0; + else + case(SDRAM_state) + Wait_Interrupt: + if(!Refresh_INT&&user_INT) + user_command_gnt <= 1'b1; + else + user_command_gnt <= 1'b0; + default: + user_command_gnt <= 1'b0; + endcase + end + + reg [COL_WIDTH-1:0] Delay_set; + always @ (posedge clk) + begin + if(!rst_n) + Delay_set <= 1'b0; + else + case(SDRAM_state) + Initialize: + case(Initialize_state) + Initialize_NOP_Command ://load tRP period + Delay_set <= tRP_period; + Initialize_Precharge_tRP://load tRC period + if(cnt_overflow) + Delay_set <= tRC_period; + Initialize_Auto_Refresh_tRC1 ://load tRC period + if(cnt_overflow) + Delay_set <= tRC_period; + Initialize_Auto_Refresh_tRC2 ://load tMRD period + if(cnt_overflow) + Delay_set <= tMRD_period; + endcase + Response_Refresh_INT: + case(Refresh_Response_state) + Refresh_NOP_Command ://load tRC period + Delay_set <= tRC_period; + endcase + Response_user_INT: + case(user_Response_state) + user_Response_start_NOP://load tRCD period + Delay_set <= tRCD_period; + user_Response_tRCD ://load user burst length period + if(cnt_overflow) + Delay_set <= user_burst_length_buf; + endcase + endcase + end + + always @ (posedge clk)//Delay_cnt + begin + if(!rst_n) + Delay_cnt <= 1'b0; + else + case(SDRAM_state) + Initialize: + case(Initialize_state) + Initialize_Precharge_All_Bank ,//cnt for tRP period + Initialize_Auto_Refresh_Command1 ,//cnt for tRC period + Initialize_Auto_Refresh_Command2 ,//cnt for tRC period + Load_Mode_Register_Command ://cnt for tMRD period + Delay_cnt <= Delay_cnt + 1'b1; + Initialize_Precharge_tRP ,//cnt for tRP period + Initialize_Auto_Refresh_tRC1 ,//cnt for tRC period + Initialize_Auto_Refresh_tRC2 ,//cnt for tRC period + Load_Mode_Register_tMRD ://cnt for tMRD period + if(cnt_overflow) + Delay_cnt <= 1'b0; + else + Delay_cnt <= Delay_cnt + 1'b1; + endcase + Response_Refresh_INT: + case(Refresh_Response_state) + Refresh_Auto_Refresh_Command ://cnt for tRC period + Delay_cnt <= Delay_cnt + 1'b1; + Refresh_Auto_Refresh_tRC ://cnt for tRC period + if(cnt_overflow) + Delay_cnt <= 1'b0; + else + Delay_cnt <= Delay_cnt + 1'b1; + endcase + Response_user_INT: + case(user_Response_state) + user_Response_Bank_activation ,//cnt for tRCD period + user_Response_Column_Selection ://cnt for user burst length + Delay_cnt <= Delay_cnt + 1'b1; + user_Response_tRCD ,//cnt for tRCD period + user_Response_wait_Precharge1 ://cnt for user burst length + if(cnt_overflow) + Delay_cnt <= 1'b0; + else + Delay_cnt <= Delay_cnt + 1'b1; + endcase + endcase + end + + always @ (posedge clk) + begin + if(!rst_n) + cnt_overflow <= 1'b0; + else if(Delay_cnt==Delay_set) + cnt_overflow <= 1'b1; + else + cnt_overflow <= 1'b0; + end + + reg [3:0] sdram_data_valid_buff; + always @ (posedge clk)//sdram_data_valid_buff + begin + if(!rst_n) + sdram_data_valid_buff <= 4'b0; + else if(user_Response_state==user_Response_wait_Precharge1 && user_rd0_wr1_buf==1'b0) + sdram_data_valid_buff <= {sdram_data_valid_buff[2:0],1'b1}; + else + sdram_data_valid_buff <= {sdram_data_valid_buff[2:0],1'b0}; + end + + reg sdram_data_valid; + always @ (posedge clk) + begin + if(SDRAM_MR[5:4]==2'b11)//CAS Latency = 3 + sdram_data_valid <= sdram_data_valid_buff[3]; + else//other CAS Latency, treated it as 2 + sdram_data_valid <= sdram_data_valid_buff[2]; + end + + reg [DQ_WIDTH-1:0] sdram_rd_data; + always @ (posedge clk) + begin + sdram_rd_data <= sdram_dq_in; + end + + reg Tx_fifo_rd_en; + always @ (posedge clk) + begin + if(!rst_n) + Tx_fifo_rd_en <= 1'b0; + else if(user_rd0_wr1_buf) + case(user_Response_state) + user_Response_tRCD: + if(cnt_overflow) + Tx_fifo_rd_en <= 1'b1; + user_Response_Column_Selection, + user_Response_wait_Precharge1: + if(Delay_cnt==Delay_set) + Tx_fifo_rd_en <= 1'b0; + endcase + else + Tx_fifo_rd_en <= 1'b0; + end + + reg sdram_dq_out_en; + always @ (posedge clk) + begin + if(!rst_n) + sdram_dq_out_en <= 1'b0; + else + sdram_dq_out_en <= Tx_fifo_rd_en; + end + + assign sdram_dq_out = Tx_fifo_rd_data[DQ_WIDTH-1 : 0]; + + reg dqm_for_read_mask; + always @ (posedge clk) + begin + if(!rst_n) + dqm_for_read_mask <= 1'b0; + else + case(user_Response_state) + user_Response_Column_Selection: + if(!user_rd0_wr1_buf) + dqm_for_read_mask <= 1'b1; + user_Response_end_NOP: + dqm_for_read_mask <= 1'b0; + endcase + end + + reg dqm_for_write_mask; + always @ (posedge clk) + begin + if(!rst_n) + dqm_for_write_mask <= 1'b0; + else + dqm_for_write_mask <= Tx_fifo_rd_en; + end + + reg [DQ_WIDTH/8-1: 0] sdram_dqm; + always @ ( * ) + begin + if(dqm_for_read_mask) + sdram_dqm <= {(DQ_WIDTH/8){1'b0}}; + else if(dqm_for_write_mask) + sdram_dqm <= Tx_fifo_rd_data[DQ_WIDTH/8+DQ_WIDTH-1 :DQ_WIDTH]; + else + sdram_dqm <= {(DQ_WIDTH/8){1'b1}}; + end + + reg sdram_cke; + reg sdram_cs_n; + reg sdram_ras_n; + reg sdram_cas_n; + reg sdram_we_n; + reg [BANK_WIDTH-1 : 0] sdram_ba; + reg [ROW_WIDTH-1 : 0] sdram_addr; + + always @ (posedge clk)//call the tasks + begin + if(!rst_n) + begin + sdram_ba <= 1'b0; + sdram_addr <= 1'b0; + Device_Deselect(1'b0); + end + else + case(SDRAM_state) + Initialize: + case(Initialize_state) + Initialize_NOP_Command : + No_Operation(1'b1);//this task can be replaced by Precharge_Power_Down_Exit + Initialize_Precharge_All_Bank : + Precharge_All_Banks(1'b1); + Initialize_Precharge_tRP : + No_Operation(1'b1); + Initialize_Auto_Refresh_Command1 : + Auto_Refresh; + Initialize_Auto_Refresh_tRC1 : + No_Operation(1'b1); + Initialize_Auto_Refresh_Command2 : + Auto_Refresh; + Initialize_Auto_Refresh_tRC2 : + No_Operation(1'b1); + Load_Mode_Register_Command : + begin + sdram_ba <= 2'b0; + sdram_addr <= SDRAM_MR; + Mode_Register_Set(1'b1); + end + Load_Mode_Register_tMRD : + No_Operation(1'b1); + default : ; + endcase + Wait_Interrupt: + No_Operation(1'b0);//this task can be replaced by Precharge_Power_Down_Entry + Response_Refresh_INT: + case(Refresh_Response_state) + Refresh_NOP_Command : + No_Operation(1'b1);//this task can be replaced by Precharge_Power_Down_Exit + Refresh_Auto_Refresh_Command : + Auto_Refresh; + Refresh_Auto_Refresh_tRC : + No_Operation(1'b1); + default : ; + endcase + Response_user_INT: + case(user_Response_state) + user_Response_start_NOP : + No_Operation(1'b1);//this task can be replaced by Precharge_Power_Down_Exit + user_Response_Bank_activation : + begin + sdram_ba <= user_start_addr_buf[BANK_WIDTH+ROW_WIDTH+COL_WIDTH-1 : ROW_WIDTH+COL_WIDTH]; + sdram_addr <= user_start_addr_buf[ROW_WIDTH+COL_WIDTH-1 : COL_WIDTH]; + Bank_Active(1'b1); + end + user_Response_tRCD : + No_Operation(1'b1); + user_Response_Column_Selection : + begin + sdram_addr[COL_WIDTH-1 : 0] <= user_start_addr_buf[COL_WIDTH-1 : 0]; + if(user_rd0_wr1_buf) + Write(1'b1); + else + Read(1'b1); + end + user_Response_wait_Precharge1 : + if(cnt_overflow&&!user_rd0_wr1_buf)//only generate precharge cmd when busrt read + Precharge_All_Banks(1'b1);//this task can be replaced by Precharge_selected_Bank(1'b1) + else + No_Operation(1'b1); + user_Response_wait_Precharge2 : + Precharge_All_Banks(1'b1);//this task can be replaced by Precharge_selected_Bank(1'b1) + user_Response_end_NOP : + No_Operation(1'b1); + endcase + default: + No_Operation(1'b1); + endcase + end + + //the following tasks descript the TRUTH TABLE of SDRAM command// + task Device_Deselect;//CKE should be HIGH at the last clock period + input CKE; + begin + sdram_cke <= CKE; + {sdram_cs_n,sdram_ras_n,sdram_cas_n,sdram_we_n} <= {4'b1111}; + end + endtask + + task No_Operation;//CKE should be HIGH at the last clock period + input CKE; + begin + sdram_cke <= CKE; + {sdram_cs_n,sdram_ras_n,sdram_cas_n,sdram_we_n} <= {4'b0111}; + end + endtask + + task Mode_Register_Set;//CKE should be HIGH at the last clock period + input CKE; + begin + sdram_cke <= CKE; + {sdram_cs_n,sdram_ras_n,sdram_cas_n,sdram_we_n} <= {4'b0000}; + end + endtask + + task Bank_Active;//CKE should be HIGH at the last clock period + input CKE; + begin + sdram_cke <= CKE; + {sdram_cs_n,sdram_ras_n,sdram_cas_n,sdram_we_n} <= {4'b0011}; + end + endtask + + task Precharge_selected_Bank;//CKE should be HIGH at the last clock period + input CKE; + begin + sdram_cke <= CKE; + {sdram_cs_n,sdram_ras_n,sdram_cas_n,sdram_we_n} <= {4'b0010}; + sdram_addr[10] <= 1'b0; + end + endtask + + task Precharge_All_Banks;//CKE should be HIGH at the last clock period + input CKE; + begin + sdram_cke <= CKE; + {sdram_cs_n,sdram_ras_n,sdram_cas_n,sdram_we_n} <= {4'b0010}; + sdram_addr[10] <= 1'b1; + end + endtask + + task Read;//CKE should be HIGH at the last clock period + input CKE; + begin + sdram_cke <= CKE; + {sdram_cs_n,sdram_ras_n,sdram_cas_n,sdram_we_n} <= {4'b0101}; + sdram_addr[10] <= 1'b0; + end + endtask + + task Read_with_Autoprecharge;//CKE should be HIGH at the last clock period + input CKE; + begin + sdram_cke <= CKE; + {sdram_cs_n,sdram_ras_n,sdram_cas_n,sdram_we_n} <= {4'b0101}; + sdram_addr[10] <= 1'b1; + end + endtask + + task Write;//CKE should be HIGH at the last clock period + input CKE; + begin + sdram_cke <= CKE; + {sdram_cs_n,sdram_ras_n,sdram_cas_n,sdram_we_n} <= {4'b0100}; + sdram_addr[10] <= 1'b0; + end + endtask + + task Write_with_Autoprecharge;//CKE should be HIGH at the last clock period + input CKE; + begin + sdram_cke <= CKE; + {sdram_cs_n,sdram_ras_n,sdram_cas_n,sdram_we_n} <= {4'b0100}; + sdram_addr[10] <= 1'b1; + end + endtask + + task Burst_stop;//CKE should be HIGH at the last clock period + input CKE; + begin + sdram_cke <= CKE; + {sdram_cs_n,sdram_ras_n,sdram_cas_n,sdram_we_n} <= {4'b0110}; + end + endtask + + task Auto_Refresh;//CKE should be HIGH at the last clock period + begin + sdram_cke <= 1'b1; + {sdram_cs_n,sdram_ras_n,sdram_cas_n,sdram_we_n} <= {4'b0001}; + end + endtask + + task Self_Refresh_Entry;//CKE should be HIGH at the last clock period + begin + sdram_cke <= 1'b0; + {sdram_cs_n,sdram_ras_n,sdram_cas_n,sdram_we_n} <= {4'b0001}; + end + endtask + + task Self_Refresh_Exit;//CKE should be LOW at the last clock period + begin + sdram_cke <= 1'b1; + {sdram_cs_n,sdram_ras_n,sdram_cas_n,sdram_we_n} <= {4'b0111}; + end + endtask + + task Precharge_Power_Down_Entry;//CKE should be HIGH at the last clock period + begin + sdram_cke <= 1'b0; + {sdram_cs_n,sdram_ras_n,sdram_cas_n,sdram_we_n} <= {4'b0111}; + end + endtask + + task Precharge_Power_Down_Exit;//CKE should be LOW at the last clock period + begin + sdram_cke <= 1'b1; + {sdram_cs_n,sdram_ras_n,sdram_cas_n,sdram_we_n} <= {4'b0111}; + end + endtask//same with Self_Refresh_Exit + + task Clock_Suspend_Entry;//CKE should be HIGH at the last clock period + begin + sdram_cke <= 1'b0; + {sdram_cs_n,sdram_ras_n,sdram_cas_n,sdram_we_n} <= {4'b1111}; + end + endtask + + task Clock_Suspend_Exit;//CKE should be LOW at the last clock period + begin + sdram_cke <= 1'b1; + //{sdram_cs_n,sdram_ras_n,sdram_cas_n,sdram_we_n} <= {4'b1111}; + end + endtask + //all tasks end here// + +endmodule \ No newline at end of file diff --git a/sdram_driver_v2.v b/sdram_driver_v2.v new file mode 100644 index 0000000..cbeb1c5 --- /dev/null +++ b/sdram_driver_v2.v @@ -0,0 +1,149 @@ +module sdram_driver_v2 # + ( + parameter COL_WIDTH = 8 ,//2^8 = 256 addresses in each colum + parameter ROW_WIDTH = 12 ,//2^12 = 4096 addresses in each bank + parameter BANK_WIDTH = 2 ,//2^2 = 4 banks in a single chip + parameter DQ_WIDTH = 8 ,//8 bit Data Bus for one chip + parameter [12:0] SDRAM_MR = 13'h0037 ,//Full Page Burst,Latency=3,Burst Read and Burst Write,Standard mode + parameter DDR_PRIMITIVE_TYPE = "VIRTEX5" //FPGA is Virtex-5 serirals + ) + ( + clk0 ,//The main clock of the control system + clk1 ,//have the same period of clk0, but the phase is shifted + rst_n ,//A low voltage may bring the control system to an oringinal state,and the data in SDRAM may be damaged + + user_command_req ,//The user want to send a read/write command,active HIGH + user_command_gnt ,//The state machine have accept the user's read/write command + user_rd0_wr1 ,//HIGH voltage means read and a low means write,synchronous to "user_command_req" + user_burst_length,//Express the read/write lenghth of each command,synchronous to "user_command_req" + user_start_addr ,//the user's read/write address,synchronous to "user_command_req" + Tx_fifo_rd_en ,//used in the user's write command,this port is synchronous to "clk0" + Tx_fifo_rd_data ,//the user write data to the fifo,synchronous to "clk0" + + sdram_data_valid,//tell the user that valid read data is coming,active HIGH + sdram_rd_data ,//synchronous to sdram_data_valid + + sdram_clk ,//connected to the CLK port of SDRAM + sdram_cke ,//connected to the CKE port of SDRAM + sdram_cs_n ,//connected to the CS_n port of SDRAM + sdram_ras_n ,//connected to the RAS_n port of SDRAM + sdram_cas_n ,//connected to the CAS_n port of SDRAM + sdram_we_n ,//connected to the WE_n port of SDRAM + sdram_ba ,//connected to the BA port of SDRAM + sdram_addr ,//connected to the ADDR port of SDRAM + sdram_dqm ,//connected to the DQM port of SDRAM + sdram_dq //connected to the DQ port of SDRAM + ); + + input clk0; + input clk1; + input rst_n; + + input user_command_req; + output user_command_gnt; + input user_rd0_wr1; + input [COL_WIDTH-1:0] user_burst_length; + input [BANK_WIDTH+ROW_WIDTH+COL_WIDTH-1 : 0] user_start_addr; + output Tx_fifo_rd_en; + input [DQ_WIDTH/8+DQ_WIDTH-1 :0 ] Tx_fifo_rd_data; + + output sdram_data_valid; + output [DQ_WIDTH-1 : 0] sdram_rd_data; + + + output sdram_clk ; + output sdram_cke ; + output sdram_cs_n ; + output sdram_ras_n; + output sdram_cas_n; + output sdram_we_n ; + output [BANK_WIDTH-1 : 0] sdram_ba ; + output [ROW_WIDTH-1 : 0] sdram_addr ; + output [DQ_WIDTH/8-1: 0] sdram_dqm ; + inout [DQ_WIDTH-1 : 0] sdram_dq ; + + wire c0_sdram_cke; + wire c0_sdram_cs_n; + wire c0_sdram_ras_n; + wire c0_sdram_cas_n; + wire c0_sdram_we_n; + wire [BANK_WIDTH-1 : 0] c0_sdram_ba; + wire [ROW_WIDTH-1 : 0] c0_sdram_addr; + wire c0_sdram_dq_out_en; + wire [DQ_WIDTH/8-1: 0] c0_sdram_dqm; + wire [DQ_WIDTH-1 : 0] c0_sdram_dq_out; + wire [DQ_WIDTH-1 : 0] c0_sdram_dq_in; + + sdram_ctrl # + ( + .COL_WIDTH (COL_WIDTH ), + .ROW_WIDTH (ROW_WIDTH ), + .BANK_WIDTH (BANK_WIDTH ), + .DQ_WIDTH (DQ_WIDTH ), + .SDRAM_MR (SDRAM_MR ) + ) + u_sdram_ctrl( + .clk (clk0 ),//The main clock of the control system + .rst_n(rst_n),//A low voltage may bring the control system to an oringinal state,but the data in SDRAM may be damaged + + .user_command_req (user_command_req ),//The user want to send a read/write command,active HIGH + .user_command_gnt (user_command_gnt ),//The state machine have accept the user's read/write command + .user_rd0_wr1 (user_rd0_wr1 ),//HIGH voltage means read and a low means write,synchronous to "user_command_req" + .user_burst_length(user_burst_length),//Express the read/write lenghth of each command,synchronous to "user_command_req" + .user_start_addr (user_start_addr ),//the user's read/write address,synchronous to "user_command_req" + .Tx_fifo_rd_en (Tx_fifo_rd_en ),//used in the user's write command,this port is synchronous to "clk0" + .Tx_fifo_rd_data (Tx_fifo_rd_data ),//the user write data to the fifo,synchronous to "clk0" + + .sdram_cke (c0_sdram_cke ), + .sdram_cs_n (c0_sdram_cs_n ), + .sdram_ras_n (c0_sdram_ras_n ), + .sdram_cas_n (c0_sdram_cas_n ), + .sdram_we_n (c0_sdram_we_n ), + .sdram_ba (c0_sdram_ba ), + .sdram_addr (c0_sdram_addr ), + .sdram_dq_out_en(c0_sdram_dq_out_en), + .sdram_dqm (c0_sdram_dqm ), + .sdram_dq_out (c0_sdram_dq_out ), + .sdram_dq_in (c0_sdram_dq_in ), + + .sdram_data_valid(sdram_data_valid),//tell the user that valid read data is coming,active HIGH + .sdram_rd_data (sdram_rd_data ) //synchronous to sdram_data_valid + ); + + sdram_io # + ( + .ROW_WIDTH (ROW_WIDTH ), + .BANK_WIDTH (BANK_WIDTH ), + .DQ_WIDTH (DQ_WIDTH ), + .DDR_PRIMITIVE_TYPE(DDR_PRIMITIVE_TYPE) + ) + u_sdram_io + ( + .clk0(clk0), + .clk1(clk1), + + .c0_sdram_cke (c0_sdram_cke ), + .c0_sdram_cs_n (c0_sdram_cs_n ), + .c0_sdram_ras_n (c0_sdram_ras_n ), + .c0_sdram_cas_n (c0_sdram_cas_n ), + .c0_sdram_we_n (c0_sdram_we_n ), + .c0_sdram_ba (c0_sdram_ba ), + .c0_sdram_addr (c0_sdram_addr ), + .c0_sdram_dq_out_en(c0_sdram_dq_out_en), + .c0_sdram_dqm (c0_sdram_dqm ), + .c0_sdram_dq_out (c0_sdram_dq_out ), + .c0_sdram_dq_in (c0_sdram_dq_in ), + + .c1_sdram_clk (sdram_clk ), + .c1_sdram_cke (sdram_cke ), + .c1_sdram_cs_n (sdram_cs_n ), + .c1_sdram_ras_n (sdram_ras_n), + .c1_sdram_cas_n (sdram_cas_n), + .c1_sdram_we_n (sdram_we_n ), + .c1_sdram_ba (sdram_ba ), + .c1_sdram_addr (sdram_addr ), + .c1_sdram_dqm (sdram_dqm ), + .c1_sdram_dq (sdram_dq ) + ); + +endmodule \ No newline at end of file diff --git a/sdram_io.v b/sdram_io.v new file mode 100644 index 0000000..0b5d9fe --- /dev/null +++ b/sdram_io.v @@ -0,0 +1,100 @@ +module sdram_io # + ( + parameter ROW_WIDTH = 12 ,//2^12 = 4096 addresses in each bank + parameter BANK_WIDTH = 2 ,//2^2 = 4 banks in a single chip + parameter DQ_WIDTH = 8 ,//8 bit Data Bus for one chip + parameter DDR_PRIMITIVE_TYPE = "VIRTEX5" //FPGA is Virtex-5 serirals + ) + ( + clk0, + clk1, + + c0_sdram_cke , + c0_sdram_cs_n , + c0_sdram_ras_n , + c0_sdram_cas_n , + c0_sdram_we_n , + c0_sdram_ba , + c0_sdram_addr , + c0_sdram_dq_out_en, + c0_sdram_dqm , + c0_sdram_dq_out , + c0_sdram_dq_in , + + c1_sdram_clk , + c1_sdram_cke , + c1_sdram_cs_n , + c1_sdram_ras_n , + c1_sdram_cas_n , + c1_sdram_we_n , + c1_sdram_ba , + c1_sdram_addr , + c1_sdram_dqm , + c1_sdram_dq + ); + + input clk0; + input clk1; + + input c0_sdram_cke; + input c0_sdram_cs_n; + input c0_sdram_ras_n; + input c0_sdram_cas_n; + input c0_sdram_we_n; + input [BANK_WIDTH-1 : 0] c0_sdram_ba; + input [ROW_WIDTH-1 : 0] c0_sdram_addr; + input c0_sdram_dq_out_en; + input [DQ_WIDTH/8-1: 0] c0_sdram_dqm; + input [DQ_WIDTH-1 : 0] c0_sdram_dq_out; + output [DQ_WIDTH-1 : 0] c0_sdram_dq_in; + + output c1_sdram_clk; + output c1_sdram_cke; + output c1_sdram_cs_n; + output c1_sdram_ras_n; + output c1_sdram_cas_n; + output c1_sdram_we_n; + output [BANK_WIDTH-1 : 0] c1_sdram_ba; + output [ROW_WIDTH-1 : 0] c1_sdram_addr; + output [DQ_WIDTH/8-1: 0] c1_sdram_dqm; + inout [DQ_WIDTH-1 : 0] c1_sdram_dq; + + //SDRAM control signals + reg c1_sdram_cke; + reg c1_sdram_cs_n; + reg c1_sdram_ras_n; + reg c1_sdram_cas_n; + reg c1_sdram_we_n; + reg [BANK_WIDTH-1 : 0] c1_sdram_ba; + reg [ROW_WIDTH-1 : 0] c1_sdram_addr; + reg [DQ_WIDTH/8-1: 0] c1_sdram_dqm; + reg [DQ_WIDTH-1:0] c1_sdram_dq_out; + reg [DQ_WIDTH-1:0] c1_sdram_dq_out_en; + always @ (posedge clk0) + begin + c1_sdram_cke <= c0_sdram_cke ; + c1_sdram_cs_n <= c0_sdram_cs_n ; + c1_sdram_ras_n <= c0_sdram_ras_n; + c1_sdram_cas_n <= c0_sdram_cas_n; + c1_sdram_we_n <= c0_sdram_we_n ; + c1_sdram_ba <= c0_sdram_ba; + c1_sdram_addr <= c0_sdram_addr; + c1_sdram_dqm <= c0_sdram_dqm; + c1_sdram_dq_out <= c0_sdram_dq_out; + c1_sdram_dq_out_en <= c0_sdram_dq_out_en; + end + + assign c1_sdram_dq = c1_sdram_dq_out_en ? c1_sdram_dq_out : {DQ_WIDTH{1'bz}}; + assign c0_sdram_dq_in = c1_sdram_dq; + + //SDRAM clk + generate + begin : gen_clk + if(DDR_PRIMITIVE_TYPE=="SPARTEN6") + ODDR2 ODDR2_clk (.S(1'b0),.R(1'b0),.D0(1'b1),.D1(1'b0),.CE(1'b1),.C0(clk1),.C1(~clk1),.Q(c1_sdram_clk)); + else if(DDR_PRIMITIVE_TYPE=="VIRTEX5") + ODDR ODDR_clk (.S(1'b0),.R(1'b0),.D1(1'b1),.D2(1'b0),.CE(1'b1),.C(clk1),.Q(c1_sdram_clk)); + end + endgenerate + +endmodule \ No newline at end of file diff --git a/top.v b/top.v new file mode 100644 index 0000000..2565edf --- /dev/null +++ b/top.v @@ -0,0 +1,162 @@ +`timescale 1ns / 1ps +module top( + input clk50m, + input uart_rx_pin, + output uart_tx_pin, + input reset_n, + output IO_A5, + + output sdram_clk ,//connected to the CLK port of SDRAM + output sdram_cke ,//connected to the CKE port of SDRAM + output sdram_cs_n ,//connected to the CS_n port of SDRAM + output sdram_ras_n ,//connected to the RAS_n port of SDRAM + output sdram_cas_n ,//connected to the CAS_n port of SDRAM + output sdram_we_n ,//connected to the WE_n port of SDRAM + /*output sdram_ba ,//connected to the BA port of SDRAM + output sdram_addr ,//connected to the ADDR port of SDRAM + output sdram_dqm ,//connected to the DQM port of SDRAM + inout sdram_dq //connected to the DQ port of SDRAM*/ + /// + output [BANK_WIDTH-1 : 0] sdram_ba, + output [ROW_WIDTH-1 : 0] sdram_addr, + output [DQ_WIDTH/8-1: 0] sdram_dqm, + inout [DQ_WIDTH-1 : 0] sdram_dq + + ); + + parameter COL_WIDTH = 9;//2^9 = 512 addresses in each colum + parameter ROW_WIDTH = 13;//2^13 = 8192 addresses in each bank + parameter BANK_WIDTH = 2;//2^2 = 4 banks in a single chip + parameter DQ_WIDTH = 16;//16 bit Data Bus for one chip + parameter [12:0] SDRAM_MR = 13'h0037;//Full Page Burst,Latency=3,Burst Read and Burst Write,Standard mode + //parameter DDR_PRIMITIVE_TYPE = "VIRTEX5" ;//FPGA is Virtex-5 serirals + parameter DDR_PRIMITIVE_TYPE = "SPARTEN6";//FPGA is Sparten-6 serirals + + wire reset = ~reset_n; + + wire clk125, clk125_ram; + clock_pll pll(.clkin(clk50m), + .clk125(clk125), + .clk125_ram(clk125_ram), + .reset(reset) + ); + wire clk = clk125; + + parameter ClkFrequency = 50000000; + parameter Baud = 115200; + parameter BaudGeneratorAccWidth = 17; + parameter BaudGeneratorInc = ((Baud<<(BaudGeneratorAccWidth-4))+(ClkFrequency>>5))/(ClkFrequency>>4); + + reg [BaudGeneratorAccWidth:0] BaudGeneratorAcc; + always @(posedge clk) + BaudGeneratorAcc <= BaudGeneratorAcc[BaudGeneratorAccWidth-1:0] + BaudGeneratorInc; + + wire BaudTick = BaudGeneratorAcc[BaudGeneratorAccWidth]; + + wire transmit_avail; + wire receive_avail; + reg rx_present_clear; + wire [7:0] rec_byte; + reg [7:0] tx_byte; + reg tx_latch; + + uart_controller uart( + .tx_data_in(tx_byte), + .tx_data_latch(tx_latch), + .clock(BaudTick), + .reset(reset), + .tx_transmitted(transmit_avail), + .tx_signal(uart_tx_pin), + .rx_present(receive_avail), + .rx_present_clear(rx_present_clear), + .rx_data(rec_byte), + .rx_signal(uart_rx_pin) + ); + + reg [3:0] state; + `define IDLE 0 + `define SENDING 1 + `define TX_WAIT 2 + + assign IO_A5 = BaudTick; + + reg has_byte; + + always @(posedge clk) begin + if (reset) begin + tx_byte <= "A"; + tx_latch <= 0; + rx_present_clear <= 0; + state <= `IDLE; + has_byte <= 0; + end + if (!tx_latch && receive_avail) begin + tx_byte <= rec_byte; + has_byte <= 1; + rx_present_clear <= 1; + end + if (rx_present_clear && !receive_avail) + rx_present_clear <= 0; + case (state) + `IDLE: begin + if (has_byte && BaudTick) begin + tx_latch <= 1; + state <= `TX_WAIT; + end + end + `TX_WAIT: begin + if(!transmit_avail) begin + tx_latch <= 0; + has_byte <= 0; + state <= `SENDING; + end + end + `SENDING: begin + if(transmit_avail) begin + state <= `IDLE; + end + //state = `TX_WAIT; + end + endcase + + end + +sdram_driver_v2 # + ( + .COL_WIDTH (COL_WIDTH ), + .ROW_WIDTH (ROW_WIDTH ), + .BANK_WIDTH (BANK_WIDTH ), + .DQ_WIDTH (DQ_WIDTH ), + .SDRAM_MR (SDRAM_MR ), + .DDR_PRIMITIVE_TYPE(DDR_PRIMITIVE_TYPE) + ) + u_sdram_driver_v2( + .clk0(clk125),//The main clock of the control system + .clk1(clk125_ram),//have the same period of clk, but the phase is shifted + .rst_n(reset_n), + + .user_command_req (user_command_req ),//The user want to send a read/write command,active HIGH + .user_command_gnt (user_command_gnt ),//The state machine have accept the user's read/write command + .user_rd0_wr1 (user_rd0_wr1 ),//HIGH voltage means read and a low means write,synchronous to "user_command_req" + .user_burst_length(user_burst_length),//Express the read/write lenghth of each command,synchronous to "user_command_req" + .user_start_addr (user_start_addr ),//the user's read/write address,synchronous to "user_command_req" + .Tx_fifo_rd_en (Tx_fifo_rd_en ),//used in the user's write command,this port is synchronous to "clk" + .Tx_fifo_rd_data (Tx_fifo_rd_data ),//the user write data to the fifo,synchronous to "clk" + + .sdram_data_valid(sdram_data_valid),//tell the user that valid read data is coming,active HIGH + .sdram_rd_data (sdram_rd_data ),//synchronous to sdram_data_valid + + .sdram_clk (sdram_clk ),//connected to the CLK port of SDRAM + .sdram_cke (sdram_cke ),//connected to the CKE port of SDRAM + .sdram_cs_n (sdram_cs_n ),//connected to the CS_n port of SDRAM + .sdram_ras_n (sdram_ras_n),//connected to the RAS_n port of SDRAM + .sdram_cas_n (sdram_cas_n),//connected to the CAS_n port of SDRAM + .sdram_we_n (sdram_we_n ),//connected to the WE_n port of SDRAM + .sdram_ba (sdram_ba ),//connected to the BA port of SDRAM + .sdram_addr (sdram_addr ),//connected to the ADDR port of SDRAM + .sdram_dqm (sdram_dqm ),//connected to the DQM port of SDRAM + .sdram_dq (sdram_dq ) //connected to the DQ port of SDRAM + ); + + + endmodule diff --git a/uart.v b/uart.v new file mode 100644 index 0000000..d092f19 --- /dev/null +++ b/uart.v @@ -0,0 +1,170 @@ +// Copyright (c) 2014 Sergiusz 'q3k' Baza艅ski +// Released under the 2-clause BSD license - see the COPYING file + +`timescale 1ns / 1ps + +/// This is not the prettiest UART you've seen... + +module uart_controller( + // Data input + input [7:0] tx_data_in, + // Data input latch + input tx_data_latch, + + // baud rate clock + input clock, + + // reset line + input reset, + + // goes 1 when the UART finished transmitting + output reg tx_transmitted, + // the actual UART transmitter output + output reg tx_signal, + + output reg rx_present, + input rx_present_clear, + output reg [7:0] rx_data, + + input rx_signal + ); + + // Internal TX data (latched from tx_data_in) + reg [7:0] tx_data; + + reg [3:0] tx_state; + reg [3:0] rx_state; + `define IDLE 0 + `define START 1 + `define BIT0 2 + `define BIT1 3 + `define BIT2 4 + `define BIT3 5 + `define BIT4 6 + `define BIT5 7 + `define BIT6 8 + `define BIT7 9 + `define STOP 10 + + /// Receiver + always @(posedge clock) + begin + if (reset) begin + rx_state <= `IDLE; + rx_present <= 0; + rx_data <= 0; + end else begin + if (rx_present_clear) + rx_present <= 0; + case (rx_state) + `IDLE: begin + if (!rx_signal) begin + // We received a start bit + rx_state <= `BIT0; + rx_present <= 0; + end + end + `BIT0: begin + rx_data[0] <= rx_signal; + rx_state <= `BIT1; + end + `BIT1: begin + rx_data[1] <= rx_signal; + rx_state <= `BIT2; + end + `BIT2: begin + rx_data[2] <= rx_signal; + rx_state <= `BIT3; + end + `BIT3: begin + rx_data[3] <= rx_signal; + rx_state <= `BIT4; + end + `BIT4: begin + rx_data[4] <= rx_signal; + rx_state <= `BIT5; + end + `BIT5: begin + rx_data[5] <= rx_signal; + rx_state <= `BIT6; + end + `BIT6: begin + rx_data[6] <= rx_signal; + rx_state <= `BIT7; + end + `BIT7: begin + rx_data[7] <= rx_signal; + rx_state <= `STOP; + end + `STOP: begin + rx_present <= 1; + rx_state <= `IDLE; + end + endcase + end + end + + /// Transmitter + always @(posedge clock) + begin + if (reset) begin + tx_state <= `IDLE; + tx_signal <= 1; + tx_data <= 0; + tx_transmitted <= 1; + end else begin + case (tx_state) + `IDLE: begin + if (tx_data_latch) + begin + tx_data <= tx_data_in; + tx_state <= `START; + tx_transmitted <= 0; + end + end + `START: begin + tx_signal <= 0; + tx_state <= `BIT0; + end + `BIT0: begin + tx_signal <= tx_data[0]; + tx_state <= `BIT1; + end + `BIT1: begin + tx_signal <= tx_data[1]; + tx_state <= `BIT2; + end + `BIT2: begin + tx_signal <= tx_data[2]; + tx_state <= `BIT3; + end + `BIT3: begin + tx_signal <= tx_data[3]; + tx_state <= `BIT4; + end + `BIT4: begin + tx_signal <= tx_data[4]; + tx_state <= `BIT5; + end + `BIT5: begin + tx_signal <= tx_data[5]; + tx_state <= `BIT6; + end + `BIT6: begin + tx_signal <= tx_data[6]; + tx_state <= `BIT7; + end + `BIT7: begin + tx_signal <= tx_data[7]; + tx_state <= `STOP; + end + `STOP: begin + tx_signal <= 1; + tx_state <= `IDLE; + tx_transmitted <= 1; + end + endcase + end + end + +endmodule