|
1 | NO CONTENT: new file 100644, binary diff hidden |
@@ -0,0 +1,15 | |||
|
1 | vendor_id=0x0403 # Vendor ID | |
|
2 | product_id=0x6010 # Product ID | |
|
3 | self_powered=false | |
|
4 | remote_wakeup=false | |
|
5 | max_power=0 | |
|
6 | in_is_isochronous=false | |
|
7 | out_is_isochronous=false | |
|
8 | suspend_pull_downs=false | |
|
9 | use_serial=false | |
|
10 | change_usb_version=false | |
|
11 | usb_version=0 | |
|
12 | manufacturer="LPP" | |
|
13 | product="LPP USB SPW Brick" | |
|
14 | serial="" | |
|
15 | chb_type=FIFO |
@@ -0,0 +1,15 | |||
|
1 | vendor_id=0x0403 # Vendor ID | |
|
2 | product_id=0x6010 # Product ID | |
|
3 | self_powered=false | |
|
4 | remote_wakeup=false | |
|
5 | max_power=0 | |
|
6 | in_is_isochronous=false | |
|
7 | out_is_isochronous=false | |
|
8 | suspend_pull_downs=false | |
|
9 | use_serial=false | |
|
10 | change_usb_version=false | |
|
11 | usb_version=0 | |
|
12 | manufacturer="LPP" | |
|
13 | product="LPP USB SPW Brick" | |
|
14 | serial="" | |
|
15 | chb_type=UART |
@@ -0,0 +1,145 | |||
|
1 | # Clocks | |
|
2 | NET "CLK50" PERIOD = 20 ns |LOC = "K3"; | |
|
3 | #NET "CLK32" PERIOD = 31.25 ns | LOC = "J4"; | |
|
4 | # LEDs | |
|
5 | NET "LEDS<0>" LOC="P11" |IOSTANDARD=LVTTL |DRIVE=8 |SLEW=SLOW; | |
|
6 | NET "LEDS<1>" LOC="N9" |IOSTANDARD=LVTTL |DRIVE=8 |SLEW=SLOW; | |
|
7 | NET "LEDS<2>" LOC="M9" |IOSTANDARD=LVTTL |DRIVE=8 |SLEW=SLOW; | |
|
8 | NET "LEDS<3>" LOC="P9" |IOSTANDARD=LVTTL |DRIVE=8 |SLEW=SLOW; | |
|
9 | NET "LEDS<4>" LOC="T8" |IOSTANDARD=LVTTL |DRIVE=8 |SLEW=SLOW; | |
|
10 | NET "LEDS<5>" LOC="N8" |IOSTANDARD=LVTTL |DRIVE=8 |SLEW=SLOW; | |
|
11 | NET "LEDS<6>" LOC="P8" |IOSTANDARD=LVTTL |DRIVE=8 |SLEW=SLOW; | |
|
12 | NET "LEDS<7>" LOC="P7" |IOSTANDARD=LVTTL |DRIVE=8 |SLEW=SLOW; | |
|
13 | ||
|
14 | # DIP Switches | |
|
15 | NET "SW<1>" LOC="L1" |IOSTANDARD=LVTTL |PULLUP; | |
|
16 | NET "SW<2>" LOC="L3" |IOSTANDARD=LVTTL |PULLUP; | |
|
17 | NET "SW<3>" LOC="L4" |IOSTANDARD=LVTTL |PULLUP; | |
|
18 | NET "SW<4>" LOC="L5" |IOSTANDARD=LVTTL |PULLUP; | |
|
19 | ||
|
20 | # SDRAM | |
|
21 | NET "dram_udqm" LOC="F15" |IOSTANDARD=LVTTL; | |
|
22 | NET "dram_clk" LOC="G16" |IOSTANDARD=LVTTL; | |
|
23 | NET "dram_cke" LOC="H16" |IOSTANDARD=LVTTL; | |
|
24 | NET "dram_ba_1" LOC="T14" |IOSTANDARD=LVTTL; | |
|
25 | NET "dram_ba_0" LOC="R14" |IOSTANDARD=LVTTL; | |
|
26 | NET "dram_cs_n" LOC="R1" |IOSTANDARD=LVTTL; | |
|
27 | NET "dram_ras_n" LOC="R2" |IOSTANDARD=LVTTL; | |
|
28 | NET "dram_cas_n" LOC="T4" |IOSTANDARD=LVTTL; | |
|
29 | NET "dram_we_n" LOC="R5" |IOSTANDARD=LVTTL; | |
|
30 | NET "dram_ldqm" LOC="T5" |IOSTANDARD=LVTTL; | |
|
31 | NET "dram_addr<0>" LOC="T15" |IOSTANDARD=LVTTL; | |
|
32 | NET "dram_addr<1>" LOC="R16" |IOSTANDARD=LVTTL; | |
|
33 | NET "dram_addr<2>" LOC="P15" |IOSTANDARD=LVTTL; | |
|
34 | NET "dram_addr<3>" LOC="P16" |IOSTANDARD=LVTTL; | |
|
35 | NET "dram_addr<4>" LOC="N16" |IOSTANDARD=LVTTL; | |
|
36 | NET "dram_addr<5>" LOC="M15" |IOSTANDARD=LVTTL; | |
|
37 | NET "dram_addr<6>" LOC="M16" |IOSTANDARD=LVTTL; | |
|
38 | NET "dram_addr<7>" LOC="L16" |IOSTANDARD=LVTTL; | |
|
39 | NET "dram_addr<8>" LOC="K15" |IOSTANDARD=LVTTL; | |
|
40 | NET "dram_addr<9>" LOC="K16" |IOSTANDARD=LVTTL; | |
|
41 | NET "dram_addr<10>" LOC="R15" |IOSTANDARD=LVTTL; | |
|
42 | NET "dram_addr<11>" LOC="J16" |IOSTANDARD=LVTTL; | |
|
43 | NET "dram_addr<12>" LOC="H15" |IOSTANDARD=LVTTL; | |
|
44 | NET "dram_dq<0>" LOC="T13" |IOSTANDARD=LVTTL; | |
|
45 | NET "dram_dq<1>" LOC="T12" |IOSTANDARD=LVTTL; | |
|
46 | NET "dram_dq<2>" LOC="R12" |IOSTANDARD=LVTTL; | |
|
47 | NET "dram_dq<3>" LOC="T9" |IOSTANDARD=LVTTL; | |
|
48 | NET "dram_dq<4>" LOC="R9" |IOSTANDARD=LVTTL; | |
|
49 | NET "dram_dq<5>" LOC="T7" |IOSTANDARD=LVTTL; | |
|
50 | NET "dram_dq<6>" LOC="R7" |IOSTANDARD=LVTTL; | |
|
51 | NET "dram_dq<7>" LOC="T6" |IOSTANDARD=LVTTL; | |
|
52 | NET "dram_dq<8>" LOC="F16" |IOSTANDARD=LVTTL; | |
|
53 | NET "dram_dq<9>" LOC="E15" |IOSTANDARD=LVTTL; | |
|
54 | NET "dram_dq<10>" LOC="E16" |IOSTANDARD=LVTTL; | |
|
55 | NET "dram_dq<11>" LOC="D16" |IOSTANDARD=LVTTL; | |
|
56 | NET "dram_dq<12>" LOC="B16" |IOSTANDARD=LVTTL; | |
|
57 | NET "dram_dq<13>" LOC="B15" |IOSTANDARD=LVTTL; | |
|
58 | NET "dram_dq<14>" LOC="C16" |IOSTANDARD=LVTTL; | |
|
59 | NET "dram_dq<15>" LOC="C15" |IOSTANDARD=LVTTL; | |
|
60 | #Created by Constraints Editor (xc6slx25-ftg256-3) - 2016/12/08 | |
|
61 | INST "dram_addr(0)" TNM = dram_addr; | |
|
62 | INST "dram_addr(1)" TNM = dram_addr; | |
|
63 | INST "dram_addr(2)" TNM = dram_addr; | |
|
64 | INST "dram_addr(3)" TNM = dram_addr; | |
|
65 | INST "dram_addr(4)" TNM = dram_addr; | |
|
66 | INST "dram_addr(5)" TNM = dram_addr; | |
|
67 | INST "dram_addr(6)" TNM = dram_addr; | |
|
68 | INST "dram_addr(7)" TNM = dram_addr; | |
|
69 | INST "dram_addr(8)" TNM = dram_addr; | |
|
70 | INST "dram_addr(9)" TNM = dram_addr; | |
|
71 | INST "dram_addr(10)" TNM = dram_addr; | |
|
72 | INST "dram_addr(11)" TNM = dram_addr; | |
|
73 | INST "dram_addr(12)" TNM = dram_addr; | |
|
74 | INST "dram_addr(0)" TNM = dram_out; | |
|
75 | INST "dram_addr(1)" TNM = dram_out; | |
|
76 | INST "dram_addr(2)" TNM = dram_out; | |
|
77 | INST "dram_addr(3)" TNM = dram_out; | |
|
78 | INST "dram_addr(4)" TNM = dram_out; | |
|
79 | INST "dram_addr(5)" TNM = dram_out; | |
|
80 | INST "dram_addr(6)" TNM = dram_out; | |
|
81 | INST "dram_addr(7)" TNM = dram_out; | |
|
82 | INST "dram_addr(8)" TNM = dram_out; | |
|
83 | INST "dram_addr(9)" TNM = dram_out; | |
|
84 | INST "dram_addr(10)" TNM = dram_out; | |
|
85 | INST "dram_addr(11)" TNM = dram_out; | |
|
86 | INST "dram_addr(12)" TNM = dram_out; | |
|
87 | INST "dram_ba_0" TNM = dram_out; | |
|
88 | INST "dram_ba_1" TNM = dram_out; | |
|
89 | INST "dram_cas_n" TNM = dram_out; | |
|
90 | INST "dram_cke" TNM = dram_out; | |
|
91 | #INST "dram_clk" TNM = dram_out; | |
|
92 | INST "dram_cs_n" TNM = dram_out; | |
|
93 | INST "dram_dq(0)" TNM = dram_out; | |
|
94 | INST "dram_dq(1)" TNM = dram_out; | |
|
95 | INST "dram_dq(2)" TNM = dram_out; | |
|
96 | INST "dram_dq(3)" TNM = dram_out; | |
|
97 | INST "dram_dq(4)" TNM = dram_out; | |
|
98 | INST "dram_dq(5)" TNM = dram_out; | |
|
99 | INST "dram_dq(6)" TNM = dram_out; | |
|
100 | INST "dram_dq(7)" TNM = dram_out; | |
|
101 | INST "dram_dq(8)" TNM = dram_out; | |
|
102 | INST "dram_dq(9)" TNM = dram_out; | |
|
103 | INST "dram_dq(10)" TNM = dram_out; | |
|
104 | INST "dram_dq(11)" TNM = dram_out; | |
|
105 | INST "dram_dq(12)" TNM = dram_out; | |
|
106 | INST "dram_dq(13)" TNM = dram_out; | |
|
107 | INST "dram_dq(14)" TNM = dram_out; | |
|
108 | INST "dram_dq(15)" TNM = dram_out; | |
|
109 | INST "dram_ldqm" TNM = dram_out; | |
|
110 | INST "dram_ras_n" TNM = dram_out; | |
|
111 | INST "dram_udqm" TNM = dram_out; | |
|
112 | INST "dram_we_n" TNM = dram_out; | |
|
113 | TIMEGRP "dram_out" OFFSET = OUT 12 ns AFTER "CLK50"; | |
|
114 | INST "dram_dq(0)" TNM = dram_in; | |
|
115 | INST "dram_dq(1)" TNM = dram_in; | |
|
116 | INST "dram_dq(2)" TNM = dram_in; | |
|
117 | INST "dram_dq(3)" TNM = dram_in; | |
|
118 | INST "dram_dq(4)" TNM = dram_in; | |
|
119 | INST "dram_dq(5)" TNM = dram_in; | |
|
120 | INST "dram_dq(6)" TNM = dram_in; | |
|
121 | INST "dram_dq(7)" TNM = dram_in; | |
|
122 | INST "dram_dq(8)" TNM = dram_in; | |
|
123 | INST "dram_dq(9)" TNM = dram_in; | |
|
124 | INST "dram_dq(10)" TNM = dram_in; | |
|
125 | INST "dram_dq(11)" TNM = dram_in; | |
|
126 | INST "dram_dq(12)" TNM = dram_in; | |
|
127 | INST "dram_dq(13)" TNM = dram_in; | |
|
128 | INST "dram_dq(14)" TNM = dram_in; | |
|
129 | INST "dram_dq(15)" TNM = dram_in; | |
|
130 | TIMEGRP "dram_in" OFFSET = IN 3 ns BEFORE "CLK50" RISING; | |
|
131 | ||
|
132 | # FTDI | |
|
133 | NET "FTDI_RXF" LOC="N3" | IOSTANDARD=LVTTL; | |
|
134 | NET "FTDI_TXE" LOC="N1" | IOSTANDARD=LVTTL; | |
|
135 | NET "FTDI_SIWUA" LOC="M3" | IOSTANDARD=LVTTL; | |
|
136 | NET "FTDI_WR" LOC="M2" | IOSTANDARD=LVTTL; | |
|
137 | NET "FTDI_RD" LOC="M1" | IOSTANDARD=LVTTL; | |
|
138 | NET "FTDI_D<0>" LOC="M7" | IOSTANDARD=LVTTL; | |
|
139 | NET "FTDI_D<1>" LOC="N6" | IOSTANDARD=LVTTL; | |
|
140 | NET "FTDI_D<2>" LOC="M6" | IOSTANDARD=LVTTL; | |
|
141 | NET "FTDI_D<3>" LOC="P5" | IOSTANDARD=LVTTL; | |
|
142 | NET "FTDI_D<4>" LOC="N5" | IOSTANDARD=LVTTL; | |
|
143 | NET "FTDI_D<5>" LOC="P4" | IOSTANDARD=LVTTL; | |
|
144 | NET "FTDI_D<6>" LOC="P2" | IOSTANDARD=LVTTL; | |
|
145 | NET "FTDI_D<7>" LOC="P1" | IOSTANDARD=LVTTL; |
@@ -0,0 +1,77 | |||
|
1 | VHDLIB=../.. | |
|
2 | SELFDIR := $(dir $(lastword $(MAKEFILE_LIST))) | |
|
3 | SCRIPTSDIR=$(VHDLIB)/scripts/ | |
|
4 | GRLIB := $(shell sh $(VHDLIB)/scripts/lpp_relpath.sh) | |
|
5 | TOP=leon3mp | |
|
6 | BOARD=MiniSpartan6p | |
|
7 | DESIGN=leon3-MiniSpartan6p | |
|
8 | include $(VHDLIB)/boards/$(BOARD)/Makefile.inc | |
|
9 | DEVICE=$(PART)-$(PACKAGE)$(SPEED) | |
|
10 | #UCF=$(VHDLIB)/boards/$(BOARD)/default.ucf | |
|
11 | UCF=$(VHDLIB)/boards/$(BOARD)/with-fifo.ucf | |
|
12 | UCF_PLANAHEAD=$(UCF) | |
|
13 | QSF=$(GRLIB)/boards/$(BOARD)/$(TOP).qsf | |
|
14 | EFFORT=high | |
|
15 | XSTOPT=-uc leon3mp.xcf | |
|
16 | SYNPOPT="set_option -pipe 1; set_option -retiming 1; set_option -write_apr_constraint 0" | |
|
17 | ||
|
18 | ||
|
19 | VHDLOPTSYNFILES = sdctrl16.vhd config.vhd leon3mp.vhd | |
|
20 | ||
|
21 | VHDLSIMFILES=mt48lc16m16a2.vhd testbench.vhd | |
|
22 | ||
|
23 | SIMTOP=testbench | |
|
24 | SDCFILE=$(GRLIB)/boards/$(BOARD)/default.sdc | |
|
25 | BITGEN=$(VHDLIB)/boards/$(BOARD)/default.ut | |
|
26 | ||
|
27 | TECHLIBS = unisim | |
|
28 | ||
|
29 | LIBSKIP = core1553bbc core1553brm core1553brt gr1553 corePCIF \ | |
|
30 | tmtc openchip hynix ihp gleichmann usbhc opencores fmf ftlib gsi | |
|
31 | ||
|
32 | DIRSKIP = b1553 pcif leon2 leon2ft crypto satcan ddr usb ata i2c \ | |
|
33 | pci grusbhc haps slink ascs can pwm greth coremp7 ac97 atf \ | |
|
34 | grlfpc \ | |
|
35 | ./dsp/lpp_fft_rtax \ | |
|
36 | ./amba_lcd_16x2_ctrlr \ | |
|
37 | ./general_purpose/lpp_AMR \ | |
|
38 | ./general_purpose/lpp_balise \ | |
|
39 | ./general_purpose/lpp_delay \ | |
|
40 | ./lpp_bootloader \ | |
|
41 | ./lpp_sim/CY7C1061DV33 \ | |
|
42 | ./lpp_uart \ | |
|
43 | ./dsp/lpp_fft \ | |
|
44 | ./lpp_leon3_soc \ | |
|
45 | ./lpp_debug_lfr | |
|
46 | ||
|
47 | FILESKIP = i2cmst.vhd \ | |
|
48 | APB_MULTI_DIODE.vhd \ | |
|
49 | APB_MULTI_DIODE.vhd \ | |
|
50 | Top_MatrixSpec.vhd \ | |
|
51 | APB_FFT.vhd \ | |
|
52 | lpp_lfr_ms_FFT.vhd \ | |
|
53 | lpp_lfr_apbreg.vhd \ | |
|
54 | CoreFFT.vhd \ | |
|
55 | lpp_lfr_ms.vhd \ | |
|
56 | lpp_lfr_sim_pkg.vhd \ | |
|
57 | mtie_maps.vhd \ | |
|
58 | ftsrctrlc.vhd \ | |
|
59 | ftsdctrl.vhd \ | |
|
60 | ftsrctrl8.vhd \ | |
|
61 | ftmctrl.vhd \ | |
|
62 | ftsdctrl64.vhd \ | |
|
63 | ftahbram.vhd \ | |
|
64 | ftahbram2.vhd \ | |
|
65 | sramft.vhd \ | |
|
66 | nandfctrlx.vhd | |
|
67 | ||
|
68 | include $(GRLIB)/bin/Makefile | |
|
69 | ||
|
70 | ################## project specific targets ########################## | |
|
71 | ||
|
72 | load-ram: | |
|
73 | xc3sprog -c ftdi -p0 leon3mp.bit | |
|
74 | ||
|
75 | load-flash: | |
|
76 | xc3sprog -c ftdi -p0 $(VHDLIB)/boards/$(BOARD)/bscan_spi_s6lx25_ftg256.bit | |
|
77 | xc3sprog -c ftdi -I leon3mp.bit |
@@ -0,0 +1,66 | |||
|
1 | This LEON3 design is tailored to the Scarab Hardware [MiniSpartan6+](https://www.scarabhardware.com/minispartan6/) board. | |
|
2 | ||
|
3 | Simulation and synthesis | |
|
4 | ------------------------ | |
|
5 | ||
|
6 | This design tries to use as much as possible free (as in freedom) tools and at least free (as in free beer) when impossible. | |
|
7 | ||
|
8 | ||
|
9 | Note that the simulation doesn't work as expected yet. | |
|
10 | ||
|
11 | ||
|
12 | To build the design: | |
|
13 | ```bash | |
|
14 | make ise | |
|
15 | ``` | |
|
16 | ||
|
17 | To load into FPGA RAM: | |
|
18 | ```bash | |
|
19 | make load-ram | |
|
20 | ``` | |
|
21 | ||
|
22 | To load into FPGA Flash: | |
|
23 | ```bash | |
|
24 | make load-flash | |
|
25 | ``` | |
|
26 | ||
|
27 | Design specifics | |
|
28 | ---------------- | |
|
29 | ||
|
30 | * The AHB and processor is clocked from the 50 MHz clock. | |
|
31 | ||
|
32 | * The SDRAM is working with the sdctrl16 memory controller taken from leon3-altera-de2-ep2c35 design. | |
|
33 | ||
|
34 | * The UART DSU interface ie enabled and connected to interface B of ft2232H chip. | |
|
35 | Start GRMON with -uart /dev/ttyUSB1 | |
|
36 | ||
|
37 | * Output from GRMON2 should look similar to this: | |
|
38 | ||
|
39 | ```bash | |
|
40 | GRMON2 LEON debug monitor v2.0.80-beta 64-bit eval version | |
|
41 | ||
|
42 | Copyright (C) 2016 Cobham Gaisler - All rights reserved. | |
|
43 | For latest updates, go to http://www.gaisler.com/ | |
|
44 | Comments or bug-reports to support@gaisler.com | |
|
45 | ||
|
46 | This eval version will expire on 18/04/2017 | |
|
47 | ||
|
48 | using port /dev/ttyUSB1 @ 115200 baud | |
|
49 | GRLIB build version: 4164 | |
|
50 | Detected frequency: 50 MHz | |
|
51 | ||
|
52 | Component Vendor | |
|
53 | LEON3 SPARC V8 Processor Cobham Gaisler | |
|
54 | AHB Debug UART Cobham Gaisler | |
|
55 | AHB/APB Bridge Cobham Gaisler | |
|
56 | LEON3 Debug Support Unit Cobham Gaisler | |
|
57 | PC133 SDRAM Controller Cobham Gaisler | |
|
58 | Multi-processor Interrupt Ctrl. Cobham Gaisler | |
|
59 | Modular Timer Unit Cobham Gaisler | |
|
60 | General Purpose I/O port Cobham Gaisler | |
|
61 | ||
|
62 | Use command 'info sys' to print a detailed report of attached cores | |
|
63 | ||
|
64 | grmon2> | |
|
65 | ||
|
66 | ``` No newline at end of file |
@@ -0,0 +1,166 | |||
|
1 | ||
|
2 | ||
|
3 | ||
|
4 | ----------------------------------------------------------------------------- | |
|
5 | -- LEON3 Demonstration design test bench configuration | |
|
6 | -- Copyright (C) 2009 Aeroflex Gaisler | |
|
7 | ------------------------------------------------------------------------------ | |
|
8 | ||
|
9 | ||
|
10 | library techmap; | |
|
11 | use techmap.gencomp.all; | |
|
12 | ||
|
13 | package config is | |
|
14 | -- Technology and synthesis options | |
|
15 | constant CFG_FABTECH : integer := spartan6; | |
|
16 | constant CFG_MEMTECH : integer := spartan6; | |
|
17 | constant CFG_PADTECH : integer := spartan6; | |
|
18 | constant CFG_TRANSTECH : integer := GTP0; | |
|
19 | constant CFG_NOASYNC : integer := 0; | |
|
20 | constant CFG_SCAN : integer := 0; | |
|
21 | -- Clock generator | |
|
22 | constant CFG_CLKTECH : integer := spartan6; | |
|
23 | constant CFG_CLKMUL : integer := (3); | |
|
24 | constant CFG_CLKDIV : integer := (2); | |
|
25 | constant CFG_OCLKDIV : integer := 1; | |
|
26 | constant CFG_OCLKBDIV : integer := 0; | |
|
27 | constant CFG_OCLKCDIV : integer := 0; | |
|
28 | constant CFG_PCIDLL : integer := 0; | |
|
29 | constant CFG_PCISYSCLK: integer := 0; | |
|
30 | constant CFG_CLK_NOFB : integer := 0; | |
|
31 | -- LEON3 processor core | |
|
32 | constant CFG_LEON3 : integer := 1; | |
|
33 | constant CFG_NCPU : integer := (1); | |
|
34 | constant CFG_NWIN : integer := (8); | |
|
35 | constant CFG_V8 : integer := 2 + 4*0; | |
|
36 | constant CFG_MAC : integer := 0; | |
|
37 | constant CFG_BP : integer := 1; | |
|
38 | constant CFG_SVT : integer := 1; | |
|
39 | constant CFG_RSTADDR : integer := 16#00000#; | |
|
40 | constant CFG_LDDEL : integer := (2); | |
|
41 | constant CFG_NOTAG : integer := 1; | |
|
42 | constant CFG_NWP : integer := (0); | |
|
43 | constant CFG_PWD : integer := 0*2; | |
|
44 | constant CFG_FPU : integer := 0 + 16*0 + 32*0; | |
|
45 | constant CFG_GRFPUSH : integer := 0; | |
|
46 | constant CFG_ICEN : integer := 1; | |
|
47 | constant CFG_ISETS : integer := 1; | |
|
48 | constant CFG_ISETSZ : integer := 8; | |
|
49 | constant CFG_ILINE : integer := 8; | |
|
50 | constant CFG_IREPL : integer := 0; | |
|
51 | constant CFG_ILOCK : integer := 0; | |
|
52 | constant CFG_ILRAMEN : integer := 0; | |
|
53 | constant CFG_ILRAMADDR: integer := 16#8E#; | |
|
54 | constant CFG_ILRAMSZ : integer := 1; | |
|
55 | constant CFG_DCEN : integer := 1; | |
|
56 | constant CFG_DSETS : integer := 1; | |
|
57 | constant CFG_DSETSZ : integer := 8; | |
|
58 | constant CFG_DLINE : integer := 8; | |
|
59 | constant CFG_DREPL : integer := 0; | |
|
60 | constant CFG_DLOCK : integer := 0; | |
|
61 | constant CFG_DSNOOP : integer := 0 + 0*2 + 4*0; | |
|
62 | constant CFG_DFIXED : integer := 16#0#; | |
|
63 | constant CFG_DLRAMEN : integer := 0; | |
|
64 | constant CFG_DLRAMADDR: integer := 16#8F#; | |
|
65 | constant CFG_DLRAMSZ : integer := 1; | |
|
66 | constant CFG_MMUEN : integer := 0; | |
|
67 | constant CFG_ITLBNUM : integer := 8; | |
|
68 | constant CFG_DTLBNUM : integer := 2; | |
|
69 | constant CFG_TLB_TYPE : integer := 1 + 0*2; | |
|
70 | constant CFG_TLB_REP : integer := 1; | |
|
71 | constant CFG_MMU_PAGE : integer := 0; | |
|
72 | constant CFG_DSU : integer := 1; | |
|
73 | constant CFG_ITBSZ : integer := 0 + 64*0; | |
|
74 | constant CFG_ATBSZ : integer := 0; | |
|
75 | constant CFG_AHBPF : integer := 0; | |
|
76 | constant CFG_LEON3FT_EN : integer := 0; | |
|
77 | constant CFG_IUFT_EN : integer := 0; | |
|
78 | constant CFG_FPUFT_EN : integer := 0; | |
|
79 | constant CFG_RF_ERRINJ : integer := 0; | |
|
80 | constant CFG_CACHE_FT_EN : integer := 0; | |
|
81 | constant CFG_CACHE_ERRINJ : integer := 0; | |
|
82 | constant CFG_LEON3_NETLIST: integer := 0; | |
|
83 | constant CFG_DISAS : integer := 0 + 0; | |
|
84 | constant CFG_PCLOW : integer := 2; | |
|
85 | constant CFG_STAT_ENABLE : integer := 0; | |
|
86 | constant CFG_STAT_CNT : integer := 1; | |
|
87 | constant CFG_STAT_NMAX : integer := 0; | |
|
88 | constant CFG_STAT_DSUEN : integer := 0; | |
|
89 | constant CFG_NP_ASI : integer := 0; | |
|
90 | constant CFG_WRPSR : integer := 0; | |
|
91 | constant CFG_ALTWIN : integer := 0; | |
|
92 | constant CFG_REX : integer := 0; | |
|
93 | -- AMBA settings | |
|
94 | constant CFG_DEFMST : integer := (0); | |
|
95 | constant CFG_RROBIN : integer := 1; | |
|
96 | constant CFG_SPLIT : integer := 1; | |
|
97 | constant CFG_FPNPEN : integer := 0; | |
|
98 | constant CFG_AHBIO : integer := 16#FFF#; | |
|
99 | constant CFG_APBADDR : integer := 16#800#; | |
|
100 | constant CFG_AHB_MON : integer := 0; | |
|
101 | constant CFG_AHB_MONERR : integer := 0; | |
|
102 | constant CFG_AHB_MONWAR : integer := 0; | |
|
103 | constant CFG_AHB_DTRACE : integer := 0; | |
|
104 | -- DSU UART | |
|
105 | constant CFG_AHB_UART : integer := 0; | |
|
106 | -- JTAG based DSU interface | |
|
107 | constant CFG_AHB_JTAG : integer := 1; | |
|
108 | -- Xilinx MIG | |
|
109 | constant CFG_MIG_DDR2 : integer := 1; | |
|
110 | constant CFG_MIG_RANKS : integer := (1); | |
|
111 | constant CFG_MIG_COLBITS : integer := (10); | |
|
112 | constant CFG_MIG_ROWBITS : integer := (13); | |
|
113 | constant CFG_MIG_BANKBITS: integer := (2); | |
|
114 | constant CFG_MIG_HMASK : integer := 16#FC0#; | |
|
115 | -- AHB ROM | |
|
116 | constant CFG_AHBROMEN : integer := 1; | |
|
117 | constant CFG_AHBROPIP : integer := 0; | |
|
118 | constant CFG_AHBRODDR : integer := 16#000#; | |
|
119 | constant CFG_ROMADDR : integer := 16#100#; | |
|
120 | constant CFG_ROMMASK : integer := 16#E00# + 16#100#; | |
|
121 | -- AHB RAM | |
|
122 | constant CFG_AHBRAMEN : integer := 1; | |
|
123 | constant CFG_AHBRSZ : integer := 4; | |
|
124 | constant CFG_AHBRADDR : integer := 16#A00#; | |
|
125 | constant CFG_AHBRPIPE : integer := 0; | |
|
126 | -- UART 1 | |
|
127 | constant CFG_UART1_ENABLE : integer := 1; | |
|
128 | constant CFG_UART1_FIFO : integer := 4; | |
|
129 | -- LEON3 interrupt controller | |
|
130 | constant CFG_IRQ3_ENABLE : integer := 1; | |
|
131 | constant CFG_IRQ3_NSEC : integer := 0; | |
|
132 | -- Modular timer | |
|
133 | constant CFG_GPT_ENABLE : integer := 1; | |
|
134 | constant CFG_GPT_NTIM : integer := (2); | |
|
135 | constant CFG_GPT_SW : integer := (8); | |
|
136 | constant CFG_GPT_TW : integer := (32); | |
|
137 | constant CFG_GPT_IRQ : integer := (8); | |
|
138 | constant CFG_GPT_SEPIRQ : integer := 1; | |
|
139 | constant CFG_GPT_WDOGEN : integer := 0; | |
|
140 | constant CFG_GPT_WDOG : integer := 16#0#; | |
|
141 | -- GPIO port | |
|
142 | constant CFG_GRGPIO_ENABLE : integer := 0; | |
|
143 | constant CFG_GRGPIO_IMASK : integer := 16#0000#; | |
|
144 | constant CFG_GRGPIO_WIDTH : integer := 1; | |
|
145 | ||
|
146 | -- SPI controller | |
|
147 | constant CFG_SPICTRL_ENABLE : integer := 1; | |
|
148 | constant CFG_SPICTRL_NUM : integer := (1); | |
|
149 | constant CFG_SPICTRL_SLVS : integer := (1); | |
|
150 | constant CFG_SPICTRL_FIFO : integer := (2); | |
|
151 | constant CFG_SPICTRL_SLVREG : integer := 1; | |
|
152 | constant CFG_SPICTRL_ODMODE : integer := 1; | |
|
153 | constant CFG_SPICTRL_AM : integer := 0; | |
|
154 | constant CFG_SPICTRL_ASEL : integer := 0; | |
|
155 | constant CFG_SPICTRL_TWEN : integer := 0; | |
|
156 | constant CFG_SPICTRL_MAXWLEN : integer := (0); | |
|
157 | constant CFG_SPICTRL_SYNCRAM : integer := 0; | |
|
158 | constant CFG_SPICTRL_FT : integer := 0; | |
|
159 | ||
|
160 | -- GRLIB debugging | |
|
161 | constant CFG_DUART : integer := 0; | |
|
162 | ||
|
163 | ||
|
164 | constant CFG_AHB_FTDI : integer := 1; | |
|
165 | constant CFG_FTDI_LOOPBACK : integer := 0; | |
|
166 | end; |
@@ -0,0 +1,340 | |||
|
1 | ||
|
2 | ||
|
3 | library ieee; | |
|
4 | use ieee.std_logic_1164.all; | |
|
5 | USE IEEE.NUMERIC_STD.ALL; | |
|
6 | library grlib; | |
|
7 | use grlib.amba.all; | |
|
8 | use grlib.stdlib.all; | |
|
9 | use grlib.devices.all; | |
|
10 | library techmap; | |
|
11 | use techmap.gencomp.all; | |
|
12 | use techmap.allclkgen.all; | |
|
13 | library gaisler; | |
|
14 | use gaisler.memctrl.all; | |
|
15 | use gaisler.leon3.all; | |
|
16 | use gaisler.uart.all; | |
|
17 | use gaisler.misc.all; | |
|
18 | use gaisler.jtag.all; | |
|
19 | --pragma translate_off | |
|
20 | use gaisler.sim.all; | |
|
21 | --pragma translate_on | |
|
22 | library lpp; | |
|
23 | use lpp.lpp_usb.all; | |
|
24 | ||
|
25 | use work.config.all; | |
|
26 | ||
|
27 | library unisim; | |
|
28 | use unisim.vcomponents.all; | |
|
29 | ||
|
30 | entity leon3mp is | |
|
31 | generic ( | |
|
32 | fabtech : integer := CFG_FABTECH; | |
|
33 | memtech : integer := CFG_MEMTECH; | |
|
34 | padtech : integer := CFG_PADTECH; | |
|
35 | clktech : integer := CFG_CLKTECH; | |
|
36 | disas : integer := CFG_DISAS; -- Enable disassembly to console | |
|
37 | dbguart : integer := CFG_DUART; -- Print UART on console | |
|
38 | pclow : integer := CFG_PCLOW | |
|
39 | ); | |
|
40 | port ( | |
|
41 | CLK50 : in std_logic; | |
|
42 | LEDS : inout std_logic_vector(7 downto 0); | |
|
43 | SW : in std_logic_vector(4 downto 1); | |
|
44 | dram_addr : out std_logic_vector(12 downto 0); | |
|
45 | dram_ba_0 : out std_logic; | |
|
46 | dram_ba_1 : out std_logic; | |
|
47 | dram_dq : inout std_logic_vector(15 downto 0); | |
|
48 | ||
|
49 | dram_clk : out std_logic; | |
|
50 | dram_cke : out std_logic; | |
|
51 | dram_cs_n : out std_logic; | |
|
52 | dram_we_n : out std_logic; -- sdram write enable | |
|
53 | dram_ras_n : out std_logic; -- sdram ras | |
|
54 | dram_cas_n : out std_logic; -- sdram cas | |
|
55 | dram_ldqm : out std_logic; -- sdram ldqm | |
|
56 | dram_udqm : out std_logic; -- sdram udqm | |
|
57 | uart_txd : out std_logic; -- DSU tx data | |
|
58 | uart_rxd : in std_logic; -- DSU rx data | |
|
59 | ||
|
60 | FTDI_RXF : in std_logic; | |
|
61 | FTDI_TXE : in std_logic; | |
|
62 | FTDI_SIWUA : out std_logic; | |
|
63 | FTDI_WR : out std_logic; | |
|
64 | FTDI_RD : out std_logic; | |
|
65 | FTDI_D : inout std_logic_vector(7 downto 0) | |
|
66 | ||
|
67 | ); | |
|
68 | end; | |
|
69 | ||
|
70 | architecture rtl of leon3mp is | |
|
71 | signal resetn : std_logic; | |
|
72 | signal clkm, rstn, rstraw, rst : std_logic; | |
|
73 | signal clkm_inv : std_logic := '0'; | |
|
74 | ||
|
75 | signal cptr : std_logic_vector(29 downto 0); | |
|
76 | constant BOARD_FREQ : integer := 25000; -- CLK input frequency in KHz | |
|
77 | constant CPU_FREQ : integer := BOARD_FREQ * CFG_CLKMUL / CFG_CLKDIV; -- cpu frequency in KHz | |
|
78 | signal sdi : sdctrl_in_type; | |
|
79 | signal sdo : sdctrl_out_type; | |
|
80 | ||
|
81 | --AMBA bus standard interface signals-- | |
|
82 | signal apbi : apb_slv_in_type; | |
|
83 | signal apbo : apb_slv_out_vector := (others => apb_none); | |
|
84 | signal ahbsi : ahb_slv_in_type; | |
|
85 | signal ahbso : ahb_slv_out_vector := (others => ahbs_none); | |
|
86 | signal ahbmi : ahb_mst_in_type; | |
|
87 | signal ahbmo : ahb_mst_out_vector := (others => ahbm_none); | |
|
88 | ||
|
89 | signal tck, tckn, tms, tdi, tdo : std_ulogic; | |
|
90 | ||
|
91 | signal cgi : clkgen_in_type; | |
|
92 | signal cgo : clkgen_out_type; | |
|
93 | ||
|
94 | signal dui : uart_in_type; | |
|
95 | signal duo : uart_out_type; | |
|
96 | ||
|
97 | signal irqi : irq_in_vector(0 to CFG_NCPU-1); | |
|
98 | signal irqo : irq_out_vector(0 to CFG_NCPU-1); | |
|
99 | ||
|
100 | signal dbgi : l3_debug_in_vector(0 to CFG_NCPU-1); | |
|
101 | signal dbgo : l3_debug_out_vector(0 to CFG_NCPU-1); | |
|
102 | ||
|
103 | signal dsui : dsu_in_type; | |
|
104 | signal dsuo : dsu_out_type; | |
|
105 | ||
|
106 | ||
|
107 | signal gpti : gptimer_in_type; | |
|
108 | ||
|
109 | signal gpioi_0 : gpio_in_type; | |
|
110 | signal gpioo_0 : gpio_out_type; | |
|
111 | ||
|
112 | signal dsubren : std_logic :='0'; | |
|
113 | ||
|
114 | ||
|
115 | signal FTDI_D_in : std_logic_vector(7 downto 0); | |
|
116 | signal FTDI_D_out : std_logic_vector(7 downto 0); | |
|
117 | signal FTDI_drive : std_logic; | |
|
118 | ||
|
119 | ||
|
120 | component sdctrl16 | |
|
121 | generic ( | |
|
122 | hindex : integer := 0; | |
|
123 | haddr : integer := 0; | |
|
124 | hmask : integer := 16#f00#; | |
|
125 | ioaddr : integer := 16#000#; | |
|
126 | iomask : integer := 16#fff#; | |
|
127 | wprot : integer := 0; | |
|
128 | invclk : integer := 0; | |
|
129 | fast : integer := 0; | |
|
130 | pwron : integer := 0; | |
|
131 | sdbits : integer := 16; | |
|
132 | oepol : integer := 0; | |
|
133 | pageburst : integer := 0; | |
|
134 | mobile : integer := 0 | |
|
135 | ); | |
|
136 | port ( | |
|
137 | rst : in std_ulogic; | |
|
138 | clk : in std_ulogic; | |
|
139 | ahbsi : in ahb_slv_in_type; | |
|
140 | ahbso : out ahb_slv_out_type; | |
|
141 | sdi : in sdctrl_in_type; | |
|
142 | sdo : out sdctrl_out_type | |
|
143 | ); | |
|
144 | end component; | |
|
145 | ||
|
146 | begin | |
|
147 | resetn <= SW(1); | |
|
148 | ||
|
149 | clk_pad : clkpad generic map (tech => padtech) port map (CLK50, clkm); | |
|
150 | clkm_inv <= not clkm; | |
|
151 | ||
|
152 | resetn_pad : inpad generic map (tech => padtech) port map (resetn, rst); | |
|
153 | rst0 : rstgen -- reset generator (reset is active LOW) | |
|
154 | port map (rst, clkm, '1', rstn, rstraw); | |
|
155 | ||
|
156 | ||
|
157 | ---------------------------------------------------------------------- | |
|
158 | --- AHB CONTROLLER -------------------------------------------------- | |
|
159 | ---------------------------------------------------------------------- | |
|
160 | ||
|
161 | ahb0 : ahbctrl -- AHB arbiter/multiplexer | |
|
162 | generic map (defmast => CFG_DEFMST, split => CFG_SPLIT, | |
|
163 | rrobin => CFG_RROBIN, ioaddr => CFG_AHBIO, | |
|
164 | nahbm => CFG_NCPU+CFG_AHB_FTDI+CFG_AHB_UART+CFG_AHB_JTAG, nahbs => 8) | |
|
165 | ||
|
166 | port map (rstn, clkm, ahbmi, ahbmo, ahbsi, ahbso); | |
|
167 | ||
|
168 | ---------------------------------------------------------------------- | |
|
169 | ----- LEON3 processor and DSU --------------------------------------- | |
|
170 | ---------------------------------------------------------------------- | |
|
171 | ||
|
172 | cpu : for i in 0 to CFG_NCPU-1 generate | |
|
173 | nosh : if CFG_GRFPUSH = 0 generate | |
|
174 | u0 : leon3s -- LEON3 processor | |
|
175 | generic map (i, fabtech, memtech, CFG_NWIN, CFG_DSU, CFG_FPU*(1-CFG_GRFPUSH), CFG_V8, | |
|
176 | 0, CFG_MAC, pclow, CFG_NOTAG, CFG_NWP, CFG_ICEN, CFG_IREPL, CFG_ISETS, CFG_ILINE, | |
|
177 | CFG_ISETSZ, CFG_ILOCK, CFG_DCEN, CFG_DREPL, CFG_DSETS, CFG_DLINE, CFG_DSETSZ, | |
|
178 | CFG_DLOCK, CFG_DSNOOP, CFG_ILRAMEN, CFG_ILRAMSZ, CFG_ILRAMADDR, CFG_DLRAMEN, | |
|
179 | CFG_DLRAMSZ, CFG_DLRAMADDR, CFG_MMUEN, CFG_ITLBNUM, CFG_DTLBNUM, CFG_TLB_TYPE, CFG_TLB_REP, | |
|
180 | CFG_LDDEL, disas, CFG_ITBSZ, CFG_PWD, CFG_SVT, CFG_RSTADDR, CFG_NCPU-1, | |
|
181 | 0, 0, CFG_MMU_PAGE, CFG_BP, CFG_NP_ASI, CFG_WRPSR) | |
|
182 | port map (clkm, rstn, ahbmi, ahbmo(i), ahbsi, ahbso, | |
|
183 | irqi(i), irqo(i), dbgi(i), dbgo(i)); | |
|
184 | end generate; | |
|
185 | end generate; | |
|
186 | ||
|
187 | --ledr[0] lit when leon 3 debugvector signals error | |
|
188 | dsugen : if CFG_DSU = 1 generate | |
|
189 | dsu0 : dsu3 -- LEON3 Debug Support Unit (slave) | |
|
190 | generic map (hindex => 2, haddr => 16#900#, hmask => 16#F00#, | |
|
191 | ncpu => CFG_NCPU, tbits => 30, tech => memtech, irq => 0, kbytes => CFG_ATBSZ) | |
|
192 | port map (rstn, clkm, ahbmi, ahbsi, ahbso(2), dbgo, dbgi, dsui, dsuo); | |
|
193 | dsui.enable <= '1'; | |
|
194 | ||
|
195 | end generate; | |
|
196 | nodsu : if CFG_DSU = 0 generate | |
|
197 | ahbso(2) <= ahbs_none; dsuo.tstop <= '0'; dsuo.active <= '0'; --no timer freeze, no light. | |
|
198 | end generate; | |
|
199 | ||
|
200 | dcomgen : if CFG_AHB_UART = 1 generate | |
|
201 | dcom0: ahbuart -- Debug UART | |
|
202 | generic map (hindex => CFG_NCPU, pindex => 7, paddr => 7) | |
|
203 | port map (rstn, clkm, dui, duo, apbi, apbo(7), ahbmi, ahbmo(CFG_NCPU)); | |
|
204 | end generate; | |
|
205 | uart_txd <= duo.txd; | |
|
206 | dui.rxd <= uart_rxd; | |
|
207 | ||
|
208 | ahbjtaggen0 :if CFG_AHB_JTAG = 1 generate | |
|
209 | ahbjtag0 : ahbjtag generic map(tech => fabtech, hindex => CFG_NCPU+CFG_AHB_UART) | |
|
210 | port map(rstn, clkm, tck, tms, tdi, tdo, ahbmi, ahbmo(CFG_NCPU+CFG_AHB_UART), | |
|
211 | open, open, open, open, open, open, open, '0'); | |
|
212 | end generate; | |
|
213 | ||
|
214 | ||
|
215 | ---------------------------------------------------------------------- | |
|
216 | --- Memory controllers ---------------------------------------------- | |
|
217 | ---------------------------------------------------------------------- | |
|
218 | ||
|
219 | ||
|
220 | sdc : sdctrl16 generic map (hindex => 3, haddr => 16#400#, hmask => 16#FE0#, -- hmask => 16#C00#, | |
|
221 | ioaddr => 1, fast => 0, pwron => 0, invclk => 0, | |
|
222 | sdbits => 16, pageburst => 2) | |
|
223 | port map (rstn, clkm, ahbsi, ahbso(3), sdi, sdo); | |
|
224 | sa_pad : outpadv generic map (width => 13, tech => padtech) | |
|
225 | port map (dram_addr, sdo.address(14 downto 2)); | |
|
226 | ba0_pad : outpad generic map (tech => padtech) | |
|
227 | port map (dram_ba_0, sdo.address(15)); | |
|
228 | ba1_pad : outpad generic map (tech => padtech) | |
|
229 | port map (dram_ba_1, sdo.address(16)); | |
|
230 | sd_pad : iopadvv generic map (width => 16, tech => padtech) | |
|
231 | port map (dram_dq(15 downto 0), sdo.data(15 downto 0), sdo.vbdrive(15 downto 0), sdi.data(15 downto 0)); | |
|
232 | sdcke_pad : outpad generic map (tech => padtech) | |
|
233 | port map (dram_cke, sdo.sdcke(0)); | |
|
234 | sdwen_pad : outpad generic map (tech => padtech) | |
|
235 | port map (dram_we_n, sdo.sdwen); | |
|
236 | sdcsn_pad : outpad generic map (tech => padtech) | |
|
237 | port map (dram_cs_n, sdo.sdcsn(0)); | |
|
238 | sdras_pad : outpad generic map (tech => padtech) | |
|
239 | port map (dram_ras_n, sdo.rasn); | |
|
240 | sdcas_pad : outpad generic map (tech => padtech) | |
|
241 | port map (dram_cas_n, sdo.casn); | |
|
242 | sdldqm_pad : outpad generic map (tech => padtech) | |
|
243 | port map (dram_ldqm, sdo.dqm(0) ); | |
|
244 | sdudqm_pad : outpad generic map (tech => padtech) | |
|
245 | port map (dram_udqm, sdo.dqm(1)); | |
|
246 | dram_clk_pad : outpad generic map (tech => padtech) | |
|
247 | port map (dram_clk, clkm_inv); | |
|
248 | ||
|
249 | ---------------------------------------------------------------------- | |
|
250 | --- APB Bridge and various periherals ------------------------------- | |
|
251 | ---------------------------------------------------------------------- | |
|
252 | ||
|
253 | apb0 : apbctrl -- AHB/APB bridge | |
|
254 | generic map (hindex => 1, haddr => CFG_APBADDR) | |
|
255 | port map (rstn, clkm, ahbsi, ahbso(1), apbi, apbo ); | |
|
256 | ||
|
257 | ---------------------------------------------------------------------------------------- | |
|
258 | ||
|
259 | irqctrl : if CFG_IRQ3_ENABLE /= 0 generate | |
|
260 | irqctrl0 : irqmp -- interrupt controller | |
|
261 | generic map (pindex => 2, paddr => 2, ncpu => CFG_NCPU) | |
|
262 | port map (rstn, clkm, apbi, apbo(2), irqo, irqi); | |
|
263 | end generate; | |
|
264 | irq3 : if CFG_IRQ3_ENABLE = 0 generate | |
|
265 | x : for i in 0 to CFG_NCPU-1 generate irqi(i).irl <= "0000"; end generate; | |
|
266 | apbo(2) <= apb_none; | |
|
267 | end generate; | |
|
268 | ||
|
269 | --Timer unit, generates interrupts when a timer underflow. | |
|
270 | gpt : if CFG_GPT_ENABLE /= 0 generate | |
|
271 | timer0 : gptimer -- timer unit | |
|
272 | generic map (pindex => 3, paddr => 3, pirq => CFG_GPT_IRQ, | |
|
273 | sepirq => CFG_GPT_SEPIRQ, sbits => CFG_GPT_SW, ntimers => CFG_GPT_NTIM, | |
|
274 | nbits => CFG_GPT_TW) | |
|
275 | port map (rstn, clkm, apbi, apbo(3), gpti, open); | |
|
276 | gpti <= gpti_dhalt_drive(dsuo.tstop); | |
|
277 | end generate; | |
|
278 | notim : if CFG_GPT_ENABLE = 0 generate apbo(3) <= apb_none; end generate; | |
|
279 | ||
|
280 | gpio0 : if CFG_GRGPIO_ENABLE /= 0 generate -- GR GPIO0 unit | |
|
281 | grgpio0: grgpio | |
|
282 | generic map( pindex => 9, paddr => 9, imask => CFG_GRGPIO_IMASK, nbits => 8) | |
|
283 | port map( rstn, clkm, apbi, apbo(9), gpioi_0, gpioo_0); | |
|
284 | pio_pads : for i in 0 to 7 generate | |
|
285 | pio_pad : iopad generic map (tech => padtech) | |
|
286 | port map (LEDS(i), gpioo_0.dout(i), gpioo_0.oen(i), gpioi_0.din(i)); | |
|
287 | end generate; | |
|
288 | end generate; | |
|
289 | nogpio0: if CFG_GRGPIO_ENABLE = 0 generate apbo(9) <= apb_none; | |
|
290 | LEDS(5 downto 0) <= FTDI_D_in(5 downto 0); | |
|
291 | LEDS(7 downto 6) <= FTDI_RXF & FTDI_TXE; | |
|
292 | ||
|
293 | end generate; | |
|
294 | ||
|
295 | ahb_ftdi0: if CFG_AHB_FTDI /=0 generate | |
|
296 | ftdi_dcom: ahb_ftdi_fifo | |
|
297 | generic map (oepol => 0 , hindex => CFG_NCPU+CFG_AHB_FTDI+CFG_AHB_UART+CFG_AHB_JTAG ) | |
|
298 | port map ( | |
|
299 | clk => clkm, | |
|
300 | rstn => rstn, | |
|
301 | ahbi => ahbmi, | |
|
302 | ahbo => ahbmo(CFG_NCPU+CFG_AHB_FTDI+CFG_AHB_UART+CFG_AHB_JTAG), | |
|
303 | ||
|
304 | FTDI_RXF => FTDI_RXF, | |
|
305 | FTDI_TXE => FTDI_TXE, | |
|
306 | FTDI_SIWUA => FTDI_SIWUA, | |
|
307 | FTDI_WR => FTDI_WR, | |
|
308 | FTDI_RD => FTDI_RD, | |
|
309 | FTDI_D_in => FTDI_D_in, | |
|
310 | FTDI_D_out => FTDI_D_out, | |
|
311 | FTDI_D_drive => FTDI_drive | |
|
312 | ); | |
|
313 | end generate; | |
|
314 | ||
|
315 | ftdi_loopback0: if CFG_FTDI_LOOPBACK /=0 generate | |
|
316 | ftdi_loopback: ftdi_async_fifo_loopback | |
|
317 | generic map (oepol => 0 ) | |
|
318 | port map ( | |
|
319 | clk => clkm, | |
|
320 | rstn => rstn, | |
|
321 | ||
|
322 | FTDI_RXF => FTDI_RXF, | |
|
323 | FTDI_TXE => FTDI_TXE, | |
|
324 | FTDI_SIWUA => FTDI_SIWUA, | |
|
325 | FTDI_WR => FTDI_WR, | |
|
326 | FTDI_RD => FTDI_RD, | |
|
327 | FTDI_D_in => FTDI_D_in, | |
|
328 | FTDI_D_out => FTDI_D_out, | |
|
329 | FTDI_D_drive => FTDI_drive | |
|
330 | ); | |
|
331 | end generate; | |
|
332 | ||
|
333 | ||
|
334 | fifo_pad : iopadv generic map (width => 8, tech => padtech) | |
|
335 | port map (FTDI_D(7 downto 0), FTDI_D_out(7 downto 0), FTDI_drive, FTDI_D_in(7 downto 0)); | |
|
336 | ||
|
337 | ||
|
338 | ||
|
339 | end rtl; | |
|
340 |
This diff has been collapsed as it changes many lines, (1550 lines changed) Show them Hide them | |||
@@ -0,0 +1,1550 | |||
|
1 | ||
|
2 | --***************************************************************************** | |
|
3 | -- | |
|
4 | -- Micron Semiconductor Products, Inc. | |
|
5 | -- | |
|
6 | -- Copyright 1997, Micron Semiconductor Products, Inc. | |
|
7 | -- All rights reserved. | |
|
8 | -- | |
|
9 | --***************************************************************************** | |
|
10 | ||
|
11 | -- pragma translate_off | |
|
12 | ||
|
13 | library ieee; | |
|
14 | use ieee.std_logic_1164.ALL; | |
|
15 | use std.textio.all; | |
|
16 | ||
|
17 | PACKAGE mti_pkg IS | |
|
18 | ||
|
19 | FUNCTION To_StdLogic (s : BIT) RETURN STD_LOGIC; | |
|
20 | FUNCTION TO_INTEGER (input : STD_LOGIC) RETURN INTEGER; | |
|
21 | FUNCTION TO_INTEGER (input : BIT_VECTOR) RETURN INTEGER; | |
|
22 | FUNCTION TO_INTEGER (input : STD_LOGIC_VECTOR) RETURN INTEGER; | |
|
23 | PROCEDURE TO_BITVECTOR (VARIABLE input : IN INTEGER; VARIABLE output : OUT BIT_VECTOR); | |
|
24 | ||
|
25 | ||
|
26 | END mti_pkg; | |
|
27 | ||
|
28 | PACKAGE BODY mti_pkg IS | |
|
29 | ||
|
30 | -- Convert BIT to STD_LOGIC | |
|
31 | FUNCTION To_StdLogic (s : BIT) RETURN STD_LOGIC IS | |
|
32 | BEGIN | |
|
33 | CASE s IS | |
|
34 | WHEN '0' => RETURN ('0'); | |
|
35 | WHEN '1' => RETURN ('1'); | |
|
36 | WHEN OTHERS => RETURN ('0'); | |
|
37 | END CASE; | |
|
38 | END; | |
|
39 | ||
|
40 | -- Convert STD_LOGIC to INTEGER | |
|
41 | FUNCTION TO_INTEGER (input : STD_LOGIC) RETURN INTEGER IS | |
|
42 | VARIABLE result : INTEGER := 0; | |
|
43 | VARIABLE weight : INTEGER := 1; | |
|
44 | BEGIN | |
|
45 | IF input = '1' THEN | |
|
46 | result := weight; | |
|
47 | ELSE | |
|
48 | result := 0; -- if unknowns, default to logic 0 | |
|
49 | END IF; | |
|
50 | RETURN result; | |
|
51 | END TO_INTEGER; | |
|
52 | ||
|
53 | -- Convert BIT_VECTOR to INTEGER | |
|
54 | FUNCTION TO_INTEGER (input : BIT_VECTOR) RETURN INTEGER IS | |
|
55 | VARIABLE result : INTEGER := 0; | |
|
56 | VARIABLE weight : INTEGER := 1; | |
|
57 | BEGIN | |
|
58 | FOR i IN input'LOW TO input'HIGH LOOP | |
|
59 | IF input(i) = '1' THEN | |
|
60 | result := result + weight; | |
|
61 | ELSE | |
|
62 | result := result + 0; -- if unknowns, default to logic 0 | |
|
63 | END IF; | |
|
64 | weight := weight * 2; | |
|
65 | END LOOP; | |
|
66 | RETURN result; | |
|
67 | END TO_INTEGER; | |
|
68 | ||
|
69 | -- Convert STD_LOGIC_VECTOR to INTEGER | |
|
70 | FUNCTION TO_INTEGER (input : STD_LOGIC_VECTOR) RETURN INTEGER IS | |
|
71 | VARIABLE result : INTEGER := 0; | |
|
72 | VARIABLE weight : INTEGER := 1; | |
|
73 | BEGIN | |
|
74 | FOR i IN input'LOW TO input'HIGH LOOP | |
|
75 | IF input(i) = '1' THEN | |
|
76 | result := result + weight; | |
|
77 | ELSE | |
|
78 | result := result + 0; -- if unknowns, default to logic 0 | |
|
79 | END IF; | |
|
80 | weight := weight * 2; | |
|
81 | END LOOP; | |
|
82 | RETURN result; | |
|
83 | END TO_INTEGER; | |
|
84 | ||
|
85 | -- Conver INTEGER to BIT_VECTOR | |
|
86 | PROCEDURE TO_BITVECTOR (VARIABLE input : IN INTEGER; VARIABLE output : OUT BIT_VECTOR) IS | |
|
87 | VARIABLE work,offset,outputlen,j : INTEGER := 0; | |
|
88 | BEGIN | |
|
89 | --length of vector | |
|
90 | IF output'LENGTH > 32 THEN --' | |
|
91 | outputlen := 32; | |
|
92 | offset := output'LENGTH - 32; --' | |
|
93 | IF input >= 0 THEN | |
|
94 | FOR i IN offset-1 DOWNTO 0 LOOP | |
|
95 | output(output'HIGH - i) := '0'; --' | |
|
96 | END LOOP; | |
|
97 | ELSE | |
|
98 | FOR i IN offset-1 DOWNTO 0 LOOP | |
|
99 | output(output'HIGH - i) := '1'; --' | |
|
100 | END LOOP; | |
|
101 | END IF; | |
|
102 | ELSE | |
|
103 | outputlen := output'LENGTH; --' | |
|
104 | END IF; | |
|
105 | --positive value | |
|
106 | IF (input >= 0) THEN | |
|
107 | work := input; | |
|
108 | j := outputlen - 1; | |
|
109 | FOR i IN 1 to 32 LOOP | |
|
110 | IF j >= 0 then | |
|
111 | IF (work MOD 2) = 0 THEN | |
|
112 | output(output'HIGH-j-offset) := '0'; --' | |
|
113 | ELSE | |
|
114 | output(output'HIGH-j-offset) := '1'; --' | |
|
115 | END IF; | |
|
116 | END IF; | |
|
117 | work := work / 2; | |
|
118 | j := j - 1; | |
|
119 | END LOOP; | |
|
120 | IF outputlen = 32 THEN | |
|
121 | output(output'HIGH) := '0'; --' | |
|
122 | END IF; | |
|
123 | --negative value | |
|
124 | ELSE | |
|
125 | work := (-input) - 1; | |
|
126 | j := outputlen - 1; | |
|
127 | FOR i IN 1 TO 32 LOOP | |
|
128 | IF j>= 0 THEN | |
|
129 | IF (work MOD 2) = 0 THEN | |
|
130 | output(output'HIGH-j-offset) := '1'; --' | |
|
131 | ELSE | |
|
132 | output(output'HIGH-j-offset) := '0'; --' | |
|
133 | END IF; | |
|
134 | END IF; | |
|
135 | work := work / 2; | |
|
136 | j := j - 1; | |
|
137 | END LOOP; | |
|
138 | IF outputlen = 32 THEN | |
|
139 | output(output'HIGH) := '1'; --' | |
|
140 | END IF; | |
|
141 | END IF; | |
|
142 | END TO_BITVECTOR; | |
|
143 | ||
|
144 | END mti_pkg; | |
|
145 | ||
|
146 | ----------------------------------------------------------------------------------------- | |
|
147 | -- | |
|
148 | -- File Name: MT48LC16M16A2.VHD | |
|
149 | -- Version: 0.0g | |
|
150 | -- Date: June 29th, 2000 | |
|
151 | -- Model: Behavioral | |
|
152 | -- Simulator: Model Technology (PC version 5.3 PE) | |
|
153 | -- | |
|
154 | -- Dependencies: None | |
|
155 | -- | |
|
156 | -- Author: Son P. Huynh | |
|
157 | -- Email: sphuynh@micron.com | |
|
158 | -- Phone: (208) 368-3825 | |
|
159 | -- Company: Micron Technology, Inc. | |
|
160 | -- Part Number: MT48LC16M16A2 (4Mb x 16 x 4 Banks) | |
|
161 | -- | |
|
162 | -- Description: Micron 256Mb SDRAM | |
|
163 | -- | |
|
164 | -- Limitation: - Doesn't check for 4096-cycle refresh --' | |
|
165 | -- | |
|
166 | -- Note: - Set simulator resolution to "ps" accuracy | |
|
167 | -- | |
|
168 | -- Disclaimer: THESE DESIGNS ARE PROVIDED "AS IS" WITH NO WARRANTY | |
|
169 | -- WHATSOEVER AND MICRON SPECIFICALLY DISCLAIMS ANY | |
|
170 | -- IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR | |
|
171 | -- A PARTICULAR PURPOSE, OR AGAINST INFRINGEMENT. | |
|
172 | -- | |
|
173 | -- Copyright (c) 1998 Micron Semiconductor Products, Inc. | |
|
174 | -- All rights researved | |
|
175 | -- | |
|
176 | -- Rev Author Phone Date Changes | |
|
177 | -- ---- ---------------------------- ---------- ------------------------------------- | |
|
178 | -- 0.0g Son Huynh 208-368-3825 06/29/2000 Add Load/Dump memory array | |
|
179 | -- Micron Technology Inc. Modify tWR + tRAS timing check | |
|
180 | -- | |
|
181 | -- 0.0f Son Huynh 208-368-3825 07/08/1999 Fix tWR = 1 Clk + 7.5 ns (Auto) | |
|
182 | -- Micron Technology Inc. Fix tWR = 15 ns (Manual) | |
|
183 | -- Fix tRP (Autoprecharge to AutoRefresh) | |
|
184 | -- | |
|
185 | -- 0.0c Son P. Huynh 208-368-3825 04/08/1999 Fix tWR + tRP in Write with AP | |
|
186 | -- Micron Technology Inc. Fix tRC check in Load Mode Register | |
|
187 | -- | |
|
188 | -- 0.0b Son P. Huynh 208-368-3825 01/06/1998 Derive from 64Mb SDRAM model | |
|
189 | -- Micron Technology Inc. | |
|
190 | -- | |
|
191 | ----------------------------------------------------------------------------------------- | |
|
192 | ||
|
193 | LIBRARY STD; | |
|
194 | USE STD.TEXTIO.ALL; | |
|
195 | LIBRARY IEEE; | |
|
196 | USE IEEE.STD_LOGIC_1164.ALL; | |
|
197 | LIBRARY WORK; | |
|
198 | USE WORK.MTI_PKG.ALL; | |
|
199 | use std.textio.all; | |
|
200 | ||
|
201 | library grlib; | |
|
202 | use grlib.stdlib.all; | |
|
203 | use grlib.stdio.all; | |
|
204 | ||
|
205 | ENTITY mt48lc16m16a2 IS | |
|
206 | GENERIC ( | |
|
207 | -- Timing Parameters for -75 (PC133) and CAS Latency = 2 | |
|
208 | tAC : TIME := 6.0 ns; | |
|
209 | tHZ : TIME := 7.0 ns; | |
|
210 | tOH : TIME := 2.7 ns; | |
|
211 | tMRD : INTEGER := 2; -- 2 Clk Cycles | |
|
212 | tRAS : TIME := 44.0 ns; | |
|
213 | tRC : TIME := 66.0 ns; | |
|
214 | tRCD : TIME := 20.0 ns; | |
|
215 | tRP : TIME := 20.0 ns; | |
|
216 | tRRD : TIME := 15.0 ns; | |
|
217 | tWRa : TIME := 7.5 ns; -- A2 Version - Auto precharge mode only (1 Clk + 7.5 ns) | |
|
218 | tWRp : TIME := 15.0 ns; -- A2 Version - Precharge mode only (15 ns) | |
|
219 | ||
|
220 | tAH : TIME := 0.8 ns; | |
|
221 | tAS : TIME := 1.5 ns; | |
|
222 | tCH : TIME := 2.5 ns; | |
|
223 | tCL : TIME := 2.5 ns; | |
|
224 | tCK : TIME := 10.0 ns; | |
|
225 | tDH : TIME := 0.8 ns; | |
|
226 | tDS : TIME := 1.5 ns; | |
|
227 | tCKH : TIME := 0.8 ns; | |
|
228 | tCKS : TIME := 1.5 ns; | |
|
229 | tCMH : TIME := 0.8 ns; | |
|
230 | tCMS : TIME := 1.5 ns; | |
|
231 | ||
|
232 | addr_bits : INTEGER := 13; | |
|
233 | data_bits : INTEGER := 16; | |
|
234 | col_bits : INTEGER := 9; | |
|
235 | index : INTEGER := 0; | |
|
236 | fname : string := "ram.srec" -- File to read from | |
|
237 | ); | |
|
238 | PORT ( | |
|
239 | Dq : INOUT STD_LOGIC_VECTOR (data_bits - 1 DOWNTO 0) := (OTHERS => 'Z'); | |
|
240 | Addr : IN STD_LOGIC_VECTOR (addr_bits - 1 DOWNTO 0) := (OTHERS => '0'); | |
|
241 | Ba : IN STD_LOGIC_VECTOR := "00"; | |
|
242 | Clk : IN STD_LOGIC := '0'; | |
|
243 | Cke : IN STD_LOGIC := '1'; | |
|
244 | Cs_n : IN STD_LOGIC := '1'; | |
|
245 | Ras_n : IN STD_LOGIC := '1'; | |
|
246 | Cas_n : IN STD_LOGIC := '1'; | |
|
247 | We_n : IN STD_LOGIC := '1'; | |
|
248 | Dqm : IN STD_LOGIC_VECTOR (1 DOWNTO 0) := "00" | |
|
249 | ); | |
|
250 | END mt48lc16m16a2; | |
|
251 | ||
|
252 | ARCHITECTURE behave OF mt48lc16m16a2 IS | |
|
253 | TYPE State IS (ACT, A_REF, BST, LMR, NOP, PRECH, READ, READ_A, WRITE, WRITE_A, LOAD_FILE, DUMP_FILE); | |
|
254 | TYPE Array4xI IS ARRAY (3 DOWNTO 0) OF INTEGER; | |
|
255 | TYPE Array4xT IS ARRAY (3 DOWNTO 0) OF TIME; | |
|
256 | TYPE Array4xB IS ARRAY (3 DOWNTO 0) OF BIT; | |
|
257 | TYPE Array4x2BV IS ARRAY (3 DOWNTO 0) OF BIT_VECTOR (1 DOWNTO 0); | |
|
258 | TYPE Array4xCBV IS ARRAY (4 DOWNTO 0) OF BIT_VECTOR (Col_bits - 1 DOWNTO 0); | |
|
259 | TYPE Array_state IS ARRAY (4 DOWNTO 0) OF State; | |
|
260 | SIGNAL Operation : State := NOP; | |
|
261 | SIGNAL Mode_reg : BIT_VECTOR (addr_bits - 1 DOWNTO 0) := (OTHERS => '0'); | |
|
262 | SIGNAL Active_enable, Aref_enable, Burst_term : BIT := '0'; | |
|
263 | SIGNAL Mode_reg_enable, Prech_enable, Read_enable, Write_enable : BIT := '0'; | |
|
264 | SIGNAL Burst_length_1, Burst_length_2, Burst_length_4, Burst_length_8 : BIT := '0'; | |
|
265 | SIGNAL Cas_latency_2, Cas_latency_3 : BIT := '0'; | |
|
266 | SIGNAL Ras_in, Cas_in, We_in : BIT := '0'; | |
|
267 | SIGNAL Write_burst_mode : BIT := '0'; | |
|
268 | SIGNAL RAS_clk, Sys_clk, CkeZ : BIT := '0'; | |
|
269 | ||
|
270 | -- Checking internal wires | |
|
271 | SIGNAL Pre_chk : BIT_VECTOR (3 DOWNTO 0) := "0000"; | |
|
272 | SIGNAL Act_chk : BIT_VECTOR (3 DOWNTO 0) := "0000"; | |
|
273 | SIGNAL Dq_in_chk, Dq_out_chk : BIT := '0'; | |
|
274 | SIGNAL Bank_chk : BIT_VECTOR (1 DOWNTO 0) := "00"; | |
|
275 | SIGNAL Row_chk : BIT_VECTOR (addr_bits - 1 DOWNTO 0) := (OTHERS => '0'); | |
|
276 | SIGNAL Col_chk : BIT_VECTOR (col_bits - 1 DOWNTO 0) := (OTHERS => '0'); | |
|
277 | ||
|
278 | BEGIN | |
|
279 | -- CS# Decode | |
|
280 | WITH Cs_n SELECT | |
|
281 | Cas_in <= TO_BIT (Cas_n, '1') WHEN '0', | |
|
282 | '1' WHEN '1', | |
|
283 | '1' WHEN OTHERS; | |
|
284 | WITH Cs_n SELECT | |
|
285 | Ras_in <= TO_BIT (Ras_n, '1') WHEN '0', | |
|
286 | '1' WHEN '1', | |
|
287 | '1' WHEN OTHERS; | |
|
288 | WITH Cs_n SELECT | |
|
289 | We_in <= TO_BIT (We_n, '1') WHEN '0', | |
|
290 | '1' WHEN '1', | |
|
291 | '1' WHEN OTHERS; | |
|
292 | ||
|
293 | -- Commands Decode | |
|
294 | Active_enable <= NOT(Ras_in) AND Cas_in AND We_in; | |
|
295 | Aref_enable <= NOT(Ras_in) AND NOT(Cas_in) AND We_in; | |
|
296 | Burst_term <= Ras_in AND Cas_in AND NOT(We_in); | |
|
297 | Mode_reg_enable <= NOT(Ras_in) AND NOT(Cas_in) AND NOT(We_in); | |
|
298 | Prech_enable <= NOT(Ras_in) AND Cas_in AND NOT(We_in); | |
|
299 | Read_enable <= Ras_in AND NOT(Cas_in) AND We_in; | |
|
300 | Write_enable <= Ras_in AND NOT(Cas_in) AND NOT(We_in); | |
|
301 | ||
|
302 | -- Burst Length Decode | |
|
303 | Burst_length_1 <= NOT(Mode_reg(2)) AND NOT(Mode_reg(1)) AND NOT(Mode_reg(0)); | |
|
304 | Burst_length_2 <= NOT(Mode_reg(2)) AND NOT(Mode_reg(1)) AND Mode_reg(0); | |
|
305 | Burst_length_4 <= NOT(Mode_reg(2)) AND Mode_reg(1) AND NOT(Mode_reg(0)); | |
|
306 | Burst_length_8 <= NOT(Mode_reg(2)) AND Mode_reg(1) AND Mode_reg(0); | |
|
307 | ||
|
308 | -- CAS Latency Decode | |
|
309 | Cas_latency_2 <= NOT(Mode_reg(6)) AND Mode_reg(5) AND NOT(Mode_reg(4)); | |
|
310 | Cas_latency_3 <= NOT(Mode_reg(6)) AND Mode_reg(5) AND Mode_reg(4); | |
|
311 | ||
|
312 | -- Write Burst Mode | |
|
313 | Write_burst_mode <= Mode_reg(9); | |
|
314 | ||
|
315 | -- RAS Clock for checking tWR and tRP | |
|
316 | PROCESS | |
|
317 | variable Clk0, Clk1 : integer := 0; | |
|
318 | begin | |
|
319 | RAS_clk <= '1'; | |
|
320 | wait for 0.5 ns; | |
|
321 | RAS_clk <= '0'; | |
|
322 | wait for 0.5 ns; | |
|
323 | if Clk0 > 100 or Clk1 > 100 then | |
|
324 | wait; | |
|
325 | else | |
|
326 | if Clk = '1' and Cke = '1' then | |
|
327 | Clk0 := 0; | |
|
328 | Clk1 := Clk1 + 1; | |
|
329 | elsif Clk = '0' and Cke = '1' then | |
|
330 | Clk0 := Clk0 + 1; | |
|
331 | Clk1 := 0; | |
|
332 | end if; | |
|
333 | end if; | |
|
334 | END PROCESS; | |
|
335 | ||
|
336 | -- System Clock | |
|
337 | int_clk : PROCESS (Clk) | |
|
338 | begin | |
|
339 | IF Clk'LAST_VALUE = '0' AND Clk = '1' THEN --' | |
|
340 | CkeZ <= TO_BIT(Cke, '1'); | |
|
341 | END IF; | |
|
342 | Sys_clk <= CkeZ AND TO_BIT(Clk, '0'); | |
|
343 | END PROCESS; | |
|
344 | ||
|
345 | state_register : PROCESS | |
|
346 | -- NOTE: The extra bits in RAM_TYPE is for checking memory access. A logic 1 means | |
|
347 | -- the location is in use. This will be checked when doing memory DUMP. | |
|
348 | TYPE ram_type IS ARRAY (2**col_bits - 1 DOWNTO 0) OF BIT_VECTOR (data_bits DOWNTO 0); | |
|
349 | TYPE ram_pntr IS ACCESS ram_type; | |
|
350 | TYPE ram_stor IS ARRAY (2**addr_bits - 1 DOWNTO 0) OF ram_pntr; | |
|
351 | VARIABLE Bank0 : ram_stor; | |
|
352 | VARIABLE Bank1 : ram_stor; | |
|
353 | VARIABLE Bank2 : ram_stor; | |
|
354 | VARIABLE Bank3 : ram_stor; | |
|
355 | VARIABLE Row_index, Col_index : INTEGER := 0; | |
|
356 | VARIABLE Dq_temp : BIT_VECTOR (data_bits DOWNTO 0) := (OTHERS => '0'); | |
|
357 | ||
|
358 | VARIABLE Col_addr : Array4xCBV; | |
|
359 | VARIABLE Bank_addr : Array4x2BV; | |
|
360 | VARIABLE Dqm_reg0, Dqm_reg1 : BIT_VECTOR (1 DOWNTO 0) := "00"; | |
|
361 | ||
|
362 | VARIABLE Bank, Previous_bank : BIT_VECTOR (1 DOWNTO 0) := "00"; | |
|
363 | VARIABLE B0_row_addr, B1_row_addr, B2_row_addr, B3_row_addr : BIT_VECTOR (addr_bits - 1 DOWNTO 0) := (OTHERS => '0'); | |
|
364 | VARIABLE Col_brst : BIT_VECTOR (col_bits - 1 DOWNTO 0) := (OTHERS => '0'); | |
|
365 | VARIABLE Row : BIT_VECTOR (addr_bits - 1 DOWNTO 0) := (OTHERS => '0'); | |
|
366 | VARIABLE Col : BIT_VECTOR (col_bits - 1 DOWNTO 0) := (OTHERS => '0'); | |
|
367 | VARIABLE Burst_counter : INTEGER := 0; | |
|
368 | ||
|
369 | VARIABLE Command : Array_state; | |
|
370 | VARIABLE Bank_precharge : Array4x2BV; | |
|
371 | VARIABLE A10_precharge : Array4xB := ('0' & '0' & '0' & '0'); | |
|
372 | VARIABLE Auto_precharge : Array4xB := ('0' & '0' & '0' & '0'); | |
|
373 | VARIABLE Read_precharge : Array4xB := ('0' & '0' & '0' & '0'); | |
|
374 | VARIABLE Write_precharge : Array4xB := ('0' & '0' & '0' & '0'); | |
|
375 | VARIABLE RW_interrupt_read : Array4xB := ('0' & '0' & '0' & '0'); | |
|
376 | VARIABLE RW_interrupt_write : Array4xB := ('0' & '0' & '0' & '0'); | |
|
377 | VARIABLE RW_interrupt_bank : BIT_VECTOR (1 DOWNTO 0) := "00"; | |
|
378 | VARIABLE Count_time : Array4xT := (0 ns & 0 ns & 0 ns & 0 ns); | |
|
379 | VARIABLE Count_precharge : Array4xI := (0 & 0 & 0 & 0); | |
|
380 | ||
|
381 | VARIABLE Data_in_enable, Data_out_enable : BIT := '0'; | |
|
382 | VARIABLE Pc_b0, Pc_b1, Pc_b2, Pc_b3 : BIT := '0'; | |
|
383 | VARIABLE Act_b0, Act_b1, Act_b2, Act_b3 : BIT := '0'; | |
|
384 | ||
|
385 | -- Timing Check | |
|
386 | VARIABLE MRD_chk : INTEGER := 0; | |
|
387 | VARIABLE WR_counter : Array4xI := (0 & 0 & 0 & 0); | |
|
388 | VARIABLE WR_time : Array4xT := (0 ns & 0 ns & 0 ns & 0 ns); | |
|
389 | VARIABLE WR_chkp : Array4xT := (0 ns & 0 ns & 0 ns & 0 ns); | |
|
390 | VARIABLE RC_chk, RRD_chk : TIME := 0 ns; | |
|
391 | VARIABLE RAS_chk0, RAS_chk1, RAS_chk2, RAS_chk3 : TIME := 0 ns; | |
|
392 | VARIABLE RCD_chk0, RCD_chk1, RCD_chk2, RCD_chk3 : TIME := 0 ns; | |
|
393 | VARIABLE RP_chk0, RP_chk1, RP_chk2, RP_chk3 : TIME := 0 ns; | |
|
394 | ||
|
395 | -- Load and Dumb variables | |
|
396 | FILE file_load : TEXT open read_mode is fname; -- Data load | |
|
397 | FILE file_dump : TEXT open write_mode is "dumpdata.txt"; -- Data dump | |
|
398 | VARIABLE bank_load : bit_vector ( 1 DOWNTO 0); | |
|
399 | VARIABLE rows_load : BIT_VECTOR (12 DOWNTO 0); | |
|
400 | VARIABLE cols_load : BIT_VECTOR ( 8 DOWNTO 0); | |
|
401 | VARIABLE data_load : BIT_VECTOR (15 DOWNTO 0); | |
|
402 | VARIABLE i, j : INTEGER; | |
|
403 | VARIABLE good_load : BOOLEAN; | |
|
404 | VARIABLE l : LINE; | |
|
405 | variable load : std_logic := '1'; | |
|
406 | variable dump : std_logic := '0'; | |
|
407 | variable ch : character; | |
|
408 | variable rectype : bit_vector(3 downto 0); | |
|
409 | variable recaddr : bit_vector(31 downto 0); | |
|
410 | variable reclen : bit_vector(7 downto 0); | |
|
411 | variable recdata : bit_vector(0 to 16*8-1); | |
|
412 | ||
|
413 | -- Initialize empty rows | |
|
414 | PROCEDURE Init_mem (Bank : bit_vector (1 DOWNTO 0); Row_index : INTEGER) IS | |
|
415 | VARIABLE i, j : INTEGER := 0; | |
|
416 | BEGIN | |
|
417 | IF Bank = "00" THEN | |
|
418 | IF Bank0 (Row_index) = NULL THEN -- Check to see if row empty | |
|
419 | Bank0 (Row_index) := NEW ram_type; -- Open new row for access | |
|
420 | FOR i IN (2**col_bits - 1) DOWNTO 0 LOOP -- Filled row with zeros | |
|
421 | FOR j IN (data_bits) DOWNTO 0 LOOP | |
|
422 | Bank0 (Row_index) (i) (j) := '0'; | |
|
423 | END LOOP; | |
|
424 | END LOOP; | |
|
425 | END IF; | |
|
426 | ELSIF Bank = "01" THEN | |
|
427 | IF Bank1 (Row_index) = NULL THEN | |
|
428 | Bank1 (Row_index) := NEW ram_type; | |
|
429 | FOR i IN (2**col_bits - 1) DOWNTO 0 LOOP | |
|
430 | FOR j IN (data_bits) DOWNTO 0 LOOP | |
|
431 | Bank1 (Row_index) (i) (j) := '0'; | |
|
432 | END LOOP; | |
|
433 | END LOOP; | |
|
434 | END IF; | |
|
435 | ELSIF Bank = "10" THEN | |
|
436 | IF Bank2 (Row_index) = NULL THEN | |
|
437 | Bank2 (Row_index) := NEW ram_type; | |
|
438 | FOR i IN (2**col_bits - 1) DOWNTO 0 LOOP | |
|
439 | FOR j IN (data_bits) DOWNTO 0 LOOP | |
|
440 | Bank2 (Row_index) (i) (j) := '0'; | |
|
441 | END LOOP; | |
|
442 | END LOOP; | |
|
443 | END IF; | |
|
444 | ELSIF Bank = "11" THEN | |
|
445 | IF Bank3 (Row_index) = NULL THEN | |
|
446 | Bank3 (Row_index) := NEW ram_type; | |
|
447 | FOR i IN (2**col_bits - 1) DOWNTO 0 LOOP | |
|
448 | FOR j IN (data_bits) DOWNTO 0 LOOP | |
|
449 | Bank3 (Row_index) (i) (j) := '0'; | |
|
450 | END LOOP; | |
|
451 | END LOOP; | |
|
452 | END IF; | |
|
453 | END IF; | |
|
454 | END; | |
|
455 | ||
|
456 | -- Burst Counter | |
|
457 | PROCEDURE Burst_decode IS | |
|
458 | VARIABLE Col_int : INTEGER := 0; | |
|
459 | VARIABLE Col_vec, Col_temp : BIT_VECTOR (col_bits - 1 DOWNTO 0) := (OTHERS => '0'); | |
|
460 | BEGIN | |
|
461 | -- Advance Burst Counter | |
|
462 | Burst_counter := Burst_counter + 1; | |
|
463 | ||
|
464 | -- Burst Type | |
|
465 | IF Mode_reg (3) = '0' THEN | |
|
466 | Col_int := TO_INTEGER(Col); | |
|
467 | Col_int := Col_int + 1; | |
|
468 | TO_BITVECTOR (Col_int, Col_temp); | |
|
469 | ELSIF Mode_reg (3) = '1' THEN | |
|
470 | TO_BITVECTOR (Burst_counter, Col_vec); | |
|
471 | Col_temp (2) := Col_vec (2) XOR Col_brst (2); | |
|
472 | Col_temp (1) := Col_vec (1) XOR Col_brst (1); | |
|
473 | Col_temp (0) := Col_vec (0) XOR Col_brst (0); | |
|
474 | END IF; | |
|
475 | ||
|
476 | -- Burst Length | |
|
477 | IF Burst_length_2 = '1' THEN | |
|
478 | Col (0) := Col_temp (0); | |
|
479 | ELSIF Burst_length_4 = '1' THEN | |
|
480 | Col (1 DOWNTO 0) := Col_temp (1 DOWNTO 0); | |
|
481 | ELSIF Burst_length_8 = '1' THEN | |
|
482 | Col (2 DOWNTO 0) := Col_temp (2 DOWNTO 0); | |
|
483 | ELSE | |
|
484 | Col := Col_temp; | |
|
485 | END IF; | |
|
486 | ||
|
487 | -- Burst Read Single Write | |
|
488 | IF Write_burst_mode = '1' AND Data_in_enable = '1' THEN | |
|
489 | Data_in_enable := '0'; | |
|
490 | END IF; | |
|
491 | ||
|
492 | -- Data counter | |
|
493 | IF Burst_length_1 = '1' THEN | |
|
494 | IF Burst_counter >= 1 THEN | |
|
495 | IF Data_in_enable = '1' THEN | |
|
496 | Data_in_enable := '0'; | |
|
497 | ELSIF Data_out_enable = '1' THEN | |
|
498 | Data_out_enable := '0'; | |
|
499 | END IF; | |
|
500 | END IF; | |
|
501 | ELSIF Burst_length_2 = '1' THEN | |
|
502 | IF Burst_counter >= 2 THEN | |
|
503 | IF Data_in_enable = '1' THEN | |
|
504 | Data_in_enable := '0'; | |
|
505 | ELSIF Data_out_enable = '1' THEN | |
|
506 | Data_out_enable := '0'; | |
|
507 | END IF; | |
|
508 | END IF; | |
|
509 | ELSIF Burst_length_4 = '1' THEN | |
|
510 | IF Burst_counter >= 4 THEN | |
|
511 | IF Data_in_enable = '1' THEN | |
|
512 | Data_in_enable := '0'; | |
|
513 | ELSIF Data_out_enable = '1' THEN | |
|
514 | Data_out_enable := '0'; | |
|
515 | END IF; | |
|
516 | END IF; | |
|
517 | ELSIF Burst_length_8 = '1' THEN | |
|
518 | IF Burst_counter >= 8 THEN | |
|
519 | IF Data_in_enable = '1' THEN | |
|
520 | Data_in_enable := '0'; | |
|
521 | ELSIF Data_out_enable = '1' THEN | |
|
522 | Data_out_enable := '0'; | |
|
523 | END IF; | |
|
524 | END IF; | |
|
525 | END IF; | |
|
526 | END; | |
|
527 | ||
|
528 | BEGIN | |
|
529 | WAIT ON Sys_clk, RAS_clk; | |
|
530 | IF Sys_clk'event AND Sys_clk = '1' AND Load = '0' AND Dump = '0' THEN --' | |
|
531 | -- Internal Command Pipeline | |
|
532 | Command(0) := Command(1); | |
|
533 | Command(1) := Command(2); | |
|
534 | Command(2) := Command(3); | |
|
535 | Command(3) := NOP; | |
|
536 | ||
|
537 | Col_addr(0) := Col_addr(1); | |
|
538 | Col_addr(1) := Col_addr(2); | |
|
539 | Col_addr(2) := Col_addr(3); | |
|
540 | Col_addr(3) := (OTHERS => '0'); | |
|
541 | ||
|
542 | Bank_addr(0) := Bank_addr(1); | |
|
543 | Bank_addr(1) := Bank_addr(2); | |
|
544 | Bank_addr(2) := Bank_addr(3); | |
|
545 | Bank_addr(3) := "00"; | |
|
546 | ||
|
547 | Bank_precharge(0) := Bank_precharge(1); | |
|
548 | Bank_precharge(1) := Bank_precharge(2); | |
|
549 | Bank_precharge(2) := Bank_precharge(3); | |
|
550 | Bank_precharge(3) := "00"; | |
|
551 | ||
|
552 | A10_precharge(0) := A10_precharge(1); | |
|
553 | A10_precharge(1) := A10_precharge(2); | |
|
554 | A10_precharge(2) := A10_precharge(3); | |
|
555 | A10_precharge(3) := '0'; | |
|
556 | ||
|
557 | -- Operation Decode (Optional for showing current command on posedge clock / debug feature) | |
|
558 | IF Active_enable = '1' THEN | |
|
559 | Operation <= ACT; | |
|
560 | ELSIF Aref_enable = '1' THEN | |
|
561 | Operation <= A_REF; | |
|
562 | ELSIF Burst_term = '1' THEN | |
|
563 | Operation <= BST; | |
|
564 | ELSIF Mode_reg_enable = '1' THEN | |
|
565 | Operation <= LMR; | |
|
566 | ELSIF Prech_enable = '1' THEN | |
|
567 | Operation <= PRECH; | |
|
568 | ELSIF Read_enable = '1' THEN | |
|
569 | IF Addr(10) = '0' THEN | |
|
570 | Operation <= READ; | |
|
571 | ELSE | |
|
572 | Operation <= READ_A; | |
|
573 | END IF; | |
|
574 | ELSIF Write_enable = '1' THEN | |
|
575 | IF Addr(10) = '0' THEN | |
|
576 | Operation <= WRITE; | |
|
577 | ELSE | |
|
578 | Operation <= WRITE_A; | |
|
579 | END IF; | |
|
580 | ELSE | |
|
581 | Operation <= NOP; | |
|
582 | END IF; | |
|
583 | ||
|
584 | -- Dqm pipeline for Read | |
|
585 | Dqm_reg0 := Dqm_reg1; | |
|
586 | Dqm_reg1 := TO_BITVECTOR(Dqm); | |
|
587 | ||
|
588 | -- Read or Write with Auto Precharge Counter | |
|
589 | IF Auto_precharge (0) = '1' THEN | |
|
590 | Count_precharge (0) := Count_precharge (0) + 1; | |
|
591 | END IF; | |
|
592 | IF Auto_precharge (1) = '1' THEN | |
|
593 | Count_precharge (1) := Count_precharge (1) + 1; | |
|
594 | END IF; | |
|
595 | IF Auto_precharge (2) = '1' THEN | |
|
596 | Count_precharge (2) := Count_precharge (2) + 1; | |
|
597 | END IF; | |
|
598 | IF Auto_precharge (3) = '1' THEN | |
|
599 | Count_precharge (3) := Count_precharge (3) + 1; | |
|
600 | END IF; | |
|
601 | ||
|
602 | -- Auto Precharge Timer for tWR | |
|
603 | if (Burst_length_1 = '1' OR Write_burst_mode = '1') then | |
|
604 | if (Count_precharge(0) = 1) then | |
|
605 | Count_time(0) := NOW; | |
|
606 | end if; | |
|
607 | if (Count_precharge(1) = 1) then | |
|
608 | Count_time(1) := NOW; | |
|
609 | end if; | |
|
610 | if (Count_precharge(2) = 1) then | |
|
611 | Count_time(2) := NOW; | |
|
612 | end if; | |
|
613 | if (Count_precharge(3) = 1) then | |
|
614 | Count_time(3) := NOW; | |
|
615 | end if; | |
|
616 | elsif (Burst_length_2 = '1') then | |
|
617 | if (Count_precharge(0) = 2) then | |
|
618 | Count_time(0) := NOW; | |
|
619 | end if; | |
|
620 | if (Count_precharge(1) = 2) then | |
|
621 | Count_time(1) := NOW; | |
|
622 | end if; | |
|
623 | if (Count_precharge(2) = 2) then | |
|
624 | Count_time(2) := NOW; | |
|
625 | end if; | |
|
626 | if (Count_precharge(3) = 2) then | |
|
627 | Count_time(3) := NOW; | |
|
628 | end if; | |
|
629 | elsif (Burst_length_4 = '1') then | |
|
630 | if (Count_precharge(0) = 4) then | |
|
631 | Count_time(0) := NOW; | |
|
632 | end if; | |
|
633 | if (Count_precharge(1) = 4) then | |
|
634 | Count_time(1) := NOW; | |
|
635 | end if; | |
|
636 | if (Count_precharge(2) = 4) then | |
|
637 | Count_time(2) := NOW; | |
|
638 | end if; | |
|
639 | if (Count_precharge(3) = 4) then | |
|
640 | Count_time(3) := NOW; | |
|
641 | end if; | |
|
642 | elsif (Burst_length_8 = '1') then | |
|
643 | if (Count_precharge(0) = 8) then | |
|
644 | Count_time(0) := NOW; | |
|
645 | end if; | |
|
646 | if (Count_precharge(1) = 8) then | |
|
647 | Count_time(1) := NOW; | |
|
648 | end if; | |
|
649 | if (Count_precharge(2) = 8) then | |
|
650 | Count_time(2) := NOW; | |
|
651 | end if; | |
|
652 | if (Count_precharge(3) = 8) then | |
|
653 | Count_time(3) := NOW; | |
|
654 | end if; | |
|
655 | end if; | |
|
656 | ||
|
657 | -- tMRD Counter | |
|
658 | MRD_chk := MRD_chk + 1; | |
|
659 | ||
|
660 | -- tWR Counter | |
|
661 | WR_counter(0) := WR_counter(0) + 1; | |
|
662 | WR_counter(1) := WR_counter(1) + 1; | |
|
663 | WR_counter(2) := WR_counter(2) + 1; | |
|
664 | WR_counter(3) := WR_counter(3) + 1; | |
|
665 | ||
|
666 | ||
|
667 | -- Auto Refresh | |
|
668 | IF Aref_enable = '1' THEN | |
|
669 | -- Auto Refresh to Auto Refresh | |
|
670 | ASSERT (NOW - RC_chk >= tRC) | |
|
671 | REPORT "tRC violation during Auto Refresh" | |
|
672 | SEVERITY WARNING; | |
|
673 | -- Precharge to Auto Refresh | |
|
674 | ASSERT (NOW - RP_chk0 >= tRP OR NOW - RP_chk1 >= tRP OR NOW - RP_chk2 >= tRP OR NOW - RP_chk3 >= tRP) | |
|
675 | REPORT "tRP violation during Auto Refresh" | |
|
676 | SEVERITY WARNING; | |
|
677 | -- All banks must be idle before refresh | |
|
678 | IF (Pc_b3 ='0' OR Pc_b2 = '0' OR Pc_b1 ='0' OR Pc_b0 = '0') THEN | |
|
679 | ASSERT (FALSE) | |
|
680 | REPORT "All banks must be Precharge before Auto Refresh" | |
|
681 | SEVERITY WARNING; | |
|
682 | END IF; | |
|
683 | -- Record current tRC time | |
|
684 | RC_chk := NOW; | |
|
685 | END IF; | |
|
686 | ||
|
687 | -- Load Mode Register | |
|
688 | IF Mode_reg_enable = '1' THEN | |
|
689 | Mode_reg <= TO_BITVECTOR (Addr); | |
|
690 | IF (Pc_b3 ='0' OR Pc_b2 = '0' OR Pc_b1 ='0' OR Pc_b0 = '0') THEN | |
|
691 | ASSERT (FALSE) | |
|
692 | REPORT "All bank must be Precharge before Load Mode Register" | |
|
693 | SEVERITY WARNING; | |
|
694 | END IF; | |
|
695 | -- REF to LMR | |
|
696 | ASSERT (NOW - RC_chk >= tRC) | |
|
697 | REPORT "tRC violation during Load Mode Register" | |
|
698 | SEVERITY WARNING; | |
|
699 | -- LMR to LMR | |
|
700 | ASSERT (MRD_chk >= tMRD) | |
|
701 | REPORT "tMRD violation during Load Mode Register" | |
|
702 | SEVERITY WARNING; | |
|
703 | -- Record current tMRD time | |
|
704 | MRD_chk := 0; | |
|
705 | END IF; | |
|
706 | ||
|
707 | -- Active Block (latch Bank and Row Address) | |
|
708 | IF Active_enable = '1' THEN | |
|
709 | IF Ba = "00" AND Pc_b0 = '1' THEN | |
|
710 | Act_b0 := '1'; | |
|
711 | Pc_b0 := '0'; | |
|
712 | B0_row_addr := TO_BITVECTOR (Addr); | |
|
713 | RCD_chk0 := NOW; | |
|
714 | RAS_chk0 := NOW; | |
|
715 | -- Precharge to Active Bank 0 | |
|
716 | ASSERT (NOW - RP_chk0 >= tRP) | |
|
717 | REPORT "tRP violation during Activate Bank 0" | |
|
718 | SEVERITY WARNING; | |
|
719 | ELSIF Ba = "01" AND Pc_b1 = '1' THEN | |
|
720 | Act_b1 := '1'; | |
|
721 | Pc_b1 := '0'; | |
|
722 | B1_row_addr := TO_BITVECTOR (Addr); | |
|
723 | RCD_chk1 := NOW; | |
|
724 | RAS_chk1 := NOW; | |
|
725 | -- Precharge to Active Bank 1 | |
|
726 | ASSERT (NOW - RP_chk1 >= tRP) | |
|
727 | REPORT "tRP violation during Activate Bank 1" | |
|
728 | SEVERITY WARNING; | |
|
729 | ELSIF Ba = "10" AND Pc_b2 = '1' THEN | |
|
730 | Act_b2 := '1'; | |
|
731 | Pc_b2 := '0'; | |
|
732 | B2_row_addr := TO_BITVECTOR (Addr); | |
|
733 | RCD_chk2 := NOW; | |
|
734 | RAS_chk2 := NOW; | |
|
735 | -- Precharge to Active Bank 2 | |
|
736 | ASSERT (NOW - RP_chk2 >= tRP) | |
|
737 | REPORT "tRP violation during Activate Bank 2" | |
|
738 | SEVERITY WARNING; | |
|
739 | ELSIF Ba = "11" AND Pc_b3 = '1' THEN | |
|
740 | Act_b3 := '1'; | |
|
741 | Pc_b3 := '0'; | |
|
742 | B3_row_addr := TO_BITVECTOR (Addr); | |
|
743 | RCD_chk3 := NOW; | |
|
744 | RAS_chk3 := NOW; | |
|
745 | -- Precharge to Active Bank 3 | |
|
746 | ASSERT (NOW - RP_chk3 >= tRP) | |
|
747 | REPORT "tRP violation during Activate Bank 3" | |
|
748 | SEVERITY WARNING; | |
|
749 | ELSIF Ba = "00" AND Pc_b0 = '0' THEN | |
|
750 | ASSERT (FALSE) | |
|
751 | REPORT "Bank 0 is not Precharged" | |
|
752 | SEVERITY WARNING; | |
|
753 | ELSIF Ba = "01" AND Pc_b1 = '0' THEN | |
|
754 | ASSERT (FALSE) | |
|
755 | REPORT "Bank 1 is not Precharged" | |
|
756 | SEVERITY WARNING; | |
|
757 | ELSIF Ba = "10" AND Pc_b2 = '0' THEN | |
|
758 | ASSERT (FALSE) | |
|
759 | REPORT "Bank 2 is not Precharged" | |
|
760 | SEVERITY WARNING; | |
|
761 | ELSIF Ba = "11" AND Pc_b3 = '0' THEN | |
|
762 | ASSERT (FALSE) | |
|
763 | REPORT "Bank 3 is not Precharged" | |
|
764 | SEVERITY WARNING; | |
|
765 | END IF; | |
|
766 | -- Active Bank A to Active Bank B | |
|
767 | IF ((Previous_bank /= TO_BITVECTOR (Ba)) AND (NOW - RRD_chk < tRRD)) THEN | |
|
768 | ASSERT (FALSE) | |
|
769 | REPORT "tRRD violation during Activate" | |
|
770 | SEVERITY WARNING; | |
|
771 | END IF; | |
|
772 | -- LMR to ACT | |
|
773 | ASSERT (MRD_chk >= tMRD) | |
|
774 | REPORT "tMRD violation during Activate" | |
|
775 | SEVERITY WARNING; | |
|
776 | -- AutoRefresh to Activate | |
|
777 | ASSERT (NOW - RC_chk >= tRC) | |
|
778 | REPORT "tRC violation during Activate" | |
|
779 | SEVERITY WARNING; | |
|
780 | -- Record variable for checking violation | |
|
781 | RRD_chk := NOW; | |
|
782 | Previous_bank := TO_BITVECTOR (Ba); | |
|
783 | END IF; | |
|
784 | ||
|
785 | -- Precharge Block | |
|
786 | IF Prech_enable = '1' THEN | |
|
787 | IF Addr(10) = '1' THEN | |
|
788 | Pc_b0 := '1'; | |
|
789 | Pc_b1 := '1'; | |
|
790 | Pc_b2 := '1'; | |
|
791 | Pc_b3 := '1'; | |
|
792 | Act_b0 := '0'; | |
|
793 | Act_b1 := '0'; | |
|
794 | Act_b2 := '0'; | |
|
795 | Act_b3 := '0'; | |
|
796 | RP_chk0 := NOW; | |
|
797 | RP_chk1 := NOW; | |
|
798 | RP_chk2 := NOW; | |
|
799 | RP_chk3 := NOW; | |
|
800 | -- Activate to Precharge all banks | |
|
801 | ASSERT ((NOW - RAS_chk0 >= tRAS) OR (NOW - RAS_chk1 >= tRAS)) | |
|
802 | REPORT "tRAS violation during Precharge all banks" | |
|
803 | SEVERITY WARNING; | |
|
804 | -- tWR violation check for Write | |
|
805 | IF ((NOW - WR_chkp(0) < tWRp) OR (NOW - WR_chkp(1) < tWRp) OR | |
|
806 | (NOW - WR_chkp(2) < tWRp) OR (NOW - WR_chkp(3) < tWRp)) THEN | |
|
807 | ASSERT (FALSE) | |
|
808 | REPORT "tWR violation during Precharge ALL banks" | |
|
809 | SEVERITY WARNING; | |
|
810 | END IF; | |
|
811 | ELSIF Addr(10) = '0' THEN | |
|
812 | IF Ba = "00" THEN | |
|
813 | Pc_b0 := '1'; | |
|
814 | Act_b0 := '0'; | |
|
815 | RP_chk0 := NOW; | |
|
816 | -- Activate to Precharge bank 0 | |
|
817 | ASSERT (NOW - RAS_chk0 >= tRAS) | |
|
818 | REPORT "tRAS violation during Precharge bank 0" | |
|
819 | SEVERITY WARNING; | |
|
820 | ELSIF Ba = "01" THEN | |
|
821 | Pc_b1 := '1'; | |
|
822 | Act_b1 := '0'; | |
|
823 | RP_chk1 := NOW; | |
|
824 | -- Activate to Precharge bank 1 | |
|
825 | ASSERT (NOW - RAS_chk1 >= tRAS) | |
|
826 | REPORT "tRAS violation during Precharge bank 1" | |
|
827 | SEVERITY WARNING; | |
|
828 | ELSIF Ba = "10" THEN | |
|
829 | Pc_b2 := '1'; | |
|
830 | Act_b2 := '0'; | |
|
831 | RP_chk2 := NOW; | |
|
832 | -- Activate to Precharge bank 2 | |
|
833 | ASSERT (NOW - RAS_chk2 >= tRAS) | |
|
834 | REPORT "tRAS violation during Precharge bank 2" | |
|
835 | SEVERITY WARNING; | |
|
836 | ELSIF Ba = "11" THEN | |
|
837 | Pc_b3 := '1'; | |
|
838 | Act_b3 := '0'; | |
|
839 | RP_chk3 := NOW; | |
|
840 | -- Activate to Precharge bank 3 | |
|
841 | ASSERT (NOW - RAS_chk3 >= tRAS) | |
|
842 | REPORT "tRAS violation during Precharge bank 3" | |
|
843 | SEVERITY WARNING; | |
|
844 | END IF; | |
|
845 | -- tWR violation check for Write | |
|
846 | ASSERT (NOW - WR_chkp(TO_INTEGER(Ba)) >= tWRp) | |
|
847 | REPORT "tWR violation during Precharge" | |
|
848 | SEVERITY WARNING; | |
|
849 | END IF; | |
|
850 | -- Terminate a Write Immediately (if same bank or all banks) | |
|
851 | IF (Data_in_enable = '1' AND (Bank = TO_BITVECTOR(Ba) OR Addr(10) = '1')) THEN | |
|
852 | Data_in_enable := '0'; | |
|
853 | END IF; | |
|
854 | -- Precharge Command Pipeline for READ | |
|
855 | IF CAS_latency_3 = '1' THEN | |
|
856 | Command(2) := PRECH; | |
|
857 | Bank_precharge(2) := TO_BITVECTOR (Ba); | |
|
858 | A10_precharge(2) := TO_BIT(Addr(10)); | |
|
859 | ELSIF CAS_latency_2 = '1' THEN | |
|
860 | Command(1) := PRECH; | |
|
861 | Bank_precharge(1) := TO_BITVECTOR (Ba); | |
|
862 | A10_precharge(1) := TO_BIT(Addr(10)); | |
|
863 | END IF; | |
|
864 | END IF; | |
|
865 | ||
|
866 | -- Burst Terminate | |
|
867 | IF Burst_term = '1' THEN | |
|
868 | -- Terminate a Write immediately | |
|
869 | IF Data_in_enable = '1' THEN | |
|
870 | Data_in_enable := '0'; | |
|
871 | END IF; | |
|
872 | -- Terminate a Read depend on CAS Latency | |
|
873 | IF CAS_latency_3 = '1' THEN | |
|
874 | Command(2) := BST; | |
|
875 | ELSIF CAS_latency_2 = '1' THEN | |
|
876 | Command(1) := BST; | |
|
877 | END IF; | |
|
878 | END IF; | |
|
879 | ||
|
880 | -- Read, Write, Column Latch | |
|
881 | IF Read_enable = '1' OR Write_enable = '1' THEN | |
|
882 | -- Check to see if bank is open (ACT) for Read or Write | |
|
883 | IF ((Ba="00" AND Pc_b0='1') OR (Ba="01" AND Pc_b1='1') OR (Ba="10" AND Pc_b2='1') OR (Ba="11" AND Pc_b3='1')) THEN | |
|
884 | ASSERT (FALSE) | |
|
885 | REPORT "Cannot Read or Write - Bank is not Activated" | |
|
886 | SEVERITY WARNING; | |
|
887 | END IF; | |
|
888 | -- Activate to Read or Write | |
|
889 | IF Ba = "00" THEN | |
|
890 | ASSERT (NOW - RCD_chk0 >= tRCD) | |
|
891 | REPORT "tRCD violation during Read or Write to Bank 0" | |
|
892 | SEVERITY WARNING; | |
|
893 | ELSIF Ba = "01" THEN | |
|
894 | ASSERT (NOW - RCD_chk1 >= tRCD) | |
|
895 | REPORT "tRCD violation during Read or Write to Bank 1" | |
|
896 | SEVERITY WARNING; | |
|
897 | ELSIF Ba = "10" THEN | |
|
898 | ASSERT (NOW - RCD_chk2 >= tRCD) | |
|
899 | REPORT "tRCD violation during Read or Write to Bank 2" | |
|
900 | SEVERITY WARNING; | |
|
901 | ELSIF Ba = "11" THEN | |
|
902 | ASSERT (NOW - RCD_chk3 >= tRCD) | |
|
903 | REPORT "tRCD violation during Read or Write to Bank 3" | |
|
904 | SEVERITY WARNING; | |
|
905 | END IF; | |
|
906 | ||
|
907 | -- Read Command | |
|
908 | IF Read_enable = '1' THEN | |
|
909 | -- CAS Latency Pipeline | |
|
910 | IF Cas_latency_3 = '1' THEN | |
|
911 | IF Addr(10) = '1' THEN | |
|
912 | Command(2) := READ_A; | |
|
913 | ELSE | |
|
914 | Command(2) := READ; | |
|
915 | END IF; | |
|
916 | Col_addr (2) := TO_BITVECTOR (Addr(col_bits - 1 DOWNTO 0)); | |
|
917 | Bank_addr (2) := TO_BITVECTOR (Ba); | |
|
918 | ELSIF Cas_latency_2 = '1' THEN | |
|
919 | IF Addr(10) = '1' THEN | |
|
920 | Command(1) := READ_A; | |
|
921 | ELSE | |
|
922 | Command(1) := READ; | |
|
923 | END IF; | |
|
924 | Col_addr (1) := TO_BITVECTOR (Addr(col_bits - 1 DOWNTO 0)); | |
|
925 | Bank_addr (1) := TO_BITVECTOR (Ba); | |
|
926 | END IF; | |
|
927 | ||
|
928 | -- Read intterupt a Write (terminate Write immediately) | |
|
929 | IF Data_in_enable = '1' THEN | |
|
930 | Data_in_enable := '0'; | |
|
931 | END IF; | |
|
932 | ||
|
933 | -- Write Command | |
|
934 | ELSIF Write_enable = '1' THEN | |
|
935 | IF Addr(10) = '1' THEN | |
|
936 | Command(0) := WRITE_A; | |
|
937 | ELSE | |
|
938 | Command(0) := WRITE; | |
|
939 | END IF; | |
|
940 | Col_addr (0) := TO_BITVECTOR (Addr(col_bits - 1 DOWNTO 0)); | |
|
941 | Bank_addr (0) := TO_BITVECTOR (Ba); | |
|
942 | ||
|
943 | -- Write intterupt a Write (terminate Write immediately) | |
|
944 | IF Data_in_enable = '1' THEN | |
|
945 | Data_in_enable := '0'; | |
|
946 | END IF; | |
|
947 | ||
|
948 | -- Write interrupt a Read (terminate Read immediately) | |
|
949 | IF Data_out_enable = '1' THEN | |
|
950 | Data_out_enable := '0'; | |
|
951 | END IF; | |
|
952 | END IF; | |
|
953 | ||
|
954 | -- Interrupt a Write with Auto Precharge | |
|
955 | IF Auto_precharge(TO_INTEGER(RW_Interrupt_Bank)) = '1' AND Write_precharge(TO_INTEGER(RW_Interrupt_Bank)) = '1' THEN | |
|
956 | RW_interrupt_write(TO_INTEGER(RW_Interrupt_Bank)) := '1'; | |
|
957 | END IF; | |
|
958 | ||
|
959 | -- Interrupt a Read with Auto Precharge | |
|
960 | IF Auto_precharge(TO_INTEGER(RW_Interrupt_Bank)) = '1' AND Read_precharge(TO_INTEGER(RW_Interrupt_Bank)) = '1' THEN | |
|
961 | RW_interrupt_read(TO_INTEGER(RW_Interrupt_Bank)) := '1'; | |
|
962 | END IF; | |
|
963 | ||
|
964 | -- Read or Write with Auto Precharge | |
|
965 | IF Addr(10) = '1' THEN | |
|
966 | Auto_precharge (TO_INTEGER(Ba)) := '1'; | |
|
967 | Count_precharge (TO_INTEGER(Ba)) := 0; | |
|
968 | RW_Interrupt_Bank := TO_BitVector(Ba); | |
|
969 | IF Read_enable = '1' THEN | |
|
970 | Read_precharge (TO_INTEGER(Ba)) := '1'; | |
|
971 | ELSIF Write_enable = '1' THEN | |
|
972 | Write_precharge (TO_INTEGER(Ba)) := '1'; | |
|
973 | END IF; | |
|
974 | END IF; | |
|
975 | END IF; | |
|
976 | ||
|
977 | -- Read with AutoPrecharge Calculation | |
|
978 | -- The device start internal precharge when: | |
|
979 | -- 1. BL/2 cycles after command | |
|
980 | -- and 2. Meet tRAS requirement | |
|
981 | -- or 3. Interrupt by a Read or Write (with or without Auto Precharge) | |
|
982 | IF ((Auto_precharge(0) = '1') AND (Read_precharge(0) = '1')) THEN | |
|
983 | IF (((NOW - RAS_chk0 >= tRAS) AND | |
|
984 | ((Burst_length_1 = '1' AND Count_precharge(0) >= 1) OR | |
|
985 | (Burst_length_2 = '1' AND Count_precharge(0) >= 2) OR | |
|
986 | (Burst_length_4 = '1' AND Count_precharge(0) >= 4) OR | |
|
987 | (Burst_length_8 = '1' AND Count_precharge(0) >= 8))) OR | |
|
988 | (RW_interrupt_read(0) = '1')) THEN | |
|
989 | Pc_b0 := '1'; | |
|
990 | Act_b0 := '0'; | |
|
991 | RP_chk0 := NOW; | |
|
992 | Auto_precharge(0) := '0'; | |
|
993 | Read_precharge(0) := '0'; | |
|
994 | RW_interrupt_read(0) := '0'; | |
|
995 | END IF; | |
|
996 | END IF; | |
|
997 | IF ((Auto_precharge(1) = '1') AND (Read_precharge(1) = '1')) THEN | |
|
998 | IF (((NOW - RAS_chk1 >= tRAS) AND | |
|
999 | ((Burst_length_1 = '1' AND Count_precharge(1) >= 1) OR | |
|
1000 | (Burst_length_2 = '1' AND Count_precharge(1) >= 2) OR | |
|
1001 | (Burst_length_4 = '1' AND Count_precharge(1) >= 4) OR | |
|
1002 | (Burst_length_8 = '1' AND Count_precharge(1) >= 8))) OR | |
|
1003 | (RW_interrupt_read(1) = '1')) THEN | |
|
1004 | Pc_b1 := '1'; | |
|
1005 | Act_b1 := '0'; | |
|
1006 | RP_chk1 := NOW; | |
|
1007 | Auto_precharge(1) := '0'; | |
|
1008 | Read_precharge(1) := '0'; | |
|
1009 | RW_interrupt_read(1) := '0'; | |
|
1010 | END IF; | |
|
1011 | END IF; | |
|
1012 | IF ((Auto_precharge(2) = '1') AND (Read_precharge(2) = '1')) THEN | |
|
1013 | IF (((NOW - RAS_chk2 >= tRAS) AND | |
|
1014 | ((Burst_length_1 = '1' AND Count_precharge(2) >= 1) OR | |
|
1015 | (Burst_length_2 = '1' AND Count_precharge(2) >= 2) OR | |
|
1016 | (Burst_length_4 = '1' AND Count_precharge(2) >= 4) OR | |
|
1017 | (Burst_length_8 = '1' AND Count_precharge(2) >= 8))) OR | |
|
1018 | (RW_interrupt_read(2) = '1')) THEN | |
|
1019 | Pc_b2 := '1'; | |
|
1020 | Act_b2 := '0'; | |
|
1021 | RP_chk2 := NOW; | |
|
1022 | Auto_precharge(2) := '0'; | |
|
1023 | Read_precharge(2) := '0'; | |
|
1024 | RW_interrupt_read(2) := '0'; | |
|
1025 | END IF; | |
|
1026 | END IF; | |
|
1027 | IF ((Auto_precharge(3) = '1') AND (Read_precharge(3) = '1')) THEN | |
|
1028 | IF (((NOW - RAS_chk3 >= tRAS) AND | |
|
1029 | ((Burst_length_1 = '1' AND Count_precharge(3) >= 1) OR | |
|
1030 | (Burst_length_2 = '1' AND Count_precharge(3) >= 2) OR | |
|
1031 | (Burst_length_4 = '1' AND Count_precharge(3) >= 4) OR | |
|
1032 | (Burst_length_8 = '1' AND Count_precharge(3) >= 8))) OR | |
|
1033 | (RW_interrupt_read(3) = '1')) THEN | |
|
1034 | Pc_b3 := '1'; | |
|
1035 | Act_b3 := '0'; | |
|
1036 | RP_chk3 := NOW; | |
|
1037 | Auto_precharge(3) := '0'; | |
|
1038 | Read_precharge(3) := '0'; | |
|
1039 | RW_interrupt_read(3) := '0'; | |
|
1040 | END IF; | |
|
1041 | END IF; | |
|
1042 | ||
|
1043 | -- Internal Precharge or Bst | |
|
1044 | IF Command(0) = PRECH THEN -- PRECH terminate a read if same bank or all banks | |
|
1045 | IF Bank_precharge(0) = Bank OR A10_precharge(0) = '1' THEN | |
|
1046 | IF Data_out_enable = '1' THEN | |
|
1047 | Data_out_enable := '0'; | |
|
1048 | END IF; | |
|
1049 | END IF; | |
|
1050 | ELSIF Command(0) = BST THEN -- BST terminate a read regardless of bank | |
|
1051 | IF Data_out_enable = '1' THEN | |
|
1052 | Data_out_enable := '0'; | |
|
1053 | END IF; | |
|
1054 | END IF; | |
|
1055 | ||
|
1056 | IF Data_out_enable = '0' THEN | |
|
1057 | Dq <= TRANSPORT (OTHERS => 'Z') AFTER tOH; | |
|
1058 | END IF; | |
|
1059 | ||
|
1060 | -- Detect Read or Write Command | |
|
1061 | IF Command(0) = READ OR Command(0) = READ_A THEN | |
|
1062 | Bank := Bank_addr (0); | |
|
1063 | Col := Col_addr (0); | |
|
1064 | Col_brst := Col_addr (0); | |
|
1065 | IF Bank_addr (0) = "00" THEN | |
|
1066 | Row := B0_row_addr; | |
|
1067 | ELSIF Bank_addr (0) = "01" THEN | |
|
1068 | Row := B1_row_addr; | |
|
1069 | ELSIF Bank_addr (0) = "10" THEN | |
|
1070 | Row := B2_row_addr; | |
|
1071 | ELSE | |
|
1072 | Row := B3_row_addr; | |
|
1073 | END IF; | |
|
1074 | Burst_counter := 0; | |
|
1075 | Data_in_enable := '0'; | |
|
1076 | Data_out_enable := '1'; | |
|
1077 | ELSIF Command(0) = WRITE OR Command(0) = WRITE_A THEN | |
|
1078 | Bank := Bank_addr(0); | |
|
1079 | Col := Col_addr(0); | |
|
1080 | Col_brst := Col_addr(0); | |
|
1081 | IF Bank_addr (0) = "00" THEN | |
|
1082 | Row := B0_row_addr; | |
|
1083 | ELSIF Bank_addr (0) = "01" THEN | |
|
1084 | Row := B1_row_addr; | |
|
1085 | ELSIF Bank_addr (0) = "10" THEN | |
|
1086 | Row := B2_row_addr; | |
|
1087 | ELSE | |
|
1088 | Row := B3_row_addr; | |
|
1089 | END IF; | |
|
1090 | Burst_counter := 0; | |
|
1091 | Data_in_enable := '1'; | |
|
1092 | Data_out_enable := '0'; | |
|
1093 | END IF; | |
|
1094 | ||
|
1095 | -- DQ (Driver / Receiver) | |
|
1096 | Row_index := TO_INTEGER (Row); | |
|
1097 | Col_index := TO_INTEGER (Col); | |
|
1098 | IF Data_in_enable = '1' THEN | |
|
1099 | IF Dqm /= "11" THEN | |
|
1100 | Init_mem (Bank, Row_index); | |
|
1101 | IF Bank = "00" THEN | |
|
1102 | Dq_temp := Bank0 (Row_index) (Col_index); | |
|
1103 | IF Dqm = "01" THEN | |
|
1104 | Dq_temp (15 DOWNTO 8) := TO_BITVECTOR (Dq (15 DOWNTO 8)); | |
|
1105 | ELSIF Dqm = "10" THEN | |
|
1106 | Dq_temp (7 DOWNTO 0) := TO_BITVECTOR (Dq (7 DOWNTO 0)); | |
|
1107 | ELSE | |
|
1108 | Dq_temp (15 DOWNTO 0) := TO_BITVECTOR (Dq (15 DOWNTO 0)); | |
|
1109 | END IF; | |
|
1110 | Bank0 (Row_index) (Col_index) := ('1' & Dq_temp(data_bits - 1 DOWNTO 0)); | |
|
1111 | ELSIF Bank = "01" THEN | |
|
1112 | Dq_temp := Bank1 (Row_index) (Col_index); | |
|
1113 | IF Dqm = "01" THEN | |
|
1114 | Dq_temp (15 DOWNTO 8) := TO_BITVECTOR (Dq (15 DOWNTO 8)); | |
|
1115 | ELSIF Dqm = "10" THEN | |
|
1116 | Dq_temp (7 DOWNTO 0) := TO_BITVECTOR (Dq (7 DOWNTO 0)); | |
|
1117 | ELSE | |
|
1118 | Dq_temp (15 DOWNTO 0) := TO_BITVECTOR (Dq (15 DOWNTO 0)); | |
|
1119 | END IF; | |
|
1120 | Bank1 (Row_index) (Col_index) := ('1' & Dq_temp(data_bits - 1 DOWNTO 0)); | |
|
1121 | ELSIF Bank = "10" THEN | |
|
1122 | Dq_temp := Bank2 (Row_index) (Col_index); | |
|
1123 | IF Dqm = "01" THEN | |
|
1124 | Dq_temp (15 DOWNTO 8) := TO_BITVECTOR (Dq (15 DOWNTO 8)); | |
|
1125 | ELSIF Dqm = "10" THEN | |
|
1126 | Dq_temp (7 DOWNTO 0) := TO_BITVECTOR (Dq (7 DOWNTO 0)); | |
|
1127 | ELSE | |
|
1128 | Dq_temp (15 DOWNTO 0) := TO_BITVECTOR (Dq (15 DOWNTO 0)); | |
|
1129 | END IF; | |
|
1130 | Bank2 (Row_index) (Col_index) := ('1' & Dq_temp(data_bits - 1 DOWNTO 0)); | |
|
1131 | ELSIF Bank = "11" THEN | |
|
1132 | Dq_temp := Bank3 (Row_index) (Col_index); | |
|
1133 | IF Dqm = "01" THEN | |
|
1134 | Dq_temp (15 DOWNTO 8) := TO_BITVECTOR (Dq (15 DOWNTO 8)); | |
|
1135 | ELSIF Dqm = "10" THEN | |
|
1136 | Dq_temp (7 DOWNTO 0) := TO_BITVECTOR (Dq (7 DOWNTO 0)); | |
|
1137 | ELSE | |
|
1138 | Dq_temp (15 DOWNTO 0) := TO_BITVECTOR (Dq (15 DOWNTO 0)); | |
|
1139 | END IF; | |
|
1140 | Bank3 (Row_index) (Col_index) := ('1' & Dq_temp(data_bits - 1 DOWNTO 0)); | |
|
1141 | END IF; | |
|
1142 | WR_chkp(TO_INTEGER(Bank)) := NOW; | |
|
1143 | WR_counter(TO_INTEGER(Bank)) := 0; | |
|
1144 | END IF; | |
|
1145 | Burst_decode; | |
|
1146 | ELSIF Data_out_enable = '1' THEN | |
|
1147 | IF Dqm_reg0 /= "11" THEN | |
|
1148 | Init_mem (Bank, Row_index); | |
|
1149 | IF Bank = "00" THEN | |
|
1150 | Dq_temp := Bank0 (Row_index) (Col_index); | |
|
1151 | IF Dqm_reg0 = "00" THEN | |
|
1152 | Dq (15 DOWNTO 0) <= TRANSPORT TO_STDLOGICVECTOR (Dq_temp (15 DOWNTO 0)) AFTER tAC; | |
|
1153 | ELSIF Dqm_reg0 = "01" THEN | |
|
1154 | Dq (15 DOWNTO 8) <= TRANSPORT TO_STDLOGICVECTOR (Dq_temp (15 DOWNTO 8)) AFTER tAC; | |
|
1155 | Dq (7 DOWNTO 0) <= TRANSPORT (OTHERS => 'Z') AFTER tAC; | |
|
1156 | ELSIF Dqm_reg0 = "10" THEN | |
|
1157 | Dq (15 DOWNTO 8) <= TRANSPORT (OTHERS => 'Z') AFTER tAC; | |
|
1158 | Dq (7 DOWNTO 0) <= TRANSPORT TO_STDLOGICVECTOR (Dq_temp (7 DOWNTO 0)) AFTER tAC; | |
|
1159 | END IF; | |
|
1160 | ELSIF Bank = "01" THEN | |
|
1161 | Dq_temp := Bank1 (Row_index) (Col_index); | |
|
1162 | IF Dqm_reg0 = "00" THEN | |
|
1163 | Dq (15 DOWNTO 0) <= TRANSPORT TO_STDLOGICVECTOR (Dq_temp (15 DOWNTO 0)) AFTER tAC; | |
|
1164 | ELSIF Dqm_reg0 = "01" THEN | |
|
1165 | Dq (15 DOWNTO 8) <= TRANSPORT TO_STDLOGICVECTOR (Dq_temp (15 DOWNTO 8)) AFTER tAC; | |
|
1166 | Dq (7 DOWNTO 0) <= TRANSPORT (OTHERS => 'Z') AFTER tAC; | |
|
1167 | ELSIF Dqm_reg0 = "10" THEN | |
|
1168 | Dq (15 DOWNTO 8) <= TRANSPORT (OTHERS => 'Z') AFTER tAC; | |
|
1169 | Dq (7 DOWNTO 0) <= TRANSPORT TO_STDLOGICVECTOR (Dq_temp (7 DOWNTO 0)) AFTER tAC; | |
|
1170 | END IF; | |
|
1171 | ELSIF Bank = "10" THEN | |
|
1172 | Dq_temp := Bank2 (Row_index) (Col_index); | |
|
1173 | IF Dqm_reg0 = "00" THEN | |
|
1174 | Dq (15 DOWNTO 0) <= TRANSPORT TO_STDLOGICVECTOR (Dq_temp (15 DOWNTO 0)) AFTER tAC; | |
|
1175 | ELSIF Dqm_reg0 = "01" THEN | |
|
1176 | Dq (15 DOWNTO 8) <= TRANSPORT TO_STDLOGICVECTOR (Dq_temp (15 DOWNTO 8)) AFTER tAC; | |
|
1177 | Dq (7 DOWNTO 0) <= TRANSPORT (OTHERS => 'Z') AFTER tAC; | |
|
1178 | ELSIF Dqm_reg0 = "10" THEN | |
|
1179 | Dq (15 DOWNTO 8) <= TRANSPORT (OTHERS => 'Z') AFTER tAC; | |
|
1180 | Dq (7 DOWNTO 0) <= TRANSPORT TO_STDLOGICVECTOR (Dq_temp (7 DOWNTO 0)) AFTER tAC; | |
|
1181 | END IF; | |
|
1182 | ELSIF Bank = "11" THEN | |
|
1183 | Dq_temp := Bank3 (Row_index) (Col_index); | |
|
1184 | IF Dqm_reg0 = "00" THEN | |
|
1185 | Dq (15 DOWNTO 0) <= TRANSPORT TO_STDLOGICVECTOR (Dq_temp (15 DOWNTO 0)) AFTER tAC; | |
|
1186 | ELSIF Dqm_reg0 = "01" THEN | |
|
1187 | Dq (15 DOWNTO 8) <= TRANSPORT TO_STDLOGICVECTOR (Dq_temp (15 DOWNTO 8)) AFTER tAC; | |
|
1188 | Dq (7 DOWNTO 0) <= TRANSPORT (OTHERS => 'Z') AFTER tAC; | |
|
1189 | ELSIF Dqm_reg0 = "10" THEN | |
|
1190 | Dq (15 DOWNTO 8) <= TRANSPORT (OTHERS => 'Z') AFTER tAC; | |
|
1191 | Dq (7 DOWNTO 0) <= TRANSPORT TO_STDLOGICVECTOR (Dq_temp (7 DOWNTO 0)) AFTER tAC; | |
|
1192 | END IF; | |
|
1193 | END IF; | |
|
1194 | ELSE | |
|
1195 | Dq <= TRANSPORT (OTHERS => 'Z') AFTER tHZ; | |
|
1196 | END IF; | |
|
1197 | Burst_decode; | |
|
1198 | END IF; | |
|
1199 | ELSIF Sys_clk'event AND Sys_clk = '1' AND Load = '1' AND Dump = '0' THEN --' | |
|
1200 | Operation <= LOAD_FILE; | |
|
1201 | load := '0'; | |
|
1202 | -- ASSERT (FALSE) REPORT "Reading memory array from file. This operation may take several minutes. Please wait..." | |
|
1203 | -- SEVERITY NOTE; | |
|
1204 | WHILE NOT endfile(file_load) LOOP | |
|
1205 | readline(file_load, l); | |
|
1206 | read(l, ch); | |
|
1207 | if (ch /= 'S') or (ch /= 's') then | |
|
1208 | hread(l, rectype); | |
|
1209 | hread(l, reclen); | |
|
1210 | recaddr := (others => '0'); | |
|
1211 | case rectype is | |
|
1212 | when "0001" => | |
|
1213 | hread(l, recaddr(15 downto 0)); | |
|
1214 | when "0010" => | |
|
1215 | hread(l, recaddr(23 downto 0)); | |
|
1216 | when "0011" => | |
|
1217 | hread(l, recaddr); | |
|
1218 | recaddr(31 downto 24) := (others => '0'); | |
|
1219 | when others => next; | |
|
1220 | end case; | |
|
1221 | hread(l, recdata); | |
|
1222 | ||
|
1223 | if index < 32 then | |
|
1224 | Bank_Load := recaddr(25 downto 24); | |
|
1225 | Rows_Load := recaddr(23 downto 11); | |
|
1226 | Cols_Load := recaddr(10 downto 2); | |
|
1227 | Init_Mem (Bank_Load, To_Integer(Rows_Load)); | |
|
1228 | IF Bank_Load = "00" THEN | |
|
1229 | for i in 0 to 3 loop | |
|
1230 | Bank0 (To_Integer(Rows_Load)) (To_Integer(Cols_Load)+i) := ('1' & recdata(i*32+index to i*32+index+15)); | |
|
1231 | end loop; | |
|
1232 | ELSIF Bank_Load = "01" THEN | |
|
1233 | for i in 0 to 3 loop | |
|
1234 | Bank1 (To_Integer(Rows_Load)) (To_Integer(Cols_Load)+i) := ('1' & recdata(i*32+index to i*32+index+15)); | |
|
1235 | end loop; | |
|
1236 | ELSIF Bank_Load = "10" THEN | |
|
1237 | for i in 0 to 3 loop | |
|
1238 | Bank2 (To_Integer(Rows_Load)) (To_Integer(Cols_Load)+i) := ('1' & recdata(i*32+index to i*32+index+15)); | |
|
1239 | end loop; | |
|
1240 | ELSIF Bank_Load = "11" THEN | |
|
1241 | for i in 0 to 3 loop | |
|
1242 | Bank3 (To_Integer(Rows_Load)) (To_Integer(Cols_Load)+i) := ('1' & recdata(i*32+index to i*32+index+15)); | |
|
1243 | end loop; | |
|
1244 | END IF; | |
|
1245 | elsif(index < 1024) then | |
|
1246 | Bank_Load := recaddr(26 downto 25); | |
|
1247 | Rows_Load := recaddr(24 downto 12); | |
|
1248 | Cols_Load := recaddr(11 downto 3); | |
|
1249 | Init_Mem (Bank_Load, To_Integer(Rows_Load)); | |
|
1250 | IF Bank_Load = "00" THEN | |
|
1251 | for i in 0 to 1 loop | |
|
1252 | Bank0 (To_Integer(Rows_Load)) (To_Integer(Cols_Load)+i) := ('1' & recdata(i*64+index-32 to i*64+index-32+15)); | |
|
1253 | end loop; | |
|
1254 | ELSIF Bank_Load = "01" THEN | |
|
1255 | for i in 0 to 1 loop | |
|
1256 | Bank1 (To_Integer(Rows_Load)) (To_Integer(Cols_Load)+i) := ('1' & recdata(i*64+index-32 to i*64+index-32+15)); | |
|
1257 | end loop; | |
|
1258 | ELSIF Bank_Load = "10" THEN | |
|
1259 | for i in 0 to 1 loop | |
|
1260 | Bank2 (To_Integer(Rows_Load)) (To_Integer(Cols_Load)+i) := ('1' & recdata(i*64+index-32 to i*64+index-32+15)); | |
|
1261 | end loop; | |
|
1262 | ELSIF Bank_Load = "11" THEN | |
|
1263 | for i in 0 to 1 loop | |
|
1264 | Bank3 (To_Integer(Rows_Load)) (To_Integer(Cols_Load)+i) := ('1' & recdata(i*64+index-32 to i*64+index-32+15)); | |
|
1265 | end loop; | |
|
1266 | END IF; | |
|
1267 | else | |
|
1268 | Bank_Load := recaddr(22 downto 21); | |
|
1269 | Rows_Load := '0' & recaddr(20 downto 9); | |
|
1270 | Cols_Load := '0' & recaddr(8 downto 1); | |
|
1271 | Init_Mem (Bank_Load, To_Integer(Rows_Load)); | |
|
1272 | IF Bank_Load = "00" THEN | |
|
1273 | for i in 0 to 7 loop | |
|
1274 | Bank0 (To_Integer(Rows_Load)) (To_Integer(Cols_Load)+i) := ('1' & recdata(i*16 to i*16+15)); | |
|
1275 | end loop; | |
|
1276 | ELSIF Bank_Load = "01" THEN | |
|
1277 | for i in 0 to 7 loop | |
|
1278 | Bank1 (To_Integer(Rows_Load)) (To_Integer(Cols_Load)+i) := ('1' & recdata(i*16 to i*16+15)); | |
|
1279 | end loop; | |
|
1280 | ELSIF Bank_Load = "10" THEN | |
|
1281 | for i in 0 to 7 loop | |
|
1282 | Bank2 (To_Integer(Rows_Load)) (To_Integer(Cols_Load)+i) := ('1' & recdata(i*16 to i*16+15)); | |
|
1283 | end loop; | |
|
1284 | ELSIF Bank_Load = "11" THEN | |
|
1285 | for i in 0 to 7 loop | |
|
1286 | Bank3 (To_Integer(Rows_Load)) (To_Integer(Cols_Load)+i) := ('1' & recdata(i*16 to i*16+15)); | |
|
1287 | end loop; | |
|
1288 | END IF; | |
|
1289 | END IF; | |
|
1290 | END IF; | |
|
1291 | END LOOP; | |
|
1292 | ELSIF Sys_clk'event AND Sys_clk = '1' AND Load = '0' AND Dump = '1' THEN --' | |
|
1293 | Operation <= DUMP_FILE; | |
|
1294 | ASSERT (FALSE) REPORT "Writing memory array to file. This operation may take several minutes. Please wait..." | |
|
1295 | SEVERITY NOTE; | |
|
1296 | WRITE (l, string'("# Micron Technology, Inc. (FILE DUMP / MEMORY DUMP)")); --' | |
|
1297 | WRITELINE (file_dump, l); | |
|
1298 | WRITE (l, string'("# BA ROWS COLS DQ")); --' | |
|
1299 | WRITELINE (file_dump, l); | |
|
1300 | WRITE (l, string'("# -- ------------- --------- ----------------")); --' | |
|
1301 | WRITELINE (file_dump, l); | |
|
1302 | -- Dumping Bank 0 | |
|
1303 | FOR i IN 0 TO 2**addr_bits -1 LOOP | |
|
1304 | -- Check if ROW is NULL | |
|
1305 | IF Bank0 (i) /= NULL THEN | |
|
1306 | For j IN 0 TO 2**col_bits - 1 LOOP | |
|
1307 | -- Check if COL is NULL | |
|
1308 | NEXT WHEN Bank0 (i) (j) (data_bits) = '0'; | |
|
1309 | WRITE (l, string'("00"), right, 4); --' | |
|
1310 | WRITE (l, To_BitVector(Conv_Std_Logic_Vector(i, addr_bits)), right, addr_bits+1); | |
|
1311 | WRITE (l, To_BitVector(Conv_std_Logic_Vector(j, col_bits)), right, col_bits+1); | |
|
1312 | WRITE (l, Bank0 (i) (j) (data_bits -1 DOWNTO 0), right, data_bits+1); | |
|
1313 | WRITELINE (file_dump, l); | |
|
1314 | END LOOP; | |
|
1315 | END IF; | |
|
1316 | END LOOP; | |
|
1317 | -- Dumping Bank 1 | |
|
1318 | FOR i IN 0 TO 2**addr_bits -1 LOOP | |
|
1319 | -- Check if ROW is NULL | |
|
1320 | IF Bank1 (i) /= NULL THEN | |
|
1321 | For j IN 0 TO 2**col_bits - 1 LOOP | |
|
1322 | -- Check if COL is NULL | |
|
1323 | NEXT WHEN Bank1 (i) (j) (data_bits) = '0'; | |
|
1324 | WRITE (l, string'("01"), right, 4); --' | |
|
1325 | WRITE (l, To_BitVector(Conv_Std_Logic_Vector(i, addr_bits)), right, addr_bits+1); | |
|
1326 | WRITE (l, To_BitVector(Conv_std_Logic_Vector(j, col_bits)), right, col_bits+1); | |
|
1327 | WRITE (l, Bank1 (i) (j) (data_bits -1 DOWNTO 0), right, data_bits+1); | |
|
1328 | WRITELINE (file_dump, l); | |
|
1329 | END LOOP; | |
|
1330 | END IF; | |
|
1331 | END LOOP; | |
|
1332 | -- Dumping Bank 2 | |
|
1333 | FOR i IN 0 TO 2**addr_bits -1 LOOP | |
|
1334 | -- Check if ROW is NULL | |
|
1335 | IF Bank2 (i) /= NULL THEN | |
|
1336 | For j IN 0 TO 2**col_bits - 1 LOOP | |
|
1337 | -- Check if COL is NULL | |
|
1338 | NEXT WHEN Bank2 (i) (j) (data_bits) = '0'; | |
|
1339 | WRITE (l, string'("10"), right, 4); --' | |
|
1340 | WRITE (l, To_BitVector(Conv_Std_Logic_Vector(i, addr_bits)), right, addr_bits+1); | |
|
1341 | WRITE (l, To_BitVector(Conv_std_Logic_Vector(j, col_bits)), right, col_bits+1); | |
|
1342 | WRITE (l, Bank2 (i) (j) (data_bits -1 DOWNTO 0), right, data_bits+1); | |
|
1343 | WRITELINE (file_dump, l); | |
|
1344 | END LOOP; | |
|
1345 | END IF; | |
|
1346 | END LOOP; | |
|
1347 | -- Dumping Bank 3 | |
|
1348 | FOR i IN 0 TO 2**addr_bits -1 LOOP | |
|
1349 | -- Check if ROW is NULL | |
|
1350 | IF Bank3 (i) /= NULL THEN | |
|
1351 | For j IN 0 TO 2**col_bits - 1 LOOP | |
|
1352 | -- Check if COL is NULL | |
|
1353 | NEXT WHEN Bank3 (i) (j) (data_bits) = '0'; | |
|
1354 | WRITE (l, string'("11"), right, 4); --' | |
|
1355 | WRITE (l, To_BitVector(Conv_Std_Logic_Vector(i, addr_bits)), right, addr_bits+1); | |
|
1356 | WRITE (l, To_BitVector(Conv_std_Logic_Vector(j, col_bits)), right, col_bits+1); | |
|
1357 | WRITE (l, Bank3 (i) (j) (data_bits -1 DOWNTO 0), right, data_bits+1); | |
|
1358 | WRITELINE (file_dump, l); | |
|
1359 | END LOOP; | |
|
1360 | END IF; | |
|
1361 | END LOOP; | |
|
1362 | END IF; | |
|
1363 | ||
|
1364 | -- Write with AutoPrecharge Calculation | |
|
1365 | -- The device start internal precharge when: | |
|
1366 | -- 1. tWR cycles after command | |
|
1367 | -- and 2. Meet tRAS requirement | |
|
1368 | -- or 3. Interrupt by a Read or Write (with or without Auto Precharge) | |
|
1369 | IF ((Auto_precharge(0) = '1') AND (Write_precharge(0) = '1')) THEN | |
|
1370 | IF (((NOW - RAS_chk0 >= tRAS) AND | |
|
1371 | (((Burst_length_1 = '1' OR Write_burst_mode = '1' ) AND Count_precharge(0) >= 1 AND NOW - Count_time(0) >= tWRa) OR | |
|
1372 | (Burst_length_2 = '1' AND Count_precharge(0) >= 2 AND NOW - Count_time(0) >= tWRa) OR | |
|
1373 | (Burst_length_4 = '1' AND Count_precharge(0) >= 4 AND NOW - Count_time(0) >= tWRa) OR | |
|
1374 | (Burst_length_8 = '1' AND Count_precharge(0) >= 8 AND NOW - Count_time(0) >= tWRa))) OR | |
|
1375 | (RW_interrupt_write(0) = '1' AND WR_counter(0) >= 1 AND NOW - WR_time(0) >= tWRa)) THEN | |
|
1376 | Auto_precharge(0) := '0'; | |
|
1377 | Write_precharge(0) := '0'; | |
|
1378 | RW_interrupt_write(0) := '0'; | |
|
1379 | Pc_b0 := '1'; | |
|
1380 | Act_b0 := '0'; | |
|
1381 | RP_chk0 := NOW; | |
|
1382 | ASSERT FALSE REPORT "Start Internal Precharge Bank 0" SEVERITY NOTE; | |
|
1383 | END IF; | |
|
1384 | END IF; | |
|
1385 | IF ((Auto_precharge(1) = '1') AND (Write_precharge(1) = '1')) THEN | |
|
1386 | IF (((NOW - RAS_chk1 >= tRAS) AND | |
|
1387 | (((Burst_length_1 = '1' OR Write_burst_mode = '1' ) AND Count_precharge(1) >= 1 AND NOW - Count_time(1) >= tWRa) OR | |
|
1388 | (Burst_length_2 = '1' AND Count_precharge(1) >= 2 AND NOW - Count_time(1) >= tWRa) OR | |
|
1389 | (Burst_length_4 = '1' AND Count_precharge(1) >= 4 AND NOW - Count_time(1) >= tWRa) OR | |
|
1390 | (Burst_length_8 = '1' AND Count_precharge(1) >= 8 AND NOW - Count_time(1) >= tWRa))) OR | |
|
1391 | (RW_interrupt_write(1) = '1' AND WR_counter(1) >= 1 AND NOW - WR_time(1) >= tWRa)) THEN | |
|
1392 | Auto_precharge(1) := '0'; | |
|
1393 | Write_precharge(1) := '0'; | |
|
1394 | RW_interrupt_write(1) := '0'; | |
|
1395 | Pc_b1 := '1'; | |
|
1396 | Act_b1 := '0'; | |
|
1397 | RP_chk1 := NOW; | |
|
1398 | END IF; | |
|
1399 | END IF; | |
|
1400 | IF ((Auto_precharge(2) = '1') AND (Write_precharge(2) = '1')) THEN | |
|
1401 | IF (((NOW - RAS_chk2 >= tRAS) AND | |
|
1402 | (((Burst_length_1 = '1' OR Write_burst_mode = '1' ) AND Count_precharge(2) >= 1 AND NOW - Count_time(2) >= tWRa) OR | |
|
1403 | (Burst_length_2 = '1' AND Count_precharge(2) >= 2 AND NOW - Count_time(2) >= tWRa) OR | |
|
1404 | (Burst_length_4 = '1' AND Count_precharge(2) >= 4 AND NOW - Count_time(2) >= tWRa) OR | |
|
1405 | (Burst_length_8 = '1' AND Count_precharge(2) >= 8 AND NOW - Count_time(2) >= tWRa))) OR | |
|
1406 | (RW_interrupt_write(2) = '1' AND WR_counter(2) >= 1 AND NOW - WR_time(2) >= tWRa)) THEN | |
|
1407 | Auto_precharge(2) := '0'; | |
|
1408 | Write_precharge(2) := '0'; | |
|
1409 | RW_interrupt_write(2) := '0'; | |
|
1410 | Pc_b2 := '1'; | |
|
1411 | Act_b2 := '0'; | |
|
1412 | RP_chk2 := NOW; | |
|
1413 | END IF; | |
|
1414 | END IF; | |
|
1415 | IF ((Auto_precharge(3) = '1') AND (Write_precharge(3) = '1')) THEN | |
|
1416 | IF (((NOW - RAS_chk3 >= tRAS) AND | |
|
1417 | (((Burst_length_1 = '1' OR Write_burst_mode = '1' ) AND Count_precharge(3) >= 1 AND NOW - Count_time(3) >= tWRa) OR | |
|
1418 | (Burst_length_2 = '1' AND Count_precharge(3) >= 2 AND NOW - Count_time(3) >= tWRa) OR | |
|
1419 | (Burst_length_4 = '1' AND Count_precharge(3) >= 4 AND NOW - Count_time(3) >= tWRa) OR | |
|
1420 | (Burst_length_8 = '1' AND Count_precharge(3) >= 8 AND NOW - Count_time(3) >= tWRa))) OR | |
|
1421 | (RW_interrupt_write(0) = '1' AND WR_counter(0) >= 1 AND NOW - WR_time(3) >= tWRa)) THEN | |
|
1422 | Auto_precharge(3) := '0'; | |
|
1423 | Write_precharge(3) := '0'; | |
|
1424 | RW_interrupt_write(3) := '0'; | |
|
1425 | Pc_b3 := '1'; | |
|
1426 | Act_b3 := '0'; | |
|
1427 | RP_chk3 := NOW; | |
|
1428 | END IF; | |
|
1429 | END IF; | |
|
1430 | ||
|
1431 | -- Checking internal wires (Optional for debug purpose) | |
|
1432 | Pre_chk (0) <= Pc_b0; | |
|
1433 | Pre_chk (1) <= Pc_b1; | |
|
1434 | Pre_chk (2) <= Pc_b2; | |
|
1435 | Pre_chk (3) <= Pc_b3; | |
|
1436 | Act_chk (0) <= Act_b0; | |
|
1437 | Act_chk (1) <= Act_b1; | |
|
1438 | Act_chk (2) <= Act_b2; | |
|
1439 | Act_chk (3) <= Act_b3; | |
|
1440 | Dq_in_chk <= Data_in_enable; | |
|
1441 | Dq_out_chk <= Data_out_enable; | |
|
1442 | Bank_chk <= Bank; | |
|
1443 | Row_chk <= Row; | |
|
1444 | Col_chk <= Col; | |
|
1445 | END PROCESS; | |
|
1446 | ||
|
1447 | ||
|
1448 | -- Clock timing checks | |
|
1449 | -- Clock_check : PROCESS | |
|
1450 | -- VARIABLE Clk_low, Clk_high : TIME := 0 ns; | |
|
1451 | -- BEGIN | |
|
1452 | -- WAIT ON Clk; | |
|
1453 | -- IF (Clk = '1' AND NOW >= 10 ns) THEN | |
|
1454 | -- ASSERT (NOW - Clk_low >= tCL) | |
|
1455 | -- REPORT "tCL violation" | |
|
1456 | -- SEVERITY WARNING; | |
|
1457 | -- ASSERT (NOW - Clk_high >= tCK) | |
|
1458 | -- REPORT "tCK violation" | |
|
1459 | -- SEVERITY WARNING; | |
|
1460 | -- Clk_high := NOW; | |
|
1461 | -- ELSIF (Clk = '0' AND NOW /= 0 ns) THEN | |
|
1462 | -- ASSERT (NOW - Clk_high >= tCH) | |
|
1463 | -- REPORT "tCH violation" | |
|
1464 | -- SEVERITY WARNING; | |
|
1465 | -- Clk_low := NOW; | |
|
1466 | -- END IF; | |
|
1467 | -- END PROCESS; | |
|
1468 | ||
|
1469 | -- Setup timing checks | |
|
1470 | Setup_check : PROCESS | |
|
1471 | BEGIN | |
|
1472 | wait; | |
|
1473 | WAIT ON Clk; | |
|
1474 | IF Clk = '1' THEN | |
|
1475 | ASSERT(Cke'LAST_EVENT >= tCKS) --' | |
|
1476 | REPORT "CKE Setup time violation -- tCKS" | |
|
1477 | SEVERITY WARNING; | |
|
1478 | ASSERT(Cs_n'LAST_EVENT >= tCMS) --' | |
|
1479 | REPORT "CS# Setup time violation -- tCMS" | |
|
1480 | SEVERITY WARNING; | |
|
1481 | ASSERT(Cas_n'LAST_EVENT >= tCMS) --' | |
|
1482 | REPORT "CAS# Setup time violation -- tCMS" | |
|
1483 | SEVERITY WARNING; | |
|
1484 | ASSERT(Ras_n'LAST_EVENT >= tCMS) --' | |
|
1485 | REPORT "RAS# Setup time violation -- tCMS" | |
|
1486 | SEVERITY WARNING; | |
|
1487 | ASSERT(We_n'LAST_EVENT >= tCMS) --' | |
|
1488 | REPORT "WE# Setup time violation -- tCMS" | |
|
1489 | SEVERITY WARNING; | |
|
1490 | ASSERT(Dqm'LAST_EVENT >= tCMS) --' | |
|
1491 | REPORT "Dqm Setup time violation -- tCMS" | |
|
1492 | SEVERITY WARNING; | |
|
1493 | ASSERT(Addr'LAST_EVENT >= tAS) --' | |
|
1494 | REPORT "ADDR Setup time violation -- tAS" | |
|
1495 | SEVERITY WARNING; | |
|
1496 | ASSERT(Ba'LAST_EVENT >= tAS) --' | |
|
1497 | REPORT "BA Setup time violation -- tAS" | |
|
1498 | SEVERITY WARNING; | |
|
1499 | ASSERT(Dq'LAST_EVENT >= tDS) --' | |
|
1500 | REPORT "Dq Setup time violation -- tDS" | |
|
1501 | SEVERITY WARNING; | |
|
1502 | END IF; | |
|
1503 | END PROCESS; | |
|
1504 | ||
|
1505 | -- Hold timing checks | |
|
1506 | Hold_check : PROCESS | |
|
1507 | BEGIN | |
|
1508 | wait; | |
|
1509 | WAIT ON Clk'DELAYED (tCKH), Clk'DELAYED (tCMH), Clk'DELAYED (tAH), Clk'DELAYED (tDH); | |
|
1510 | IF Clk'DELAYED (tCKH) = '1' THEN --' | |
|
1511 | ASSERT(Cke'LAST_EVENT > tCKH) --' | |
|
1512 | REPORT "CKE Hold time violation -- tCKH" | |
|
1513 | SEVERITY WARNING; | |
|
1514 | END IF; | |
|
1515 | IF Clk'DELAYED (tCMH) = '1' THEN --' | |
|
1516 | ASSERT(Cs_n'LAST_EVENT > tCMH) --' | |
|
1517 | REPORT "CS# Hold time violation -- tCMH" | |
|
1518 | SEVERITY WARNING; | |
|
1519 | ASSERT(Cas_n'LAST_EVENT > tCMH) --' | |
|
1520 | REPORT "CAS# Hold time violation -- tCMH" | |
|
1521 | SEVERITY WARNING; | |
|
1522 | ASSERT(Ras_n'LAST_EVENT > tCMH) --' | |
|
1523 | REPORT "RAS# Hold time violation -- tCMH" | |
|
1524 | SEVERITY WARNING; | |
|
1525 | ASSERT(We_n'LAST_EVENT > tCMH) --' | |
|
1526 | REPORT "WE# Hold time violation -- tCMH" | |
|
1527 | SEVERITY WARNING; | |
|
1528 | ASSERT(Dqm'LAST_EVENT > tCMH) --' | |
|
1529 | REPORT "Dqm Hold time violation -- tCMH" | |
|
1530 | SEVERITY WARNING; | |
|
1531 | END IF; | |
|
1532 | IF Clk'DELAYED (tAH) = '1' THEN --' | |
|
1533 | ASSERT(Addr'LAST_EVENT > tAH) --' | |
|
1534 | REPORT "ADDR Hold time violation -- tAH" | |
|
1535 | SEVERITY WARNING; | |
|
1536 | ASSERT(Ba'LAST_EVENT > tAH) --' | |
|
1537 | REPORT "BA Hold time violation -- tAH" | |
|
1538 | SEVERITY WARNING; | |
|
1539 | END IF; | |
|
1540 | IF Clk'DELAYED (tDH) = '1' THEN --' | |
|
1541 | ASSERT(Dq'LAST_EVENT > tDH) --' | |
|
1542 | REPORT "Dq Hold time violation -- tDH" | |
|
1543 | SEVERITY WARNING; | |
|
1544 | END IF; | |
|
1545 | END PROCESS; | |
|
1546 | ||
|
1547 | END behave; | |
|
1548 | ||
|
1549 | -- pragma translate_on | |
|
1550 |
This diff has been collapsed as it changes many lines, (1053 lines changed) Show them Hide them | |||
@@ -0,0 +1,1053 | |||
|
1 | ------------------------------------------------------------------------------ | |
|
2 | -- This file is a part of the GRLIB VHDL IP LIBRARY | |
|
3 | -- Copyright (C) 2003 - 2008, Gaisler Research | |
|
4 | -- Copyright (C) 2008 - 2014, Aeroflex Gaisler | |
|
5 | -- Copyright (C) 2015 - 2016, Cobham Gaisler | |
|
6 | -- | |
|
7 | -- This program is free software; you can redistribute it and/or modify | |
|
8 | -- it under the terms of the GNU General Public License as published by | |
|
9 | -- the Free Software Foundation; either version 2 of the License, or | |
|
10 | -- (at your option) any later version. | |
|
11 | -- | |
|
12 | -- This program is distributed in the hope that it will be useful, | |
|
13 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of | |
|
14 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
|
15 | -- GNU General Public License for more details. | |
|
16 | -- | |
|
17 | -- You should have received a copy of the GNU General Public License | |
|
18 | -- along with this program; if not, write to the Free Software | |
|
19 | -- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
|
20 | ----------------------------------------------------------------------------- | |
|
21 | -- Entity: sdctrl16 | |
|
22 | -- File: sdctrl16.vhd | |
|
23 | -- Author: Jiri Gaisler - Gaisler Research | |
|
24 | -- Modified by: Daniel Bengtsson & Richard Fång | |
|
25 | -- Description: 16- and 32-bit SDRAM memory controller. | |
|
26 | ------------------------------------------------------------------------------ | |
|
27 | ||
|
28 | library ieee; | |
|
29 | use ieee.std_logic_1164.all; | |
|
30 | library grlib; | |
|
31 | use grlib.amba.all; | |
|
32 | use grlib.stdlib.all; | |
|
33 | library gaisler; | |
|
34 | use grlib.devices.all; | |
|
35 | use gaisler.memctrl.all; | |
|
36 | ||
|
37 | entity sdctrl16 is | |
|
38 | generic ( | |
|
39 | hindex : integer := 0; | |
|
40 | haddr : integer := 0; | |
|
41 | hmask : integer := 16#f00#; | |
|
42 | ioaddr : integer := 16#000#; | |
|
43 | iomask : integer := 16#fff#; | |
|
44 | wprot : integer := 0; | |
|
45 | invclk : integer := 0; | |
|
46 | fast : integer := 0; | |
|
47 | pwron : integer := 0; | |
|
48 | sdbits : integer := 16; | |
|
49 | oepol : integer := 0; | |
|
50 | pageburst : integer := 0; | |
|
51 | mobile : integer := 0 | |
|
52 | ); | |
|
53 | port ( | |
|
54 | rst : in std_ulogic; | |
|
55 | clk : in std_ulogic; | |
|
56 | ahbsi : in ahb_slv_in_type; | |
|
57 | ahbso : out ahb_slv_out_type; | |
|
58 | sdi : in sdctrl_in_type; | |
|
59 | sdo : out sdctrl_out_type | |
|
60 | ); | |
|
61 | end; | |
|
62 | ||
|
63 | architecture rtl of sdctrl16 is | |
|
64 | ||
|
65 | constant WPROTEN : boolean := wprot = 1; | |
|
66 | constant SDINVCLK : boolean := invclk = 1; | |
|
67 | constant BUS16 : boolean := (sdbits = 16); | |
|
68 | constant BUS32 : boolean := (sdbits = 32); | |
|
69 | constant BUS64 : boolean := (sdbits = 64); | |
|
70 | ||
|
71 | constant REVISION : integer := 1; | |
|
72 | ||
|
73 | constant PM_PD : std_logic_vector(2 downto 0) := "001"; | |
|
74 | constant PM_SR : std_logic_vector(2 downto 0) := "010"; | |
|
75 | constant PM_DPD : std_logic_vector(2 downto 0) := "101"; | |
|
76 | ||
|
77 | constant std_rammask: Std_Logic_Vector(31 downto 20) := | |
|
78 | Conv_Std_Logic_Vector(hmask, 12); | |
|
79 | ||
|
80 | constant hconfig : ahb_config_type := ( | |
|
81 | 0 => ahb_device_reg ( VENDOR_GAISLER, GAISLER_SDCTRL, 0, REVISION, 0), | |
|
82 | 4 => ahb_membar(haddr, '1', '1', hmask), | |
|
83 | 5 => ahb_iobar(ioaddr, iomask), | |
|
84 | others => zero32); | |
|
85 | ||
|
86 | type mcycletype is (midle, active, leadout); | |
|
87 | type sdcycletype is (act1, act2, act3, act3_16, rd1, rd2, rd3, rd4, rd4_16, rd5, rd6, rd7, rd8, | |
|
88 | wr1, wr1_16, wr2, wr3, wr4, wr5, sidle, | |
|
89 | sref, pd, dpd); | |
|
90 | type icycletype is (iidle, pre, ref, lmode, emode, finish); | |
|
91 | ||
|
92 | -- sdram configuration register | |
|
93 | ||
|
94 | type sdram_cfg_type is record | |
|
95 | command : std_logic_vector(2 downto 0); | |
|
96 | csize : std_logic_vector(1 downto 0); | |
|
97 | bsize : std_logic_vector(2 downto 0); | |
|
98 | casdel : std_ulogic; -- CAS to data delay: 2/3 clock cycles | |
|
99 | trfc : std_logic_vector(2 downto 0); | |
|
100 | trp : std_ulogic; -- precharge to activate: 2/3 clock cycles | |
|
101 | refresh : std_logic_vector(14 downto 0); | |
|
102 | renable : std_ulogic; | |
|
103 | pageburst : std_ulogic; | |
|
104 | mobileen : std_logic_vector(1 downto 0); -- Mobile SD support, Mobile SD enabled | |
|
105 | ds : std_logic_vector(3 downto 0); -- ds(1:0) (ds(3:2) used to detect update) | |
|
106 | tcsr : std_logic_vector(3 downto 0); -- tcrs(1:0) (tcrs(3:2) used to detect update) | |
|
107 | pasr : std_logic_vector(5 downto 0); -- pasr(2:0) (pasr(5:3) used to detect update) | |
|
108 | pmode : std_logic_vector(2 downto 0); -- Power-Saving mode | |
|
109 | txsr : std_logic_vector(3 downto 0); -- Exit Self Refresh timing | |
|
110 | cke : std_ulogic; -- Clock enable | |
|
111 | end record; | |
|
112 | ||
|
113 | -- local registers | |
|
114 | ||
|
115 | type reg_type is record | |
|
116 | hready : std_ulogic; | |
|
117 | hsel : std_ulogic; | |
|
118 | bdrive : std_ulogic; | |
|
119 | nbdrive : std_ulogic; | |
|
120 | burst : std_ulogic; | |
|
121 | wprothit : std_ulogic; | |
|
122 | hio : std_ulogic; | |
|
123 | startsd : std_ulogic; | |
|
124 | lhw : std_ulogic; --Lower halfword | |
|
125 | ||
|
126 | mstate : mcycletype; | |
|
127 | sdstate : sdcycletype; | |
|
128 | cmstate : mcycletype; | |
|
129 | istate : icycletype; | |
|
130 | icnt : std_logic_vector(2 downto 0); | |
|
131 | ||
|
132 | haddr : std_logic_vector(31 downto 0); | |
|
133 | hrdata : std_logic_vector((sdbits-1)+((16/sdbits)*16) downto 0); | |
|
134 | hwdata : std_logic_vector(31 downto 0); | |
|
135 | hwrite : std_ulogic; | |
|
136 | htrans : std_logic_vector(1 downto 0); | |
|
137 | hresp : std_logic_vector(1 downto 0); | |
|
138 | size : std_logic_vector(1 downto 0); | |
|
139 | ||
|
140 | cfg : sdram_cfg_type; | |
|
141 | trfc : std_logic_vector(3 downto 0); | |
|
142 | refresh : std_logic_vector(14 downto 0); | |
|
143 | sdcsn : std_logic_vector(1 downto 0); | |
|
144 | sdwen : std_ulogic; | |
|
145 | rasn : std_ulogic; | |
|
146 | casn : std_ulogic; | |
|
147 | dqm : std_logic_vector(7 downto 0); | |
|
148 | address : std_logic_vector(16 downto 2); -- memory address | |
|
149 | bsel : std_ulogic; | |
|
150 | ||
|
151 | idlecnt : std_logic_vector(3 downto 0); -- Counter, 16 idle clock sycles before entering Power-Saving mode | |
|
152 | sref_tmpcom : std_logic_vector(2 downto 0); -- Save SD command when exit sref | |
|
153 | end record; | |
|
154 | ||
|
155 | signal r, ri : reg_type; | |
|
156 | signal rbdrive, ribdrive : std_logic_vector(31 downto 0); | |
|
157 | attribute syn_preserve : boolean; | |
|
158 | attribute syn_preserve of rbdrive : signal is true; | |
|
159 | ||
|
160 | begin | |
|
161 | ||
|
162 | ctrl : process(rst, ahbsi, r, sdi, rbdrive) | |
|
163 | variable v : reg_type; -- local variables for registers | |
|
164 | variable startsd : std_ulogic; | |
|
165 | variable dataout : std_logic_vector(31 downto 0); -- data from memory | |
|
166 | variable regsd : std_logic_vector(31 downto 0); -- data from registers | |
|
167 | variable dqm : std_logic_vector(7 downto 0); | |
|
168 | variable raddr : std_logic_vector(12 downto 0); | |
|
169 | variable adec : std_ulogic; | |
|
170 | variable rams : std_logic_vector(1 downto 0); | |
|
171 | variable ba : std_logic_vector(1 downto 0); | |
|
172 | variable haddr : std_logic_vector(31 downto 0); | |
|
173 | variable dout : std_logic_vector(31 downto 0); | |
|
174 | variable hsize : std_logic_vector(1 downto 0); | |
|
175 | variable hwrite : std_ulogic; | |
|
176 | variable htrans : std_logic_vector(1 downto 0); | |
|
177 | variable hready : std_ulogic; | |
|
178 | variable vbdrive : std_logic_vector(31 downto 0); | |
|
179 | variable bdrive : std_ulogic; | |
|
180 | variable lline : std_logic_vector(2 downto 0); | |
|
181 | variable lineburst : boolean; | |
|
182 | variable haddr_tmp : std_logic_vector(31 downto 0); | |
|
183 | variable arefresh : std_logic; | |
|
184 | variable hwdata : std_logic_vector(31 downto 0); | |
|
185 | ||
|
186 | begin | |
|
187 | ||
|
188 | -- Variable default settings to avoid latches | |
|
189 | ||
|
190 | v := r; startsd := '0'; v.hresp := HRESP_OKAY; vbdrive := rbdrive; arefresh := '0'; | |
|
191 | if BUS16 then | |
|
192 | if (r.lhw = '1') then --muxes read data to correct part of the register. | |
|
193 | v.hrdata(sdbits-1 downto 0) := sdi.data(sdbits-1 downto 0); | |
|
194 | else | |
|
195 | v.hrdata((sdbits*2)-1 downto sdbits) := sdi.data(sdbits-1 downto 0); | |
|
196 | end if; | |
|
197 | else | |
|
198 | v.hrdata(sdbits-1 downto sdbits-32) := sdi.data(sdbits-1 downto sdbits-32); | |
|
199 | v.hrdata(31 downto 0) := sdi.data(31 downto 0); | |
|
200 | end if; | |
|
201 | hwdata := ahbreadword(ahbsi.hwdata, r.haddr(4 downto 2)); v.hwdata := hwdata; | |
|
202 | lline := not r.cfg.casdel & r.cfg.casdel & r.cfg.casdel; | |
|
203 | if (pageburst = 0) or ((pageburst = 2) and r.cfg.pageburst = '0') then | |
|
204 | lineburst := true; | |
|
205 | else lineburst := false; end if; | |
|
206 | ||
|
207 | ||
|
208 | if ((ahbsi.hready and ahbsi.hsel(hindex)) = '1') then | |
|
209 | v.size := ahbsi.hsize(1 downto 0); v.hwrite := ahbsi.hwrite; | |
|
210 | v.htrans := ahbsi.htrans; | |
|
211 | if ahbsi.htrans(1) = '1' then | |
|
212 | v.hio := ahbsi.hmbsel(1); | |
|
213 | v.hsel := '1'; v.hready := v.hio; | |
|
214 | end if; | |
|
215 | v.haddr := ahbsi.haddr; | |
|
216 | -- addr must be masked since address range can be smaller than | |
|
217 | -- total banksize. this can result in wrong chip select being | |
|
218 | -- asserted | |
|
219 | for i in 31 downto 20 loop | |
|
220 | v.haddr(i) := ahbsi.haddr(i) and not std_rammask(i); | |
|
221 | end loop; | |
|
222 | end if; | |
|
223 | ||
|
224 | if (r.hsel = '1') and (ahbsi.hready = '0') then | |
|
225 | haddr := r.haddr; hsize := r.size; | |
|
226 | htrans := r.htrans; hwrite := r.hwrite; | |
|
227 | else | |
|
228 | haddr := ahbsi.haddr; hsize := ahbsi.hsize(1 downto 0); | |
|
229 | htrans := ahbsi.htrans; hwrite := ahbsi.hwrite; | |
|
230 | -- addr must be masked since address range can be smaller than | |
|
231 | -- total banksize. this can result in wrong chip select being | |
|
232 | -- asserted | |
|
233 | for i in 31 downto 20 loop | |
|
234 | haddr(i) := ahbsi.haddr(i) and not std_rammask(i); | |
|
235 | end loop; | |
|
236 | end if; | |
|
237 | if fast = 1 then haddr := r.haddr; end if; | |
|
238 | ||
|
239 | if ahbsi.hready = '1' then v.hsel := ahbsi.hsel(hindex); end if; | |
|
240 | ||
|
241 | -- main state | |
|
242 | if BUS16 then | |
|
243 | case r.size is | |
|
244 | when "00" => --bytesize | |
|
245 | case r.haddr(0) is | |
|
246 | when '0' => dqm := "11111101"; | |
|
247 | when others => dqm := "11111110"; | |
|
248 | end case; | |
|
249 | when others => dqm := "11111100"; --halfword, word | |
|
250 | end case; | |
|
251 | else | |
|
252 | case r.size is | |
|
253 | when "00" => | |
|
254 | case r.haddr(1 downto 0) is | |
|
255 | when "00" => dqm := "11110111"; | |
|
256 | when "01" => dqm := "11111011"; | |
|
257 | when "10" => dqm := "11111101"; | |
|
258 | when others => dqm := "11111110"; | |
|
259 | end case; | |
|
260 | when "01" => | |
|
261 | if r.haddr(1) = '0' then dqm := "11110011"; else dqm := "11111100"; end if; | |
|
262 | when others => dqm := "11110000"; | |
|
263 | end case; | |
|
264 | end if; | |
|
265 | -- | |
|
266 | -- case r.size is | |
|
267 | -- when "00" => | |
|
268 | -- case r.haddr(1 downto 0) is | |
|
269 | -- when "00" => dqm := "11111101"; lhw := '0'; --lhv := r.haddr(1) | |
|
270 | -- when "01" => dqm := "11111110"; lhw := '0'; | |
|
271 | -- when "10" => dqm := "11111101"; lhw := '1'; | |
|
272 | -- when others => dqm := "11111110"; lhw := '1'; | |
|
273 | -- end case; | |
|
274 | -- when "01" => | |
|
275 | -- dqm := "11111100"; | |
|
276 | -- if r.haddr(1) = '0' then | |
|
277 | -- lhw := '0'; | |
|
278 | -- else | |
|
279 | -- lhw := '1'; | |
|
280 | -- end if; | |
|
281 | -- when others => dqm := "11111100"; --remember when word: lhw first 0 then 1 | |
|
282 | -- end case; | |
|
283 | -- | |
|
284 | if BUS64 and (r.bsel = '1') then dqm := dqm(3 downto 0) & "1111"; end if; | |
|
285 | ||
|
286 | -- main FSM | |
|
287 | ||
|
288 | case r.mstate is | |
|
289 | when midle => | |
|
290 | if ((v.hsel and htrans(1) and not v.hio) = '1') then | |
|
291 | if (r.sdstate = sidle) and (r.cfg.command = "000") | |
|
292 | and (r.cmstate = midle) and (v.hio = '0') | |
|
293 | then | |
|
294 | if fast = 0 then startsd := '1'; else v.startsd := '1'; end if; | |
|
295 | v.mstate := active; | |
|
296 | elsif ((r.sdstate = sref) or (r.sdstate = pd) or (r.sdstate = dpd)) | |
|
297 | and (r.cfg.command = "000") and (r.cmstate = midle) and (v.hio = '0') | |
|
298 | then | |
|
299 | v.startsd := '1'; | |
|
300 | if r.sdstate = dpd then -- Error response when on Deep Power-Down mode | |
|
301 | v.hresp := HRESP_ERROR; | |
|
302 | else | |
|
303 | v.mstate := active; | |
|
304 | end if; | |
|
305 | end if; | |
|
306 | end if; | |
|
307 | when others => null; | |
|
308 | end case; | |
|
309 | ||
|
310 | startsd := startsd or r.startsd; | |
|
311 | ||
|
312 | -- generate row and column address size | |
|
313 | ||
|
314 | if BUS16 then | |
|
315 | case r.cfg.csize is | |
|
316 | when "00" => raddr := haddr(21 downto 9);-- case to check for bursting over row limit, since 1 row is 512 byte. | |
|
317 | when "01" => raddr := haddr(22 downto 10); | |
|
318 | when "10" => raddr := haddr(23 downto 11); | |
|
319 | when others => | |
|
320 | if r.cfg.bsize = "110" then raddr := haddr(25 downto 13); --tänk | |
|
321 | else raddr := haddr(24 downto 12); end if; | |
|
322 | end case; | |
|
323 | else | |
|
324 | case r.cfg.csize is | |
|
325 | when "00" => raddr := haddr(22 downto 10); | |
|
326 | when "01" => raddr := haddr(23 downto 11); | |
|
327 | when "10" => raddr := haddr(24 downto 12); | |
|
328 | when others => | |
|
329 | if r.cfg.bsize = "111" then raddr := haddr(26 downto 14); | |
|
330 | else raddr := haddr(25 downto 13); end if; | |
|
331 | end case; | |
|
332 | end if; | |
|
333 | ||
|
334 | -- generate bank address | |
|
335 | -- if BUS16 then --011 | |
|
336 | -- ba := genmux(r.cfg.bsize, haddr(26 downto 19)) & | |
|
337 | -- genmux(r.cfg.bsize, haddr(25 downto 18)); | |
|
338 | -- else | |
|
339 | ba := genmux(r.cfg.bsize, haddr(28 downto 21)) & | |
|
340 | genmux(r.cfg.bsize, haddr(27 downto 20)); | |
|
341 | -- end if; | |
|
342 | ||
|
343 | -- generate chip select | |
|
344 | ||
|
345 | if BUS64 then | |
|
346 | adec := genmux(r.cfg.bsize, haddr(30 downto 23)); | |
|
347 | v.bsel := genmux(r.cfg.bsize, r.haddr(29 downto 22)); | |
|
348 | else | |
|
349 | adec := genmux(r.cfg.bsize, haddr(29 downto 22)); v.bsel := '0'; | |
|
350 | end if; | |
|
351 | -- elsif BUS32 then | |
|
352 | -- adec := genmux(r.cfg.bsize, haddr(29 downto 22)); v.bsel := '0'; | |
|
353 | -- else | |
|
354 | -- adec := genmux(r.cfg.bsize, haddr(27 downto 20)); v.bsel := '0'; | |
|
355 | -- end if; | |
|
356 | ||
|
357 | rams := adec & not adec; | |
|
358 | ||
|
359 | -- sdram access FSM | |
|
360 | ||
|
361 | if r.trfc /= "0000" then v.trfc := r.trfc - 1; end if; | |
|
362 | ||
|
363 | if r.idlecnt /= "0000" then v.idlecnt := r.idlecnt - 1; end if; | |
|
364 | ||
|
365 | case r.sdstate is | |
|
366 | ||
|
367 | when sidle => | |
|
368 | if (startsd = '1') and (r.cfg.command = "000") and (r.cmstate = midle) then | |
|
369 | -- if BUS16 then | |
|
370 | -- v.address(16 downto 2) := '0' & ba & raddr(11 downto 0); --since 1 bit lower row => tot adress field 14 bits | |
|
371 | -- else | |
|
372 | v.address(16 downto 2) := ba & raddr; -- ba(16-15) & raddr(14-2) (2+13= 15 bits) | |
|
373 | -- end if; | |
|
374 | v.sdcsn := not rams(1 downto 0); v.rasn := '0'; v.sdstate := act1; | |
|
375 | v.startsd := '0'; | |
|
376 | elsif (r.idlecnt = "0000") and (r.cfg.command = "000") | |
|
377 | and (r.cmstate = midle) and (r.cfg.mobileen(1) = '1') then | |
|
378 | case r.cfg.pmode is | |
|
379 | when PM_SR => | |
|
380 | v.cfg.cke := '0'; v.sdstate := sref; | |
|
381 | v.sdcsn := (others => '0'); v.rasn := '0'; v.casn := '0'; | |
|
382 | v.trfc := (r.cfg.trp and r.cfg.mobileen(1)) & r.cfg.trfc; -- Control minimum duration of Self Refresh mode (= tRAS) | |
|
383 | when PM_PD => v.cfg.cke := '0'; v.sdstate := pd; | |
|
384 | when PM_DPD => | |
|
385 | v.cfg.cke := '0'; v.sdstate := dpd; | |
|
386 | v.sdcsn := (others => '0'); v.sdwen := '0'; v.rasn := '1'; v.casn := '1'; | |
|
387 | when others => | |
|
388 | end case; | |
|
389 | end if; | |
|
390 | ||
|
391 | when act1 => | |
|
392 | v.rasn := '1'; v.trfc := (r.cfg.trp and r.cfg.mobileen(1)) & r.cfg.trfc; | |
|
393 | if r.cfg.casdel = '1' then v.sdstate := act2; else | |
|
394 | v.sdstate := act3; | |
|
395 | if not BUS16 then -- needs if, otherwise it might clock in incorrect write data to state act3_16 | |
|
396 | v.hready := r.hwrite and ahbsi.htrans(0) and ahbsi.htrans(1); | |
|
397 | end if; | |
|
398 | end if; | |
|
399 | if WPROTEN then | |
|
400 | v.wprothit := sdi.wprot; | |
|
401 | if sdi.wprot = '1' then v.hresp := HRESP_ERROR; end if; | |
|
402 | end if; | |
|
403 | ||
|
404 | when act2 => | |
|
405 | v.sdstate := act3; | |
|
406 | if not BUS16 then | |
|
407 | v.hready := r.hwrite and ahbsi.htrans(0) and ahbsi.htrans(1); | |
|
408 | end if; | |
|
409 | if WPROTEN and (r.wprothit = '1') then | |
|
410 | v.hresp := HRESP_ERROR; v.hready := '0'; | |
|
411 | end if; | |
|
412 | ||
|
413 | when act3 => | |
|
414 | v.casn := '0'; | |
|
415 | if BUS16 then --HW adress needed to memory | |
|
416 | v.address(14 downto 2) := r.haddr(12 downto 11) & '0' & r.haddr(10 downto 1); --only allowed to use tot adressbits - ba bits | |
|
417 | -- v.address(13 downto 2) := r.haddr(11) & '0' & r.haddr(10 downto 1); --only allowed to use tot adressbits - ba bits | |
|
418 | v.lhw := r.haddr(1); -- 14-2 = 12 colummn bits => 13 downto 2 | |
|
419 | else | |
|
420 | v.address(14 downto 2) := r.haddr(13 downto 12) & '0' & r.haddr(11 downto 2); | |
|
421 | end if; | |
|
422 | v.dqm := dqm; v.burst := r.hready; -- ?? | |
|
423 | ||
|
424 | if r.hwrite = '1' then | |
|
425 | ||
|
426 | if BUS16 then --16 bit | |
|
427 | if r.size(1) = '1' then --word | |
|
428 | v.hready := ahbsi.htrans(0) and ahbsi.htrans(1); --delayed this check 1 state to keep write data correct in act3_16 | |
|
429 | v.burst := ahbsi.htrans(0) and ahbsi.htrans(1); | |
|
430 | v.sdstate := act3_16; -- goto state for second part of word transfer | |
|
431 | -- v.lhw := '0'; --write MSB 16 bits to AMBA adress that ends with 00 | |
|
432 | else --halfword or byte | |
|
433 | v.sdstate := act3_16; v.hready := '1'; | |
|
434 | end if; | |
|
435 | else --32 bit or 64 | |
|
436 | v.sdstate := wr1; | |
|
437 | if ahbsi.htrans = "11" or (r.hready = '0') then v.hready := '1'; end if; | |
|
438 | end if; | |
|
439 | v.sdwen := '0'; v.bdrive := '0'; --write | |
|
440 | if WPROTEN and (r.wprothit = '1') then | |
|
441 | v.hresp := HRESP_ERROR; v.hready := '1'; | |
|
442 | if BUS16 then v.sdstate := act3_16; else v.sdstate := wr1; end if; | |
|
443 | v.sdwen := '1'; v.bdrive := '1'; v.casn := '1'; --skip write, remember hready high in next state | |
|
444 | end if; | |
|
445 | else v.sdstate := rd1; end if; | |
|
446 | ||
|
447 | when act3_16 => --handle 16 bit and WORD write | |
|
448 | v.address(14 downto 2) := r.haddr(12 downto 11) & '0' & r.haddr(10 downto 2) & '1'; | |
|
449 | -- v.address(13 downto 2) := r.haddr(11) & '0' & r.haddr(10 downto 2) & '1'; | |
|
450 | v.lhw := '1'; | |
|
451 | if (r.hready and r.burst) = '1' and not (WPROTEN and (r.wprothit = '1')) then | |
|
452 | v.hready := '0'; --kolla på transfertyp nonseq om vi vill delaya nedankoll. | |
|
453 | if( ahbsi.htrans = "11" and | |
|
454 | not ((r.haddr(5 downto 2) = "1111") and (r.cfg.command = "100")) and | |
|
455 | not ((r.haddr(9) xor ahbsi.haddr(9)) = '1' and r.cfg.csize = "00") ) then | |
|
456 | v.sdstate := wr1_16; | |
|
457 | end if; | |
|
458 | elsif r.burst = '1' or (r.hready and not r.burst) = '1' then --terminate burst or single write | |
|
459 | v.sdstate := wr2; v.bdrive := '1'; v.casn := '1'; v.sdwen := '1'; | |
|
460 | v.dqm := (others => '1'); | |
|
461 | else -- complete single write | |
|
462 | v.hready := '1'; | |
|
463 | v.sdstate := act3_16; --gick till wr1 förut | |
|
464 | end if; | |
|
465 | ||
|
466 | when wr1_16 => | |
|
467 | v.address(14 downto 2) := r.haddr(12 downto 11) & '0' & r.haddr(10 downto 1); | |
|
468 | -- v.address(13 downto 2) := r.haddr(11) & '0' & r.haddr(10 downto 1); | |
|
469 | v.lhw := r.haddr(1); | |
|
470 | v.sdstate := act3_16; | |
|
471 | v.hready := '1'; | |
|
472 | ||
|
473 | when wr1 => | |
|
474 | v.address(14 downto 2) := r.haddr(13 downto 12) & '0' & r.haddr(11 downto 2); | |
|
475 | if (((r.burst and r.hready) = '1') and (r.htrans = "11")) | |
|
476 | and not (WPROTEN and (r.wprothit = '1')) | |
|
477 | then | |
|
478 | v.hready := ahbsi.htrans(0) and ahbsi.htrans(1) and r.hready; | |
|
479 | if ((r.haddr(5 downto 2) = "1111") and (r.cfg.command = "100")) then -- exit on refresh | |
|
480 | v.hready := '0'; | |
|
481 | end if; | |
|
482 | else | |
|
483 | v.sdstate := wr2; v.bdrive := '1'; v.casn := '1'; v.sdwen := '1'; | |
|
484 | v.dqm := (others => '1'); | |
|
485 | end if; | |
|
486 | ||
|
487 | when wr2 => | |
|
488 | if (r.cfg.trp = '0') then v.rasn := '0'; v.sdwen := '0'; end if; | |
|
489 | v.sdstate := wr3; | |
|
490 | ||
|
491 | when wr3 => | |
|
492 | if (r.cfg.trp = '1') then | |
|
493 | v.rasn := '0'; v.sdwen := '0'; v.sdstate := wr4; | |
|
494 | else | |
|
495 | v.sdcsn := "11"; v.rasn := '1'; v.sdwen := '1'; v.sdstate := sidle; | |
|
496 | v.idlecnt := (others => '1'); | |
|
497 | end if; | |
|
498 | ||
|
499 | when wr4 => | |
|
500 | v.sdcsn := "11"; v.rasn := '1'; v.sdwen := '1'; | |
|
501 | if (r.cfg.trp = '1') then v.sdstate := wr5; | |
|
502 | else v.sdstate := sidle; v.idlecnt := (others => '1'); end if; | |
|
503 | ||
|
504 | when wr5 => | |
|
505 | v.sdstate := sidle; v.idlecnt := (others => '1'); | |
|
506 | ||
|
507 | when rd1 => --first read applied to sdram | |
|
508 | v.casn := '1'; v.sdstate := rd7; --nop | |
|
509 | if not BUS16 then --starting adress cannot be XXXX...111 since we have word burst in this case. and lowest bit always 0. | |
|
510 | if lineburst and (ahbsi.htrans = "11") then | |
|
511 | if r.haddr(4 downto 2) = "111" then | |
|
512 | v.address(9 downto 5) := r.address(9 downto 5) + 1; --adds only within 1KB limit. | |
|
513 | v.address(4 downto 2) := "000"; v.casn := '0'; | |
|
514 | end if; | |
|
515 | end if; | |
|
516 | end if; | |
|
517 | ||
|
518 | when rd7 => | |
|
519 | v.casn := '1'; --nop | |
|
520 | if BUS16 then | |
|
521 | if r.cfg.casdel = '1' then --casdel3 | |
|
522 | v.sdstate := rd2; | |
|
523 | if lineburst and (ahbsi.htrans = "11") then | |
|
524 | if r.haddr(3 downto 1) = "110" then | |
|
525 | v.address(10 downto 5) := r.address(10 downto 5) + 1; | |
|
526 | v.address(4 downto 2) := "000"; v.casn := '0'; | |
|
527 | end if; | |
|
528 | end if; | |
|
529 | else --casdel2 | |
|
530 | v.sdstate := rd3; | |
|
531 | if ahbsi.htrans /= "11" then | |
|
532 | if (r.trfc(3 downto 1) = "000") then v.rasn := '0'; v.sdwen := '0'; end if; | |
|
533 | elsif lineburst then | |
|
534 | if r.haddr(3 downto 1) = "110" then | |
|
535 | v.address(10 downto 5) := r.address(10 downto 5) + 1; | |
|
536 | v.address(4 downto 2) := "000"; v.casn := '0'; | |
|
537 | end if; | |
|
538 | end if; | |
|
539 | end if; | |
|
540 | else -- 32 bit or larger | |
|
541 | if r.cfg.casdel = '1' then --casdel3 | |
|
542 | v.sdstate := rd2; | |
|
543 | if lineburst and (ahbsi.htrans = "11") then | |
|
544 | if r.haddr(4 downto 2) = "110" then | |
|
545 | v.address(9 downto 5) := r.address(9 downto 5) + 1; | |
|
546 | v.address(4 downto 2) := "000"; v.casn := '0'; | |
|
547 | end if; | |
|
548 | end if; | |
|
549 | else --casdel2 | |
|
550 | v.sdstate := rd3; | |
|
551 | if ahbsi.htrans /= "11" then | |
|
552 | if (r.trfc(3 downto 1) = "000") then v.rasn := '0'; v.sdwen := '0'; end if; --precharge | |
|
553 | elsif lineburst then | |
|
554 | if r.haddr(4 downto 2) = "110" then | |
|
555 | v.address(9 downto 5) := r.address(9 downto 5) + 1; | |
|
556 | v.address(4 downto 2) := "000"; v.casn := '0'; | |
|
557 | end if; | |
|
558 | end if; | |
|
559 | end if; | |
|
560 | end if; | |
|
561 | ||
|
562 | when rd2 => | |
|
563 | v.casn := '1'; v.sdstate := rd3; | |
|
564 | if BUS16 then | |
|
565 | if ahbsi.htrans /= "11" then | |
|
566 | v.rasn := '0'; v.sdwen := '0'; v.dqm := (others => '1'); --precharge & DQM | |
|
567 | --note that DQM always has 2 cycle delay before blocking data. So NP if we fetch second HW | |
|
568 | end if; | |
|
569 | else | |
|
570 | if ahbsi.htrans /= "11" then v.rasn := '0'; v.sdwen := '0'; v.dqm := (others => '1'); --precharge & DQM | |
|
571 | elsif lineburst then | |
|
572 | if r.haddr(4 downto 2) = "101" then | |
|
573 | v.address(9 downto 5) := r.address(9 downto 5) + 1; | |
|
574 | v.address(4 downto 2) := "000"; v.casn := '0'; | |
|
575 | end if; | |
|
576 | end if; | |
|
577 | end if; | |
|
578 | ||
|
579 | when rd3 => --first read data from sdram output v.lhw := r.haddr(1); | |
|
580 | v.casn := '1'; --if read before cas makes nop else if pre => no difference | |
|
581 | if BUS16 then | |
|
582 | --note if read is for halfwor or byte we dont want to read a second time but exit. | |
|
583 | --if the read is a word we need to change LHW to one since the next read should be muxed in next cylcle. | |
|
584 | -- if r.size(1) = '1' then --word v.hready := not r.size(1) | |
|
585 | -- v.sdstate := rd4_16; v.hready := '0'; --hready low since just first part of a word | |
|
586 | -- v.lhw := '1'; -- read low 16 next state | |
|
587 | -- else --HW or byte | |
|
588 | -- v.sdstate := rd4_16; v.hready := '1'; | |
|
589 | -- end if; | |
|
590 | v.sdstate := rd4_16; | |
|
591 | v.lhw := not r.lhw; --r.lhw is 0 for word, we should invert for next half of word.For HW or Byte v.lhw does not matter. | |
|
592 | v.hready := not r.size(1); --if word transfer the r.size(1) is 1 and hready goes low.If HW or byte r.size(1)=0 => hready=1 | |
|
593 | if r.sdwen = '0' then | |
|
594 | v.rasn := '1'; v.sdwen := '1'; v.sdcsn := "11"; v.dqm := (others => '1'); -- make DSEL (NOP) | |
|
595 | elsif lineburst and ((ahbsi.htrans = "11") and (r.cfg.casdel = '1')) then --only enter if cl3 | |
|
596 | if r.haddr(3 downto 1) = "100" then | |
|
597 | v.address(10 downto 5) := r.address(10 downto 5) + 1; | |
|
598 | v.address(4 downto 2) := "000"; v.casn := '0'; | |
|
599 | end if; | |
|
600 | end if; | |
|
601 | else --32 bit or larger | |
|
602 | v.sdstate := rd4; v.hready := '1'; | |
|
603 | if r.sdwen = '0' then | |
|
604 | v.rasn := '1'; v.sdwen := '1'; v.sdcsn := "11"; v.dqm := (others => '1'); -- make DSEL (NOP) | |
|
605 | elsif lineburst and (ahbsi.htrans = "11") and (r.casn = '1') then | |
|
606 | if r.haddr(4 downto 2) = ("10" & not r.cfg.casdel) then | |
|
607 | v.address(9 downto 5) := r.address(9 downto 5) + 1; | |
|
608 | v.address(4 downto 2) := "000"; v.casn := '0'; | |
|
609 | end if; | |
|
610 | end if; | |
|
611 | end if; | |
|
612 | ||
|
613 | when rd4_16 => --enter as word (r.hready is still 0) else 1. If hready one next transfer sampled into v. | |
|
614 | --v.hready := '1'; | |
|
615 | v.hready := not r.hready;-- if Byte or HW exit with hready low. If word flip bit, makes correct exit with hready low. | |
|
616 | v.lhw := not r.lhw; --r.lhw is one the first time we enter (taking care of second part of word) | |
|
617 | v.casn := '1'; | |
|
618 | --quit on: Single transfer CL 2/3 (prcharge if CL 2 and timer was not 0) | |
|
619 | if (ahbsi.htrans /= "11" and (r.hready = '1')) or | |
|
620 | ((r.haddr(9) xor ahbsi.haddr(9)) = '1' and r.cfg.csize = "00" and r.hready = '1') or --probably dont have to check hready 1 since if 0 adresses equal. | |
|
621 | ((r.haddr(5 downto 2) = "1111") and (r.cfg.command = "100") and (r.hready = '1')) then --quit on: ST W/HW/BYTE OR | |
|
622 | --v.hready := '0'; --if Byte or HW exit with hready low, if ST word exit with high. | |
|
623 | v.dqm := (others => '1'); | |
|
624 | if r.sdcsn /= "11" then --not prechargeing | |
|
625 | v.rasn := '0'; v.sdwen := '0'; v.sdstate := rd5; --precharge | |
|
626 | else--exit | |
|
627 | if r.cfg.trp = '1' then v.sdstate := rd6; | |
|
628 | else v.sdstate := sidle; v.idlecnt := (others => '1'); end if; | |
|
629 | end if; | |
|
630 | elsif lineburst then --NOTE: r.casn = 1 makes sure its the first halfword of a word that is checked (hready low) | |
|
631 | if r.cfg.casdel = '0' then | |
|
632 | if (r.haddr(3 downto 1) = "100") and (r.casn = '1') then --lline = 011 if casdel =1, 100 if casdel= 0 | |
|
633 | v.address(10 downto 5) := r.address(10 downto 5) + 1; | |
|
634 | v.address(4 downto 2) := "000"; v.casn := '0'; | |
|
635 | end if; | |
|
636 | else | |
|
637 | if (r.haddr(3 downto 1) = "010") and (r.hready = '1') then --lline = 011 if casdel =1, 100 if casdel= 0 | |
|
638 | v.address(10 downto 5) := r.address(10 downto 5) + 1; | |
|
639 | v.address(4 downto 2) := "000"; v.casn := '0'; | |
|
640 | end if; | |
|
641 | end if; | |
|
642 | end if; | |
|
643 | ||
|
644 | when rd4 => | |
|
645 | v.hready := '1'; v.casn := '1'; | |
|
646 | if (ahbsi.htrans /= "11") or (r.sdcsn = "11") or | |
|
647 | ((r.haddr(5 downto 2) = "1111") and (r.cfg.command = "100")) -- exit on refresh | |
|
648 | then | |
|
649 | v.hready := '0'; v.dqm := (others => '1'); | |
|
650 | if (r.sdcsn /= "11") then | |
|
651 | v.rasn := '0'; v.sdwen := '0'; v.sdstate := rd5; | |
|
652 | else | |
|
653 | if r.cfg.trp = '1' then v.sdstate := rd6; | |
|
654 | else v.sdstate := sidle; v.idlecnt := (others => '1'); end if; | |
|
655 | end if; | |
|
656 | elsif lineburst then | |
|
657 | if (r.haddr(4 downto 2) = lline) and (r.casn = '1') then | |
|
658 | v.address(9 downto 5) := r.address(9 downto 5) + 1; | |
|
659 | v.address(4 downto 2) := "000"; v.casn := '0'; | |
|
660 | end if; | |
|
661 | end if; | |
|
662 | ||
|
663 | when rd5 => | |
|
664 | if r.cfg.trp = '1' then v.sdstate := rd6; else v.sdstate := sidle; v.idlecnt := (others => '1'); end if; | |
|
665 | v.sdcsn := (others => '1'); v.rasn := '1'; v.sdwen := '1'; v.dqm := (others => '1'); | |
|
666 | v.casn := '1'; | |
|
667 | ||
|
668 | when rd6 => | |
|
669 | v.sdstate := sidle; v.idlecnt := (others => '1'); v.dqm := (others => '1'); | |
|
670 | v.sdcsn := (others => '1'); v.rasn := '1'; v.sdwen := '1'; | |
|
671 | ||
|
672 | when sref => | |
|
673 | if (startsd = '1' and (r.hio = '0')) | |
|
674 | or (r.cfg.command /= "000") or r.cfg.pmode /= PM_SR then | |
|
675 | if r.trfc = "0000" then -- Minimum duration (= tRAS) | |
|
676 | v.cfg.cke := '1'; | |
|
677 | v.sdcsn := (others => '0'); v.rasn := '1'; v.casn := '1'; | |
|
678 | end if; | |
|
679 | if r.cfg.cke = '1' then | |
|
680 | if (r.idlecnt = "0000") then -- tXSR ns with NOP | |
|
681 | v.sdstate := sidle; | |
|
682 | v.idlecnt := (others => '1'); | |
|
683 | v.sref_tmpcom := r.cfg.command; | |
|
684 | v.cfg.command := "100"; | |
|
685 | end if; | |
|
686 | else | |
|
687 | v.idlecnt := r.cfg.txsr; | |
|
688 | end if; | |
|
689 | end if; | |
|
690 | ||
|
691 | when pd => | |
|
692 | if (startsd = '1' and (r.hio = '0')) | |
|
693 | or (r.cfg.command /= "000") or r.cfg.pmode /= PM_PD then | |
|
694 | v.cfg.cke := '1'; | |
|
695 | v.sdstate := sidle; | |
|
696 | v.idlecnt := (others => '1'); | |
|
697 | end if; | |
|
698 | ||
|
699 | when dpd => | |
|
700 | v.sdcsn := (others => '1'); v.sdwen := '1'; v.rasn := '1'; v.casn := '1'; | |
|
701 | v.cfg.renable := '0'; | |
|
702 | if (startsd = '1' and r.hio = '0') then | |
|
703 | v.hready := '1'; -- ack all accesses with Error response | |
|
704 | v.startsd := '0'; | |
|
705 | v.hresp := HRESP_ERROR; | |
|
706 | elsif r.cfg.pmode /= PM_DPD then | |
|
707 | v.cfg.cke := '1'; | |
|
708 | if r.cfg.cke = '1' then | |
|
709 | v.sdstate := sidle; | |
|
710 | v.idlecnt := (others => '1'); | |
|
711 | v.cfg.renable := '1'; | |
|
712 | end if; | |
|
713 | end if; | |
|
714 | ||
|
715 | when others => | |
|
716 | v.sdstate := sidle; v.idlecnt := (others => '1'); | |
|
717 | end case; | |
|
718 | ||
|
719 | -- sdram commands | |
|
720 | ||
|
721 | case r.cmstate is | |
|
722 | when midle => | |
|
723 | if r.sdstate = sidle then | |
|
724 | case r.cfg.command is | |
|
725 | when "010" => -- precharge | |
|
726 | v.sdcsn := (others => '0'); v.rasn := '0'; v.sdwen := '0'; | |
|
727 | v.address(12) := '1'; v.cmstate := active; | |
|
728 | when "100" => -- auto-refresh | |
|
729 | v.sdcsn := (others => '0'); v.rasn := '0'; v.casn := '0'; | |
|
730 | v.cmstate := active; | |
|
731 | when "110" => -- Lodad Mode Reg | |
|
732 | v.sdcsn := (others => '0'); v.rasn := '0'; v.casn := '0'; | |
|
733 | v.sdwen := '0'; v.cmstate := active; | |
|
734 | if lineburst then | |
|
735 | v.address(16 downto 2) := "0000010001" & r.cfg.casdel & "0011"; | |
|
736 | else | |
|
737 | v.address(16 downto 2) := "0000010001" & r.cfg.casdel & "0111"; | |
|
738 | end if; | |
|
739 | when "111" => -- Load Ext-Mode Reg | |
|
740 | v.sdcsn := (others => '0'); v.rasn := '0'; v.casn := '0'; | |
|
741 | v.sdwen := '0'; v.cmstate := active; | |
|
742 | v.address(16 downto 2) := "10000000" & r.cfg.ds(1 downto 0) & r.cfg.tcsr(1 downto 0) | |
|
743 | & r.cfg.pasr(2 downto 0); | |
|
744 | when others => null; | |
|
745 | end case; | |
|
746 | end if; | |
|
747 | when active => | |
|
748 | v.sdcsn := (others => '1'); v.rasn := '1'; v.casn := '1'; | |
|
749 | v.sdwen := '1'; --v.cfg.command := "000"; | |
|
750 | v.cfg.command := r.sref_tmpcom; v.sref_tmpcom := "000"; | |
|
751 | v.cmstate := leadout; v.trfc := (r.cfg.trp and r.cfg.mobileen(1)) & r.cfg.trfc; | |
|
752 | when leadout => | |
|
753 | if r.trfc = "0000" then v.cmstate := midle; end if; | |
|
754 | ||
|
755 | end case; | |
|
756 | ||
|
757 | -- sdram init | |
|
758 | ||
|
759 | case r.istate is | |
|
760 | when iidle => | |
|
761 | v.cfg.cke := '1'; | |
|
762 | if r.cfg.renable = '1' and r.cfg.cke = '1' then | |
|
763 | v.cfg.command := "010"; v.istate := pre; | |
|
764 | end if; | |
|
765 | when pre => | |
|
766 | if r.cfg.command = "000" then | |
|
767 | v.cfg.command := "100"; v.istate := ref; v.icnt := "111"; | |
|
768 | end if; | |
|
769 | when ref => | |
|
770 | if r.cfg.command = "000" then | |
|
771 | v.cfg.command := "100"; v.icnt := r.icnt - 1; | |
|
772 | if r.icnt = "000" then v.istate := lmode; v.cfg.command := "110"; end if; | |
|
773 | end if; | |
|
774 | when lmode => | |
|
775 | if r.cfg.command = "000" then | |
|
776 | if r.cfg.mobileen = "11" then | |
|
777 | v.cfg.command := "111"; v.istate := emode; | |
|
778 | else | |
|
779 | v.istate := finish; | |
|
780 | end if; | |
|
781 | end if; | |
|
782 | when emode => | |
|
783 | if r.cfg.command = "000" then | |
|
784 | v.istate := finish; | |
|
785 | end if; | |
|
786 | when others => | |
|
787 | if r.cfg.renable = '0' and r.sdstate /= dpd then | |
|
788 | v.istate := iidle; | |
|
789 | end if; | |
|
790 | end case; | |
|
791 | ||
|
792 | if (ahbsi.hready and ahbsi.hsel(hindex) ) = '1' then | |
|
793 | if ahbsi.htrans(1) = '0' then v.hready := '1'; end if; | |
|
794 | end if; | |
|
795 | ||
|
796 | if (r.hsel and r.hio and not r.hready) = '1' then v.hready := '1'; end if; | |
|
797 | ||
|
798 | -- second part of main fsm | |
|
799 | ||
|
800 | case r.mstate is | |
|
801 | when active => | |
|
802 | if v.hready = '1' then | |
|
803 | v.mstate := midle; | |
|
804 | end if; | |
|
805 | when others => null; | |
|
806 | end case; | |
|
807 | ||
|
808 | -- sdram refresh counter | |
|
809 | ||
|
810 | -- pragma translate_off | |
|
811 | if not is_x(r.cfg.refresh) then | |
|
812 | -- pragma translate_on | |
|
813 | if (r.cfg.renable = '1') and (r.istate = finish) and r.sdstate /= sref then | |
|
814 | v.refresh := r.refresh - 1; | |
|
815 | if (v.refresh(14) and not r.refresh(14)) = '1' then | |
|
816 | v.refresh := r.cfg.refresh; | |
|
817 | v.cfg.command := "100"; | |
|
818 | arefresh := '1'; | |
|
819 | end if; | |
|
820 | end if; | |
|
821 | -- pragma translate_off | |
|
822 | end if; | |
|
823 | -- pragma translate_on | |
|
824 | ||
|
825 | -- AHB register access | |
|
826 | -- if writing to IO space config regs. Just mapping write data to all config values in config reg | |
|
827 | if (r.hsel and r.hio and r.hwrite and r.htrans(1)) = '1' then | |
|
828 | if r.haddr(3 downto 2) = "00" then | |
|
829 | if pageburst = 2 then v.cfg.pageburst := hwdata(17); end if; | |
|
830 | v.cfg.command := hwdata(20 downto 18); | |
|
831 | v.cfg.csize := hwdata(22 downto 21); | |
|
832 | v.cfg.bsize := hwdata(25 downto 23); | |
|
833 | v.cfg.casdel := hwdata(26); | |
|
834 | v.cfg.trfc := hwdata(29 downto 27); | |
|
835 | v.cfg.trp := hwdata(30); | |
|
836 | v.cfg.renable := hwdata(31); | |
|
837 | v.cfg.refresh := hwdata(14 downto 0); | |
|
838 | v.refresh := (others => '0'); | |
|
839 | elsif r.haddr(3 downto 2) = "01" then | |
|
840 | if r.cfg.mobileen(1) = '1' and mobile /= 3 then v.cfg.mobileen(0) := hwdata(31); end if; | |
|
841 | if r.cfg.pmode = "000" then | |
|
842 | v.cfg.cke := hwdata(30); | |
|
843 | end if; | |
|
844 | if r.cfg.mobileen(1) = '1' then | |
|
845 | v.cfg.txsr := hwdata(23 downto 20); | |
|
846 | v.cfg.pmode := hwdata(18 downto 16); | |
|
847 | v.cfg.ds(3 downto 2) := hwdata( 6 downto 5); | |
|
848 | v.cfg.tcsr(3 downto 2) := hwdata( 4 downto 3); | |
|
849 | v.cfg.pasr(5 downto 3) := hwdata( 2 downto 0); | |
|
850 | end if; | |
|
851 | end if; | |
|
852 | end if; | |
|
853 | ||
|
854 | -- Disable CS and DPD when Mobile SDR is Disabled | |
|
855 | if r.cfg.mobileen(0) = '0' then v.cfg.pmode(2) := '0'; end if; | |
|
856 | ||
|
857 | -- Update EMR when ds, tcsr or pasr change | |
|
858 | if r.cfg.command = "000" and arefresh = '0' and r.cfg.mobileen(0) = '1' then | |
|
859 | if r.cfg.ds(1 downto 0) /= r.cfg.ds(3 downto 2) then | |
|
860 | v.cfg.command := "111"; v.cfg.ds(1 downto 0) := r.cfg.ds(3 downto 2); | |
|
861 | end if; | |
|
862 | if r.cfg.tcsr(1 downto 0) /= r.cfg.tcsr(3 downto 2) then | |
|
863 | v.cfg.command := "111"; v.cfg.tcsr(1 downto 0) := r.cfg.tcsr(3 downto 2); | |
|
864 | end if; | |
|
865 | if r.cfg.pasr(2 downto 0) /= r.cfg.pasr(5 downto 3) then | |
|
866 | v.cfg.command := "111"; v.cfg.pasr(2 downto 0) := r.cfg.pasr(5 downto 3); | |
|
867 | end if; | |
|
868 | end if; | |
|
869 | ||
|
870 | regsd := (others => '0'); | |
|
871 | --reads out config registers (r/w does not matter) according to manual depending on address, notice generic determines data width. | |
|
872 | if r.haddr(3 downto 2) = "00" then | |
|
873 | regsd(31 downto 18) := r.cfg.renable & r.cfg.trp & r.cfg.trfc & | |
|
874 | r.cfg.casdel & r.cfg.bsize & r.cfg.csize & r.cfg.command; | |
|
875 | if not lineburst then regsd(17) := '1'; end if; | |
|
876 | regsd(16) := r.cfg.mobileen(1); | |
|
877 | if BUS64 then regsd(15) := '1'; end if; | |
|
878 | regsd(14 downto 0) := r.cfg.refresh; | |
|
879 | elsif r.haddr(3 downto 2) = "01" then | |
|
880 | regsd(31) := r.cfg.mobileen(0); | |
|
881 | regsd(30) := r.cfg.cke; | |
|
882 | regsd(23 downto 0) := r.cfg.txsr & '0' & r.cfg.pmode & "000000000" & | |
|
883 | r.cfg.ds(1 downto 0) & r.cfg.tcsr(1 downto 0) & r.cfg.pasr(2 downto 0); | |
|
884 | end if; | |
|
885 | ||
|
886 | if (r.hsel and r.hio) = '1' then dout := regsd; | |
|
887 | else | |
|
888 | if BUS64 and r.bsel = '1' then dout := r.hrdata(63 downto 32); | |
|
889 | else dout := r.hrdata(31 downto 0); end if; | |
|
890 | end if; | |
|
891 | ||
|
892 | v.nbdrive := not v.bdrive; | |
|
893 | ||
|
894 | if oepol = 1 then bdrive := r.nbdrive; vbdrive := (others => v.nbdrive); | |
|
895 | else bdrive := r.bdrive; vbdrive := (others => v.bdrive);end if; | |
|
896 | ||
|
897 | -- reset | |
|
898 | ||
|
899 | if rst = '0' then | |
|
900 | v.sdstate := sidle; | |
|
901 | v.mstate := midle; | |
|
902 | v.istate := iidle; | |
|
903 | v.cmstate := midle; | |
|
904 | v.hsel := '0'; | |
|
905 | v.cfg.command := "000"; | |
|
906 | v.cfg.csize := "01"; | |
|
907 | v.cfg.bsize := "011"; | |
|
908 | v.cfg.casdel := '1'; | |
|
909 | v.cfg.trfc := "111"; | |
|
910 | if pwron = 1 then v.cfg.renable := '1'; | |
|
911 | else v.cfg.renable := '0'; end if; | |
|
912 | v.cfg.trp := '1'; | |
|
913 | v.dqm := (others => '1'); | |
|
914 | v.sdwen := '1'; | |
|
915 | v.rasn := '1'; | |
|
916 | v.casn := '1'; | |
|
917 | v.hready := '1'; | |
|
918 | v.bsel := '0'; | |
|
919 | v.startsd := '0'; | |
|
920 | if (pageburst = 2) then | |
|
921 | v.cfg.pageburst := '0'; | |
|
922 | end if; | |
|
923 | if mobile >= 2 then v.cfg.mobileen := "11"; | |
|
924 | elsif mobile = 1 then v.cfg.mobileen := "10"; | |
|
925 | else v.cfg.mobileen := "00"; end if; | |
|
926 | v.cfg.txsr := (others => '1'); | |
|
927 | v.cfg.pmode := (others => '0'); | |
|
928 | v.cfg.ds := (others => '0'); | |
|
929 | v.cfg.tcsr := (others => '0'); | |
|
930 | v.cfg.pasr := (others => '0'); | |
|
931 | if mobile >= 2 then v.cfg.cke := '0'; | |
|
932 | else v.cfg.cke := '1'; end if; | |
|
933 | v.sref_tmpcom := "000"; | |
|
934 | v.idlecnt := (others => '1'); | |
|
935 | end if; | |
|
936 | ||
|
937 | ri <= v; | |
|
938 | ribdrive <= vbdrive; | |
|
939 | ||
|
940 | ahbso.hready <= r.hready; | |
|
941 | ahbso.hresp <= r.hresp; | |
|
942 | ahbso.hrdata <= ahbdrivedata(dout); | |
|
943 | ||
|
944 | end process; | |
|
945 | ||
|
946 | --sdo.sdcke <= (others => '1'); | |
|
947 | sdo.sdcke <= (others => r.cfg.cke); | |
|
948 | ahbso.hconfig <= hconfig; | |
|
949 | ahbso.hirq <= (others => '0'); | |
|
950 | ahbso.hindex <= hindex; | |
|
951 | ahbso.hsplit <= (others => '0'); | |
|
952 | ||
|
953 | -- Quick hack to get rid of undriven signal warnings. Check this for future | |
|
954 | -- merge with main sdctrl. | |
|
955 | drivehack : block | |
|
956 | begin | |
|
957 | sdo.qdrive <= '0'; | |
|
958 | sdo.nbdrive <= '0'; | |
|
959 | sdo.ce <= '0'; | |
|
960 | sdo.moben <= '0'; | |
|
961 | sdo.cal_rst <= '0'; | |
|
962 | sdo.oct <= '0'; | |
|
963 | sdo.xsdcsn <= (others => '1'); | |
|
964 | sdo.data(127 downto 16) <= (others => '0'); | |
|
965 | sdo.cb <= (others => '0'); | |
|
966 | sdo.ba <= (others => '0'); | |
|
967 | sdo.sdck <= (others => '0'); | |
|
968 | sdo.cal_en <= (others => '0'); | |
|
969 | sdo.cal_inc <= (others => '0'); | |
|
970 | sdo.cal_pll <= (others => '0'); | |
|
971 | sdo.odt <= (others => '0'); | |
|
972 | sdo.conf <= (others => '0'); | |
|
973 | sdo.vcbdrive <= (others => '0'); | |
|
974 | sdo.dqs_gate <= '0'; | |
|
975 | sdo.cbdqm <= (others => '0'); | |
|
976 | sdo.cbcal_en <= (others => '0'); | |
|
977 | sdo.cbcal_inc <= (others => '0'); | |
|
978 | sdo.read_pend <= (others => '0'); | |
|
979 | sdo.regwdata <= (others => '0'); | |
|
980 | sdo.regwrite <= (others => '0'); | |
|
981 | end block drivehack; | |
|
982 | ||
|
983 | regs : process(clk, rst) begin | |
|
984 | if rising_edge(clk) then | |
|
985 | r <= ri; rbdrive <= ribdrive; | |
|
986 | if rst = '0' then r.icnt <= (others => '0'); end if; | |
|
987 | end if; | |
|
988 | if (rst = '0') then | |
|
989 | r.sdcsn <= (others => '1'); r.bdrive <= '1'; r.nbdrive <= '0'; | |
|
990 | if oepol = 0 then rbdrive <= (others => '1'); | |
|
991 | else rbdrive <= (others => '0'); end if; | |
|
992 | end if; | |
|
993 | end process; | |
|
994 | ||
|
995 | rgen : if not SDINVCLK generate | |
|
996 | sdo.address <= r.address; | |
|
997 | sdo.bdrive <= r.nbdrive when oepol = 1 else r.bdrive; | |
|
998 | sdo.vbdrive <= zero32 & rbdrive; | |
|
999 | sdo.sdcsn <= r.sdcsn; | |
|
1000 | sdo.sdwen <= r.sdwen; | |
|
1001 | sdo.dqm <= "11111111" & r.dqm; | |
|
1002 | sdo.rasn <= r.rasn; | |
|
1003 | sdo.casn <= r.casn; | |
|
1004 | ||
|
1005 | mux16_wrdata : if BUS16 generate --mux data depending on Low/High HW | |
|
1006 | sdo.data(15 downto 0) <= r.hwdata(15 downto 0) when r.lhw = '1' else r.hwdata(31 downto 16); | |
|
1007 | end generate; | |
|
1008 | ||
|
1009 | wrdata : if not BUS16 generate | |
|
1010 | drivebus: for i in 0 to sdbits/64 generate | |
|
1011 | sdo.data(31+32*i downto 32*i) <= r.hwdata; | |
|
1012 | end generate; | |
|
1013 | end generate; | |
|
1014 | end generate; | |
|
1015 | ||
|
1016 | ngen : if SDINVCLK generate | |
|
1017 | nregs : process(clk, rst) begin | |
|
1018 | if falling_edge(clk) then | |
|
1019 | sdo.address <= r.address; | |
|
1020 | if oepol = 1 then sdo.bdrive <= r.nbdrive; | |
|
1021 | else sdo.bdrive <= r.bdrive; end if; | |
|
1022 | sdo.vbdrive <= zero32 & rbdrive; | |
|
1023 | sdo.sdcsn <= r.sdcsn; | |
|
1024 | sdo.sdwen <= r.sdwen; | |
|
1025 | sdo.dqm <= "11111111" & r.dqm; | |
|
1026 | sdo.rasn <= r.rasn; | |
|
1027 | sdo.casn <= r.casn; | |
|
1028 | if BUS16 then --mux data depending on Low/High HW | |
|
1029 | if (r.lhw ='1') then | |
|
1030 | sdo.data(15 downto 0) <= r.hwdata(15 downto 0); | |
|
1031 | else | |
|
1032 | sdo.data(15 downto 0) <= r.hwdata(31 downto 16); | |
|
1033 | end if; | |
|
1034 | end if; | |
|
1035 | ||
|
1036 | if not BUS16 then | |
|
1037 | for i in 0 to sdbits/64 loop | |
|
1038 | sdo.data(31+32*i downto 32*i) <= r.hwdata; | |
|
1039 | end loop; | |
|
1040 | end if; | |
|
1041 | end if; | |
|
1042 | if rst = '0' then sdo.sdcsn <= (others => '1'); end if; | |
|
1043 | end process; | |
|
1044 | end generate; | |
|
1045 | ||
|
1046 | -- pragma translate_off | |
|
1047 | bootmsg : report_version | |
|
1048 | generic map ("sdctrl16" & tost(hindex) & | |
|
1049 | ": PC133 SDRAM controller rev " & tost(REVISION)); | |
|
1050 | -- pragma translate_on | |
|
1051 | ||
|
1052 | end; | |
|
1053 |
@@ -0,0 +1,224 | |||
|
1 | ------------------------------------------------------------------------------ | |
|
2 | -- LEON3 Demonstration design test bench | |
|
3 | -- Copyright (C) 2004 Jiri Gaisler, Gaisler Research | |
|
4 | ------------------------------------------------------------------------------ | |
|
5 | ------------------------------------------------------------------------------ | |
|
6 | -- This file is a part of the GRLIB VHDL IP LIBRARY | |
|
7 | -- Copyright (C) 2003 - 2008, Gaisler Research | |
|
8 | -- Copyright (C) 2008 - 2014, Aeroflex Gaisler | |
|
9 | -- Copyright (C) 2015 - 2016, Cobham Gaisler | |
|
10 | -- | |
|
11 | -- This program is free software; you can redistribute it and/or modify | |
|
12 | -- it under the terms of the GNU General Public License as published by | |
|
13 | -- the Free Software Foundation; either version 2 of the License, or | |
|
14 | -- (at your option) any later version. | |
|
15 | -- | |
|
16 | -- This program is distributed in the hope that it will be useful, | |
|
17 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of | |
|
18 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
|
19 | -- GNU General Public License for more details. | |
|
20 | -- | |
|
21 | -- You should have received a copy of the GNU General Public License | |
|
22 | -- along with this program; if not, write to the Free Software | |
|
23 | -- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
|
24 | ||
|
25 | library ieee; | |
|
26 | use ieee.std_logic_1164.all; | |
|
27 | use ieee.numeric_std.all; | |
|
28 | library gaisler; | |
|
29 | use gaisler.libdcom.all; | |
|
30 | use gaisler.sim.all; | |
|
31 | use work.debug.all; | |
|
32 | library techmap; | |
|
33 | use techmap.gencomp.all; | |
|
34 | library micron; | |
|
35 | use micron.components.all; | |
|
36 | library grlib; | |
|
37 | use grlib.stdlib.all; | |
|
38 | ||
|
39 | use work.config.all; -- configuration | |
|
40 | ||
|
41 | ||
|
42 | entity testbench is | |
|
43 | generic ( | |
|
44 | fabtech : integer := CFG_FABTECH; | |
|
45 | memtech : integer := CFG_MEMTECH; | |
|
46 | padtech : integer := CFG_PADTECH; | |
|
47 | clktech : integer := CFG_CLKTECH; | |
|
48 | disas : integer := CFG_DISAS; -- Enable disassembly to console | |
|
49 | dbguart : integer := CFG_DUART; -- Print UART on console | |
|
50 | pclow : integer := CFG_PCLOW; | |
|
51 | ||
|
52 | clkperiod : integer := 20; -- system clock period | |
|
53 | romdepth : integer := 22 -- rom address depth (flash 4 MB) | |
|
54 | -- sramwidth : integer := 32; -- ram data width (8/16/32) | |
|
55 | -- sramdepth : integer := 20; -- ram address depth | |
|
56 | -- srambanks : integer := 2 -- number of ram banks | |
|
57 | ); | |
|
58 | end; | |
|
59 | ||
|
60 | architecture behav of testbench is | |
|
61 | ||
|
62 | constant promfile : string := "prom.srec"; -- rom contents | |
|
63 | constant sramfile : string := "ram.srec"; -- ram contents | |
|
64 | constant sdramfile : string := "ram.srec"; -- sdram contents | |
|
65 | ||
|
66 | ||
|
67 | signal SW : std_logic_vector(4 downto 1); | |
|
68 | signal clk : std_logic := '0'; | |
|
69 | signal Rst : std_logic := '0'; -- Reset | |
|
70 | constant ct : integer := clkperiod/2; | |
|
71 | ||
|
72 | signal address : std_logic_vector(21 downto 0); | |
|
73 | signal data : std_logic_vector(31 downto 24); | |
|
74 | ||
|
75 | signal romsn : std_logic; | |
|
76 | signal oen : std_logic; | |
|
77 | signal writen : std_logic; | |
|
78 | signal dsuen, dsutx, dsurx, dsubre, dsuact : std_logic; | |
|
79 | signal dsurst : std_logic; | |
|
80 | signal error : std_logic; | |
|
81 | ||
|
82 | signal sdcke : std_logic; | |
|
83 | signal sdcsn : std_logic; | |
|
84 | signal sdwen : std_logic; -- write en | |
|
85 | signal sdrasn : std_logic; -- row addr stb | |
|
86 | signal sdcasn : std_logic; -- col addr stb | |
|
87 | signal dram_ldqm : std_logic; | |
|
88 | signal dram_udqm : std_logic; | |
|
89 | signal sdclk : std_logic; | |
|
90 | signal dram_ba : std_logic_vector(1 downto 0); | |
|
91 | ||
|
92 | signal FTDI_RXF : std_logic; | |
|
93 | signal FTDI_TXE : std_logic; | |
|
94 | signal FTDI_SIWUA : std_logic; | |
|
95 | signal FTDI_WR : std_logic; | |
|
96 | signal FTDI_RD : std_logic; | |
|
97 | signal FTDI_D : std_logic_vector(7 downto 0):=(others=>'Z'); | |
|
98 | ||
|
99 | constant lresp : boolean := false; | |
|
100 | ||
|
101 | ||
|
102 | signal sa : std_logic_vector(12 downto 0); | |
|
103 | signal sd : std_logic_vector(15 downto 0); | |
|
104 | ||
|
105 | ||
|
106 | begin | |
|
107 | ||
|
108 | clk <= not clk after ct * 1 ns; --50 MHz clk | |
|
109 | rst <= dsurst; --reset | |
|
110 | dsuen <= '1'; | |
|
111 | dsubre <= '1'; -- inverted on the board | |
|
112 | sw(1) <= rst; | |
|
113 | ||
|
114 | d3 : entity work.leon3mp | |
|
115 | generic map ( fabtech, memtech, padtech, clktech, disas, dbguart, pclow ) | |
|
116 | port map ( | |
|
117 | CLK50 => clk, | |
|
118 | LEDS => open, | |
|
119 | SW => SW, | |
|
120 | dram_addr => sa, | |
|
121 | dram_ba_0 => dram_ba(0), | |
|
122 | dram_ba_1 => dram_ba(1), | |
|
123 | dram_dq => sd(15 downto 0), | |
|
124 | dram_clk => sdclk, | |
|
125 | dram_cke => sdcke, | |
|
126 | dram_cs_n => sdcsn, | |
|
127 | dram_we_n => sdwen, | |
|
128 | dram_ras_n => sdrasn, | |
|
129 | dram_cas_n => sdcasn, | |
|
130 | dram_ldqm => dram_ldqm, | |
|
131 | dram_udqm => dram_udqm, | |
|
132 | uart_txd => dsutx, | |
|
133 | uart_rxd => dsurx, | |
|
134 | ||
|
135 | FTDI_RXF => FTDI_RXF, | |
|
136 | FTDI_TXE => FTDI_TXE, | |
|
137 | FTDI_SIWUA => FTDI_SIWUA, | |
|
138 | FTDI_WR => FTDI_WR, | |
|
139 | FTDI_RD => FTDI_RD, | |
|
140 | FTDI_D => FTDI_D | |
|
141 | ); | |
|
142 | ||
|
143 | u1: entity work.mt48lc16m16a2 generic map (addr_bits => 13, col_bits => 9, index => 1024, fname => sdramfile) | |
|
144 | PORT MAP( | |
|
145 | Dq => sd(15 downto 0), Addr => sa(12 downto 0), | |
|
146 | Ba => dram_ba, Clk => sdclk, Cke => sdcke, | |
|
147 | Cs_n => sdcsn, Ras_n => sdrasn, Cas_n => sdcasn, We_n => sdwen, | |
|
148 | Dqm(0) => dram_ldqm, Dqm(1) => dram_udqm ); | |
|
149 | ||
|
150 | ||
|
151 | ||
|
152 | error <= 'H'; -- ERROR pull-up | |
|
153 | ||
|
154 | iuerr : process | |
|
155 | begin | |
|
156 | wait for 2500 ns; | |
|
157 | if to_x01(error) = '1' then wait on error; end if; | |
|
158 | assert (to_x01(error) = '1') | |
|
159 | report "*** IU in error mode, simulation halted ***" | |
|
160 | severity failure ; | |
|
161 | end process; | |
|
162 | ||
|
163 | data <= buskeep(data) after 5 ns; | |
|
164 | sd <= buskeep(sd) after 5 ns; | |
|
165 | ||
|
166 | testftdi : process | |
|
167 | procedure ftdi_write(signal FTDI_RXF : out std_logic; signal FTDI_RD : in std_logic; value : integer; signal FTDI_D: out std_logic_vector(7 downto 0)) is | |
|
168 | begin | |
|
169 | FTDI_RXF <= '0'; | |
|
170 | wait until FTDI_RD = '0'; | |
|
171 | wait for 14 ns; | |
|
172 | FTDI_D <= conv_std_logic_vector(value,8); | |
|
173 | wait for 16 ns; | |
|
174 | FTDI_D <= (others=>'Z'); | |
|
175 | wait until FTDI_RD = '1'; | |
|
176 | FTDI_RXF <= '1'; | |
|
177 | wait for 3 ns; | |
|
178 | end; | |
|
179 | procedure dcom_ftdi_write_reg(signal FTDI_RXF : out std_logic; signal FTDI_RD : in std_logic; address : std_logic_vector(31 downto 0); value : std_logic_vector(31 downto 0); signal FTDI_D: out std_logic_vector(7 downto 0)) is | |
|
180 | begin | |
|
181 | ftdi_write(FTDI_RXF,FTDI_RD,16#C0#,FTDI_D); | |
|
182 | ftdi_write(FTDI_RXF,FTDI_RD,to_integer(UNSIGNED(address(31 downto 24))),FTDI_D); | |
|
183 | ftdi_write(FTDI_RXF,FTDI_RD,to_integer(UNSIGNED(address(23 downto 16))),FTDI_D); | |
|
184 | ftdi_write(FTDI_RXF,FTDI_RD,to_integer(UNSIGNED(address(15 downto 8))),FTDI_D); | |
|
185 | ftdi_write(FTDI_RXF,FTDI_RD,to_integer(UNSIGNED(address(7 downto 0))),FTDI_D); | |
|
186 | ftdi_write(FTDI_RXF,FTDI_RD,to_integer(UNSIGNED(value(31 downto 24))),FTDI_D); | |
|
187 | ftdi_write(FTDI_RXF,FTDI_RD,to_integer(UNSIGNED(value(23 downto 16))),FTDI_D); | |
|
188 | ftdi_write(FTDI_RXF,FTDI_RD,to_integer(UNSIGNED(value(15 downto 8))),FTDI_D); | |
|
189 | ftdi_write(FTDI_RXF,FTDI_RD,to_integer(UNSIGNED(value(7 downto 0))),FTDI_D); | |
|
190 | ||
|
191 | end; | |
|
192 | procedure dcom_ftdi_read_reg(signal FTDI_RXF : out std_logic; signal FTDI_RD : in std_logic; address : std_logic_vector(31 downto 0); signal FTDI_D: out std_logic_vector(7 downto 0)) is | |
|
193 | begin | |
|
194 | ftdi_write(FTDI_RXF,FTDI_RD,16#80#,FTDI_D); | |
|
195 | ftdi_write(FTDI_RXF,FTDI_RD,to_integer(UNSIGNED(address(31 downto 24))),FTDI_D); | |
|
196 | ftdi_write(FTDI_RXF,FTDI_RD,to_integer(UNSIGNED(address(23 downto 16))),FTDI_D); | |
|
197 | ftdi_write(FTDI_RXF,FTDI_RD,to_integer(UNSIGNED(address(15 downto 8))),FTDI_D); | |
|
198 | ftdi_write(FTDI_RXF,FTDI_RD,to_integer(UNSIGNED(address(7 downto 0))),FTDI_D); | |
|
199 | end; | |
|
200 | begin | |
|
201 | FTDI_D <= (others=>'Z'); | |
|
202 | dsurst <= '0'; | |
|
203 | FTDI_RXF <= '1'; | |
|
204 | wait for 100 ns; | |
|
205 | dsurst <= '1'; | |
|
206 | wait for 100 ns; | |
|
207 | dcom_ftdi_read_reg(FTDI_RXF,FTDI_RD,X"80000000",FTDI_D); | |
|
208 | dcom_ftdi_read_reg(FTDI_RXF,FTDI_RD,X"80000004",FTDI_D); | |
|
209 | dcom_ftdi_read_reg(FTDI_RXF,FTDI_RD,X"80000008",FTDI_D); | |
|
210 | dcom_ftdi_read_reg(FTDI_RXF,FTDI_RD,X"8000000C",FTDI_D); | |
|
211 | dcom_ftdi_read_reg(FTDI_RXF,FTDI_RD,X"80000010",FTDI_D); | |
|
212 | wait; | |
|
213 | end process; | |
|
214 | ||
|
215 | txe: process | |
|
216 | begin | |
|
217 | FTDI_TXE <= '0'; | |
|
218 | wait until FTDI_WR = '0'; | |
|
219 | wait for 14 ns; | |
|
220 | FTDI_TXE <= '1'; | |
|
221 | wait for 49 ns; | |
|
222 | end process; | |
|
223 | end ; | |
|
224 |
@@ -0,0 +1,77 | |||
|
1 | VHDLIB=../.. | |
|
2 | SELFDIR := $(dir $(lastword $(MAKEFILE_LIST))) | |
|
3 | SCRIPTSDIR=$(VHDLIB)/scripts/ | |
|
4 | GRLIB := $(shell sh $(VHDLIB)/scripts/lpp_relpath.sh) | |
|
5 | TOP=leon3mp | |
|
6 | BOARD=MiniSpartan6p | |
|
7 | DESIGN=leon3-MiniSpartan6p | |
|
8 | include $(VHDLIB)/boards/$(BOARD)/Makefile.inc | |
|
9 | DEVICE=$(PART)-$(PACKAGE)$(SPEED) | |
|
10 | UCF=withSPW.ucf | |
|
11 | UCF_PLANAHEAD=$(UCF) | |
|
12 | QSF=$(GRLIB)/boards/$(BOARD)/$(TOP).qsf | |
|
13 | EFFORT=high | |
|
14 | XSTOPT=-uc leon3mp.xcf | |
|
15 | SYNPOPT="set_option -pipe 1; set_option -retiming 1; set_option -write_apr_constraint 0" | |
|
16 | ||
|
17 | ||
|
18 | VHDLOPTSYNFILES = sdctrl16.vhd config.vhd leon3mp.vhd | |
|
19 | ||
|
20 | VHDLSIMFILES=mt48lc16m16a2.vhd testbench.vhd | |
|
21 | ||
|
22 | SIMTOP=testbench | |
|
23 | SDCFILE=$(GRLIB)/boards/$(BOARD)/default.sdc | |
|
24 | BITGEN=$(VHDLIB)/boards/$(BOARD)/default.ut | |
|
25 | ||
|
26 | TECHLIBS = unisim | |
|
27 | ||
|
28 | LIBSKIP = core1553bbc core1553brm core1553brt gr1553 corePCIF \ | |
|
29 | tmtc openchip hynix ihp gleichmann usbhc fmf ftlib gsi | |
|
30 | ||
|
31 | DIRSKIP = b1553 pcif leon2 leon2ft crypto satcan ddr usb ata i2c \ | |
|
32 | pci grusbhc haps slink ascs can pwm greth coremp7 ac97 atf \ | |
|
33 | grlfpc \ | |
|
34 | ./dsp/lpp_fft_rtax \ | |
|
35 | ./amba_lcd_16x2_ctrlr \ | |
|
36 | ./general_purpose/lpp_AMR \ | |
|
37 | ./general_purpose/lpp_balise \ | |
|
38 | ./general_purpose/lpp_delay \ | |
|
39 | ./lpp_bootloader \ | |
|
40 | ./lpp_sim/CY7C1061DV33 \ | |
|
41 | ./lpp_uart \ | |
|
42 | ./lpp_usb \ | |
|
43 | ./dsp/lpp_fft \ | |
|
44 | ./lpp_leon3_soc \ | |
|
45 | ./lpp_debug_lfr | |
|
46 | ||
|
47 | FILESKIP = i2cmst.vhd \ | |
|
48 | APB_MULTI_DIODE.vhd \ | |
|
49 | APB_MULTI_DIODE.vhd \ | |
|
50 | Top_MatrixSpec.vhd \ | |
|
51 | APB_FFT.vhd \ | |
|
52 | lpp_lfr_ms_FFT.vhd \ | |
|
53 | lpp_lfr_apbreg.vhd \ | |
|
54 | CoreFFT.vhd \ | |
|
55 | lpp_lfr_ms.vhd \ | |
|
56 | lpp_lfr_sim_pkg.vhd \ | |
|
57 | mtie_maps.vhd \ | |
|
58 | ftsrctrlc.vhd \ | |
|
59 | ftsdctrl.vhd \ | |
|
60 | ftsrctrl8.vhd \ | |
|
61 | ftmctrl.vhd \ | |
|
62 | ftsdctrl64.vhd \ | |
|
63 | ftahbram.vhd \ | |
|
64 | ftahbram2.vhd \ | |
|
65 | sramft.vhd \ | |
|
66 | nandfctrlx.vhd | |
|
67 | ||
|
68 | include $(GRLIB)/bin/Makefile | |
|
69 | ||
|
70 | ################## project specific targets ########################## | |
|
71 | ||
|
72 | load-ram: | |
|
73 | xc3sprog -c ftdi -p0 leon3mp.bit | |
|
74 | ||
|
75 | load-flash: | |
|
76 | xc3sprog -c ftdi -p0 $(VHDLIB)/boards/$(BOARD)/bscan_spi_s6lx25_ftg256.bit | |
|
77 | xc3sprog -c ftdi -I leon3mp.bit |
@@ -0,0 +1,66 | |||
|
1 | This LEON3 design is tailored to the Scarab Hardware [MiniSpartan6+](https://www.scarabhardware.com/minispartan6/) board. | |
|
2 | ||
|
3 | Simulation and synthesis | |
|
4 | ------------------------ | |
|
5 | ||
|
6 | This design tries to use as much as possible free (as in freedom) tools and at least free (as in free beer) when impossible. | |
|
7 | ||
|
8 | ||
|
9 | Note that the simulation doesn't work as expected yet. | |
|
10 | ||
|
11 | ||
|
12 | To build the design: | |
|
13 | ```bash | |
|
14 | make ise | |
|
15 | ``` | |
|
16 | ||
|
17 | To load into FPGA RAM: | |
|
18 | ```bash | |
|
19 | make load-ram | |
|
20 | ``` | |
|
21 | ||
|
22 | To load into FPGA Flash: | |
|
23 | ```bash | |
|
24 | make load-flash | |
|
25 | ``` | |
|
26 | ||
|
27 | Design specifics | |
|
28 | ---------------- | |
|
29 | ||
|
30 | * The AHB and processor is clocked from the 50 MHz clock. | |
|
31 | ||
|
32 | * The SDRAM is working with the sdctrl16 memory controller taken from leon3-altera-de2-ep2c35 design. | |
|
33 | ||
|
34 | * The UART DSU interface ie enabled and connected to interface B of ft2232H chip. | |
|
35 | Start GRMON with -uart /dev/ttyUSB1 | |
|
36 | ||
|
37 | * Output from GRMON2 should look similar to this: | |
|
38 | ||
|
39 | ```bash | |
|
40 | GRMON2 LEON debug monitor v2.0.80-beta 64-bit eval version | |
|
41 | ||
|
42 | Copyright (C) 2016 Cobham Gaisler - All rights reserved. | |
|
43 | For latest updates, go to http://www.gaisler.com/ | |
|
44 | Comments or bug-reports to support@gaisler.com | |
|
45 | ||
|
46 | This eval version will expire on 18/04/2017 | |
|
47 | ||
|
48 | using port /dev/ttyUSB1 @ 115200 baud | |
|
49 | GRLIB build version: 4164 | |
|
50 | Detected frequency: 50 MHz | |
|
51 | ||
|
52 | Component Vendor | |
|
53 | LEON3 SPARC V8 Processor Cobham Gaisler | |
|
54 | AHB Debug UART Cobham Gaisler | |
|
55 | AHB/APB Bridge Cobham Gaisler | |
|
56 | LEON3 Debug Support Unit Cobham Gaisler | |
|
57 | PC133 SDRAM Controller Cobham Gaisler | |
|
58 | Multi-processor Interrupt Ctrl. Cobham Gaisler | |
|
59 | Modular Timer Unit Cobham Gaisler | |
|
60 | General Purpose I/O port Cobham Gaisler | |
|
61 | ||
|
62 | Use command 'info sys' to print a detailed report of attached cores | |
|
63 | ||
|
64 | grmon2> | |
|
65 | ||
|
66 | ``` No newline at end of file |
@@ -0,0 +1,11 | |||
|
1 | F0 -> L46P -> DOUT+ -> 9 -> Grey | |
|
2 | F1 -> L46N -> DOUT- -> 5 -> Yellow | |
|
3 | ||
|
4 | F5 -> L40P -> SOUT+ -> 8 -> Violet | |
|
5 | F7 -> L40N -> SOUT- -> 4 -> Orange | |
|
6 | ||
|
7 | F3 -> L53P -> SIN+ -> 2 -> Brown | |
|
8 | F6 -> L53N -> SIN- -> 7 -> Blue | |
|
9 | ||
|
10 | F9 -> L39N -> DIN- -> 6 -> Green | |
|
11 | F10 -> L39P -> DIN+ -> 1 -> Black |
@@ -0,0 +1,162 | |||
|
1 | ||
|
2 | ||
|
3 | ||
|
4 | ----------------------------------------------------------------------------- | |
|
5 | -- LEON3 Demonstration design test bench configuration | |
|
6 | -- Copyright (C) 2009 Aeroflex Gaisler | |
|
7 | ------------------------------------------------------------------------------ | |
|
8 | ||
|
9 | ||
|
10 | library techmap; | |
|
11 | use techmap.gencomp.all; | |
|
12 | ||
|
13 | package config is | |
|
14 | -- Technology and synthesis options | |
|
15 | constant CFG_FABTECH : integer := spartan6; | |
|
16 | constant CFG_MEMTECH : integer := spartan6; | |
|
17 | constant CFG_PADTECH : integer := spartan6; | |
|
18 | constant CFG_TRANSTECH : integer := GTP0; | |
|
19 | constant CFG_NOASYNC : integer := 0; | |
|
20 | constant CFG_SCAN : integer := 0; | |
|
21 | -- Clock generator | |
|
22 | constant CFG_CLKTECH : integer := spartan6; | |
|
23 | constant CFG_CLKMUL : integer := (3); | |
|
24 | constant CFG_CLKDIV : integer := (2); | |
|
25 | constant CFG_OCLKDIV : integer := 1; | |
|
26 | constant CFG_OCLKBDIV : integer := 0; | |
|
27 | constant CFG_OCLKCDIV : integer := 0; | |
|
28 | constant CFG_PCIDLL : integer := 0; | |
|
29 | constant CFG_PCISYSCLK: integer := 0; | |
|
30 | constant CFG_CLK_NOFB : integer := 0; | |
|
31 | -- LEON3 processor core | |
|
32 | constant CFG_LEON3 : integer := 1; | |
|
33 | constant CFG_NCPU : integer := (1); | |
|
34 | constant CFG_NWIN : integer := (8); | |
|
35 | constant CFG_V8 : integer := 2 + 4*0; | |
|
36 | constant CFG_MAC : integer := 0; | |
|
37 | constant CFG_BP : integer := 1; | |
|
38 | constant CFG_SVT : integer := 1; | |
|
39 | constant CFG_RSTADDR : integer := 16#00000#; | |
|
40 | constant CFG_LDDEL : integer := (2); | |
|
41 | constant CFG_NOTAG : integer := 1; | |
|
42 | constant CFG_NWP : integer := (0); | |
|
43 | constant CFG_PWD : integer := 0*2; | |
|
44 | constant CFG_FPU : integer := 0 + 16*0 + 32*0; | |
|
45 | constant CFG_GRFPUSH : integer := 0; | |
|
46 | constant CFG_ICEN : integer := 1; | |
|
47 | constant CFG_ISETS : integer := 1; | |
|
48 | constant CFG_ISETSZ : integer := 8; | |
|
49 | constant CFG_ILINE : integer := 8; | |
|
50 | constant CFG_IREPL : integer := 0; | |
|
51 | constant CFG_ILOCK : integer := 0; | |
|
52 | constant CFG_ILRAMEN : integer := 0; | |
|
53 | constant CFG_ILRAMADDR: integer := 16#8E#; | |
|
54 | constant CFG_ILRAMSZ : integer := 1; | |
|
55 | constant CFG_DCEN : integer := 1; | |
|
56 | constant CFG_DSETS : integer := 1; | |
|
57 | constant CFG_DSETSZ : integer := 8; | |
|
58 | constant CFG_DLINE : integer := 8; | |
|
59 | constant CFG_DREPL : integer := 0; | |
|
60 | constant CFG_DLOCK : integer := 0; | |
|
61 | constant CFG_DSNOOP : integer := 0 + 0*2 + 4*0; | |
|
62 | constant CFG_DFIXED : integer := 16#0#; | |
|
63 | constant CFG_DLRAMEN : integer := 0; | |
|
64 | constant CFG_DLRAMADDR: integer := 16#8F#; | |
|
65 | constant CFG_DLRAMSZ : integer := 1; | |
|
66 | constant CFG_MMUEN : integer := 0; | |
|
67 | constant CFG_ITLBNUM : integer := 8; | |
|
68 | constant CFG_DTLBNUM : integer := 2; | |
|
69 | constant CFG_TLB_TYPE : integer := 1 + 0*2; | |
|
70 | constant CFG_TLB_REP : integer := 1; | |
|
71 | constant CFG_MMU_PAGE : integer := 0; | |
|
72 | constant CFG_DSU : integer := 1; | |
|
73 | constant CFG_ITBSZ : integer := 0 + 64*0; | |
|
74 | constant CFG_ATBSZ : integer := 0; | |
|
75 | constant CFG_AHBPF : integer := 0; | |
|
76 | constant CFG_LEON3FT_EN : integer := 0; | |
|
77 | constant CFG_IUFT_EN : integer := 0; | |
|
78 | constant CFG_FPUFT_EN : integer := 0; | |
|
79 | constant CFG_RF_ERRINJ : integer := 0; | |
|
80 | constant CFG_CACHE_FT_EN : integer := 0; | |
|
81 | constant CFG_CACHE_ERRINJ : integer := 0; | |
|
82 | constant CFG_LEON3_NETLIST: integer := 0; | |
|
83 | constant CFG_DISAS : integer := 0 + 0; | |
|
84 | constant CFG_PCLOW : integer := 2; | |
|
85 | constant CFG_STAT_ENABLE : integer := 0; | |
|
86 | constant CFG_STAT_CNT : integer := 1; | |
|
87 | constant CFG_STAT_NMAX : integer := 0; | |
|
88 | constant CFG_STAT_DSUEN : integer := 0; | |
|
89 | constant CFG_NP_ASI : integer := 0; | |
|
90 | constant CFG_WRPSR : integer := 0; | |
|
91 | constant CFG_ALTWIN : integer := 0; | |
|
92 | constant CFG_REX : integer := 0; | |
|
93 | -- AMBA settings | |
|
94 | constant CFG_DEFMST : integer := (0); | |
|
95 | constant CFG_RROBIN : integer := 1; | |
|
96 | constant CFG_SPLIT : integer := 1; | |
|
97 | constant CFG_FPNPEN : integer := 0; | |
|
98 | constant CFG_AHBIO : integer := 16#FFF#; | |
|
99 | constant CFG_APBADDR : integer := 16#800#; | |
|
100 | constant CFG_AHB_MON : integer := 0; | |
|
101 | constant CFG_AHB_MONERR : integer := 0; | |
|
102 | constant CFG_AHB_MONWAR : integer := 0; | |
|
103 | constant CFG_AHB_DTRACE : integer := 0; | |
|
104 | -- DSU UART | |
|
105 | constant CFG_AHB_UART : integer := 1; | |
|
106 | -- JTAG based DSU interface | |
|
107 | constant CFG_AHB_JTAG : integer := 1; | |
|
108 | -- Xilinx MIG | |
|
109 | constant CFG_MIG_DDR2 : integer := 1; | |
|
110 | constant CFG_MIG_RANKS : integer := (1); | |
|
111 | constant CFG_MIG_COLBITS : integer := (10); | |
|
112 | constant CFG_MIG_ROWBITS : integer := (13); | |
|
113 | constant CFG_MIG_BANKBITS: integer := (2); | |
|
114 | constant CFG_MIG_HMASK : integer := 16#FC0#; | |
|
115 | -- AHB ROM | |
|
116 | constant CFG_AHBROMEN : integer := 1; | |
|
117 | constant CFG_AHBROPIP : integer := 0; | |
|
118 | constant CFG_AHBRODDR : integer := 16#000#; | |
|
119 | constant CFG_ROMADDR : integer := 16#100#; | |
|
120 | constant CFG_ROMMASK : integer := 16#E00# + 16#100#; | |
|
121 | -- AHB RAM | |
|
122 | constant CFG_AHBRAMEN : integer := 1; | |
|
123 | constant CFG_AHBRSZ : integer := 4; | |
|
124 | constant CFG_AHBRADDR : integer := 16#A00#; | |
|
125 | constant CFG_AHBRPIPE : integer := 0; | |
|
126 | -- UART 1 | |
|
127 | constant CFG_UART1_ENABLE : integer := 1; | |
|
128 | constant CFG_UART1_FIFO : integer := 4; | |
|
129 | -- LEON3 interrupt controller | |
|
130 | constant CFG_IRQ3_ENABLE : integer := 1; | |
|
131 | constant CFG_IRQ3_NSEC : integer := 0; | |
|
132 | -- Modular timer | |
|
133 | constant CFG_GPT_ENABLE : integer := 1; | |
|
134 | constant CFG_GPT_NTIM : integer := (2); | |
|
135 | constant CFG_GPT_SW : integer := (8); | |
|
136 | constant CFG_GPT_TW : integer := (32); | |
|
137 | constant CFG_GPT_IRQ : integer := (8); | |
|
138 | constant CFG_GPT_SEPIRQ : integer := 1; | |
|
139 | constant CFG_GPT_WDOGEN : integer := 0; | |
|
140 | constant CFG_GPT_WDOG : integer := 16#0#; | |
|
141 | -- GPIO port | |
|
142 | constant CFG_GRGPIO_ENABLE : integer := 1; | |
|
143 | constant CFG_GRGPIO_IMASK : integer := 16#0000#; | |
|
144 | constant CFG_GRGPIO_WIDTH : integer := 1; | |
|
145 | ||
|
146 | -- SPI controller | |
|
147 | constant CFG_SPICTRL_ENABLE : integer := 1; | |
|
148 | constant CFG_SPICTRL_NUM : integer := (1); | |
|
149 | constant CFG_SPICTRL_SLVS : integer := (1); | |
|
150 | constant CFG_SPICTRL_FIFO : integer := (2); | |
|
151 | constant CFG_SPICTRL_SLVREG : integer := 1; | |
|
152 | constant CFG_SPICTRL_ODMODE : integer := 1; | |
|
153 | constant CFG_SPICTRL_AM : integer := 0; | |
|
154 | constant CFG_SPICTRL_ASEL : integer := 0; | |
|
155 | constant CFG_SPICTRL_TWEN : integer := 0; | |
|
156 | constant CFG_SPICTRL_MAXWLEN : integer := (0); | |
|
157 | constant CFG_SPICTRL_SYNCRAM : integer := 0; | |
|
158 | constant CFG_SPICTRL_FT : integer := 0; | |
|
159 | ||
|
160 | -- GRLIB debugging | |
|
161 | constant CFG_DUART : integer := 0; | |
|
162 | end; |
@@ -0,0 +1,350 | |||
|
1 | ||
|
2 | ||
|
3 | library ieee; | |
|
4 | use ieee.std_logic_1164.all; | |
|
5 | USE IEEE.NUMERIC_STD.ALL; | |
|
6 | library grlib; | |
|
7 | use grlib.amba.all; | |
|
8 | use grlib.stdlib.all; | |
|
9 | use grlib.devices.all; | |
|
10 | library techmap; | |
|
11 | use techmap.gencomp.all; | |
|
12 | use techmap.allclkgen.all; | |
|
13 | library gaisler; | |
|
14 | use gaisler.memctrl.all; | |
|
15 | use gaisler.leon3.all; | |
|
16 | use gaisler.uart.all; | |
|
17 | use gaisler.misc.all; | |
|
18 | --pragma translate_off | |
|
19 | use gaisler.sim.all; | |
|
20 | --pragma translate_on | |
|
21 | library opencores; | |
|
22 | use opencores.spwpkg.all; | |
|
23 | use opencores.spwambapkg.all; | |
|
24 | ||
|
25 | use work.config.all; | |
|
26 | ||
|
27 | library unisim; | |
|
28 | use unisim.vcomponents.all; | |
|
29 | ||
|
30 | entity leon3mp is | |
|
31 | generic ( | |
|
32 | fabtech : integer := CFG_FABTECH; | |
|
33 | memtech : integer := CFG_MEMTECH; | |
|
34 | padtech : integer := CFG_PADTECH; | |
|
35 | clktech : integer := CFG_CLKTECH; | |
|
36 | disas : integer := CFG_DISAS; -- Enable disassembly to console | |
|
37 | dbguart : integer := CFG_DUART; -- Print UART on console | |
|
38 | pclow : integer := CFG_PCLOW | |
|
39 | ); | |
|
40 | port ( | |
|
41 | CLK50 : in std_logic; | |
|
42 | LEDS : inout std_logic_vector(7 downto 0); | |
|
43 | SW : in std_logic_vector(4 downto 1); | |
|
44 | dram_addr : out std_logic_vector(12 downto 0); | |
|
45 | dram_ba_0 : out std_logic; | |
|
46 | dram_ba_1 : out std_logic; | |
|
47 | dram_dq : inout std_logic_vector(15 downto 0); | |
|
48 | ||
|
49 | dram_clk : out std_logic; | |
|
50 | dram_cke : out std_logic; | |
|
51 | dram_cs_n : out std_logic; | |
|
52 | dram_we_n : out std_logic; -- sdram write enable | |
|
53 | dram_ras_n : out std_logic; -- sdram ras | |
|
54 | dram_cas_n : out std_logic; -- sdram cas | |
|
55 | dram_ldqm : out std_logic; -- sdram ldqm | |
|
56 | dram_udqm : out std_logic; -- sdram udqm | |
|
57 | uart_txd : out std_logic; -- DSU tx data | |
|
58 | uart_rxd : in std_logic; -- DSU rx data | |
|
59 | ||
|
60 | spw_rxdp : in std_logic; | |
|
61 | spw_rxdn : in std_logic; | |
|
62 | spw_rxsp : in std_logic; | |
|
63 | spw_rxsn : in std_logic; | |
|
64 | spw_txdp : out std_logic; | |
|
65 | spw_txdn : out std_logic; | |
|
66 | spw_txsp : out std_logic; | |
|
67 | spw_txsn : out std_logic | |
|
68 | ); | |
|
69 | end; | |
|
70 | ||
|
71 | architecture rtl of leon3mp is | |
|
72 | signal resetn : std_logic; | |
|
73 | signal clkm, rstn, rstraw, rst : std_logic; | |
|
74 | signal clkm_inv : std_logic := '0'; | |
|
75 | ||
|
76 | signal cptr : std_logic_vector(29 downto 0); | |
|
77 | constant BOARD_FREQ : integer := 25000; -- CLK input frequency in KHz | |
|
78 | constant CPU_FREQ : integer := BOARD_FREQ * CFG_CLKMUL / CFG_CLKDIV; -- cpu frequency in KHz | |
|
79 | signal sdi : sdctrl_in_type; | |
|
80 | signal sdo : sdctrl_out_type; | |
|
81 | ||
|
82 | --AMBA bus standard interface signals-- | |
|
83 | signal apbi : apb_slv_in_type; | |
|
84 | signal apbo : apb_slv_out_vector := (others => apb_none); | |
|
85 | signal ahbsi : ahb_slv_in_type; | |
|
86 | signal ahbso : ahb_slv_out_vector := (others => ahbs_none); | |
|
87 | signal ahbmi : ahb_mst_in_type; | |
|
88 | signal ahbmo : ahb_mst_out_vector := (others => ahbm_none); | |
|
89 | ||
|
90 | signal cgi : clkgen_in_type; | |
|
91 | signal cgo : clkgen_out_type; | |
|
92 | ||
|
93 | signal dui : uart_in_type; | |
|
94 | signal duo : uart_out_type; | |
|
95 | ||
|
96 | signal irqi : irq_in_vector(0 to CFG_NCPU-1); | |
|
97 | signal irqo : irq_out_vector(0 to CFG_NCPU-1); | |
|
98 | ||
|
99 | signal dbgi : l3_debug_in_vector(0 to CFG_NCPU-1); | |
|
100 | signal dbgo : l3_debug_out_vector(0 to CFG_NCPU-1); | |
|
101 | ||
|
102 | signal dsui : dsu_in_type; | |
|
103 | signal dsuo : dsu_out_type; | |
|
104 | ||
|
105 | ||
|
106 | signal gpti : gptimer_in_type; | |
|
107 | signal gpto : gptimer_out_type; | |
|
108 | ||
|
109 | signal gpioi_0 : gpio_in_type; | |
|
110 | signal gpioo_0 : gpio_out_type; | |
|
111 | ||
|
112 | signal dsubren : std_logic :='0'; | |
|
113 | ||
|
114 | signal spw_di: std_logic; | |
|
115 | signal spw_si: std_logic; | |
|
116 | signal spw_do: std_logic; | |
|
117 | signal spw_so: std_logic; | |
|
118 | signal spw_tick_in: std_logic; | |
|
119 | ||
|
120 | component sdctrl16 | |
|
121 | generic ( | |
|
122 | hindex : integer := 0; | |
|
123 | haddr : integer := 0; | |
|
124 | hmask : integer := 16#f00#; | |
|
125 | ioaddr : integer := 16#000#; | |
|
126 | iomask : integer := 16#fff#; | |
|
127 | wprot : integer := 0; | |
|
128 | invclk : integer := 0; | |
|
129 | fast : integer := 0; | |
|
130 | pwron : integer := 0; | |
|
131 | sdbits : integer := 16; | |
|
132 | oepol : integer := 0; | |
|
133 | pageburst : integer := 0; | |
|
134 | mobile : integer := 0 | |
|
135 | ); | |
|
136 | port ( | |
|
137 | rst : in std_ulogic; | |
|
138 | clk : in std_ulogic; | |
|
139 | ahbsi : in ahb_slv_in_type; | |
|
140 | ahbso : out ahb_slv_out_type; | |
|
141 | sdi : in sdctrl_in_type; | |
|
142 | sdo : out sdctrl_out_type | |
|
143 | ); | |
|
144 | end component; | |
|
145 | ||
|
146 | begin | |
|
147 | resetn <= SW(1); | |
|
148 | ||
|
149 | clk_pad : clkpad generic map (tech => padtech) port map (CLK50, clkm); | |
|
150 | clkm_inv <= not clkm; | |
|
151 | ||
|
152 | resetn_pad : inpad generic map (tech => padtech) port map (resetn, rst); | |
|
153 | rst0 : rstgen -- reset generator (reset is active LOW) | |
|
154 | port map (rst, clkm, '1', rstn, rstraw); | |
|
155 | ||
|
156 | ||
|
157 | ---------------------------------------------------------------------- | |
|
158 | --- AHB CONTROLLER -------------------------------------------------- | |
|
159 | ---------------------------------------------------------------------- | |
|
160 | ||
|
161 | ahb0 : ahbctrl -- AHB arbiter/multiplexer | |
|
162 | generic map (defmast => CFG_DEFMST, split => CFG_SPLIT, | |
|
163 | rrobin => CFG_RROBIN, ioaddr => CFG_AHBIO, | |
|
164 | nahbm => CFG_NCPU+CFG_AHB_UART+1, nahbs => 8) | |
|
165 | ||
|
166 | port map (rstn, clkm, ahbmi, ahbmo, ahbsi, ahbso); | |
|
167 | ||
|
168 | ---------------------------------------------------------------------- | |
|
169 | ----- LEON3 processor and DSU --------------------------------------- | |
|
170 | ---------------------------------------------------------------------- | |
|
171 | ||
|
172 | cpu : for i in 0 to CFG_NCPU-1 generate | |
|
173 | nosh : if CFG_GRFPUSH = 0 generate | |
|
174 | u0 : leon3s -- LEON3 processor | |
|
175 | generic map (i, fabtech, memtech, CFG_NWIN, CFG_DSU, CFG_FPU*(1-CFG_GRFPUSH), CFG_V8, | |
|
176 | 0, CFG_MAC, pclow, CFG_NOTAG, CFG_NWP, CFG_ICEN, CFG_IREPL, CFG_ISETS, CFG_ILINE, | |
|
177 | CFG_ISETSZ, CFG_ILOCK, CFG_DCEN, CFG_DREPL, CFG_DSETS, CFG_DLINE, CFG_DSETSZ, | |
|
178 | CFG_DLOCK, CFG_DSNOOP, CFG_ILRAMEN, CFG_ILRAMSZ, CFG_ILRAMADDR, CFG_DLRAMEN, | |
|
179 | CFG_DLRAMSZ, CFG_DLRAMADDR, CFG_MMUEN, CFG_ITLBNUM, CFG_DTLBNUM, CFG_TLB_TYPE, CFG_TLB_REP, | |
|
180 | CFG_LDDEL, disas, CFG_ITBSZ, CFG_PWD, CFG_SVT, CFG_RSTADDR, CFG_NCPU-1, | |
|
181 | 0, 0, CFG_MMU_PAGE, CFG_BP, CFG_NP_ASI, CFG_WRPSR) | |
|
182 | port map (clkm, rstn, ahbmi, ahbmo(i), ahbsi, ahbso, | |
|
183 | irqi(i), irqo(i), dbgi(i), dbgo(i)); | |
|
184 | end generate; | |
|
185 | end generate; | |
|
186 | ||
|
187 | --ledr[0] lit when leon 3 debugvector signals error | |
|
188 | dsugen : if CFG_DSU = 1 generate | |
|
189 | dsu0 : dsu3 -- LEON3 Debug Support Unit (slave) | |
|
190 | generic map (hindex => 2, haddr => 16#900#, hmask => 16#F00#, | |
|
191 | ncpu => CFG_NCPU, tbits => 30, tech => memtech, irq => 0, kbytes => CFG_ATBSZ) | |
|
192 | port map (rstn, clkm, ahbmi, ahbsi, ahbso(2), dbgo, dbgi, dsui, dsuo); | |
|
193 | dsui.enable <= '1'; | |
|
194 | ||
|
195 | end generate; | |
|
196 | nodsu : if CFG_DSU = 0 generate | |
|
197 | ahbso(2) <= ahbs_none; dsuo.tstop <= '0'; dsuo.active <= '0'; --no timer freeze, no light. | |
|
198 | end generate; | |
|
199 | ||
|
200 | dcomgen : if CFG_AHB_UART = 1 generate | |
|
201 | dcom0: ahbuart -- Debug UART | |
|
202 | generic map (hindex => CFG_NCPU, pindex => 7, paddr => 7) | |
|
203 | port map (rstn, clkm, dui, duo, apbi, apbo(7), ahbmi, ahbmo(CFG_NCPU)); | |
|
204 | end generate; | |
|
205 | uart_txd <= duo.txd; | |
|
206 | dui.rxd <= uart_rxd; | |
|
207 | ||
|
208 | ||
|
209 | ---------------------------------------------------------------------- | |
|
210 | --- Memory controllers ---------------------------------------------- | |
|
211 | ---------------------------------------------------------------------- | |
|
212 | ||
|
213 | ||
|
214 | sdc : sdctrl16 generic map (hindex => 3, haddr => 16#400#, hmask => 16#FE0#, -- hmask => 16#C00#, | |
|
215 | ioaddr => 1, fast => 0, pwron => 0, invclk => 0, | |
|
216 | sdbits => 16, pageburst => 2) | |
|
217 | port map (rstn, clkm, ahbsi, ahbso(3), sdi, sdo); | |
|
218 | sa_pad : outpadv generic map (width => 13, tech => padtech) | |
|
219 | port map (dram_addr, sdo.address(14 downto 2)); | |
|
220 | ba0_pad : outpad generic map (tech => padtech) | |
|
221 | port map (dram_ba_0, sdo.address(15)); | |
|
222 | ba1_pad : outpad generic map (tech => padtech) | |
|
223 | port map (dram_ba_1, sdo.address(16)); | |
|
224 | sd_pad : iopadvv generic map (width => 16, tech => padtech) | |
|
225 | port map (dram_dq(15 downto 0), sdo.data(15 downto 0), sdo.vbdrive(15 downto 0), sdi.data(15 downto 0)); | |
|
226 | sdcke_pad : outpad generic map (tech => padtech) | |
|
227 | port map (dram_cke, sdo.sdcke(0)); | |
|
228 | sdwen_pad : outpad generic map (tech => padtech) | |
|
229 | port map (dram_we_n, sdo.sdwen); | |
|
230 | sdcsn_pad : outpad generic map (tech => padtech) | |
|
231 | port map (dram_cs_n, sdo.sdcsn(0)); | |
|
232 | sdras_pad : outpad generic map (tech => padtech) | |
|
233 | port map (dram_ras_n, sdo.rasn); | |
|
234 | sdcas_pad : outpad generic map (tech => padtech) | |
|
235 | port map (dram_cas_n, sdo.casn); | |
|
236 | sdldqm_pad : outpad generic map (tech => padtech) | |
|
237 | port map (dram_ldqm, sdo.dqm(0) ); | |
|
238 | sdudqm_pad : outpad generic map (tech => padtech) | |
|
239 | port map (dram_udqm, sdo.dqm(1)); | |
|
240 | dram_clk_pad : outpad generic map (tech => padtech) | |
|
241 | port map (dram_clk, clkm_inv); | |
|
242 | ||
|
243 | ---------------------------------------------------------------------- | |
|
244 | --- APB Bridge and various periherals ------------------------------- | |
|
245 | ---------------------------------------------------------------------- | |
|
246 | ||
|
247 | apb0 : apbctrl -- AHB/APB bridge | |
|
248 | generic map (hindex => 1, haddr => CFG_APBADDR) | |
|
249 | port map (rstn, clkm, ahbsi, ahbso(1), apbi, apbo ); | |
|
250 | ||
|
251 | ---------------------------------------------------------------------------------------- | |
|
252 | ||
|
253 | irqctrl : if CFG_IRQ3_ENABLE /= 0 generate | |
|
254 | irqctrl0 : irqmp -- interrupt controller | |
|
255 | generic map (pindex => 2, paddr => 2, ncpu => CFG_NCPU) | |
|
256 | port map (rstn, clkm, apbi, apbo(2), irqo, irqi); | |
|
257 | end generate; | |
|
258 | irq3 : if CFG_IRQ3_ENABLE = 0 generate | |
|
259 | x : for i in 0 to CFG_NCPU-1 generate irqi(i).irl <= "0000"; end generate; | |
|
260 | apbo(2) <= apb_none; | |
|
261 | end generate; | |
|
262 | ||
|
263 | --Timer unit, generates interrupts when a timer underflow. | |
|
264 | gpt : if CFG_GPT_ENABLE /= 0 generate | |
|
265 | timer0 : gptimer -- timer unit | |
|
266 | generic map (pindex => 3, paddr => 3, pirq => CFG_GPT_IRQ, | |
|
267 | sepirq => CFG_GPT_SEPIRQ, sbits => CFG_GPT_SW, ntimers => CFG_GPT_NTIM, | |
|
268 | nbits => CFG_GPT_TW) | |
|
269 | port map (rstn, clkm, apbi, apbo(3), gpti, gpto); | |
|
270 | gpti <= gpti_dhalt_drive(dsuo.tstop); | |
|
271 | end generate; | |
|
272 | notim : if CFG_GPT_ENABLE = 0 generate apbo(3) <= apb_none; end generate; | |
|
273 | ||
|
274 | gpio0 : if CFG_GRGPIO_ENABLE /= 0 generate -- GR GPIO0 unit | |
|
275 | grgpio0: grgpio | |
|
276 | generic map( pindex => 9, paddr => 9, imask => CFG_GRGPIO_IMASK, nbits => 8) | |
|
277 | port map( rstn, clkm, apbi, apbo(9), gpioi_0, gpioo_0); | |
|
278 | pio_pads : for i in 0 to 7 generate | |
|
279 | pio_pad : iopad generic map (tech => padtech) | |
|
280 | port map (LEDS(i), gpioo_0.dout(i), gpioo_0.oen(i), gpioi_0.din(i)); | |
|
281 | end generate; | |
|
282 | end generate; | |
|
283 | nogpio0: if CFG_GRGPIO_ENABLE = 0 generate apbo(9) <= apb_none; end generate; | |
|
284 | ||
|
285 | ||
|
286 | ----------------------------------------------------------------------- | |
|
287 | --- SpaceWire Light -------------------------------------------------- | |
|
288 | ----------------------------------------------------------------------- | |
|
289 | ||
|
290 | spw0: spwamba | |
|
291 | generic map ( | |
|
292 | tech => memtech, | |
|
293 | hindex => 2, | |
|
294 | pindex => 10, | |
|
295 | paddr => 10, | |
|
296 | pirq => 10, | |
|
297 | sysfreq => 50.0e6, | |
|
298 | txclkfreq => 10.0e6, | |
|
299 | rximpl => impl_generic, | |
|
300 | rxchunk => 1, | |
|
301 | tximpl => impl_generic, | |
|
302 | timecodegen => true, | |
|
303 | rxfifosize => 11, | |
|
304 | txfifosize => 11, | |
|
305 | desctablesize => 10, | |
|
306 | maxburst => 3 ) | |
|
307 | port map ( | |
|
308 | clk => clkm, | |
|
309 | rxclk => clkm, | |
|
310 | txclk => clkm, | |
|
311 | rstn => rstn, | |
|
312 | apbi => apbi, | |
|
313 | apbo => apbo(10), | |
|
314 | ahbi => ahbmi, | |
|
315 | ahbo => ahbmo(2), | |
|
316 | tick_in => spw_tick_in, | |
|
317 | tick_out => open, | |
|
318 | spw_di => spw_di, | |
|
319 | spw_si => spw_si, | |
|
320 | spw_do => spw_do, | |
|
321 | spw_so => spw_so ); | |
|
322 | ||
|
323 | spw_tick_in <= gpto.tick(2) when CFG_GPT_ENABLE /= 0 else '0'; | |
|
324 | ||
|
325 | spw_rxd_pad: inpad_ds | |
|
326 | generic map (padtech, lvds, x33v) | |
|
327 | port map (spw_rxdp, spw_rxdn, spw_di); | |
|
328 | spw_rxs_pad: inpad_ds | |
|
329 | generic map (padtech, lvds, x33v) | |
|
330 | port map (spw_rxsp, spw_rxsn, spw_si); | |
|
331 | -- spw_txd_pad: outpad_ds | |
|
332 | -- generic map (padtech, lvds, x33v) | |
|
333 | -- port map (spw_txdp, spw_txdn, spw_do, '0'); | |
|
334 | -- spw_txs_pad: outpad_ds | |
|
335 | -- generic map (padtech, lvds, x33v) | |
|
336 | -- port map (spw_txsp, spw_txsn, spw_so, '0'); | |
|
337 | ||
|
338 | ||
|
339 | spw_txdp_pad : outpad generic map (tech => padtech) | |
|
340 | port map (spw_txdp, spw_do); | |
|
341 | spw_txdn_pad : outpad generic map (tech => padtech) | |
|
342 | port map (spw_txdn, not spw_do); | |
|
343 | ||
|
344 | spw_txsp_pad : outpad generic map (tech => padtech) | |
|
345 | port map (spw_txsp, spw_so); | |
|
346 | spw_txsn_pad : outpad generic map (tech => padtech) | |
|
347 | port map (spw_txsn, not spw_so); | |
|
348 | ||
|
349 | end rtl; | |
|
350 |
This diff has been collapsed as it changes many lines, (1550 lines changed) Show them Hide them | |||
@@ -0,0 +1,1550 | |||
|
1 | ||
|
2 | --***************************************************************************** | |
|
3 | -- | |
|
4 | -- Micron Semiconductor Products, Inc. | |
|
5 | -- | |
|
6 | -- Copyright 1997, Micron Semiconductor Products, Inc. | |
|
7 | -- All rights reserved. | |
|
8 | -- | |
|
9 | --***************************************************************************** | |
|
10 | ||
|
11 | -- pragma translate_off | |
|
12 | ||
|
13 | library ieee; | |
|
14 | use ieee.std_logic_1164.ALL; | |
|
15 | use std.textio.all; | |
|
16 | ||
|
17 | PACKAGE mti_pkg IS | |
|
18 | ||
|
19 | FUNCTION To_StdLogic (s : BIT) RETURN STD_LOGIC; | |
|
20 | FUNCTION TO_INTEGER (input : STD_LOGIC) RETURN INTEGER; | |
|
21 | FUNCTION TO_INTEGER (input : BIT_VECTOR) RETURN INTEGER; | |
|
22 | FUNCTION TO_INTEGER (input : STD_LOGIC_VECTOR) RETURN INTEGER; | |
|
23 | PROCEDURE TO_BITVECTOR (VARIABLE input : IN INTEGER; VARIABLE output : OUT BIT_VECTOR); | |
|
24 | ||
|
25 | ||
|
26 | END mti_pkg; | |
|
27 | ||
|
28 | PACKAGE BODY mti_pkg IS | |
|
29 | ||
|
30 | -- Convert BIT to STD_LOGIC | |
|
31 | FUNCTION To_StdLogic (s : BIT) RETURN STD_LOGIC IS | |
|
32 | BEGIN | |
|
33 | CASE s IS | |
|
34 | WHEN '0' => RETURN ('0'); | |
|
35 | WHEN '1' => RETURN ('1'); | |
|
36 | WHEN OTHERS => RETURN ('0'); | |
|
37 | END CASE; | |
|
38 | END; | |
|
39 | ||
|
40 | -- Convert STD_LOGIC to INTEGER | |
|
41 | FUNCTION TO_INTEGER (input : STD_LOGIC) RETURN INTEGER IS | |
|
42 | VARIABLE result : INTEGER := 0; | |
|
43 | VARIABLE weight : INTEGER := 1; | |
|
44 | BEGIN | |
|
45 | IF input = '1' THEN | |
|
46 | result := weight; | |
|
47 | ELSE | |
|
48 | result := 0; -- if unknowns, default to logic 0 | |
|
49 | END IF; | |
|
50 | RETURN result; | |
|
51 | END TO_INTEGER; | |
|
52 | ||
|
53 | -- Convert BIT_VECTOR to INTEGER | |
|
54 | FUNCTION TO_INTEGER (input : BIT_VECTOR) RETURN INTEGER IS | |
|
55 | VARIABLE result : INTEGER := 0; | |
|
56 | VARIABLE weight : INTEGER := 1; | |
|
57 | BEGIN | |
|
58 | FOR i IN input'LOW TO input'HIGH LOOP | |
|
59 | IF input(i) = '1' THEN | |
|
60 | result := result + weight; | |
|
61 | ELSE | |
|
62 | result := result + 0; -- if unknowns, default to logic 0 | |
|
63 | END IF; | |
|
64 | weight := weight * 2; | |
|
65 | END LOOP; | |
|
66 | RETURN result; | |
|
67 | END TO_INTEGER; | |
|
68 | ||
|
69 | -- Convert STD_LOGIC_VECTOR to INTEGER | |
|
70 | FUNCTION TO_INTEGER (input : STD_LOGIC_VECTOR) RETURN INTEGER IS | |
|
71 | VARIABLE result : INTEGER := 0; | |
|
72 | VARIABLE weight : INTEGER := 1; | |
|
73 | BEGIN | |
|
74 | FOR i IN input'LOW TO input'HIGH LOOP | |
|
75 | IF input(i) = '1' THEN | |
|
76 | result := result + weight; | |
|
77 | ELSE | |
|
78 | result := result + 0; -- if unknowns, default to logic 0 | |
|
79 | END IF; | |
|
80 | weight := weight * 2; | |
|
81 | END LOOP; | |
|
82 | RETURN result; | |
|
83 | END TO_INTEGER; | |
|
84 | ||
|
85 | -- Conver INTEGER to BIT_VECTOR | |
|
86 | PROCEDURE TO_BITVECTOR (VARIABLE input : IN INTEGER; VARIABLE output : OUT BIT_VECTOR) IS | |
|
87 | VARIABLE work,offset,outputlen,j : INTEGER := 0; | |
|
88 | BEGIN | |
|
89 | --length of vector | |
|
90 | IF output'LENGTH > 32 THEN --' | |
|
91 | outputlen := 32; | |
|
92 | offset := output'LENGTH - 32; --' | |
|
93 | IF input >= 0 THEN | |
|
94 | FOR i IN offset-1 DOWNTO 0 LOOP | |
|
95 | output(output'HIGH - i) := '0'; --' | |
|
96 | END LOOP; | |
|
97 | ELSE | |
|
98 | FOR i IN offset-1 DOWNTO 0 LOOP | |
|
99 | output(output'HIGH - i) := '1'; --' | |
|
100 | END LOOP; | |
|
101 | END IF; | |
|
102 | ELSE | |
|
103 | outputlen := output'LENGTH; --' | |
|
104 | END IF; | |
|
105 | --positive value | |
|
106 | IF (input >= 0) THEN | |
|
107 | work := input; | |
|
108 | j := outputlen - 1; | |
|
109 | FOR i IN 1 to 32 LOOP | |
|
110 | IF j >= 0 then | |
|
111 | IF (work MOD 2) = 0 THEN | |
|
112 | output(output'HIGH-j-offset) := '0'; --' | |
|
113 | ELSE | |
|
114 | output(output'HIGH-j-offset) := '1'; --' | |
|
115 | END IF; | |
|
116 | END IF; | |
|
117 | work := work / 2; | |
|
118 | j := j - 1; | |
|
119 | END LOOP; | |
|
120 | IF outputlen = 32 THEN | |
|
121 | output(output'HIGH) := '0'; --' | |
|
122 | END IF; | |
|
123 | --negative value | |
|
124 | ELSE | |
|
125 | work := (-input) - 1; | |
|
126 | j := outputlen - 1; | |
|
127 | FOR i IN 1 TO 32 LOOP | |
|
128 | IF j>= 0 THEN | |
|
129 | IF (work MOD 2) = 0 THEN | |
|
130 | output(output'HIGH-j-offset) := '1'; --' | |
|
131 | ELSE | |
|
132 | output(output'HIGH-j-offset) := '0'; --' | |
|
133 | END IF; | |
|
134 | END IF; | |
|
135 | work := work / 2; | |
|
136 | j := j - 1; | |
|
137 | END LOOP; | |
|
138 | IF outputlen = 32 THEN | |
|
139 | output(output'HIGH) := '1'; --' | |
|
140 | END IF; | |
|
141 | END IF; | |
|
142 | END TO_BITVECTOR; | |
|
143 | ||
|
144 | END mti_pkg; | |
|
145 | ||
|
146 | ----------------------------------------------------------------------------------------- | |
|
147 | -- | |
|
148 | -- File Name: MT48LC16M16A2.VHD | |
|
149 | -- Version: 0.0g | |
|
150 | -- Date: June 29th, 2000 | |
|
151 | -- Model: Behavioral | |
|
152 | -- Simulator: Model Technology (PC version 5.3 PE) | |
|
153 | -- | |
|
154 | -- Dependencies: None | |
|
155 | -- | |
|
156 | -- Author: Son P. Huynh | |
|
157 | -- Email: sphuynh@micron.com | |
|
158 | -- Phone: (208) 368-3825 | |
|
159 | -- Company: Micron Technology, Inc. | |
|
160 | -- Part Number: MT48LC16M16A2 (4Mb x 16 x 4 Banks) | |
|
161 | -- | |
|
162 | -- Description: Micron 256Mb SDRAM | |
|
163 | -- | |
|
164 | -- Limitation: - Doesn't check for 4096-cycle refresh --' | |
|
165 | -- | |
|
166 | -- Note: - Set simulator resolution to "ps" accuracy | |
|
167 | -- | |
|
168 | -- Disclaimer: THESE DESIGNS ARE PROVIDED "AS IS" WITH NO WARRANTY | |
|
169 | -- WHATSOEVER AND MICRON SPECIFICALLY DISCLAIMS ANY | |
|
170 | -- IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR | |
|
171 | -- A PARTICULAR PURPOSE, OR AGAINST INFRINGEMENT. | |
|
172 | -- | |
|
173 | -- Copyright (c) 1998 Micron Semiconductor Products, Inc. | |
|
174 | -- All rights researved | |
|
175 | -- | |
|
176 | -- Rev Author Phone Date Changes | |
|
177 | -- ---- ---------------------------- ---------- ------------------------------------- | |
|
178 | -- 0.0g Son Huynh 208-368-3825 06/29/2000 Add Load/Dump memory array | |
|
179 | -- Micron Technology Inc. Modify tWR + tRAS timing check | |
|
180 | -- | |
|
181 | -- 0.0f Son Huynh 208-368-3825 07/08/1999 Fix tWR = 1 Clk + 7.5 ns (Auto) | |
|
182 | -- Micron Technology Inc. Fix tWR = 15 ns (Manual) | |
|
183 | -- Fix tRP (Autoprecharge to AutoRefresh) | |
|
184 | -- | |
|
185 | -- 0.0c Son P. Huynh 208-368-3825 04/08/1999 Fix tWR + tRP in Write with AP | |
|
186 | -- Micron Technology Inc. Fix tRC check in Load Mode Register | |
|
187 | -- | |
|
188 | -- 0.0b Son P. Huynh 208-368-3825 01/06/1998 Derive from 64Mb SDRAM model | |
|
189 | -- Micron Technology Inc. | |
|
190 | -- | |
|
191 | ----------------------------------------------------------------------------------------- | |
|
192 | ||
|
193 | LIBRARY STD; | |
|
194 | USE STD.TEXTIO.ALL; | |
|
195 | LIBRARY IEEE; | |
|
196 | USE IEEE.STD_LOGIC_1164.ALL; | |
|
197 | LIBRARY WORK; | |
|
198 | USE WORK.MTI_PKG.ALL; | |
|
199 | use std.textio.all; | |
|
200 | ||
|
201 | library grlib; | |
|
202 | use grlib.stdlib.all; | |
|
203 | use grlib.stdio.all; | |
|
204 | ||
|
205 | ENTITY mt48lc16m16a2 IS | |
|
206 | GENERIC ( | |
|
207 | -- Timing Parameters for -75 (PC133) and CAS Latency = 2 | |
|
208 | tAC : TIME := 6.0 ns; | |
|
209 | tHZ : TIME := 7.0 ns; | |
|
210 | tOH : TIME := 2.7 ns; | |
|
211 | tMRD : INTEGER := 2; -- 2 Clk Cycles | |
|
212 | tRAS : TIME := 44.0 ns; | |
|
213 | tRC : TIME := 66.0 ns; | |
|
214 | tRCD : TIME := 20.0 ns; | |
|
215 | tRP : TIME := 20.0 ns; | |
|
216 | tRRD : TIME := 15.0 ns; | |
|
217 | tWRa : TIME := 7.5 ns; -- A2 Version - Auto precharge mode only (1 Clk + 7.5 ns) | |
|
218 | tWRp : TIME := 15.0 ns; -- A2 Version - Precharge mode only (15 ns) | |
|
219 | ||
|
220 | tAH : TIME := 0.8 ns; | |
|
221 | tAS : TIME := 1.5 ns; | |
|
222 | tCH : TIME := 2.5 ns; | |
|
223 | tCL : TIME := 2.5 ns; | |
|
224 | tCK : TIME := 10.0 ns; | |
|
225 | tDH : TIME := 0.8 ns; | |
|
226 | tDS : TIME := 1.5 ns; | |
|
227 | tCKH : TIME := 0.8 ns; | |
|
228 | tCKS : TIME := 1.5 ns; | |
|
229 | tCMH : TIME := 0.8 ns; | |
|
230 | tCMS : TIME := 1.5 ns; | |
|
231 | ||
|
232 | addr_bits : INTEGER := 13; | |
|
233 | data_bits : INTEGER := 16; | |
|
234 | col_bits : INTEGER := 9; | |
|
235 | index : INTEGER := 0; | |
|
236 | fname : string := "ram.srec" -- File to read from | |
|
237 | ); | |
|
238 | PORT ( | |
|
239 | Dq : INOUT STD_LOGIC_VECTOR (data_bits - 1 DOWNTO 0) := (OTHERS => 'Z'); | |
|
240 | Addr : IN STD_LOGIC_VECTOR (addr_bits - 1 DOWNTO 0) := (OTHERS => '0'); | |
|
241 | Ba : IN STD_LOGIC_VECTOR := "00"; | |
|
242 | Clk : IN STD_LOGIC := '0'; | |
|
243 | Cke : IN STD_LOGIC := '1'; | |
|
244 | Cs_n : IN STD_LOGIC := '1'; | |
|
245 | Ras_n : IN STD_LOGIC := '1'; | |
|
246 | Cas_n : IN STD_LOGIC := '1'; | |
|
247 | We_n : IN STD_LOGIC := '1'; | |
|
248 | Dqm : IN STD_LOGIC_VECTOR (1 DOWNTO 0) := "00" | |
|
249 | ); | |
|
250 | END mt48lc16m16a2; | |
|
251 | ||
|
252 | ARCHITECTURE behave OF mt48lc16m16a2 IS | |
|
253 | TYPE State IS (ACT, A_REF, BST, LMR, NOP, PRECH, READ, READ_A, WRITE, WRITE_A, LOAD_FILE, DUMP_FILE); | |
|
254 | TYPE Array4xI IS ARRAY (3 DOWNTO 0) OF INTEGER; | |
|
255 | TYPE Array4xT IS ARRAY (3 DOWNTO 0) OF TIME; | |
|
256 | TYPE Array4xB IS ARRAY (3 DOWNTO 0) OF BIT; | |
|
257 | TYPE Array4x2BV IS ARRAY (3 DOWNTO 0) OF BIT_VECTOR (1 DOWNTO 0); | |
|
258 | TYPE Array4xCBV IS ARRAY (4 DOWNTO 0) OF BIT_VECTOR (Col_bits - 1 DOWNTO 0); | |
|
259 | TYPE Array_state IS ARRAY (4 DOWNTO 0) OF State; | |
|
260 | SIGNAL Operation : State := NOP; | |
|
261 | SIGNAL Mode_reg : BIT_VECTOR (addr_bits - 1 DOWNTO 0) := (OTHERS => '0'); | |
|
262 | SIGNAL Active_enable, Aref_enable, Burst_term : BIT := '0'; | |
|
263 | SIGNAL Mode_reg_enable, Prech_enable, Read_enable, Write_enable : BIT := '0'; | |
|
264 | SIGNAL Burst_length_1, Burst_length_2, Burst_length_4, Burst_length_8 : BIT := '0'; | |
|
265 | SIGNAL Cas_latency_2, Cas_latency_3 : BIT := '0'; | |
|
266 | SIGNAL Ras_in, Cas_in, We_in : BIT := '0'; | |
|
267 | SIGNAL Write_burst_mode : BIT := '0'; | |
|
268 | SIGNAL RAS_clk, Sys_clk, CkeZ : BIT := '0'; | |
|
269 | ||
|
270 | -- Checking internal wires | |
|
271 | SIGNAL Pre_chk : BIT_VECTOR (3 DOWNTO 0) := "0000"; | |
|
272 | SIGNAL Act_chk : BIT_VECTOR (3 DOWNTO 0) := "0000"; | |
|
273 | SIGNAL Dq_in_chk, Dq_out_chk : BIT := '0'; | |
|
274 | SIGNAL Bank_chk : BIT_VECTOR (1 DOWNTO 0) := "00"; | |
|
275 | SIGNAL Row_chk : BIT_VECTOR (addr_bits - 1 DOWNTO 0) := (OTHERS => '0'); | |
|
276 | SIGNAL Col_chk : BIT_VECTOR (col_bits - 1 DOWNTO 0) := (OTHERS => '0'); | |
|
277 | ||
|
278 | BEGIN | |
|
279 | -- CS# Decode | |
|
280 | WITH Cs_n SELECT | |
|
281 | Cas_in <= TO_BIT (Cas_n, '1') WHEN '0', | |
|
282 | '1' WHEN '1', | |
|
283 | '1' WHEN OTHERS; | |
|
284 | WITH Cs_n SELECT | |
|
285 | Ras_in <= TO_BIT (Ras_n, '1') WHEN '0', | |
|
286 | '1' WHEN '1', | |
|
287 | '1' WHEN OTHERS; | |
|
288 | WITH Cs_n SELECT | |
|
289 | We_in <= TO_BIT (We_n, '1') WHEN '0', | |
|
290 | '1' WHEN '1', | |
|
291 | '1' WHEN OTHERS; | |
|
292 | ||
|
293 | -- Commands Decode | |
|
294 | Active_enable <= NOT(Ras_in) AND Cas_in AND We_in; | |
|
295 | Aref_enable <= NOT(Ras_in) AND NOT(Cas_in) AND We_in; | |
|
296 | Burst_term <= Ras_in AND Cas_in AND NOT(We_in); | |
|
297 | Mode_reg_enable <= NOT(Ras_in) AND NOT(Cas_in) AND NOT(We_in); | |
|
298 | Prech_enable <= NOT(Ras_in) AND Cas_in AND NOT(We_in); | |
|
299 | Read_enable <= Ras_in AND NOT(Cas_in) AND We_in; | |
|
300 | Write_enable <= Ras_in AND NOT(Cas_in) AND NOT(We_in); | |
|
301 | ||
|
302 | -- Burst Length Decode | |
|
303 | Burst_length_1 <= NOT(Mode_reg(2)) AND NOT(Mode_reg(1)) AND NOT(Mode_reg(0)); | |
|
304 | Burst_length_2 <= NOT(Mode_reg(2)) AND NOT(Mode_reg(1)) AND Mode_reg(0); | |
|
305 | Burst_length_4 <= NOT(Mode_reg(2)) AND Mode_reg(1) AND NOT(Mode_reg(0)); | |
|
306 | Burst_length_8 <= NOT(Mode_reg(2)) AND Mode_reg(1) AND Mode_reg(0); | |
|
307 | ||
|
308 | -- CAS Latency Decode | |
|
309 | Cas_latency_2 <= NOT(Mode_reg(6)) AND Mode_reg(5) AND NOT(Mode_reg(4)); | |
|
310 | Cas_latency_3 <= NOT(Mode_reg(6)) AND Mode_reg(5) AND Mode_reg(4); | |
|
311 | ||
|
312 | -- Write Burst Mode | |
|
313 | Write_burst_mode <= Mode_reg(9); | |
|
314 | ||
|
315 | -- RAS Clock for checking tWR and tRP | |
|
316 | PROCESS | |
|
317 | variable Clk0, Clk1 : integer := 0; | |
|
318 | begin | |
|
319 | RAS_clk <= '1'; | |
|
320 | wait for 0.5 ns; | |
|
321 | RAS_clk <= '0'; | |
|
322 | wait for 0.5 ns; | |
|
323 | if Clk0 > 100 or Clk1 > 100 then | |
|
324 | wait; | |
|
325 | else | |
|
326 | if Clk = '1' and Cke = '1' then | |
|
327 | Clk0 := 0; | |
|
328 | Clk1 := Clk1 + 1; | |
|
329 | elsif Clk = '0' and Cke = '1' then | |
|
330 | Clk0 := Clk0 + 1; | |
|
331 | Clk1 := 0; | |
|
332 | end if; | |
|
333 | end if; | |
|
334 | END PROCESS; | |
|
335 | ||
|
336 | -- System Clock | |
|
337 | int_clk : PROCESS (Clk) | |
|
338 | begin | |
|
339 | IF Clk'LAST_VALUE = '0' AND Clk = '1' THEN --' | |
|
340 | CkeZ <= TO_BIT(Cke, '1'); | |
|
341 | END IF; | |
|
342 | Sys_clk <= CkeZ AND TO_BIT(Clk, '0'); | |
|
343 | END PROCESS; | |
|
344 | ||
|
345 | state_register : PROCESS | |
|
346 | -- NOTE: The extra bits in RAM_TYPE is for checking memory access. A logic 1 means | |
|
347 | -- the location is in use. This will be checked when doing memory DUMP. | |
|
348 | TYPE ram_type IS ARRAY (2**col_bits - 1 DOWNTO 0) OF BIT_VECTOR (data_bits DOWNTO 0); | |
|
349 | TYPE ram_pntr IS ACCESS ram_type; | |
|
350 | TYPE ram_stor IS ARRAY (2**addr_bits - 1 DOWNTO 0) OF ram_pntr; | |
|
351 | VARIABLE Bank0 : ram_stor; | |
|
352 | VARIABLE Bank1 : ram_stor; | |
|
353 | VARIABLE Bank2 : ram_stor; | |
|
354 | VARIABLE Bank3 : ram_stor; | |
|
355 | VARIABLE Row_index, Col_index : INTEGER := 0; | |
|
356 | VARIABLE Dq_temp : BIT_VECTOR (data_bits DOWNTO 0) := (OTHERS => '0'); | |
|
357 | ||
|
358 | VARIABLE Col_addr : Array4xCBV; | |
|
359 | VARIABLE Bank_addr : Array4x2BV; | |
|
360 | VARIABLE Dqm_reg0, Dqm_reg1 : BIT_VECTOR (1 DOWNTO 0) := "00"; | |
|
361 | ||
|
362 | VARIABLE Bank, Previous_bank : BIT_VECTOR (1 DOWNTO 0) := "00"; | |
|
363 | VARIABLE B0_row_addr, B1_row_addr, B2_row_addr, B3_row_addr : BIT_VECTOR (addr_bits - 1 DOWNTO 0) := (OTHERS => '0'); | |
|
364 | VARIABLE Col_brst : BIT_VECTOR (col_bits - 1 DOWNTO 0) := (OTHERS => '0'); | |
|
365 | VARIABLE Row : BIT_VECTOR (addr_bits - 1 DOWNTO 0) := (OTHERS => '0'); | |
|
366 | VARIABLE Col : BIT_VECTOR (col_bits - 1 DOWNTO 0) := (OTHERS => '0'); | |
|
367 | VARIABLE Burst_counter : INTEGER := 0; | |
|
368 | ||
|
369 | VARIABLE Command : Array_state; | |
|
370 | VARIABLE Bank_precharge : Array4x2BV; | |
|
371 | VARIABLE A10_precharge : Array4xB := ('0' & '0' & '0' & '0'); | |
|
372 | VARIABLE Auto_precharge : Array4xB := ('0' & '0' & '0' & '0'); | |
|
373 | VARIABLE Read_precharge : Array4xB := ('0' & '0' & '0' & '0'); | |
|
374 | VARIABLE Write_precharge : Array4xB := ('0' & '0' & '0' & '0'); | |
|
375 | VARIABLE RW_interrupt_read : Array4xB := ('0' & '0' & '0' & '0'); | |
|
376 | VARIABLE RW_interrupt_write : Array4xB := ('0' & '0' & '0' & '0'); | |
|
377 | VARIABLE RW_interrupt_bank : BIT_VECTOR (1 DOWNTO 0) := "00"; | |
|
378 | VARIABLE Count_time : Array4xT := (0 ns & 0 ns & 0 ns & 0 ns); | |
|
379 | VARIABLE Count_precharge : Array4xI := (0 & 0 & 0 & 0); | |
|
380 | ||
|
381 | VARIABLE Data_in_enable, Data_out_enable : BIT := '0'; | |
|
382 | VARIABLE Pc_b0, Pc_b1, Pc_b2, Pc_b3 : BIT := '0'; | |
|
383 | VARIABLE Act_b0, Act_b1, Act_b2, Act_b3 : BIT := '0'; | |
|
384 | ||
|
385 | -- Timing Check | |
|
386 | VARIABLE MRD_chk : INTEGER := 0; | |
|
387 | VARIABLE WR_counter : Array4xI := (0 & 0 & 0 & 0); | |
|
388 | VARIABLE WR_time : Array4xT := (0 ns & 0 ns & 0 ns & 0 ns); | |
|
389 | VARIABLE WR_chkp : Array4xT := (0 ns & 0 ns & 0 ns & 0 ns); | |
|
390 | VARIABLE RC_chk, RRD_chk : TIME := 0 ns; | |
|
391 | VARIABLE RAS_chk0, RAS_chk1, RAS_chk2, RAS_chk3 : TIME := 0 ns; | |
|
392 | VARIABLE RCD_chk0, RCD_chk1, RCD_chk2, RCD_chk3 : TIME := 0 ns; | |
|
393 | VARIABLE RP_chk0, RP_chk1, RP_chk2, RP_chk3 : TIME := 0 ns; | |
|
394 | ||
|
395 | -- Load and Dumb variables | |
|
396 | FILE file_load : TEXT open read_mode is fname; -- Data load | |
|
397 | FILE file_dump : TEXT open write_mode is "dumpdata.txt"; -- Data dump | |
|
398 | VARIABLE bank_load : bit_vector ( 1 DOWNTO 0); | |
|
399 | VARIABLE rows_load : BIT_VECTOR (12 DOWNTO 0); | |
|
400 | VARIABLE cols_load : BIT_VECTOR ( 8 DOWNTO 0); | |
|
401 | VARIABLE data_load : BIT_VECTOR (15 DOWNTO 0); | |
|
402 | VARIABLE i, j : INTEGER; | |
|
403 | VARIABLE good_load : BOOLEAN; | |
|
404 | VARIABLE l : LINE; | |
|
405 | variable load : std_logic := '1'; | |
|
406 | variable dump : std_logic := '0'; | |
|
407 | variable ch : character; | |
|
408 | variable rectype : bit_vector(3 downto 0); | |
|
409 | variable recaddr : bit_vector(31 downto 0); | |
|
410 | variable reclen : bit_vector(7 downto 0); | |
|
411 | variable recdata : bit_vector(0 to 16*8-1); | |
|
412 | ||
|
413 | -- Initialize empty rows | |
|
414 | PROCEDURE Init_mem (Bank : bit_vector (1 DOWNTO 0); Row_index : INTEGER) IS | |
|
415 | VARIABLE i, j : INTEGER := 0; | |
|
416 | BEGIN | |
|
417 | IF Bank = "00" THEN | |
|
418 | IF Bank0 (Row_index) = NULL THEN -- Check to see if row empty | |
|
419 | Bank0 (Row_index) := NEW ram_type; -- Open new row for access | |
|
420 | FOR i IN (2**col_bits - 1) DOWNTO 0 LOOP -- Filled row with zeros | |
|
421 | FOR j IN (data_bits) DOWNTO 0 LOOP | |
|
422 | Bank0 (Row_index) (i) (j) := '0'; | |
|
423 | END LOOP; | |
|
424 | END LOOP; | |
|
425 | END IF; | |
|
426 | ELSIF Bank = "01" THEN | |
|
427 | IF Bank1 (Row_index) = NULL THEN | |
|
428 | Bank1 (Row_index) := NEW ram_type; | |
|
429 | FOR i IN (2**col_bits - 1) DOWNTO 0 LOOP | |
|
430 | FOR j IN (data_bits) DOWNTO 0 LOOP | |
|
431 | Bank1 (Row_index) (i) (j) := '0'; | |
|
432 | END LOOP; | |
|
433 | END LOOP; | |
|
434 | END IF; | |
|
435 | ELSIF Bank = "10" THEN | |
|
436 | IF Bank2 (Row_index) = NULL THEN | |
|
437 | Bank2 (Row_index) := NEW ram_type; | |
|
438 | FOR i IN (2**col_bits - 1) DOWNTO 0 LOOP | |
|
439 | FOR j IN (data_bits) DOWNTO 0 LOOP | |
|
440 | Bank2 (Row_index) (i) (j) := '0'; | |
|
441 | END LOOP; | |
|
442 | END LOOP; | |
|
443 | END IF; | |
|
444 | ELSIF Bank = "11" THEN | |
|
445 | IF Bank3 (Row_index) = NULL THEN | |
|
446 | Bank3 (Row_index) := NEW ram_type; | |
|
447 | FOR i IN (2**col_bits - 1) DOWNTO 0 LOOP | |
|
448 | FOR j IN (data_bits) DOWNTO 0 LOOP | |
|
449 | Bank3 (Row_index) (i) (j) := '0'; | |
|
450 | END LOOP; | |
|
451 | END LOOP; | |
|
452 | END IF; | |
|
453 | END IF; | |
|
454 | END; | |
|
455 | ||
|
456 | -- Burst Counter | |
|
457 | PROCEDURE Burst_decode IS | |
|
458 | VARIABLE Col_int : INTEGER := 0; | |
|
459 | VARIABLE Col_vec, Col_temp : BIT_VECTOR (col_bits - 1 DOWNTO 0) := (OTHERS => '0'); | |
|
460 | BEGIN | |
|
461 | -- Advance Burst Counter | |
|
462 | Burst_counter := Burst_counter + 1; | |
|
463 | ||
|
464 | -- Burst Type | |
|
465 | IF Mode_reg (3) = '0' THEN | |
|
466 | Col_int := TO_INTEGER(Col); | |
|
467 | Col_int := Col_int + 1; | |
|
468 | TO_BITVECTOR (Col_int, Col_temp); | |
|
469 | ELSIF Mode_reg (3) = '1' THEN | |
|
470 | TO_BITVECTOR (Burst_counter, Col_vec); | |
|
471 | Col_temp (2) := Col_vec (2) XOR Col_brst (2); | |
|
472 | Col_temp (1) := Col_vec (1) XOR Col_brst (1); | |
|
473 | Col_temp (0) := Col_vec (0) XOR Col_brst (0); | |
|
474 | END IF; | |
|
475 | ||
|
476 | -- Burst Length | |
|
477 | IF Burst_length_2 = '1' THEN | |
|
478 | Col (0) := Col_temp (0); | |
|
479 | ELSIF Burst_length_4 = '1' THEN | |
|
480 | Col (1 DOWNTO 0) := Col_temp (1 DOWNTO 0); | |
|
481 | ELSIF Burst_length_8 = '1' THEN | |
|
482 | Col (2 DOWNTO 0) := Col_temp (2 DOWNTO 0); | |
|
483 | ELSE | |
|
484 | Col := Col_temp; | |
|
485 | END IF; | |
|
486 | ||
|
487 | -- Burst Read Single Write | |
|
488 | IF Write_burst_mode = '1' AND Data_in_enable = '1' THEN | |
|
489 | Data_in_enable := '0'; | |
|
490 | END IF; | |
|
491 | ||
|
492 | -- Data counter | |
|
493 | IF Burst_length_1 = '1' THEN | |
|
494 | IF Burst_counter >= 1 THEN | |
|
495 | IF Data_in_enable = '1' THEN | |
|
496 | Data_in_enable := '0'; | |
|
497 | ELSIF Data_out_enable = '1' THEN | |
|
498 | Data_out_enable := '0'; | |
|
499 | END IF; | |
|
500 | END IF; | |
|
501 | ELSIF Burst_length_2 = '1' THEN | |
|
502 | IF Burst_counter >= 2 THEN | |
|
503 | IF Data_in_enable = '1' THEN | |
|
504 | Data_in_enable := '0'; | |
|
505 | ELSIF Data_out_enable = '1' THEN | |
|
506 | Data_out_enable := '0'; | |
|
507 | END IF; | |
|
508 | END IF; | |
|
509 | ELSIF Burst_length_4 = '1' THEN | |
|
510 | IF Burst_counter >= 4 THEN | |
|
511 | IF Data_in_enable = '1' THEN | |
|
512 | Data_in_enable := '0'; | |
|
513 | ELSIF Data_out_enable = '1' THEN | |
|
514 | Data_out_enable := '0'; | |
|
515 | END IF; | |
|
516 | END IF; | |
|
517 | ELSIF Burst_length_8 = '1' THEN | |
|
518 | IF Burst_counter >= 8 THEN | |
|
519 | IF Data_in_enable = '1' THEN | |
|
520 | Data_in_enable := '0'; | |
|
521 | ELSIF Data_out_enable = '1' THEN | |
|
522 | Data_out_enable := '0'; | |
|
523 | END IF; | |
|
524 | END IF; | |
|
525 | END IF; | |
|
526 | END; | |
|
527 | ||
|
528 | BEGIN | |
|
529 | WAIT ON Sys_clk, RAS_clk; | |
|
530 | IF Sys_clk'event AND Sys_clk = '1' AND Load = '0' AND Dump = '0' THEN --' | |
|
531 | -- Internal Command Pipeline | |
|
532 | Command(0) := Command(1); | |
|
533 | Command(1) := Command(2); | |
|
534 | Command(2) := Command(3); | |
|
535 | Command(3) := NOP; | |
|
536 | ||
|
537 | Col_addr(0) := Col_addr(1); | |
|
538 | Col_addr(1) := Col_addr(2); | |
|
539 | Col_addr(2) := Col_addr(3); | |
|
540 | Col_addr(3) := (OTHERS => '0'); | |
|
541 | ||
|
542 | Bank_addr(0) := Bank_addr(1); | |
|
543 | Bank_addr(1) := Bank_addr(2); | |
|
544 | Bank_addr(2) := Bank_addr(3); | |
|
545 | Bank_addr(3) := "00"; | |
|
546 | ||
|
547 | Bank_precharge(0) := Bank_precharge(1); | |
|
548 | Bank_precharge(1) := Bank_precharge(2); | |
|
549 | Bank_precharge(2) := Bank_precharge(3); | |
|
550 | Bank_precharge(3) := "00"; | |
|
551 | ||
|
552 | A10_precharge(0) := A10_precharge(1); | |
|
553 | A10_precharge(1) := A10_precharge(2); | |
|
554 | A10_precharge(2) := A10_precharge(3); | |
|
555 | A10_precharge(3) := '0'; | |
|
556 | ||
|
557 | -- Operation Decode (Optional for showing current command on posedge clock / debug feature) | |
|
558 | IF Active_enable = '1' THEN | |
|
559 | Operation <= ACT; | |
|
560 | ELSIF Aref_enable = '1' THEN | |
|
561 | Operation <= A_REF; | |
|
562 | ELSIF Burst_term = '1' THEN | |
|
563 | Operation <= BST; | |
|
564 | ELSIF Mode_reg_enable = '1' THEN | |
|
565 | Operation <= LMR; | |
|
566 | ELSIF Prech_enable = '1' THEN | |
|
567 | Operation <= PRECH; | |
|
568 | ELSIF Read_enable = '1' THEN | |
|
569 | IF Addr(10) = '0' THEN | |
|
570 | Operation <= READ; | |
|
571 | ELSE | |
|
572 | Operation <= READ_A; | |
|
573 | END IF; | |
|
574 | ELSIF Write_enable = '1' THEN | |
|
575 | IF Addr(10) = '0' THEN | |
|
576 | Operation <= WRITE; | |
|
577 | ELSE | |
|
578 | Operation <= WRITE_A; | |
|
579 | END IF; | |
|
580 | ELSE | |
|
581 | Operation <= NOP; | |
|
582 | END IF; | |
|
583 | ||
|
584 | -- Dqm pipeline for Read | |
|
585 | Dqm_reg0 := Dqm_reg1; | |
|
586 | Dqm_reg1 := TO_BITVECTOR(Dqm); | |
|
587 | ||
|
588 | -- Read or Write with Auto Precharge Counter | |
|
589 | IF Auto_precharge (0) = '1' THEN | |
|
590 | Count_precharge (0) := Count_precharge (0) + 1; | |
|
591 | END IF; | |
|
592 | IF Auto_precharge (1) = '1' THEN | |
|
593 | Count_precharge (1) := Count_precharge (1) + 1; | |
|
594 | END IF; | |
|
595 | IF Auto_precharge (2) = '1' THEN | |
|
596 | Count_precharge (2) := Count_precharge (2) + 1; | |
|
597 | END IF; | |
|
598 | IF Auto_precharge (3) = '1' THEN | |
|
599 | Count_precharge (3) := Count_precharge (3) + 1; | |
|
600 | END IF; | |
|
601 | ||
|
602 | -- Auto Precharge Timer for tWR | |
|
603 | if (Burst_length_1 = '1' OR Write_burst_mode = '1') then | |
|
604 | if (Count_precharge(0) = 1) then | |
|
605 | Count_time(0) := NOW; | |
|
606 | end if; | |
|
607 | if (Count_precharge(1) = 1) then | |
|
608 | Count_time(1) := NOW; | |
|
609 | end if; | |
|
610 | if (Count_precharge(2) = 1) then | |
|
611 | Count_time(2) := NOW; | |
|
612 | end if; | |
|
613 | if (Count_precharge(3) = 1) then | |
|
614 | Count_time(3) := NOW; | |
|
615 | end if; | |
|
616 | elsif (Burst_length_2 = '1') then | |
|
617 | if (Count_precharge(0) = 2) then | |
|
618 | Count_time(0) := NOW; | |
|
619 | end if; | |
|
620 | if (Count_precharge(1) = 2) then | |
|
621 | Count_time(1) := NOW; | |
|
622 | end if; | |
|
623 | if (Count_precharge(2) = 2) then | |
|
624 | Count_time(2) := NOW; | |
|
625 | end if; | |
|
626 | if (Count_precharge(3) = 2) then | |
|
627 | Count_time(3) := NOW; | |
|
628 | end if; | |
|
629 | elsif (Burst_length_4 = '1') then | |
|
630 | if (Count_precharge(0) = 4) then | |
|
631 | Count_time(0) := NOW; | |
|
632 | end if; | |
|
633 | if (Count_precharge(1) = 4) then | |
|
634 | Count_time(1) := NOW; | |
|
635 | end if; | |
|
636 | if (Count_precharge(2) = 4) then | |
|
637 | Count_time(2) := NOW; | |
|
638 | end if; | |
|
639 | if (Count_precharge(3) = 4) then | |
|
640 | Count_time(3) := NOW; | |
|
641 | end if; | |
|
642 | elsif (Burst_length_8 = '1') then | |
|
643 | if (Count_precharge(0) = 8) then | |
|
644 | Count_time(0) := NOW; | |
|
645 | end if; | |
|
646 | if (Count_precharge(1) = 8) then | |
|
647 | Count_time(1) := NOW; | |
|
648 | end if; | |
|
649 | if (Count_precharge(2) = 8) then | |
|
650 | Count_time(2) := NOW; | |
|
651 | end if; | |
|
652 | if (Count_precharge(3) = 8) then | |
|
653 | Count_time(3) := NOW; | |
|
654 | end if; | |
|
655 | end if; | |
|
656 | ||
|
657 | -- tMRD Counter | |
|
658 | MRD_chk := MRD_chk + 1; | |
|
659 | ||
|
660 | -- tWR Counter | |
|
661 | WR_counter(0) := WR_counter(0) + 1; | |
|
662 | WR_counter(1) := WR_counter(1) + 1; | |
|
663 | WR_counter(2) := WR_counter(2) + 1; | |
|
664 | WR_counter(3) := WR_counter(3) + 1; | |
|
665 | ||
|
666 | ||
|
667 | -- Auto Refresh | |
|
668 | IF Aref_enable = '1' THEN | |
|
669 | -- Auto Refresh to Auto Refresh | |
|
670 | ASSERT (NOW - RC_chk >= tRC) | |
|
671 | REPORT "tRC violation during Auto Refresh" | |
|
672 | SEVERITY WARNING; | |
|
673 | -- Precharge to Auto Refresh | |
|
674 | ASSERT (NOW - RP_chk0 >= tRP OR NOW - RP_chk1 >= tRP OR NOW - RP_chk2 >= tRP OR NOW - RP_chk3 >= tRP) | |
|
675 | REPORT "tRP violation during Auto Refresh" | |
|
676 | SEVERITY WARNING; | |
|
677 | -- All banks must be idle before refresh | |
|
678 | IF (Pc_b3 ='0' OR Pc_b2 = '0' OR Pc_b1 ='0' OR Pc_b0 = '0') THEN | |
|
679 | ASSERT (FALSE) | |
|
680 | REPORT "All banks must be Precharge before Auto Refresh" | |
|
681 | SEVERITY WARNING; | |
|
682 | END IF; | |
|
683 | -- Record current tRC time | |
|
684 | RC_chk := NOW; | |
|
685 | END IF; | |
|
686 | ||
|
687 | -- Load Mode Register | |
|
688 | IF Mode_reg_enable = '1' THEN | |
|
689 | Mode_reg <= TO_BITVECTOR (Addr); | |
|
690 | IF (Pc_b3 ='0' OR Pc_b2 = '0' OR Pc_b1 ='0' OR Pc_b0 = '0') THEN | |
|
691 | ASSERT (FALSE) | |
|
692 | REPORT "All bank must be Precharge before Load Mode Register" | |
|
693 | SEVERITY WARNING; | |
|
694 | END IF; | |
|
695 | -- REF to LMR | |
|
696 | ASSERT (NOW - RC_chk >= tRC) | |
|
697 | REPORT "tRC violation during Load Mode Register" | |
|
698 | SEVERITY WARNING; | |
|
699 | -- LMR to LMR | |
|
700 | ASSERT (MRD_chk >= tMRD) | |
|
701 | REPORT "tMRD violation during Load Mode Register" | |
|
702 | SEVERITY WARNING; | |
|
703 | -- Record current tMRD time | |
|
704 | MRD_chk := 0; | |
|
705 | END IF; | |
|
706 | ||
|
707 | -- Active Block (latch Bank and Row Address) | |
|
708 | IF Active_enable = '1' THEN | |
|
709 | IF Ba = "00" AND Pc_b0 = '1' THEN | |
|
710 | Act_b0 := '1'; | |
|
711 | Pc_b0 := '0'; | |
|
712 | B0_row_addr := TO_BITVECTOR (Addr); | |
|
713 | RCD_chk0 := NOW; | |
|
714 | RAS_chk0 := NOW; | |
|
715 | -- Precharge to Active Bank 0 | |
|
716 | ASSERT (NOW - RP_chk0 >= tRP) | |
|
717 | REPORT "tRP violation during Activate Bank 0" | |
|
718 | SEVERITY WARNING; | |
|
719 | ELSIF Ba = "01" AND Pc_b1 = '1' THEN | |
|
720 | Act_b1 := '1'; | |
|
721 | Pc_b1 := '0'; | |
|
722 | B1_row_addr := TO_BITVECTOR (Addr); | |
|
723 | RCD_chk1 := NOW; | |
|
724 | RAS_chk1 := NOW; | |
|
725 | -- Precharge to Active Bank 1 | |
|
726 | ASSERT (NOW - RP_chk1 >= tRP) | |
|
727 | REPORT "tRP violation during Activate Bank 1" | |
|
728 | SEVERITY WARNING; | |
|
729 | ELSIF Ba = "10" AND Pc_b2 = '1' THEN | |
|
730 | Act_b2 := '1'; | |
|
731 | Pc_b2 := '0'; | |
|
732 | B2_row_addr := TO_BITVECTOR (Addr); | |
|
733 | RCD_chk2 := NOW; | |
|
734 | RAS_chk2 := NOW; | |
|
735 | -- Precharge to Active Bank 2 | |
|
736 | ASSERT (NOW - RP_chk2 >= tRP) | |
|
737 | REPORT "tRP violation during Activate Bank 2" | |
|
738 | SEVERITY WARNING; | |
|
739 | ELSIF Ba = "11" AND Pc_b3 = '1' THEN | |
|
740 | Act_b3 := '1'; | |
|
741 | Pc_b3 := '0'; | |
|
742 | B3_row_addr := TO_BITVECTOR (Addr); | |
|
743 | RCD_chk3 := NOW; | |
|
744 | RAS_chk3 := NOW; | |
|
745 | -- Precharge to Active Bank 3 | |
|
746 | ASSERT (NOW - RP_chk3 >= tRP) | |
|
747 | REPORT "tRP violation during Activate Bank 3" | |
|
748 | SEVERITY WARNING; | |
|
749 | ELSIF Ba = "00" AND Pc_b0 = '0' THEN | |
|
750 | ASSERT (FALSE) | |
|
751 | REPORT "Bank 0 is not Precharged" | |
|
752 | SEVERITY WARNING; | |
|
753 | ELSIF Ba = "01" AND Pc_b1 = '0' THEN | |
|
754 | ASSERT (FALSE) | |
|
755 | REPORT "Bank 1 is not Precharged" | |
|
756 | SEVERITY WARNING; | |
|
757 | ELSIF Ba = "10" AND Pc_b2 = '0' THEN | |
|
758 | ASSERT (FALSE) | |
|
759 | REPORT "Bank 2 is not Precharged" | |
|
760 | SEVERITY WARNING; | |
|
761 | ELSIF Ba = "11" AND Pc_b3 = '0' THEN | |
|
762 | ASSERT (FALSE) | |
|
763 | REPORT "Bank 3 is not Precharged" | |
|
764 | SEVERITY WARNING; | |
|
765 | END IF; | |
|
766 | -- Active Bank A to Active Bank B | |
|
767 | IF ((Previous_bank /= TO_BITVECTOR (Ba)) AND (NOW - RRD_chk < tRRD)) THEN | |
|
768 | ASSERT (FALSE) | |
|
769 | REPORT "tRRD violation during Activate" | |
|
770 | SEVERITY WARNING; | |
|
771 | END IF; | |
|
772 | -- LMR to ACT | |
|
773 | ASSERT (MRD_chk >= tMRD) | |
|
774 | REPORT "tMRD violation during Activate" | |
|
775 | SEVERITY WARNING; | |
|
776 | -- AutoRefresh to Activate | |
|
777 | ASSERT (NOW - RC_chk >= tRC) | |
|
778 | REPORT "tRC violation during Activate" | |
|
779 | SEVERITY WARNING; | |
|
780 | -- Record variable for checking violation | |
|
781 | RRD_chk := NOW; | |
|
782 | Previous_bank := TO_BITVECTOR (Ba); | |
|
783 | END IF; | |
|
784 | ||
|
785 | -- Precharge Block | |
|
786 | IF Prech_enable = '1' THEN | |
|
787 | IF Addr(10) = '1' THEN | |
|
788 | Pc_b0 := '1'; | |
|
789 | Pc_b1 := '1'; | |
|
790 | Pc_b2 := '1'; | |
|
791 | Pc_b3 := '1'; | |
|
792 | Act_b0 := '0'; | |
|
793 | Act_b1 := '0'; | |
|
794 | Act_b2 := '0'; | |
|
795 | Act_b3 := '0'; | |
|
796 | RP_chk0 := NOW; | |
|
797 | RP_chk1 := NOW; | |
|
798 | RP_chk2 := NOW; | |
|
799 | RP_chk3 := NOW; | |
|
800 | -- Activate to Precharge all banks | |
|
801 | ASSERT ((NOW - RAS_chk0 >= tRAS) OR (NOW - RAS_chk1 >= tRAS)) | |
|
802 | REPORT "tRAS violation during Precharge all banks" | |
|
803 | SEVERITY WARNING; | |
|
804 | -- tWR violation check for Write | |
|
805 | IF ((NOW - WR_chkp(0) < tWRp) OR (NOW - WR_chkp(1) < tWRp) OR | |
|
806 | (NOW - WR_chkp(2) < tWRp) OR (NOW - WR_chkp(3) < tWRp)) THEN | |
|
807 | ASSERT (FALSE) | |
|
808 | REPORT "tWR violation during Precharge ALL banks" | |
|
809 | SEVERITY WARNING; | |
|
810 | END IF; | |
|
811 | ELSIF Addr(10) = '0' THEN | |
|
812 | IF Ba = "00" THEN | |
|
813 | Pc_b0 := '1'; | |
|
814 | Act_b0 := '0'; | |
|
815 | RP_chk0 := NOW; | |
|
816 | -- Activate to Precharge bank 0 | |
|
817 | ASSERT (NOW - RAS_chk0 >= tRAS) | |
|
818 | REPORT "tRAS violation during Precharge bank 0" | |
|
819 | SEVERITY WARNING; | |
|
820 | ELSIF Ba = "01" THEN | |
|
821 | Pc_b1 := '1'; | |
|
822 | Act_b1 := '0'; | |
|
823 | RP_chk1 := NOW; | |
|
824 | -- Activate to Precharge bank 1 | |
|
825 | ASSERT (NOW - RAS_chk1 >= tRAS) | |
|
826 | REPORT "tRAS violation during Precharge bank 1" | |
|
827 | SEVERITY WARNING; | |
|
828 | ELSIF Ba = "10" THEN | |
|
829 | Pc_b2 := '1'; | |
|
830 | Act_b2 := '0'; | |
|
831 | RP_chk2 := NOW; | |
|
832 | -- Activate to Precharge bank 2 | |
|
833 | ASSERT (NOW - RAS_chk2 >= tRAS) | |
|
834 | REPORT "tRAS violation during Precharge bank 2" | |
|
835 | SEVERITY WARNING; | |
|
836 | ELSIF Ba = "11" THEN | |
|
837 | Pc_b3 := '1'; | |
|
838 | Act_b3 := '0'; | |
|
839 | RP_chk3 := NOW; | |
|
840 | -- Activate to Precharge bank 3 | |
|
841 | ASSERT (NOW - RAS_chk3 >= tRAS) | |
|
842 | REPORT "tRAS violation during Precharge bank 3" | |
|
843 | SEVERITY WARNING; | |
|
844 | END IF; | |
|
845 | -- tWR violation check for Write | |
|
846 | ASSERT (NOW - WR_chkp(TO_INTEGER(Ba)) >= tWRp) | |
|
847 | REPORT "tWR violation during Precharge" | |
|
848 | SEVERITY WARNING; | |
|
849 | END IF; | |
|
850 | -- Terminate a Write Immediately (if same bank or all banks) | |
|
851 | IF (Data_in_enable = '1' AND (Bank = TO_BITVECTOR(Ba) OR Addr(10) = '1')) THEN | |
|
852 | Data_in_enable := '0'; | |
|
853 | END IF; | |
|
854 | -- Precharge Command Pipeline for READ | |
|
855 | IF CAS_latency_3 = '1' THEN | |
|
856 | Command(2) := PRECH; | |
|
857 | Bank_precharge(2) := TO_BITVECTOR (Ba); | |
|
858 | A10_precharge(2) := TO_BIT(Addr(10)); | |
|
859 | ELSIF CAS_latency_2 = '1' THEN | |
|
860 | Command(1) := PRECH; | |
|
861 | Bank_precharge(1) := TO_BITVECTOR (Ba); | |
|
862 | A10_precharge(1) := TO_BIT(Addr(10)); | |
|
863 | END IF; | |
|
864 | END IF; | |
|
865 | ||
|
866 | -- Burst Terminate | |
|
867 | IF Burst_term = '1' THEN | |
|
868 | -- Terminate a Write immediately | |
|
869 | IF Data_in_enable = '1' THEN | |
|
870 | Data_in_enable := '0'; | |
|
871 | END IF; | |
|
872 | -- Terminate a Read depend on CAS Latency | |
|
873 | IF CAS_latency_3 = '1' THEN | |
|
874 | Command(2) := BST; | |
|
875 | ELSIF CAS_latency_2 = '1' THEN | |
|
876 | Command(1) := BST; | |
|
877 | END IF; | |
|
878 | END IF; | |
|
879 | ||
|
880 | -- Read, Write, Column Latch | |
|
881 | IF Read_enable = '1' OR Write_enable = '1' THEN | |
|
882 | -- Check to see if bank is open (ACT) for Read or Write | |
|
883 | IF ((Ba="00" AND Pc_b0='1') OR (Ba="01" AND Pc_b1='1') OR (Ba="10" AND Pc_b2='1') OR (Ba="11" AND Pc_b3='1')) THEN | |
|
884 | ASSERT (FALSE) | |
|
885 | REPORT "Cannot Read or Write - Bank is not Activated" | |
|
886 | SEVERITY WARNING; | |
|
887 | END IF; | |
|
888 | -- Activate to Read or Write | |
|
889 | IF Ba = "00" THEN | |
|
890 | ASSERT (NOW - RCD_chk0 >= tRCD) | |
|
891 | REPORT "tRCD violation during Read or Write to Bank 0" | |
|
892 | SEVERITY WARNING; | |
|
893 | ELSIF Ba = "01" THEN | |
|
894 | ASSERT (NOW - RCD_chk1 >= tRCD) | |
|
895 | REPORT "tRCD violation during Read or Write to Bank 1" | |
|
896 | SEVERITY WARNING; | |
|
897 | ELSIF Ba = "10" THEN | |
|
898 | ASSERT (NOW - RCD_chk2 >= tRCD) | |
|
899 | REPORT "tRCD violation during Read or Write to Bank 2" | |
|
900 | SEVERITY WARNING; | |
|
901 | ELSIF Ba = "11" THEN | |
|
902 | ASSERT (NOW - RCD_chk3 >= tRCD) | |
|
903 | REPORT "tRCD violation during Read or Write to Bank 3" | |
|
904 | SEVERITY WARNING; | |
|
905 | END IF; | |
|
906 | ||
|
907 | -- Read Command | |
|
908 | IF Read_enable = '1' THEN | |
|
909 | -- CAS Latency Pipeline | |
|
910 | IF Cas_latency_3 = '1' THEN | |
|
911 | IF Addr(10) = '1' THEN | |
|
912 | Command(2) := READ_A; | |
|
913 | ELSE | |
|
914 | Command(2) := READ; | |
|
915 | END IF; | |
|
916 | Col_addr (2) := TO_BITVECTOR (Addr(col_bits - 1 DOWNTO 0)); | |
|
917 | Bank_addr (2) := TO_BITVECTOR (Ba); | |
|
918 | ELSIF Cas_latency_2 = '1' THEN | |
|
919 | IF Addr(10) = '1' THEN | |
|
920 | Command(1) := READ_A; | |
|
921 | ELSE | |
|
922 | Command(1) := READ; | |
|
923 | END IF; | |
|
924 | Col_addr (1) := TO_BITVECTOR (Addr(col_bits - 1 DOWNTO 0)); | |
|
925 | Bank_addr (1) := TO_BITVECTOR (Ba); | |
|
926 | END IF; | |
|
927 | ||
|
928 | -- Read intterupt a Write (terminate Write immediately) | |
|
929 | IF Data_in_enable = '1' THEN | |
|
930 | Data_in_enable := '0'; | |
|
931 | END IF; | |
|
932 | ||
|
933 | -- Write Command | |
|
934 | ELSIF Write_enable = '1' THEN | |
|
935 | IF Addr(10) = '1' THEN | |
|
936 | Command(0) := WRITE_A; | |
|
937 | ELSE | |
|
938 | Command(0) := WRITE; | |
|
939 | END IF; | |
|
940 | Col_addr (0) := TO_BITVECTOR (Addr(col_bits - 1 DOWNTO 0)); | |
|
941 | Bank_addr (0) := TO_BITVECTOR (Ba); | |
|
942 | ||
|
943 | -- Write intterupt a Write (terminate Write immediately) | |
|
944 | IF Data_in_enable = '1' THEN | |
|
945 | Data_in_enable := '0'; | |
|
946 | END IF; | |
|
947 | ||
|
948 | -- Write interrupt a Read (terminate Read immediately) | |
|
949 | IF Data_out_enable = '1' THEN | |
|
950 | Data_out_enable := '0'; | |
|
951 | END IF; | |
|
952 | END IF; | |
|
953 | ||
|
954 | -- Interrupt a Write with Auto Precharge | |
|
955 | IF Auto_precharge(TO_INTEGER(RW_Interrupt_Bank)) = '1' AND Write_precharge(TO_INTEGER(RW_Interrupt_Bank)) = '1' THEN | |
|
956 | RW_interrupt_write(TO_INTEGER(RW_Interrupt_Bank)) := '1'; | |
|
957 | END IF; | |
|
958 | ||
|
959 | -- Interrupt a Read with Auto Precharge | |
|
960 | IF Auto_precharge(TO_INTEGER(RW_Interrupt_Bank)) = '1' AND Read_precharge(TO_INTEGER(RW_Interrupt_Bank)) = '1' THEN | |
|
961 | RW_interrupt_read(TO_INTEGER(RW_Interrupt_Bank)) := '1'; | |
|
962 | END IF; | |
|
963 | ||
|
964 | -- Read or Write with Auto Precharge | |
|
965 | IF Addr(10) = '1' THEN | |
|
966 | Auto_precharge (TO_INTEGER(Ba)) := '1'; | |
|
967 | Count_precharge (TO_INTEGER(Ba)) := 0; | |
|
968 | RW_Interrupt_Bank := TO_BitVector(Ba); | |
|
969 | IF Read_enable = '1' THEN | |
|
970 | Read_precharge (TO_INTEGER(Ba)) := '1'; | |
|
971 | ELSIF Write_enable = '1' THEN | |
|
972 | Write_precharge (TO_INTEGER(Ba)) := '1'; | |
|
973 | END IF; | |
|
974 | END IF; | |
|
975 | END IF; | |
|
976 | ||
|
977 | -- Read with AutoPrecharge Calculation | |
|
978 | -- The device start internal precharge when: | |
|
979 | -- 1. BL/2 cycles after command | |
|
980 | -- and 2. Meet tRAS requirement | |
|
981 | -- or 3. Interrupt by a Read or Write (with or without Auto Precharge) | |
|
982 | IF ((Auto_precharge(0) = '1') AND (Read_precharge(0) = '1')) THEN | |
|
983 | IF (((NOW - RAS_chk0 >= tRAS) AND | |
|
984 | ((Burst_length_1 = '1' AND Count_precharge(0) >= 1) OR | |
|
985 | (Burst_length_2 = '1' AND Count_precharge(0) >= 2) OR | |
|
986 | (Burst_length_4 = '1' AND Count_precharge(0) >= 4) OR | |
|
987 | (Burst_length_8 = '1' AND Count_precharge(0) >= 8))) OR | |
|
988 | (RW_interrupt_read(0) = '1')) THEN | |
|
989 | Pc_b0 := '1'; | |
|
990 | Act_b0 := '0'; | |
|
991 | RP_chk0 := NOW; | |
|
992 | Auto_precharge(0) := '0'; | |
|
993 | Read_precharge(0) := '0'; | |
|
994 | RW_interrupt_read(0) := '0'; | |
|
995 | END IF; | |
|
996 | END IF; | |
|
997 | IF ((Auto_precharge(1) = '1') AND (Read_precharge(1) = '1')) THEN | |
|
998 | IF (((NOW - RAS_chk1 >= tRAS) AND | |
|
999 | ((Burst_length_1 = '1' AND Count_precharge(1) >= 1) OR | |
|
1000 | (Burst_length_2 = '1' AND Count_precharge(1) >= 2) OR | |
|
1001 | (Burst_length_4 = '1' AND Count_precharge(1) >= 4) OR | |
|
1002 | (Burst_length_8 = '1' AND Count_precharge(1) >= 8))) OR | |
|
1003 | (RW_interrupt_read(1) = '1')) THEN | |
|
1004 | Pc_b1 := '1'; | |
|
1005 | Act_b1 := '0'; | |
|
1006 | RP_chk1 := NOW; | |
|
1007 | Auto_precharge(1) := '0'; | |
|
1008 | Read_precharge(1) := '0'; | |
|
1009 | RW_interrupt_read(1) := '0'; | |
|
1010 | END IF; | |
|
1011 | END IF; | |
|
1012 | IF ((Auto_precharge(2) = '1') AND (Read_precharge(2) = '1')) THEN | |
|
1013 | IF (((NOW - RAS_chk2 >= tRAS) AND | |
|
1014 | ((Burst_length_1 = '1' AND Count_precharge(2) >= 1) OR | |
|
1015 | (Burst_length_2 = '1' AND Count_precharge(2) >= 2) OR | |
|
1016 | (Burst_length_4 = '1' AND Count_precharge(2) >= 4) OR | |
|
1017 | (Burst_length_8 = '1' AND Count_precharge(2) >= 8))) OR | |
|
1018 | (RW_interrupt_read(2) = '1')) THEN | |
|
1019 | Pc_b2 := '1'; | |
|
1020 | Act_b2 := '0'; | |
|
1021 | RP_chk2 := NOW; | |
|
1022 | Auto_precharge(2) := '0'; | |
|
1023 | Read_precharge(2) := '0'; | |
|
1024 | RW_interrupt_read(2) := '0'; | |
|
1025 | END IF; | |
|
1026 | END IF; | |
|
1027 | IF ((Auto_precharge(3) = '1') AND (Read_precharge(3) = '1')) THEN | |
|
1028 | IF (((NOW - RAS_chk3 >= tRAS) AND | |
|
1029 | ((Burst_length_1 = '1' AND Count_precharge(3) >= 1) OR | |
|
1030 | (Burst_length_2 = '1' AND Count_precharge(3) >= 2) OR | |
|
1031 | (Burst_length_4 = '1' AND Count_precharge(3) >= 4) OR | |
|
1032 | (Burst_length_8 = '1' AND Count_precharge(3) >= 8))) OR | |
|
1033 | (RW_interrupt_read(3) = '1')) THEN | |
|
1034 | Pc_b3 := '1'; | |
|
1035 | Act_b3 := '0'; | |
|
1036 | RP_chk3 := NOW; | |
|
1037 | Auto_precharge(3) := '0'; | |
|
1038 | Read_precharge(3) := '0'; | |
|
1039 | RW_interrupt_read(3) := '0'; | |
|
1040 | END IF; | |
|
1041 | END IF; | |
|
1042 | ||
|
1043 | -- Internal Precharge or Bst | |
|
1044 | IF Command(0) = PRECH THEN -- PRECH terminate a read if same bank or all banks | |
|
1045 | IF Bank_precharge(0) = Bank OR A10_precharge(0) = '1' THEN | |
|
1046 | IF Data_out_enable = '1' THEN | |
|
1047 | Data_out_enable := '0'; | |
|
1048 | END IF; | |
|
1049 | END IF; | |
|
1050 | ELSIF Command(0) = BST THEN -- BST terminate a read regardless of bank | |
|
1051 | IF Data_out_enable = '1' THEN | |
|
1052 | Data_out_enable := '0'; | |
|
1053 | END IF; | |
|
1054 | END IF; | |
|
1055 | ||
|
1056 | IF Data_out_enable = '0' THEN | |
|
1057 | Dq <= TRANSPORT (OTHERS => 'Z') AFTER tOH; | |
|
1058 | END IF; | |
|
1059 | ||
|
1060 | -- Detect Read or Write Command | |
|
1061 | IF Command(0) = READ OR Command(0) = READ_A THEN | |
|
1062 | Bank := Bank_addr (0); | |
|
1063 | Col := Col_addr (0); | |
|
1064 | Col_brst := Col_addr (0); | |
|
1065 | IF Bank_addr (0) = "00" THEN | |
|
1066 | Row := B0_row_addr; | |
|
1067 | ELSIF Bank_addr (0) = "01" THEN | |
|
1068 | Row := B1_row_addr; | |
|
1069 | ELSIF Bank_addr (0) = "10" THEN | |
|
1070 | Row := B2_row_addr; | |
|
1071 | ELSE | |
|
1072 | Row := B3_row_addr; | |
|
1073 | END IF; | |
|
1074 | Burst_counter := 0; | |
|
1075 | Data_in_enable := '0'; | |
|
1076 | Data_out_enable := '1'; | |
|
1077 | ELSIF Command(0) = WRITE OR Command(0) = WRITE_A THEN | |
|
1078 | Bank := Bank_addr(0); | |
|
1079 | Col := Col_addr(0); | |
|
1080 | Col_brst := Col_addr(0); | |
|
1081 | IF Bank_addr (0) = "00" THEN | |
|
1082 | Row := B0_row_addr; | |
|
1083 | ELSIF Bank_addr (0) = "01" THEN | |
|
1084 | Row := B1_row_addr; | |
|
1085 | ELSIF Bank_addr (0) = "10" THEN | |
|
1086 | Row := B2_row_addr; | |
|
1087 | ELSE | |
|
1088 | Row := B3_row_addr; | |
|
1089 | END IF; | |
|
1090 | Burst_counter := 0; | |
|
1091 | Data_in_enable := '1'; | |
|
1092 | Data_out_enable := '0'; | |
|
1093 | END IF; | |
|
1094 | ||
|
1095 | -- DQ (Driver / Receiver) | |
|
1096 | Row_index := TO_INTEGER (Row); | |
|
1097 | Col_index := TO_INTEGER (Col); | |
|
1098 | IF Data_in_enable = '1' THEN | |
|
1099 | IF Dqm /= "11" THEN | |
|
1100 | Init_mem (Bank, Row_index); | |
|
1101 | IF Bank = "00" THEN | |
|
1102 | Dq_temp := Bank0 (Row_index) (Col_index); | |
|
1103 | IF Dqm = "01" THEN | |
|
1104 | Dq_temp (15 DOWNTO 8) := TO_BITVECTOR (Dq (15 DOWNTO 8)); | |
|
1105 | ELSIF Dqm = "10" THEN | |
|
1106 | Dq_temp (7 DOWNTO 0) := TO_BITVECTOR (Dq (7 DOWNTO 0)); | |
|
1107 | ELSE | |
|
1108 | Dq_temp (15 DOWNTO 0) := TO_BITVECTOR (Dq (15 DOWNTO 0)); | |
|
1109 | END IF; | |
|
1110 | Bank0 (Row_index) (Col_index) := ('1' & Dq_temp(data_bits - 1 DOWNTO 0)); | |
|
1111 | ELSIF Bank = "01" THEN | |
|
1112 | Dq_temp := Bank1 (Row_index) (Col_index); | |
|
1113 | IF Dqm = "01" THEN | |
|
1114 | Dq_temp (15 DOWNTO 8) := TO_BITVECTOR (Dq (15 DOWNTO 8)); | |
|
1115 | ELSIF Dqm = "10" THEN | |
|
1116 | Dq_temp (7 DOWNTO 0) := TO_BITVECTOR (Dq (7 DOWNTO 0)); | |
|
1117 | ELSE | |
|
1118 | Dq_temp (15 DOWNTO 0) := TO_BITVECTOR (Dq (15 DOWNTO 0)); | |
|
1119 | END IF; | |
|
1120 | Bank1 (Row_index) (Col_index) := ('1' & Dq_temp(data_bits - 1 DOWNTO 0)); | |
|
1121 | ELSIF Bank = "10" THEN | |
|
1122 | Dq_temp := Bank2 (Row_index) (Col_index); | |
|
1123 | IF Dqm = "01" THEN | |
|
1124 | Dq_temp (15 DOWNTO 8) := TO_BITVECTOR (Dq (15 DOWNTO 8)); | |
|
1125 | ELSIF Dqm = "10" THEN | |
|
1126 | Dq_temp (7 DOWNTO 0) := TO_BITVECTOR (Dq (7 DOWNTO 0)); | |
|
1127 | ELSE | |
|
1128 | Dq_temp (15 DOWNTO 0) := TO_BITVECTOR (Dq (15 DOWNTO 0)); | |
|
1129 | END IF; | |
|
1130 | Bank2 (Row_index) (Col_index) := ('1' & Dq_temp(data_bits - 1 DOWNTO 0)); | |
|
1131 | ELSIF Bank = "11" THEN | |
|
1132 | Dq_temp := Bank3 (Row_index) (Col_index); | |
|
1133 | IF Dqm = "01" THEN | |
|
1134 | Dq_temp (15 DOWNTO 8) := TO_BITVECTOR (Dq (15 DOWNTO 8)); | |
|
1135 | ELSIF Dqm = "10" THEN | |
|
1136 | Dq_temp (7 DOWNTO 0) := TO_BITVECTOR (Dq (7 DOWNTO 0)); | |
|
1137 | ELSE | |
|
1138 | Dq_temp (15 DOWNTO 0) := TO_BITVECTOR (Dq (15 DOWNTO 0)); | |
|
1139 | END IF; | |
|
1140 | Bank3 (Row_index) (Col_index) := ('1' & Dq_temp(data_bits - 1 DOWNTO 0)); | |
|
1141 | END IF; | |
|
1142 | WR_chkp(TO_INTEGER(Bank)) := NOW; | |
|
1143 | WR_counter(TO_INTEGER(Bank)) := 0; | |
|
1144 | END IF; | |
|
1145 | Burst_decode; | |
|
1146 | ELSIF Data_out_enable = '1' THEN | |
|
1147 | IF Dqm_reg0 /= "11" THEN | |
|
1148 | Init_mem (Bank, Row_index); | |
|
1149 | IF Bank = "00" THEN | |
|
1150 | Dq_temp := Bank0 (Row_index) (Col_index); | |
|
1151 | IF Dqm_reg0 = "00" THEN | |
|
1152 | Dq (15 DOWNTO 0) <= TRANSPORT TO_STDLOGICVECTOR (Dq_temp (15 DOWNTO 0)) AFTER tAC; | |
|
1153 | ELSIF Dqm_reg0 = "01" THEN | |
|
1154 | Dq (15 DOWNTO 8) <= TRANSPORT TO_STDLOGICVECTOR (Dq_temp (15 DOWNTO 8)) AFTER tAC; | |
|
1155 | Dq (7 DOWNTO 0) <= TRANSPORT (OTHERS => 'Z') AFTER tAC; | |
|
1156 | ELSIF Dqm_reg0 = "10" THEN | |
|
1157 | Dq (15 DOWNTO 8) <= TRANSPORT (OTHERS => 'Z') AFTER tAC; | |
|
1158 | Dq (7 DOWNTO 0) <= TRANSPORT TO_STDLOGICVECTOR (Dq_temp (7 DOWNTO 0)) AFTER tAC; | |
|
1159 | END IF; | |
|
1160 | ELSIF Bank = "01" THEN | |
|
1161 | Dq_temp := Bank1 (Row_index) (Col_index); | |
|
1162 | IF Dqm_reg0 = "00" THEN | |
|
1163 | Dq (15 DOWNTO 0) <= TRANSPORT TO_STDLOGICVECTOR (Dq_temp (15 DOWNTO 0)) AFTER tAC; | |
|
1164 | ELSIF Dqm_reg0 = "01" THEN | |
|
1165 | Dq (15 DOWNTO 8) <= TRANSPORT TO_STDLOGICVECTOR (Dq_temp (15 DOWNTO 8)) AFTER tAC; | |
|
1166 | Dq (7 DOWNTO 0) <= TRANSPORT (OTHERS => 'Z') AFTER tAC; | |
|
1167 | ELSIF Dqm_reg0 = "10" THEN | |
|
1168 | Dq (15 DOWNTO 8) <= TRANSPORT (OTHERS => 'Z') AFTER tAC; | |
|
1169 | Dq (7 DOWNTO 0) <= TRANSPORT TO_STDLOGICVECTOR (Dq_temp (7 DOWNTO 0)) AFTER tAC; | |
|
1170 | END IF; | |
|
1171 | ELSIF Bank = "10" THEN | |
|
1172 | Dq_temp := Bank2 (Row_index) (Col_index); | |
|
1173 | IF Dqm_reg0 = "00" THEN | |
|
1174 | Dq (15 DOWNTO 0) <= TRANSPORT TO_STDLOGICVECTOR (Dq_temp (15 DOWNTO 0)) AFTER tAC; | |
|
1175 | ELSIF Dqm_reg0 = "01" THEN | |
|
1176 | Dq (15 DOWNTO 8) <= TRANSPORT TO_STDLOGICVECTOR (Dq_temp (15 DOWNTO 8)) AFTER tAC; | |
|
1177 | Dq (7 DOWNTO 0) <= TRANSPORT (OTHERS => 'Z') AFTER tAC; | |
|
1178 | ELSIF Dqm_reg0 = "10" THEN | |
|
1179 | Dq (15 DOWNTO 8) <= TRANSPORT (OTHERS => 'Z') AFTER tAC; | |
|
1180 | Dq (7 DOWNTO 0) <= TRANSPORT TO_STDLOGICVECTOR (Dq_temp (7 DOWNTO 0)) AFTER tAC; | |
|
1181 | END IF; | |
|
1182 | ELSIF Bank = "11" THEN | |
|
1183 | Dq_temp := Bank3 (Row_index) (Col_index); | |
|
1184 | IF Dqm_reg0 = "00" THEN | |
|
1185 | Dq (15 DOWNTO 0) <= TRANSPORT TO_STDLOGICVECTOR (Dq_temp (15 DOWNTO 0)) AFTER tAC; | |
|
1186 | ELSIF Dqm_reg0 = "01" THEN | |
|
1187 | Dq (15 DOWNTO 8) <= TRANSPORT TO_STDLOGICVECTOR (Dq_temp (15 DOWNTO 8)) AFTER tAC; | |
|
1188 | Dq (7 DOWNTO 0) <= TRANSPORT (OTHERS => 'Z') AFTER tAC; | |
|
1189 | ELSIF Dqm_reg0 = "10" THEN | |
|
1190 | Dq (15 DOWNTO 8) <= TRANSPORT (OTHERS => 'Z') AFTER tAC; | |
|
1191 | Dq (7 DOWNTO 0) <= TRANSPORT TO_STDLOGICVECTOR (Dq_temp (7 DOWNTO 0)) AFTER tAC; | |
|
1192 | END IF; | |
|
1193 | END IF; | |
|
1194 | ELSE | |
|
1195 | Dq <= TRANSPORT (OTHERS => 'Z') AFTER tHZ; | |
|
1196 | END IF; | |
|
1197 | Burst_decode; | |
|
1198 | END IF; | |
|
1199 | ELSIF Sys_clk'event AND Sys_clk = '1' AND Load = '1' AND Dump = '0' THEN --' | |
|
1200 | Operation <= LOAD_FILE; | |
|
1201 | load := '0'; | |
|
1202 | -- ASSERT (FALSE) REPORT "Reading memory array from file. This operation may take several minutes. Please wait..." | |
|
1203 | -- SEVERITY NOTE; | |
|
1204 | WHILE NOT endfile(file_load) LOOP | |
|
1205 | readline(file_load, l); | |
|
1206 | read(l, ch); | |
|
1207 | if (ch /= 'S') or (ch /= 's') then | |
|
1208 | hread(l, rectype); | |
|
1209 | hread(l, reclen); | |
|
1210 | recaddr := (others => '0'); | |
|
1211 | case rectype is | |
|
1212 | when "0001" => | |
|
1213 | hread(l, recaddr(15 downto 0)); | |
|
1214 | when "0010" => | |
|
1215 | hread(l, recaddr(23 downto 0)); | |
|
1216 | when "0011" => | |
|
1217 | hread(l, recaddr); | |
|
1218 | recaddr(31 downto 24) := (others => '0'); | |
|
1219 | when others => next; | |
|
1220 | end case; | |
|
1221 | hread(l, recdata); | |
|
1222 | ||
|
1223 | if index < 32 then | |
|
1224 | Bank_Load := recaddr(25 downto 24); | |
|
1225 | Rows_Load := recaddr(23 downto 11); | |
|
1226 | Cols_Load := recaddr(10 downto 2); | |
|
1227 | Init_Mem (Bank_Load, To_Integer(Rows_Load)); | |
|
1228 | IF Bank_Load = "00" THEN | |
|
1229 | for i in 0 to 3 loop | |
|
1230 | Bank0 (To_Integer(Rows_Load)) (To_Integer(Cols_Load)+i) := ('1' & recdata(i*32+index to i*32+index+15)); | |
|
1231 | end loop; | |
|
1232 | ELSIF Bank_Load = "01" THEN | |
|
1233 | for i in 0 to 3 loop | |
|
1234 | Bank1 (To_Integer(Rows_Load)) (To_Integer(Cols_Load)+i) := ('1' & recdata(i*32+index to i*32+index+15)); | |
|
1235 | end loop; | |
|
1236 | ELSIF Bank_Load = "10" THEN | |
|
1237 | for i in 0 to 3 loop | |
|
1238 | Bank2 (To_Integer(Rows_Load)) (To_Integer(Cols_Load)+i) := ('1' & recdata(i*32+index to i*32+index+15)); | |
|
1239 | end loop; | |
|
1240 | ELSIF Bank_Load = "11" THEN | |
|
1241 | for i in 0 to 3 loop | |
|
1242 | Bank3 (To_Integer(Rows_Load)) (To_Integer(Cols_Load)+i) := ('1' & recdata(i*32+index to i*32+index+15)); | |
|
1243 | end loop; | |
|
1244 | END IF; | |
|
1245 | elsif(index < 1024) then | |
|
1246 | Bank_Load := recaddr(26 downto 25); | |
|
1247 | Rows_Load := recaddr(24 downto 12); | |
|
1248 | Cols_Load := recaddr(11 downto 3); | |
|
1249 | Init_Mem (Bank_Load, To_Integer(Rows_Load)); | |
|
1250 | IF Bank_Load = "00" THEN | |
|
1251 | for i in 0 to 1 loop | |
|
1252 | Bank0 (To_Integer(Rows_Load)) (To_Integer(Cols_Load)+i) := ('1' & recdata(i*64+index-32 to i*64+index-32+15)); | |
|
1253 | end loop; | |
|
1254 | ELSIF Bank_Load = "01" THEN | |
|
1255 | for i in 0 to 1 loop | |
|
1256 | Bank1 (To_Integer(Rows_Load)) (To_Integer(Cols_Load)+i) := ('1' & recdata(i*64+index-32 to i*64+index-32+15)); | |
|
1257 | end loop; | |
|
1258 | ELSIF Bank_Load = "10" THEN | |
|
1259 | for i in 0 to 1 loop | |
|
1260 | Bank2 (To_Integer(Rows_Load)) (To_Integer(Cols_Load)+i) := ('1' & recdata(i*64+index-32 to i*64+index-32+15)); | |
|
1261 | end loop; | |
|
1262 | ELSIF Bank_Load = "11" THEN | |
|
1263 | for i in 0 to 1 loop | |
|
1264 | Bank3 (To_Integer(Rows_Load)) (To_Integer(Cols_Load)+i) := ('1' & recdata(i*64+index-32 to i*64+index-32+15)); | |
|
1265 | end loop; | |
|
1266 | END IF; | |
|
1267 | else | |
|
1268 | Bank_Load := recaddr(22 downto 21); | |
|
1269 | Rows_Load := '0' & recaddr(20 downto 9); | |
|
1270 | Cols_Load := '0' & recaddr(8 downto 1); | |
|
1271 | Init_Mem (Bank_Load, To_Integer(Rows_Load)); | |
|
1272 | IF Bank_Load = "00" THEN | |
|
1273 | for i in 0 to 7 loop | |
|
1274 | Bank0 (To_Integer(Rows_Load)) (To_Integer(Cols_Load)+i) := ('1' & recdata(i*16 to i*16+15)); | |
|
1275 | end loop; | |
|
1276 | ELSIF Bank_Load = "01" THEN | |
|
1277 | for i in 0 to 7 loop | |
|
1278 | Bank1 (To_Integer(Rows_Load)) (To_Integer(Cols_Load)+i) := ('1' & recdata(i*16 to i*16+15)); | |
|
1279 | end loop; | |
|
1280 | ELSIF Bank_Load = "10" THEN | |
|
1281 | for i in 0 to 7 loop | |
|
1282 | Bank2 (To_Integer(Rows_Load)) (To_Integer(Cols_Load)+i) := ('1' & recdata(i*16 to i*16+15)); | |
|
1283 | end loop; | |
|
1284 | ELSIF Bank_Load = "11" THEN | |
|
1285 | for i in 0 to 7 loop | |
|
1286 | Bank3 (To_Integer(Rows_Load)) (To_Integer(Cols_Load)+i) := ('1' & recdata(i*16 to i*16+15)); | |
|
1287 | end loop; | |
|
1288 | END IF; | |
|
1289 | END IF; | |
|
1290 | END IF; | |
|
1291 | END LOOP; | |
|
1292 | ELSIF Sys_clk'event AND Sys_clk = '1' AND Load = '0' AND Dump = '1' THEN --' | |
|
1293 | Operation <= DUMP_FILE; | |
|
1294 | ASSERT (FALSE) REPORT "Writing memory array to file. This operation may take several minutes. Please wait..." | |
|
1295 | SEVERITY NOTE; | |
|
1296 | WRITE (l, string'("# Micron Technology, Inc. (FILE DUMP / MEMORY DUMP)")); --' | |
|
1297 | WRITELINE (file_dump, l); | |
|
1298 | WRITE (l, string'("# BA ROWS COLS DQ")); --' | |
|
1299 | WRITELINE (file_dump, l); | |
|
1300 | WRITE (l, string'("# -- ------------- --------- ----------------")); --' | |
|
1301 | WRITELINE (file_dump, l); | |
|
1302 | -- Dumping Bank 0 | |
|
1303 | FOR i IN 0 TO 2**addr_bits -1 LOOP | |
|
1304 | -- Check if ROW is NULL | |
|
1305 | IF Bank0 (i) /= NULL THEN | |
|
1306 | For j IN 0 TO 2**col_bits - 1 LOOP | |
|
1307 | -- Check if COL is NULL | |
|
1308 | NEXT WHEN Bank0 (i) (j) (data_bits) = '0'; | |
|
1309 | WRITE (l, string'("00"), right, 4); --' | |
|
1310 | WRITE (l, To_BitVector(Conv_Std_Logic_Vector(i, addr_bits)), right, addr_bits+1); | |
|
1311 | WRITE (l, To_BitVector(Conv_std_Logic_Vector(j, col_bits)), right, col_bits+1); | |
|
1312 | WRITE (l, Bank0 (i) (j) (data_bits -1 DOWNTO 0), right, data_bits+1); | |
|
1313 | WRITELINE (file_dump, l); | |
|
1314 | END LOOP; | |
|
1315 | END IF; | |
|
1316 | END LOOP; | |
|
1317 | -- Dumping Bank 1 | |
|
1318 | FOR i IN 0 TO 2**addr_bits -1 LOOP | |
|
1319 | -- Check if ROW is NULL | |
|
1320 | IF Bank1 (i) /= NULL THEN | |
|
1321 | For j IN 0 TO 2**col_bits - 1 LOOP | |
|
1322 | -- Check if COL is NULL | |
|
1323 | NEXT WHEN Bank1 (i) (j) (data_bits) = '0'; | |
|
1324 | WRITE (l, string'("01"), right, 4); --' | |
|
1325 | WRITE (l, To_BitVector(Conv_Std_Logic_Vector(i, addr_bits)), right, addr_bits+1); | |
|
1326 | WRITE (l, To_BitVector(Conv_std_Logic_Vector(j, col_bits)), right, col_bits+1); | |
|
1327 | WRITE (l, Bank1 (i) (j) (data_bits -1 DOWNTO 0), right, data_bits+1); | |
|
1328 | WRITELINE (file_dump, l); | |
|
1329 | END LOOP; | |
|
1330 | END IF; | |
|
1331 | END LOOP; | |
|
1332 | -- Dumping Bank 2 | |
|
1333 | FOR i IN 0 TO 2**addr_bits -1 LOOP | |
|
1334 | -- Check if ROW is NULL | |
|
1335 | IF Bank2 (i) /= NULL THEN | |
|
1336 | For j IN 0 TO 2**col_bits - 1 LOOP | |
|
1337 | -- Check if COL is NULL | |
|
1338 | NEXT WHEN Bank2 (i) (j) (data_bits) = '0'; | |
|
1339 | WRITE (l, string'("10"), right, 4); --' | |
|
1340 | WRITE (l, To_BitVector(Conv_Std_Logic_Vector(i, addr_bits)), right, addr_bits+1); | |
|
1341 | WRITE (l, To_BitVector(Conv_std_Logic_Vector(j, col_bits)), right, col_bits+1); | |
|
1342 | WRITE (l, Bank2 (i) (j) (data_bits -1 DOWNTO 0), right, data_bits+1); | |
|
1343 | WRITELINE (file_dump, l); | |
|
1344 | END LOOP; | |
|
1345 | END IF; | |
|
1346 | END LOOP; | |
|
1347 | -- Dumping Bank 3 | |
|
1348 | FOR i IN 0 TO 2**addr_bits -1 LOOP | |
|
1349 | -- Check if ROW is NULL | |
|
1350 | IF Bank3 (i) /= NULL THEN | |
|
1351 | For j IN 0 TO 2**col_bits - 1 LOOP | |
|
1352 | -- Check if COL is NULL | |
|
1353 | NEXT WHEN Bank3 (i) (j) (data_bits) = '0'; | |
|
1354 | WRITE (l, string'("11"), right, 4); --' | |
|
1355 | WRITE (l, To_BitVector(Conv_Std_Logic_Vector(i, addr_bits)), right, addr_bits+1); | |
|
1356 | WRITE (l, To_BitVector(Conv_std_Logic_Vector(j, col_bits)), right, col_bits+1); | |
|
1357 | WRITE (l, Bank3 (i) (j) (data_bits -1 DOWNTO 0), right, data_bits+1); | |
|
1358 | WRITELINE (file_dump, l); | |
|
1359 | END LOOP; | |
|
1360 | END IF; | |
|
1361 | END LOOP; | |
|
1362 | END IF; | |
|
1363 | ||
|
1364 | -- Write with AutoPrecharge Calculation | |
|
1365 | -- The device start internal precharge when: | |
|
1366 | -- 1. tWR cycles after command | |
|
1367 | -- and 2. Meet tRAS requirement | |
|
1368 | -- or 3. Interrupt by a Read or Write (with or without Auto Precharge) | |
|
1369 | IF ((Auto_precharge(0) = '1') AND (Write_precharge(0) = '1')) THEN | |
|
1370 | IF (((NOW - RAS_chk0 >= tRAS) AND | |
|
1371 | (((Burst_length_1 = '1' OR Write_burst_mode = '1' ) AND Count_precharge(0) >= 1 AND NOW - Count_time(0) >= tWRa) OR | |
|
1372 | (Burst_length_2 = '1' AND Count_precharge(0) >= 2 AND NOW - Count_time(0) >= tWRa) OR | |
|
1373 | (Burst_length_4 = '1' AND Count_precharge(0) >= 4 AND NOW - Count_time(0) >= tWRa) OR | |
|
1374 | (Burst_length_8 = '1' AND Count_precharge(0) >= 8 AND NOW - Count_time(0) >= tWRa))) OR | |
|
1375 | (RW_interrupt_write(0) = '1' AND WR_counter(0) >= 1 AND NOW - WR_time(0) >= tWRa)) THEN | |
|
1376 | Auto_precharge(0) := '0'; | |
|
1377 | Write_precharge(0) := '0'; | |
|
1378 | RW_interrupt_write(0) := '0'; | |
|
1379 | Pc_b0 := '1'; | |
|
1380 | Act_b0 := '0'; | |
|
1381 | RP_chk0 := NOW; | |
|
1382 | ASSERT FALSE REPORT "Start Internal Precharge Bank 0" SEVERITY NOTE; | |
|
1383 | END IF; | |
|
1384 | END IF; | |
|
1385 | IF ((Auto_precharge(1) = '1') AND (Write_precharge(1) = '1')) THEN | |
|
1386 | IF (((NOW - RAS_chk1 >= tRAS) AND | |
|
1387 | (((Burst_length_1 = '1' OR Write_burst_mode = '1' ) AND Count_precharge(1) >= 1 AND NOW - Count_time(1) >= tWRa) OR | |
|
1388 | (Burst_length_2 = '1' AND Count_precharge(1) >= 2 AND NOW - Count_time(1) >= tWRa) OR | |
|
1389 | (Burst_length_4 = '1' AND Count_precharge(1) >= 4 AND NOW - Count_time(1) >= tWRa) OR | |
|
1390 | (Burst_length_8 = '1' AND Count_precharge(1) >= 8 AND NOW - Count_time(1) >= tWRa))) OR | |
|
1391 | (RW_interrupt_write(1) = '1' AND WR_counter(1) >= 1 AND NOW - WR_time(1) >= tWRa)) THEN | |
|
1392 | Auto_precharge(1) := '0'; | |
|
1393 | Write_precharge(1) := '0'; | |
|
1394 | RW_interrupt_write(1) := '0'; | |
|
1395 | Pc_b1 := '1'; | |
|
1396 | Act_b1 := '0'; | |
|
1397 | RP_chk1 := NOW; | |
|
1398 | END IF; | |
|
1399 | END IF; | |
|
1400 | IF ((Auto_precharge(2) = '1') AND (Write_precharge(2) = '1')) THEN | |
|
1401 | IF (((NOW - RAS_chk2 >= tRAS) AND | |
|
1402 | (((Burst_length_1 = '1' OR Write_burst_mode = '1' ) AND Count_precharge(2) >= 1 AND NOW - Count_time(2) >= tWRa) OR | |
|
1403 | (Burst_length_2 = '1' AND Count_precharge(2) >= 2 AND NOW - Count_time(2) >= tWRa) OR | |
|
1404 | (Burst_length_4 = '1' AND Count_precharge(2) >= 4 AND NOW - Count_time(2) >= tWRa) OR | |
|
1405 | (Burst_length_8 = '1' AND Count_precharge(2) >= 8 AND NOW - Count_time(2) >= tWRa))) OR | |
|
1406 | (RW_interrupt_write(2) = '1' AND WR_counter(2) >= 1 AND NOW - WR_time(2) >= tWRa)) THEN | |
|
1407 | Auto_precharge(2) := '0'; | |
|
1408 | Write_precharge(2) := '0'; | |
|
1409 | RW_interrupt_write(2) := '0'; | |
|
1410 | Pc_b2 := '1'; | |
|
1411 | Act_b2 := '0'; | |
|
1412 | RP_chk2 := NOW; | |
|
1413 | END IF; | |
|
1414 | END IF; | |
|
1415 | IF ((Auto_precharge(3) = '1') AND (Write_precharge(3) = '1')) THEN | |
|
1416 | IF (((NOW - RAS_chk3 >= tRAS) AND | |
|
1417 | (((Burst_length_1 = '1' OR Write_burst_mode = '1' ) AND Count_precharge(3) >= 1 AND NOW - Count_time(3) >= tWRa) OR | |
|
1418 | (Burst_length_2 = '1' AND Count_precharge(3) >= 2 AND NOW - Count_time(3) >= tWRa) OR | |
|
1419 | (Burst_length_4 = '1' AND Count_precharge(3) >= 4 AND NOW - Count_time(3) >= tWRa) OR | |
|
1420 | (Burst_length_8 = '1' AND Count_precharge(3) >= 8 AND NOW - Count_time(3) >= tWRa))) OR | |
|
1421 | (RW_interrupt_write(0) = '1' AND WR_counter(0) >= 1 AND NOW - WR_time(3) >= tWRa)) THEN | |
|
1422 | Auto_precharge(3) := '0'; | |
|
1423 | Write_precharge(3) := '0'; | |
|
1424 | RW_interrupt_write(3) := '0'; | |
|
1425 | Pc_b3 := '1'; | |
|
1426 | Act_b3 := '0'; | |
|
1427 | RP_chk3 := NOW; | |
|
1428 | END IF; | |
|
1429 | END IF; | |
|
1430 | ||
|
1431 | -- Checking internal wires (Optional for debug purpose) | |
|
1432 | Pre_chk (0) <= Pc_b0; | |
|
1433 | Pre_chk (1) <= Pc_b1; | |
|
1434 | Pre_chk (2) <= Pc_b2; | |
|
1435 | Pre_chk (3) <= Pc_b3; | |
|
1436 | Act_chk (0) <= Act_b0; | |
|
1437 | Act_chk (1) <= Act_b1; | |
|
1438 | Act_chk (2) <= Act_b2; | |
|
1439 | Act_chk (3) <= Act_b3; | |
|
1440 | Dq_in_chk <= Data_in_enable; | |
|
1441 | Dq_out_chk <= Data_out_enable; | |
|
1442 | Bank_chk <= Bank; | |
|
1443 | Row_chk <= Row; | |
|
1444 | Col_chk <= Col; | |
|
1445 | END PROCESS; | |
|
1446 | ||
|
1447 | ||
|
1448 | -- Clock timing checks | |
|
1449 | -- Clock_check : PROCESS | |
|
1450 | -- VARIABLE Clk_low, Clk_high : TIME := 0 ns; | |
|
1451 | -- BEGIN | |
|
1452 | -- WAIT ON Clk; | |
|
1453 | -- IF (Clk = '1' AND NOW >= 10 ns) THEN | |
|
1454 | -- ASSERT (NOW - Clk_low >= tCL) | |
|
1455 | -- REPORT "tCL violation" | |
|
1456 | -- SEVERITY WARNING; | |
|
1457 | -- ASSERT (NOW - Clk_high >= tCK) | |
|
1458 | -- REPORT "tCK violation" | |
|
1459 | -- SEVERITY WARNING; | |
|
1460 | -- Clk_high := NOW; | |
|
1461 | -- ELSIF (Clk = '0' AND NOW /= 0 ns) THEN | |
|
1462 | -- ASSERT (NOW - Clk_high >= tCH) | |
|
1463 | -- REPORT "tCH violation" | |
|
1464 | -- SEVERITY WARNING; | |
|
1465 | -- Clk_low := NOW; | |
|
1466 | -- END IF; | |
|
1467 | -- END PROCESS; | |
|
1468 | ||
|
1469 | -- Setup timing checks | |
|
1470 | Setup_check : PROCESS | |
|
1471 | BEGIN | |
|
1472 | wait; | |
|
1473 | WAIT ON Clk; | |
|
1474 | IF Clk = '1' THEN | |
|
1475 | ASSERT(Cke'LAST_EVENT >= tCKS) --' | |
|
1476 | REPORT "CKE Setup time violation -- tCKS" | |
|
1477 | SEVERITY WARNING; | |
|
1478 | ASSERT(Cs_n'LAST_EVENT >= tCMS) --' | |
|
1479 | REPORT "CS# Setup time violation -- tCMS" | |
|
1480 | SEVERITY WARNING; | |
|
1481 | ASSERT(Cas_n'LAST_EVENT >= tCMS) --' | |
|
1482 | REPORT "CAS# Setup time violation -- tCMS" | |
|
1483 | SEVERITY WARNING; | |
|
1484 | ASSERT(Ras_n'LAST_EVENT >= tCMS) --' | |
|
1485 | REPORT "RAS# Setup time violation -- tCMS" | |
|
1486 | SEVERITY WARNING; | |
|
1487 | ASSERT(We_n'LAST_EVENT >= tCMS) --' | |
|
1488 | REPORT "WE# Setup time violation -- tCMS" | |
|
1489 | SEVERITY WARNING; | |
|
1490 | ASSERT(Dqm'LAST_EVENT >= tCMS) --' | |
|
1491 | REPORT "Dqm Setup time violation -- tCMS" | |
|
1492 | SEVERITY WARNING; | |
|
1493 | ASSERT(Addr'LAST_EVENT >= tAS) --' | |
|
1494 | REPORT "ADDR Setup time violation -- tAS" | |
|
1495 | SEVERITY WARNING; | |
|
1496 | ASSERT(Ba'LAST_EVENT >= tAS) --' | |
|
1497 | REPORT "BA Setup time violation -- tAS" | |
|
1498 | SEVERITY WARNING; | |
|
1499 | ASSERT(Dq'LAST_EVENT >= tDS) --' | |
|
1500 | REPORT "Dq Setup time violation -- tDS" | |
|
1501 | SEVERITY WARNING; | |
|
1502 | END IF; | |
|
1503 | END PROCESS; | |
|
1504 | ||
|
1505 | -- Hold timing checks | |
|
1506 | Hold_check : PROCESS | |
|
1507 | BEGIN | |
|
1508 | wait; | |
|
1509 | WAIT ON Clk'DELAYED (tCKH), Clk'DELAYED (tCMH), Clk'DELAYED (tAH), Clk'DELAYED (tDH); | |
|
1510 | IF Clk'DELAYED (tCKH) = '1' THEN --' | |
|
1511 | ASSERT(Cke'LAST_EVENT > tCKH) --' | |
|
1512 | REPORT "CKE Hold time violation -- tCKH" | |
|
1513 | SEVERITY WARNING; | |
|
1514 | END IF; | |
|
1515 | IF Clk'DELAYED (tCMH) = '1' THEN --' | |
|
1516 | ASSERT(Cs_n'LAST_EVENT > tCMH) --' | |
|
1517 | REPORT "CS# Hold time violation -- tCMH" | |
|
1518 | SEVERITY WARNING; | |
|
1519 | ASSERT(Cas_n'LAST_EVENT > tCMH) --' | |
|
1520 | REPORT "CAS# Hold time violation -- tCMH" | |
|
1521 | SEVERITY WARNING; | |
|
1522 | ASSERT(Ras_n'LAST_EVENT > tCMH) --' | |
|
1523 | REPORT "RAS# Hold time violation -- tCMH" | |
|
1524 | SEVERITY WARNING; | |
|
1525 | ASSERT(We_n'LAST_EVENT > tCMH) --' | |
|
1526 | REPORT "WE# Hold time violation -- tCMH" | |
|
1527 | SEVERITY WARNING; | |
|
1528 | ASSERT(Dqm'LAST_EVENT > tCMH) --' | |
|
1529 | REPORT "Dqm Hold time violation -- tCMH" | |
|
1530 | SEVERITY WARNING; | |
|
1531 | END IF; | |
|
1532 | IF Clk'DELAYED (tAH) = '1' THEN --' | |
|
1533 | ASSERT(Addr'LAST_EVENT > tAH) --' | |
|
1534 | REPORT "ADDR Hold time violation -- tAH" | |
|
1535 | SEVERITY WARNING; | |
|
1536 | ASSERT(Ba'LAST_EVENT > tAH) --' | |
|
1537 | REPORT "BA Hold time violation -- tAH" | |
|
1538 | SEVERITY WARNING; | |
|
1539 | END IF; | |
|
1540 | IF Clk'DELAYED (tDH) = '1' THEN --' | |
|
1541 | ASSERT(Dq'LAST_EVENT > tDH) --' | |
|
1542 | REPORT "Dq Hold time violation -- tDH" | |
|
1543 | SEVERITY WARNING; | |
|
1544 | END IF; | |
|
1545 | END PROCESS; | |
|
1546 | ||
|
1547 | END behave; | |
|
1548 | ||
|
1549 | -- pragma translate_on | |
|
1550 |
@@ -0,0 +1,69 | |||
|
1 | <?xml version='1.0' encoding='utf-8'?> | |
|
2 | <soc name="Leon"> | |
|
3 | <peripheral vid="8" name="SpaceWire Light" pid="305"> | |
|
4 | <register name="Control register" addOffset="0"> | |
|
5 | <bitField size="1" offset="0" name="Reset" mode="3" desc="Write '1' to reset SPWAMBA core (auto-clear)."/> | |
|
6 | <bitField size="1" offset="1" name="Reset DMA" mode="3" desc="Write '1' to reset DMA engines (auto-clear)."/> | |
|
7 | <bitField name="Link Start" offset="2" size="1" mode="3" desc="Link start signal. '1' = actively try to start a SpaceWire link."/> | |
|
8 | <bitField name="Link Auto Start" offset="3" size="1" mode="3" desc="Link autostart signal. '1' = start link after receiving NULL from other side."/> | |
|
9 | <bitField name="Link Disable" offset="4" size="1" mode="3" desc="Link disable signal. '1' = shut down current link and do not establish new link."/> | |
|
10 | <bitField name="Time Code EN" offset="5" size="1" mode="3" desc="Allow time-code transmission through tick_in signal."/> | |
|
11 | <bitField name="Restart RX DMA" offset="6" size="1" mode="3" desc="Write '1' to (re-)start RX DMA (auto-clear)."/> | |
|
12 | <bitField name="Restart TX DMA" offset="7" size="1" mode="3" desc="Write '1' to (re-)start TX DMA (auto-clear)."/> | |
|
13 | <bitField name="Cancel TX DMA" offset="8" size="1" mode="3" desc="Write '1' to cancel running TX DMA and discard data from TX FIFO (auto-clear)."/> | |
|
14 | <bitField name="Link Up/Down IE" offset="9" size="1" mode="3" desc="Enable interrupt on link up/down."/> | |
|
15 | <bitField name="Time Code IE" offset="10" size="1" mode="3" desc="Enable interrupt on time code received."/> | |
|
16 | <bitField name="RXDESCIE" offset="11" size="1" mode="3" desc="Enable interrupt on completed RX descriptor with IE='1'."/> | |
|
17 | <bitField name="TXDESCIE" offset="12" size="1" mode="3" desc="Enable interrupt on completed TX descriptor with IE='1'."/> | |
|
18 | <bitField name="RXIE" offset="13" size="1" mode="3" desc="Enable interrupt on RX packet received."/> | |
|
19 | <bitField name="DescSz" offset="24" size="4" mode="1" desc="Value of desctablesize generic (read-only)."/> | |
|
20 | </register> | |
|
21 | <register name="Status register" addOffset="4"> | |
|
22 | <bitField size="2" offset="0" name="LSTAT" mode="1" desc="Link status: 0=off, 1=started, 2=connecting, 3=run (read-only)."/> | |
|
23 | <bitField size="1" offset="2" name="DISCERR" mode="3" desc="Got disconnect error (sticky, write '1' to clear)."/> | |
|
24 | <bitField size="1" offset="3" name="PARERR" mode="3" desc="Got parity error (sticky, write '1' to clear)."/> | |
|
25 | <bitField size="1" offset="4" name="ESCERR" mode="3" desc="Got escape error (sticky, write '1' to clear)."/> | |
|
26 | <bitField size="1" offset="5" name="CREDERR" mode="3" desc="Got credit error (sticky, write '1' to clear)."/> | |
|
27 | <bitField size="1" offset="6" name="RXDMA" mode="1" desc="RX DMA running (read-only)."/> | |
|
28 | <bitField size="1" offset="7" name="RXDMA" mode="1" desc="TX DMA running (read-only)."/> | |
|
29 | <bitField size="1" offset="8" name="AHBERR" mode="1" desc="AHB error occurred (sticky, reset DMA engine to clear)."/> | |
|
30 | <bitField size="1" offset="9" name="UNUSED" mode="3" desc="unused"/> | |
|
31 | <bitField size="1" offset="10" name="TIMECODE" mode="3" desc="Received time-code (sticky, write '1' to clear)."/> | |
|
32 | <bitField size="1" offset="11" name="RXDESCCOMP" mode="3" desc="Completed RX descriptor with IE='1' (sticky, write '1' to clear)."/> | |
|
33 | <bitField size="1" offset="12" name="TXDESCCOMP" mode="3" desc="Completed TX descriptor with IE='1' (sticky, write '1' to clear)."/> | |
|
34 | <bitField size="1" offset="13" name="RECPACKT" mode="3" desc="Received packet (sticky, write '1' to clear)."/> | |
|
35 | <bitField size="1" offset="14" name="RXE" mode="1" desc="RX buffer is empty and last packet has been completely transfered to RX DMA (read-only)."/> | |
|
36 | </register> | |
|
37 | <register name="Transmission clock scaler" addOffset="8"> | |
|
38 | <bitField size="8" offset="0" name="N" mode="3" desc="Clock division factor minus 1. The actual TX bit rate is determined by (txclk frequency) / (scaler + 1). | |
|
39 | During the handshake phase, this register is ignored and the TX bit rate is forced to 10 Mbit. After reset, this | |
|
40 | register defaults to the scaler value needed for 10 Mbit."/> | |
|
41 | </register> | |
|
42 | <register name="Time-code register" addOffset="12"> | |
|
43 | <bitField size="6" offset="0" name="Address" mode="1" desc="Last received time-code value (read-only)."/> | |
|
44 | <bitField size="2" offset="6" name="Address" mode="1" desc="Control bits received with last time-code (read-only)."/> | |
|
45 | <bitField size="6" offset="12" name="Address" mode="3" desc="Time-code value to send on next tick_in (auto-increment)."/> | |
|
46 | <bitField size="2" offset="14" name="Address" mode="3" desc="Reserved, write as zero."/> | |
|
47 | <bitField size="1" offset="15" name="Address" mode="3" desc="Write '1' to send a time-code immediately (auto-clear)."/> | |
|
48 | </register> | |
|
49 | <register name="Descriptor pointer for RX DMA" addOffset="16"> | |
|
50 | <bitField size="3" offset="0" name="DATA" mode="3" desc="Reserved, write as zero."/> | |
|
51 | <bitField size="10" offset="3" name="DATA" mode="3" desc="Descriptor index (auto-increment)."/> | |
|
52 | <bitField size="19" offset="13" name="DATA" mode="3" desc="Fixed address bits of descriptor table."/> | |
|
53 | </register> | |
|
54 | <register name="Descriptor pointer for TX DMA" addOffset="20"> | |
|
55 | <bitField size="3" offset="0" name="DATA" mode="3" desc="Reserved, write as zero."/> | |
|
56 | <bitField size="10" offset="3" name="DATA" mode="3" desc="Descriptor index (auto-increment)."/> | |
|
57 | <bitField size="19" offset="13" name="DATA" mode="3" desc="Fixed address bits of descriptor table."/> | |
|
58 | </register> | |
|
59 | </peripheral> | |
|
60 | </soc> | |
|
61 | ||
|
62 | ||
|
63 | ||
|
64 | ||
|
65 | ||
|
66 | ||
|
67 | ||
|
68 | ||
|
69 |
This diff has been collapsed as it changes many lines, (1053 lines changed) Show them Hide them | |||
@@ -0,0 +1,1053 | |||
|
1 | ------------------------------------------------------------------------------ | |
|
2 | -- This file is a part of the GRLIB VHDL IP LIBRARY | |
|
3 | -- Copyright (C) 2003 - 2008, Gaisler Research | |
|
4 | -- Copyright (C) 2008 - 2014, Aeroflex Gaisler | |
|
5 | -- Copyright (C) 2015 - 2016, Cobham Gaisler | |
|
6 | -- | |
|
7 | -- This program is free software; you can redistribute it and/or modify | |
|
8 | -- it under the terms of the GNU General Public License as published by | |
|
9 | -- the Free Software Foundation; either version 2 of the License, or | |
|
10 | -- (at your option) any later version. | |
|
11 | -- | |
|
12 | -- This program is distributed in the hope that it will be useful, | |
|
13 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of | |
|
14 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
|
15 | -- GNU General Public License for more details. | |
|
16 | -- | |
|
17 | -- You should have received a copy of the GNU General Public License | |
|
18 | -- along with this program; if not, write to the Free Software | |
|
19 | -- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
|
20 | ----------------------------------------------------------------------------- | |
|
21 | -- Entity: sdctrl16 | |
|
22 | -- File: sdctrl16.vhd | |
|
23 | -- Author: Jiri Gaisler - Gaisler Research | |
|
24 | -- Modified by: Daniel Bengtsson & Richard Fång | |
|
25 | -- Description: 16- and 32-bit SDRAM memory controller. | |
|
26 | ------------------------------------------------------------------------------ | |
|
27 | ||
|
28 | library ieee; | |
|
29 | use ieee.std_logic_1164.all; | |
|
30 | library grlib; | |
|
31 | use grlib.amba.all; | |
|
32 | use grlib.stdlib.all; | |
|
33 | library gaisler; | |
|
34 | use grlib.devices.all; | |
|
35 | use gaisler.memctrl.all; | |
|
36 | ||
|
37 | entity sdctrl16 is | |
|
38 | generic ( | |
|
39 | hindex : integer := 0; | |
|
40 | haddr : integer := 0; | |
|
41 | hmask : integer := 16#f00#; | |
|
42 | ioaddr : integer := 16#000#; | |
|
43 | iomask : integer := 16#fff#; | |
|
44 | wprot : integer := 0; | |
|
45 | invclk : integer := 0; | |
|
46 | fast : integer := 0; | |
|
47 | pwron : integer := 0; | |
|
48 | sdbits : integer := 16; | |
|
49 | oepol : integer := 0; | |
|
50 | pageburst : integer := 0; | |
|
51 | mobile : integer := 0 | |
|
52 | ); | |
|
53 | port ( | |
|
54 | rst : in std_ulogic; | |
|
55 | clk : in std_ulogic; | |
|
56 | ahbsi : in ahb_slv_in_type; | |
|
57 | ahbso : out ahb_slv_out_type; | |
|
58 | sdi : in sdctrl_in_type; | |
|
59 | sdo : out sdctrl_out_type | |
|
60 | ); | |
|
61 | end; | |
|
62 | ||
|
63 | architecture rtl of sdctrl16 is | |
|
64 | ||
|
65 | constant WPROTEN : boolean := wprot = 1; | |
|
66 | constant SDINVCLK : boolean := invclk = 1; | |
|
67 | constant BUS16 : boolean := (sdbits = 16); | |
|
68 | constant BUS32 : boolean := (sdbits = 32); | |
|
69 | constant BUS64 : boolean := (sdbits = 64); | |
|
70 | ||
|
71 | constant REVISION : integer := 1; | |
|
72 | ||
|
73 | constant PM_PD : std_logic_vector(2 downto 0) := "001"; | |
|
74 | constant PM_SR : std_logic_vector(2 downto 0) := "010"; | |
|
75 | constant PM_DPD : std_logic_vector(2 downto 0) := "101"; | |
|
76 | ||
|
77 | constant std_rammask: Std_Logic_Vector(31 downto 20) := | |
|
78 | Conv_Std_Logic_Vector(hmask, 12); | |
|
79 | ||
|
80 | constant hconfig : ahb_config_type := ( | |
|
81 | 0 => ahb_device_reg ( VENDOR_GAISLER, GAISLER_SDCTRL, 0, REVISION, 0), | |
|
82 | 4 => ahb_membar(haddr, '1', '1', hmask), | |
|
83 | 5 => ahb_iobar(ioaddr, iomask), | |
|
84 | others => zero32); | |
|
85 | ||
|
86 | type mcycletype is (midle, active, leadout); | |
|
87 | type sdcycletype is (act1, act2, act3, act3_16, rd1, rd2, rd3, rd4, rd4_16, rd5, rd6, rd7, rd8, | |
|
88 | wr1, wr1_16, wr2, wr3, wr4, wr5, sidle, | |
|
89 | sref, pd, dpd); | |
|
90 | type icycletype is (iidle, pre, ref, lmode, emode, finish); | |
|
91 | ||
|
92 | -- sdram configuration register | |
|
93 | ||
|
94 | type sdram_cfg_type is record | |
|
95 | command : std_logic_vector(2 downto 0); | |
|
96 | csize : std_logic_vector(1 downto 0); | |
|
97 | bsize : std_logic_vector(2 downto 0); | |
|
98 | casdel : std_ulogic; -- CAS to data delay: 2/3 clock cycles | |
|
99 | trfc : std_logic_vector(2 downto 0); | |
|
100 | trp : std_ulogic; -- precharge to activate: 2/3 clock cycles | |
|
101 | refresh : std_logic_vector(14 downto 0); | |
|
102 | renable : std_ulogic; | |
|
103 | pageburst : std_ulogic; | |
|
104 | mobileen : std_logic_vector(1 downto 0); -- Mobile SD support, Mobile SD enabled | |
|
105 | ds : std_logic_vector(3 downto 0); -- ds(1:0) (ds(3:2) used to detect update) | |
|
106 | tcsr : std_logic_vector(3 downto 0); -- tcrs(1:0) (tcrs(3:2) used to detect update) | |
|
107 | pasr : std_logic_vector(5 downto 0); -- pasr(2:0) (pasr(5:3) used to detect update) | |
|
108 | pmode : std_logic_vector(2 downto 0); -- Power-Saving mode | |
|
109 | txsr : std_logic_vector(3 downto 0); -- Exit Self Refresh timing | |
|
110 | cke : std_ulogic; -- Clock enable | |
|
111 | end record; | |
|
112 | ||
|
113 | -- local registers | |
|
114 | ||
|
115 | type reg_type is record | |
|
116 | hready : std_ulogic; | |
|
117 | hsel : std_ulogic; | |
|
118 | bdrive : std_ulogic; | |
|
119 | nbdrive : std_ulogic; | |
|
120 | burst : std_ulogic; | |
|
121 | wprothit : std_ulogic; | |
|
122 | hio : std_ulogic; | |
|
123 | startsd : std_ulogic; | |
|
124 | lhw : std_ulogic; --Lower halfword | |
|
125 | ||
|
126 | mstate : mcycletype; | |
|
127 | sdstate : sdcycletype; | |
|
128 | cmstate : mcycletype; | |
|
129 | istate : icycletype; | |
|
130 | icnt : std_logic_vector(2 downto 0); | |
|
131 | ||
|
132 | haddr : std_logic_vector(31 downto 0); | |
|
133 | hrdata : std_logic_vector((sdbits-1)+((16/sdbits)*16) downto 0); | |
|
134 | hwdata : std_logic_vector(31 downto 0); | |
|
135 | hwrite : std_ulogic; | |
|
136 | htrans : std_logic_vector(1 downto 0); | |
|
137 | hresp : std_logic_vector(1 downto 0); | |
|
138 | size : std_logic_vector(1 downto 0); | |
|
139 | ||
|
140 | cfg : sdram_cfg_type; | |
|
141 | trfc : std_logic_vector(3 downto 0); | |
|
142 | refresh : std_logic_vector(14 downto 0); | |
|
143 | sdcsn : std_logic_vector(1 downto 0); | |
|
144 | sdwen : std_ulogic; | |
|
145 | rasn : std_ulogic; | |
|
146 | casn : std_ulogic; | |
|
147 | dqm : std_logic_vector(7 downto 0); | |
|
148 | address : std_logic_vector(16 downto 2); -- memory address | |
|
149 | bsel : std_ulogic; | |
|
150 | ||
|
151 | idlecnt : std_logic_vector(3 downto 0); -- Counter, 16 idle clock sycles before entering Power-Saving mode | |
|
152 | sref_tmpcom : std_logic_vector(2 downto 0); -- Save SD command when exit sref | |
|
153 | end record; | |
|
154 | ||
|
155 | signal r, ri : reg_type; | |
|
156 | signal rbdrive, ribdrive : std_logic_vector(31 downto 0); | |
|
157 | attribute syn_preserve : boolean; | |
|
158 | attribute syn_preserve of rbdrive : signal is true; | |
|
159 | ||
|
160 | begin | |
|
161 | ||
|
162 | ctrl : process(rst, ahbsi, r, sdi, rbdrive) | |
|
163 | variable v : reg_type; -- local variables for registers | |
|
164 | variable startsd : std_ulogic; | |
|
165 | variable dataout : std_logic_vector(31 downto 0); -- data from memory | |
|
166 | variable regsd : std_logic_vector(31 downto 0); -- data from registers | |
|
167 | variable dqm : std_logic_vector(7 downto 0); | |
|
168 | variable raddr : std_logic_vector(12 downto 0); | |
|
169 | variable adec : std_ulogic; | |
|
170 | variable rams : std_logic_vector(1 downto 0); | |
|
171 | variable ba : std_logic_vector(1 downto 0); | |
|
172 | variable haddr : std_logic_vector(31 downto 0); | |
|
173 | variable dout : std_logic_vector(31 downto 0); | |
|
174 | variable hsize : std_logic_vector(1 downto 0); | |
|
175 | variable hwrite : std_ulogic; | |
|
176 | variable htrans : std_logic_vector(1 downto 0); | |
|
177 | variable hready : std_ulogic; | |
|
178 | variable vbdrive : std_logic_vector(31 downto 0); | |
|
179 | variable bdrive : std_ulogic; | |
|
180 | variable lline : std_logic_vector(2 downto 0); | |
|
181 | variable lineburst : boolean; | |
|
182 | variable haddr_tmp : std_logic_vector(31 downto 0); | |
|
183 | variable arefresh : std_logic; | |
|
184 | variable hwdata : std_logic_vector(31 downto 0); | |
|
185 | ||
|
186 | begin | |
|
187 | ||
|
188 | -- Variable default settings to avoid latches | |
|
189 | ||
|
190 | v := r; startsd := '0'; v.hresp := HRESP_OKAY; vbdrive := rbdrive; arefresh := '0'; | |
|
191 | if BUS16 then | |
|
192 | if (r.lhw = '1') then --muxes read data to correct part of the register. | |
|
193 | v.hrdata(sdbits-1 downto 0) := sdi.data(sdbits-1 downto 0); | |
|
194 | else | |
|
195 | v.hrdata((sdbits*2)-1 downto sdbits) := sdi.data(sdbits-1 downto 0); | |
|
196 | end if; | |
|
197 | else | |
|
198 | v.hrdata(sdbits-1 downto sdbits-32) := sdi.data(sdbits-1 downto sdbits-32); | |
|
199 | v.hrdata(31 downto 0) := sdi.data(31 downto 0); | |
|
200 | end if; | |
|
201 | hwdata := ahbreadword(ahbsi.hwdata, r.haddr(4 downto 2)); v.hwdata := hwdata; | |
|
202 | lline := not r.cfg.casdel & r.cfg.casdel & r.cfg.casdel; | |
|
203 | if (pageburst = 0) or ((pageburst = 2) and r.cfg.pageburst = '0') then | |
|
204 | lineburst := true; | |
|
205 | else lineburst := false; end if; | |
|
206 | ||
|
207 | ||
|
208 | if ((ahbsi.hready and ahbsi.hsel(hindex)) = '1') then | |
|
209 | v.size := ahbsi.hsize(1 downto 0); v.hwrite := ahbsi.hwrite; | |
|
210 | v.htrans := ahbsi.htrans; | |
|
211 | if ahbsi.htrans(1) = '1' then | |
|
212 | v.hio := ahbsi.hmbsel(1); | |
|
213 | v.hsel := '1'; v.hready := v.hio; | |
|
214 | end if; | |
|
215 | v.haddr := ahbsi.haddr; | |
|
216 | -- addr must be masked since address range can be smaller than | |
|
217 | -- total banksize. this can result in wrong chip select being | |
|
218 | -- asserted | |
|
219 | for i in 31 downto 20 loop | |
|
220 | v.haddr(i) := ahbsi.haddr(i) and not std_rammask(i); | |
|
221 | end loop; | |
|
222 | end if; | |
|
223 | ||
|
224 | if (r.hsel = '1') and (ahbsi.hready = '0') then | |
|
225 | haddr := r.haddr; hsize := r.size; | |
|
226 | htrans := r.htrans; hwrite := r.hwrite; | |
|
227 | else | |
|
228 | haddr := ahbsi.haddr; hsize := ahbsi.hsize(1 downto 0); | |
|
229 | htrans := ahbsi.htrans; hwrite := ahbsi.hwrite; | |
|
230 | -- addr must be masked since address range can be smaller than | |
|
231 | -- total banksize. this can result in wrong chip select being | |
|
232 | -- asserted | |
|
233 | for i in 31 downto 20 loop | |
|
234 | haddr(i) := ahbsi.haddr(i) and not std_rammask(i); | |
|
235 | end loop; | |
|
236 | end if; | |
|
237 | if fast = 1 then haddr := r.haddr; end if; | |
|
238 | ||
|
239 | if ahbsi.hready = '1' then v.hsel := ahbsi.hsel(hindex); end if; | |
|
240 | ||
|
241 | -- main state | |
|
242 | if BUS16 then | |
|
243 | case r.size is | |
|
244 | when "00" => --bytesize | |
|
245 | case r.haddr(0) is | |
|
246 | when '0' => dqm := "11111101"; | |
|
247 | when others => dqm := "11111110"; | |
|
248 | end case; | |
|
249 | when others => dqm := "11111100"; --halfword, word | |
|
250 | end case; | |
|
251 | else | |
|
252 | case r.size is | |
|
253 | when "00" => | |
|
254 | case r.haddr(1 downto 0) is | |
|
255 | when "00" => dqm := "11110111"; | |
|
256 | when "01" => dqm := "11111011"; | |
|
257 | when "10" => dqm := "11111101"; | |
|
258 | when others => dqm := "11111110"; | |
|
259 | end case; | |
|
260 | when "01" => | |
|
261 | if r.haddr(1) = '0' then dqm := "11110011"; else dqm := "11111100"; end if; | |
|
262 | when others => dqm := "11110000"; | |
|
263 | end case; | |
|
264 | end if; | |
|
265 | -- | |
|
266 | -- case r.size is | |
|
267 | -- when "00" => | |
|
268 | -- case r.haddr(1 downto 0) is | |
|
269 | -- when "00" => dqm := "11111101"; lhw := '0'; --lhv := r.haddr(1) | |
|
270 | -- when "01" => dqm := "11111110"; lhw := '0'; | |
|
271 | -- when "10" => dqm := "11111101"; lhw := '1'; | |
|
272 | -- when others => dqm := "11111110"; lhw := '1'; | |
|
273 | -- end case; | |
|
274 | -- when "01" => | |
|
275 | -- dqm := "11111100"; | |
|
276 | -- if r.haddr(1) = '0' then | |
|
277 | -- lhw := '0'; | |
|
278 | -- else | |
|
279 | -- lhw := '1'; | |
|
280 | -- end if; | |
|
281 | -- when others => dqm := "11111100"; --remember when word: lhw first 0 then 1 | |
|
282 | -- end case; | |
|
283 | -- | |
|
284 | if BUS64 and (r.bsel = '1') then dqm := dqm(3 downto 0) & "1111"; end if; | |
|
285 | ||
|
286 | -- main FSM | |
|
287 | ||
|
288 | case r.mstate is | |
|
289 | when midle => | |
|
290 | if ((v.hsel and htrans(1) and not v.hio) = '1') then | |
|
291 | if (r.sdstate = sidle) and (r.cfg.command = "000") | |
|
292 | and (r.cmstate = midle) and (v.hio = '0') | |
|
293 | then | |
|
294 | if fast = 0 then startsd := '1'; else v.startsd := '1'; end if; | |
|
295 | v.mstate := active; | |
|
296 | elsif ((r.sdstate = sref) or (r.sdstate = pd) or (r.sdstate = dpd)) | |
|
297 | and (r.cfg.command = "000") and (r.cmstate = midle) and (v.hio = '0') | |
|
298 | then | |
|
299 | v.startsd := '1'; | |
|
300 | if r.sdstate = dpd then -- Error response when on Deep Power-Down mode | |
|
301 | v.hresp := HRESP_ERROR; | |
|
302 | else | |
|
303 | v.mstate := active; | |
|
304 | end if; | |
|
305 | end if; | |
|
306 | end if; | |
|
307 | when others => null; | |
|
308 | end case; | |
|
309 | ||
|
310 | startsd := startsd or r.startsd; | |
|
311 | ||
|
312 | -- generate row and column address size | |
|
313 | ||
|
314 | if BUS16 then | |
|
315 | case r.cfg.csize is | |
|
316 | when "00" => raddr := haddr(21 downto 9);-- case to check for bursting over row limit, since 1 row is 512 byte. | |
|
317 | when "01" => raddr := haddr(22 downto 10); | |
|
318 | when "10" => raddr := haddr(23 downto 11); | |
|
319 | when others => | |
|
320 | if r.cfg.bsize = "110" then raddr := haddr(25 downto 13); --tänk | |
|
321 | else raddr := haddr(24 downto 12); end if; | |
|
322 | end case; | |
|
323 | else | |
|
324 | case r.cfg.csize is | |
|
325 | when "00" => raddr := haddr(22 downto 10); | |
|
326 | when "01" => raddr := haddr(23 downto 11); | |
|
327 | when "10" => raddr := haddr(24 downto 12); | |
|
328 | when others => | |
|
329 | if r.cfg.bsize = "111" then raddr := haddr(26 downto 14); | |
|
330 | else raddr := haddr(25 downto 13); end if; | |
|
331 | end case; | |
|
332 | end if; | |
|
333 | ||
|
334 | -- generate bank address | |
|
335 | -- if BUS16 then --011 | |
|
336 | -- ba := genmux(r.cfg.bsize, haddr(26 downto 19)) & | |
|
337 | -- genmux(r.cfg.bsize, haddr(25 downto 18)); | |
|
338 | -- else | |
|
339 | ba := genmux(r.cfg.bsize, haddr(28 downto 21)) & | |
|
340 | genmux(r.cfg.bsize, haddr(27 downto 20)); | |
|
341 | -- end if; | |
|
342 | ||
|
343 | -- generate chip select | |
|
344 | ||
|
345 | if BUS64 then | |
|
346 | adec := genmux(r.cfg.bsize, haddr(30 downto 23)); | |
|
347 | v.bsel := genmux(r.cfg.bsize, r.haddr(29 downto 22)); | |
|
348 | else | |
|
349 | adec := genmux(r.cfg.bsize, haddr(29 downto 22)); v.bsel := '0'; | |
|
350 | end if; | |
|
351 | -- elsif BUS32 then | |
|
352 | -- adec := genmux(r.cfg.bsize, haddr(29 downto 22)); v.bsel := '0'; | |
|
353 | -- else | |
|
354 | -- adec := genmux(r.cfg.bsize, haddr(27 downto 20)); v.bsel := '0'; | |
|
355 | -- end if; | |
|
356 | ||
|
357 | rams := adec & not adec; | |
|
358 | ||
|
359 | -- sdram access FSM | |
|
360 | ||
|
361 | if r.trfc /= "0000" then v.trfc := r.trfc - 1; end if; | |
|
362 | ||
|
363 | if r.idlecnt /= "0000" then v.idlecnt := r.idlecnt - 1; end if; | |
|
364 | ||
|
365 | case r.sdstate is | |
|
366 | ||
|
367 | when sidle => | |
|
368 | if (startsd = '1') and (r.cfg.command = "000") and (r.cmstate = midle) then | |
|
369 | -- if BUS16 then | |
|
370 | -- v.address(16 downto 2) := '0' & ba & raddr(11 downto 0); --since 1 bit lower row => tot adress field 14 bits | |
|
371 | -- else | |
|
372 | v.address(16 downto 2) := ba & raddr; -- ba(16-15) & raddr(14-2) (2+13= 15 bits) | |
|
373 | -- end if; | |
|
374 | v.sdcsn := not rams(1 downto 0); v.rasn := '0'; v.sdstate := act1; | |
|
375 | v.startsd := '0'; | |
|
376 | elsif (r.idlecnt = "0000") and (r.cfg.command = "000") | |
|
377 | and (r.cmstate = midle) and (r.cfg.mobileen(1) = '1') then | |
|
378 | case r.cfg.pmode is | |
|
379 | when PM_SR => | |
|
380 | v.cfg.cke := '0'; v.sdstate := sref; | |
|
381 | v.sdcsn := (others => '0'); v.rasn := '0'; v.casn := '0'; | |
|
382 | v.trfc := (r.cfg.trp and r.cfg.mobileen(1)) & r.cfg.trfc; -- Control minimum duration of Self Refresh mode (= tRAS) | |
|
383 | when PM_PD => v.cfg.cke := '0'; v.sdstate := pd; | |
|
384 | when PM_DPD => | |
|
385 | v.cfg.cke := '0'; v.sdstate := dpd; | |
|
386 | v.sdcsn := (others => '0'); v.sdwen := '0'; v.rasn := '1'; v.casn := '1'; | |
|
387 | when others => | |
|
388 | end case; | |
|
389 | end if; | |
|
390 | ||
|
391 | when act1 => | |
|
392 | v.rasn := '1'; v.trfc := (r.cfg.trp and r.cfg.mobileen(1)) & r.cfg.trfc; | |
|
393 | if r.cfg.casdel = '1' then v.sdstate := act2; else | |
|
394 | v.sdstate := act3; | |
|
395 | if not BUS16 then -- needs if, otherwise it might clock in incorrect write data to state act3_16 | |
|
396 | v.hready := r.hwrite and ahbsi.htrans(0) and ahbsi.htrans(1); | |
|
397 | end if; | |
|
398 | end if; | |
|
399 | if WPROTEN then | |
|
400 | v.wprothit := sdi.wprot; | |
|
401 | if sdi.wprot = '1' then v.hresp := HRESP_ERROR; end if; | |
|
402 | end if; | |
|
403 | ||
|
404 | when act2 => | |
|
405 | v.sdstate := act3; | |
|
406 | if not BUS16 then | |
|
407 | v.hready := r.hwrite and ahbsi.htrans(0) and ahbsi.htrans(1); | |
|
408 | end if; | |
|
409 | if WPROTEN and (r.wprothit = '1') then | |
|
410 | v.hresp := HRESP_ERROR; v.hready := '0'; | |
|
411 | end if; | |
|
412 | ||
|
413 | when act3 => | |
|
414 | v.casn := '0'; | |
|
415 | if BUS16 then --HW adress needed to memory | |
|
416 | v.address(14 downto 2) := r.haddr(12 downto 11) & '0' & r.haddr(10 downto 1); --only allowed to use tot adressbits - ba bits | |
|
417 | -- v.address(13 downto 2) := r.haddr(11) & '0' & r.haddr(10 downto 1); --only allowed to use tot adressbits - ba bits | |
|
418 | v.lhw := r.haddr(1); -- 14-2 = 12 colummn bits => 13 downto 2 | |
|
419 | else | |
|
420 | v.address(14 downto 2) := r.haddr(13 downto 12) & '0' & r.haddr(11 downto 2); | |
|
421 | end if; | |
|
422 | v.dqm := dqm; v.burst := r.hready; -- ?? | |
|
423 | ||
|
424 | if r.hwrite = '1' then | |
|
425 | ||
|
426 | if BUS16 then --16 bit | |
|
427 | if r.size(1) = '1' then --word | |
|
428 | v.hready := ahbsi.htrans(0) and ahbsi.htrans(1); --delayed this check 1 state to keep write data correct in act3_16 | |
|
429 | v.burst := ahbsi.htrans(0) and ahbsi.htrans(1); | |
|
430 | v.sdstate := act3_16; -- goto state for second part of word transfer | |
|
431 | -- v.lhw := '0'; --write MSB 16 bits to AMBA adress that ends with 00 | |
|
432 | else --halfword or byte | |
|
433 | v.sdstate := act3_16; v.hready := '1'; | |
|
434 | end if; | |
|
435 | else --32 bit or 64 | |
|
436 | v.sdstate := wr1; | |
|
437 | if ahbsi.htrans = "11" or (r.hready = '0') then v.hready := '1'; end if; | |
|
438 | end if; | |
|
439 | v.sdwen := '0'; v.bdrive := '0'; --write | |
|
440 | if WPROTEN and (r.wprothit = '1') then | |
|
441 | v.hresp := HRESP_ERROR; v.hready := '1'; | |
|
442 | if BUS16 then v.sdstate := act3_16; else v.sdstate := wr1; end if; | |
|
443 | v.sdwen := '1'; v.bdrive := '1'; v.casn := '1'; --skip write, remember hready high in next state | |
|
444 | end if; | |
|
445 | else v.sdstate := rd1; end if; | |
|
446 | ||
|
447 | when act3_16 => --handle 16 bit and WORD write | |
|
448 | v.address(14 downto 2) := r.haddr(12 downto 11) & '0' & r.haddr(10 downto 2) & '1'; | |
|
449 | -- v.address(13 downto 2) := r.haddr(11) & '0' & r.haddr(10 downto 2) & '1'; | |
|
450 | v.lhw := '1'; | |
|
451 | if (r.hready and r.burst) = '1' and not (WPROTEN and (r.wprothit = '1')) then | |
|
452 | v.hready := '0'; --kolla på transfertyp nonseq om vi vill delaya nedankoll. | |
|
453 | if( ahbsi.htrans = "11" and | |
|
454 | not ((r.haddr(5 downto 2) = "1111") and (r.cfg.command = "100")) and | |
|
455 | not ((r.haddr(9) xor ahbsi.haddr(9)) = '1' and r.cfg.csize = "00") ) then | |
|
456 | v.sdstate := wr1_16; | |
|
457 | end if; | |
|
458 | elsif r.burst = '1' or (r.hready and not r.burst) = '1' then --terminate burst or single write | |
|
459 | v.sdstate := wr2; v.bdrive := '1'; v.casn := '1'; v.sdwen := '1'; | |
|
460 | v.dqm := (others => '1'); | |
|
461 | else -- complete single write | |
|
462 | v.hready := '1'; | |
|
463 | v.sdstate := act3_16; --gick till wr1 förut | |
|
464 | end if; | |
|
465 | ||
|
466 | when wr1_16 => | |
|
467 | v.address(14 downto 2) := r.haddr(12 downto 11) & '0' & r.haddr(10 downto 1); | |
|
468 | -- v.address(13 downto 2) := r.haddr(11) & '0' & r.haddr(10 downto 1); | |
|
469 | v.lhw := r.haddr(1); | |
|
470 | v.sdstate := act3_16; | |
|
471 | v.hready := '1'; | |
|
472 | ||
|
473 | when wr1 => | |
|
474 | v.address(14 downto 2) := r.haddr(13 downto 12) & '0' & r.haddr(11 downto 2); | |
|
475 | if (((r.burst and r.hready) = '1') and (r.htrans = "11")) | |
|
476 | and not (WPROTEN and (r.wprothit = '1')) | |
|
477 | then | |
|
478 | v.hready := ahbsi.htrans(0) and ahbsi.htrans(1) and r.hready; | |
|
479 | if ((r.haddr(5 downto 2) = "1111") and (r.cfg.command = "100")) then -- exit on refresh | |
|
480 | v.hready := '0'; | |
|
481 | end if; | |
|
482 | else | |
|
483 | v.sdstate := wr2; v.bdrive := '1'; v.casn := '1'; v.sdwen := '1'; | |
|
484 | v.dqm := (others => '1'); | |
|
485 | end if; | |
|
486 | ||
|
487 | when wr2 => | |
|
488 | if (r.cfg.trp = '0') then v.rasn := '0'; v.sdwen := '0'; end if; | |
|
489 | v.sdstate := wr3; | |
|
490 | ||
|
491 | when wr3 => | |
|
492 | if (r.cfg.trp = '1') then | |
|
493 | v.rasn := '0'; v.sdwen := '0'; v.sdstate := wr4; | |
|
494 | else | |
|
495 | v.sdcsn := "11"; v.rasn := '1'; v.sdwen := '1'; v.sdstate := sidle; | |
|
496 | v.idlecnt := (others => '1'); | |
|
497 | end if; | |
|
498 | ||
|
499 | when wr4 => | |
|
500 | v.sdcsn := "11"; v.rasn := '1'; v.sdwen := '1'; | |
|
501 | if (r.cfg.trp = '1') then v.sdstate := wr5; | |
|
502 | else v.sdstate := sidle; v.idlecnt := (others => '1'); end if; | |
|
503 | ||
|
504 | when wr5 => | |
|
505 | v.sdstate := sidle; v.idlecnt := (others => '1'); | |
|
506 | ||
|
507 | when rd1 => --first read applied to sdram | |
|
508 | v.casn := '1'; v.sdstate := rd7; --nop | |
|
509 | if not BUS16 then --starting adress cannot be XXXX...111 since we have word burst in this case. and lowest bit always 0. | |
|
510 | if lineburst and (ahbsi.htrans = "11") then | |
|
511 | if r.haddr(4 downto 2) = "111" then | |
|
512 | v.address(9 downto 5) := r.address(9 downto 5) + 1; --adds only within 1KB limit. | |
|
513 | v.address(4 downto 2) := "000"; v.casn := '0'; | |
|
514 | end if; | |
|
515 | end if; | |
|
516 | end if; | |
|
517 | ||
|
518 | when rd7 => | |
|
519 | v.casn := '1'; --nop | |
|
520 | if BUS16 then | |
|
521 | if r.cfg.casdel = '1' then --casdel3 | |
|
522 | v.sdstate := rd2; | |
|
523 | if lineburst and (ahbsi.htrans = "11") then | |
|
524 | if r.haddr(3 downto 1) = "110" then | |
|
525 | v.address(10 downto 5) := r.address(10 downto 5) + 1; | |
|
526 | v.address(4 downto 2) := "000"; v.casn := '0'; | |
|
527 | end if; | |
|
528 | end if; | |
|
529 | else --casdel2 | |
|
530 | v.sdstate := rd3; | |
|
531 | if ahbsi.htrans /= "11" then | |
|
532 | if (r.trfc(3 downto 1) = "000") then v.rasn := '0'; v.sdwen := '0'; end if; | |
|
533 | elsif lineburst then | |
|
534 | if r.haddr(3 downto 1) = "110" then | |
|
535 | v.address(10 downto 5) := r.address(10 downto 5) + 1; | |
|
536 | v.address(4 downto 2) := "000"; v.casn := '0'; | |
|
537 | end if; | |
|
538 | end if; | |
|
539 | end if; | |
|
540 | else -- 32 bit or larger | |
|
541 | if r.cfg.casdel = '1' then --casdel3 | |
|
542 | v.sdstate := rd2; | |
|
543 | if lineburst and (ahbsi.htrans = "11") then | |
|
544 | if r.haddr(4 downto 2) = "110" then | |
|
545 | v.address(9 downto 5) := r.address(9 downto 5) + 1; | |
|
546 | v.address(4 downto 2) := "000"; v.casn := '0'; | |
|
547 | end if; | |
|
548 | end if; | |
|
549 | else --casdel2 | |
|
550 | v.sdstate := rd3; | |
|
551 | if ahbsi.htrans /= "11" then | |
|
552 | if (r.trfc(3 downto 1) = "000") then v.rasn := '0'; v.sdwen := '0'; end if; --precharge | |
|
553 | elsif lineburst then | |
|
554 | if r.haddr(4 downto 2) = "110" then | |
|
555 | v.address(9 downto 5) := r.address(9 downto 5) + 1; | |
|
556 | v.address(4 downto 2) := "000"; v.casn := '0'; | |
|
557 | end if; | |
|
558 | end if; | |
|
559 | end if; | |
|
560 | end if; | |
|
561 | ||
|
562 | when rd2 => | |
|
563 | v.casn := '1'; v.sdstate := rd3; | |
|
564 | if BUS16 then | |
|
565 | if ahbsi.htrans /= "11" then | |
|
566 | v.rasn := '0'; v.sdwen := '0'; v.dqm := (others => '1'); --precharge & DQM | |
|
567 | --note that DQM always has 2 cycle delay before blocking data. So NP if we fetch second HW | |
|
568 | end if; | |
|
569 | else | |
|
570 | if ahbsi.htrans /= "11" then v.rasn := '0'; v.sdwen := '0'; v.dqm := (others => '1'); --precharge & DQM | |
|
571 | elsif lineburst then | |
|
572 | if r.haddr(4 downto 2) = "101" then | |
|
573 | v.address(9 downto 5) := r.address(9 downto 5) + 1; | |
|
574 | v.address(4 downto 2) := "000"; v.casn := '0'; | |
|
575 | end if; | |
|
576 | end if; | |
|
577 | end if; | |
|
578 | ||
|
579 | when rd3 => --first read data from sdram output v.lhw := r.haddr(1); | |
|
580 | v.casn := '1'; --if read before cas makes nop else if pre => no difference | |
|
581 | if BUS16 then | |
|
582 | --note if read is for halfwor or byte we dont want to read a second time but exit. | |
|
583 | --if the read is a word we need to change LHW to one since the next read should be muxed in next cylcle. | |
|
584 | -- if r.size(1) = '1' then --word v.hready := not r.size(1) | |
|
585 | -- v.sdstate := rd4_16; v.hready := '0'; --hready low since just first part of a word | |
|
586 | -- v.lhw := '1'; -- read low 16 next state | |
|
587 | -- else --HW or byte | |
|
588 | -- v.sdstate := rd4_16; v.hready := '1'; | |
|
589 | -- end if; | |
|
590 | v.sdstate := rd4_16; | |
|
591 | v.lhw := not r.lhw; --r.lhw is 0 for word, we should invert for next half of word.For HW or Byte v.lhw does not matter. | |
|
592 | v.hready := not r.size(1); --if word transfer the r.size(1) is 1 and hready goes low.If HW or byte r.size(1)=0 => hready=1 | |
|
593 | if r.sdwen = '0' then | |
|
594 | v.rasn := '1'; v.sdwen := '1'; v.sdcsn := "11"; v.dqm := (others => '1'); -- make DSEL (NOP) | |
|
595 | elsif lineburst and ((ahbsi.htrans = "11") and (r.cfg.casdel = '1')) then --only enter if cl3 | |
|
596 | if r.haddr(3 downto 1) = "100" then | |
|
597 | v.address(10 downto 5) := r.address(10 downto 5) + 1; | |
|
598 | v.address(4 downto 2) := "000"; v.casn := '0'; | |
|
599 | end if; | |
|
600 | end if; | |
|
601 | else --32 bit or larger | |
|
602 | v.sdstate := rd4; v.hready := '1'; | |
|
603 | if r.sdwen = '0' then | |
|
604 | v.rasn := '1'; v.sdwen := '1'; v.sdcsn := "11"; v.dqm := (others => '1'); -- make DSEL (NOP) | |
|
605 | elsif lineburst and (ahbsi.htrans = "11") and (r.casn = '1') then | |
|
606 | if r.haddr(4 downto 2) = ("10" & not r.cfg.casdel) then | |
|
607 | v.address(9 downto 5) := r.address(9 downto 5) + 1; | |
|
608 | v.address(4 downto 2) := "000"; v.casn := '0'; | |
|
609 | end if; | |
|
610 | end if; | |
|
611 | end if; | |
|
612 | ||
|
613 | when rd4_16 => --enter as word (r.hready is still 0) else 1. If hready one next transfer sampled into v. | |
|
614 | --v.hready := '1'; | |
|
615 | v.hready := not r.hready;-- if Byte or HW exit with hready low. If word flip bit, makes correct exit with hready low. | |
|
616 | v.lhw := not r.lhw; --r.lhw is one the first time we enter (taking care of second part of word) | |
|
617 | v.casn := '1'; | |
|
618 | --quit on: Single transfer CL 2/3 (prcharge if CL 2 and timer was not 0) | |
|
619 | if (ahbsi.htrans /= "11" and (r.hready = '1')) or | |
|
620 | ((r.haddr(9) xor ahbsi.haddr(9)) = '1' and r.cfg.csize = "00" and r.hready = '1') or --probably dont have to check hready 1 since if 0 adresses equal. | |
|
621 | ((r.haddr(5 downto 2) = "1111") and (r.cfg.command = "100") and (r.hready = '1')) then --quit on: ST W/HW/BYTE OR | |
|
622 | --v.hready := '0'; --if Byte or HW exit with hready low, if ST word exit with high. | |
|
623 | v.dqm := (others => '1'); | |
|
624 | if r.sdcsn /= "11" then --not prechargeing | |
|
625 | v.rasn := '0'; v.sdwen := '0'; v.sdstate := rd5; --precharge | |
|
626 | else--exit | |
|
627 | if r.cfg.trp = '1' then v.sdstate := rd6; | |
|
628 | else v.sdstate := sidle; v.idlecnt := (others => '1'); end if; | |
|
629 | end if; | |
|
630 | elsif lineburst then --NOTE: r.casn = 1 makes sure its the first halfword of a word that is checked (hready low) | |
|
631 | if r.cfg.casdel = '0' then | |
|
632 | if (r.haddr(3 downto 1) = "100") and (r.casn = '1') then --lline = 011 if casdel =1, 100 if casdel= 0 | |
|
633 | v.address(10 downto 5) := r.address(10 downto 5) + 1; | |
|
634 | v.address(4 downto 2) := "000"; v.casn := '0'; | |
|
635 | end if; | |
|
636 | else | |
|
637 | if (r.haddr(3 downto 1) = "010") and (r.hready = '1') then --lline = 011 if casdel =1, 100 if casdel= 0 | |
|
638 | v.address(10 downto 5) := r.address(10 downto 5) + 1; | |
|
639 | v.address(4 downto 2) := "000"; v.casn := '0'; | |
|
640 | end if; | |
|
641 | end if; | |
|
642 | end if; | |
|
643 | ||
|
644 | when rd4 => | |
|
645 | v.hready := '1'; v.casn := '1'; | |
|
646 | if (ahbsi.htrans /= "11") or (r.sdcsn = "11") or | |
|
647 | ((r.haddr(5 downto 2) = "1111") and (r.cfg.command = "100")) -- exit on refresh | |
|
648 | then | |
|
649 | v.hready := '0'; v.dqm := (others => '1'); | |
|
650 | if (r.sdcsn /= "11") then | |
|
651 | v.rasn := '0'; v.sdwen := '0'; v.sdstate := rd5; | |
|
652 | else | |
|
653 | if r.cfg.trp = '1' then v.sdstate := rd6; | |
|
654 | else v.sdstate := sidle; v.idlecnt := (others => '1'); end if; | |
|
655 | end if; | |
|
656 | elsif lineburst then | |
|
657 | if (r.haddr(4 downto 2) = lline) and (r.casn = '1') then | |
|
658 | v.address(9 downto 5) := r.address(9 downto 5) + 1; | |
|
659 | v.address(4 downto 2) := "000"; v.casn := '0'; | |
|
660 | end if; | |
|
661 | end if; | |
|
662 | ||
|
663 | when rd5 => | |
|
664 | if r.cfg.trp = '1' then v.sdstate := rd6; else v.sdstate := sidle; v.idlecnt := (others => '1'); end if; | |
|
665 | v.sdcsn := (others => '1'); v.rasn := '1'; v.sdwen := '1'; v.dqm := (others => '1'); | |
|
666 | v.casn := '1'; | |
|
667 | ||
|
668 | when rd6 => | |
|
669 | v.sdstate := sidle; v.idlecnt := (others => '1'); v.dqm := (others => '1'); | |
|
670 | v.sdcsn := (others => '1'); v.rasn := '1'; v.sdwen := '1'; | |
|
671 | ||
|
672 | when sref => | |
|
673 | if (startsd = '1' and (r.hio = '0')) | |
|
674 | or (r.cfg.command /= "000") or r.cfg.pmode /= PM_SR then | |
|
675 | if r.trfc = "0000" then -- Minimum duration (= tRAS) | |
|
676 | v.cfg.cke := '1'; | |
|
677 | v.sdcsn := (others => '0'); v.rasn := '1'; v.casn := '1'; | |
|
678 | end if; | |
|
679 | if r.cfg.cke = '1' then | |
|
680 | if (r.idlecnt = "0000") then -- tXSR ns with NOP | |
|
681 | v.sdstate := sidle; | |
|
682 | v.idlecnt := (others => '1'); | |
|
683 | v.sref_tmpcom := r.cfg.command; | |
|
684 | v.cfg.command := "100"; | |
|
685 | end if; | |
|
686 | else | |
|
687 | v.idlecnt := r.cfg.txsr; | |
|
688 | end if; | |
|
689 | end if; | |
|
690 | ||
|
691 | when pd => | |
|
692 | if (startsd = '1' and (r.hio = '0')) | |
|
693 | or (r.cfg.command /= "000") or r.cfg.pmode /= PM_PD then | |
|
694 | v.cfg.cke := '1'; | |
|
695 | v.sdstate := sidle; | |
|
696 | v.idlecnt := (others => '1'); | |
|
697 | end if; | |
|
698 | ||
|
699 | when dpd => | |
|
700 | v.sdcsn := (others => '1'); v.sdwen := '1'; v.rasn := '1'; v.casn := '1'; | |
|
701 | v.cfg.renable := '0'; | |
|
702 | if (startsd = '1' and r.hio = '0') then | |
|
703 | v.hready := '1'; -- ack all accesses with Error response | |
|
704 | v.startsd := '0'; | |
|
705 | v.hresp := HRESP_ERROR; | |
|
706 | elsif r.cfg.pmode /= PM_DPD then | |
|
707 | v.cfg.cke := '1'; | |
|
708 | if r.cfg.cke = '1' then | |
|
709 | v.sdstate := sidle; | |
|
710 | v.idlecnt := (others => '1'); | |
|
711 | v.cfg.renable := '1'; | |
|
712 | end if; | |
|
713 | end if; | |
|
714 | ||
|
715 | when others => | |
|
716 | v.sdstate := sidle; v.idlecnt := (others => '1'); | |
|
717 | end case; | |
|
718 | ||
|
719 | -- sdram commands | |
|
720 | ||
|
721 | case r.cmstate is | |
|
722 | when midle => | |
|
723 | if r.sdstate = sidle then | |
|
724 | case r.cfg.command is | |
|
725 | when "010" => -- precharge | |
|
726 | v.sdcsn := (others => '0'); v.rasn := '0'; v.sdwen := '0'; | |
|
727 | v.address(12) := '1'; v.cmstate := active; | |
|
728 | when "100" => -- auto-refresh | |
|
729 | v.sdcsn := (others => '0'); v.rasn := '0'; v.casn := '0'; | |
|
730 | v.cmstate := active; | |
|
731 | when "110" => -- Lodad Mode Reg | |
|
732 | v.sdcsn := (others => '0'); v.rasn := '0'; v.casn := '0'; | |
|
733 | v.sdwen := '0'; v.cmstate := active; | |
|
734 | if lineburst then | |
|
735 | v.address(16 downto 2) := "0000010001" & r.cfg.casdel & "0011"; | |
|
736 | else | |
|
737 | v.address(16 downto 2) := "0000010001" & r.cfg.casdel & "0111"; | |
|
738 | end if; | |
|
739 | when "111" => -- Load Ext-Mode Reg | |
|
740 | v.sdcsn := (others => '0'); v.rasn := '0'; v.casn := '0'; | |
|
741 | v.sdwen := '0'; v.cmstate := active; | |
|
742 | v.address(16 downto 2) := "10000000" & r.cfg.ds(1 downto 0) & r.cfg.tcsr(1 downto 0) | |
|
743 | & r.cfg.pasr(2 downto 0); | |
|
744 | when others => null; | |
|
745 | end case; | |
|
746 | end if; | |
|
747 | when active => | |
|
748 | v.sdcsn := (others => '1'); v.rasn := '1'; v.casn := '1'; | |
|
749 | v.sdwen := '1'; --v.cfg.command := "000"; | |
|
750 | v.cfg.command := r.sref_tmpcom; v.sref_tmpcom := "000"; | |
|
751 | v.cmstate := leadout; v.trfc := (r.cfg.trp and r.cfg.mobileen(1)) & r.cfg.trfc; | |
|
752 | when leadout => | |
|
753 | if r.trfc = "0000" then v.cmstate := midle; end if; | |
|
754 | ||
|
755 | end case; | |
|
756 | ||
|
757 | -- sdram init | |
|
758 | ||
|
759 | case r.istate is | |
|
760 | when iidle => | |
|
761 | v.cfg.cke := '1'; | |
|
762 | if r.cfg.renable = '1' and r.cfg.cke = '1' then | |
|
763 | v.cfg.command := "010"; v.istate := pre; | |
|
764 | end if; | |
|
765 | when pre => | |
|
766 | if r.cfg.command = "000" then | |
|
767 | v.cfg.command := "100"; v.istate := ref; v.icnt := "111"; | |
|
768 | end if; | |
|
769 | when ref => | |
|
770 | if r.cfg.command = "000" then | |
|
771 | v.cfg.command := "100"; v.icnt := r.icnt - 1; | |
|
772 | if r.icnt = "000" then v.istate := lmode; v.cfg.command := "110"; end if; | |
|
773 | end if; | |
|
774 | when lmode => | |
|
775 | if r.cfg.command = "000" then | |
|
776 | if r.cfg.mobileen = "11" then | |
|
777 | v.cfg.command := "111"; v.istate := emode; | |
|
778 | else | |
|
779 | v.istate := finish; | |
|
780 | end if; | |
|
781 | end if; | |
|
782 | when emode => | |
|
783 | if r.cfg.command = "000" then | |
|
784 | v.istate := finish; | |
|
785 | end if; | |
|
786 | when others => | |
|
787 | if r.cfg.renable = '0' and r.sdstate /= dpd then | |
|
788 | v.istate := iidle; | |
|
789 | end if; | |
|
790 | end case; | |
|
791 | ||
|
792 | if (ahbsi.hready and ahbsi.hsel(hindex) ) = '1' then | |
|
793 | if ahbsi.htrans(1) = '0' then v.hready := '1'; end if; | |
|
794 | end if; | |
|
795 | ||
|
796 | if (r.hsel and r.hio and not r.hready) = '1' then v.hready := '1'; end if; | |
|
797 | ||
|
798 | -- second part of main fsm | |
|
799 | ||
|
800 | case r.mstate is | |
|
801 | when active => | |
|
802 | if v.hready = '1' then | |
|
803 | v.mstate := midle; | |
|
804 | end if; | |
|
805 | when others => null; | |
|
806 | end case; | |
|
807 | ||
|
808 | -- sdram refresh counter | |
|
809 | ||
|
810 | -- pragma translate_off | |
|
811 | if not is_x(r.cfg.refresh) then | |
|
812 | -- pragma translate_on | |
|
813 | if (r.cfg.renable = '1') and (r.istate = finish) and r.sdstate /= sref then | |
|
814 | v.refresh := r.refresh - 1; | |
|
815 | if (v.refresh(14) and not r.refresh(14)) = '1' then | |
|
816 | v.refresh := r.cfg.refresh; | |
|
817 | v.cfg.command := "100"; | |
|
818 | arefresh := '1'; | |
|
819 | end if; | |
|
820 | end if; | |
|
821 | -- pragma translate_off | |
|
822 | end if; | |
|
823 | -- pragma translate_on | |
|
824 | ||
|
825 | -- AHB register access | |
|
826 | -- if writing to IO space config regs. Just mapping write data to all config values in config reg | |
|
827 | if (r.hsel and r.hio and r.hwrite and r.htrans(1)) = '1' then | |
|
828 | if r.haddr(3 downto 2) = "00" then | |
|
829 | if pageburst = 2 then v.cfg.pageburst := hwdata(17); end if; | |
|
830 | v.cfg.command := hwdata(20 downto 18); | |
|
831 | v.cfg.csize := hwdata(22 downto 21); | |
|
832 | v.cfg.bsize := hwdata(25 downto 23); | |
|
833 | v.cfg.casdel := hwdata(26); | |
|
834 | v.cfg.trfc := hwdata(29 downto 27); | |
|
835 | v.cfg.trp := hwdata(30); | |
|
836 | v.cfg.renable := hwdata(31); | |
|
837 | v.cfg.refresh := hwdata(14 downto 0); | |
|
838 | v.refresh := (others => '0'); | |
|
839 | elsif r.haddr(3 downto 2) = "01" then | |
|
840 | if r.cfg.mobileen(1) = '1' and mobile /= 3 then v.cfg.mobileen(0) := hwdata(31); end if; | |
|
841 | if r.cfg.pmode = "000" then | |
|
842 | v.cfg.cke := hwdata(30); | |
|
843 | end if; | |
|
844 | if r.cfg.mobileen(1) = '1' then | |
|
845 | v.cfg.txsr := hwdata(23 downto 20); | |
|
846 | v.cfg.pmode := hwdata(18 downto 16); | |
|
847 | v.cfg.ds(3 downto 2) := hwdata( 6 downto 5); | |
|
848 | v.cfg.tcsr(3 downto 2) := hwdata( 4 downto 3); | |
|
849 | v.cfg.pasr(5 downto 3) := hwdata( 2 downto 0); | |
|
850 | end if; | |
|
851 | end if; | |
|
852 | end if; | |
|
853 | ||
|
854 | -- Disable CS and DPD when Mobile SDR is Disabled | |
|
855 | if r.cfg.mobileen(0) = '0' then v.cfg.pmode(2) := '0'; end if; | |
|
856 | ||
|
857 | -- Update EMR when ds, tcsr or pasr change | |
|
858 | if r.cfg.command = "000" and arefresh = '0' and r.cfg.mobileen(0) = '1' then | |
|
859 | if r.cfg.ds(1 downto 0) /= r.cfg.ds(3 downto 2) then | |
|
860 | v.cfg.command := "111"; v.cfg.ds(1 downto 0) := r.cfg.ds(3 downto 2); | |
|
861 | end if; | |
|
862 | if r.cfg.tcsr(1 downto 0) /= r.cfg.tcsr(3 downto 2) then | |
|
863 | v.cfg.command := "111"; v.cfg.tcsr(1 downto 0) := r.cfg.tcsr(3 downto 2); | |
|
864 | end if; | |
|
865 | if r.cfg.pasr(2 downto 0) /= r.cfg.pasr(5 downto 3) then | |
|
866 | v.cfg.command := "111"; v.cfg.pasr(2 downto 0) := r.cfg.pasr(5 downto 3); | |
|
867 | end if; | |
|
868 | end if; | |
|
869 | ||
|
870 | regsd := (others => '0'); | |
|
871 | --reads out config registers (r/w does not matter) according to manual depending on address, notice generic determines data width. | |
|
872 | if r.haddr(3 downto 2) = "00" then | |
|
873 | regsd(31 downto 18) := r.cfg.renable & r.cfg.trp & r.cfg.trfc & | |
|
874 | r.cfg.casdel & r.cfg.bsize & r.cfg.csize & r.cfg.command; | |
|
875 | if not lineburst then regsd(17) := '1'; end if; | |
|
876 | regsd(16) := r.cfg.mobileen(1); | |
|
877 | if BUS64 then regsd(15) := '1'; end if; | |
|
878 | regsd(14 downto 0) := r.cfg.refresh; | |
|
879 | elsif r.haddr(3 downto 2) = "01" then | |
|
880 | regsd(31) := r.cfg.mobileen(0); | |
|
881 | regsd(30) := r.cfg.cke; | |
|
882 | regsd(23 downto 0) := r.cfg.txsr & '0' & r.cfg.pmode & "000000000" & | |
|
883 | r.cfg.ds(1 downto 0) & r.cfg.tcsr(1 downto 0) & r.cfg.pasr(2 downto 0); | |
|
884 | end if; | |
|
885 | ||
|
886 | if (r.hsel and r.hio) = '1' then dout := regsd; | |
|
887 | else | |
|
888 | if BUS64 and r.bsel = '1' then dout := r.hrdata(63 downto 32); | |
|
889 | else dout := r.hrdata(31 downto 0); end if; | |
|
890 | end if; | |
|
891 | ||
|
892 | v.nbdrive := not v.bdrive; | |
|
893 | ||
|
894 | if oepol = 1 then bdrive := r.nbdrive; vbdrive := (others => v.nbdrive); | |
|
895 | else bdrive := r.bdrive; vbdrive := (others => v.bdrive);end if; | |
|
896 | ||
|
897 | -- reset | |
|
898 | ||
|
899 | if rst = '0' then | |
|
900 | v.sdstate := sidle; | |
|
901 | v.mstate := midle; | |
|
902 | v.istate := iidle; | |
|
903 | v.cmstate := midle; | |
|
904 | v.hsel := '0'; | |
|
905 | v.cfg.command := "000"; | |
|
906 | v.cfg.csize := "01"; | |
|
907 | v.cfg.bsize := "011"; | |
|
908 | v.cfg.casdel := '1'; | |
|
909 | v.cfg.trfc := "111"; | |
|
910 | if pwron = 1 then v.cfg.renable := '1'; | |
|
911 | else v.cfg.renable := '0'; end if; | |
|
912 | v.cfg.trp := '1'; | |
|
913 | v.dqm := (others => '1'); | |
|
914 | v.sdwen := '1'; | |
|
915 | v.rasn := '1'; | |
|
916 | v.casn := '1'; | |
|
917 | v.hready := '1'; | |
|
918 | v.bsel := '0'; | |
|
919 | v.startsd := '0'; | |
|
920 | if (pageburst = 2) then | |
|
921 | v.cfg.pageburst := '0'; | |
|
922 | end if; | |
|
923 | if mobile >= 2 then v.cfg.mobileen := "11"; | |
|
924 | elsif mobile = 1 then v.cfg.mobileen := "10"; | |
|
925 | else v.cfg.mobileen := "00"; end if; | |
|
926 | v.cfg.txsr := (others => '1'); | |
|
927 | v.cfg.pmode := (others => '0'); | |
|
928 | v.cfg.ds := (others => '0'); | |
|
929 | v.cfg.tcsr := (others => '0'); | |
|
930 | v.cfg.pasr := (others => '0'); | |
|
931 | if mobile >= 2 then v.cfg.cke := '0'; | |
|
932 | else v.cfg.cke := '1'; end if; | |
|
933 | v.sref_tmpcom := "000"; | |
|
934 | v.idlecnt := (others => '1'); | |
|
935 | end if; | |
|
936 | ||
|
937 | ri <= v; | |
|
938 | ribdrive <= vbdrive; | |
|
939 | ||
|
940 | ahbso.hready <= r.hready; | |
|
941 | ahbso.hresp <= r.hresp; | |
|
942 | ahbso.hrdata <= ahbdrivedata(dout); | |
|
943 | ||
|
944 | end process; | |
|
945 | ||
|
946 | --sdo.sdcke <= (others => '1'); | |
|
947 | sdo.sdcke <= (others => r.cfg.cke); | |
|
948 | ahbso.hconfig <= hconfig; | |
|
949 | ahbso.hirq <= (others => '0'); | |
|
950 | ahbso.hindex <= hindex; | |
|
951 | ahbso.hsplit <= (others => '0'); | |
|
952 | ||
|
953 | -- Quick hack to get rid of undriven signal warnings. Check this for future | |
|
954 | -- merge with main sdctrl. | |
|
955 | drivehack : block | |
|
956 | begin | |
|
957 | sdo.qdrive <= '0'; | |
|
958 | sdo.nbdrive <= '0'; | |
|
959 | sdo.ce <= '0'; | |
|
960 | sdo.moben <= '0'; | |
|
961 | sdo.cal_rst <= '0'; | |
|
962 | sdo.oct <= '0'; | |
|
963 | sdo.xsdcsn <= (others => '1'); | |
|
964 | sdo.data(127 downto 16) <= (others => '0'); | |
|
965 | sdo.cb <= (others => '0'); | |
|
966 | sdo.ba <= (others => '0'); | |
|
967 | sdo.sdck <= (others => '0'); | |
|
968 | sdo.cal_en <= (others => '0'); | |
|
969 | sdo.cal_inc <= (others => '0'); | |
|
970 | sdo.cal_pll <= (others => '0'); | |
|
971 | sdo.odt <= (others => '0'); | |
|
972 | sdo.conf <= (others => '0'); | |
|
973 | sdo.vcbdrive <= (others => '0'); | |
|
974 | sdo.dqs_gate <= '0'; | |
|
975 | sdo.cbdqm <= (others => '0'); | |
|
976 | sdo.cbcal_en <= (others => '0'); | |
|
977 | sdo.cbcal_inc <= (others => '0'); | |
|
978 | sdo.read_pend <= (others => '0'); | |
|
979 | sdo.regwdata <= (others => '0'); | |
|
980 | sdo.regwrite <= (others => '0'); | |
|
981 | end block drivehack; | |
|
982 | ||
|
983 | regs : process(clk, rst) begin | |
|
984 | if rising_edge(clk) then | |
|
985 | r <= ri; rbdrive <= ribdrive; | |
|
986 | if rst = '0' then r.icnt <= (others => '0'); end if; | |
|
987 | end if; | |
|
988 | if (rst = '0') then | |
|
989 | r.sdcsn <= (others => '1'); r.bdrive <= '1'; r.nbdrive <= '0'; | |
|
990 | if oepol = 0 then rbdrive <= (others => '1'); | |
|
991 | else rbdrive <= (others => '0'); end if; | |
|
992 | end if; | |
|
993 | end process; | |
|
994 | ||
|
995 | rgen : if not SDINVCLK generate | |
|
996 | sdo.address <= r.address; | |
|
997 | sdo.bdrive <= r.nbdrive when oepol = 1 else r.bdrive; | |
|
998 | sdo.vbdrive <= zero32 & rbdrive; | |
|
999 | sdo.sdcsn <= r.sdcsn; | |
|
1000 | sdo.sdwen <= r.sdwen; | |
|
1001 | sdo.dqm <= "11111111" & r.dqm; | |
|
1002 | sdo.rasn <= r.rasn; | |
|
1003 | sdo.casn <= r.casn; | |
|
1004 | ||
|
1005 | mux16_wrdata : if BUS16 generate --mux data depending on Low/High HW | |
|
1006 | sdo.data(15 downto 0) <= r.hwdata(15 downto 0) when r.lhw = '1' else r.hwdata(31 downto 16); | |
|
1007 | end generate; | |
|
1008 | ||
|
1009 | wrdata : if not BUS16 generate | |
|
1010 | drivebus: for i in 0 to sdbits/64 generate | |
|
1011 | sdo.data(31+32*i downto 32*i) <= r.hwdata; | |
|
1012 | end generate; | |
|
1013 | end generate; | |
|
1014 | end generate; | |
|
1015 | ||
|
1016 | ngen : if SDINVCLK generate | |
|
1017 | nregs : process(clk, rst) begin | |
|
1018 | if falling_edge(clk) then | |
|
1019 | sdo.address <= r.address; | |
|
1020 | if oepol = 1 then sdo.bdrive <= r.nbdrive; | |
|
1021 | else sdo.bdrive <= r.bdrive; end if; | |
|
1022 | sdo.vbdrive <= zero32 & rbdrive; | |
|
1023 | sdo.sdcsn <= r.sdcsn; | |
|
1024 | sdo.sdwen <= r.sdwen; | |
|
1025 | sdo.dqm <= "11111111" & r.dqm; | |
|
1026 | sdo.rasn <= r.rasn; | |
|
1027 | sdo.casn <= r.casn; | |
|
1028 | if BUS16 then --mux data depending on Low/High HW | |
|
1029 | if (r.lhw ='1') then | |
|
1030 | sdo.data(15 downto 0) <= r.hwdata(15 downto 0); | |
|
1031 | else | |
|
1032 | sdo.data(15 downto 0) <= r.hwdata(31 downto 16); | |
|
1033 | end if; | |
|
1034 | end if; | |
|
1035 | ||
|
1036 | if not BUS16 then | |
|
1037 | for i in 0 to sdbits/64 loop | |
|
1038 | sdo.data(31+32*i downto 32*i) <= r.hwdata; | |
|
1039 | end loop; | |
|
1040 | end if; | |
|
1041 | end if; | |
|
1042 | if rst = '0' then sdo.sdcsn <= (others => '1'); end if; | |
|
1043 | end process; | |
|
1044 | end generate; | |
|
1045 | ||
|
1046 | -- pragma translate_off | |
|
1047 | bootmsg : report_version | |
|
1048 | generic map ("sdctrl16" & tost(hindex) & | |
|
1049 | ": PC133 SDRAM controller rev " & tost(REVISION)); | |
|
1050 | -- pragma translate_on | |
|
1051 | ||
|
1052 | end; | |
|
1053 |
@@ -0,0 +1,200 | |||
|
1 | ------------------------------------------------------------------------------ | |
|
2 | -- LEON3 Demonstration design test bench | |
|
3 | -- Copyright (C) 2004 Jiri Gaisler, Gaisler Research | |
|
4 | ------------------------------------------------------------------------------ | |
|
5 | ------------------------------------------------------------------------------ | |
|
6 | -- This file is a part of the GRLIB VHDL IP LIBRARY | |
|
7 | -- Copyright (C) 2003 - 2008, Gaisler Research | |
|
8 | -- Copyright (C) 2008 - 2014, Aeroflex Gaisler | |
|
9 | -- Copyright (C) 2015 - 2016, Cobham Gaisler | |
|
10 | -- | |
|
11 | -- This program is free software; you can redistribute it and/or modify | |
|
12 | -- it under the terms of the GNU General Public License as published by | |
|
13 | -- the Free Software Foundation; either version 2 of the License, or | |
|
14 | -- (at your option) any later version. | |
|
15 | -- | |
|
16 | -- This program is distributed in the hope that it will be useful, | |
|
17 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of | |
|
18 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
|
19 | -- GNU General Public License for more details. | |
|
20 | -- | |
|
21 | -- You should have received a copy of the GNU General Public License | |
|
22 | -- along with this program; if not, write to the Free Software | |
|
23 | -- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
|
24 | ||
|
25 | library ieee; | |
|
26 | use ieee.std_logic_1164.all; | |
|
27 | library gaisler; | |
|
28 | use gaisler.libdcom.all; | |
|
29 | use gaisler.sim.all; | |
|
30 | use work.debug.all; | |
|
31 | library techmap; | |
|
32 | use techmap.gencomp.all; | |
|
33 | library micron; | |
|
34 | use micron.components.all; | |
|
35 | library grlib; | |
|
36 | use grlib.stdlib.all; | |
|
37 | ||
|
38 | use work.config.all; -- configuration | |
|
39 | ||
|
40 | ||
|
41 | entity testbench is | |
|
42 | generic ( | |
|
43 | fabtech : integer := CFG_FABTECH; | |
|
44 | memtech : integer := CFG_MEMTECH; | |
|
45 | padtech : integer := CFG_PADTECH; | |
|
46 | clktech : integer := CFG_CLKTECH; | |
|
47 | disas : integer := CFG_DISAS; -- Enable disassembly to console | |
|
48 | dbguart : integer := CFG_DUART; -- Print UART on console | |
|
49 | pclow : integer := CFG_PCLOW; | |
|
50 | ||
|
51 | clkperiod : integer := 20; -- system clock period | |
|
52 | romdepth : integer := 22 -- rom address depth (flash 4 MB) | |
|
53 | -- sramwidth : integer := 32; -- ram data width (8/16/32) | |
|
54 | -- sramdepth : integer := 20; -- ram address depth | |
|
55 | -- srambanks : integer := 2 -- number of ram banks | |
|
56 | ); | |
|
57 | end; | |
|
58 | ||
|
59 | architecture behav of testbench is | |
|
60 | ||
|
61 | constant promfile : string := "prom.srec"; -- rom contents | |
|
62 | constant sramfile : string := "ram.srec"; -- ram contents | |
|
63 | constant sdramfile : string := "ram.srec"; -- sdram contents | |
|
64 | ||
|
65 | ||
|
66 | signal SW : std_logic_vector(4 downto 1); | |
|
67 | signal clk : std_logic := '0'; | |
|
68 | signal Rst : std_logic := '0'; -- Reset | |
|
69 | constant ct : integer := clkperiod/2; | |
|
70 | ||
|
71 | signal address : std_logic_vector(21 downto 0); | |
|
72 | signal data : std_logic_vector(31 downto 24); | |
|
73 | ||
|
74 | signal romsn : std_logic; | |
|
75 | signal oen : std_logic; | |
|
76 | signal writen : std_logic; | |
|
77 | signal dsuen, dsutx, dsurx, dsubre, dsuact : std_logic; | |
|
78 | signal dsurst : std_logic; | |
|
79 | signal error : std_logic; | |
|
80 | ||
|
81 | signal sdcke : std_logic; | |
|
82 | signal sdcsn : std_logic; | |
|
83 | signal sdwen : std_logic; -- write en | |
|
84 | signal sdrasn : std_logic; -- row addr stb | |
|
85 | signal sdcasn : std_logic; -- col addr stb | |
|
86 | signal dram_ldqm : std_logic; | |
|
87 | signal dram_udqm : std_logic; | |
|
88 | signal sdclk : std_logic; | |
|
89 | signal dram_ba : std_logic_vector(1 downto 0); | |
|
90 | ||
|
91 | ||
|
92 | ||
|
93 | constant lresp : boolean := false; | |
|
94 | ||
|
95 | ||
|
96 | signal sa : std_logic_vector(12 downto 0); | |
|
97 | signal sd : std_logic_vector(15 downto 0); | |
|
98 | ||
|
99 | ||
|
100 | begin | |
|
101 | ||
|
102 | clk <= not clk after ct * 1 ns; --50 MHz clk | |
|
103 | rst <= dsurst; --reset | |
|
104 | dsuen <= '1'; | |
|
105 | dsubre <= '1'; -- inverted on the board | |
|
106 | sw(1) <= rst; | |
|
107 | ||
|
108 | d3 : entity work.leon3mp | |
|
109 | generic map ( fabtech, memtech, padtech, clktech, disas, dbguart, pclow ) | |
|
110 | port map ( | |
|
111 | CLK50 => clk, | |
|
112 | LEDS => open, | |
|
113 | SW => SW, | |
|
114 | dram_addr => sa, | |
|
115 | dram_ba_0 => dram_ba(0), | |
|
116 | dram_ba_1 => dram_ba(1), | |
|
117 | dram_dq => sd(15 downto 0), | |
|
118 | dram_clk => sdclk, | |
|
119 | dram_cke => sdcke, | |
|
120 | dram_cs_n => sdcsn, | |
|
121 | dram_we_n => sdwen, | |
|
122 | dram_ras_n => sdrasn, | |
|
123 | dram_cas_n => sdcasn, | |
|
124 | dram_ldqm => dram_ldqm, | |
|
125 | dram_udqm => dram_udqm, | |
|
126 | uart_txd => dsutx, | |
|
127 | uart_rxd => dsurx); | |
|
128 | ||
|
129 | u1: entity work.mt48lc16m16a2 generic map (addr_bits => 13, col_bits => 9, index => 1024, fname => sdramfile) | |
|
130 | PORT MAP( | |
|
131 | Dq => sd(15 downto 0), Addr => sa(12 downto 0), | |
|
132 | Ba => dram_ba, Clk => sdclk, Cke => sdcke, | |
|
133 | Cs_n => sdcsn, Ras_n => sdrasn, Cas_n => sdcasn, We_n => sdwen, | |
|
134 | Dqm(0) => dram_ldqm, Dqm(1) => dram_udqm ); | |
|
135 | ||
|
136 | ||
|
137 | ||
|
138 | error <= 'H'; -- ERROR pull-up | |
|
139 | ||
|
140 | iuerr : process | |
|
141 | begin | |
|
142 | wait for 2500 ns; | |
|
143 | if to_x01(error) = '1' then wait on error; end if; | |
|
144 | assert (to_x01(error) = '1') | |
|
145 | report "*** IU in error mode, simulation halted ***" | |
|
146 | severity failure ; | |
|
147 | end process; | |
|
148 | ||
|
149 | data <= buskeep(data) after 5 ns; | |
|
150 | sd <= buskeep(sd) after 5 ns; | |
|
151 | ||
|
152 | dsucom : process | |
|
153 | variable w32 : std_logic_vector(31 downto 0); | |
|
154 | constant txp : time := 160 * 1 ns; | |
|
155 | procedure writeReg(signal dsutx : out std_logic; address : integer; value : integer) is | |
|
156 | begin | |
|
157 | txc(dsutx, 16#c0#, txp); --control byte | |
|
158 | txa(dsutx, (address / (256*256*256)) , (address / (256*256)), (address / (256)), address, txp); --adress | |
|
159 | txa(dsutx, (value / (256*256*256)) , (value / (256*256)), (value / (256)), value, txp); --write data | |
|
160 | end; | |
|
161 | ||
|
162 | procedure readReg(signal dsurx : in std_logic; signal dsutx : out std_logic; address : integer; value: out std_logic_vector) is | |
|
163 | ||
|
164 | begin | |
|
165 | txc(dsutx, 16#a0#, txp); --control byte | |
|
166 | txa(dsutx, (address / (256*256*256)) , (address / (256*256)), (address / (256)), address, txp); --adress | |
|
167 | rxi(dsurx, value, txp, lresp); --write data | |
|
168 | end; | |
|
169 | ||
|
170 | procedure dsucfg(signal dsurx : in std_logic; signal dsutx : out std_logic) is | |
|
171 | variable c8 : std_logic_vector(7 downto 0); | |
|
172 | begin | |
|
173 | dsutx <= '1'; | |
|
174 | dsurst <= '0'; --reset low | |
|
175 | wait for 500 ns; | |
|
176 | dsurst <= '1'; --reset high | |
|
177 | --wait; --evig w8 | |
|
178 | wait for 5000 ns; | |
|
179 | txc(dsutx, 16#55#, txp); | |
|
180 | --dsucfg(dsutx, dsurx); | |
|
181 | writeReg(dsutx,16#40000000#,16#12345678#); | |
|
182 | writeReg(dsutx,16#40000004#,16#22222222#); | |
|
183 | writeReg(dsutx,16#40000008#,16#33333333#); | |
|
184 | writeReg(dsutx,16#4000000C#,16#44444444#); | |
|
185 | ||
|
186 | readReg(dsurx,dsutx,16#40000000#,w32); | |
|
187 | readReg(dsurx,dsutx,16#40000004#,w32); | |
|
188 | readReg(dsurx,dsutx,16#40000008#,w32); | |
|
189 | readReg(dsurx,dsutx,16#4000000C#,w32); | |
|
190 | ||
|
191 | end; | |
|
192 | ||
|
193 | begin | |
|
194 | dsucfg(dsutx, dsurx); | |
|
195 | ||
|
196 | ||
|
197 | wait; | |
|
198 | end process; | |
|
199 | end ; | |
|
200 |
@@ -0,0 +1,143 | |||
|
1 | # Clocks | |
|
2 | NET "CLK50" PERIOD = 20 ns |LOC = "K3"; | |
|
3 | #NET "CLK32" PERIOD = 31.25 ns | LOC = "J4"; | |
|
4 | # LEDs | |
|
5 | NET "LEDS<0>" LOC="P11" |IOSTANDARD=LVTTL |DRIVE=8 |SLEW=SLOW; | |
|
6 | NET "LEDS<1>" LOC="N9" |IOSTANDARD=LVTTL |DRIVE=8 |SLEW=SLOW; | |
|
7 | NET "LEDS<2>" LOC="M9" |IOSTANDARD=LVTTL |DRIVE=8 |SLEW=SLOW; | |
|
8 | NET "LEDS<3>" LOC="P9" |IOSTANDARD=LVTTL |DRIVE=8 |SLEW=SLOW; | |
|
9 | NET "LEDS<4>" LOC="T8" |IOSTANDARD=LVTTL |DRIVE=8 |SLEW=SLOW; | |
|
10 | NET "LEDS<5>" LOC="N8" |IOSTANDARD=LVTTL |DRIVE=8 |SLEW=SLOW; | |
|
11 | NET "LEDS<6>" LOC="P8" |IOSTANDARD=LVTTL |DRIVE=8 |SLEW=SLOW; | |
|
12 | NET "LEDS<7>" LOC="P7" |IOSTANDARD=LVTTL |DRIVE=8 |SLEW=SLOW; | |
|
13 | ||
|
14 | # DIP Switches | |
|
15 | NET "SW<1>" LOC="L1" |IOSTANDARD=LVTTL |PULLUP; | |
|
16 | NET "SW<2>" LOC="L3" |IOSTANDARD=LVTTL |PULLUP; | |
|
17 | NET "SW<3>" LOC="L4" |IOSTANDARD=LVTTL |PULLUP; | |
|
18 | NET "SW<4>" LOC="L5" |IOSTANDARD=LVTTL |PULLUP; | |
|
19 | ||
|
20 | NET "uart_rxd" LOC="M7" |IOSTANDARD=LVTTL; | |
|
21 | NET "uart_txd" LOC="N6" |IOSTANDARD=LVTTL; | |
|
22 | ||
|
23 | # SDRAM | |
|
24 | NET "dram_udqm" LOC="F15" |IOSTANDARD=LVTTL; | |
|
25 | NET "dram_clk" LOC="G16" |IOSTANDARD=LVTTL; | |
|
26 | NET "dram_cke" LOC="H16" |IOSTANDARD=LVTTL; | |
|
27 | NET "dram_ba_1" LOC="T14" |IOSTANDARD=LVTTL; | |
|
28 | NET "dram_ba_0" LOC="R14" |IOSTANDARD=LVTTL; | |
|
29 | NET "dram_cs_n" LOC="R1" |IOSTANDARD=LVTTL; | |
|
30 | NET "dram_ras_n" LOC="R2" |IOSTANDARD=LVTTL; | |
|
31 | NET "dram_cas_n" LOC="T4" |IOSTANDARD=LVTTL; | |
|
32 | NET "dram_we_n" LOC="R5" |IOSTANDARD=LVTTL; | |
|
33 | NET "dram_ldqm" LOC="T5" |IOSTANDARD=LVTTL; | |
|
34 | NET "dram_addr<0>" LOC="T15" |IOSTANDARD=LVTTL; | |
|
35 | NET "dram_addr<1>" LOC="R16" |IOSTANDARD=LVTTL; | |
|
36 | NET "dram_addr<2>" LOC="P15" |IOSTANDARD=LVTTL; | |
|
37 | NET "dram_addr<3>" LOC="P16" |IOSTANDARD=LVTTL; | |
|
38 | NET "dram_addr<4>" LOC="N16" |IOSTANDARD=LVTTL; | |
|
39 | NET "dram_addr<5>" LOC="M15" |IOSTANDARD=LVTTL; | |
|
40 | NET "dram_addr<6>" LOC="M16" |IOSTANDARD=LVTTL; | |
|
41 | NET "dram_addr<7>" LOC="L16" |IOSTANDARD=LVTTL; | |
|
42 | NET "dram_addr<8>" LOC="K15" |IOSTANDARD=LVTTL; | |
|
43 | NET "dram_addr<9>" LOC="K16" |IOSTANDARD=LVTTL; | |
|
44 | NET "dram_addr<10>" LOC="R15" |IOSTANDARD=LVTTL; | |
|
45 | NET "dram_addr<11>" LOC="J16" |IOSTANDARD=LVTTL; | |
|
46 | NET "dram_addr<12>" LOC="H15" |IOSTANDARD=LVTTL; | |
|
47 | NET "dram_dq<0>" LOC="T13" |IOSTANDARD=LVTTL; | |
|
48 | NET "dram_dq<1>" LOC="T12" |IOSTANDARD=LVTTL; | |
|
49 | NET "dram_dq<2>" LOC="R12" |IOSTANDARD=LVTTL; | |
|
50 | NET "dram_dq<3>" LOC="T9" |IOSTANDARD=LVTTL; | |
|
51 | NET "dram_dq<4>" LOC="R9" |IOSTANDARD=LVTTL; | |
|
52 | NET "dram_dq<5>" LOC="T7" |IOSTANDARD=LVTTL; | |
|
53 | NET "dram_dq<6>" LOC="R7" |IOSTANDARD=LVTTL; | |
|
54 | NET "dram_dq<7>" LOC="T6" |IOSTANDARD=LVTTL; | |
|
55 | NET "dram_dq<8>" LOC="F16" |IOSTANDARD=LVTTL; | |
|
56 | NET "dram_dq<9>" LOC="E15" |IOSTANDARD=LVTTL; | |
|
57 | NET "dram_dq<10>" LOC="E16" |IOSTANDARD=LVTTL; | |
|
58 | NET "dram_dq<11>" LOC="D16" |IOSTANDARD=LVTTL; | |
|
59 | NET "dram_dq<12>" LOC="B16" |IOSTANDARD=LVTTL; | |
|
60 | NET "dram_dq<13>" LOC="B15" |IOSTANDARD=LVTTL; | |
|
61 | NET "dram_dq<14>" LOC="C16" |IOSTANDARD=LVTTL; | |
|
62 | NET "dram_dq<15>" LOC="C15" |IOSTANDARD=LVTTL; | |
|
63 | #Created by Constraints Editor (xc6slx25-ftg256-3) - 2016/12/08 | |
|
64 | INST "dram_addr(0)" TNM = dram_addr; | |
|
65 | INST "dram_addr(1)" TNM = dram_addr; | |
|
66 | INST "dram_addr(2)" TNM = dram_addr; | |
|
67 | INST "dram_addr(3)" TNM = dram_addr; | |
|
68 | INST "dram_addr(4)" TNM = dram_addr; | |
|
69 | INST "dram_addr(5)" TNM = dram_addr; | |
|
70 | INST "dram_addr(6)" TNM = dram_addr; | |
|
71 | INST "dram_addr(7)" TNM = dram_addr; | |
|
72 | INST "dram_addr(8)" TNM = dram_addr; | |
|
73 | INST "dram_addr(9)" TNM = dram_addr; | |
|
74 | INST "dram_addr(10)" TNM = dram_addr; | |
|
75 | INST "dram_addr(11)" TNM = dram_addr; | |
|
76 | INST "dram_addr(12)" TNM = dram_addr; | |
|
77 | INST "dram_addr(0)" TNM = dram_out; | |
|
78 | INST "dram_addr(1)" TNM = dram_out; | |
|
79 | INST "dram_addr(2)" TNM = dram_out; | |
|
80 | INST "dram_addr(3)" TNM = dram_out; | |
|
81 | INST "dram_addr(4)" TNM = dram_out; | |
|
82 | INST "dram_addr(5)" TNM = dram_out; | |
|
83 | INST "dram_addr(6)" TNM = dram_out; | |
|
84 | INST "dram_addr(7)" TNM = dram_out; | |
|
85 | INST "dram_addr(8)" TNM = dram_out; | |
|
86 | INST "dram_addr(9)" TNM = dram_out; | |
|
87 | INST "dram_addr(10)" TNM = dram_out; | |
|
88 | INST "dram_addr(11)" TNM = dram_out; | |
|
89 | INST "dram_addr(12)" TNM = dram_out; | |
|
90 | INST "dram_ba_0" TNM = dram_out; | |
|
91 | INST "dram_ba_1" TNM = dram_out; | |
|
92 | INST "dram_cas_n" TNM = dram_out; | |
|
93 | INST "dram_cke" TNM = dram_out; | |
|
94 | #INST "dram_clk" TNM = dram_out; | |
|
95 | INST "dram_cs_n" TNM = dram_out; | |
|
96 | INST "dram_dq(0)" TNM = dram_out; | |
|
97 | INST "dram_dq(1)" TNM = dram_out; | |
|
98 | INST "dram_dq(2)" TNM = dram_out; | |
|
99 | INST "dram_dq(3)" TNM = dram_out; | |
|
100 | INST "dram_dq(4)" TNM = dram_out; | |
|
101 | INST "dram_dq(5)" TNM = dram_out; | |
|
102 | INST "dram_dq(6)" TNM = dram_out; | |
|
103 | INST "dram_dq(7)" TNM = dram_out; | |
|
104 | INST "dram_dq(8)" TNM = dram_out; | |
|
105 | INST "dram_dq(9)" TNM = dram_out; | |
|
106 | INST "dram_dq(10)" TNM = dram_out; | |
|
107 | INST "dram_dq(11)" TNM = dram_out; | |
|
108 | INST "dram_dq(12)" TNM = dram_out; | |
|
109 | INST "dram_dq(13)" TNM = dram_out; | |
|
110 | INST "dram_dq(14)" TNM = dram_out; | |
|
111 | INST "dram_dq(15)" TNM = dram_out; | |
|
112 | INST "dram_ldqm" TNM = dram_out; | |
|
113 | INST "dram_ras_n" TNM = dram_out; | |
|
114 | INST "dram_udqm" TNM = dram_out; | |
|
115 | INST "dram_we_n" TNM = dram_out; | |
|
116 | TIMEGRP "dram_out" OFFSET = OUT 12 ns AFTER "CLK50"; | |
|
117 | INST "dram_dq(0)" TNM = dram_in; | |
|
118 | INST "dram_dq(1)" TNM = dram_in; | |
|
119 | INST "dram_dq(2)" TNM = dram_in; | |
|
120 | INST "dram_dq(3)" TNM = dram_in; | |
|
121 | INST "dram_dq(4)" TNM = dram_in; | |
|
122 | INST "dram_dq(5)" TNM = dram_in; | |
|
123 | INST "dram_dq(6)" TNM = dram_in; | |
|
124 | INST "dram_dq(7)" TNM = dram_in; | |
|
125 | INST "dram_dq(8)" TNM = dram_in; | |
|
126 | INST "dram_dq(9)" TNM = dram_in; | |
|
127 | INST "dram_dq(10)" TNM = dram_in; | |
|
128 | INST "dram_dq(11)" TNM = dram_in; | |
|
129 | INST "dram_dq(12)" TNM = dram_in; | |
|
130 | INST "dram_dq(13)" TNM = dram_in; | |
|
131 | INST "dram_dq(14)" TNM = dram_in; | |
|
132 | INST "dram_dq(15)" TNM = dram_in; | |
|
133 | TIMEGRP "dram_in" OFFSET = IN 3 ns BEFORE "CLK50" RISING; | |
|
134 | ||
|
135 | ||
|
136 | NET "spw_rxdp" LOC = "h2";# | IOSTANDARD = LVDS_33; | |
|
137 | NET "spw_rxdn" LOC = "h1";# | IOSTANDARD = LVDS_33; | |
|
138 | NET "spw_rxsp" LOC = "f4";# | IOSTANDARD = LVDS_33; | |
|
139 | NET "spw_rxsn" LOC = "f3";# | IOSTANDARD = LVDS_33; | |
|
140 | NET "spw_txdp" LOC = "e2";# | IOSTANDARD = LVTTL; | |
|
141 | NET "spw_txdn" LOC = "e1";# | IOSTANDARD = LVTTL; | |
|
142 | NET "spw_txsp" LOC = "g3";# | IOSTANDARD = LVTTL; | |
|
143 | NET "spw_txsn" LOC = "g1";# | IOSTANDARD = LVTTL; |
@@ -0,0 +1,77 | |||
|
1 | VHDLIB=../.. | |
|
2 | SELFDIR := $(dir $(lastword $(MAKEFILE_LIST))) | |
|
3 | SCRIPTSDIR=$(VHDLIB)/scripts/ | |
|
4 | GRLIB := $(shell sh $(VHDLIB)/scripts/lpp_relpath.sh) | |
|
5 | TOP=leon3mp | |
|
6 | BOARD=MiniSpartan6p | |
|
7 | DESIGN=leon3-MiniSpartan6p | |
|
8 | include $(VHDLIB)/boards/$(BOARD)/Makefile.inc | |
|
9 | DEVICE=$(PART)-$(PACKAGE)$(SPEED) | |
|
10 | UCF=withSPW.ucf | |
|
11 | UCF_PLANAHEAD=$(UCF) | |
|
12 | QSF=$(GRLIB)/boards/$(BOARD)/$(TOP).qsf | |
|
13 | EFFORT=high | |
|
14 | XSTOPT=-uc leon3mp.xcf | |
|
15 | SYNPOPT="set_option -pipe 1; set_option -retiming 1; set_option -write_apr_constraint 0" | |
|
16 | ||
|
17 | ||
|
18 | VHDLOPTSYNFILES = sdctrl16.vhd config.vhd leon3mp.vhd | |
|
19 | ||
|
20 | VHDLSIMFILES=mt48lc16m16a2.vhd testbench.vhd | |
|
21 | ||
|
22 | SIMTOP=testbench | |
|
23 | SDCFILE=$(GRLIB)/boards/$(BOARD)/default.sdc | |
|
24 | BITGEN=$(VHDLIB)/boards/$(BOARD)/default.ut | |
|
25 | ||
|
26 | TECHLIBS = unisim | |
|
27 | ||
|
28 | LIBSKIP = core1553bbc core1553brm core1553brt gr1553 corePCIF \ | |
|
29 | tmtc openchip hynix ihp gleichmann usbhc fmf ftlib gsi | |
|
30 | ||
|
31 | DIRSKIP = b1553 pcif leon2 leon2ft crypto satcan ddr usb ata i2c \ | |
|
32 | pci grusbhc haps slink ascs can pwm greth coremp7 ac97 atf \ | |
|
33 | grlfpc \ | |
|
34 | ./dsp/lpp_fft_rtax \ | |
|
35 | ./amba_lcd_16x2_ctrlr \ | |
|
36 | ./general_purpose/lpp_AMR \ | |
|
37 | ./general_purpose/lpp_balise \ | |
|
38 | ./general_purpose/lpp_delay \ | |
|
39 | ./lpp_bootloader \ | |
|
40 | ./lpp_sim/CY7C1061DV33 \ | |
|
41 | ./lpp_uart \ | |
|
42 | ./lpp_usb \ | |
|
43 | ./dsp/lpp_fft \ | |
|
44 | ./lpp_leon3_soc \ | |
|
45 | ./lpp_debug_lfr | |
|
46 | ||
|
47 | FILESKIP = i2cmst.vhd \ | |
|
48 | APB_MULTI_DIODE.vhd \ | |
|
49 | APB_MULTI_DIODE.vhd \ | |
|
50 | Top_MatrixSpec.vhd \ | |
|
51 | APB_FFT.vhd \ | |
|
52 | lpp_lfr_ms_FFT.vhd \ | |
|
53 | lpp_lfr_apbreg.vhd \ | |
|
54 | CoreFFT.vhd \ | |
|
55 | lpp_lfr_ms.vhd \ | |
|
56 | lpp_lfr_sim_pkg.vhd \ | |
|
57 | mtie_maps.vhd \ | |
|
58 | ftsrctrlc.vhd \ | |
|
59 | ftsdctrl.vhd \ | |
|
60 | ftsrctrl8.vhd \ | |
|
61 | ftmctrl.vhd \ | |
|
62 | ftsdctrl64.vhd \ | |
|
63 | ftahbram.vhd \ | |
|
64 | ftahbram2.vhd \ | |
|
65 | sramft.vhd \ | |
|
66 | nandfctrlx.vhd | |
|
67 | ||
|
68 | include $(GRLIB)/bin/Makefile | |
|
69 | ||
|
70 | ################## project specific targets ########################## | |
|
71 | ||
|
72 | load-ram: | |
|
73 | xc3sprog -c ftdi -p0 leon3mp.bit | |
|
74 | ||
|
75 | load-flash: | |
|
76 | xc3sprog -c ftdi -p0 $(VHDLIB)/boards/$(BOARD)/bscan_spi_s6lx25_ftg256.bit | |
|
77 | xc3sprog -c ftdi -I leon3mp.bit |
@@ -0,0 +1,66 | |||
|
1 | This LEON3 design is tailored to the Scarab Hardware [MiniSpartan6+](https://www.scarabhardware.com/minispartan6/) board. | |
|
2 | ||
|
3 | Simulation and synthesis | |
|
4 | ------------------------ | |
|
5 | ||
|
6 | This design tries to use as much as possible free (as in freedom) tools and at least free (as in free beer) when impossible. | |
|
7 | ||
|
8 | ||
|
9 | Note that the simulation doesn't work as expected yet. | |
|
10 | ||
|
11 | ||
|
12 | To build the design: | |
|
13 | ```bash | |
|
14 | make ise | |
|
15 | ``` | |
|
16 | ||
|
17 | To load into FPGA RAM: | |
|
18 | ```bash | |
|
19 | make load-ram | |
|
20 | ``` | |
|
21 | ||
|
22 | To load into FPGA Flash: | |
|
23 | ```bash | |
|
24 | make load-flash | |
|
25 | ``` | |
|
26 | ||
|
27 | Design specifics | |
|
28 | ---------------- | |
|
29 | ||
|
30 | * The AHB and processor is clocked from the 50 MHz clock. | |
|
31 | ||
|
32 | * The SDRAM is working with the sdctrl16 memory controller taken from leon3-altera-de2-ep2c35 design. | |
|
33 | ||
|
34 | * The UART DSU interface ie enabled and connected to interface B of ft2232H chip. | |
|
35 | Start GRMON with -uart /dev/ttyUSB1 | |
|
36 | ||
|
37 | * Output from GRMON2 should look similar to this: | |
|
38 | ||
|
39 | ```bash | |
|
40 | GRMON2 LEON debug monitor v2.0.80-beta 64-bit eval version | |
|
41 | ||
|
42 | Copyright (C) 2016 Cobham Gaisler - All rights reserved. | |
|
43 | For latest updates, go to http://www.gaisler.com/ | |
|
44 | Comments or bug-reports to support@gaisler.com | |
|
45 | ||
|
46 | This eval version will expire on 18/04/2017 | |
|
47 | ||
|
48 | using port /dev/ttyUSB1 @ 115200 baud | |
|
49 | GRLIB build version: 4164 | |
|
50 | Detected frequency: 50 MHz | |
|
51 | ||
|
52 | Component Vendor | |
|
53 | LEON3 SPARC V8 Processor Cobham Gaisler | |
|
54 | AHB Debug UART Cobham Gaisler | |
|
55 | AHB/APB Bridge Cobham Gaisler | |
|
56 | LEON3 Debug Support Unit Cobham Gaisler | |
|
57 | PC133 SDRAM Controller Cobham Gaisler | |
|
58 | Multi-processor Interrupt Ctrl. Cobham Gaisler | |
|
59 | Modular Timer Unit Cobham Gaisler | |
|
60 | General Purpose I/O port Cobham Gaisler | |
|
61 | ||
|
62 | Use command 'info sys' to print a detailed report of attached cores | |
|
63 | ||
|
64 | grmon2> | |
|
65 | ||
|
66 | ``` No newline at end of file |
@@ -0,0 +1,11 | |||
|
1 | F0 -> L46P -> DOUT+ -> 9 -> Grey | |
|
2 | F1 -> L46N -> DOUT- -> 5 -> Yellow | |
|
3 | ||
|
4 | F5 -> L40P -> SOUT+ -> 8 -> Violet | |
|
5 | F7 -> L40N -> SOUT- -> 4 -> Orange | |
|
6 | ||
|
7 | F3 -> L53P -> SIN+ -> 2 -> Brown | |
|
8 | F6 -> L53N -> SIN- -> 7 -> Blue | |
|
9 | ||
|
10 | F9 -> L39N -> DIN- -> 6 -> Green | |
|
11 | F10 -> L39P -> DIN+ -> 1 -> Black |
@@ -0,0 +1,162 | |||
|
1 | ||
|
2 | ||
|
3 | ||
|
4 | ----------------------------------------------------------------------------- | |
|
5 | -- LEON3 Demonstration design test bench configuration | |
|
6 | -- Copyright (C) 2009 Aeroflex Gaisler | |
|
7 | ------------------------------------------------------------------------------ | |
|
8 | ||
|
9 | ||
|
10 | library techmap; | |
|
11 | use techmap.gencomp.all; | |
|
12 | ||
|
13 | package config is | |
|
14 | -- Technology and synthesis options | |
|
15 | constant CFG_FABTECH : integer := spartan6; | |
|
16 | constant CFG_MEMTECH : integer := spartan6; | |
|
17 | constant CFG_PADTECH : integer := spartan6; | |
|
18 | constant CFG_TRANSTECH : integer := GTP0; | |
|
19 | constant CFG_NOASYNC : integer := 0; | |
|
20 | constant CFG_SCAN : integer := 0; | |
|
21 | -- Clock generator | |
|
22 | constant CFG_CLKTECH : integer := spartan6; | |
|
23 | constant CFG_CLKMUL : integer := (3); | |
|
24 | constant CFG_CLKDIV : integer := (2); | |
|
25 | constant CFG_OCLKDIV : integer := 1; | |
|
26 | constant CFG_OCLKBDIV : integer := 0; | |
|
27 | constant CFG_OCLKCDIV : integer := 0; | |
|
28 | constant CFG_PCIDLL : integer := 0; | |
|
29 | constant CFG_PCISYSCLK: integer := 0; | |
|
30 | constant CFG_CLK_NOFB : integer := 0; | |
|
31 | -- LEON3 processor core | |
|
32 | constant CFG_LEON3 : integer := 1; | |
|
33 | constant CFG_NCPU : integer := (1); | |
|
34 | constant CFG_NWIN : integer := (8); | |
|
35 | constant CFG_V8 : integer := 2 + 4*0; | |
|
36 | constant CFG_MAC : integer := 0; | |
|
37 | constant CFG_BP : integer := 1; | |
|
38 | constant CFG_SVT : integer := 1; | |
|
39 | constant CFG_RSTADDR : integer := 16#00000#; | |
|
40 | constant CFG_LDDEL : integer := (2); | |
|
41 | constant CFG_NOTAG : integer := 1; | |
|
42 | constant CFG_NWP : integer := (0); | |
|
43 | constant CFG_PWD : integer := 0*2; | |
|
44 | constant CFG_FPU : integer := 0 + 16*0 + 32*0; | |
|
45 | constant CFG_GRFPUSH : integer := 0; | |
|
46 | constant CFG_ICEN : integer := 1; | |
|
47 | constant CFG_ISETS : integer := 1; | |
|
48 | constant CFG_ISETSZ : integer := 8; | |
|
49 | constant CFG_ILINE : integer := 8; | |
|
50 | constant CFG_IREPL : integer := 0; | |
|
51 | constant CFG_ILOCK : integer := 0; | |
|
52 | constant CFG_ILRAMEN : integer := 0; | |
|
53 | constant CFG_ILRAMADDR: integer := 16#8E#; | |
|
54 | constant CFG_ILRAMSZ : integer := 1; | |
|
55 | constant CFG_DCEN : integer := 1; | |
|
56 | constant CFG_DSETS : integer := 1; | |
|
57 | constant CFG_DSETSZ : integer := 8; | |
|
58 | constant CFG_DLINE : integer := 8; | |
|
59 | constant CFG_DREPL : integer := 0; | |
|
60 | constant CFG_DLOCK : integer := 0; | |
|
61 | constant CFG_DSNOOP : integer := 0 + 0*2 + 4*0; | |
|
62 | constant CFG_DFIXED : integer := 16#0#; | |
|
63 | constant CFG_DLRAMEN : integer := 0; | |
|
64 | constant CFG_DLRAMADDR: integer := 16#8F#; | |
|
65 | constant CFG_DLRAMSZ : integer := 1; | |
|
66 | constant CFG_MMUEN : integer := 0; | |
|
67 | constant CFG_ITLBNUM : integer := 8; | |
|
68 | constant CFG_DTLBNUM : integer := 2; | |
|
69 | constant CFG_TLB_TYPE : integer := 1 + 0*2; | |
|
70 | constant CFG_TLB_REP : integer := 1; | |
|
71 | constant CFG_MMU_PAGE : integer := 0; | |
|
72 | constant CFG_DSU : integer := 1; | |
|
73 | constant CFG_ITBSZ : integer := 0 + 64*0; | |
|
74 | constant CFG_ATBSZ : integer := 0; | |
|
75 | constant CFG_AHBPF : integer := 0; | |
|
76 | constant CFG_LEON3FT_EN : integer := 0; | |
|
77 | constant CFG_IUFT_EN : integer := 0; | |
|
78 | constant CFG_FPUFT_EN : integer := 0; | |
|
79 | constant CFG_RF_ERRINJ : integer := 0; | |
|
80 | constant CFG_CACHE_FT_EN : integer := 0; | |
|
81 | constant CFG_CACHE_ERRINJ : integer := 0; | |
|
82 | constant CFG_LEON3_NETLIST: integer := 0; | |
|
83 | constant CFG_DISAS : integer := 0 + 0; | |
|
84 | constant CFG_PCLOW : integer := 2; | |
|
85 | constant CFG_STAT_ENABLE : integer := 0; | |
|
86 | constant CFG_STAT_CNT : integer := 1; | |
|
87 | constant CFG_STAT_NMAX : integer := 0; | |
|
88 | constant CFG_STAT_DSUEN : integer := 0; | |
|
89 | constant CFG_NP_ASI : integer := 0; | |
|
90 | constant CFG_WRPSR : integer := 0; | |
|
91 | constant CFG_ALTWIN : integer := 0; | |
|
92 | constant CFG_REX : integer := 0; | |
|
93 | -- AMBA settings | |
|
94 | constant CFG_DEFMST : integer := (0); | |
|
95 | constant CFG_RROBIN : integer := 1; | |
|
96 | constant CFG_SPLIT : integer := 1; | |
|
97 | constant CFG_FPNPEN : integer := 0; | |
|
98 | constant CFG_AHBIO : integer := 16#FFF#; | |
|
99 | constant CFG_APBADDR : integer := 16#800#; | |
|
100 | constant CFG_AHB_MON : integer := 0; | |
|
101 | constant CFG_AHB_MONERR : integer := 0; | |
|
102 | constant CFG_AHB_MONWAR : integer := 0; | |
|
103 | constant CFG_AHB_DTRACE : integer := 0; | |
|
104 | -- DSU UART | |
|
105 | constant CFG_AHB_UART : integer := 1; | |
|
106 | -- JTAG based DSU interface | |
|
107 | constant CFG_AHB_JTAG : integer := 1; | |
|
108 | -- Xilinx MIG | |
|
109 | constant CFG_MIG_DDR2 : integer := 1; | |
|
110 | constant CFG_MIG_RANKS : integer := (1); | |
|
111 | constant CFG_MIG_COLBITS : integer := (10); | |
|
112 | constant CFG_MIG_ROWBITS : integer := (13); | |
|
113 | constant CFG_MIG_BANKBITS: integer := (2); | |
|
114 | constant CFG_MIG_HMASK : integer := 16#FC0#; | |
|
115 | -- AHB ROM | |
|
116 | constant CFG_AHBROMEN : integer := 1; | |
|
117 | constant CFG_AHBROPIP : integer := 0; | |
|
118 | constant CFG_AHBRODDR : integer := 16#000#; | |
|
119 | constant CFG_ROMADDR : integer := 16#100#; | |
|
120 | constant CFG_ROMMASK : integer := 16#E00# + 16#100#; | |
|
121 | -- AHB RAM | |
|
122 | constant CFG_AHBRAMEN : integer := 1; | |
|
123 | constant CFG_AHBRSZ : integer := 4; | |
|
124 | constant CFG_AHBRADDR : integer := 16#A00#; | |
|
125 | constant CFG_AHBRPIPE : integer := 0; | |
|
126 | -- UART 1 | |
|
127 | constant CFG_UART1_ENABLE : integer := 1; | |
|
128 | constant CFG_UART1_FIFO : integer := 4; | |
|
129 | -- LEON3 interrupt controller | |
|
130 | constant CFG_IRQ3_ENABLE : integer := 1; | |
|
131 | constant CFG_IRQ3_NSEC : integer := 0; | |
|
132 | -- Modular timer | |
|
133 | constant CFG_GPT_ENABLE : integer := 1; | |
|
134 | constant CFG_GPT_NTIM : integer := (2); | |
|
135 | constant CFG_GPT_SW : integer := (8); | |
|
136 | constant CFG_GPT_TW : integer := (32); | |
|
137 | constant CFG_GPT_IRQ : integer := (8); | |
|
138 | constant CFG_GPT_SEPIRQ : integer := 1; | |
|
139 | constant CFG_GPT_WDOGEN : integer := 0; | |
|
140 | constant CFG_GPT_WDOG : integer := 16#0#; | |
|
141 | -- GPIO port | |
|
142 | constant CFG_GRGPIO_ENABLE : integer := 1; | |
|
143 | constant CFG_GRGPIO_IMASK : integer := 16#0000#; | |
|
144 | constant CFG_GRGPIO_WIDTH : integer := 1; | |
|
145 | ||
|
146 | -- SPI controller | |
|
147 | constant CFG_SPICTRL_ENABLE : integer := 1; | |
|
148 | constant CFG_SPICTRL_NUM : integer := (1); | |
|
149 | constant CFG_SPICTRL_SLVS : integer := (1); | |
|
150 | constant CFG_SPICTRL_FIFO : integer := (2); | |
|
151 | constant CFG_SPICTRL_SLVREG : integer := 1; | |
|
152 | constant CFG_SPICTRL_ODMODE : integer := 1; | |
|
153 | constant CFG_SPICTRL_AM : integer := 0; | |
|
154 | constant CFG_SPICTRL_ASEL : integer := 0; | |
|
155 | constant CFG_SPICTRL_TWEN : integer := 0; | |
|
156 | constant CFG_SPICTRL_MAXWLEN : integer := (0); | |
|
157 | constant CFG_SPICTRL_SYNCRAM : integer := 0; | |
|
158 | constant CFG_SPICTRL_FT : integer := 0; | |
|
159 | ||
|
160 | -- GRLIB debugging | |
|
161 | constant CFG_DUART : integer := 0; | |
|
162 | end; |
@@ -0,0 +1,425 | |||
|
1 | ||
|
2 | ||
|
3 | library ieee; | |
|
4 | use ieee.std_logic_1164.all; | |
|
5 | USE IEEE.NUMERIC_STD.ALL; | |
|
6 | library grlib; | |
|
7 | use grlib.amba.all; | |
|
8 | use grlib.stdlib.all; | |
|
9 | use grlib.devices.all; | |
|
10 | library techmap; | |
|
11 | use techmap.gencomp.all; | |
|
12 | use techmap.allclkgen.all; | |
|
13 | library gaisler; | |
|
14 | use gaisler.memctrl.all; | |
|
15 | use gaisler.leon3.all; | |
|
16 | use gaisler.uart.all; | |
|
17 | use gaisler.misc.all; | |
|
18 | --pragma translate_off | |
|
19 | use gaisler.sim.all; | |
|
20 | --pragma translate_on | |
|
21 | library opencores; | |
|
22 | use opencores.spwpkg.all; | |
|
23 | use opencores.spwambapkg.all; | |
|
24 | LIBRARY lpp; | |
|
25 | USE lpp.general_purpose.ALL; | |
|
26 | use lpp.lpp_amba.all; | |
|
27 | USE lpp.lpp_lfr_management.ALL; | |
|
28 | ||
|
29 | use work.config.all; | |
|
30 | ||
|
31 | library unisim; | |
|
32 | use unisim.vcomponents.all; | |
|
33 | ||
|
34 | entity leon3mp is | |
|
35 | generic ( | |
|
36 | fabtech : integer := CFG_FABTECH; | |
|
37 | memtech : integer := CFG_MEMTECH; | |
|
38 | padtech : integer := CFG_PADTECH; | |
|
39 | clktech : integer := CFG_CLKTECH; | |
|
40 | disas : integer := CFG_DISAS; -- Enable disassembly to console | |
|
41 | dbguart : integer := CFG_DUART; -- Print UART on console | |
|
42 | pclow : integer := CFG_PCLOW | |
|
43 | ); | |
|
44 | port ( | |
|
45 | CLK50 : in std_logic; | |
|
46 | LEDS : inout std_logic_vector(7 downto 0); | |
|
47 | SW : in std_logic_vector(4 downto 1); | |
|
48 | dram_addr : out std_logic_vector(12 downto 0); | |
|
49 | dram_ba_0 : out std_logic; | |
|
50 | dram_ba_1 : out std_logic; | |
|
51 | dram_dq : inout std_logic_vector(15 downto 0); | |
|
52 | ||
|
53 | dram_clk : out std_logic; | |
|
54 | dram_cke : out std_logic; | |
|
55 | dram_cs_n : out std_logic; | |
|
56 | dram_we_n : out std_logic; -- sdram write enable | |
|
57 | dram_ras_n : out std_logic; -- sdram ras | |
|
58 | dram_cas_n : out std_logic; -- sdram cas | |
|
59 | dram_ldqm : out std_logic; -- sdram ldqm | |
|
60 | dram_udqm : out std_logic; -- sdram udqm | |
|
61 | uart_txd : out std_logic; -- DSU tx data | |
|
62 | uart_rxd : in std_logic; -- DSU rx data | |
|
63 | ||
|
64 | spw_rxdp : in std_logic; | |
|
65 | spw_rxdn : in std_logic; | |
|
66 | spw_rxsp : in std_logic; | |
|
67 | spw_rxsn : in std_logic; | |
|
68 | spw_txdp : out std_logic; | |
|
69 | spw_txdn : out std_logic; | |
|
70 | spw_txsp : out std_logic; | |
|
71 | spw_txsn : out std_logic | |
|
72 | ); | |
|
73 | end; | |
|
74 | ||
|
75 | architecture rtl of leon3mp is | |
|
76 | signal resetn : std_logic; | |
|
77 | signal clkm, rstn, rstraw, rst : std_logic; | |
|
78 | signal clk_50 : std_logic := '0'; | |
|
79 | signal clkm_inv : std_logic := '0'; | |
|
80 | ||
|
81 | signal cptr : std_logic_vector(29 downto 0); | |
|
82 | constant BOARD_FREQ : integer := 25000; -- CLK input frequency in KHz | |
|
83 | constant CPU_FREQ : integer := BOARD_FREQ * CFG_CLKMUL / CFG_CLKDIV; -- cpu frequency in KHz | |
|
84 | signal sdi : sdctrl_in_type; | |
|
85 | signal sdo : sdctrl_out_type; | |
|
86 | ||
|
87 | --AMBA bus standard interface signals-- | |
|
88 | signal apbi : apb_slv_in_type; | |
|
89 | signal apbo : apb_slv_out_vector := (others => apb_none); | |
|
90 | signal ahbsi : ahb_slv_in_type; | |
|
91 | signal ahbso : ahb_slv_out_vector := (others => ahbs_none); | |
|
92 | signal ahbmi : ahb_mst_in_type; | |
|
93 | signal ahbmo : ahb_mst_out_vector := (others => ahbm_none); | |
|
94 | ||
|
95 | signal cgi : clkgen_in_type; | |
|
96 | signal cgo : clkgen_out_type; | |
|
97 | ||
|
98 | signal dui : uart_in_type; | |
|
99 | signal duo : uart_out_type; | |
|
100 | ||
|
101 | signal irqi : irq_in_vector(0 to CFG_NCPU-1); | |
|
102 | signal irqo : irq_out_vector(0 to CFG_NCPU-1); | |
|
103 | ||
|
104 | signal dbgi : l3_debug_in_vector(0 to CFG_NCPU-1); | |
|
105 | signal dbgo : l3_debug_out_vector(0 to CFG_NCPU-1); | |
|
106 | ||
|
107 | signal dsui : dsu_in_type; | |
|
108 | signal dsuo : dsu_out_type; | |
|
109 | ||
|
110 | ||
|
111 | signal gpti : gptimer_in_type; | |
|
112 | signal gpto : gptimer_out_type; | |
|
113 | ||
|
114 | signal gpioi_0 : gpio_in_type; | |
|
115 | signal gpioo_0 : gpio_out_type; | |
|
116 | ||
|
117 | signal dsubren : std_logic :='0'; | |
|
118 | ||
|
119 | signal spw_di: std_logic; | |
|
120 | signal spw_si: std_logic; | |
|
121 | signal spw_do: std_logic; | |
|
122 | signal spw_so: std_logic; | |
|
123 | signal spw_tick_in: std_logic; | |
|
124 | signal spw_tick_out: std_logic; | |
|
125 | ||
|
126 | -- AdvancedTrigger | |
|
127 | SIGNAL Trigger : STD_LOGIC; | |
|
128 | SIGNAL coarse_time : STD_LOGIC_VECTOR(31 DOWNTO 0); | |
|
129 | SIGNAL fine_time : STD_LOGIC_VECTOR(15 DOWNTO 0); | |
|
130 | ||
|
131 | component sdctrl16 | |
|
132 | generic ( | |
|
133 | hindex : integer := 0; | |
|
134 | haddr : integer := 0; | |
|
135 | hmask : integer := 16#f00#; | |
|
136 | ioaddr : integer := 16#000#; | |
|
137 | iomask : integer := 16#fff#; | |
|
138 | wprot : integer := 0; | |
|
139 | invclk : integer := 0; | |
|
140 | fast : integer := 0; | |
|
141 | pwron : integer := 0; | |
|
142 | sdbits : integer := 16; | |
|
143 | oepol : integer := 0; | |
|
144 | pageburst : integer := 0; | |
|
145 | mobile : integer := 0 | |
|
146 | ); | |
|
147 | port ( | |
|
148 | rst : in std_ulogic; | |
|
149 | clk : in std_ulogic; | |
|
150 | ahbsi : in ahb_slv_in_type; | |
|
151 | ahbso : out ahb_slv_out_type; | |
|
152 | sdi : in sdctrl_in_type; | |
|
153 | sdo : out sdctrl_out_type | |
|
154 | ); | |
|
155 | end component; | |
|
156 | ||
|
157 | begin | |
|
158 | resetn <= SW(1); | |
|
159 | ||
|
160 | clk_pad : clkpad generic map (tech => padtech) port map (CLK50, clk_50); | |
|
161 | process(clk_50) | |
|
162 | begin | |
|
163 | if clk_50'event and clk_50='1' then | |
|
164 | clkm <= not clkm; | |
|
165 | end if; | |
|
166 | end process; | |
|
167 | clkm_inv <= not clkm; | |
|
168 | ||
|
169 | resetn_pad : inpad generic map (tech => padtech) port map (resetn, rst); | |
|
170 | rst0 : rstgen -- reset generator (reset is active LOW) | |
|
171 | port map (rst, clkm, '1', rstn, rstraw); | |
|
172 | ||
|
173 | ||
|
174 | ---------------------------------------------------------------------- | |
|
175 | --- AHB CONTROLLER -------------------------------------------------- | |
|
176 | ---------------------------------------------------------------------- | |
|
177 | ||
|
178 | ahb0 : ahbctrl -- AHB arbiter/multiplexer | |
|
179 | generic map (defmast => CFG_DEFMST, split => CFG_SPLIT, | |
|
180 | rrobin => CFG_RROBIN, ioaddr => CFG_AHBIO, | |
|
181 | nahbm => CFG_NCPU+CFG_AHB_UART+1, nahbs => 8) | |
|
182 | ||
|
183 | port map (rstn, clkm, ahbmi, ahbmo, ahbsi, ahbso); | |
|
184 | ||
|
185 | ---------------------------------------------------------------------- | |
|
186 | ----- LEON3 processor and DSU --------------------------------------- | |
|
187 | ---------------------------------------------------------------------- | |
|
188 | ||
|
189 | cpu : for i in 0 to CFG_NCPU-1 generate | |
|
190 | nosh : if CFG_GRFPUSH = 0 generate | |
|
191 | u0 : leon3s -- LEON3 processor | |
|
192 | generic map (i, fabtech, memtech, CFG_NWIN, CFG_DSU, CFG_FPU*(1-CFG_GRFPUSH), CFG_V8, | |
|
193 | 0, CFG_MAC, pclow, CFG_NOTAG, CFG_NWP, CFG_ICEN, CFG_IREPL, CFG_ISETS, CFG_ILINE, | |
|
194 | CFG_ISETSZ, CFG_ILOCK, CFG_DCEN, CFG_DREPL, CFG_DSETS, CFG_DLINE, CFG_DSETSZ, | |
|
195 | CFG_DLOCK, CFG_DSNOOP, CFG_ILRAMEN, CFG_ILRAMSZ, CFG_ILRAMADDR, CFG_DLRAMEN, | |
|
196 | CFG_DLRAMSZ, CFG_DLRAMADDR, CFG_MMUEN, CFG_ITLBNUM, CFG_DTLBNUM, CFG_TLB_TYPE, CFG_TLB_REP, | |
|
197 | CFG_LDDEL, disas, CFG_ITBSZ, CFG_PWD, CFG_SVT, CFG_RSTADDR, CFG_NCPU-1, | |
|
198 | 0, 0, CFG_MMU_PAGE, CFG_BP, CFG_NP_ASI, CFG_WRPSR) | |
|
199 | port map (clkm, rstn, ahbmi, ahbmo(i), ahbsi, ahbso, | |
|
200 | irqi(i), irqo(i), dbgi(i), dbgo(i)); | |
|
201 | end generate; | |
|
202 | end generate; | |
|
203 | ||
|
204 | --ledr[0] lit when leon 3 debugvector signals error | |
|
205 | dsugen : if CFG_DSU = 1 generate | |
|
206 | dsu0 : dsu3 -- LEON3 Debug Support Unit (slave) | |
|
207 | generic map (hindex => 2, haddr => 16#900#, hmask => 16#F00#, | |
|
208 | ncpu => CFG_NCPU, tbits => 30, tech => memtech, irq => 0, kbytes => CFG_ATBSZ) | |
|
209 | port map (rstn, clkm, ahbmi, ahbsi, ahbso(2), dbgo, dbgi, dsui, dsuo); | |
|
210 | dsui.enable <= '1'; | |
|
211 | ||
|
212 | end generate; | |
|
213 | nodsu : if CFG_DSU = 0 generate | |
|
214 | ahbso(2) <= ahbs_none; dsuo.tstop <= '0'; dsuo.active <= '0'; --no timer freeze, no light. | |
|
215 | end generate; | |
|
216 | ||
|
217 | dcomgen : if CFG_AHB_UART = 1 generate | |
|
218 | dcom0: ahbuart -- Debug UART | |
|
219 | generic map (hindex => CFG_NCPU, pindex => 7, paddr => 7) | |
|
220 | port map (rstn, clkm, dui, duo, apbi, apbo(7), ahbmi, ahbmo(CFG_NCPU)); | |
|
221 | end generate; | |
|
222 | uart_txd <= duo.txd; | |
|
223 | dui.rxd <= uart_rxd; | |
|
224 | ||
|
225 | ||
|
226 | ---------------------------------------------------------------------- | |
|
227 | --- Memory controllers ---------------------------------------------- | |
|
228 | ---------------------------------------------------------------------- | |
|
229 | ||
|
230 | ||
|
231 | sdc : sdctrl16 generic map (hindex => 3, haddr => 16#400#, hmask => 16#FE0#, -- hmask => 16#C00#, | |
|
232 | ioaddr => 1, fast => 0, pwron => 0, invclk => 0, | |
|
233 | sdbits => 16, pageburst => 2) | |
|
234 | port map (rstn, clkm, ahbsi, ahbso(3), sdi, sdo); | |
|
235 | sa_pad : outpadv generic map (width => 13, tech => padtech) | |
|
236 | port map (dram_addr, sdo.address(14 downto 2)); | |
|
237 | ba0_pad : outpad generic map (tech => padtech) | |
|
238 | port map (dram_ba_0, sdo.address(15)); | |
|
239 | ba1_pad : outpad generic map (tech => padtech) | |
|
240 | port map (dram_ba_1, sdo.address(16)); | |
|
241 | sd_pad : iopadvv generic map (width => 16, tech => padtech) | |
|
242 | port map (dram_dq(15 downto 0), sdo.data(15 downto 0), sdo.vbdrive(15 downto 0), sdi.data(15 downto 0)); | |
|
243 | sdcke_pad : outpad generic map (tech => padtech) | |
|
244 | port map (dram_cke, sdo.sdcke(0)); | |
|
245 | sdwen_pad : outpad generic map (tech => padtech) | |
|
246 | port map (dram_we_n, sdo.sdwen); | |
|
247 | sdcsn_pad : outpad generic map (tech => padtech) | |
|
248 | port map (dram_cs_n, sdo.sdcsn(0)); | |
|
249 | sdras_pad : outpad generic map (tech => padtech) | |
|
250 | port map (dram_ras_n, sdo.rasn); | |
|
251 | sdcas_pad : outpad generic map (tech => padtech) | |
|
252 | port map (dram_cas_n, sdo.casn); | |
|
253 | sdldqm_pad : outpad generic map (tech => padtech) | |
|
254 | port map (dram_ldqm, sdo.dqm(0) ); | |
|
255 | sdudqm_pad : outpad generic map (tech => padtech) | |
|
256 | port map (dram_udqm, sdo.dqm(1)); | |
|
257 | dram_clk_pad : outpad generic map (tech => padtech) | |
|
258 | port map (dram_clk, clkm_inv); | |
|
259 | ||
|
260 | ---------------------------------------------------------------------- | |
|
261 | --- APB Bridge and various periherals ------------------------------- | |
|
262 | ---------------------------------------------------------------------- | |
|
263 | ||
|
264 | apb0 : apbctrl -- AHB/APB bridge | |
|
265 | generic map (hindex => 1, haddr => CFG_APBADDR) | |
|
266 | port map (rstn, clkm, ahbsi, ahbso(1), apbi, apbo ); | |
|
267 | ||
|
268 | ---------------------------------------------------------------------------------------- | |
|
269 | ||
|
270 | irqctrl : if CFG_IRQ3_ENABLE /= 0 generate | |
|
271 | irqctrl0 : irqmp -- interrupt controller | |
|
272 | generic map (pindex => 2, paddr => 2, ncpu => CFG_NCPU) | |
|
273 | port map (rstn, clkm, apbi, apbo(2), irqo, irqi); | |
|
274 | end generate; | |
|
275 | irq3 : if CFG_IRQ3_ENABLE = 0 generate | |
|
276 | x : for i in 0 to CFG_NCPU-1 generate irqi(i).irl <= "0000"; end generate; | |
|
277 | apbo(2) <= apb_none; | |
|
278 | end generate; | |
|
279 | ||
|
280 | --Timer unit, generates interrupts when a timer underflow. | |
|
281 | gpt : if CFG_GPT_ENABLE /= 0 generate | |
|
282 | timer0 : gptimer -- timer unit | |
|
283 | generic map (pindex => 3, paddr => 3, pirq => CFG_GPT_IRQ, | |
|
284 | sepirq => CFG_GPT_SEPIRQ, sbits => CFG_GPT_SW, ntimers => CFG_GPT_NTIM, | |
|
285 | nbits => CFG_GPT_TW) | |
|
286 | port map (rstn, clkm, apbi, apbo(3), gpti, gpto); | |
|
287 | gpti <= gpti_dhalt_drive(dsuo.tstop); | |
|
288 | end generate; | |
|
289 | notim : if CFG_GPT_ENABLE = 0 generate apbo(3) <= apb_none; end generate; | |
|
290 | ||
|
291 | gpio0 : if CFG_GRGPIO_ENABLE /= 0 generate -- GR GPIO0 unit | |
|
292 | grgpio0: grgpio | |
|
293 | generic map( pindex => 9, paddr => 9, imask => CFG_GRGPIO_IMASK, nbits => 4) | |
|
294 | port map( rstn, clkm, apbi, apbo(9), gpioi_0, gpioo_0); | |
|
295 | pio_pads : for i in 0 to 3 generate | |
|
296 | pio_pad : iopad generic map (tech => padtech) | |
|
297 | port map (LEDS(i), gpioo_0.dout(i), gpioo_0.oen(i), gpioi_0.din(i)); | |
|
298 | end generate; | |
|
299 | end generate; | |
|
300 | nogpio0: if CFG_GRGPIO_ENABLE = 0 generate apbo(9) <= apb_none; end generate; | |
|
301 | ||
|
302 | ||
|
303 | ------------------------------------------------------------------------------- | |
|
304 | -- APB_LFR_MANAGEMENT --------------------------------------------------------- | |
|
305 | ------------------------------------------------------------------------------- | |
|
306 | apb_lfr_management_1 : apb_lfr_management | |
|
307 | GENERIC MAP ( | |
|
308 | tech => fabtech, | |
|
309 | pindex => 6, | |
|
310 | paddr => 6, | |
|
311 | pmask => 16#fff#, | |
|
312 | NB_SECOND_DESYNC => 60) -- 60 secondes of desynchronization before CoarseTime's MSB is Set | |
|
313 | PORT MAP ( | |
|
314 | clk25MHz => clkm, | |
|
315 | resetn_25MHz => rstn, | |
|
316 | grspw_tick => spw_tick_out, | |
|
317 | apbi => apbi, | |
|
318 | apbo => apbo(6), | |
|
319 | HK_sample => X"0000", | |
|
320 | HK_val => '0', | |
|
321 | HK_sel => OPEN, | |
|
322 | DAC_SDO => OPEN, | |
|
323 | DAC_SCK => OPEN, | |
|
324 | DAC_SYNC => OPEN, | |
|
325 | DAC_CAL_EN => OPEN, | |
|
326 | coarse_time => coarse_time, | |
|
327 | fine_time => fine_time, | |
|
328 | LFR_soft_rstn => OPEN | |
|
329 | ); | |
|
330 | ||
|
331 | ---------------------------------------------------------------------- | |
|
332 | --- APB_ADVANCED_TRIGGER ----------------------------------------------------------- | |
|
333 | ---------------------------------------------------------------------- | |
|
334 | advtrig0: APB_ADVANCED_TRIGGER | |
|
335 | generic map( | |
|
336 | pindex => 5, | |
|
337 | paddr => 5) | |
|
338 | port map( | |
|
339 | rstn => rstn, | |
|
340 | clk => clkm, | |
|
341 | apbi => apbi, | |
|
342 | apbo => apbo(5), | |
|
343 | ||
|
344 | SPW_Tickout => spw_tick_out, | |
|
345 | CoarseTime => coarse_time, | |
|
346 | FineTime => fine_time, | |
|
347 | ||
|
348 | Trigger => Trigger | |
|
349 | ); | |
|
350 | ||
|
351 | ||
|
352 | DISCO1_TRIG1_PAD : outpad GENERIC MAP (tech => inferred) | |
|
353 | PORT MAP (LEDS(4), Trigger); | |
|
354 | DISCO2_TRIG1_PAD : outpad GENERIC MAP (tech => inferred) | |
|
355 | PORT MAP (LEDS(5), Trigger); | |
|
356 | DISCO3_TRIG1_PAD : outpad GENERIC MAP (tech => inferred) | |
|
357 | PORT MAP (LEDS(6), Trigger); | |
|
358 | DISCO4_TRIG1_PAD : outpad GENERIC MAP (tech => inferred) | |
|
359 | PORT MAP (LEDS(7), Trigger); | |
|
360 | ||
|
361 | ----------------------------------------------------------------------- | |
|
362 | --- SpaceWire Light -------------------------------------------------- | |
|
363 | ----------------------------------------------------------------------- | |
|
364 | ||
|
365 | spw0: spwamba | |
|
366 | generic map ( | |
|
367 | tech => memtech, | |
|
368 | hindex => 2, | |
|
369 | pindex => 10, | |
|
370 | paddr => 10, | |
|
371 | pirq => 10, | |
|
372 | sysfreq => 25.0e6, | |
|
373 | txclkfreq => 50.0e6, | |
|
374 | rximpl => impl_fast, | |
|
375 | rxchunk => 1, | |
|
376 | tximpl => impl_fast, | |
|
377 | timecodegen => true, | |
|
378 | rxfifosize => 11, | |
|
379 | txfifosize => 11, | |
|
380 | desctablesize => 10, | |
|
381 | maxburst => 3 ) | |
|
382 | port map ( | |
|
383 | clk => clkm, | |
|
384 | rxclk => clk_50, | |
|
385 | txclk => clk_50, | |
|
386 | rstn => rstn, | |
|
387 | apbi => apbi, | |
|
388 | apbo => apbo(10), | |
|
389 | ahbi => ahbmi, | |
|
390 | ahbo => ahbmo(2), | |
|
391 | tick_in => spw_tick_in, | |
|
392 | tick_out => spw_tick_out, | |
|
393 | spw_di => spw_di, | |
|
394 | spw_si => spw_si, | |
|
395 | spw_do => spw_do, | |
|
396 | spw_so => spw_so ); | |
|
397 | ||
|
398 | spw_tick_in <= gpto.tick(2) when CFG_GPT_ENABLE /= 0 else '0'; | |
|
399 | ||
|
400 | spw_rxd_pad: inpad_ds | |
|
401 | generic map (padtech, lvds, x33v) | |
|
402 | port map (spw_rxdp, spw_rxdn, spw_di); | |
|
403 | spw_rxs_pad: inpad_ds | |
|
404 | generic map (padtech, lvds, x33v) | |
|
405 | port map (spw_rxsp, spw_rxsn, spw_si); | |
|
406 | -- spw_txd_pad: outpad_ds | |
|
407 | -- generic map (padtech, lvds, x33v) | |
|
408 | -- port map (spw_txdp, spw_txdn, spw_do, '0'); | |
|
409 | -- spw_txs_pad: outpad_ds | |
|
410 | -- generic map (padtech, lvds, x33v) | |
|
411 | -- port map (spw_txsp, spw_txsn, spw_so, '0'); | |
|
412 | ||
|
413 | ||
|
414 | spw_txdp_pad : outpad generic map (tech => padtech) | |
|
415 | port map (spw_txdp, spw_do); | |
|
416 | spw_txdn_pad : outpad generic map (tech => padtech) | |
|
417 | port map (spw_txdn, not spw_do); | |
|
418 | ||
|
419 | spw_txsp_pad : outpad generic map (tech => padtech) | |
|
420 | port map (spw_txsp, spw_so); | |
|
421 | spw_txsn_pad : outpad generic map (tech => padtech) | |
|
422 | port map (spw_txsn, not spw_so); | |
|
423 | ||
|
424 | end rtl; | |
|
425 |
This diff has been collapsed as it changes many lines, (1550 lines changed) Show them Hide them | |||
@@ -0,0 +1,1550 | |||
|
1 | ||
|
2 | --***************************************************************************** | |
|
3 | -- | |
|
4 | -- Micron Semiconductor Products, Inc. | |
|
5 | -- | |
|
6 | -- Copyright 1997, Micron Semiconductor Products, Inc. | |
|
7 | -- All rights reserved. | |
|
8 | -- | |
|
9 | --***************************************************************************** | |
|
10 | ||
|
11 | -- pragma translate_off | |
|
12 | ||
|
13 | library ieee; | |
|
14 | use ieee.std_logic_1164.ALL; | |
|
15 | use std.textio.all; | |
|
16 | ||
|
17 | PACKAGE mti_pkg IS | |
|
18 | ||
|
19 | FUNCTION To_StdLogic (s : BIT) RETURN STD_LOGIC; | |
|
20 | FUNCTION TO_INTEGER (input : STD_LOGIC) RETURN INTEGER; | |
|
21 | FUNCTION TO_INTEGER (input : BIT_VECTOR) RETURN INTEGER; | |
|
22 | FUNCTION TO_INTEGER (input : STD_LOGIC_VECTOR) RETURN INTEGER; | |
|
23 | PROCEDURE TO_BITVECTOR (VARIABLE input : IN INTEGER; VARIABLE output : OUT BIT_VECTOR); | |
|
24 | ||
|
25 | ||
|
26 | END mti_pkg; | |
|
27 | ||
|
28 | PACKAGE BODY mti_pkg IS | |
|
29 | ||
|
30 | -- Convert BIT to STD_LOGIC | |
|
31 | FUNCTION To_StdLogic (s : BIT) RETURN STD_LOGIC IS | |
|
32 | BEGIN | |
|
33 | CASE s IS | |
|
34 | WHEN '0' => RETURN ('0'); | |
|
35 | WHEN '1' => RETURN ('1'); | |
|
36 | WHEN OTHERS => RETURN ('0'); | |
|
37 | END CASE; | |
|
38 | END; | |
|
39 | ||
|
40 | -- Convert STD_LOGIC to INTEGER | |
|
41 | FUNCTION TO_INTEGER (input : STD_LOGIC) RETURN INTEGER IS | |
|
42 | VARIABLE result : INTEGER := 0; | |
|
43 | VARIABLE weight : INTEGER := 1; | |
|
44 | BEGIN | |
|
45 | IF input = '1' THEN | |
|
46 | result := weight; | |
|
47 | ELSE | |
|
48 | result := 0; -- if unknowns, default to logic 0 | |
|
49 | END IF; | |
|
50 | RETURN result; | |
|
51 | END TO_INTEGER; | |
|
52 | ||
|
53 | -- Convert BIT_VECTOR to INTEGER | |
|
54 | FUNCTION TO_INTEGER (input : BIT_VECTOR) RETURN INTEGER IS | |
|
55 | VARIABLE result : INTEGER := 0; | |
|
56 | VARIABLE weight : INTEGER := 1; | |
|
57 | BEGIN | |
|
58 | FOR i IN input'LOW TO input'HIGH LOOP | |
|
59 | IF input(i) = '1' THEN | |
|
60 | result := result + weight; | |
|
61 | ELSE | |
|
62 | result := result + 0; -- if unknowns, default to logic 0 | |
|
63 | END IF; | |
|
64 | weight := weight * 2; | |
|
65 | END LOOP; | |
|
66 | RETURN result; | |
|
67 | END TO_INTEGER; | |
|
68 | ||
|
69 | -- Convert STD_LOGIC_VECTOR to INTEGER | |
|
70 | FUNCTION TO_INTEGER (input : STD_LOGIC_VECTOR) RETURN INTEGER IS | |
|
71 | VARIABLE result : INTEGER := 0; | |
|
72 | VARIABLE weight : INTEGER := 1; | |
|
73 | BEGIN | |
|
74 | FOR i IN input'LOW TO input'HIGH LOOP | |
|
75 | IF input(i) = '1' THEN | |
|
76 | result := result + weight; | |
|
77 | ELSE | |
|
78 | result := result + 0; -- if unknowns, default to logic 0 | |
|
79 | END IF; | |
|
80 | weight := weight * 2; | |
|
81 | END LOOP; | |
|
82 | RETURN result; | |
|
83 | END TO_INTEGER; | |
|
84 | ||
|
85 | -- Conver INTEGER to BIT_VECTOR | |
|
86 | PROCEDURE TO_BITVECTOR (VARIABLE input : IN INTEGER; VARIABLE output : OUT BIT_VECTOR) IS | |
|
87 | VARIABLE work,offset,outputlen,j : INTEGER := 0; | |
|
88 | BEGIN | |
|
89 | --length of vector | |
|
90 | IF output'LENGTH > 32 THEN --' | |
|
91 | outputlen := 32; | |
|
92 | offset := output'LENGTH - 32; --' | |
|
93 | IF input >= 0 THEN | |
|
94 | FOR i IN offset-1 DOWNTO 0 LOOP | |
|
95 | output(output'HIGH - i) := '0'; --' | |
|
96 | END LOOP; | |
|
97 | ELSE | |
|
98 | FOR i IN offset-1 DOWNTO 0 LOOP | |
|
99 | output(output'HIGH - i) := '1'; --' | |
|
100 | END LOOP; | |
|
101 | END IF; | |
|
102 | ELSE | |
|
103 | outputlen := output'LENGTH; --' | |
|
104 | END IF; | |
|
105 | --positive value | |
|
106 | IF (input >= 0) THEN | |
|
107 | work := input; | |
|
108 | j := outputlen - 1; | |
|
109 | FOR i IN 1 to 32 LOOP | |
|
110 | IF j >= 0 then | |
|
111 | IF (work MOD 2) = 0 THEN | |
|
112 | output(output'HIGH-j-offset) := '0'; --' | |
|
113 | ELSE | |
|
114 | output(output'HIGH-j-offset) := '1'; --' | |
|
115 | END IF; | |
|
116 | END IF; | |
|
117 | work := work / 2; | |
|
118 | j := j - 1; | |
|
119 | END LOOP; | |
|
120 | IF outputlen = 32 THEN | |
|
121 | output(output'HIGH) := '0'; --' | |
|
122 | END IF; | |
|
123 | --negative value | |
|
124 | ELSE | |
|
125 | work := (-input) - 1; | |
|
126 | j := outputlen - 1; | |
|
127 | FOR i IN 1 TO 32 LOOP | |
|
128 | IF j>= 0 THEN | |
|
129 | IF (work MOD 2) = 0 THEN | |
|
130 | output(output'HIGH-j-offset) := '1'; --' | |
|
131 | ELSE | |
|
132 | output(output'HIGH-j-offset) := '0'; --' | |
|
133 | END IF; | |
|
134 | END IF; | |
|
135 | work := work / 2; | |
|
136 | j := j - 1; | |
|
137 | END LOOP; | |
|
138 | IF outputlen = 32 THEN | |
|
139 | output(output'HIGH) := '1'; --' | |
|
140 | END IF; | |
|
141 | END IF; | |
|
142 | END TO_BITVECTOR; | |
|
143 | ||
|
144 | END mti_pkg; | |
|
145 | ||
|
146 | ----------------------------------------------------------------------------------------- | |
|
147 | -- | |
|
148 | -- File Name: MT48LC16M16A2.VHD | |
|
149 | -- Version: 0.0g | |
|
150 | -- Date: June 29th, 2000 | |
|
151 | -- Model: Behavioral | |
|
152 | -- Simulator: Model Technology (PC version 5.3 PE) | |
|
153 | -- | |
|
154 | -- Dependencies: None | |
|
155 | -- | |
|
156 | -- Author: Son P. Huynh | |
|
157 | -- Email: sphuynh@micron.com | |
|
158 | -- Phone: (208) 368-3825 | |
|
159 | -- Company: Micron Technology, Inc. | |
|
160 | -- Part Number: MT48LC16M16A2 (4Mb x 16 x 4 Banks) | |
|
161 | -- | |
|
162 | -- Description: Micron 256Mb SDRAM | |
|
163 | -- | |
|
164 | -- Limitation: - Doesn't check for 4096-cycle refresh --' | |
|
165 | -- | |
|
166 | -- Note: - Set simulator resolution to "ps" accuracy | |
|
167 | -- | |
|
168 | -- Disclaimer: THESE DESIGNS ARE PROVIDED "AS IS" WITH NO WARRANTY | |
|
169 | -- WHATSOEVER AND MICRON SPECIFICALLY DISCLAIMS ANY | |
|
170 | -- IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR | |
|
171 | -- A PARTICULAR PURPOSE, OR AGAINST INFRINGEMENT. | |
|
172 | -- | |
|
173 | -- Copyright (c) 1998 Micron Semiconductor Products, Inc. | |
|
174 | -- All rights researved | |
|
175 | -- | |
|
176 | -- Rev Author Phone Date Changes | |
|
177 | -- ---- ---------------------------- ---------- ------------------------------------- | |
|
178 | -- 0.0g Son Huynh 208-368-3825 06/29/2000 Add Load/Dump memory array | |
|
179 | -- Micron Technology Inc. Modify tWR + tRAS timing check | |
|
180 | -- | |
|
181 | -- 0.0f Son Huynh 208-368-3825 07/08/1999 Fix tWR = 1 Clk + 7.5 ns (Auto) | |
|
182 | -- Micron Technology Inc. Fix tWR = 15 ns (Manual) | |
|
183 | -- Fix tRP (Autoprecharge to AutoRefresh) | |
|
184 | -- | |
|
185 | -- 0.0c Son P. Huynh 208-368-3825 04/08/1999 Fix tWR + tRP in Write with AP | |
|
186 | -- Micron Technology Inc. Fix tRC check in Load Mode Register | |
|
187 | -- | |
|
188 | -- 0.0b Son P. Huynh 208-368-3825 01/06/1998 Derive from 64Mb SDRAM model | |
|
189 | -- Micron Technology Inc. | |
|
190 | -- | |
|
191 | ----------------------------------------------------------------------------------------- | |
|
192 | ||
|
193 | LIBRARY STD; | |
|
194 | USE STD.TEXTIO.ALL; | |
|
195 | LIBRARY IEEE; | |
|
196 | USE IEEE.STD_LOGIC_1164.ALL; | |
|
197 | LIBRARY WORK; | |
|
198 | USE WORK.MTI_PKG.ALL; | |
|
199 | use std.textio.all; | |
|
200 | ||
|
201 | library grlib; | |
|
202 | use grlib.stdlib.all; | |
|
203 | use grlib.stdio.all; | |
|
204 | ||
|
205 | ENTITY mt48lc16m16a2 IS | |
|
206 | GENERIC ( | |
|
207 | -- Timing Parameters for -75 (PC133) and CAS Latency = 2 | |
|
208 | tAC : TIME := 6.0 ns; | |
|
209 | tHZ : TIME := 7.0 ns; | |
|
210 | tOH : TIME := 2.7 ns; | |
|
211 | tMRD : INTEGER := 2; -- 2 Clk Cycles | |
|
212 | tRAS : TIME := 44.0 ns; | |
|
213 | tRC : TIME := 66.0 ns; | |
|
214 | tRCD : TIME := 20.0 ns; | |
|
215 | tRP : TIME := 20.0 ns; | |
|
216 | tRRD : TIME := 15.0 ns; | |
|
217 | tWRa : TIME := 7.5 ns; -- A2 Version - Auto precharge mode only (1 Clk + 7.5 ns) | |
|
218 | tWRp : TIME := 15.0 ns; -- A2 Version - Precharge mode only (15 ns) | |
|
219 | ||
|
220 | tAH : TIME := 0.8 ns; | |
|
221 | tAS : TIME := 1.5 ns; | |
|
222 | tCH : TIME := 2.5 ns; | |
|
223 | tCL : TIME := 2.5 ns; | |
|
224 | tCK : TIME := 10.0 ns; | |
|
225 | tDH : TIME := 0.8 ns; | |
|
226 | tDS : TIME := 1.5 ns; | |
|
227 | tCKH : TIME := 0.8 ns; | |
|
228 | tCKS : TIME := 1.5 ns; | |
|
229 | tCMH : TIME := 0.8 ns; | |
|
230 | tCMS : TIME := 1.5 ns; | |
|
231 | ||
|
232 | addr_bits : INTEGER := 13; | |
|
233 | data_bits : INTEGER := 16; | |
|
234 | col_bits : INTEGER := 9; | |
|
235 | index : INTEGER := 0; | |
|
236 | fname : string := "ram.srec" -- File to read from | |
|
237 | ); | |
|
238 | PORT ( | |
|
239 | Dq : INOUT STD_LOGIC_VECTOR (data_bits - 1 DOWNTO 0) := (OTHERS => 'Z'); | |
|
240 | Addr : IN STD_LOGIC_VECTOR (addr_bits - 1 DOWNTO 0) := (OTHERS => '0'); | |
|
241 | Ba : IN STD_LOGIC_VECTOR := "00"; | |
|
242 | Clk : IN STD_LOGIC := '0'; | |
|
243 | Cke : IN STD_LOGIC := '1'; | |
|
244 | Cs_n : IN STD_LOGIC := '1'; | |
|
245 | Ras_n : IN STD_LOGIC := '1'; | |
|
246 | Cas_n : IN STD_LOGIC := '1'; | |
|
247 | We_n : IN STD_LOGIC := '1'; | |
|
248 | Dqm : IN STD_LOGIC_VECTOR (1 DOWNTO 0) := "00" | |
|
249 | ); | |
|
250 | END mt48lc16m16a2; | |
|
251 | ||
|
252 | ARCHITECTURE behave OF mt48lc16m16a2 IS | |
|
253 | TYPE State IS (ACT, A_REF, BST, LMR, NOP, PRECH, READ, READ_A, WRITE, WRITE_A, LOAD_FILE, DUMP_FILE); | |
|
254 | TYPE Array4xI IS ARRAY (3 DOWNTO 0) OF INTEGER; | |
|
255 | TYPE Array4xT IS ARRAY (3 DOWNTO 0) OF TIME; | |
|
256 | TYPE Array4xB IS ARRAY (3 DOWNTO 0) OF BIT; | |
|
257 | TYPE Array4x2BV IS ARRAY (3 DOWNTO 0) OF BIT_VECTOR (1 DOWNTO 0); | |
|
258 | TYPE Array4xCBV IS ARRAY (4 DOWNTO 0) OF BIT_VECTOR (Col_bits - 1 DOWNTO 0); | |
|
259 | TYPE Array_state IS ARRAY (4 DOWNTO 0) OF State; | |
|
260 | SIGNAL Operation : State := NOP; | |
|
261 | SIGNAL Mode_reg : BIT_VECTOR (addr_bits - 1 DOWNTO 0) := (OTHERS => '0'); | |
|
262 | SIGNAL Active_enable, Aref_enable, Burst_term : BIT := '0'; | |
|
263 | SIGNAL Mode_reg_enable, Prech_enable, Read_enable, Write_enable : BIT := '0'; | |
|
264 | SIGNAL Burst_length_1, Burst_length_2, Burst_length_4, Burst_length_8 : BIT := '0'; | |
|
265 | SIGNAL Cas_latency_2, Cas_latency_3 : BIT := '0'; | |
|
266 | SIGNAL Ras_in, Cas_in, We_in : BIT := '0'; | |
|
267 | SIGNAL Write_burst_mode : BIT := '0'; | |
|
268 | SIGNAL RAS_clk, Sys_clk, CkeZ : BIT := '0'; | |
|
269 | ||
|
270 | -- Checking internal wires | |
|
271 | SIGNAL Pre_chk : BIT_VECTOR (3 DOWNTO 0) := "0000"; | |
|
272 | SIGNAL Act_chk : BIT_VECTOR (3 DOWNTO 0) := "0000"; | |
|
273 | SIGNAL Dq_in_chk, Dq_out_chk : BIT := '0'; | |
|
274 | SIGNAL Bank_chk : BIT_VECTOR (1 DOWNTO 0) := "00"; | |
|
275 | SIGNAL Row_chk : BIT_VECTOR (addr_bits - 1 DOWNTO 0) := (OTHERS => '0'); | |
|
276 | SIGNAL Col_chk : BIT_VECTOR (col_bits - 1 DOWNTO 0) := (OTHERS => '0'); | |
|
277 | ||
|
278 | BEGIN | |
|
279 | -- CS# Decode | |
|
280 | WITH Cs_n SELECT | |
|
281 | Cas_in <= TO_BIT (Cas_n, '1') WHEN '0', | |
|
282 | '1' WHEN '1', | |
|
283 | '1' WHEN OTHERS; | |
|
284 | WITH Cs_n SELECT | |
|
285 | Ras_in <= TO_BIT (Ras_n, '1') WHEN '0', | |
|
286 | '1' WHEN '1', | |
|
287 | '1' WHEN OTHERS; | |
|
288 | WITH Cs_n SELECT | |
|
289 | We_in <= TO_BIT (We_n, '1') WHEN '0', | |
|
290 | '1' WHEN '1', | |
|
291 | '1' WHEN OTHERS; | |
|
292 | ||
|
293 | -- Commands Decode | |
|
294 | Active_enable <= NOT(Ras_in) AND Cas_in AND We_in; | |
|
295 | Aref_enable <= NOT(Ras_in) AND NOT(Cas_in) AND We_in; | |
|
296 | Burst_term <= Ras_in AND Cas_in AND NOT(We_in); | |
|
297 | Mode_reg_enable <= NOT(Ras_in) AND NOT(Cas_in) AND NOT(We_in); | |
|
298 | Prech_enable <= NOT(Ras_in) AND Cas_in AND NOT(We_in); | |
|
299 | Read_enable <= Ras_in AND NOT(Cas_in) AND We_in; | |
|
300 | Write_enable <= Ras_in AND NOT(Cas_in) AND NOT(We_in); | |
|
301 | ||
|
302 | -- Burst Length Decode | |
|
303 | Burst_length_1 <= NOT(Mode_reg(2)) AND NOT(Mode_reg(1)) AND NOT(Mode_reg(0)); | |
|
304 | Burst_length_2 <= NOT(Mode_reg(2)) AND NOT(Mode_reg(1)) AND Mode_reg(0); | |
|
305 | Burst_length_4 <= NOT(Mode_reg(2)) AND Mode_reg(1) AND NOT(Mode_reg(0)); | |
|
306 | Burst_length_8 <= NOT(Mode_reg(2)) AND Mode_reg(1) AND Mode_reg(0); | |
|
307 | ||
|
308 | -- CAS Latency Decode | |
|
309 | Cas_latency_2 <= NOT(Mode_reg(6)) AND Mode_reg(5) AND NOT(Mode_reg(4)); | |
|
310 | Cas_latency_3 <= NOT(Mode_reg(6)) AND Mode_reg(5) AND Mode_reg(4); | |
|
311 | ||
|
312 | -- Write Burst Mode | |
|
313 | Write_burst_mode <= Mode_reg(9); | |
|
314 | ||
|
315 | -- RAS Clock for checking tWR and tRP | |
|
316 | PROCESS | |
|
317 | variable Clk0, Clk1 : integer := 0; | |
|
318 | begin | |
|
319 | RAS_clk <= '1'; | |
|
320 | wait for 0.5 ns; | |
|
321 | RAS_clk <= '0'; | |
|
322 | wait for 0.5 ns; | |
|
323 | if Clk0 > 100 or Clk1 > 100 then | |
|
324 | wait; | |
|
325 | else | |
|
326 | if Clk = '1' and Cke = '1' then | |
|
327 | Clk0 := 0; | |
|
328 | Clk1 := Clk1 + 1; | |
|
329 | elsif Clk = '0' and Cke = '1' then | |
|
330 | Clk0 := Clk0 + 1; | |
|
331 | Clk1 := 0; | |
|
332 | end if; | |
|
333 | end if; | |
|
334 | END PROCESS; | |
|
335 | ||
|
336 | -- System Clock | |
|
337 | int_clk : PROCESS (Clk) | |
|
338 | begin | |
|
339 | IF Clk'LAST_VALUE = '0' AND Clk = '1' THEN --' | |
|
340 | CkeZ <= TO_BIT(Cke, '1'); | |
|
341 | END IF; | |
|
342 | Sys_clk <= CkeZ AND TO_BIT(Clk, '0'); | |
|
343 | END PROCESS; | |
|
344 | ||
|
345 | state_register : PROCESS | |
|
346 | -- NOTE: The extra bits in RAM_TYPE is for checking memory access. A logic 1 means | |
|
347 | -- the location is in use. This will be checked when doing memory DUMP. | |
|
348 | TYPE ram_type IS ARRAY (2**col_bits - 1 DOWNTO 0) OF BIT_VECTOR (data_bits DOWNTO 0); | |
|
349 | TYPE ram_pntr IS ACCESS ram_type; | |
|
350 | TYPE ram_stor IS ARRAY (2**addr_bits - 1 DOWNTO 0) OF ram_pntr; | |
|
351 | VARIABLE Bank0 : ram_stor; | |
|
352 | VARIABLE Bank1 : ram_stor; | |
|
353 | VARIABLE Bank2 : ram_stor; | |
|
354 | VARIABLE Bank3 : ram_stor; | |
|
355 | VARIABLE Row_index, Col_index : INTEGER := 0; | |
|
356 | VARIABLE Dq_temp : BIT_VECTOR (data_bits DOWNTO 0) := (OTHERS => '0'); | |
|
357 | ||
|
358 | VARIABLE Col_addr : Array4xCBV; | |
|
359 | VARIABLE Bank_addr : Array4x2BV; | |
|
360 | VARIABLE Dqm_reg0, Dqm_reg1 : BIT_VECTOR (1 DOWNTO 0) := "00"; | |
|
361 | ||
|
362 | VARIABLE Bank, Previous_bank : BIT_VECTOR (1 DOWNTO 0) := "00"; | |
|
363 | VARIABLE B0_row_addr, B1_row_addr, B2_row_addr, B3_row_addr : BIT_VECTOR (addr_bits - 1 DOWNTO 0) := (OTHERS => '0'); | |
|
364 | VARIABLE Col_brst : BIT_VECTOR (col_bits - 1 DOWNTO 0) := (OTHERS => '0'); | |
|
365 | VARIABLE Row : BIT_VECTOR (addr_bits - 1 DOWNTO 0) := (OTHERS => '0'); | |
|
366 | VARIABLE Col : BIT_VECTOR (col_bits - 1 DOWNTO 0) := (OTHERS => '0'); | |
|
367 | VARIABLE Burst_counter : INTEGER := 0; | |
|
368 | ||
|
369 | VARIABLE Command : Array_state; | |
|
370 | VARIABLE Bank_precharge : Array4x2BV; | |
|
371 | VARIABLE A10_precharge : Array4xB := ('0' & '0' & '0' & '0'); | |
|
372 | VARIABLE Auto_precharge : Array4xB := ('0' & '0' & '0' & '0'); | |
|
373 | VARIABLE Read_precharge : Array4xB := ('0' & '0' & '0' & '0'); | |
|
374 | VARIABLE Write_precharge : Array4xB := ('0' & '0' & '0' & '0'); | |
|
375 | VARIABLE RW_interrupt_read : Array4xB := ('0' & '0' & '0' & '0'); | |
|
376 | VARIABLE RW_interrupt_write : Array4xB := ('0' & '0' & '0' & '0'); | |
|
377 | VARIABLE RW_interrupt_bank : BIT_VECTOR (1 DOWNTO 0) := "00"; | |
|
378 | VARIABLE Count_time : Array4xT := (0 ns & 0 ns & 0 ns & 0 ns); | |
|
379 | VARIABLE Count_precharge : Array4xI := (0 & 0 & 0 & 0); | |
|
380 | ||
|
381 | VARIABLE Data_in_enable, Data_out_enable : BIT := '0'; | |
|
382 | VARIABLE Pc_b0, Pc_b1, Pc_b2, Pc_b3 : BIT := '0'; | |
|
383 | VARIABLE Act_b0, Act_b1, Act_b2, Act_b3 : BIT := '0'; | |
|
384 | ||
|
385 | -- Timing Check | |
|
386 | VARIABLE MRD_chk : INTEGER := 0; | |
|
387 | VARIABLE WR_counter : Array4xI := (0 & 0 & 0 & 0); | |
|
388 | VARIABLE WR_time : Array4xT := (0 ns & 0 ns & 0 ns & 0 ns); | |
|
389 | VARIABLE WR_chkp : Array4xT := (0 ns & 0 ns & 0 ns & 0 ns); | |
|
390 | VARIABLE RC_chk, RRD_chk : TIME := 0 ns; | |
|
391 | VARIABLE RAS_chk0, RAS_chk1, RAS_chk2, RAS_chk3 : TIME := 0 ns; | |
|
392 | VARIABLE RCD_chk0, RCD_chk1, RCD_chk2, RCD_chk3 : TIME := 0 ns; | |
|
393 | VARIABLE RP_chk0, RP_chk1, RP_chk2, RP_chk3 : TIME := 0 ns; | |
|
394 | ||
|
395 | -- Load and Dumb variables | |
|
396 | FILE file_load : TEXT open read_mode is fname; -- Data load | |
|
397 | FILE file_dump : TEXT open write_mode is "dumpdata.txt"; -- Data dump | |
|
398 | VARIABLE bank_load : bit_vector ( 1 DOWNTO 0); | |
|
399 | VARIABLE rows_load : BIT_VECTOR (12 DOWNTO 0); | |
|
400 | VARIABLE cols_load : BIT_VECTOR ( 8 DOWNTO 0); | |
|
401 | VARIABLE data_load : BIT_VECTOR (15 DOWNTO 0); | |
|
402 | VARIABLE i, j : INTEGER; | |
|
403 | VARIABLE good_load : BOOLEAN; | |
|
404 | VARIABLE l : LINE; | |
|
405 | variable load : std_logic := '1'; | |
|
406 | variable dump : std_logic := '0'; | |
|
407 | variable ch : character; | |
|
408 | variable rectype : bit_vector(3 downto 0); | |
|
409 | variable recaddr : bit_vector(31 downto 0); | |
|
410 | variable reclen : bit_vector(7 downto 0); | |
|
411 | variable recdata : bit_vector(0 to 16*8-1); | |
|
412 | ||
|
413 | -- Initialize empty rows | |
|
414 | PROCEDURE Init_mem (Bank : bit_vector (1 DOWNTO 0); Row_index : INTEGER) IS | |
|
415 | VARIABLE i, j : INTEGER := 0; | |
|
416 | BEGIN | |
|
417 | IF Bank = "00" THEN | |
|
418 | IF Bank0 (Row_index) = NULL THEN -- Check to see if row empty | |
|
419 | Bank0 (Row_index) := NEW ram_type; -- Open new row for access | |
|
420 | FOR i IN (2**col_bits - 1) DOWNTO 0 LOOP -- Filled row with zeros | |
|
421 | FOR j IN (data_bits) DOWNTO 0 LOOP | |
|
422 | Bank0 (Row_index) (i) (j) := '0'; | |
|
423 | END LOOP; | |
|
424 | END LOOP; | |
|
425 | END IF; | |
|
426 | ELSIF Bank = "01" THEN | |
|
427 | IF Bank1 (Row_index) = NULL THEN | |
|
428 | Bank1 (Row_index) := NEW ram_type; | |
|
429 | FOR i IN (2**col_bits - 1) DOWNTO 0 LOOP | |
|
430 | FOR j IN (data_bits) DOWNTO 0 LOOP | |
|
431 | Bank1 (Row_index) (i) (j) := '0'; | |
|
432 | END LOOP; | |
|
433 | END LOOP; | |
|
434 | END IF; | |
|
435 | ELSIF Bank = "10" THEN | |
|
436 | IF Bank2 (Row_index) = NULL THEN | |
|
437 | Bank2 (Row_index) := NEW ram_type; | |
|
438 | FOR i IN (2**col_bits - 1) DOWNTO 0 LOOP | |
|
439 | FOR j IN (data_bits) DOWNTO 0 LOOP | |
|
440 | Bank2 (Row_index) (i) (j) := '0'; | |
|
441 | END LOOP; | |
|
442 | END LOOP; | |
|
443 | END IF; | |
|
444 | ELSIF Bank = "11" THEN | |
|
445 | IF Bank3 (Row_index) = NULL THEN | |
|
446 | Bank3 (Row_index) := NEW ram_type; | |
|
447 | FOR i IN (2**col_bits - 1) DOWNTO 0 LOOP | |
|
448 | FOR j IN (data_bits) DOWNTO 0 LOOP | |
|
449 | Bank3 (Row_index) (i) (j) := '0'; | |
|
450 | END LOOP; | |
|
451 | END LOOP; | |
|
452 | END IF; | |
|
453 | END IF; | |
|
454 | END; | |
|
455 | ||
|
456 | -- Burst Counter | |
|
457 | PROCEDURE Burst_decode IS | |
|
458 | VARIABLE Col_int : INTEGER := 0; | |
|
459 | VARIABLE Col_vec, Col_temp : BIT_VECTOR (col_bits - 1 DOWNTO 0) := (OTHERS => '0'); | |
|
460 | BEGIN | |
|
461 | -- Advance Burst Counter | |
|
462 | Burst_counter := Burst_counter + 1; | |
|
463 | ||
|
464 | -- Burst Type | |
|
465 | IF Mode_reg (3) = '0' THEN | |
|
466 | Col_int := TO_INTEGER(Col); | |
|
467 | Col_int := Col_int + 1; | |
|
468 | TO_BITVECTOR (Col_int, Col_temp); | |
|
469 | ELSIF Mode_reg (3) = '1' THEN | |
|
470 | TO_BITVECTOR (Burst_counter, Col_vec); | |
|
471 | Col_temp (2) := Col_vec (2) XOR Col_brst (2); | |
|
472 | Col_temp (1) := Col_vec (1) XOR Col_brst (1); | |
|
473 | Col_temp (0) := Col_vec (0) XOR Col_brst (0); | |
|
474 | END IF; | |
|
475 | ||
|
476 | -- Burst Length | |
|
477 | IF Burst_length_2 = '1' THEN | |
|
478 | Col (0) := Col_temp (0); | |
|
479 | ELSIF Burst_length_4 = '1' THEN | |
|
480 | Col (1 DOWNTO 0) := Col_temp (1 DOWNTO 0); | |
|
481 | ELSIF Burst_length_8 = '1' THEN | |
|
482 | Col (2 DOWNTO 0) := Col_temp (2 DOWNTO 0); | |
|
483 | ELSE | |
|
484 | Col := Col_temp; | |
|
485 | END IF; | |
|
486 | ||
|
487 | -- Burst Read Single Write | |
|
488 | IF Write_burst_mode = '1' AND Data_in_enable = '1' THEN | |
|
489 | Data_in_enable := '0'; | |
|
490 | END IF; | |
|
491 | ||
|
492 | -- Data counter | |
|
493 | IF Burst_length_1 = '1' THEN | |
|
494 | IF Burst_counter >= 1 THEN | |
|
495 | IF Data_in_enable = '1' THEN | |
|
496 | Data_in_enable := '0'; | |
|
497 | ELSIF Data_out_enable = '1' THEN | |
|
498 | Data_out_enable := '0'; | |
|
499 | END IF; | |
|
500 | END IF; | |
|
501 | ELSIF Burst_length_2 = '1' THEN | |
|
502 | IF Burst_counter >= 2 THEN | |
|
503 | IF Data_in_enable = '1' THEN | |
|
504 | Data_in_enable := '0'; | |
|
505 | ELSIF Data_out_enable = '1' THEN | |
|
506 | Data_out_enable := '0'; | |
|
507 | END IF; | |
|
508 | END IF; | |
|
509 | ELSIF Burst_length_4 = '1' THEN | |
|
510 | IF Burst_counter >= 4 THEN | |
|
511 | IF Data_in_enable = '1' THEN | |
|
512 | Data_in_enable := '0'; | |
|
513 | ELSIF Data_out_enable = '1' THEN | |
|
514 | Data_out_enable := '0'; | |
|
515 | END IF; | |
|
516 | END IF; | |
|
517 | ELSIF Burst_length_8 = '1' THEN | |
|
518 | IF Burst_counter >= 8 THEN | |
|
519 | IF Data_in_enable = '1' THEN | |
|
520 | Data_in_enable := '0'; | |
|
521 | ELSIF Data_out_enable = '1' THEN | |
|
522 | Data_out_enable := '0'; | |
|
523 | END IF; | |
|
524 | END IF; | |
|
525 | END IF; | |
|
526 | END; | |
|
527 | ||
|
528 | BEGIN | |
|
529 | WAIT ON Sys_clk, RAS_clk; | |
|
530 | IF Sys_clk'event AND Sys_clk = '1' AND Load = '0' AND Dump = '0' THEN --' | |
|
531 | -- Internal Command Pipeline | |
|
532 | Command(0) := Command(1); | |
|
533 | Command(1) := Command(2); | |
|
534 | Command(2) := Command(3); | |
|
535 | Command(3) := NOP; | |
|
536 | ||
|
537 | Col_addr(0) := Col_addr(1); | |
|
538 | Col_addr(1) := Col_addr(2); | |
|
539 | Col_addr(2) := Col_addr(3); | |
|
540 | Col_addr(3) := (OTHERS => '0'); | |
|
541 | ||
|
542 | Bank_addr(0) := Bank_addr(1); | |
|
543 | Bank_addr(1) := Bank_addr(2); | |
|
544 | Bank_addr(2) := Bank_addr(3); | |
|
545 | Bank_addr(3) := "00"; | |
|
546 | ||
|
547 | Bank_precharge(0) := Bank_precharge(1); | |
|
548 | Bank_precharge(1) := Bank_precharge(2); | |
|
549 | Bank_precharge(2) := Bank_precharge(3); | |
|
550 | Bank_precharge(3) := "00"; | |
|
551 | ||
|
552 | A10_precharge(0) := A10_precharge(1); | |
|
553 | A10_precharge(1) := A10_precharge(2); | |
|
554 | A10_precharge(2) := A10_precharge(3); | |
|
555 | A10_precharge(3) := '0'; | |
|
556 | ||
|
557 | -- Operation Decode (Optional for showing current command on posedge clock / debug feature) | |
|
558 | IF Active_enable = '1' THEN | |
|
559 | Operation <= ACT; | |
|
560 | ELSIF Aref_enable = '1' THEN | |
|
561 | Operation <= A_REF; | |
|
562 | ELSIF Burst_term = '1' THEN | |
|
563 | Operation <= BST; | |
|
564 | ELSIF Mode_reg_enable = '1' THEN | |
|
565 | Operation <= LMR; | |
|
566 | ELSIF Prech_enable = '1' THEN | |
|
567 | Operation <= PRECH; | |
|
568 | ELSIF Read_enable = '1' THEN | |
|
569 | IF Addr(10) = '0' THEN | |
|
570 | Operation <= READ; | |
|
571 | ELSE | |
|
572 | Operation <= READ_A; | |
|
573 | END IF; | |
|
574 | ELSIF Write_enable = '1' THEN | |
|
575 | IF Addr(10) = '0' THEN | |
|
576 | Operation <= WRITE; | |
|
577 | ELSE | |
|
578 | Operation <= WRITE_A; | |
|
579 | END IF; | |
|
580 | ELSE | |
|
581 | Operation <= NOP; | |
|
582 | END IF; | |
|
583 | ||
|
584 | -- Dqm pipeline for Read | |
|
585 | Dqm_reg0 := Dqm_reg1; | |
|
586 | Dqm_reg1 := TO_BITVECTOR(Dqm); | |
|
587 | ||
|
588 | -- Read or Write with Auto Precharge Counter | |
|
589 | IF Auto_precharge (0) = '1' THEN | |
|
590 | Count_precharge (0) := Count_precharge (0) + 1; | |
|
591 | END IF; | |
|
592 | IF Auto_precharge (1) = '1' THEN | |
|
593 | Count_precharge (1) := Count_precharge (1) + 1; | |
|
594 | END IF; | |
|
595 | IF Auto_precharge (2) = '1' THEN | |
|
596 | Count_precharge (2) := Count_precharge (2) + 1; | |
|
597 | END IF; | |
|
598 | IF Auto_precharge (3) = '1' THEN | |
|
599 | Count_precharge (3) := Count_precharge (3) + 1; | |
|
600 | END IF; | |
|
601 | ||
|
602 | -- Auto Precharge Timer for tWR | |
|
603 | if (Burst_length_1 = '1' OR Write_burst_mode = '1') then | |
|
604 | if (Count_precharge(0) = 1) then | |
|
605 | Count_time(0) := NOW; | |
|
606 | end if; | |
|
607 | if (Count_precharge(1) = 1) then | |
|
608 | Count_time(1) := NOW; | |
|
609 | end if; | |
|
610 | if (Count_precharge(2) = 1) then | |
|
611 | Count_time(2) := NOW; | |
|
612 | end if; | |
|
613 | if (Count_precharge(3) = 1) then | |
|
614 | Count_time(3) := NOW; | |
|
615 | end if; | |
|
616 | elsif (Burst_length_2 = '1') then | |
|
617 | if (Count_precharge(0) = 2) then | |
|
618 | Count_time(0) := NOW; | |
|
619 | end if; | |
|
620 | if (Count_precharge(1) = 2) then | |
|
621 | Count_time(1) := NOW; | |
|
622 | end if; | |
|
623 | if (Count_precharge(2) = 2) then | |
|
624 | Count_time(2) := NOW; | |
|
625 | end if; | |
|
626 | if (Count_precharge(3) = 2) then | |
|
627 | Count_time(3) := NOW; | |
|
628 | end if; | |
|
629 | elsif (Burst_length_4 = '1') then | |
|
630 | if (Count_precharge(0) = 4) then | |
|
631 | Count_time(0) := NOW; | |
|
632 | end if; | |
|
633 | if (Count_precharge(1) = 4) then | |
|
634 | Count_time(1) := NOW; | |
|
635 | end if; | |
|
636 | if (Count_precharge(2) = 4) then | |
|
637 | Count_time(2) := NOW; | |
|
638 | end if; | |
|
639 | if (Count_precharge(3) = 4) then | |
|
640 | Count_time(3) := NOW; | |
|
641 | end if; | |
|
642 | elsif (Burst_length_8 = '1') then | |
|
643 | if (Count_precharge(0) = 8) then | |
|
644 | Count_time(0) := NOW; | |
|
645 | end if; | |
|
646 | if (Count_precharge(1) = 8) then | |
|
647 | Count_time(1) := NOW; | |
|
648 | end if; | |
|
649 | if (Count_precharge(2) = 8) then | |
|
650 | Count_time(2) := NOW; | |
|
651 | end if; | |
|
652 | if (Count_precharge(3) = 8) then | |
|
653 | Count_time(3) := NOW; | |
|
654 | end if; | |
|
655 | end if; | |
|
656 | ||
|
657 | -- tMRD Counter | |
|
658 | MRD_chk := MRD_chk + 1; | |
|
659 | ||
|
660 | -- tWR Counter | |
|
661 | WR_counter(0) := WR_counter(0) + 1; | |
|
662 | WR_counter(1) := WR_counter(1) + 1; | |
|
663 | WR_counter(2) := WR_counter(2) + 1; | |
|
664 | WR_counter(3) := WR_counter(3) + 1; | |
|
665 | ||
|
666 | ||
|
667 | -- Auto Refresh | |
|
668 | IF Aref_enable = '1' THEN | |
|
669 | -- Auto Refresh to Auto Refresh | |
|
670 | ASSERT (NOW - RC_chk >= tRC) | |
|
671 | REPORT "tRC violation during Auto Refresh" | |
|
672 | SEVERITY WARNING; | |
|
673 | -- Precharge to Auto Refresh | |
|
674 | ASSERT (NOW - RP_chk0 >= tRP OR NOW - RP_chk1 >= tRP OR NOW - RP_chk2 >= tRP OR NOW - RP_chk3 >= tRP) | |
|
675 | REPORT "tRP violation during Auto Refresh" | |
|
676 | SEVERITY WARNING; | |
|
677 | -- All banks must be idle before refresh | |
|
678 | IF (Pc_b3 ='0' OR Pc_b2 = '0' OR Pc_b1 ='0' OR Pc_b0 = '0') THEN | |
|
679 | ASSERT (FALSE) | |
|
680 | REPORT "All banks must be Precharge before Auto Refresh" | |
|
681 | SEVERITY WARNING; | |
|
682 | END IF; | |
|
683 | -- Record current tRC time | |
|
684 | RC_chk := NOW; | |
|
685 | END IF; | |
|
686 | ||
|
687 | -- Load Mode Register | |
|
688 | IF Mode_reg_enable = '1' THEN | |
|
689 | Mode_reg <= TO_BITVECTOR (Addr); | |
|
690 | IF (Pc_b3 ='0' OR Pc_b2 = '0' OR Pc_b1 ='0' OR Pc_b0 = '0') THEN | |
|
691 | ASSERT (FALSE) | |
|
692 | REPORT "All bank must be Precharge before Load Mode Register" | |
|
693 | SEVERITY WARNING; | |
|
694 | END IF; | |
|
695 | -- REF to LMR | |
|
696 | ASSERT (NOW - RC_chk >= tRC) | |
|
697 | REPORT "tRC violation during Load Mode Register" | |
|
698 | SEVERITY WARNING; | |
|
699 | -- LMR to LMR | |
|
700 | ASSERT (MRD_chk >= tMRD) | |
|
701 | REPORT "tMRD violation during Load Mode Register" | |
|
702 | SEVERITY WARNING; | |
|
703 | -- Record current tMRD time | |
|
704 | MRD_chk := 0; | |
|
705 | END IF; | |
|
706 | ||
|
707 | -- Active Block (latch Bank and Row Address) | |
|
708 | IF Active_enable = '1' THEN | |
|
709 | IF Ba = "00" AND Pc_b0 = '1' THEN | |
|
710 | Act_b0 := '1'; | |
|
711 | Pc_b0 := '0'; | |
|
712 | B0_row_addr := TO_BITVECTOR (Addr); | |
|
713 | RCD_chk0 := NOW; | |
|
714 | RAS_chk0 := NOW; | |
|
715 | -- Precharge to Active Bank 0 | |
|
716 | ASSERT (NOW - RP_chk0 >= tRP) | |
|
717 | REPORT "tRP violation during Activate Bank 0" | |
|
718 | SEVERITY WARNING; | |
|
719 | ELSIF Ba = "01" AND Pc_b1 = '1' THEN | |
|
720 | Act_b1 := '1'; | |
|
721 | Pc_b1 := '0'; | |
|
722 | B1_row_addr := TO_BITVECTOR (Addr); | |
|
723 | RCD_chk1 := NOW; | |
|
724 | RAS_chk1 := NOW; | |
|
725 | -- Precharge to Active Bank 1 | |
|
726 | ASSERT (NOW - RP_chk1 >= tRP) | |
|
727 | REPORT "tRP violation during Activate Bank 1" | |
|
728 | SEVERITY WARNING; | |
|
729 | ELSIF Ba = "10" AND Pc_b2 = '1' THEN | |
|
730 | Act_b2 := '1'; | |
|
731 | Pc_b2 := '0'; | |
|
732 | B2_row_addr := TO_BITVECTOR (Addr); | |
|
733 | RCD_chk2 := NOW; | |
|
734 | RAS_chk2 := NOW; | |
|
735 | -- Precharge to Active Bank 2 | |
|
736 | ASSERT (NOW - RP_chk2 >= tRP) | |
|
737 | REPORT "tRP violation during Activate Bank 2" | |
|
738 | SEVERITY WARNING; | |
|
739 | ELSIF Ba = "11" AND Pc_b3 = '1' THEN | |
|
740 | Act_b3 := '1'; | |
|
741 | Pc_b3 := '0'; | |
|
742 | B3_row_addr := TO_BITVECTOR (Addr); | |
|
743 | RCD_chk3 := NOW; | |
|
744 | RAS_chk3 := NOW; | |
|
745 | -- Precharge to Active Bank 3 | |
|
746 | ASSERT (NOW - RP_chk3 >= tRP) | |
|
747 | REPORT "tRP violation during Activate Bank 3" | |
|
748 | SEVERITY WARNING; | |
|
749 | ELSIF Ba = "00" AND Pc_b0 = '0' THEN | |
|
750 | ASSERT (FALSE) | |
|
751 | REPORT "Bank 0 is not Precharged" | |
|
752 | SEVERITY WARNING; | |
|
753 | ELSIF Ba = "01" AND Pc_b1 = '0' THEN | |
|
754 | ASSERT (FALSE) | |
|
755 | REPORT "Bank 1 is not Precharged" | |
|
756 | SEVERITY WARNING; | |
|
757 | ELSIF Ba = "10" AND Pc_b2 = '0' THEN | |
|
758 | ASSERT (FALSE) | |
|
759 | REPORT "Bank 2 is not Precharged" | |
|
760 | SEVERITY WARNING; | |
|
761 | ELSIF Ba = "11" AND Pc_b3 = '0' THEN | |
|
762 | ASSERT (FALSE) | |
|
763 | REPORT "Bank 3 is not Precharged" | |
|
764 | SEVERITY WARNING; | |
|
765 | END IF; | |
|
766 | -- Active Bank A to Active Bank B | |
|
767 | IF ((Previous_bank /= TO_BITVECTOR (Ba)) AND (NOW - RRD_chk < tRRD)) THEN | |
|
768 | ASSERT (FALSE) | |
|
769 | REPORT "tRRD violation during Activate" | |
|
770 | SEVERITY WARNING; | |
|
771 | END IF; | |
|
772 | -- LMR to ACT | |
|
773 | ASSERT (MRD_chk >= tMRD) | |
|
774 | REPORT "tMRD violation during Activate" | |
|
775 | SEVERITY WARNING; | |
|
776 | -- AutoRefresh to Activate | |
|
777 | ASSERT (NOW - RC_chk >= tRC) | |
|
778 | REPORT "tRC violation during Activate" | |
|
779 | SEVERITY WARNING; | |
|
780 | -- Record variable for checking violation | |
|
781 | RRD_chk := NOW; | |
|
782 | Previous_bank := TO_BITVECTOR (Ba); | |
|
783 | END IF; | |
|
784 | ||
|
785 | -- Precharge Block | |
|
786 | IF Prech_enable = '1' THEN | |
|
787 | IF Addr(10) = '1' THEN | |
|
788 | Pc_b0 := '1'; | |
|
789 | Pc_b1 := '1'; | |
|
790 | Pc_b2 := '1'; | |
|
791 | Pc_b3 := '1'; | |
|
792 | Act_b0 := '0'; | |
|
793 | Act_b1 := '0'; | |
|
794 | Act_b2 := '0'; | |
|
795 | Act_b3 := '0'; | |
|
796 | RP_chk0 := NOW; | |
|
797 | RP_chk1 := NOW; | |
|
798 | RP_chk2 := NOW; | |
|
799 | RP_chk3 := NOW; | |
|
800 | -- Activate to Precharge all banks | |
|
801 | ASSERT ((NOW - RAS_chk0 >= tRAS) OR (NOW - RAS_chk1 >= tRAS)) | |
|
802 | REPORT "tRAS violation during Precharge all banks" | |
|
803 | SEVERITY WARNING; | |
|
804 | -- tWR violation check for Write | |
|
805 | IF ((NOW - WR_chkp(0) < tWRp) OR (NOW - WR_chkp(1) < tWRp) OR | |
|
806 | (NOW - WR_chkp(2) < tWRp) OR (NOW - WR_chkp(3) < tWRp)) THEN | |
|
807 | ASSERT (FALSE) | |
|
808 | REPORT "tWR violation during Precharge ALL banks" | |
|
809 | SEVERITY WARNING; | |
|
810 | END IF; | |
|
811 | ELSIF Addr(10) = '0' THEN | |
|
812 | IF Ba = "00" THEN | |
|
813 | Pc_b0 := '1'; | |
|
814 | Act_b0 := '0'; | |
|
815 | RP_chk0 := NOW; | |
|
816 | -- Activate to Precharge bank 0 | |
|
817 | ASSERT (NOW - RAS_chk0 >= tRAS) | |
|
818 | REPORT "tRAS violation during Precharge bank 0" | |
|
819 | SEVERITY WARNING; | |
|
820 | ELSIF Ba = "01" THEN | |
|
821 | Pc_b1 := '1'; | |
|
822 | Act_b1 := '0'; | |
|
823 | RP_chk1 := NOW; | |
|
824 | -- Activate to Precharge bank 1 | |
|
825 | ASSERT (NOW - RAS_chk1 >= tRAS) | |
|
826 | REPORT "tRAS violation during Precharge bank 1" | |
|
827 | SEVERITY WARNING; | |
|
828 | ELSIF Ba = "10" THEN | |
|
829 | Pc_b2 := '1'; | |
|
830 | Act_b2 := '0'; | |
|
831 | RP_chk2 := NOW; | |
|
832 | -- Activate to Precharge bank 2 | |
|
833 | ASSERT (NOW - RAS_chk2 >= tRAS) | |
|
834 | REPORT "tRAS violation during Precharge bank 2" | |
|
835 | SEVERITY WARNING; | |
|
836 | ELSIF Ba = "11" THEN | |
|
837 | Pc_b3 := '1'; | |
|
838 | Act_b3 := '0'; | |
|
839 | RP_chk3 := NOW; | |
|
840 | -- Activate to Precharge bank 3 | |
|
841 | ASSERT (NOW - RAS_chk3 >= tRAS) | |
|
842 | REPORT "tRAS violation during Precharge bank 3" | |
|
843 | SEVERITY WARNING; | |
|
844 | END IF; | |
|
845 | -- tWR violation check for Write | |
|
846 | ASSERT (NOW - WR_chkp(TO_INTEGER(Ba)) >= tWRp) | |
|
847 | REPORT "tWR violation during Precharge" | |
|
848 | SEVERITY WARNING; | |
|
849 | END IF; | |
|
850 | -- Terminate a Write Immediately (if same bank or all banks) | |
|
851 | IF (Data_in_enable = '1' AND (Bank = TO_BITVECTOR(Ba) OR Addr(10) = '1')) THEN | |
|
852 | Data_in_enable := '0'; | |
|
853 | END IF; | |
|
854 | -- Precharge Command Pipeline for READ | |
|
855 | IF CAS_latency_3 = '1' THEN | |
|
856 | Command(2) := PRECH; | |
|
857 | Bank_precharge(2) := TO_BITVECTOR (Ba); | |
|
858 | A10_precharge(2) := TO_BIT(Addr(10)); | |
|
859 | ELSIF CAS_latency_2 = '1' THEN | |
|
860 | Command(1) := PRECH; | |
|
861 | Bank_precharge(1) := TO_BITVECTOR (Ba); | |
|
862 | A10_precharge(1) := TO_BIT(Addr(10)); | |
|
863 | END IF; | |
|
864 | END IF; | |
|
865 | ||
|
866 | -- Burst Terminate | |
|
867 | IF Burst_term = '1' THEN | |
|
868 | -- Terminate a Write immediately | |
|
869 | IF Data_in_enable = '1' THEN | |
|
870 | Data_in_enable := '0'; | |
|
871 | END IF; | |
|
872 | -- Terminate a Read depend on CAS Latency | |
|
873 | IF CAS_latency_3 = '1' THEN | |
|
874 | Command(2) := BST; | |
|
875 | ELSIF CAS_latency_2 = '1' THEN | |
|
876 | Command(1) := BST; | |
|
877 | END IF; | |
|
878 | END IF; | |
|
879 | ||
|
880 | -- Read, Write, Column Latch | |
|
881 | IF Read_enable = '1' OR Write_enable = '1' THEN | |
|
882 | -- Check to see if bank is open (ACT) for Read or Write | |
|
883 | IF ((Ba="00" AND Pc_b0='1') OR (Ba="01" AND Pc_b1='1') OR (Ba="10" AND Pc_b2='1') OR (Ba="11" AND Pc_b3='1')) THEN | |
|
884 | ASSERT (FALSE) | |
|
885 | REPORT "Cannot Read or Write - Bank is not Activated" | |
|
886 | SEVERITY WARNING; | |
|
887 | END IF; | |
|
888 | -- Activate to Read or Write | |
|
889 | IF Ba = "00" THEN | |
|
890 | ASSERT (NOW - RCD_chk0 >= tRCD) | |
|
891 | REPORT "tRCD violation during Read or Write to Bank 0" | |
|
892 | SEVERITY WARNING; | |
|
893 | ELSIF Ba = "01" THEN | |
|
894 | ASSERT (NOW - RCD_chk1 >= tRCD) | |
|
895 | REPORT "tRCD violation during Read or Write to Bank 1" | |
|
896 | SEVERITY WARNING; | |
|
897 | ELSIF Ba = "10" THEN | |
|
898 | ASSERT (NOW - RCD_chk2 >= tRCD) | |
|
899 | REPORT "tRCD violation during Read or Write to Bank 2" | |
|
900 | SEVERITY WARNING; | |
|
901 | ELSIF Ba = "11" THEN | |
|
902 | ASSERT (NOW - RCD_chk3 >= tRCD) | |
|
903 | REPORT "tRCD violation during Read or Write to Bank 3" | |
|
904 | SEVERITY WARNING; | |
|
905 | END IF; | |
|
906 | ||
|
907 | -- Read Command | |
|
908 | IF Read_enable = '1' THEN | |
|
909 | -- CAS Latency Pipeline | |
|
910 | IF Cas_latency_3 = '1' THEN | |
|
911 | IF Addr(10) = '1' THEN | |
|
912 | Command(2) := READ_A; | |
|
913 | ELSE | |
|
914 | Command(2) := READ; | |
|
915 | END IF; | |
|
916 | Col_addr (2) := TO_BITVECTOR (Addr(col_bits - 1 DOWNTO 0)); | |
|
917 | Bank_addr (2) := TO_BITVECTOR (Ba); | |
|
918 | ELSIF Cas_latency_2 = '1' THEN | |
|
919 | IF Addr(10) = '1' THEN | |
|
920 | Command(1) := READ_A; | |
|
921 | ELSE | |
|
922 | Command(1) := READ; | |
|
923 | END IF; | |
|
924 | Col_addr (1) := TO_BITVECTOR (Addr(col_bits - 1 DOWNTO 0)); | |
|
925 | Bank_addr (1) := TO_BITVECTOR (Ba); | |
|
926 | END IF; | |
|
927 | ||
|
928 | -- Read intterupt a Write (terminate Write immediately) | |
|
929 | IF Data_in_enable = '1' THEN | |
|
930 | Data_in_enable := '0'; | |
|
931 | END IF; | |
|
932 | ||
|
933 | -- Write Command | |
|
934 | ELSIF Write_enable = '1' THEN | |
|
935 | IF Addr(10) = '1' THEN | |
|
936 | Command(0) := WRITE_A; | |
|
937 | ELSE | |
|
938 | Command(0) := WRITE; | |
|
939 | END IF; | |
|
940 | Col_addr (0) := TO_BITVECTOR (Addr(col_bits - 1 DOWNTO 0)); | |
|
941 | Bank_addr (0) := TO_BITVECTOR (Ba); | |
|
942 | ||
|
943 | -- Write intterupt a Write (terminate Write immediately) | |
|
944 | IF Data_in_enable = '1' THEN | |
|
945 | Data_in_enable := '0'; | |
|
946 | END IF; | |
|
947 | ||
|
948 | -- Write interrupt a Read (terminate Read immediately) | |
|
949 | IF Data_out_enable = '1' THEN | |
|
950 | Data_out_enable := '0'; | |
|
951 | END IF; | |
|
952 | END IF; | |
|
953 | ||
|
954 | -- Interrupt a Write with Auto Precharge | |
|
955 | IF Auto_precharge(TO_INTEGER(RW_Interrupt_Bank)) = '1' AND Write_precharge(TO_INTEGER(RW_Interrupt_Bank)) = '1' THEN | |
|
956 | RW_interrupt_write(TO_INTEGER(RW_Interrupt_Bank)) := '1'; | |
|
957 | END IF; | |
|
958 | ||
|
959 | -- Interrupt a Read with Auto Precharge | |
|
960 | IF Auto_precharge(TO_INTEGER(RW_Interrupt_Bank)) = '1' AND Read_precharge(TO_INTEGER(RW_Interrupt_Bank)) = '1' THEN | |
|
961 | RW_interrupt_read(TO_INTEGER(RW_Interrupt_Bank)) := '1'; | |
|
962 | END IF; | |
|
963 | ||
|
964 | -- Read or Write with Auto Precharge | |
|
965 | IF Addr(10) = '1' THEN | |
|
966 | Auto_precharge (TO_INTEGER(Ba)) := '1'; | |
|
967 | Count_precharge (TO_INTEGER(Ba)) := 0; | |
|
968 | RW_Interrupt_Bank := TO_BitVector(Ba); | |
|
969 | IF Read_enable = '1' THEN | |
|
970 | Read_precharge (TO_INTEGER(Ba)) := '1'; | |
|
971 | ELSIF Write_enable = '1' THEN | |
|
972 | Write_precharge (TO_INTEGER(Ba)) := '1'; | |
|
973 | END IF; | |
|
974 | END IF; | |
|
975 | END IF; | |
|
976 | ||
|
977 | -- Read with AutoPrecharge Calculation | |
|
978 | -- The device start internal precharge when: | |
|
979 | -- 1. BL/2 cycles after command | |
|
980 | -- and 2. Meet tRAS requirement | |
|
981 | -- or 3. Interrupt by a Read or Write (with or without Auto Precharge) | |
|
982 | IF ((Auto_precharge(0) = '1') AND (Read_precharge(0) = '1')) THEN | |
|
983 | IF (((NOW - RAS_chk0 >= tRAS) AND | |
|
984 | ((Burst_length_1 = '1' AND Count_precharge(0) >= 1) OR | |
|
985 | (Burst_length_2 = '1' AND Count_precharge(0) >= 2) OR | |
|
986 | (Burst_length_4 = '1' AND Count_precharge(0) >= 4) OR | |
|
987 | (Burst_length_8 = '1' AND Count_precharge(0) >= 8))) OR | |
|
988 | (RW_interrupt_read(0) = '1')) THEN | |
|
989 | Pc_b0 := '1'; | |
|
990 | Act_b0 := '0'; | |
|
991 | RP_chk0 := NOW; | |
|
992 | Auto_precharge(0) := '0'; | |
|
993 | Read_precharge(0) := '0'; | |
|
994 | RW_interrupt_read(0) := '0'; | |
|
995 | END IF; | |
|
996 | END IF; | |
|
997 | IF ((Auto_precharge(1) = '1') AND (Read_precharge(1) = '1')) THEN | |
|
998 | IF (((NOW - RAS_chk1 >= tRAS) AND | |
|
999 | ((Burst_length_1 = '1' AND Count_precharge(1) >= 1) OR | |
|
1000 | (Burst_length_2 = '1' AND Count_precharge(1) >= 2) OR | |
|
1001 | (Burst_length_4 = '1' AND Count_precharge(1) >= 4) OR | |
|
1002 | (Burst_length_8 = '1' AND Count_precharge(1) >= 8))) OR | |
|
1003 | (RW_interrupt_read(1) = '1')) THEN | |
|
1004 | Pc_b1 := '1'; | |
|
1005 | Act_b1 := '0'; | |
|
1006 | RP_chk1 := NOW; | |
|
1007 | Auto_precharge(1) := '0'; | |
|
1008 | Read_precharge(1) := '0'; | |
|
1009 | RW_interrupt_read(1) := '0'; | |
|
1010 | END IF; | |
|
1011 | END IF; | |
|
1012 | IF ((Auto_precharge(2) = '1') AND (Read_precharge(2) = '1')) THEN | |
|
1013 | IF (((NOW - RAS_chk2 >= tRAS) AND | |
|
1014 | ((Burst_length_1 = '1' AND Count_precharge(2) >= 1) OR | |
|
1015 | (Burst_length_2 = '1' AND Count_precharge(2) >= 2) OR | |
|
1016 | (Burst_length_4 = '1' AND Count_precharge(2) >= 4) OR | |
|
1017 | (Burst_length_8 = '1' AND Count_precharge(2) >= 8))) OR | |
|
1018 | (RW_interrupt_read(2) = '1')) THEN | |
|
1019 | Pc_b2 := '1'; | |
|
1020 | Act_b2 := '0'; | |
|
1021 | RP_chk2 := NOW; | |
|
1022 | Auto_precharge(2) := '0'; | |
|
1023 | Read_precharge(2) := '0'; | |
|
1024 | RW_interrupt_read(2) := '0'; | |
|
1025 | END IF; | |
|
1026 | END IF; | |
|
1027 | IF ((Auto_precharge(3) = '1') AND (Read_precharge(3) = '1')) THEN | |
|
1028 | IF (((NOW - RAS_chk3 >= tRAS) AND | |
|
1029 | ((Burst_length_1 = '1' AND Count_precharge(3) >= 1) OR | |
|
1030 | (Burst_length_2 = '1' AND Count_precharge(3) >= 2) OR | |
|
1031 | (Burst_length_4 = '1' AND Count_precharge(3) >= 4) OR | |
|
1032 | (Burst_length_8 = '1' AND Count_precharge(3) >= 8))) OR | |
|
1033 | (RW_interrupt_read(3) = '1')) THEN | |
|
1034 | Pc_b3 := '1'; | |
|
1035 | Act_b3 := '0'; | |
|
1036 | RP_chk3 := NOW; | |
|
1037 | Auto_precharge(3) := '0'; | |
|
1038 | Read_precharge(3) := '0'; | |
|
1039 | RW_interrupt_read(3) := '0'; | |
|
1040 | END IF; | |
|
1041 | END IF; | |
|
1042 | ||
|
1043 | -- Internal Precharge or Bst | |
|
1044 | IF Command(0) = PRECH THEN -- PRECH terminate a read if same bank or all banks | |
|
1045 | IF Bank_precharge(0) = Bank OR A10_precharge(0) = '1' THEN | |
|
1046 | IF Data_out_enable = '1' THEN | |
|
1047 | Data_out_enable := '0'; | |
|
1048 | END IF; | |
|
1049 | END IF; | |
|
1050 | ELSIF Command(0) = BST THEN -- BST terminate a read regardless of bank | |
|
1051 | IF Data_out_enable = '1' THEN | |
|
1052 | Data_out_enable := '0'; | |
|
1053 | END IF; | |
|
1054 | END IF; | |
|
1055 | ||
|
1056 | IF Data_out_enable = '0' THEN | |
|
1057 | Dq <= TRANSPORT (OTHERS => 'Z') AFTER tOH; | |
|
1058 | END IF; | |
|
1059 | ||
|
1060 | -- Detect Read or Write Command | |
|
1061 | IF Command(0) = READ OR Command(0) = READ_A THEN | |
|
1062 | Bank := Bank_addr (0); | |
|
1063 | Col := Col_addr (0); | |
|
1064 | Col_brst := Col_addr (0); | |
|
1065 | IF Bank_addr (0) = "00" THEN | |
|
1066 | Row := B0_row_addr; | |
|
1067 | ELSIF Bank_addr (0) = "01" THEN | |
|
1068 | Row := B1_row_addr; | |
|
1069 | ELSIF Bank_addr (0) = "10" THEN | |
|
1070 | Row := B2_row_addr; | |
|
1071 | ELSE | |
|
1072 | Row := B3_row_addr; | |
|
1073 | END IF; | |
|
1074 | Burst_counter := 0; | |
|
1075 | Data_in_enable := '0'; | |
|
1076 | Data_out_enable := '1'; | |
|
1077 | ELSIF Command(0) = WRITE OR Command(0) = WRITE_A THEN | |
|
1078 | Bank := Bank_addr(0); | |
|
1079 | Col := Col_addr(0); | |
|
1080 | Col_brst := Col_addr(0); | |
|
1081 | IF Bank_addr (0) = "00" THEN | |
|
1082 | Row := B0_row_addr; | |
|
1083 | ELSIF Bank_addr (0) = "01" THEN | |
|
1084 | Row := B1_row_addr; | |
|
1085 | ELSIF Bank_addr (0) = "10" THEN | |
|
1086 | Row := B2_row_addr; | |
|
1087 | ELSE | |
|
1088 | Row := B3_row_addr; | |
|
1089 | END IF; | |
|
1090 | Burst_counter := 0; | |
|
1091 | Data_in_enable := '1'; | |
|
1092 | Data_out_enable := '0'; | |
|
1093 | END IF; | |
|
1094 | ||
|
1095 | -- DQ (Driver / Receiver) | |
|
1096 | Row_index := TO_INTEGER (Row); | |
|
1097 | Col_index := TO_INTEGER (Col); | |
|
1098 | IF Data_in_enable = '1' THEN | |
|
1099 | IF Dqm /= "11" THEN | |
|
1100 | Init_mem (Bank, Row_index); | |
|
1101 | IF Bank = "00" THEN | |
|
1102 | Dq_temp := Bank0 (Row_index) (Col_index); | |
|
1103 | IF Dqm = "01" THEN | |
|
1104 | Dq_temp (15 DOWNTO 8) := TO_BITVECTOR (Dq (15 DOWNTO 8)); | |
|
1105 | ELSIF Dqm = "10" THEN | |
|
1106 | Dq_temp (7 DOWNTO 0) := TO_BITVECTOR (Dq (7 DOWNTO 0)); | |
|
1107 | ELSE | |
|
1108 | Dq_temp (15 DOWNTO 0) := TO_BITVECTOR (Dq (15 DOWNTO 0)); | |
|
1109 | END IF; | |
|
1110 | Bank0 (Row_index) (Col_index) := ('1' & Dq_temp(data_bits - 1 DOWNTO 0)); | |
|
1111 | ELSIF Bank = "01" THEN | |
|
1112 | Dq_temp := Bank1 (Row_index) (Col_index); | |
|
1113 | IF Dqm = "01" THEN | |
|
1114 | Dq_temp (15 DOWNTO 8) := TO_BITVECTOR (Dq (15 DOWNTO 8)); | |
|
1115 | ELSIF Dqm = "10" THEN | |
|
1116 | Dq_temp (7 DOWNTO 0) := TO_BITVECTOR (Dq (7 DOWNTO 0)); | |
|
1117 | ELSE | |
|
1118 | Dq_temp (15 DOWNTO 0) := TO_BITVECTOR (Dq (15 DOWNTO 0)); | |
|
1119 | END IF; | |
|
1120 | Bank1 (Row_index) (Col_index) := ('1' & Dq_temp(data_bits - 1 DOWNTO 0)); | |
|
1121 | ELSIF Bank = "10" THEN | |
|
1122 | Dq_temp := Bank2 (Row_index) (Col_index); | |
|
1123 | IF Dqm = "01" THEN | |
|
1124 | Dq_temp (15 DOWNTO 8) := TO_BITVECTOR (Dq (15 DOWNTO 8)); | |
|
1125 | ELSIF Dqm = "10" THEN | |
|
1126 | Dq_temp (7 DOWNTO 0) := TO_BITVECTOR (Dq (7 DOWNTO 0)); | |
|
1127 | ELSE | |
|
1128 | Dq_temp (15 DOWNTO 0) := TO_BITVECTOR (Dq (15 DOWNTO 0)); | |
|
1129 | END IF; | |
|
1130 | Bank2 (Row_index) (Col_index) := ('1' & Dq_temp(data_bits - 1 DOWNTO 0)); | |
|
1131 | ELSIF Bank = "11" THEN | |
|
1132 | Dq_temp := Bank3 (Row_index) (Col_index); | |
|
1133 | IF Dqm = "01" THEN | |
|
1134 | Dq_temp (15 DOWNTO 8) := TO_BITVECTOR (Dq (15 DOWNTO 8)); | |
|
1135 | ELSIF Dqm = "10" THEN | |
|
1136 | Dq_temp (7 DOWNTO 0) := TO_BITVECTOR (Dq (7 DOWNTO 0)); | |
|
1137 | ELSE | |
|
1138 | Dq_temp (15 DOWNTO 0) := TO_BITVECTOR (Dq (15 DOWNTO 0)); | |
|
1139 | END IF; | |
|
1140 | Bank3 (Row_index) (Col_index) := ('1' & Dq_temp(data_bits - 1 DOWNTO 0)); | |
|
1141 | END IF; | |
|
1142 | WR_chkp(TO_INTEGER(Bank)) := NOW; | |
|
1143 | WR_counter(TO_INTEGER(Bank)) := 0; | |
|
1144 | END IF; | |
|
1145 | Burst_decode; | |
|
1146 | ELSIF Data_out_enable = '1' THEN | |
|
1147 | IF Dqm_reg0 /= "11" THEN | |
|
1148 | Init_mem (Bank, Row_index); | |
|
1149 | IF Bank = "00" THEN | |
|
1150 | Dq_temp := Bank0 (Row_index) (Col_index); | |
|
1151 | IF Dqm_reg0 = "00" THEN | |
|
1152 | Dq (15 DOWNTO 0) <= TRANSPORT TO_STDLOGICVECTOR (Dq_temp (15 DOWNTO 0)) AFTER tAC; | |
|
1153 | ELSIF Dqm_reg0 = "01" THEN | |
|
1154 | Dq (15 DOWNTO 8) <= TRANSPORT TO_STDLOGICVECTOR (Dq_temp (15 DOWNTO 8)) AFTER tAC; | |
|
1155 | Dq (7 DOWNTO 0) <= TRANSPORT (OTHERS => 'Z') AFTER tAC; | |
|
1156 | ELSIF Dqm_reg0 = "10" THEN | |
|
1157 | Dq (15 DOWNTO 8) <= TRANSPORT (OTHERS => 'Z') AFTER tAC; | |
|
1158 | Dq (7 DOWNTO 0) <= TRANSPORT TO_STDLOGICVECTOR (Dq_temp (7 DOWNTO 0)) AFTER tAC; | |
|
1159 | END IF; | |
|
1160 | ELSIF Bank = "01" THEN | |
|
1161 | Dq_temp := Bank1 (Row_index) (Col_index); | |
|
1162 | IF Dqm_reg0 = "00" THEN | |
|
1163 | Dq (15 DOWNTO 0) <= TRANSPORT TO_STDLOGICVECTOR (Dq_temp (15 DOWNTO 0)) AFTER tAC; | |
|
1164 | ELSIF Dqm_reg0 = "01" THEN | |
|
1165 | Dq (15 DOWNTO 8) <= TRANSPORT TO_STDLOGICVECTOR (Dq_temp (15 DOWNTO 8)) AFTER tAC; | |
|
1166 | Dq (7 DOWNTO 0) <= TRANSPORT (OTHERS => 'Z') AFTER tAC; | |
|
1167 | ELSIF Dqm_reg0 = "10" THEN | |
|
1168 | Dq (15 DOWNTO 8) <= TRANSPORT (OTHERS => 'Z') AFTER tAC; | |
|
1169 | Dq (7 DOWNTO 0) <= TRANSPORT TO_STDLOGICVECTOR (Dq_temp (7 DOWNTO 0)) AFTER tAC; | |
|
1170 | END IF; | |
|
1171 | ELSIF Bank = "10" THEN | |
|
1172 | Dq_temp := Bank2 (Row_index) (Col_index); | |
|
1173 | IF Dqm_reg0 = "00" THEN | |
|
1174 | Dq (15 DOWNTO 0) <= TRANSPORT TO_STDLOGICVECTOR (Dq_temp (15 DOWNTO 0)) AFTER tAC; | |
|
1175 | ELSIF Dqm_reg0 = "01" THEN | |
|
1176 | Dq (15 DOWNTO 8) <= TRANSPORT TO_STDLOGICVECTOR (Dq_temp (15 DOWNTO 8)) AFTER tAC; | |
|
1177 | Dq (7 DOWNTO 0) <= TRANSPORT (OTHERS => 'Z') AFTER tAC; | |
|
1178 | ELSIF Dqm_reg0 = "10" THEN | |
|
1179 | Dq (15 DOWNTO 8) <= TRANSPORT (OTHERS => 'Z') AFTER tAC; | |
|
1180 | Dq (7 DOWNTO 0) <= TRANSPORT TO_STDLOGICVECTOR (Dq_temp (7 DOWNTO 0)) AFTER tAC; | |
|
1181 | END IF; | |
|
1182 | ELSIF Bank = "11" THEN | |
|
1183 | Dq_temp := Bank3 (Row_index) (Col_index); | |
|
1184 | IF Dqm_reg0 = "00" THEN | |
|
1185 | Dq (15 DOWNTO 0) <= TRANSPORT TO_STDLOGICVECTOR (Dq_temp (15 DOWNTO 0)) AFTER tAC; | |
|
1186 | ELSIF Dqm_reg0 = "01" THEN | |
|
1187 | Dq (15 DOWNTO 8) <= TRANSPORT TO_STDLOGICVECTOR (Dq_temp (15 DOWNTO 8)) AFTER tAC; | |
|
1188 | Dq (7 DOWNTO 0) <= TRANSPORT (OTHERS => 'Z') AFTER tAC; | |
|
1189 | ELSIF Dqm_reg0 = "10" THEN | |
|
1190 | Dq (15 DOWNTO 8) <= TRANSPORT (OTHERS => 'Z') AFTER tAC; | |
|
1191 | Dq (7 DOWNTO 0) <= TRANSPORT TO_STDLOGICVECTOR (Dq_temp (7 DOWNTO 0)) AFTER tAC; | |
|
1192 | END IF; | |
|
1193 | END IF; | |
|
1194 | ELSE | |
|
1195 | Dq <= TRANSPORT (OTHERS => 'Z') AFTER tHZ; | |
|
1196 | END IF; | |
|
1197 | Burst_decode; | |
|
1198 | END IF; | |
|
1199 | ELSIF Sys_clk'event AND Sys_clk = '1' AND Load = '1' AND Dump = '0' THEN --' | |
|
1200 | Operation <= LOAD_FILE; | |
|
1201 | load := '0'; | |
|
1202 | -- ASSERT (FALSE) REPORT "Reading memory array from file. This operation may take several minutes. Please wait..." | |
|
1203 | -- SEVERITY NOTE; | |
|
1204 | WHILE NOT endfile(file_load) LOOP | |
|
1205 | readline(file_load, l); | |
|
1206 | read(l, ch); | |
|
1207 | if (ch /= 'S') or (ch /= 's') then | |
|
1208 | hread(l, rectype); | |
|
1209 | hread(l, reclen); | |
|
1210 | recaddr := (others => '0'); | |
|
1211 | case rectype is | |
|
1212 | when "0001" => | |
|
1213 | hread(l, recaddr(15 downto 0)); | |
|
1214 | when "0010" => | |
|
1215 | hread(l, recaddr(23 downto 0)); | |
|
1216 | when "0011" => | |
|
1217 | hread(l, recaddr); | |
|
1218 | recaddr(31 downto 24) := (others => '0'); | |
|
1219 | when others => next; | |
|
1220 | end case; | |
|
1221 | hread(l, recdata); | |
|
1222 | ||
|
1223 | if index < 32 then | |
|
1224 | Bank_Load := recaddr(25 downto 24); | |
|
1225 | Rows_Load := recaddr(23 downto 11); | |
|
1226 | Cols_Load := recaddr(10 downto 2); | |
|
1227 | Init_Mem (Bank_Load, To_Integer(Rows_Load)); | |
|
1228 | IF Bank_Load = "00" THEN | |
|
1229 | for i in 0 to 3 loop | |
|
1230 | Bank0 (To_Integer(Rows_Load)) (To_Integer(Cols_Load)+i) := ('1' & recdata(i*32+index to i*32+index+15)); | |
|
1231 | end loop; | |
|
1232 | ELSIF Bank_Load = "01" THEN | |
|
1233 | for i in 0 to 3 loop | |
|
1234 | Bank1 (To_Integer(Rows_Load)) (To_Integer(Cols_Load)+i) := ('1' & recdata(i*32+index to i*32+index+15)); | |
|
1235 | end loop; | |
|
1236 | ELSIF Bank_Load = "10" THEN | |
|
1237 | for i in 0 to 3 loop | |
|
1238 | Bank2 (To_Integer(Rows_Load)) (To_Integer(Cols_Load)+i) := ('1' & recdata(i*32+index to i*32+index+15)); | |
|
1239 | end loop; | |
|
1240 | ELSIF Bank_Load = "11" THEN | |
|
1241 | for i in 0 to 3 loop | |
|
1242 | Bank3 (To_Integer(Rows_Load)) (To_Integer(Cols_Load)+i) := ('1' & recdata(i*32+index to i*32+index+15)); | |
|
1243 | end loop; | |
|
1244 | END IF; | |
|
1245 | elsif(index < 1024) then | |
|
1246 | Bank_Load := recaddr(26 downto 25); | |
|
1247 | Rows_Load := recaddr(24 downto 12); | |
|
1248 | Cols_Load := recaddr(11 downto 3); | |
|
1249 | Init_Mem (Bank_Load, To_Integer(Rows_Load)); | |
|
1250 | IF Bank_Load = "00" THEN | |
|
1251 | for i in 0 to 1 loop | |
|
1252 | Bank0 (To_Integer(Rows_Load)) (To_Integer(Cols_Load)+i) := ('1' & recdata(i*64+index-32 to i*64+index-32+15)); | |
|
1253 | end loop; | |
|
1254 | ELSIF Bank_Load = "01" THEN | |
|
1255 | for i in 0 to 1 loop | |
|
1256 | Bank1 (To_Integer(Rows_Load)) (To_Integer(Cols_Load)+i) := ('1' & recdata(i*64+index-32 to i*64+index-32+15)); | |
|
1257 | end loop; | |
|
1258 | ELSIF Bank_Load = "10" THEN | |
|
1259 | for i in 0 to 1 loop | |
|
1260 | Bank2 (To_Integer(Rows_Load)) (To_Integer(Cols_Load)+i) := ('1' & recdata(i*64+index-32 to i*64+index-32+15)); | |
|
1261 | end loop; | |
|
1262 | ELSIF Bank_Load = "11" THEN | |
|
1263 | for i in 0 to 1 loop | |
|
1264 | Bank3 (To_Integer(Rows_Load)) (To_Integer(Cols_Load)+i) := ('1' & recdata(i*64+index-32 to i*64+index-32+15)); | |
|
1265 | end loop; | |
|
1266 | END IF; | |
|
1267 | else | |
|
1268 | Bank_Load := recaddr(22 downto 21); | |
|
1269 | Rows_Load := '0' & recaddr(20 downto 9); | |
|
1270 | Cols_Load := '0' & recaddr(8 downto 1); | |
|
1271 | Init_Mem (Bank_Load, To_Integer(Rows_Load)); | |
|
1272 | IF Bank_Load = "00" THEN | |
|
1273 | for i in 0 to 7 loop | |
|
1274 | Bank0 (To_Integer(Rows_Load)) (To_Integer(Cols_Load)+i) := ('1' & recdata(i*16 to i*16+15)); | |
|
1275 | end loop; | |
|
1276 | ELSIF Bank_Load = "01" THEN | |
|
1277 | for i in 0 to 7 loop | |
|
1278 | Bank1 (To_Integer(Rows_Load)) (To_Integer(Cols_Load)+i) := ('1' & recdata(i*16 to i*16+15)); | |
|
1279 | end loop; | |
|
1280 | ELSIF Bank_Load = "10" THEN | |
|
1281 | for i in 0 to 7 loop | |
|
1282 | Bank2 (To_Integer(Rows_Load)) (To_Integer(Cols_Load)+i) := ('1' & recdata(i*16 to i*16+15)); | |
|
1283 | end loop; | |
|
1284 | ELSIF Bank_Load = "11" THEN | |
|
1285 | for i in 0 to 7 loop | |
|
1286 | Bank3 (To_Integer(Rows_Load)) (To_Integer(Cols_Load)+i) := ('1' & recdata(i*16 to i*16+15)); | |
|
1287 | end loop; | |
|
1288 | END IF; | |
|
1289 | END IF; | |
|
1290 | END IF; | |
|
1291 | END LOOP; | |
|
1292 | ELSIF Sys_clk'event AND Sys_clk = '1' AND Load = '0' AND Dump = '1' THEN --' | |
|
1293 | Operation <= DUMP_FILE; | |
|
1294 | ASSERT (FALSE) REPORT "Writing memory array to file. This operation may take several minutes. Please wait..." | |
|
1295 | SEVERITY NOTE; | |
|
1296 | WRITE (l, string'("# Micron Technology, Inc. (FILE DUMP / MEMORY DUMP)")); --' | |
|
1297 | WRITELINE (file_dump, l); | |
|
1298 | WRITE (l, string'("# BA ROWS COLS DQ")); --' | |
|
1299 | WRITELINE (file_dump, l); | |
|
1300 | WRITE (l, string'("# -- ------------- --------- ----------------")); --' | |
|
1301 | WRITELINE (file_dump, l); | |
|
1302 | -- Dumping Bank 0 | |
|
1303 | FOR i IN 0 TO 2**addr_bits -1 LOOP | |
|
1304 | -- Check if ROW is NULL | |
|
1305 | IF Bank0 (i) /= NULL THEN | |
|
1306 | For j IN 0 TO 2**col_bits - 1 LOOP | |
|
1307 | -- Check if COL is NULL | |
|
1308 | NEXT WHEN Bank0 (i) (j) (data_bits) = '0'; | |
|
1309 | WRITE (l, string'("00"), right, 4); --' | |
|
1310 | WRITE (l, To_BitVector(Conv_Std_Logic_Vector(i, addr_bits)), right, addr_bits+1); | |
|
1311 | WRITE (l, To_BitVector(Conv_std_Logic_Vector(j, col_bits)), right, col_bits+1); | |
|
1312 | WRITE (l, Bank0 (i) (j) (data_bits -1 DOWNTO 0), right, data_bits+1); | |
|
1313 | WRITELINE (file_dump, l); | |
|
1314 | END LOOP; | |
|
1315 | END IF; | |
|
1316 | END LOOP; | |
|
1317 | -- Dumping Bank 1 | |
|
1318 | FOR i IN 0 TO 2**addr_bits -1 LOOP | |
|
1319 | -- Check if ROW is NULL | |
|
1320 | IF Bank1 (i) /= NULL THEN | |
|
1321 | For j IN 0 TO 2**col_bits - 1 LOOP | |
|
1322 | -- Check if COL is NULL | |
|
1323 | NEXT WHEN Bank1 (i) (j) (data_bits) = '0'; | |
|
1324 | WRITE (l, string'("01"), right, 4); --' | |
|
1325 | WRITE (l, To_BitVector(Conv_Std_Logic_Vector(i, addr_bits)), right, addr_bits+1); | |
|
1326 | WRITE (l, To_BitVector(Conv_std_Logic_Vector(j, col_bits)), right, col_bits+1); | |
|
1327 | WRITE (l, Bank1 (i) (j) (data_bits -1 DOWNTO 0), right, data_bits+1); | |
|
1328 | WRITELINE (file_dump, l); | |
|
1329 | END LOOP; | |
|
1330 | END IF; | |
|
1331 | END LOOP; | |
|
1332 | -- Dumping Bank 2 | |
|
1333 | FOR i IN 0 TO 2**addr_bits -1 LOOP | |
|
1334 | -- Check if ROW is NULL | |
|
1335 | IF Bank2 (i) /= NULL THEN | |
|
1336 | For j IN 0 TO 2**col_bits - 1 LOOP | |
|
1337 | -- Check if COL is NULL | |
|
1338 | NEXT WHEN Bank2 (i) (j) (data_bits) = '0'; | |
|
1339 | WRITE (l, string'("10"), right, 4); --' | |
|
1340 | WRITE (l, To_BitVector(Conv_Std_Logic_Vector(i, addr_bits)), right, addr_bits+1); | |
|
1341 | WRITE (l, To_BitVector(Conv_std_Logic_Vector(j, col_bits)), right, col_bits+1); | |
|
1342 | WRITE (l, Bank2 (i) (j) (data_bits -1 DOWNTO 0), right, data_bits+1); | |
|
1343 | WRITELINE (file_dump, l); | |
|
1344 | END LOOP; | |
|
1345 | END IF; | |
|
1346 | END LOOP; | |
|
1347 | -- Dumping Bank 3 | |
|
1348 | FOR i IN 0 TO 2**addr_bits -1 LOOP | |
|
1349 | -- Check if ROW is NULL | |
|
1350 | IF Bank3 (i) /= NULL THEN | |
|
1351 | For j IN 0 TO 2**col_bits - 1 LOOP | |
|
1352 | -- Check if COL is NULL | |
|
1353 | NEXT WHEN Bank3 (i) (j) (data_bits) = '0'; | |
|
1354 | WRITE (l, string'("11"), right, 4); --' | |
|
1355 | WRITE (l, To_BitVector(Conv_Std_Logic_Vector(i, addr_bits)), right, addr_bits+1); | |
|
1356 | WRITE (l, To_BitVector(Conv_std_Logic_Vector(j, col_bits)), right, col_bits+1); | |
|
1357 | WRITE (l, Bank3 (i) (j) (data_bits -1 DOWNTO 0), right, data_bits+1); | |
|
1358 | WRITELINE (file_dump, l); | |
|
1359 | END LOOP; | |
|
1360 | END IF; | |
|
1361 | END LOOP; | |
|
1362 | END IF; | |
|
1363 | ||
|
1364 | -- Write with AutoPrecharge Calculation | |
|
1365 | -- The device start internal precharge when: | |
|
1366 | -- 1. tWR cycles after command | |
|
1367 | -- and 2. Meet tRAS requirement | |
|
1368 | -- or 3. Interrupt by a Read or Write (with or without Auto Precharge) | |
|
1369 | IF ((Auto_precharge(0) = '1') AND (Write_precharge(0) = '1')) THEN | |
|
1370 | IF (((NOW - RAS_chk0 >= tRAS) AND | |
|
1371 | (((Burst_length_1 = '1' OR Write_burst_mode = '1' ) AND Count_precharge(0) >= 1 AND NOW - Count_time(0) >= tWRa) OR | |
|
1372 | (Burst_length_2 = '1' AND Count_precharge(0) >= 2 AND NOW - Count_time(0) >= tWRa) OR | |
|
1373 | (Burst_length_4 = '1' AND Count_precharge(0) >= 4 AND NOW - Count_time(0) >= tWRa) OR | |
|
1374 | (Burst_length_8 = '1' AND Count_precharge(0) >= 8 AND NOW - Count_time(0) >= tWRa))) OR | |
|
1375 | (RW_interrupt_write(0) = '1' AND WR_counter(0) >= 1 AND NOW - WR_time(0) >= tWRa)) THEN | |
|
1376 | Auto_precharge(0) := '0'; | |
|
1377 | Write_precharge(0) := '0'; | |
|
1378 | RW_interrupt_write(0) := '0'; | |
|
1379 | Pc_b0 := '1'; | |
|
1380 | Act_b0 := '0'; | |
|
1381 | RP_chk0 := NOW; | |
|
1382 | ASSERT FALSE REPORT "Start Internal Precharge Bank 0" SEVERITY NOTE; | |
|
1383 | END IF; | |
|
1384 | END IF; | |
|
1385 | IF ((Auto_precharge(1) = '1') AND (Write_precharge(1) = '1')) THEN | |
|
1386 | IF (((NOW - RAS_chk1 >= tRAS) AND | |
|
1387 | (((Burst_length_1 = '1' OR Write_burst_mode = '1' ) AND Count_precharge(1) >= 1 AND NOW - Count_time(1) >= tWRa) OR | |
|
1388 | (Burst_length_2 = '1' AND Count_precharge(1) >= 2 AND NOW - Count_time(1) >= tWRa) OR | |
|
1389 | (Burst_length_4 = '1' AND Count_precharge(1) >= 4 AND NOW - Count_time(1) >= tWRa) OR | |
|
1390 | (Burst_length_8 = '1' AND Count_precharge(1) >= 8 AND NOW - Count_time(1) >= tWRa))) OR | |
|
1391 | (RW_interrupt_write(1) = '1' AND WR_counter(1) >= 1 AND NOW - WR_time(1) >= tWRa)) THEN | |
|
1392 | Auto_precharge(1) := '0'; | |
|
1393 | Write_precharge(1) := '0'; | |
|
1394 | RW_interrupt_write(1) := '0'; | |
|
1395 | Pc_b1 := '1'; | |
|
1396 | Act_b1 := '0'; | |
|
1397 | RP_chk1 := NOW; | |
|
1398 | END IF; | |
|
1399 | END IF; | |
|
1400 | IF ((Auto_precharge(2) = '1') AND (Write_precharge(2) = '1')) THEN | |
|
1401 | IF (((NOW - RAS_chk2 >= tRAS) AND | |
|
1402 | (((Burst_length_1 = '1' OR Write_burst_mode = '1' ) AND Count_precharge(2) >= 1 AND NOW - Count_time(2) >= tWRa) OR | |
|
1403 | (Burst_length_2 = '1' AND Count_precharge(2) >= 2 AND NOW - Count_time(2) >= tWRa) OR | |
|
1404 | (Burst_length_4 = '1' AND Count_precharge(2) >= 4 AND NOW - Count_time(2) >= tWRa) OR | |
|
1405 | (Burst_length_8 = '1' AND Count_precharge(2) >= 8 AND NOW - Count_time(2) >= tWRa))) OR | |
|
1406 | (RW_interrupt_write(2) = '1' AND WR_counter(2) >= 1 AND NOW - WR_time(2) >= tWRa)) THEN | |
|
1407 | Auto_precharge(2) := '0'; | |
|
1408 | Write_precharge(2) := '0'; | |
|
1409 | RW_interrupt_write(2) := '0'; | |
|
1410 | Pc_b2 := '1'; | |
|
1411 | Act_b2 := '0'; | |
|
1412 | RP_chk2 := NOW; | |
|
1413 | END IF; | |
|
1414 | END IF; | |
|
1415 | IF ((Auto_precharge(3) = '1') AND (Write_precharge(3) = '1')) THEN | |
|
1416 | IF (((NOW - RAS_chk3 >= tRAS) AND | |
|
1417 | (((Burst_length_1 = '1' OR Write_burst_mode = '1' ) AND Count_precharge(3) >= 1 AND NOW - Count_time(3) >= tWRa) OR | |
|
1418 | (Burst_length_2 = '1' AND Count_precharge(3) >= 2 AND NOW - Count_time(3) >= tWRa) OR | |
|
1419 | (Burst_length_4 = '1' AND Count_precharge(3) >= 4 AND NOW - Count_time(3) >= tWRa) OR | |
|
1420 | (Burst_length_8 = '1' AND Count_precharge(3) >= 8 AND NOW - Count_time(3) >= tWRa))) OR | |
|
1421 | (RW_interrupt_write(0) = '1' AND WR_counter(0) >= 1 AND NOW - WR_time(3) >= tWRa)) THEN | |
|
1422 | Auto_precharge(3) := '0'; | |
|
1423 | Write_precharge(3) := '0'; | |
|
1424 | RW_interrupt_write(3) := '0'; | |
|
1425 | Pc_b3 := '1'; | |
|
1426 | Act_b3 := '0'; | |
|
1427 | RP_chk3 := NOW; | |
|
1428 | END IF; | |
|
1429 | END IF; | |
|
1430 | ||
|
1431 | -- Checking internal wires (Optional for debug purpose) | |
|
1432 | Pre_chk (0) <= Pc_b0; | |
|
1433 | Pre_chk (1) <= Pc_b1; | |
|
1434 | Pre_chk (2) <= Pc_b2; | |
|
1435 | Pre_chk (3) <= Pc_b3; | |
|
1436 | Act_chk (0) <= Act_b0; | |
|
1437 | Act_chk (1) <= Act_b1; | |
|
1438 | Act_chk (2) <= Act_b2; | |
|
1439 | Act_chk (3) <= Act_b3; | |
|
1440 | Dq_in_chk <= Data_in_enable; | |
|
1441 | Dq_out_chk <= Data_out_enable; | |
|
1442 | Bank_chk <= Bank; | |
|
1443 | Row_chk <= Row; | |
|
1444 | Col_chk <= Col; | |
|
1445 | END PROCESS; | |
|
1446 | ||
|
1447 | ||
|
1448 | -- Clock timing checks | |
|
1449 | -- Clock_check : PROCESS | |
|
1450 | -- VARIABLE Clk_low, Clk_high : TIME := 0 ns; | |
|
1451 | -- BEGIN | |
|
1452 | -- WAIT ON Clk; | |
|
1453 | -- IF (Clk = '1' AND NOW >= 10 ns) THEN | |
|
1454 | -- ASSERT (NOW - Clk_low >= tCL) | |
|
1455 | -- REPORT "tCL violation" | |
|
1456 | -- SEVERITY WARNING; | |
|
1457 | -- ASSERT (NOW - Clk_high >= tCK) | |
|
1458 | -- REPORT "tCK violation" | |
|
1459 | -- SEVERITY WARNING; | |
|
1460 | -- Clk_high := NOW; | |
|
1461 | -- ELSIF (Clk = '0' AND NOW /= 0 ns) THEN | |
|
1462 | -- ASSERT (NOW - Clk_high >= tCH) | |
|
1463 | -- REPORT "tCH violation" | |
|
1464 | -- SEVERITY WARNING; | |
|
1465 | -- Clk_low := NOW; | |
|
1466 | -- END IF; | |
|
1467 | -- END PROCESS; | |
|
1468 | ||
|
1469 | -- Setup timing checks | |
|
1470 | Setup_check : PROCESS | |
|
1471 | BEGIN | |
|
1472 | wait; | |
|
1473 | WAIT ON Clk; | |
|
1474 | IF Clk = '1' THEN | |
|
1475 | ASSERT(Cke'LAST_EVENT >= tCKS) --' | |
|
1476 | REPORT "CKE Setup time violation -- tCKS" | |
|
1477 | SEVERITY WARNING; | |
|
1478 | ASSERT(Cs_n'LAST_EVENT >= tCMS) --' | |
|
1479 | REPORT "CS# Setup time violation -- tCMS" | |
|
1480 | SEVERITY WARNING; | |
|
1481 | ASSERT(Cas_n'LAST_EVENT >= tCMS) --' | |
|
1482 | REPORT "CAS# Setup time violation -- tCMS" | |
|
1483 | SEVERITY WARNING; | |
|
1484 | ASSERT(Ras_n'LAST_EVENT >= tCMS) --' | |
|
1485 | REPORT "RAS# Setup time violation -- tCMS" | |
|
1486 | SEVERITY WARNING; | |
|
1487 | ASSERT(We_n'LAST_EVENT >= tCMS) --' | |
|
1488 | REPORT "WE# Setup time violation -- tCMS" | |
|
1489 | SEVERITY WARNING; | |
|
1490 | ASSERT(Dqm'LAST_EVENT >= tCMS) --' | |
|
1491 | REPORT "Dqm Setup time violation -- tCMS" | |
|
1492 | SEVERITY WARNING; | |
|
1493 | ASSERT(Addr'LAST_EVENT >= tAS) --' | |
|
1494 | REPORT "ADDR Setup time violation -- tAS" | |
|
1495 | SEVERITY WARNING; | |
|
1496 | ASSERT(Ba'LAST_EVENT >= tAS) --' | |
|
1497 | REPORT "BA Setup time violation -- tAS" | |
|
1498 | SEVERITY WARNING; | |
|
1499 | ASSERT(Dq'LAST_EVENT >= tDS) --' | |
|
1500 | REPORT "Dq Setup time violation -- tDS" | |
|
1501 | SEVERITY WARNING; | |
|
1502 | END IF; | |
|
1503 | END PROCESS; | |
|
1504 | ||
|
1505 | -- Hold timing checks | |
|
1506 | Hold_check : PROCESS | |
|
1507 | BEGIN | |
|
1508 | wait; | |
|
1509 | WAIT ON Clk'DELAYED (tCKH), Clk'DELAYED (tCMH), Clk'DELAYED (tAH), Clk'DELAYED (tDH); | |
|
1510 | IF Clk'DELAYED (tCKH) = '1' THEN --' | |
|
1511 | ASSERT(Cke'LAST_EVENT > tCKH) --' | |
|
1512 | REPORT "CKE Hold time violation -- tCKH" | |
|
1513 | SEVERITY WARNING; | |
|
1514 | END IF; | |
|
1515 | IF Clk'DELAYED (tCMH) = '1' THEN --' | |
|
1516 | ASSERT(Cs_n'LAST_EVENT > tCMH) --' | |
|
1517 | REPORT "CS# Hold time violation -- tCMH" | |
|
1518 | SEVERITY WARNING; | |
|
1519 | ASSERT(Cas_n'LAST_EVENT > tCMH) --' | |
|
1520 | REPORT "CAS# Hold time violation -- tCMH" | |
|
1521 | SEVERITY WARNING; | |
|
1522 | ASSERT(Ras_n'LAST_EVENT > tCMH) --' | |
|
1523 | REPORT "RAS# Hold time violation -- tCMH" | |
|
1524 | SEVERITY WARNING; | |
|
1525 | ASSERT(We_n'LAST_EVENT > tCMH) --' | |
|
1526 | REPORT "WE# Hold time violation -- tCMH" | |
|
1527 | SEVERITY WARNING; | |
|
1528 | ASSERT(Dqm'LAST_EVENT > tCMH) --' | |
|
1529 | REPORT "Dqm Hold time violation -- tCMH" | |
|
1530 | SEVERITY WARNING; | |
|
1531 | END IF; | |
|
1532 | IF Clk'DELAYED (tAH) = '1' THEN --' | |
|
1533 | ASSERT(Addr'LAST_EVENT > tAH) --' | |
|
1534 | REPORT "ADDR Hold time violation -- tAH" | |
|
1535 | SEVERITY WARNING; | |
|
1536 | ASSERT(Ba'LAST_EVENT > tAH) --' | |
|
1537 | REPORT "BA Hold time violation -- tAH" | |
|
1538 | SEVERITY WARNING; | |
|
1539 | END IF; | |
|
1540 | IF Clk'DELAYED (tDH) = '1' THEN --' | |
|
1541 | ASSERT(Dq'LAST_EVENT > tDH) --' | |
|
1542 | REPORT "Dq Hold time violation -- tDH" | |
|
1543 | SEVERITY WARNING; | |
|
1544 | END IF; | |
|
1545 | END PROCESS; | |
|
1546 | ||
|
1547 | END behave; | |
|
1548 | ||
|
1549 | -- pragma translate_on | |
|
1550 |
@@ -0,0 +1,69 | |||
|
1 | <?xml version='1.0' encoding='utf-8'?> | |
|
2 | <soc name="Leon"> | |
|
3 | <peripheral vid="8" name="SpaceWire Light" pid="305"> | |
|
4 | <register name="Control register" addOffset="0"> | |
|
5 | <bitField size="1" offset="0" name="Reset" mode="3" desc="Write '1' to reset SPWAMBA core (auto-clear)."/> | |
|
6 | <bitField size="1" offset="1" name="Reset DMA" mode="3" desc="Write '1' to reset DMA engines (auto-clear)."/> | |
|
7 | <bitField name="Link Start" offset="2" size="1" mode="3" desc="Link start signal. '1' = actively try to start a SpaceWire link."/> | |
|
8 | <bitField name="Link Auto Start" offset="3" size="1" mode="3" desc="Link autostart signal. '1' = start link after receiving NULL from other side."/> | |
|
9 | <bitField name="Link Disable" offset="4" size="1" mode="3" desc="Link disable signal. '1' = shut down current link and do not establish new link."/> | |
|
10 | <bitField name="Time Code EN" offset="5" size="1" mode="3" desc="Allow time-code transmission through tick_in signal."/> | |
|
11 | <bitField name="Restart RX DMA" offset="6" size="1" mode="3" desc="Write '1' to (re-)start RX DMA (auto-clear)."/> | |
|
12 | <bitField name="Restart TX DMA" offset="7" size="1" mode="3" desc="Write '1' to (re-)start TX DMA (auto-clear)."/> | |
|
13 | <bitField name="Cancel TX DMA" offset="8" size="1" mode="3" desc="Write '1' to cancel running TX DMA and discard data from TX FIFO (auto-clear)."/> | |
|
14 | <bitField name="Link Up/Down IE" offset="9" size="1" mode="3" desc="Enable interrupt on link up/down."/> | |
|
15 | <bitField name="Time Code IE" offset="10" size="1" mode="3" desc="Enable interrupt on time code received."/> | |
|
16 | <bitField name="RXDESCIE" offset="11" size="1" mode="3" desc="Enable interrupt on completed RX descriptor with IE='1'."/> | |
|
17 | <bitField name="TXDESCIE" offset="12" size="1" mode="3" desc="Enable interrupt on completed TX descriptor with IE='1'."/> | |
|
18 | <bitField name="RXIE" offset="13" size="1" mode="3" desc="Enable interrupt on RX packet received."/> | |
|
19 | <bitField name="DescSz" offset="24" size="4" mode="1" desc="Value of desctablesize generic (read-only)."/> | |
|
20 | </register> | |
|
21 | <register name="Status register" addOffset="4"> | |
|
22 | <bitField size="2" offset="0" name="LSTAT" mode="1" desc="Link status: 0=off, 1=started, 2=connecting, 3=run (read-only)."/> | |
|
23 | <bitField size="1" offset="2" name="DISCERR" mode="3" desc="Got disconnect error (sticky, write '1' to clear)."/> | |
|
24 | <bitField size="1" offset="3" name="PARERR" mode="3" desc="Got parity error (sticky, write '1' to clear)."/> | |
|
25 | <bitField size="1" offset="4" name="ESCERR" mode="3" desc="Got escape error (sticky, write '1' to clear)."/> | |
|
26 | <bitField size="1" offset="5" name="CREDERR" mode="3" desc="Got credit error (sticky, write '1' to clear)."/> | |
|
27 | <bitField size="1" offset="6" name="RXDMA" mode="1" desc="RX DMA running (read-only)."/> | |
|
28 | <bitField size="1" offset="7" name="RXDMA" mode="1" desc="TX DMA running (read-only)."/> | |
|
29 | <bitField size="1" offset="8" name="AHBERR" mode="1" desc="AHB error occurred (sticky, reset DMA engine to clear)."/> | |
|
30 | <bitField size="1" offset="9" name="UNUSED" mode="3" desc="unused"/> | |
|
31 | <bitField size="1" offset="10" name="TIMECODE" mode="3" desc="Received time-code (sticky, write '1' to clear)."/> | |
|
32 | <bitField size="1" offset="11" name="RXDESCCOMP" mode="3" desc="Completed RX descriptor with IE='1' (sticky, write '1' to clear)."/> | |
|
33 | <bitField size="1" offset="12" name="TXDESCCOMP" mode="3" desc="Completed TX descriptor with IE='1' (sticky, write '1' to clear)."/> | |
|
34 | <bitField size="1" offset="13" name="RECPACKT" mode="3" desc="Received packet (sticky, write '1' to clear)."/> | |
|
35 | <bitField size="1" offset="14" name="RXE" mode="1" desc="RX buffer is empty and last packet has been completely transfered to RX DMA (read-only)."/> | |
|
36 | </register> | |
|
37 | <register name="Transmission clock scaler" addOffset="8"> | |
|
38 | <bitField size="8" offset="0" name="N" mode="3" desc="Clock division factor minus 1. The actual TX bit rate is determined by (txclk frequency) / (scaler + 1). | |
|
39 | During the handshake phase, this register is ignored and the TX bit rate is forced to 10 Mbit. After reset, this | |
|
40 | register defaults to the scaler value needed for 10 Mbit."/> | |
|
41 | </register> | |
|
42 | <register name="Time-code register" addOffset="12"> | |
|
43 | <bitField size="6" offset="0" name="Address" mode="1" desc="Last received time-code value (read-only)."/> | |
|
44 | <bitField size="2" offset="6" name="Address" mode="1" desc="Control bits received with last time-code (read-only)."/> | |
|
45 | <bitField size="6" offset="12" name="Address" mode="3" desc="Time-code value to send on next tick_in (auto-increment)."/> | |
|
46 | <bitField size="2" offset="14" name="Address" mode="3" desc="Reserved, write as zero."/> | |
|
47 | <bitField size="1" offset="15" name="Address" mode="3" desc="Write '1' to send a time-code immediately (auto-clear)."/> | |
|
48 | </register> | |
|
49 | <register name="Descriptor pointer for RX DMA" addOffset="16"> | |
|
50 | <bitField size="3" offset="0" name="DATA" mode="3" desc="Reserved, write as zero."/> | |
|
51 | <bitField size="10" offset="3" name="DATA" mode="3" desc="Descriptor index (auto-increment)."/> | |
|
52 | <bitField size="19" offset="13" name="DATA" mode="3" desc="Fixed address bits of descriptor table."/> | |
|
53 | </register> | |
|
54 | <register name="Descriptor pointer for TX DMA" addOffset="20"> | |
|
55 | <bitField size="3" offset="0" name="DATA" mode="3" desc="Reserved, write as zero."/> | |
|
56 | <bitField size="10" offset="3" name="DATA" mode="3" desc="Descriptor index (auto-increment)."/> | |
|
57 | <bitField size="19" offset="13" name="DATA" mode="3" desc="Fixed address bits of descriptor table."/> | |
|
58 | </register> | |
|
59 | </peripheral> | |
|
60 | </soc> | |
|
61 | ||
|
62 | ||
|
63 | ||
|
64 | ||
|
65 | ||
|
66 | ||
|
67 | ||
|
68 | ||
|
69 |
This diff has been collapsed as it changes many lines, (1053 lines changed) Show them Hide them | |||
@@ -0,0 +1,1053 | |||
|
1 | ------------------------------------------------------------------------------ | |
|
2 | -- This file is a part of the GRLIB VHDL IP LIBRARY | |
|
3 | -- Copyright (C) 2003 - 2008, Gaisler Research | |
|
4 | -- Copyright (C) 2008 - 2014, Aeroflex Gaisler | |
|
5 | -- Copyright (C) 2015 - 2016, Cobham Gaisler | |
|
6 | -- | |
|
7 | -- This program is free software; you can redistribute it and/or modify | |
|
8 | -- it under the terms of the GNU General Public License as published by | |
|
9 | -- the Free Software Foundation; either version 2 of the License, or | |
|
10 | -- (at your option) any later version. | |
|
11 | -- | |
|
12 | -- This program is distributed in the hope that it will be useful, | |
|
13 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of | |
|
14 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
|
15 | -- GNU General Public License for more details. | |
|
16 | -- | |
|
17 | -- You should have received a copy of the GNU General Public License | |
|
18 | -- along with this program; if not, write to the Free Software | |
|
19 | -- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
|
20 | ----------------------------------------------------------------------------- | |
|
21 | -- Entity: sdctrl16 | |
|
22 | -- File: sdctrl16.vhd | |
|
23 | -- Author: Jiri Gaisler - Gaisler Research | |
|
24 | -- Modified by: Daniel Bengtsson & Richard Fång | |
|
25 | -- Description: 16- and 32-bit SDRAM memory controller. | |
|
26 | ------------------------------------------------------------------------------ | |
|
27 | ||
|
28 | library ieee; | |
|
29 | use ieee.std_logic_1164.all; | |
|
30 | library grlib; | |
|
31 | use grlib.amba.all; | |
|
32 | use grlib.stdlib.all; | |
|
33 | library gaisler; | |
|
34 | use grlib.devices.all; | |
|
35 | use gaisler.memctrl.all; | |
|
36 | ||
|
37 | entity sdctrl16 is | |
|
38 | generic ( | |
|
39 | hindex : integer := 0; | |
|
40 | haddr : integer := 0; | |
|
41 | hmask : integer := 16#f00#; | |
|
42 | ioaddr : integer := 16#000#; | |
|
43 | iomask : integer := 16#fff#; | |
|
44 | wprot : integer := 0; | |
|
45 | invclk : integer := 0; | |
|
46 | fast : integer := 0; | |
|
47 | pwron : integer := 0; | |
|
48 | sdbits : integer := 16; | |
|
49 | oepol : integer := 0; | |
|
50 | pageburst : integer := 0; | |
|
51 | mobile : integer := 0 | |
|
52 | ); | |
|
53 | port ( | |
|
54 | rst : in std_ulogic; | |
|
55 | clk : in std_ulogic; | |
|
56 | ahbsi : in ahb_slv_in_type; | |
|
57 | ahbso : out ahb_slv_out_type; | |
|
58 | sdi : in sdctrl_in_type; | |
|
59 | sdo : out sdctrl_out_type | |
|
60 | ); | |
|
61 | end; | |
|
62 | ||
|
63 | architecture rtl of sdctrl16 is | |
|
64 | ||
|
65 | constant WPROTEN : boolean := wprot = 1; | |
|
66 | constant SDINVCLK : boolean := invclk = 1; | |
|
67 | constant BUS16 : boolean := (sdbits = 16); | |
|
68 | constant BUS32 : boolean := (sdbits = 32); | |
|
69 | constant BUS64 : boolean := (sdbits = 64); | |
|
70 | ||
|
71 | constant REVISION : integer := 1; | |
|
72 | ||
|
73 | constant PM_PD : std_logic_vector(2 downto 0) := "001"; | |
|
74 | constant PM_SR : std_logic_vector(2 downto 0) := "010"; | |
|
75 | constant PM_DPD : std_logic_vector(2 downto 0) := "101"; | |
|
76 | ||
|
77 | constant std_rammask: Std_Logic_Vector(31 downto 20) := | |
|
78 | Conv_Std_Logic_Vector(hmask, 12); | |
|
79 | ||
|
80 | constant hconfig : ahb_config_type := ( | |
|
81 | 0 => ahb_device_reg ( VENDOR_GAISLER, GAISLER_SDCTRL, 0, REVISION, 0), | |
|
82 | 4 => ahb_membar(haddr, '1', '1', hmask), | |
|
83 | 5 => ahb_iobar(ioaddr, iomask), | |
|
84 | others => zero32); | |
|
85 | ||
|
86 | type mcycletype is (midle, active, leadout); | |
|
87 | type sdcycletype is (act1, act2, act3, act3_16, rd1, rd2, rd3, rd4, rd4_16, rd5, rd6, rd7, rd8, | |
|
88 | wr1, wr1_16, wr2, wr3, wr4, wr5, sidle, | |
|
89 | sref, pd, dpd); | |
|
90 | type icycletype is (iidle, pre, ref, lmode, emode, finish); | |
|
91 | ||
|
92 | -- sdram configuration register | |
|
93 | ||
|
94 | type sdram_cfg_type is record | |
|
95 | command : std_logic_vector(2 downto 0); | |
|
96 | csize : std_logic_vector(1 downto 0); | |
|
97 | bsize : std_logic_vector(2 downto 0); | |
|
98 | casdel : std_ulogic; -- CAS to data delay: 2/3 clock cycles | |
|
99 | trfc : std_logic_vector(2 downto 0); | |
|
100 | trp : std_ulogic; -- precharge to activate: 2/3 clock cycles | |
|
101 | refresh : std_logic_vector(14 downto 0); | |
|
102 | renable : std_ulogic; | |
|
103 | pageburst : std_ulogic; | |
|
104 | mobileen : std_logic_vector(1 downto 0); -- Mobile SD support, Mobile SD enabled | |
|
105 | ds : std_logic_vector(3 downto 0); -- ds(1:0) (ds(3:2) used to detect update) | |
|
106 | tcsr : std_logic_vector(3 downto 0); -- tcrs(1:0) (tcrs(3:2) used to detect update) | |
|
107 | pasr : std_logic_vector(5 downto 0); -- pasr(2:0) (pasr(5:3) used to detect update) | |
|
108 | pmode : std_logic_vector(2 downto 0); -- Power-Saving mode | |
|
109 | txsr : std_logic_vector(3 downto 0); -- Exit Self Refresh timing | |
|
110 | cke : std_ulogic; -- Clock enable | |
|
111 | end record; | |
|
112 | ||
|
113 | -- local registers | |
|
114 | ||
|
115 | type reg_type is record | |
|
116 | hready : std_ulogic; | |
|
117 | hsel : std_ulogic; | |
|
118 | bdrive : std_ulogic; | |
|
119 | nbdrive : std_ulogic; | |
|
120 | burst : std_ulogic; | |
|
121 | wprothit : std_ulogic; | |
|
122 | hio : std_ulogic; | |
|
123 | startsd : std_ulogic; | |
|
124 | lhw : std_ulogic; --Lower halfword | |
|
125 | ||
|
126 | mstate : mcycletype; | |
|
127 | sdstate : sdcycletype; | |
|
128 | cmstate : mcycletype; | |
|
129 | istate : icycletype; | |
|
130 | icnt : std_logic_vector(2 downto 0); | |
|
131 | ||
|
132 | haddr : std_logic_vector(31 downto 0); | |
|
133 | hrdata : std_logic_vector((sdbits-1)+((16/sdbits)*16) downto 0); | |
|
134 | hwdata : std_logic_vector(31 downto 0); | |
|
135 | hwrite : std_ulogic; | |
|
136 | htrans : std_logic_vector(1 downto 0); | |
|
137 | hresp : std_logic_vector(1 downto 0); | |
|
138 | size : std_logic_vector(1 downto 0); | |
|
139 | ||
|
140 | cfg : sdram_cfg_type; | |
|
141 | trfc : std_logic_vector(3 downto 0); | |
|
142 | refresh : std_logic_vector(14 downto 0); | |
|
143 | sdcsn : std_logic_vector(1 downto 0); | |
|
144 | sdwen : std_ulogic; | |
|
145 | rasn : std_ulogic; | |
|
146 | casn : std_ulogic; | |
|
147 | dqm : std_logic_vector(7 downto 0); | |
|
148 | address : std_logic_vector(16 downto 2); -- memory address | |
|
149 | bsel : std_ulogic; | |
|
150 | ||
|
151 | idlecnt : std_logic_vector(3 downto 0); -- Counter, 16 idle clock sycles before entering Power-Saving mode | |
|
152 | sref_tmpcom : std_logic_vector(2 downto 0); -- Save SD command when exit sref | |
|
153 | end record; | |
|
154 | ||
|
155 | signal r, ri : reg_type; | |
|
156 | signal rbdrive, ribdrive : std_logic_vector(31 downto 0); | |
|
157 | attribute syn_preserve : boolean; | |
|
158 | attribute syn_preserve of rbdrive : signal is true; | |
|
159 | ||
|
160 | begin | |
|
161 | ||
|
162 | ctrl : process(rst, ahbsi, r, sdi, rbdrive) | |
|
163 | variable v : reg_type; -- local variables for registers | |
|
164 | variable startsd : std_ulogic; | |
|
165 | variable dataout : std_logic_vector(31 downto 0); -- data from memory | |
|
166 | variable regsd : std_logic_vector(31 downto 0); -- data from registers | |
|
167 | variable dqm : std_logic_vector(7 downto 0); | |
|
168 | variable raddr : std_logic_vector(12 downto 0); | |
|
169 | variable adec : std_ulogic; | |
|
170 | variable rams : std_logic_vector(1 downto 0); | |
|
171 | variable ba : std_logic_vector(1 downto 0); | |
|
172 | variable haddr : std_logic_vector(31 downto 0); | |
|
173 | variable dout : std_logic_vector(31 downto 0); | |
|
174 | variable hsize : std_logic_vector(1 downto 0); | |
|
175 | variable hwrite : std_ulogic; | |
|
176 | variable htrans : std_logic_vector(1 downto 0); | |
|
177 | variable hready : std_ulogic; | |
|
178 | variable vbdrive : std_logic_vector(31 downto 0); | |
|
179 | variable bdrive : std_ulogic; | |
|
180 | variable lline : std_logic_vector(2 downto 0); | |
|
181 | variable lineburst : boolean; | |
|
182 | variable haddr_tmp : std_logic_vector(31 downto 0); | |
|
183 | variable arefresh : std_logic; | |
|
184 | variable hwdata : std_logic_vector(31 downto 0); | |
|
185 | ||
|
186 | begin | |
|
187 | ||
|
188 | -- Variable default settings to avoid latches | |
|
189 | ||
|
190 | v := r; startsd := '0'; v.hresp := HRESP_OKAY; vbdrive := rbdrive; arefresh := '0'; | |
|
191 | if BUS16 then | |
|
192 | if (r.lhw = '1') then --muxes read data to correct part of the register. | |
|
193 | v.hrdata(sdbits-1 downto 0) := sdi.data(sdbits-1 downto 0); | |
|
194 | else | |
|
195 | v.hrdata((sdbits*2)-1 downto sdbits) := sdi.data(sdbits-1 downto 0); | |
|
196 | end if; | |
|
197 | else | |
|
198 | v.hrdata(sdbits-1 downto sdbits-32) := sdi.data(sdbits-1 downto sdbits-32); | |
|
199 | v.hrdata(31 downto 0) := sdi.data(31 downto 0); | |
|
200 | end if; | |
|
201 | hwdata := ahbreadword(ahbsi.hwdata, r.haddr(4 downto 2)); v.hwdata := hwdata; | |
|
202 | lline := not r.cfg.casdel & r.cfg.casdel & r.cfg.casdel; | |
|
203 | if (pageburst = 0) or ((pageburst = 2) and r.cfg.pageburst = '0') then | |
|
204 | lineburst := true; | |
|
205 | else lineburst := false; end if; | |
|
206 | ||
|
207 | ||
|
208 | if ((ahbsi.hready and ahbsi.hsel(hindex)) = '1') then | |
|
209 | v.size := ahbsi.hsize(1 downto 0); v.hwrite := ahbsi.hwrite; | |
|
210 | v.htrans := ahbsi.htrans; | |
|
211 | if ahbsi.htrans(1) = '1' then | |
|
212 | v.hio := ahbsi.hmbsel(1); | |
|
213 | v.hsel := '1'; v.hready := v.hio; | |
|
214 | end if; | |
|
215 | v.haddr := ahbsi.haddr; | |
|
216 | -- addr must be masked since address range can be smaller than | |
|
217 | -- total banksize. this can result in wrong chip select being | |
|
218 | -- asserted | |
|
219 | for i in 31 downto 20 loop | |
|
220 | v.haddr(i) := ahbsi.haddr(i) and not std_rammask(i); | |
|
221 | end loop; | |
|
222 | end if; | |
|
223 | ||
|
224 | if (r.hsel = '1') and (ahbsi.hready = '0') then | |
|
225 | haddr := r.haddr; hsize := r.size; | |
|
226 | htrans := r.htrans; hwrite := r.hwrite; | |
|
227 | else | |
|
228 | haddr := ahbsi.haddr; hsize := ahbsi.hsize(1 downto 0); | |
|
229 | htrans := ahbsi.htrans; hwrite := ahbsi.hwrite; | |
|
230 | -- addr must be masked since address range can be smaller than | |
|
231 | -- total banksize. this can result in wrong chip select being | |
|
232 | -- asserted | |
|
233 | for i in 31 downto 20 loop | |
|
234 | haddr(i) := ahbsi.haddr(i) and not std_rammask(i); | |
|
235 | end loop; | |
|
236 | end if; | |
|
237 | if fast = 1 then haddr := r.haddr; end if; | |
|
238 | ||
|
239 | if ahbsi.hready = '1' then v.hsel := ahbsi.hsel(hindex); end if; | |
|
240 | ||
|
241 | -- main state | |
|
242 | if BUS16 then | |
|
243 | case r.size is | |
|
244 | when "00" => --bytesize | |
|
245 | case r.haddr(0) is | |
|
246 | when '0' => dqm := "11111101"; | |
|
247 | when others => dqm := "11111110"; | |
|
248 | end case; | |
|
249 | when others => dqm := "11111100"; --halfword, word | |
|
250 | end case; | |
|
251 | else | |
|
252 | case r.size is | |
|
253 | when "00" => | |
|
254 | case r.haddr(1 downto 0) is | |
|
255 | when "00" => dqm := "11110111"; | |
|
256 | when "01" => dqm := "11111011"; | |
|
257 | when "10" => dqm := "11111101"; | |
|
258 | when others => dqm := "11111110"; | |
|
259 | end case; | |
|
260 | when "01" => | |
|
261 | if r.haddr(1) = '0' then dqm := "11110011"; else dqm := "11111100"; end if; | |
|
262 | when others => dqm := "11110000"; | |
|
263 | end case; | |
|
264 | end if; | |
|
265 | -- | |
|
266 | -- case r.size is | |
|
267 | -- when "00" => | |
|
268 | -- case r.haddr(1 downto 0) is | |
|
269 | -- when "00" => dqm := "11111101"; lhw := '0'; --lhv := r.haddr(1) | |
|
270 | -- when "01" => dqm := "11111110"; lhw := '0'; | |
|
271 | -- when "10" => dqm := "11111101"; lhw := '1'; | |
|
272 | -- when others => dqm := "11111110"; lhw := '1'; | |
|
273 | -- end case; | |
|
274 | -- when "01" => | |
|
275 | -- dqm := "11111100"; | |
|
276 | -- if r.haddr(1) = '0' then | |
|
277 | -- lhw := '0'; | |
|
278 | -- else | |
|
279 | -- lhw := '1'; | |
|
280 | -- end if; | |
|
281 | -- when others => dqm := "11111100"; --remember when word: lhw first 0 then 1 | |
|
282 | -- end case; | |
|
283 | -- | |
|
284 | if BUS64 and (r.bsel = '1') then dqm := dqm(3 downto 0) & "1111"; end if; | |
|
285 | ||
|
286 | -- main FSM | |
|
287 | ||
|
288 | case r.mstate is | |
|
289 | when midle => | |
|
290 | if ((v.hsel and htrans(1) and not v.hio) = '1') then | |
|
291 | if (r.sdstate = sidle) and (r.cfg.command = "000") | |
|
292 | and (r.cmstate = midle) and (v.hio = '0') | |
|
293 | then | |
|
294 | if fast = 0 then startsd := '1'; else v.startsd := '1'; end if; | |
|
295 | v.mstate := active; | |
|
296 | elsif ((r.sdstate = sref) or (r.sdstate = pd) or (r.sdstate = dpd)) | |
|
297 | and (r.cfg.command = "000") and (r.cmstate = midle) and (v.hio = '0') | |
|
298 | then | |
|
299 | v.startsd := '1'; | |
|
300 | if r.sdstate = dpd then -- Error response when on Deep Power-Down mode | |
|
301 | v.hresp := HRESP_ERROR; | |
|
302 | else | |
|
303 | v.mstate := active; | |
|
304 | end if; | |
|
305 | end if; | |
|
306 | end if; | |
|
307 | when others => null; | |
|
308 | end case; | |
|
309 | ||
|
310 | startsd := startsd or r.startsd; | |
|
311 | ||
|
312 | -- generate row and column address size | |
|
313 | ||
|
314 | if BUS16 then | |
|
315 | case r.cfg.csize is | |
|
316 | when "00" => raddr := haddr(21 downto 9);-- case to check for bursting over row limit, since 1 row is 512 byte. | |
|
317 | when "01" => raddr := haddr(22 downto 10); | |
|
318 | when "10" => raddr := haddr(23 downto 11); | |
|
319 | when others => | |
|
320 | if r.cfg.bsize = "110" then raddr := haddr(25 downto 13); --tänk | |
|
321 | else raddr := haddr(24 downto 12); end if; | |
|
322 | end case; | |
|
323 | else | |
|
324 | case r.cfg.csize is | |
|
325 | when "00" => raddr := haddr(22 downto 10); | |
|
326 | when "01" => raddr := haddr(23 downto 11); | |
|
327 | when "10" => raddr := haddr(24 downto 12); | |
|
328 | when others => | |
|
329 | if r.cfg.bsize = "111" then raddr := haddr(26 downto 14); | |
|
330 | else raddr := haddr(25 downto 13); end if; | |
|
331 | end case; | |
|
332 | end if; | |
|
333 | ||
|
334 | -- generate bank address | |
|
335 | -- if BUS16 then --011 | |
|
336 | -- ba := genmux(r.cfg.bsize, haddr(26 downto 19)) & | |
|
337 | -- genmux(r.cfg.bsize, haddr(25 downto 18)); | |
|
338 | -- else | |
|
339 | ba := genmux(r.cfg.bsize, haddr(28 downto 21)) & | |
|
340 | genmux(r.cfg.bsize, haddr(27 downto 20)); | |
|
341 | -- end if; | |
|
342 | ||
|
343 | -- generate chip select | |
|
344 | ||
|
345 | if BUS64 then | |
|
346 | adec := genmux(r.cfg.bsize, haddr(30 downto 23)); | |
|
347 | v.bsel := genmux(r.cfg.bsize, r.haddr(29 downto 22)); | |
|
348 | else | |
|
349 | adec := genmux(r.cfg.bsize, haddr(29 downto 22)); v.bsel := '0'; | |
|
350 | end if; | |
|
351 | -- elsif BUS32 then | |
|
352 | -- adec := genmux(r.cfg.bsize, haddr(29 downto 22)); v.bsel := '0'; | |
|
353 | -- else | |
|
354 | -- adec := genmux(r.cfg.bsize, haddr(27 downto 20)); v.bsel := '0'; | |
|
355 | -- end if; | |
|
356 | ||
|
357 | rams := adec & not adec; | |
|
358 | ||
|
359 | -- sdram access FSM | |
|
360 | ||
|
361 | if r.trfc /= "0000" then v.trfc := r.trfc - 1; end if; | |
|
362 | ||
|
363 | if r.idlecnt /= "0000" then v.idlecnt := r.idlecnt - 1; end if; | |
|
364 | ||
|
365 | case r.sdstate is | |
|
366 | ||
|
367 | when sidle => | |
|
368 | if (startsd = '1') and (r.cfg.command = "000") and (r.cmstate = midle) then | |
|
369 | -- if BUS16 then | |
|
370 | -- v.address(16 downto 2) := '0' & ba & raddr(11 downto 0); --since 1 bit lower row => tot adress field 14 bits | |
|
371 | -- else | |
|
372 | v.address(16 downto 2) := ba & raddr; -- ba(16-15) & raddr(14-2) (2+13= 15 bits) | |
|
373 | -- end if; | |
|
374 | v.sdcsn := not rams(1 downto 0); v.rasn := '0'; v.sdstate := act1; | |
|
375 | v.startsd := '0'; | |
|
376 | elsif (r.idlecnt = "0000") and (r.cfg.command = "000") | |
|
377 | and (r.cmstate = midle) and (r.cfg.mobileen(1) = '1') then | |
|
378 | case r.cfg.pmode is | |
|
379 | when PM_SR => | |
|
380 | v.cfg.cke := '0'; v.sdstate := sref; | |
|
381 | v.sdcsn := (others => '0'); v.rasn := '0'; v.casn := '0'; | |
|
382 | v.trfc := (r.cfg.trp and r.cfg.mobileen(1)) & r.cfg.trfc; -- Control minimum duration of Self Refresh mode (= tRAS) | |
|
383 | when PM_PD => v.cfg.cke := '0'; v.sdstate := pd; | |
|
384 | when PM_DPD => | |
|
385 | v.cfg.cke := '0'; v.sdstate := dpd; | |
|
386 | v.sdcsn := (others => '0'); v.sdwen := '0'; v.rasn := '1'; v.casn := '1'; | |
|
387 | when others => | |
|
388 | end case; | |
|
389 | end if; | |
|
390 | ||
|
391 | when act1 => | |
|
392 | v.rasn := '1'; v.trfc := (r.cfg.trp and r.cfg.mobileen(1)) & r.cfg.trfc; | |
|
393 | if r.cfg.casdel = '1' then v.sdstate := act2; else | |
|
394 | v.sdstate := act3; | |
|
395 | if not BUS16 then -- needs if, otherwise it might clock in incorrect write data to state act3_16 | |
|
396 | v.hready := r.hwrite and ahbsi.htrans(0) and ahbsi.htrans(1); | |
|
397 | end if; | |
|
398 | end if; | |
|
399 | if WPROTEN then | |
|
400 | v.wprothit := sdi.wprot; | |
|
401 | if sdi.wprot = '1' then v.hresp := HRESP_ERROR; end if; | |
|
402 | end if; | |
|
403 | ||
|
404 | when act2 => | |
|
405 | v.sdstate := act3; | |
|
406 | if not BUS16 then | |
|
407 | v.hready := r.hwrite and ahbsi.htrans(0) and ahbsi.htrans(1); | |
|
408 | end if; | |
|
409 | if WPROTEN and (r.wprothit = '1') then | |
|
410 | v.hresp := HRESP_ERROR; v.hready := '0'; | |
|
411 | end if; | |
|
412 | ||
|
413 | when act3 => | |
|
414 | v.casn := '0'; | |
|
415 | if BUS16 then --HW adress needed to memory | |
|
416 | v.address(14 downto 2) := r.haddr(12 downto 11) & '0' & r.haddr(10 downto 1); --only allowed to use tot adressbits - ba bits | |
|
417 | -- v.address(13 downto 2) := r.haddr(11) & '0' & r.haddr(10 downto 1); --only allowed to use tot adressbits - ba bits | |
|
418 | v.lhw := r.haddr(1); -- 14-2 = 12 colummn bits => 13 downto 2 | |
|
419 | else | |
|
420 | v.address(14 downto 2) := r.haddr(13 downto 12) & '0' & r.haddr(11 downto 2); | |
|
421 | end if; | |
|
422 | v.dqm := dqm; v.burst := r.hready; -- ?? | |
|
423 | ||
|
424 | if r.hwrite = '1' then | |
|
425 | ||
|
426 | if BUS16 then --16 bit | |
|
427 | if r.size(1) = '1' then --word | |
|
428 | v.hready := ahbsi.htrans(0) and ahbsi.htrans(1); --delayed this check 1 state to keep write data correct in act3_16 | |
|
429 | v.burst := ahbsi.htrans(0) and ahbsi.htrans(1); | |
|
430 | v.sdstate := act3_16; -- goto state for second part of word transfer | |
|
431 | -- v.lhw := '0'; --write MSB 16 bits to AMBA adress that ends with 00 | |
|
432 | else --halfword or byte | |
|
433 | v.sdstate := act3_16; v.hready := '1'; | |
|
434 | end if; | |
|
435 | else --32 bit or 64 | |
|
436 | v.sdstate := wr1; | |
|
437 | if ahbsi.htrans = "11" or (r.hready = '0') then v.hready := '1'; end if; | |
|
438 | end if; | |
|
439 | v.sdwen := '0'; v.bdrive := '0'; --write | |
|
440 | if WPROTEN and (r.wprothit = '1') then | |
|
441 | v.hresp := HRESP_ERROR; v.hready := '1'; | |
|
442 | if BUS16 then v.sdstate := act3_16; else v.sdstate := wr1; end if; | |
|
443 | v.sdwen := '1'; v.bdrive := '1'; v.casn := '1'; --skip write, remember hready high in next state | |
|
444 | end if; | |
|
445 | else v.sdstate := rd1; end if; | |
|
446 | ||
|
447 | when act3_16 => --handle 16 bit and WORD write | |
|
448 | v.address(14 downto 2) := r.haddr(12 downto 11) & '0' & r.haddr(10 downto 2) & '1'; | |
|
449 | -- v.address(13 downto 2) := r.haddr(11) & '0' & r.haddr(10 downto 2) & '1'; | |
|
450 | v.lhw := '1'; | |
|
451 | if (r.hready and r.burst) = '1' and not (WPROTEN and (r.wprothit = '1')) then | |
|
452 | v.hready := '0'; --kolla på transfertyp nonseq om vi vill delaya nedankoll. | |
|
453 | if( ahbsi.htrans = "11" and | |
|
454 | not ((r.haddr(5 downto 2) = "1111") and (r.cfg.command = "100")) and | |
|
455 | not ((r.haddr(9) xor ahbsi.haddr(9)) = '1' and r.cfg.csize = "00") ) then | |
|
456 | v.sdstate := wr1_16; | |
|
457 | end if; | |
|
458 | elsif r.burst = '1' or (r.hready and not r.burst) = '1' then --terminate burst or single write | |
|
459 | v.sdstate := wr2; v.bdrive := '1'; v.casn := '1'; v.sdwen := '1'; | |
|
460 | v.dqm := (others => '1'); | |
|
461 | else -- complete single write | |
|
462 | v.hready := '1'; | |
|
463 | v.sdstate := act3_16; --gick till wr1 förut | |
|
464 | end if; | |
|
465 | ||
|
466 | when wr1_16 => | |
|
467 | v.address(14 downto 2) := r.haddr(12 downto 11) & '0' & r.haddr(10 downto 1); | |
|
468 | -- v.address(13 downto 2) := r.haddr(11) & '0' & r.haddr(10 downto 1); | |
|
469 | v.lhw := r.haddr(1); | |
|
470 | v.sdstate := act3_16; | |
|
471 | v.hready := '1'; | |
|
472 | ||
|
473 | when wr1 => | |
|
474 | v.address(14 downto 2) := r.haddr(13 downto 12) & '0' & r.haddr(11 downto 2); | |
|
475 | if (((r.burst and r.hready) = '1') and (r.htrans = "11")) | |
|
476 | and not (WPROTEN and (r.wprothit = '1')) | |
|
477 | then | |
|
478 | v.hready := ahbsi.htrans(0) and ahbsi.htrans(1) and r.hready; | |
|
479 | if ((r.haddr(5 downto 2) = "1111") and (r.cfg.command = "100")) then -- exit on refresh | |
|
480 | v.hready := '0'; | |
|
481 | end if; | |
|
482 | else | |
|
483 | v.sdstate := wr2; v.bdrive := '1'; v.casn := '1'; v.sdwen := '1'; | |
|
484 | v.dqm := (others => '1'); | |
|
485 | end if; | |
|
486 | ||
|
487 | when wr2 => | |
|
488 | if (r.cfg.trp = '0') then v.rasn := '0'; v.sdwen := '0'; end if; | |
|
489 | v.sdstate := wr3; | |
|
490 | ||
|
491 | when wr3 => | |
|
492 | if (r.cfg.trp = '1') then | |
|
493 | v.rasn := '0'; v.sdwen := '0'; v.sdstate := wr4; | |
|
494 | else | |
|
495 | v.sdcsn := "11"; v.rasn := '1'; v.sdwen := '1'; v.sdstate := sidle; | |
|
496 | v.idlecnt := (others => '1'); | |
|
497 | end if; | |
|
498 | ||
|
499 | when wr4 => | |
|
500 | v.sdcsn := "11"; v.rasn := '1'; v.sdwen := '1'; | |
|
501 | if (r.cfg.trp = '1') then v.sdstate := wr5; | |
|
502 | else v.sdstate := sidle; v.idlecnt := (others => '1'); end if; | |
|
503 | ||
|
504 | when wr5 => | |
|
505 | v.sdstate := sidle; v.idlecnt := (others => '1'); | |
|
506 | ||
|
507 | when rd1 => --first read applied to sdram | |
|
508 | v.casn := '1'; v.sdstate := rd7; --nop | |
|
509 | if not BUS16 then --starting adress cannot be XXXX...111 since we have word burst in this case. and lowest bit always 0. | |
|
510 | if lineburst and (ahbsi.htrans = "11") then | |
|
511 | if r.haddr(4 downto 2) = "111" then | |
|
512 | v.address(9 downto 5) := r.address(9 downto 5) + 1; --adds only within 1KB limit. | |
|
513 | v.address(4 downto 2) := "000"; v.casn := '0'; | |
|
514 | end if; | |
|
515 | end if; | |
|
516 | end if; | |
|
517 | ||
|
518 | when rd7 => | |
|
519 | v.casn := '1'; --nop | |
|
520 | if BUS16 then | |
|
521 | if r.cfg.casdel = '1' then --casdel3 | |
|
522 | v.sdstate := rd2; | |
|
523 | if lineburst and (ahbsi.htrans = "11") then | |
|
524 | if r.haddr(3 downto 1) = "110" then | |
|
525 | v.address(10 downto 5) := r.address(10 downto 5) + 1; | |
|
526 | v.address(4 downto 2) := "000"; v.casn := '0'; | |
|
527 | end if; | |
|
528 | end if; | |
|
529 | else --casdel2 | |
|
530 | v.sdstate := rd3; | |
|
531 | if ahbsi.htrans /= "11" then | |
|
532 | if (r.trfc(3 downto 1) = "000") then v.rasn := '0'; v.sdwen := '0'; end if; | |
|
533 | elsif lineburst then | |
|
534 | if r.haddr(3 downto 1) = "110" then | |
|
535 | v.address(10 downto 5) := r.address(10 downto 5) + 1; | |
|
536 | v.address(4 downto 2) := "000"; v.casn := '0'; | |
|
537 | end if; | |
|
538 | end if; | |
|
539 | end if; | |
|
540 | else -- 32 bit or larger | |
|
541 | if r.cfg.casdel = '1' then --casdel3 | |
|
542 | v.sdstate := rd2; | |
|
543 | if lineburst and (ahbsi.htrans = "11") then | |
|
544 | if r.haddr(4 downto 2) = "110" then | |
|
545 | v.address(9 downto 5) := r.address(9 downto 5) + 1; | |
|
546 | v.address(4 downto 2) := "000"; v.casn := '0'; | |
|
547 | end if; | |
|
548 | end if; | |
|
549 | else --casdel2 | |
|
550 | v.sdstate := rd3; | |
|
551 | if ahbsi.htrans /= "11" then | |
|
552 | if (r.trfc(3 downto 1) = "000") then v.rasn := '0'; v.sdwen := '0'; end if; --precharge | |
|
553 | elsif lineburst then | |
|
554 | if r.haddr(4 downto 2) = "110" then | |
|
555 | v.address(9 downto 5) := r.address(9 downto 5) + 1; | |
|
556 | v.address(4 downto 2) := "000"; v.casn := '0'; | |
|
557 | end if; | |
|
558 | end if; | |
|
559 | end if; | |
|
560 | end if; | |
|
561 | ||
|
562 | when rd2 => | |
|
563 | v.casn := '1'; v.sdstate := rd3; | |
|
564 | if BUS16 then | |
|
565 | if ahbsi.htrans /= "11" then | |
|
566 | v.rasn := '0'; v.sdwen := '0'; v.dqm := (others => '1'); --precharge & DQM | |
|
567 | --note that DQM always has 2 cycle delay before blocking data. So NP if we fetch second HW | |
|
568 | end if; | |
|
569 | else | |
|
570 | if ahbsi.htrans /= "11" then v.rasn := '0'; v.sdwen := '0'; v.dqm := (others => '1'); --precharge & DQM | |
|
571 | elsif lineburst then | |
|
572 | if r.haddr(4 downto 2) = "101" then | |
|
573 | v.address(9 downto 5) := r.address(9 downto 5) + 1; | |
|
574 | v.address(4 downto 2) := "000"; v.casn := '0'; | |
|
575 | end if; | |
|
576 | end if; | |
|
577 | end if; | |
|
578 | ||
|
579 | when rd3 => --first read data from sdram output v.lhw := r.haddr(1); | |
|
580 | v.casn := '1'; --if read before cas makes nop else if pre => no difference | |
|
581 | if BUS16 then | |
|
582 | --note if read is for halfwor or byte we dont want to read a second time but exit. | |
|
583 | --if the read is a word we need to change LHW to one since the next read should be muxed in next cylcle. | |
|
584 | -- if r.size(1) = '1' then --word v.hready := not r.size(1) | |
|
585 | -- v.sdstate := rd4_16; v.hready := '0'; --hready low since just first part of a word | |
|
586 | -- v.lhw := '1'; -- read low 16 next state | |
|
587 | -- else --HW or byte | |
|
588 | -- v.sdstate := rd4_16; v.hready := '1'; | |
|
589 | -- end if; | |
|
590 | v.sdstate := rd4_16; | |
|
591 | v.lhw := not r.lhw; --r.lhw is 0 for word, we should invert for next half of word.For HW or Byte v.lhw does not matter. | |
|
592 | v.hready := not r.size(1); --if word transfer the r.size(1) is 1 and hready goes low.If HW or byte r.size(1)=0 => hready=1 | |
|
593 | if r.sdwen = '0' then | |
|
594 | v.rasn := '1'; v.sdwen := '1'; v.sdcsn := "11"; v.dqm := (others => '1'); -- make DSEL (NOP) | |
|
595 | elsif lineburst and ((ahbsi.htrans = "11") and (r.cfg.casdel = '1')) then --only enter if cl3 | |
|
596 | if r.haddr(3 downto 1) = "100" then | |
|
597 | v.address(10 downto 5) := r.address(10 downto 5) + 1; | |
|
598 | v.address(4 downto 2) := "000"; v.casn := '0'; | |
|
599 | end if; | |
|
600 | end if; | |
|
601 | else --32 bit or larger | |
|
602 | v.sdstate := rd4; v.hready := '1'; | |
|
603 | if r.sdwen = '0' then | |
|
604 | v.rasn := '1'; v.sdwen := '1'; v.sdcsn := "11"; v.dqm := (others => '1'); -- make DSEL (NOP) | |
|
605 | elsif lineburst and (ahbsi.htrans = "11") and (r.casn = '1') then | |
|
606 | if r.haddr(4 downto 2) = ("10" & not r.cfg.casdel) then | |
|
607 | v.address(9 downto 5) := r.address(9 downto 5) + 1; | |
|
608 | v.address(4 downto 2) := "000"; v.casn := '0'; | |
|
609 | end if; | |
|
610 | end if; | |
|
611 | end if; | |
|
612 | ||
|
613 | when rd4_16 => --enter as word (r.hready is still 0) else 1. If hready one next transfer sampled into v. | |
|
614 | --v.hready := '1'; | |
|
615 | v.hready := not r.hready;-- if Byte or HW exit with hready low. If word flip bit, makes correct exit with hready low. | |
|
616 | v.lhw := not r.lhw; --r.lhw is one the first time we enter (taking care of second part of word) | |
|
617 | v.casn := '1'; | |
|
618 | --quit on: Single transfer CL 2/3 (prcharge if CL 2 and timer was not 0) | |
|
619 | if (ahbsi.htrans /= "11" and (r.hready = '1')) or | |
|
620 | ((r.haddr(9) xor ahbsi.haddr(9)) = '1' and r.cfg.csize = "00" and r.hready = '1') or --probably dont have to check hready 1 since if 0 adresses equal. | |
|
621 | ((r.haddr(5 downto 2) = "1111") and (r.cfg.command = "100") and (r.hready = '1')) then --quit on: ST W/HW/BYTE OR | |
|
622 | --v.hready := '0'; --if Byte or HW exit with hready low, if ST word exit with high. | |
|
623 | v.dqm := (others => '1'); | |
|
624 | if r.sdcsn /= "11" then --not prechargeing | |
|
625 | v.rasn := '0'; v.sdwen := '0'; v.sdstate := rd5; --precharge | |
|
626 | else--exit | |
|
627 | if r.cfg.trp = '1' then v.sdstate := rd6; | |
|
628 | else v.sdstate := sidle; v.idlecnt := (others => '1'); end if; | |
|
629 | end if; | |
|
630 | elsif lineburst then --NOTE: r.casn = 1 makes sure its the first halfword of a word that is checked (hready low) | |
|
631 | if r.cfg.casdel = '0' then | |
|
632 | if (r.haddr(3 downto 1) = "100") and (r.casn = '1') then --lline = 011 if casdel =1, 100 if casdel= 0 | |
|
633 | v.address(10 downto 5) := r.address(10 downto 5) + 1; | |
|
634 | v.address(4 downto 2) := "000"; v.casn := '0'; | |
|
635 | end if; | |
|
636 | else | |
|
637 | if (r.haddr(3 downto 1) = "010") and (r.hready = '1') then --lline = 011 if casdel =1, 100 if casdel= 0 | |
|
638 | v.address(10 downto 5) := r.address(10 downto 5) + 1; | |
|
639 | v.address(4 downto 2) := "000"; v.casn := '0'; | |
|
640 | end if; | |
|
641 | end if; | |
|
642 | end if; | |
|
643 | ||
|
644 | when rd4 => | |
|
645 | v.hready := '1'; v.casn := '1'; | |
|
646 | if (ahbsi.htrans /= "11") or (r.sdcsn = "11") or | |
|
647 | ((r.haddr(5 downto 2) = "1111") and (r.cfg.command = "100")) -- exit on refresh | |
|
648 | then | |
|
649 | v.hready := '0'; v.dqm := (others => '1'); | |
|
650 | if (r.sdcsn /= "11") then | |
|
651 | v.rasn := '0'; v.sdwen := '0'; v.sdstate := rd5; | |
|
652 | else | |
|
653 | if r.cfg.trp = '1' then v.sdstate := rd6; | |
|
654 | else v.sdstate := sidle; v.idlecnt := (others => '1'); end if; | |
|
655 | end if; | |
|
656 | elsif lineburst then | |
|
657 | if (r.haddr(4 downto 2) = lline) and (r.casn = '1') then | |
|
658 | v.address(9 downto 5) := r.address(9 downto 5) + 1; | |
|
659 | v.address(4 downto 2) := "000"; v.casn := '0'; | |
|
660 | end if; | |
|
661 | end if; | |
|
662 | ||
|
663 | when rd5 => | |
|
664 | if r.cfg.trp = '1' then v.sdstate := rd6; else v.sdstate := sidle; v.idlecnt := (others => '1'); end if; | |
|
665 | v.sdcsn := (others => '1'); v.rasn := '1'; v.sdwen := '1'; v.dqm := (others => '1'); | |
|
666 | v.casn := '1'; | |
|
667 | ||
|
668 | when rd6 => | |
|
669 | v.sdstate := sidle; v.idlecnt := (others => '1'); v.dqm := (others => '1'); | |
|
670 | v.sdcsn := (others => '1'); v.rasn := '1'; v.sdwen := '1'; | |
|
671 | ||
|
672 | when sref => | |
|
673 | if (startsd = '1' and (r.hio = '0')) | |
|
674 | or (r.cfg.command /= "000") or r.cfg.pmode /= PM_SR then | |
|
675 | if r.trfc = "0000" then -- Minimum duration (= tRAS) | |
|
676 | v.cfg.cke := '1'; | |
|
677 | v.sdcsn := (others => '0'); v.rasn := '1'; v.casn := '1'; | |
|
678 | end if; | |
|
679 | if r.cfg.cke = '1' then | |
|
680 | if (r.idlecnt = "0000") then -- tXSR ns with NOP | |
|
681 | v.sdstate := sidle; | |
|
682 | v.idlecnt := (others => '1'); | |
|
683 | v.sref_tmpcom := r.cfg.command; | |
|
684 | v.cfg.command := "100"; | |
|
685 | end if; | |
|
686 | else | |
|
687 | v.idlecnt := r.cfg.txsr; | |
|
688 | end if; | |
|
689 | end if; | |
|
690 | ||
|
691 | when pd => | |
|
692 | if (startsd = '1' and (r.hio = '0')) | |
|
693 | or (r.cfg.command /= "000") or r.cfg.pmode /= PM_PD then | |
|
694 | v.cfg.cke := '1'; | |
|
695 | v.sdstate := sidle; | |
|
696 | v.idlecnt := (others => '1'); | |
|
697 | end if; | |
|
698 | ||
|
699 | when dpd => | |
|
700 | v.sdcsn := (others => '1'); v.sdwen := '1'; v.rasn := '1'; v.casn := '1'; | |
|
701 | v.cfg.renable := '0'; | |
|
702 | if (startsd = '1' and r.hio = '0') then | |
|
703 | v.hready := '1'; -- ack all accesses with Error response | |
|
704 | v.startsd := '0'; | |
|
705 | v.hresp := HRESP_ERROR; | |
|
706 | elsif r.cfg.pmode /= PM_DPD then | |
|
707 | v.cfg.cke := '1'; | |
|
708 | if r.cfg.cke = '1' then | |
|
709 | v.sdstate := sidle; | |
|
710 | v.idlecnt := (others => '1'); | |
|
711 | v.cfg.renable := '1'; | |
|
712 | end if; | |
|
713 | end if; | |
|
714 | ||
|
715 | when others => | |
|
716 | v.sdstate := sidle; v.idlecnt := (others => '1'); | |
|
717 | end case; | |
|
718 | ||
|
719 | -- sdram commands | |
|
720 | ||
|
721 | case r.cmstate is | |
|
722 | when midle => | |
|
723 | if r.sdstate = sidle then | |
|
724 | case r.cfg.command is | |
|
725 | when "010" => -- precharge | |
|
726 | v.sdcsn := (others => '0'); v.rasn := '0'; v.sdwen := '0'; | |
|
727 | v.address(12) := '1'; v.cmstate := active; | |
|
728 | when "100" => -- auto-refresh | |
|
729 | v.sdcsn := (others => '0'); v.rasn := '0'; v.casn := '0'; | |
|
730 | v.cmstate := active; | |
|
731 | when "110" => -- Lodad Mode Reg | |
|
732 | v.sdcsn := (others => '0'); v.rasn := '0'; v.casn := '0'; | |
|
733 | v.sdwen := '0'; v.cmstate := active; | |
|
734 | if lineburst then | |
|
735 | v.address(16 downto 2) := "0000010001" & r.cfg.casdel & "0011"; | |
|
736 | else | |
|
737 | v.address(16 downto 2) := "0000010001" & r.cfg.casdel & "0111"; | |
|
738 | end if; | |
|
739 | when "111" => -- Load Ext-Mode Reg | |
|
740 | v.sdcsn := (others => '0'); v.rasn := '0'; v.casn := '0'; | |
|
741 | v.sdwen := '0'; v.cmstate := active; | |
|
742 | v.address(16 downto 2) := "10000000" & r.cfg.ds(1 downto 0) & r.cfg.tcsr(1 downto 0) | |
|
743 | & r.cfg.pasr(2 downto 0); | |
|
744 | when others => null; | |
|
745 | end case; | |
|
746 | end if; | |
|
747 | when active => | |
|
748 | v.sdcsn := (others => '1'); v.rasn := '1'; v.casn := '1'; | |
|
749 | v.sdwen := '1'; --v.cfg.command := "000"; | |
|
750 | v.cfg.command := r.sref_tmpcom; v.sref_tmpcom := "000"; | |
|
751 | v.cmstate := leadout; v.trfc := (r.cfg.trp and r.cfg.mobileen(1)) & r.cfg.trfc; | |
|
752 | when leadout => | |
|
753 | if r.trfc = "0000" then v.cmstate := midle; end if; | |
|
754 | ||
|
755 | end case; | |
|
756 | ||
|
757 | -- sdram init | |
|
758 | ||
|
759 | case r.istate is | |
|
760 | when iidle => | |
|
761 | v.cfg.cke := '1'; | |
|
762 | if r.cfg.renable = '1' and r.cfg.cke = '1' then | |
|
763 | v.cfg.command := "010"; v.istate := pre; | |
|
764 | end if; | |
|
765 | when pre => | |
|
766 | if r.cfg.command = "000" then | |
|
767 | v.cfg.command := "100"; v.istate := ref; v.icnt := "111"; | |
|
768 | end if; | |
|
769 | when ref => | |
|
770 | if r.cfg.command = "000" then | |
|
771 | v.cfg.command := "100"; v.icnt := r.icnt - 1; | |
|
772 | if r.icnt = "000" then v.istate := lmode; v.cfg.command := "110"; end if; | |
|
773 | end if; | |
|
774 | when lmode => | |
|
775 | if r.cfg.command = "000" then | |
|
776 | if r.cfg.mobileen = "11" then | |
|
777 | v.cfg.command := "111"; v.istate := emode; | |
|
778 | else | |
|
779 | v.istate := finish; | |
|
780 | end if; | |
|
781 | end if; | |
|
782 | when emode => | |
|
783 | if r.cfg.command = "000" then | |
|
784 | v.istate := finish; | |
|
785 | end if; | |
|
786 | when others => | |
|
787 | if r.cfg.renable = '0' and r.sdstate /= dpd then | |
|
788 | v.istate := iidle; | |
|
789 | end if; | |
|
790 | end case; | |
|
791 | ||
|
792 | if (ahbsi.hready and ahbsi.hsel(hindex) ) = '1' then | |
|
793 | if ahbsi.htrans(1) = '0' then v.hready := '1'; end if; | |
|
794 | end if; | |
|
795 | ||
|
796 | if (r.hsel and r.hio and not r.hready) = '1' then v.hready := '1'; end if; | |
|
797 | ||
|
798 | -- second part of main fsm | |
|
799 | ||
|
800 | case r.mstate is | |
|
801 | when active => | |
|
802 | if v.hready = '1' then | |
|
803 | v.mstate := midle; | |
|
804 | end if; | |
|
805 | when others => null; | |
|
806 | end case; | |
|
807 | ||
|
808 | -- sdram refresh counter | |
|
809 | ||
|
810 | -- pragma translate_off | |
|
811 | if not is_x(r.cfg.refresh) then | |
|
812 | -- pragma translate_on | |
|
813 | if (r.cfg.renable = '1') and (r.istate = finish) and r.sdstate /= sref then | |
|
814 | v.refresh := r.refresh - 1; | |
|
815 | if (v.refresh(14) and not r.refresh(14)) = '1' then | |
|
816 | v.refresh := r.cfg.refresh; | |
|
817 | v.cfg.command := "100"; | |
|
818 | arefresh := '1'; | |
|
819 | end if; | |
|
820 | end if; | |
|
821 | -- pragma translate_off | |
|
822 | end if; | |
|
823 | -- pragma translate_on | |
|
824 | ||
|
825 | -- AHB register access | |
|
826 | -- if writing to IO space config regs. Just mapping write data to all config values in config reg | |
|
827 | if (r.hsel and r.hio and r.hwrite and r.htrans(1)) = '1' then | |
|
828 | if r.haddr(3 downto 2) = "00" then | |
|
829 | if pageburst = 2 then v.cfg.pageburst := hwdata(17); end if; | |
|
830 | v.cfg.command := hwdata(20 downto 18); | |
|
831 | v.cfg.csize := hwdata(22 downto 21); | |
|
832 | v.cfg.bsize := hwdata(25 downto 23); | |
|
833 | v.cfg.casdel := hwdata(26); | |
|
834 | v.cfg.trfc := hwdata(29 downto 27); | |
|
835 | v.cfg.trp := hwdata(30); | |
|
836 | v.cfg.renable := hwdata(31); | |
|
837 | v.cfg.refresh := hwdata(14 downto 0); | |
|
838 | v.refresh := (others => '0'); | |
|
839 | elsif r.haddr(3 downto 2) = "01" then | |
|
840 | if r.cfg.mobileen(1) = '1' and mobile /= 3 then v.cfg.mobileen(0) := hwdata(31); end if; | |
|
841 | if r.cfg.pmode = "000" then | |
|
842 | v.cfg.cke := hwdata(30); | |
|
843 | end if; | |
|
844 | if r.cfg.mobileen(1) = '1' then | |
|
845 | v.cfg.txsr := hwdata(23 downto 20); | |
|
846 | v.cfg.pmode := hwdata(18 downto 16); | |
|
847 | v.cfg.ds(3 downto 2) := hwdata( 6 downto 5); | |
|
848 | v.cfg.tcsr(3 downto 2) := hwdata( 4 downto 3); | |
|
849 | v.cfg.pasr(5 downto 3) := hwdata( 2 downto 0); | |
|
850 | end if; | |
|
851 | end if; | |
|
852 | end if; | |
|
853 | ||
|
854 | -- Disable CS and DPD when Mobile SDR is Disabled | |
|
855 | if r.cfg.mobileen(0) = '0' then v.cfg.pmode(2) := '0'; end if; | |
|
856 | ||
|
857 | -- Update EMR when ds, tcsr or pasr change | |
|
858 | if r.cfg.command = "000" and arefresh = '0' and r.cfg.mobileen(0) = '1' then | |
|
859 | if r.cfg.ds(1 downto 0) /= r.cfg.ds(3 downto 2) then | |
|
860 | v.cfg.command := "111"; v.cfg.ds(1 downto 0) := r.cfg.ds(3 downto 2); | |
|
861 | end if; | |
|
862 | if r.cfg.tcsr(1 downto 0) /= r.cfg.tcsr(3 downto 2) then | |
|
863 | v.cfg.command := "111"; v.cfg.tcsr(1 downto 0) := r.cfg.tcsr(3 downto 2); | |
|
864 | end if; | |
|
865 | if r.cfg.pasr(2 downto 0) /= r.cfg.pasr(5 downto 3) then | |
|
866 | v.cfg.command := "111"; v.cfg.pasr(2 downto 0) := r.cfg.pasr(5 downto 3); | |
|
867 | end if; | |
|
868 | end if; | |
|
869 | ||
|
870 | regsd := (others => '0'); | |
|
871 | --reads out config registers (r/w does not matter) according to manual depending on address, notice generic determines data width. | |
|
872 | if r.haddr(3 downto 2) = "00" then | |
|
873 | regsd(31 downto 18) := r.cfg.renable & r.cfg.trp & r.cfg.trfc & | |
|
874 | r.cfg.casdel & r.cfg.bsize & r.cfg.csize & r.cfg.command; | |
|
875 | if not lineburst then regsd(17) := '1'; end if; | |
|
876 | regsd(16) := r.cfg.mobileen(1); | |
|
877 | if BUS64 then regsd(15) := '1'; end if; | |
|
878 | regsd(14 downto 0) := r.cfg.refresh; | |
|
879 | elsif r.haddr(3 downto 2) = "01" then | |
|
880 | regsd(31) := r.cfg.mobileen(0); | |
|
881 | regsd(30) := r.cfg.cke; | |
|
882 | regsd(23 downto 0) := r.cfg.txsr & '0' & r.cfg.pmode & "000000000" & | |
|
883 | r.cfg.ds(1 downto 0) & r.cfg.tcsr(1 downto 0) & r.cfg.pasr(2 downto 0); | |
|
884 | end if; | |
|
885 | ||
|
886 | if (r.hsel and r.hio) = '1' then dout := regsd; | |
|
887 | else | |
|
888 | if BUS64 and r.bsel = '1' then dout := r.hrdata(63 downto 32); | |
|
889 | else dout := r.hrdata(31 downto 0); end if; | |
|
890 | end if; | |
|
891 | ||
|
892 | v.nbdrive := not v.bdrive; | |
|
893 | ||
|
894 | if oepol = 1 then bdrive := r.nbdrive; vbdrive := (others => v.nbdrive); | |
|
895 | else bdrive := r.bdrive; vbdrive := (others => v.bdrive);end if; | |
|
896 | ||
|
897 | -- reset | |
|
898 | ||
|
899 | if rst = '0' then | |
|
900 | v.sdstate := sidle; | |
|
901 | v.mstate := midle; | |
|
902 | v.istate := iidle; | |
|
903 | v.cmstate := midle; | |
|
904 | v.hsel := '0'; | |
|
905 | v.cfg.command := "000"; | |
|
906 | v.cfg.csize := "01"; | |
|
907 | v.cfg.bsize := "011"; | |
|
908 | v.cfg.casdel := '1'; | |
|
909 | v.cfg.trfc := "111"; | |
|
910 | if pwron = 1 then v.cfg.renable := '1'; | |
|
911 | else v.cfg.renable := '0'; end if; | |
|
912 | v.cfg.trp := '1'; | |
|
913 | v.dqm := (others => '1'); | |
|
914 | v.sdwen := '1'; | |
|
915 | v.rasn := '1'; | |
|
916 | v.casn := '1'; | |
|
917 | v.hready := '1'; | |
|
918 | v.bsel := '0'; | |
|
919 | v.startsd := '0'; | |
|
920 | if (pageburst = 2) then | |
|
921 | v.cfg.pageburst := '0'; | |
|
922 | end if; | |
|
923 | if mobile >= 2 then v.cfg.mobileen := "11"; | |
|
924 | elsif mobile = 1 then v.cfg.mobileen := "10"; | |
|
925 | else v.cfg.mobileen := "00"; end if; | |
|
926 | v.cfg.txsr := (others => '1'); | |
|
927 | v.cfg.pmode := (others => '0'); | |
|
928 | v.cfg.ds := (others => '0'); | |
|
929 | v.cfg.tcsr := (others => '0'); | |
|
930 | v.cfg.pasr := (others => '0'); | |
|
931 | if mobile >= 2 then v.cfg.cke := '0'; | |
|
932 | else v.cfg.cke := '1'; end if; | |
|
933 | v.sref_tmpcom := "000"; | |
|
934 | v.idlecnt := (others => '1'); | |
|
935 | end if; | |
|
936 | ||
|
937 | ri <= v; | |
|
938 | ribdrive <= vbdrive; | |
|
939 | ||
|
940 | ahbso.hready <= r.hready; | |
|
941 | ahbso.hresp <= r.hresp; | |
|
942 | ahbso.hrdata <= ahbdrivedata(dout); | |
|
943 | ||
|
944 | end process; | |
|
945 | ||
|
946 | --sdo.sdcke <= (others => '1'); | |
|
947 | sdo.sdcke <= (others => r.cfg.cke); | |
|
948 | ahbso.hconfig <= hconfig; | |
|
949 | ahbso.hirq <= (others => '0'); | |
|
950 | ahbso.hindex <= hindex; | |
|
951 | ahbso.hsplit <= (others => '0'); | |
|
952 | ||
|
953 | -- Quick hack to get rid of undriven signal warnings. Check this for future | |
|
954 | -- merge with main sdctrl. | |
|
955 | drivehack : block | |
|
956 | begin | |
|
957 | sdo.qdrive <= '0'; | |
|
958 | sdo.nbdrive <= '0'; | |
|
959 | sdo.ce <= '0'; | |
|
960 | sdo.moben <= '0'; | |
|
961 | sdo.cal_rst <= '0'; | |
|
962 | sdo.oct <= '0'; | |
|
963 | sdo.xsdcsn <= (others => '1'); | |
|
964 | sdo.data(127 downto 16) <= (others => '0'); | |
|
965 | sdo.cb <= (others => '0'); | |
|
966 | sdo.ba <= (others => '0'); | |
|
967 | sdo.sdck <= (others => '0'); | |
|
968 | sdo.cal_en <= (others => '0'); | |
|
969 | sdo.cal_inc <= (others => '0'); | |
|
970 | sdo.cal_pll <= (others => '0'); | |
|
971 | sdo.odt <= (others => '0'); | |
|
972 | sdo.conf <= (others => '0'); | |
|
973 | sdo.vcbdrive <= (others => '0'); | |
|
974 | sdo.dqs_gate <= '0'; | |
|
975 | sdo.cbdqm <= (others => '0'); | |
|
976 | sdo.cbcal_en <= (others => '0'); | |
|
977 | sdo.cbcal_inc <= (others => '0'); | |
|
978 | sdo.read_pend <= (others => '0'); | |
|
979 | sdo.regwdata <= (others => '0'); | |
|
980 | sdo.regwrite <= (others => '0'); | |
|
981 | end block drivehack; | |
|
982 | ||
|
983 | regs : process(clk, rst) begin | |
|
984 | if rising_edge(clk) then | |
|
985 | r <= ri; rbdrive <= ribdrive; | |
|
986 | if rst = '0' then r.icnt <= (others => '0'); end if; | |
|
987 | end if; | |
|
988 | if (rst = '0') then | |
|
989 | r.sdcsn <= (others => '1'); r.bdrive <= '1'; r.nbdrive <= '0'; | |
|
990 | if oepol = 0 then rbdrive <= (others => '1'); | |
|
991 | else rbdrive <= (others => '0'); end if; | |
|
992 | end if; | |
|
993 | end process; | |
|
994 | ||
|
995 | rgen : if not SDINVCLK generate | |
|
996 | sdo.address <= r.address; | |
|
997 | sdo.bdrive <= r.nbdrive when oepol = 1 else r.bdrive; | |
|
998 | sdo.vbdrive <= zero32 & rbdrive; | |
|
999 | sdo.sdcsn <= r.sdcsn; | |
|
1000 | sdo.sdwen <= r.sdwen; | |
|
1001 | sdo.dqm <= "11111111" & r.dqm; | |
|
1002 | sdo.rasn <= r.rasn; | |
|
1003 | sdo.casn <= r.casn; | |
|
1004 | ||
|
1005 | mux16_wrdata : if BUS16 generate --mux data depending on Low/High HW | |
|
1006 | sdo.data(15 downto 0) <= r.hwdata(15 downto 0) when r.lhw = '1' else r.hwdata(31 downto 16); | |
|
1007 | end generate; | |
|
1008 | ||
|
1009 | wrdata : if not BUS16 generate | |
|
1010 | drivebus: for i in 0 to sdbits/64 generate | |
|
1011 | sdo.data(31+32*i downto 32*i) <= r.hwdata; | |
|
1012 | end generate; | |
|
1013 | end generate; | |
|
1014 | end generate; | |
|
1015 | ||
|
1016 | ngen : if SDINVCLK generate | |
|
1017 | nregs : process(clk, rst) begin | |
|
1018 | if falling_edge(clk) then | |
|
1019 | sdo.address <= r.address; | |
|
1020 | if oepol = 1 then sdo.bdrive <= r.nbdrive; | |
|
1021 | else sdo.bdrive <= r.bdrive; end if; | |
|
1022 | sdo.vbdrive <= zero32 & rbdrive; | |
|
1023 | sdo.sdcsn <= r.sdcsn; | |
|
1024 | sdo.sdwen <= r.sdwen; | |
|
1025 | sdo.dqm <= "11111111" & r.dqm; | |
|
1026 | sdo.rasn <= r.rasn; | |
|
1027 | sdo.casn <= r.casn; | |
|
1028 | if BUS16 then --mux data depending on Low/High HW | |
|
1029 | if (r.lhw ='1') then | |
|
1030 | sdo.data(15 downto 0) <= r.hwdata(15 downto 0); | |
|
1031 | else | |
|
1032 | sdo.data(15 downto 0) <= r.hwdata(31 downto 16); | |
|
1033 | end if; | |
|
1034 | end if; | |
|
1035 | ||
|
1036 | if not BUS16 then | |
|
1037 | for i in 0 to sdbits/64 loop | |
|
1038 | sdo.data(31+32*i downto 32*i) <= r.hwdata; | |
|
1039 | end loop; | |
|
1040 | end if; | |
|
1041 | end if; | |
|
1042 | if rst = '0' then sdo.sdcsn <= (others => '1'); end if; | |
|
1043 | end process; | |
|
1044 | end generate; | |
|
1045 | ||
|
1046 | -- pragma translate_off | |
|
1047 | bootmsg : report_version | |
|
1048 | generic map ("sdctrl16" & tost(hindex) & | |
|
1049 | ": PC133 SDRAM controller rev " & tost(REVISION)); | |
|
1050 | -- pragma translate_on | |
|
1051 | ||
|
1052 | end; | |
|
1053 |
@@ -0,0 +1,200 | |||
|
1 | ------------------------------------------------------------------------------ | |
|
2 | -- LEON3 Demonstration design test bench | |
|
3 | -- Copyright (C) 2004 Jiri Gaisler, Gaisler Research | |
|
4 | ------------------------------------------------------------------------------ | |
|
5 | ------------------------------------------------------------------------------ | |
|
6 | -- This file is a part of the GRLIB VHDL IP LIBRARY | |
|
7 | -- Copyright (C) 2003 - 2008, Gaisler Research | |
|
8 | -- Copyright (C) 2008 - 2014, Aeroflex Gaisler | |
|
9 | -- Copyright (C) 2015 - 2016, Cobham Gaisler | |
|
10 | -- | |
|
11 | -- This program is free software; you can redistribute it and/or modify | |
|
12 | -- it under the terms of the GNU General Public License as published by | |
|
13 | -- the Free Software Foundation; either version 2 of the License, or | |
|
14 | -- (at your option) any later version. | |
|
15 | -- | |
|
16 | -- This program is distributed in the hope that it will be useful, | |
|
17 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of | |
|
18 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
|
19 | -- GNU General Public License for more details. | |
|
20 | -- | |
|
21 | -- You should have received a copy of the GNU General Public License | |
|
22 | -- along with this program; if not, write to the Free Software | |
|
23 | -- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
|
24 | ||
|
25 | library ieee; | |
|
26 | use ieee.std_logic_1164.all; | |
|
27 | library gaisler; | |
|
28 | use gaisler.libdcom.all; | |
|
29 | use gaisler.sim.all; | |
|
30 | use work.debug.all; | |
|
31 | library techmap; | |
|
32 | use techmap.gencomp.all; | |
|
33 | library micron; | |
|
34 | use micron.components.all; | |
|
35 | library grlib; | |
|
36 | use grlib.stdlib.all; | |
|
37 | ||
|
38 | use work.config.all; -- configuration | |
|
39 | ||
|
40 | ||
|
41 | entity testbench is | |
|
42 | generic ( | |
|
43 | fabtech : integer := CFG_FABTECH; | |
|
44 | memtech : integer := CFG_MEMTECH; | |
|
45 | padtech : integer := CFG_PADTECH; | |
|
46 | clktech : integer := CFG_CLKTECH; | |
|
47 | disas : integer := CFG_DISAS; -- Enable disassembly to console | |
|
48 | dbguart : integer := CFG_DUART; -- Print UART on console | |
|
49 | pclow : integer := CFG_PCLOW; | |
|
50 | ||
|
51 | clkperiod : integer := 20; -- system clock period | |
|
52 | romdepth : integer := 22 -- rom address depth (flash 4 MB) | |
|
53 | -- sramwidth : integer := 32; -- ram data width (8/16/32) | |
|
54 | -- sramdepth : integer := 20; -- ram address depth | |
|
55 | -- srambanks : integer := 2 -- number of ram banks | |
|
56 | ); | |
|
57 | end; | |
|
58 | ||
|
59 | architecture behav of testbench is | |
|
60 | ||
|
61 | constant promfile : string := "prom.srec"; -- rom contents | |
|
62 | constant sramfile : string := "ram.srec"; -- ram contents | |
|
63 | constant sdramfile : string := "ram.srec"; -- sdram contents | |
|
64 | ||
|
65 | ||
|
66 | signal SW : std_logic_vector(4 downto 1); | |
|
67 | signal clk : std_logic := '0'; | |
|
68 | signal Rst : std_logic := '0'; -- Reset | |
|
69 | constant ct : integer := clkperiod/2; | |
|
70 | ||
|
71 | signal address : std_logic_vector(21 downto 0); | |
|
72 | signal data : std_logic_vector(31 downto 24); | |
|
73 | ||
|
74 | signal romsn : std_logic; | |
|
75 | signal oen : std_logic; | |
|
76 | signal writen : std_logic; | |
|
77 | signal dsuen, dsutx, dsurx, dsubre, dsuact : std_logic; | |
|
78 | signal dsurst : std_logic; | |
|
79 | signal error : std_logic; | |
|
80 | ||
|
81 | signal sdcke : std_logic; | |
|
82 | signal sdcsn : std_logic; | |
|
83 | signal sdwen : std_logic; -- write en | |
|
84 | signal sdrasn : std_logic; -- row addr stb | |
|
85 | signal sdcasn : std_logic; -- col addr stb | |
|
86 | signal dram_ldqm : std_logic; | |
|
87 | signal dram_udqm : std_logic; | |
|
88 | signal sdclk : std_logic; | |
|
89 | signal dram_ba : std_logic_vector(1 downto 0); | |
|
90 | ||
|
91 | ||
|
92 | ||
|
93 | constant lresp : boolean := false; | |
|
94 | ||
|
95 | ||
|
96 | signal sa : std_logic_vector(12 downto 0); | |
|
97 | signal sd : std_logic_vector(15 downto 0); | |
|
98 | ||
|
99 | ||
|
100 | begin | |
|
101 | ||
|
102 | clk <= not clk after ct * 1 ns; --50 MHz clk | |
|
103 | rst <= dsurst; --reset | |
|
104 | dsuen <= '1'; | |
|
105 | dsubre <= '1'; -- inverted on the board | |
|
106 | sw(1) <= rst; | |
|
107 | ||
|
108 | d3 : entity work.leon3mp | |
|
109 | generic map ( fabtech, memtech, padtech, clktech, disas, dbguart, pclow ) | |
|
110 | port map ( | |
|
111 | CLK50 => clk, | |
|
112 | LEDS => open, | |
|
113 | SW => SW, | |
|
114 | dram_addr => sa, | |
|
115 | dram_ba_0 => dram_ba(0), | |
|
116 | dram_ba_1 => dram_ba(1), | |
|
117 | dram_dq => sd(15 downto 0), | |
|
118 | dram_clk => sdclk, | |
|
119 | dram_cke => sdcke, | |
|
120 | dram_cs_n => sdcsn, | |
|
121 | dram_we_n => sdwen, | |
|
122 | dram_ras_n => sdrasn, | |
|
123 | dram_cas_n => sdcasn, | |
|
124 | dram_ldqm => dram_ldqm, | |
|
125 | dram_udqm => dram_udqm, | |
|
126 | uart_txd => dsutx, | |
|
127 | uart_rxd => dsurx); | |
|
128 | ||
|
129 | u1: entity work.mt48lc16m16a2 generic map (addr_bits => 13, col_bits => 9, index => 1024, fname => sdramfile) | |
|
130 | PORT MAP( | |
|
131 | Dq => sd(15 downto 0), Addr => sa(12 downto 0), | |
|
132 | Ba => dram_ba, Clk => sdclk, Cke => sdcke, | |
|
133 | Cs_n => sdcsn, Ras_n => sdrasn, Cas_n => sdcasn, We_n => sdwen, | |
|
134 | Dqm(0) => dram_ldqm, Dqm(1) => dram_udqm ); | |
|
135 | ||
|
136 | ||
|
137 | ||
|
138 | error <= 'H'; -- ERROR pull-up | |
|
139 | ||
|
140 | iuerr : process | |
|
141 | begin | |
|
142 | wait for 2500 ns; | |
|
143 | if to_x01(error) = '1' then wait on error; end if; | |
|
144 | assert (to_x01(error) = '1') | |
|
145 | report "*** IU in error mode, simulation halted ***" | |
|
146 | severity failure ; | |
|
147 | end process; | |
|
148 | ||
|
149 | data <= buskeep(data) after 5 ns; | |
|
150 | sd <= buskeep(sd) after 5 ns; | |
|
151 | ||
|
152 | dsucom : process | |
|
153 | variable w32 : std_logic_vector(31 downto 0); | |
|
154 | constant txp : time := 160 * 1 ns; | |
|
155 | procedure writeReg(signal dsutx : out std_logic; address : integer; value : integer) is | |
|
156 | begin | |
|
157 | txc(dsutx, 16#c0#, txp); --control byte | |
|
158 | txa(dsutx, (address / (256*256*256)) , (address / (256*256)), (address / (256)), address, txp); --adress | |
|
159 | txa(dsutx, (value / (256*256*256)) , (value / (256*256)), (value / (256)), value, txp); --write data | |
|
160 | end; | |
|
161 | ||
|
162 | procedure readReg(signal dsurx : in std_logic; signal dsutx : out std_logic; address : integer; value: out std_logic_vector) is | |
|
163 | ||
|
164 | begin | |
|
165 | txc(dsutx, 16#a0#, txp); --control byte | |
|
166 | txa(dsutx, (address / (256*256*256)) , (address / (256*256)), (address / (256)), address, txp); --adress | |
|
167 | rxi(dsurx, value, txp, lresp); --write data | |
|
168 | end; | |
|
169 | ||
|
170 | procedure dsucfg(signal dsurx : in std_logic; signal dsutx : out std_logic) is | |
|
171 | variable c8 : std_logic_vector(7 downto 0); | |
|
172 | begin | |
|
173 | dsutx <= '1'; | |
|
174 | dsurst <= '0'; --reset low | |
|
175 | wait for 500 ns; | |
|
176 | dsurst <= '1'; --reset high | |
|
177 | --wait; --evig w8 | |
|
178 | wait for 5000 ns; | |
|
179 | txc(dsutx, 16#55#, txp); | |
|
180 | --dsucfg(dsutx, dsurx); | |
|
181 | writeReg(dsutx,16#40000000#,16#12345678#); | |
|
182 | writeReg(dsutx,16#40000004#,16#22222222#); | |
|
183 | writeReg(dsutx,16#40000008#,16#33333333#); | |
|
184 | writeReg(dsutx,16#4000000C#,16#44444444#); | |
|
185 | ||
|
186 | readReg(dsurx,dsutx,16#40000000#,w32); | |
|
187 | readReg(dsurx,dsutx,16#40000004#,w32); | |
|
188 | readReg(dsurx,dsutx,16#40000008#,w32); | |
|
189 | readReg(dsurx,dsutx,16#4000000C#,w32); | |
|
190 | ||
|
191 | end; | |
|
192 | ||
|
193 | begin | |
|
194 | dsucfg(dsutx, dsurx); | |
|
195 | ||
|
196 | ||
|
197 | wait; | |
|
198 | end process; | |
|
199 | end ; | |
|
200 |
@@ -0,0 +1,143 | |||
|
1 | # Clocks | |
|
2 | NET "CLK50" PERIOD = 20 ns |LOC = "K3"; | |
|
3 | #NET "CLK32" PERIOD = 31.25 ns | LOC = "J4"; | |
|
4 | # LEDs | |
|
5 | NET "LEDS<0>" LOC="P11" |IOSTANDARD=LVTTL |DRIVE=8 |SLEW=SLOW; | |
|
6 | NET "LEDS<1>" LOC="N9" |IOSTANDARD=LVTTL |DRIVE=8 |SLEW=SLOW; | |
|
7 | NET "LEDS<2>" LOC="M9" |IOSTANDARD=LVTTL |DRIVE=8 |SLEW=SLOW; | |
|
8 | NET "LEDS<3>" LOC="P9" |IOSTANDARD=LVTTL |DRIVE=8 |SLEW=SLOW; | |
|
9 | NET "LEDS<4>" LOC="T8" |IOSTANDARD=LVTTL |DRIVE=8 |SLEW=SLOW; | |
|
10 | NET "LEDS<5>" LOC="N8" |IOSTANDARD=LVTTL |DRIVE=8 |SLEW=SLOW; | |
|
11 | NET "LEDS<6>" LOC="P8" |IOSTANDARD=LVTTL |DRIVE=8 |SLEW=SLOW; | |
|
12 | NET "LEDS<7>" LOC="P7" |IOSTANDARD=LVTTL |DRIVE=8 |SLEW=SLOW; | |
|
13 | ||
|
14 | # DIP Switches | |
|
15 | NET "SW<1>" LOC="L1" |IOSTANDARD=LVTTL |PULLUP; | |
|
16 | NET "SW<2>" LOC="L3" |IOSTANDARD=LVTTL |PULLUP; | |
|
17 | NET "SW<3>" LOC="L4" |IOSTANDARD=LVTTL |PULLUP; | |
|
18 | NET "SW<4>" LOC="L5" |IOSTANDARD=LVTTL |PULLUP; | |
|
19 | ||
|
20 | NET "uart_rxd" LOC="M7" |IOSTANDARD=LVTTL; | |
|
21 | NET "uart_txd" LOC="N6" |IOSTANDARD=LVTTL; | |
|
22 | ||
|
23 | # SDRAM | |
|
24 | NET "dram_udqm" LOC="F15" |IOSTANDARD=LVTTL; | |
|
25 | NET "dram_clk" LOC="G16" |IOSTANDARD=LVTTL; | |
|
26 | NET "dram_cke" LOC="H16" |IOSTANDARD=LVTTL; | |
|
27 | NET "dram_ba_1" LOC="T14" |IOSTANDARD=LVTTL; | |
|
28 | NET "dram_ba_0" LOC="R14" |IOSTANDARD=LVTTL; | |
|
29 | NET "dram_cs_n" LOC="R1" |IOSTANDARD=LVTTL; | |
|
30 | NET "dram_ras_n" LOC="R2" |IOSTANDARD=LVTTL; | |
|
31 | NET "dram_cas_n" LOC="T4" |IOSTANDARD=LVTTL; | |
|
32 | NET "dram_we_n" LOC="R5" |IOSTANDARD=LVTTL; | |
|
33 | NET "dram_ldqm" LOC="T5" |IOSTANDARD=LVTTL; | |
|
34 | NET "dram_addr<0>" LOC="T15" |IOSTANDARD=LVTTL; | |
|
35 | NET "dram_addr<1>" LOC="R16" |IOSTANDARD=LVTTL; | |
|
36 | NET "dram_addr<2>" LOC="P15" |IOSTANDARD=LVTTL; | |
|
37 | NET "dram_addr<3>" LOC="P16" |IOSTANDARD=LVTTL; | |
|
38 | NET "dram_addr<4>" LOC="N16" |IOSTANDARD=LVTTL; | |
|
39 | NET "dram_addr<5>" LOC="M15" |IOSTANDARD=LVTTL; | |
|
40 | NET "dram_addr<6>" LOC="M16" |IOSTANDARD=LVTTL; | |
|
41 | NET "dram_addr<7>" LOC="L16" |IOSTANDARD=LVTTL; | |
|
42 | NET "dram_addr<8>" LOC="K15" |IOSTANDARD=LVTTL; | |
|
43 | NET "dram_addr<9>" LOC="K16" |IOSTANDARD=LVTTL; | |
|
44 | NET "dram_addr<10>" LOC="R15" |IOSTANDARD=LVTTL; | |
|
45 | NET "dram_addr<11>" LOC="J16" |IOSTANDARD=LVTTL; | |
|
46 | NET "dram_addr<12>" LOC="H15" |IOSTANDARD=LVTTL; | |
|
47 | NET "dram_dq<0>" LOC="T13" |IOSTANDARD=LVTTL; | |
|
48 | NET "dram_dq<1>" LOC="T12" |IOSTANDARD=LVTTL; | |
|
49 | NET "dram_dq<2>" LOC="R12" |IOSTANDARD=LVTTL; | |
|
50 | NET "dram_dq<3>" LOC="T9" |IOSTANDARD=LVTTL; | |
|
51 | NET "dram_dq<4>" LOC="R9" |IOSTANDARD=LVTTL; | |
|
52 | NET "dram_dq<5>" LOC="T7" |IOSTANDARD=LVTTL; | |
|
53 | NET "dram_dq<6>" LOC="R7" |IOSTANDARD=LVTTL; | |
|
54 | NET "dram_dq<7>" LOC="T6" |IOSTANDARD=LVTTL; | |
|
55 | NET "dram_dq<8>" LOC="F16" |IOSTANDARD=LVTTL; | |
|
56 | NET "dram_dq<9>" LOC="E15" |IOSTANDARD=LVTTL; | |
|
57 | NET "dram_dq<10>" LOC="E16" |IOSTANDARD=LVTTL; | |
|
58 | NET "dram_dq<11>" LOC="D16" |IOSTANDARD=LVTTL; | |
|
59 | NET "dram_dq<12>" LOC="B16" |IOSTANDARD=LVTTL; | |
|
60 | NET "dram_dq<13>" LOC="B15" |IOSTANDARD=LVTTL; | |
|
61 | NET "dram_dq<14>" LOC="C16" |IOSTANDARD=LVTTL; | |
|
62 | NET "dram_dq<15>" LOC="C15" |IOSTANDARD=LVTTL; | |
|
63 | #Created by Constraints Editor (xc6slx25-ftg256-3) - 2016/12/08 | |
|
64 | INST "dram_addr(0)" TNM = dram_addr; | |
|
65 | INST "dram_addr(1)" TNM = dram_addr; | |
|
66 | INST "dram_addr(2)" TNM = dram_addr; | |
|
67 | INST "dram_addr(3)" TNM = dram_addr; | |
|
68 | INST "dram_addr(4)" TNM = dram_addr; | |
|
69 | INST "dram_addr(5)" TNM = dram_addr; | |
|
70 | INST "dram_addr(6)" TNM = dram_addr; | |
|
71 | INST "dram_addr(7)" TNM = dram_addr; | |
|
72 | INST "dram_addr(8)" TNM = dram_addr; | |
|
73 | INST "dram_addr(9)" TNM = dram_addr; | |
|
74 | INST "dram_addr(10)" TNM = dram_addr; | |
|
75 | INST "dram_addr(11)" TNM = dram_addr; | |
|
76 | INST "dram_addr(12)" TNM = dram_addr; | |
|
77 | INST "dram_addr(0)" TNM = dram_out; | |
|
78 | INST "dram_addr(1)" TNM = dram_out; | |
|
79 | INST "dram_addr(2)" TNM = dram_out; | |
|
80 | INST "dram_addr(3)" TNM = dram_out; | |
|
81 | INST "dram_addr(4)" TNM = dram_out; | |
|
82 | INST "dram_addr(5)" TNM = dram_out; | |
|
83 | INST "dram_addr(6)" TNM = dram_out; | |
|
84 | INST "dram_addr(7)" TNM = dram_out; | |
|
85 | INST "dram_addr(8)" TNM = dram_out; | |
|
86 | INST "dram_addr(9)" TNM = dram_out; | |
|
87 | INST "dram_addr(10)" TNM = dram_out; | |
|
88 | INST "dram_addr(11)" TNM = dram_out; | |
|
89 | INST "dram_addr(12)" TNM = dram_out; | |
|
90 | INST "dram_ba_0" TNM = dram_out; | |
|
91 | INST "dram_ba_1" TNM = dram_out; | |
|
92 | INST "dram_cas_n" TNM = dram_out; | |
|
93 | INST "dram_cke" TNM = dram_out; | |
|
94 | #INST "dram_clk" TNM = dram_out; | |
|
95 | INST "dram_cs_n" TNM = dram_out; | |
|
96 | INST "dram_dq(0)" TNM = dram_out; | |
|
97 | INST "dram_dq(1)" TNM = dram_out; | |
|
98 | INST "dram_dq(2)" TNM = dram_out; | |
|
99 | INST "dram_dq(3)" TNM = dram_out; | |
|
100 | INST "dram_dq(4)" TNM = dram_out; | |
|
101 | INST "dram_dq(5)" TNM = dram_out; | |
|
102 | INST "dram_dq(6)" TNM = dram_out; | |
|
103 | INST "dram_dq(7)" TNM = dram_out; | |
|
104 | INST "dram_dq(8)" TNM = dram_out; | |
|
105 | INST "dram_dq(9)" TNM = dram_out; | |
|
106 | INST "dram_dq(10)" TNM = dram_out; | |
|
107 | INST "dram_dq(11)" TNM = dram_out; | |
|
108 | INST "dram_dq(12)" TNM = dram_out; | |
|
109 | INST "dram_dq(13)" TNM = dram_out; | |
|
110 | INST "dram_dq(14)" TNM = dram_out; | |
|
111 | INST "dram_dq(15)" TNM = dram_out; | |
|
112 | INST "dram_ldqm" TNM = dram_out; | |
|
113 | INST "dram_ras_n" TNM = dram_out; | |
|
114 | INST "dram_udqm" TNM = dram_out; | |
|
115 | INST "dram_we_n" TNM = dram_out; | |
|
116 | TIMEGRP "dram_out" OFFSET = OUT 12 ns AFTER "CLK50"; | |
|
117 | INST "dram_dq(0)" TNM = dram_in; | |
|
118 | INST "dram_dq(1)" TNM = dram_in; | |
|
119 | INST "dram_dq(2)" TNM = dram_in; | |
|
120 | INST "dram_dq(3)" TNM = dram_in; | |
|
121 | INST "dram_dq(4)" TNM = dram_in; | |
|
122 | INST "dram_dq(5)" TNM = dram_in; | |
|
123 | INST "dram_dq(6)" TNM = dram_in; | |
|
124 | INST "dram_dq(7)" TNM = dram_in; | |
|
125 | INST "dram_dq(8)" TNM = dram_in; | |
|
126 | INST "dram_dq(9)" TNM = dram_in; | |
|
127 | INST "dram_dq(10)" TNM = dram_in; | |
|
128 | INST "dram_dq(11)" TNM = dram_in; | |
|
129 | INST "dram_dq(12)" TNM = dram_in; | |
|
130 | INST "dram_dq(13)" TNM = dram_in; | |
|
131 | INST "dram_dq(14)" TNM = dram_in; | |
|
132 | INST "dram_dq(15)" TNM = dram_in; | |
|
133 | TIMEGRP "dram_in" OFFSET = IN 3 ns BEFORE "CLK50" RISING; | |
|
134 | ||
|
135 | ||
|
136 | NET "spw_rxdp" LOC = "h2";# | IOSTANDARD = LVDS_33; | |
|
137 | NET "spw_rxdn" LOC = "h1";# | IOSTANDARD = LVDS_33; | |
|
138 | NET "spw_rxsp" LOC = "f4";# | IOSTANDARD = LVDS_33; | |
|
139 | NET "spw_rxsn" LOC = "f3";# | IOSTANDARD = LVDS_33; | |
|
140 | NET "spw_txdp" LOC = "e2";# | IOSTANDARD = LVTTL; | |
|
141 | NET "spw_txdn" LOC = "e1";# | IOSTANDARD = LVTTL; | |
|
142 | NET "spw_txsp" LOC = "g3";# | IOSTANDARD = LVTTL; | |
|
143 | NET "spw_txsn" LOC = "g1";# | IOSTANDARD = LVTTL; |
@@ -0,0 +1,83 | |||
|
1 | ------------------------------------------------------------------------------ | |
|
2 | -- This file is a part of the LPP VHDL IP LIBRARY | |
|
3 | -- Copyright (C) 2016, Laboratory of Plasmas Physic - CNRS | |
|
4 | -- | |
|
5 | -- This program is free software; you can redistribute it and/or modify | |
|
6 | -- it under the terms of the GNU General Public License as published by | |
|
7 | -- the Free Software Foundation; either version 3 of the License, or | |
|
8 | -- (at your option) any later version. | |
|
9 | -- | |
|
10 | -- This program is distributed in the hope that it will be useful, | |
|
11 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of | |
|
12 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
|
13 | -- GNU General Public License for more details. | |
|
14 | -- | |
|
15 | -- You should have received a copy of the GNU General Public License | |
|
16 | -- along with this program; if not, write to the Free Software | |
|
17 | -- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
|
18 | ------------------------------------------------------------------------------ | |
|
19 | -- Author : Alexis Jeandet | |
|
20 | -- Mail : alexis.jeandet@lpp.polytechnique.fr | |
|
21 | ------------------------------------------------------------------------------ | |
|
22 | library ieee; | |
|
23 | use ieee.std_logic_1164.all; | |
|
24 | library grlib; | |
|
25 | use grlib.amba.all; | |
|
26 | use grlib.stdlib.all; | |
|
27 | use grlib.devices.all; | |
|
28 | library gaisler; | |
|
29 | use gaisler.libdcom.all; | |
|
30 | use gaisler.uart.all; | |
|
31 | library lpp; | |
|
32 | use lpp.lpp_usb.all; | |
|
33 | use lpp.lpp_amba.all; | |
|
34 | use lpp.apb_devices_list.all; | |
|
35 | ||
|
36 | ||
|
37 | entity ahb_ftdi_fifo is | |
|
38 | generic ( | |
|
39 | oepol : integer := 0; | |
|
40 | hindex : integer := 0 | |
|
41 | ); | |
|
42 | port ( | |
|
43 | clk : in std_logic; | |
|
44 | rstn : in std_logic; | |
|
45 | ||
|
46 | ahbi : in ahb_mst_in_type; | |
|
47 | ahbo : out ahb_mst_out_type; | |
|
48 | ||
|
49 | FTDI_RXF : in std_logic; | |
|
50 | FTDI_TXE : in std_logic; | |
|
51 | FTDI_SIWUA : out std_logic; | |
|
52 | FTDI_WR : out std_logic; | |
|
53 | FTDI_RD : out std_logic; | |
|
54 | FTDI_D_in : in std_logic_vector(7 downto 0); | |
|
55 | FTDI_D_out : out std_logic_vector(7 downto 0); | |
|
56 | FTDI_D_drive : out std_logic | |
|
57 | ); | |
|
58 | end ahb_ftdi_fifo; | |
|
59 | ||
|
60 | architecture beh of ahb_ftdi_fifo is | |
|
61 | ||
|
62 | constant REVISION : integer := 0; | |
|
63 | ||
|
64 | signal dmai : ahb_dma_in_type; | |
|
65 | signal dmao : ahb_dma_out_type; | |
|
66 | signal duarti : dcom_uart_in_type; | |
|
67 | signal duarto : dcom_uart_out_type; | |
|
68 | ||
|
69 | begin | |
|
70 | ||
|
71 | ahbmst0 : ahbmst | |
|
72 | generic map (hindex => hindex, venid => VENDOR_LPP, devid => LPP_AHB_FTDI_FIFO) | |
|
73 | port map (rstn, clk, dmai, dmao, ahbi, ahbo); | |
|
74 | ||
|
75 | dcom_fifo0 : ftdi_async_fifo generic map (oepol) | |
|
76 | port map (clk, rstn, duarti, duarto, FTDI_RXF, FTDI_TXE, FTDI_SIWUA, | |
|
77 | FTDI_WR, FTDI_RD, FTDI_D_in, FTDI_D_out, FTDI_D_drive); | |
|
78 | ||
|
79 | dcom0 : dcom port map (rstn, clk, dmai, dmao, duarti, duarto, ahbi); | |
|
80 | ||
|
81 | ||
|
82 | end beh; | |
|
83 |
@@ -0,0 +1,142 | |||
|
1 | ------------------------------------------------------------------------------ | |
|
2 | -- This file is a part of the LPP VHDL IP LIBRARY | |
|
3 | -- Copyright (C) 2016, Laboratory of Plasmas Physic - CNRS | |
|
4 | -- | |
|
5 | -- This program is free software; you can redistribute it and/or modify | |
|
6 | -- it under the terms of the GNU General Public License as published by | |
|
7 | -- the Free Software Foundation; either version 3 of the License, or | |
|
8 | -- (at your option) any later version. | |
|
9 | -- | |
|
10 | -- This program is distributed in the hope that it will be useful, | |
|
11 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of | |
|
12 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
|
13 | -- GNU General Public License for more details. | |
|
14 | -- | |
|
15 | -- You should have received a copy of the GNU General Public License | |
|
16 | -- along with this program; if not, write to the Free Software | |
|
17 | -- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
|
18 | ------------------------------------------------------------------------------ | |
|
19 | -- Author : Alexis Jeandet | |
|
20 | -- Mail : alexis.jeandet@lpp.polytechnique.fr | |
|
21 | ------------------------------------------------------------------------------ | |
|
22 | library ieee; | |
|
23 | use ieee.std_logic_1164.all; | |
|
24 | library grlib; | |
|
25 | use grlib.stdlib.all; | |
|
26 | use grlib.devices.all; | |
|
27 | library gaisler; | |
|
28 | use gaisler.libdcom.all; | |
|
29 | use gaisler.uart.all; | |
|
30 | library lpp; | |
|
31 | use lpp.lpp_usb.all; | |
|
32 | ||
|
33 | ||
|
34 | entity ftdi_async_fifo is | |
|
35 | generic ( | |
|
36 | oepol : integer := 0 | |
|
37 | ); | |
|
38 | port ( | |
|
39 | clk : in std_logic; | |
|
40 | rstn : in std_logic; | |
|
41 | ||
|
42 | dcom_in : in dcom_uart_in_type; | |
|
43 | dcom_out : out dcom_uart_out_type; | |
|
44 | ||
|
45 | FTDI_RXF : in std_logic; | |
|
46 | FTDI_TXE : in std_logic; | |
|
47 | FTDI_SIWUA : out std_logic; | |
|
48 | FTDI_WR : out std_logic; | |
|
49 | FTDI_RD : out std_logic; | |
|
50 | FTDI_D_in : in std_logic_vector(7 downto 0); | |
|
51 | FTDI_D_out : out std_logic_vector(7 downto 0); | |
|
52 | FTDI_D_drive : out std_logic | |
|
53 | ); | |
|
54 | end ftdi_async_fifo; | |
|
55 | ||
|
56 | architecture beh of ftdi_async_fifo is | |
|
57 | ||
|
58 | type fifo_fsm_st is (idle,waitForTXE,preWrite,Write,postWrite,preRead,Read,postRead); | |
|
59 | signal state : fifo_fsm_st:=idle; | |
|
60 | signal output_en : std_logic; | |
|
61 | signal dready : std_logic; | |
|
62 | ||
|
63 | begin | |
|
64 | ||
|
65 | acthi: if oepol = 1 generate | |
|
66 | output_en <= '1'; | |
|
67 | end generate; | |
|
68 | actlow: if oepol = 0 generate | |
|
69 | output_en <= '0'; | |
|
70 | end generate; | |
|
71 | ||
|
72 | dcom_out.dready <= dready; | |
|
73 | FTDI_SIWUA <= '1'; | |
|
74 | ||
|
75 | process(rstn,clk) | |
|
76 | begin | |
|
77 | if rstn = '0' then | |
|
78 | FTDI_RD <= '1'; | |
|
79 | FTDI_WR <= '1'; | |
|
80 | FTDI_D_drive <= not output_en; | |
|
81 | dready <= '0'; | |
|
82 | dcom_out.tsempty <= '0'; | |
|
83 | dcom_out.thempty <= '1'; | |
|
84 | dcom_out.lock <= '1'; | |
|
85 | dcom_out.data <= (others => '0'); | |
|
86 | elsif clk'event and clk='1' then | |
|
87 | case state is | |
|
88 | when idle => | |
|
89 | if dcom_in.read = '1' then | |
|
90 | dready <= '0'; | |
|
91 | end if; | |
|
92 | FTDI_D_drive <= not output_en; | |
|
93 | FTDI_WR <= '1'; | |
|
94 | dcom_out.thempty <= '1'; | |
|
95 | if dcom_in.write = '1' then | |
|
96 | dcom_out.thempty <= '0'; | |
|
97 | state <= waitForTXE; | |
|
98 | elsif FTDI_RXF = '0' and dready = '0' then | |
|
99 | state <= preRead; | |
|
100 | FTDI_RD <= '0'; | |
|
101 | end if; | |
|
102 | when waitForTXE => | |
|
103 | if FTDI_TXE = '0' then | |
|
104 | state <= preWrite; | |
|
105 | FTDI_D_drive <= output_en; | |
|
106 | FTDI_D_out <= dcom_in.data; | |
|
107 | end if; | |
|
108 | when preWrite => | |
|
109 | FTDI_WR <= '0'; | |
|
110 | state <= Write; | |
|
111 | when Write => | |
|
112 | FTDI_D_drive <= not output_en; | |
|
113 | state <= idle; | |
|
114 | when preRead => | |
|
115 | state <= Read; | |
|
116 | dcom_out.data <= FTDI_D_in; | |
|
117 | when Read => | |
|
118 | FTDI_RD <= '1'; | |
|
119 | dready <= '1'; | |
|
120 | state <= idle; | |
|
121 | when others => NULL; | |
|
122 | end case; | |
|
123 | end if; | |
|
124 | end process; | |
|
125 | ||
|
126 | end beh; | |
|
127 | ||
|
128 | -- type dcom_uart_in_type is record | |
|
129 | -- read : std_ulogic; | |
|
130 | -- write : std_ulogic; | |
|
131 | -- data : std_logic_vector(7 downto 0); | |
|
132 | -- end record; | |
|
133 | ||
|
134 | -- type dcom_uart_out_type is record | |
|
135 | -- dready : std_ulogic; -> data from ftdi to DCOM | |
|
136 | -- tsempty : std_ulogic; -> not used by decom -> set to 0 | |
|
137 | -- thempty : std_ulogic; -> tels dcom that ready to write to ftdi | |
|
138 | -- lock : std_ulogic; -> set to 1 | |
|
139 | -- enable : std_ulogic; -> unused | |
|
140 | -- data : std_logic_vector(7 downto 0); | |
|
141 | -- end record; | |
|
142 |
@@ -0,0 +1,132 | |||
|
1 | ------------------------------------------------------------------------------ | |
|
2 | -- This file is a part of the LPP VHDL IP LIBRARY | |
|
3 | -- Copyright (C) 2016, Laboratory of Plasmas Physic - CNRS | |
|
4 | -- | |
|
5 | -- This program is free software; you can redistribute it and/or modify | |
|
6 | -- it under the terms of the GNU General Public License as published by | |
|
7 | -- the Free Software Foundation; either version 3 of the License, or | |
|
8 | -- (at your option) any later version. | |
|
9 | -- | |
|
10 | -- This program is distributed in the hope that it will be useful, | |
|
11 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of | |
|
12 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
|
13 | -- GNU General Public License for more details. | |
|
14 | -- | |
|
15 | -- You should have received a copy of the GNU General Public License | |
|
16 | -- along with this program; if not, write to the Free Software | |
|
17 | -- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
|
18 | ------------------------------------------------------------------------------ | |
|
19 | -- Author : Alexis Jeandet | |
|
20 | -- Mail : alexis.jeandet@lpp.polytechnique.fr | |
|
21 | ------------------------------------------------------------------------------ | |
|
22 | library ieee; | |
|
23 | use ieee.std_logic_1164.all; | |
|
24 | library grlib; | |
|
25 | use grlib.stdlib.all; | |
|
26 | use grlib.devices.all; | |
|
27 | library gaisler; | |
|
28 | use gaisler.libdcom.all; | |
|
29 | use gaisler.uart.all; | |
|
30 | library lpp; | |
|
31 | use lpp.lpp_usb.all; | |
|
32 | ||
|
33 | ||
|
34 | entity ftdi_async_fifo_loopback is | |
|
35 | generic ( | |
|
36 | oepol : integer := 0 | |
|
37 | ); | |
|
38 | port ( | |
|
39 | clk : in std_logic; | |
|
40 | rstn : in std_logic; | |
|
41 | ||
|
42 | ||
|
43 | FTDI_RXF : in std_logic; | |
|
44 | FTDI_TXE : in std_logic; | |
|
45 | FTDI_SIWUA : out std_logic; | |
|
46 | FTDI_WR : out std_logic; | |
|
47 | FTDI_RD : out std_logic; | |
|
48 | FTDI_D_in : in std_logic_vector(7 downto 0); | |
|
49 | FTDI_D_out : out std_logic_vector(7 downto 0); | |
|
50 | FTDI_D_drive : out std_logic | |
|
51 | ); | |
|
52 | end ftdi_async_fifo_loopback; | |
|
53 | ||
|
54 | architecture beh of ftdi_async_fifo_loopback is | |
|
55 | ||
|
56 | type fifo_fsm_st is (idle,waitTXE,preWrite,Write,postWrite,preRead,Read,postRead); | |
|
57 | signal state : fifo_fsm_st:=idle; | |
|
58 | signal output_en : std_logic; | |
|
59 | signal dready : std_logic; | |
|
60 | signal fifo_flush_cntr : integer := 31; | |
|
61 | signal fifo_siwu_pulse : std_logic_vector(3 downto 0):= (others => '1'); | |
|
62 | ||
|
63 | begin | |
|
64 | ||
|
65 | acthi: if oepol = 1 generate | |
|
66 | output_en <= '1'; | |
|
67 | end generate; | |
|
68 | actlow: if oepol = 0 generate | |
|
69 | output_en <= '0'; | |
|
70 | end generate; | |
|
71 | ||
|
72 | FTDI_SIWUA <= '1';--fifo_siwu_pulse(0); | |
|
73 | ||
|
74 | process(rstn,clk) | |
|
75 | begin | |
|
76 | if rstn = '0' then | |
|
77 | FTDI_RD <= '1'; | |
|
78 | FTDI_WR <= '1'; | |
|
79 | FTDI_D_drive <= not output_en; | |
|
80 | elsif clk'event and clk='1' then | |
|
81 | if fifo_flush_cntr = 1 then | |
|
82 | fifo_siwu_pulse <= (others => '0'); | |
|
83 | else | |
|
84 | fifo_siwu_pulse <= '1' & fifo_siwu_pulse(3 downto 1); | |
|
85 | end if; | |
|
86 | case state is | |
|
87 | when idle => | |
|
88 | if FTDI_RXF = '0' then | |
|
89 | state <= preRead; | |
|
90 | FTDI_RD <= '0'; | |
|
91 | end if; | |
|
92 | FTDI_WR <= '1'; | |
|
93 | when preWrite => | |
|
94 | FTDI_WR <= '0'; | |
|
95 | state <= Write; | |
|
96 | when Write => | |
|
97 | FTDI_D_drive <= not output_en; | |
|
98 | state <= idle; | |
|
99 | fifo_flush_cntr <= 31; | |
|
100 | when preRead => | |
|
101 | state <= Read; | |
|
102 | when Read => | |
|
103 | FTDI_D_out <= FTDI_D_in; | |
|
104 | FTDI_RD <= '1'; | |
|
105 | state <= waitTXE; | |
|
106 | when waitTXE => | |
|
107 | if FTDI_TXE = '0' then | |
|
108 | state <= preWrite; | |
|
109 | FTDI_D_drive <= output_en; | |
|
110 | end if; | |
|
111 | when others => NULL; | |
|
112 | end case; | |
|
113 | end if; | |
|
114 | end process; | |
|
115 | ||
|
116 | end beh; | |
|
117 | ||
|
118 | -- type dcom_uart_in_type is record | |
|
119 | -- read : std_ulogic; | |
|
120 | -- write : std_ulogic; | |
|
121 | -- data : std_logic_vector(7 downto 0); | |
|
122 | -- end record; | |
|
123 | ||
|
124 | -- type dcom_uart_out_type is record | |
|
125 | -- dready : std_ulogic; -> data from ftdi to DCOM | |
|
126 | -- tsempty : std_ulogic; -> not used by decom -> set to 0 | |
|
127 | -- thempty : std_ulogic; -> tels dcom that ready to write to ftdi | |
|
128 | -- lock : std_ulogic; -> set to 1 | |
|
129 | -- enable : std_ulogic; -> unused | |
|
130 | -- data : std_logic_vector(7 downto 0); | |
|
131 | -- end record; | |
|
132 |
This diff has been collapsed as it changes many lines, (739 lines changed) Show them Hide them | |||
@@ -0,0 +1,739 | |||
|
1 | -- | |
|
2 | -- AHB master for AMBA interface. | |
|
3 | -- | |
|
4 | -- This is a helper entity for the SpaceWire AMBA interface. | |
|
5 | -- It implements the AHB master which transfers data from/to main memory. | |
|
6 | -- | |
|
7 | -- Descriptor flag bits on input: | |
|
8 | -- bit 15:0 (RX) max nr of bytes to receive (must be a multiple of 4) | |
|
9 | -- (TX) nr of bytes to transmit | |
|
10 | -- bit 16 EN: '1' = descriptor enabled | |
|
11 | -- bit 17 WR: wrap to beginning of descriptor table | |
|
12 | -- bit 18 IE: interrupt at end of descriptor | |
|
13 | -- bit 19 '0' | |
|
14 | -- bit 20 (TX only) send EOP after end of data | |
|
15 | -- bit 21 (TX only) send EEP after end of data | |
|
16 | -- | |
|
17 | -- Descriptor flag bits after completion of frame: | |
|
18 | -- bit 15:0 (RX only) LEN: nr of bytes received | |
|
19 | -- (TX) undefined | |
|
20 | -- bit 16 '0' | |
|
21 | -- bit 18:17 undefined | |
|
22 | -- bit 19 '1' to indicate descriptor completed | |
|
23 | --- bit 20 (RX only) received EOP after end of data | |
|
24 | -- bit 21 (RX only) received EEP after end of data | |
|
25 | -- | |
|
26 | ||
|
27 | library ieee; | |
|
28 | use ieee.std_logic_1164.all; | |
|
29 | use ieee.numeric_std.all; | |
|
30 | library grlib; | |
|
31 | use grlib.amba.all; | |
|
32 | use grlib.stdlib.all; | |
|
33 | use work.spwambapkg.all; | |
|
34 | ||
|
35 | ||
|
36 | entity spwahbmst is | |
|
37 | ||
|
38 | generic ( | |
|
39 | -- AHB master index. | |
|
40 | hindex: integer; | |
|
41 | ||
|
42 | -- AHB plug&play information. | |
|
43 | hconfig: ahb_config_type; | |
|
44 | ||
|
45 | -- Maximum burst length as the 2-logarithm of the number of words. | |
|
46 | maxburst: integer range 1 to 8 | |
|
47 | ); | |
|
48 | ||
|
49 | port ( | |
|
50 | -- System clock. | |
|
51 | clk: in std_logic; | |
|
52 | ||
|
53 | -- Synchronous reset (active-low). | |
|
54 | rstn: in std_logic; | |
|
55 | ||
|
56 | -- Inputs from SpaceWire core. | |
|
57 | msti: in spw_ahbmst_in_type; | |
|
58 | ||
|
59 | -- Outputs to SpaceWire core. | |
|
60 | msto: out spw_ahbmst_out_type; | |
|
61 | ||
|
62 | -- AHB master input signals. | |
|
63 | ahbi: in ahb_mst_in_type; | |
|
64 | ||
|
65 | -- AHB master output signals. | |
|
66 | ahbo: out ahb_mst_out_type | |
|
67 | ); | |
|
68 | ||
|
69 | end entity spwahbmst; | |
|
70 | ||
|
71 | architecture spwahbmst_arch of spwahbmst is | |
|
72 | ||
|
73 | -- | |
|
74 | -- Registers. | |
|
75 | -- | |
|
76 | ||
|
77 | type state_type is ( | |
|
78 | st_idle, | |
|
79 | st_rxgetdesc, st_rxgetptr, st_rxtransfer, st_rxfinal, st_rxputdesc, | |
|
80 | st_txgetdesc, st_txgetptr, st_txtransfer, st_txfinal, st_txputdesc, st_txskip ); | |
|
81 | ||
|
82 | type burst_state_type is ( bs_idle, bs_setup, bs_active, bs_end ); | |
|
83 | ||
|
84 | type regs_type is record | |
|
85 | -- dma state | |
|
86 | rxdma_act: std_ulogic; | |
|
87 | txdma_act: std_ulogic; | |
|
88 | ahberror: std_ulogic; | |
|
89 | -- main state machine | |
|
90 | mstate: state_type; | |
|
91 | firstword: std_ulogic; | |
|
92 | prefertx: std_ulogic; | |
|
93 | -- rx descriptor state | |
|
94 | rxdes_en: std_ulogic; | |
|
95 | rxdes_wr: std_ulogic; | |
|
96 | rxdes_ie: std_ulogic; | |
|
97 | rxdes_eop: std_ulogic; | |
|
98 | rxdes_eep: std_ulogic; | |
|
99 | rxdes_len: std_logic_vector(13 downto 0); -- in 32-bit words | |
|
100 | rxdes_pos: std_logic_vector(15 downto 0); -- in bytes | |
|
101 | rxaddr: std_logic_vector(31 downto 2); | |
|
102 | rxdesc_next: std_ulogic; | |
|
103 | -- tx descriptor state | |
|
104 | txdes_en: std_ulogic; | |
|
105 | txdes_wr: std_ulogic; | |
|
106 | txdes_ie: std_ulogic; | |
|
107 | txdes_eop: std_ulogic; | |
|
108 | txdes_eep: std_ulogic; | |
|
109 | txdes_len: std_logic_vector(15 downto 0); -- in bytes | |
|
110 | txaddr: std_logic_vector(31 downto 2); | |
|
111 | txdesc_next: std_ulogic; | |
|
112 | -- interrupts | |
|
113 | int_rxdesc: std_ulogic; | |
|
114 | int_txdesc: std_ulogic; | |
|
115 | int_rxpacket: std_ulogic; | |
|
116 | -- burst state | |
|
117 | burststat: burst_state_type; | |
|
118 | hbusreq: std_ulogic; | |
|
119 | hwrite: std_ulogic; | |
|
120 | haddr: std_logic_vector(31 downto 2); | |
|
121 | hwdata: std_logic_vector(31 downto 0); | |
|
122 | end record; | |
|
123 | ||
|
124 | constant regs_reset: regs_type := ( | |
|
125 | rxdma_act => '0', | |
|
126 | txdma_act => '0', | |
|
127 | ahberror => '0', | |
|
128 | mstate => st_idle, | |
|
129 | firstword => '0', | |
|
130 | prefertx => '0', | |
|
131 | rxdes_en => '0', | |
|
132 | rxdes_wr => '0', | |
|
133 | rxdes_ie => '0', | |
|
134 | rxdes_eop => '0', | |
|
135 | rxdes_eep => '0', | |
|
136 | rxdes_len => (others => '0'), | |
|
137 | rxdes_pos => (others => '0'), | |
|
138 | rxaddr => (others => '0'), | |
|
139 | rxdesc_next => '0', | |
|
140 | txdes_en => '0', | |
|
141 | txdes_wr => '0', | |
|
142 | txdes_ie => '0', | |
|
143 | txdes_eop => '0', | |
|
144 | txdes_eep => '0', | |
|
145 | txdes_len => (others => '0'), | |
|
146 | txaddr => (others => '0'), | |
|
147 | txdesc_next => '0', | |
|
148 | int_rxdesc => '0', | |
|
149 | int_txdesc => '0', | |
|
150 | int_rxpacket => '0', | |
|
151 | burststat => bs_idle, | |
|
152 | hbusreq => '0', | |
|
153 | hwrite => '0', | |
|
154 | haddr => (others => '0'), | |
|
155 | hwdata => (others => '0') ); | |
|
156 | ||
|
157 | signal r: regs_type := regs_reset; | |
|
158 | signal rin: regs_type; | |
|
159 | ||
|
160 | begin | |
|
161 | ||
|
162 | -- | |
|
163 | -- Combinatorial process | |
|
164 | -- | |
|
165 | process (r, rstn, msti, ahbi) is | |
|
166 | variable v: regs_type; | |
|
167 | variable v_hrdata: std_logic_vector(31 downto 0); | |
|
168 | variable v_burstreq: std_logic; | |
|
169 | variable v_burstack: std_logic; | |
|
170 | variable v_rxfifo_read: std_logic; | |
|
171 | variable v_txfifo_write: std_logic; | |
|
172 | variable v_txfifo_wdata: std_logic_vector(35 downto 0); | |
|
173 | begin | |
|
174 | v := r; | |
|
175 | ||
|
176 | -- Decode AHB data bus (64-bit AHB compatibility). | |
|
177 | v_hrdata := ahbreadword(ahbi.hrdata); | |
|
178 | ||
|
179 | -- Assume no burst request. | |
|
180 | v_burstreq := '0'; | |
|
181 | ||
|
182 | -- Detect request from burst state machine for next data word. | |
|
183 | v_burstack := ahbi.hready and | |
|
184 | conv_std_logic(r.burststat = bs_active or r.burststat = bs_end); | |
|
185 | ||
|
186 | -- Assume no fifo activity; take data for TX fifo from AHB bus. | |
|
187 | v_rxfifo_read := '0'; | |
|
188 | v_txfifo_write := '0'; | |
|
189 | v_txfifo_wdata(35 downto 32) := (others => '0'); | |
|
190 | v_txfifo_wdata(31 downto 0) := v_hrdata; | |
|
191 | ||
|
192 | -- Reset registers for interrupts and descriptor updates. | |
|
193 | v.int_rxdesc := '0'; | |
|
194 | v.int_txdesc := '0'; | |
|
195 | v.int_rxpacket := '0'; | |
|
196 | v.rxdesc_next := '0'; | |
|
197 | v.txdesc_next := '0'; | |
|
198 | ||
|
199 | -- Start DMA on external request. | |
|
200 | if msti.rxdma_start = '1' then v.rxdma_act := '1'; end if; | |
|
201 | if msti.txdma_start = '1' then v.txdma_act := '1'; end if; | |
|
202 | ||
|
203 | -- | |
|
204 | -- Main state machine. | |
|
205 | -- | |
|
206 | case r.mstate is | |
|
207 | ||
|
208 | when st_idle => | |
|
209 | -- Waiting for something to do. | |
|
210 | v.prefertx := '0'; | |
|
211 | v.firstword := '1'; | |
|
212 | if msti.txdma_cancel = '1' then | |
|
213 | v.txdma_act := '0'; | |
|
214 | v.txdes_en := '0'; | |
|
215 | end if; | |
|
216 | if r.rxdma_act = '1' and msti.rxfifo_empty = '0' and | |
|
217 | (r.prefertx = '0' or r.txdma_act = '0' or msti.txfifo_highw = '1') then | |
|
218 | -- Start RX transfer. | |
|
219 | if r.rxdes_en = '1' then | |
|
220 | -- Transfer RX data to current descriptor. | |
|
221 | v_burstreq := '1'; | |
|
222 | v.hwrite := '1'; | |
|
223 | v.haddr := r.rxaddr; | |
|
224 | v.mstate := st_rxtransfer; | |
|
225 | else | |
|
226 | -- Must fetch new RX descriptor. | |
|
227 | v_burstreq := '1'; | |
|
228 | v.hwrite := '0'; | |
|
229 | v.haddr := msti.rxdesc_ptr & "0"; | |
|
230 | v.mstate := st_rxgetdesc; | |
|
231 | end if; | |
|
232 | elsif r.txdma_act = '1' and msti.txdma_cancel = '0' and msti.txfifo_highw = '0' then | |
|
233 | -- Start TX transfer. | |
|
234 | if r.txdes_en = '1' then | |
|
235 | -- Transfer TX data from current descriptor. | |
|
236 | if unsigned(r.txdes_len) = 0 then | |
|
237 | -- Only send EOP/EEP and write back descriptor. | |
|
238 | v_burstreq := '1'; | |
|
239 | v.hwrite := '1'; | |
|
240 | v.haddr := msti.txdesc_ptr & "0"; | |
|
241 | v.txdesc_next := '1'; | |
|
242 | v.mstate := st_txputdesc; | |
|
243 | else | |
|
244 | -- Start burst transfer. | |
|
245 | v_burstreq := '1'; | |
|
246 | v.hwrite := '0'; | |
|
247 | v.haddr := r.txaddr; | |
|
248 | if unsigned(r.txdes_len) <= 4 then | |
|
249 | -- Transfer only one word. | |
|
250 | v.mstate := st_txfinal; | |
|
251 | else | |
|
252 | v.mstate := st_txtransfer; | |
|
253 | end if; | |
|
254 | end if; | |
|
255 | else | |
|
256 | -- Must fetch new TX descriptor. | |
|
257 | v_burstreq := '1'; | |
|
258 | v.hwrite := '0'; | |
|
259 | v.haddr := msti.txdesc_ptr & "0"; | |
|
260 | v.mstate := st_txgetdesc; | |
|
261 | end if; | |
|
262 | end if; | |
|
263 | ||
|
264 | when st_rxgetdesc => | |
|
265 | -- Read RX descriptor flags from memory. | |
|
266 | v_burstreq := '1'; | |
|
267 | v.hwrite := '0'; | |
|
268 | v.rxdes_len := v_hrdata(15 downto 2); | |
|
269 | v.rxdes_en := v_hrdata(16); | |
|
270 | v.rxdes_wr := v_hrdata(17); | |
|
271 | v.rxdes_ie := v_hrdata(18); | |
|
272 | v.rxdes_eop := '0'; | |
|
273 | v.rxdes_eep := '0'; | |
|
274 | v.rxdes_pos := (others => '0'); | |
|
275 | if v_burstack = '1' then | |
|
276 | -- Got descriptor flags. | |
|
277 | v_burstreq := '0'; | |
|
278 | v.mstate := st_rxgetptr; | |
|
279 | end if; | |
|
280 | ||
|
281 | when st_rxgetptr => | |
|
282 | -- Read RX data pointer from memory. | |
|
283 | v.rxaddr := v_hrdata(31 downto 2); | |
|
284 | v.haddr := v_hrdata(31 downto 2); | |
|
285 | v.firstword := '1'; | |
|
286 | if v_burstack = '1' then | |
|
287 | -- Got data pointer. | |
|
288 | if r.rxdes_en = '1' then | |
|
289 | -- Start transfer. | |
|
290 | v_burstreq := '1'; | |
|
291 | v.hwrite := '1'; | |
|
292 | v.mstate := st_rxtransfer; | |
|
293 | else | |
|
294 | -- Reached end of valid descriptors; stop. | |
|
295 | v.rxdma_act := '0'; | |
|
296 | v.mstate := st_idle; | |
|
297 | end if; | |
|
298 | end if; | |
|
299 | ||
|
300 | when st_rxtransfer => | |
|
301 | -- Continue an RX transfer. | |
|
302 | v_burstreq := '1'; | |
|
303 | v.hwrite := '1'; | |
|
304 | v.firstword := '0'; | |
|
305 | if v_burstack = '1' or r.firstword = '1' then | |
|
306 | -- Setup first/next data word. | |
|
307 | v.hwdata := msti.rxfifo_rdata(31 downto 0); | |
|
308 | v_rxfifo_read := '1'; | |
|
309 | -- Update pointers. | |
|
310 | v.rxdes_len := std_logic_vector(unsigned(r.rxdes_len) - 1); | |
|
311 | v.rxdes_pos := std_logic_vector(unsigned(r.rxdes_pos) + 4); | |
|
312 | v.rxaddr := std_logic_vector(unsigned(r.rxaddr) + 1); | |
|
313 | -- Detect EOP/EEP. | |
|
314 | v.rxdes_eop := | |
|
315 | (msti.rxfifo_rdata(35) and not msti.rxfifo_rdata(24)) or | |
|
316 | (msti.rxfifo_rdata(34) and not msti.rxfifo_rdata(16)) or | |
|
317 | (msti.rxfifo_rdata(33) and not msti.rxfifo_rdata(8)) or | |
|
318 | (msti.rxfifo_rdata(32) and not msti.rxfifo_rdata(0)); | |
|
319 | v.rxdes_eep := | |
|
320 | (msti.rxfifo_rdata(35) and msti.rxfifo_rdata(24)) or | |
|
321 | (msti.rxfifo_rdata(34) and msti.rxfifo_rdata(16)) or | |
|
322 | (msti.rxfifo_rdata(33) and msti.rxfifo_rdata(8)) or | |
|
323 | (msti.rxfifo_rdata(32) and msti.rxfifo_rdata(0)); | |
|
324 | -- Adjust frame length in case of EOP/EEP. | |
|
325 | if msti.rxfifo_rdata(35) = '1' then | |
|
326 | v.rxdes_pos := r.rxdes_pos(r.rxdes_pos'high downto 2) & "00"; | |
|
327 | elsif msti.rxfifo_rdata(34) = '1' then | |
|
328 | v.rxdes_pos := r.rxdes_pos(r.rxdes_pos'high downto 2) & "01"; | |
|
329 | elsif msti.rxfifo_rdata(33) = '1' then | |
|
330 | v.rxdes_pos := r.rxdes_pos(r.rxdes_pos'high downto 2) & "10"; | |
|
331 | elsif msti.rxfifo_rdata(32) = '1' then | |
|
332 | v.rxdes_pos := r.rxdes_pos(r.rxdes_pos'high downto 2) & "11"; | |
|
333 | end if; | |
|
334 | -- Stop at end of requested length or end of packet or fifo empty. | |
|
335 | if msti.rxfifo_nxempty = '1' or | |
|
336 | orv(msti.rxfifo_rdata(35 downto 32)) = '1' or | |
|
337 | unsigned(r.rxdes_len) = 1 then | |
|
338 | v_burstreq := '0'; | |
|
339 | v.mstate := st_rxfinal; | |
|
340 | end if; | |
|
341 | -- Stop at max burst length boundary. | |
|
342 | if (andv(r.rxaddr(maxburst+1 downto 2)) = '1') then | |
|
343 | v_burstreq := '0'; | |
|
344 | v.mstate := st_rxfinal; | |
|
345 | end if; | |
|
346 | end if; | |
|
347 | ||
|
348 | when st_rxfinal => | |
|
349 | -- Last data cycle of an RX transfer. | |
|
350 | if v_burstack = '1' then | |
|
351 | if unsigned(r.rxdes_len) = 0 or | |
|
352 | r.rxdes_eop = '1' or r.rxdes_eep = '1' then | |
|
353 | -- End of frame; write back descriptor. | |
|
354 | v_burstreq := '1'; | |
|
355 | v.hwrite := '1'; | |
|
356 | v.haddr := msti.rxdesc_ptr & "0"; | |
|
357 | v.rxdesc_next := '1'; | |
|
358 | v.mstate := st_rxputdesc; | |
|
359 | else | |
|
360 | -- Go through st_idle to pick up more work. | |
|
361 | v.mstate := st_idle; | |
|
362 | end if; | |
|
363 | end if; | |
|
364 | -- Give preference to TX work since we just did some RX work. | |
|
365 | v.prefertx := '1'; | |
|
366 | ||
|
367 | when st_rxputdesc => | |
|
368 | -- Write back RX descriptor. | |
|
369 | v.hwdata(15 downto 0) := r.rxdes_pos; | |
|
370 | v.hwdata(16) := '0'; | |
|
371 | v.hwdata(17) := r.rxdes_wr; | |
|
372 | v.hwdata(18) := r.rxdes_ie; | |
|
373 | v.hwdata(19) := '1'; | |
|
374 | v.hwdata(20) := r.rxdes_eop; | |
|
375 | v.hwdata(21) := r.rxdes_eep; | |
|
376 | v.hwdata(31 downto 22) := (others => '0'); | |
|
377 | if v_burstack = '1' then | |
|
378 | -- Frame done. | |
|
379 | v.rxdes_en := '0'; | |
|
380 | v.int_rxdesc := r.rxdes_ie; | |
|
381 | v.int_rxpacket := r.rxdes_eop or r.rxdes_eep; | |
|
382 | -- Go to st_idle. | |
|
383 | v.mstate := st_idle; | |
|
384 | end if; | |
|
385 | ||
|
386 | when st_txgetdesc => | |
|
387 | -- Read TX descriptor flags from memory. | |
|
388 | v_burstreq := '1'; | |
|
389 | v.hwrite := '0'; | |
|
390 | v.txdes_len := v_hrdata(15 downto 0); | |
|
391 | v.txdes_en := v_hrdata(16); | |
|
392 | v.txdes_wr := v_hrdata(17); | |
|
393 | v.txdes_ie := v_hrdata(18); | |
|
394 | v.txdes_eop := v_hrdata(20); | |
|
395 | v.txdes_eep := v_hrdata(21); | |
|
396 | if v_burstack = '1' then | |
|
397 | -- Got descriptor flags. | |
|
398 | v_burstreq := '0'; | |
|
399 | v.mstate := st_txgetptr; | |
|
400 | end if; | |
|
401 | ||
|
402 | when st_txgetptr => | |
|
403 | -- Read TX data pointer from memory. | |
|
404 | v.txaddr := v_hrdata(31 downto 2); | |
|
405 | if v_burstack = '1' then | |
|
406 | -- Got data pointer. | |
|
407 | if r.txdes_en = '1' then | |
|
408 | -- Start transfer. | |
|
409 | if unsigned(r.txdes_len) = 0 then | |
|
410 | -- Only send EOP/EEP and write back descriptor. | |
|
411 | v_burstreq := '1'; | |
|
412 | v.hwrite := '1'; | |
|
413 | v.haddr := msti.txdesc_ptr & "0"; | |
|
414 | v.txdesc_next := '1'; | |
|
415 | v.mstate := st_txputdesc; | |
|
416 | else | |
|
417 | v_burstreq := '1'; | |
|
418 | v.hwrite := '0'; | |
|
419 | v.haddr := v_hrdata(31 downto 2); | |
|
420 | if unsigned(r.txdes_len) <= 4 then | |
|
421 | -- Transfer only one word. | |
|
422 | v.mstate := st_txfinal; | |
|
423 | else | |
|
424 | v.mstate := st_txtransfer; | |
|
425 | end if; | |
|
426 | end if; | |
|
427 | else | |
|
428 | -- Reached end of valid descriptors; stop. | |
|
429 | v.txdma_act := '0'; | |
|
430 | v.mstate := st_idle; | |
|
431 | end if; | |
|
432 | end if; | |
|
433 | ||
|
434 | when st_txtransfer => | |
|
435 | -- Continue an TX transfer. | |
|
436 | v_burstreq := '1'; | |
|
437 | v.hwrite := '0'; | |
|
438 | if v_burstack = '1' then | |
|
439 | -- Got next data word from memory. | |
|
440 | v_txfifo_write := '1'; | |
|
441 | -- Update pointers. | |
|
442 | v.txdes_len := std_logic_vector(unsigned(r.txdes_len) - 4); | |
|
443 | v.txaddr := std_logic_vector(unsigned(r.txaddr) + 1); | |
|
444 | -- Handle end of burst/transfer. | |
|
445 | if andv(r.txaddr(maxburst+1 downto 2)) = '1' then | |
|
446 | -- This was the last data cycle before the max burst boundary. | |
|
447 | -- Go through st_idle to pick up more work. | |
|
448 | v_burstreq := '0'; | |
|
449 | v.mstate := st_idle; | |
|
450 | elsif msti.txfifo_nxfull = '1' then | |
|
451 | -- Fifo full; stop transfer, ignore final data cycle. | |
|
452 | v_burstreq := '0'; | |
|
453 | v.mstate := st_txskip; | |
|
454 | elsif unsigned(r.txdes_len) <= 8 then | |
|
455 | -- Stop at end of requested length (one more data cycle). | |
|
456 | v_burstreq := '0'; | |
|
457 | v.mstate := st_txfinal; | |
|
458 | elsif andv(r.txaddr(maxburst+1 downto 3)) = '1' then | |
|
459 | -- Stop at max burst length boundary (one more data cycle). | |
|
460 | v_burstreq := '0'; | |
|
461 | end if; | |
|
462 | else | |
|
463 | if andv(r.txaddr(maxburst+1 downto 2)) = '1' then | |
|
464 | -- Stop at max burst length boundary (just one more data cycle). | |
|
465 | v_burstreq := '0'; | |
|
466 | end if; | |
|
467 | end if; | |
|
468 | ||
|
469 | when st_txfinal => | |
|
470 | -- Last data cycle of a TX descriptor (1 <= txdes_len <= 4). | |
|
471 | if v_burstack = '1' then | |
|
472 | -- Got last data word from memory. | |
|
473 | v_txfifo_write := '1'; | |
|
474 | v.txdes_len := std_logic_vector(unsigned(r.txdes_len) - 4); | |
|
475 | -- Insert EOP in last word if needed. | |
|
476 | -- (Or set bit 7 in the flag byte to indicate that the | |
|
477 | -- frame ends while the packet continues.) | |
|
478 | case r.txdes_len(1 downto 0) is | |
|
479 | when "01" => | |
|
480 | v_txfifo_wdata(34) := '1'; | |
|
481 | v_txfifo_wdata(23) := not (r.txdes_eop or r.txdes_eep); | |
|
482 | v_txfifo_wdata(22 downto 17) := "000000"; | |
|
483 | v_txfifo_wdata(16) := r.txdes_eep; | |
|
484 | when "10" => | |
|
485 | v_txfifo_wdata(33) := '1'; | |
|
486 | v_txfifo_wdata(15) := not (r.txdes_eop or r.txdes_eep); | |
|
487 | v_txfifo_wdata(14 downto 9) := "000000"; | |
|
488 | v_txfifo_wdata(8) := r.txdes_eep; | |
|
489 | when "11" => | |
|
490 | v_txfifo_wdata(32) := '1'; | |
|
491 | v_txfifo_wdata(7) := not (r.txdes_eop or r.txdes_eep); | |
|
492 | v_txfifo_wdata(6 downto 1) := "000000"; | |
|
493 | v_txfifo_wdata(0) := r.txdes_eep; | |
|
494 | when others => | |
|
495 | -- txdes_len = 4 | |
|
496 | -- Store 4 data bytes now; store EOP in st_txputdesc (if needed). | |
|
497 | end case; | |
|
498 | if msti.txfifo_nxfull = '1' and r.txdes_len(1 downto 0) = "00" then | |
|
499 | -- Fifo full so no room to store EOP. | |
|
500 | v.mstate := st_idle; | |
|
501 | v.haddr := msti.txdesc_ptr & "0"; | |
|
502 | else | |
|
503 | -- Prepare to write back descriptor. | |
|
504 | v_burstreq := '1'; | |
|
505 | v.hwrite := '1'; | |
|
506 | v.haddr := msti.txdesc_ptr & "0"; | |
|
507 | v.txdesc_next := '1'; | |
|
508 | v.mstate := st_txputdesc; | |
|
509 | end if; | |
|
510 | end if; | |
|
511 | ||
|
512 | when st_txputdesc => | |
|
513 | -- Write back TX descriptor. | |
|
514 | v.hwdata(15 downto 0) := (others => '0'); | |
|
515 | v.hwdata(16) := '0'; | |
|
516 | v.hwdata(17) := r.txdes_wr; | |
|
517 | v.hwdata(18) := r.txdes_ie; | |
|
518 | v.hwdata(19) := '1'; | |
|
519 | v.hwdata(20) := r.txdes_eop; | |
|
520 | v.hwdata(21) := r.txdes_eep; | |
|
521 | v.hwdata(31 downto 22) := (others => '0'); | |
|
522 | if v_burstack = '1' then | |
|
523 | if r.txdes_len(1 downto 0) = "00" and | |
|
524 | (r.txdes_eop = '1' or r.txdes_eep = '1') then | |
|
525 | -- Store EOP in TX fifo. | |
|
526 | v_txfifo_write := '1'; | |
|
527 | v_txfifo_wdata(35) := '1'; | |
|
528 | v_txfifo_wdata(31 downto 25) := "0000000"; | |
|
529 | v_txfifo_wdata(24) := r.txdes_eep; | |
|
530 | end if; | |
|
531 | -- Frame done. | |
|
532 | v.txdes_en := '0'; | |
|
533 | v.int_txdesc := r.txdes_ie; | |
|
534 | -- Go to st_idle and give preference to RX work. | |
|
535 | v.mstate := st_idle; | |
|
536 | end if; | |
|
537 | ||
|
538 | when st_txskip => | |
|
539 | -- Ignore last data cycle of burst because TX fifo is full. | |
|
540 | if v_burstack = '1' then | |
|
541 | v.mstate := st_idle; | |
|
542 | end if; | |
|
543 | ||
|
544 | end case; | |
|
545 | ||
|
546 | -- Abort DMA when an AHB error occurs. | |
|
547 | if r.ahberror = '1' then | |
|
548 | v.rxdma_act := '0'; | |
|
549 | v.txdma_act := '0'; | |
|
550 | v.mstate := st_idle; | |
|
551 | end if; | |
|
552 | ||
|
553 | ||
|
554 | -- | |
|
555 | -- Burst state machine. | |
|
556 | -- | |
|
557 | -- A transfer starts when the main state machine combinatorially pulls | |
|
558 | -- v_burstreq high and assigns v.haddr and v.hwrite (i.e. r.haddr and | |
|
559 | -- r.hwrite must be valid in the first clock cycle AFTER rising v_burstreq). | |
|
560 | -- In case of a write transfer, r.hwdata must be valid in the second | |
|
561 | -- clock cycle after rising v_burstreq. | |
|
562 | -- | |
|
563 | -- During the transfer, the burst state machine announces each word | |
|
564 | -- with a v_burstack pulse. During a read transfer, ahbi.hrdata is | |
|
565 | -- valid when v_burstack is high. During a write transfer, a next | |
|
566 | -- word must be assigned to v.hwdata on the v_burstack pulse. | |
|
567 | -- | |
|
568 | -- For a single-word transfer, v_burstreq should be high for only one | |
|
569 | -- clock cycle. For a multi-word transfer, v_burstreq should be high | |
|
570 | -- until the last-but-one v_burstack pulse. I.e. after v_burstreq is | |
|
571 | -- released combinatorially on a v_burstack pulse, one last v_burstack | |
|
572 | -- pulse will follow. | |
|
573 | -- | |
|
574 | -- The burst state machine transparently handles bus arbitration and | |
|
575 | -- retrying of transfers. In case of a non-retryable error, r.ahberror | |
|
576 | -- is set high and further transfers are blocked. The main state | |
|
577 | -- machine is responsible for ensuring that bursts do not cross a | |
|
578 | -- forbidden address boundary. | |
|
579 | -- | |
|
580 | case r.burststat is | |
|
581 | ||
|
582 | when bs_idle => | |
|
583 | -- Wait for request and bus grant. | |
|
584 | -- (htrans = HTRANS_IDLE) | |
|
585 | v.hbusreq := r.hbusreq or v_burstreq; | |
|
586 | if (r.hbusreq = '1' or v_burstreq = '1') and | |
|
587 | ahbi.hready = '1' and | |
|
588 | ahbi.hgrant(hindex) = '1' then | |
|
589 | -- Start burst. | |
|
590 | v.burststat := bs_setup; | |
|
591 | end if; | |
|
592 | -- Block new bursts after an error occurred. | |
|
593 | if r.ahberror = '1' then | |
|
594 | v.hbusreq := '0'; | |
|
595 | v.burststat := bs_idle; | |
|
596 | end if; | |
|
597 | ||
|
598 | when bs_setup => | |
|
599 | -- First address cycle. | |
|
600 | -- (htrans = HTRANS_NONSEQ) | |
|
601 | v.hbusreq := '1'; | |
|
602 | if ahbi.hready = '1' then | |
|
603 | -- Increment address and continue burst in bs_active. | |
|
604 | v.haddr(maxburst+1 downto 2) := std_logic_vector(unsigned(r.haddr(maxburst+1 downto 2)) + 1); | |
|
605 | v.burststat := bs_active; | |
|
606 | -- Stop burst when application ends the transfer. | |
|
607 | v.hbusreq := v_burstreq; | |
|
608 | if v_burstreq = '0' then | |
|
609 | v.burststat := bs_end; | |
|
610 | end if; | |
|
611 | -- Stop burst when we are kicked off the bus. | |
|
612 | if ahbi.hgrant(hindex) = '0' then | |
|
613 | v.burststat := bs_end; | |
|
614 | end if; | |
|
615 | end if; | |
|
616 | ||
|
617 | when bs_active => | |
|
618 | -- Continue burst. | |
|
619 | -- (htrans = HTRANS_SEQ) | |
|
620 | v.hbusreq := '1'; | |
|
621 | if ahbi.hresp /= HRESP_OKAY then | |
|
622 | -- Error response from slave. | |
|
623 | v.haddr(maxburst+1 downto 2) := std_logic_vector(unsigned(r.haddr(maxburst+1 downto 2)) - 1); | |
|
624 | if ahbi.hresp = HRESP_ERROR then | |
|
625 | -- Permanent error. | |
|
626 | v.ahberror := '1'; | |
|
627 | v.hbusreq := '0'; | |
|
628 | else | |
|
629 | -- Must retry request. | |
|
630 | v.hbusreq := '1'; | |
|
631 | end if; | |
|
632 | v.burststat := bs_idle; | |
|
633 | elsif ahbi.hready = '1' then | |
|
634 | -- Increment address. | |
|
635 | v.haddr(maxburst+1 downto 2) := std_logic_vector(unsigned(r.haddr(maxburst+1 downto 2)) + 1); | |
|
636 | -- Stop burst when application ends the transfer. | |
|
637 | v.hbusreq := v_burstreq; | |
|
638 | if v_burstreq = '0' then | |
|
639 | v.burststat := bs_end; | |
|
640 | end if; | |
|
641 | -- Stop burst when we are kicked off the bus. | |
|
642 | if ahbi.hgrant(hindex) = '0' then | |
|
643 | v.burststat := bs_end; | |
|
644 | end if; | |
|
645 | end if; | |
|
646 | ||
|
647 | when bs_end => | |
|
648 | -- Last data cycle of burst. | |
|
649 | -- (htrans = HTRANS_IDLE) | |
|
650 | v.hbusreq := r.hbusreq or v_burstreq; | |
|
651 | if ahbi.hresp /= HRESP_OKAY then | |
|
652 | -- Error response from slave. | |
|
653 | v.haddr(maxburst+1 downto 2) := std_logic_vector(unsigned(r.haddr(maxburst+1 downto 2)) - 1); | |
|
654 | if ahbi.hresp = HRESP_ERROR then | |
|
655 | -- Permanent error. | |
|
656 | v.ahberror := '1'; | |
|
657 | v.hbusreq := '0'; | |
|
658 | else | |
|
659 | -- Must retry request. | |
|
660 | v.hbusreq := '1'; | |
|
661 | end if; | |
|
662 | v.burststat := bs_idle; | |
|
663 | elsif ahbi.hready = '1' then | |
|
664 | -- Burst complete. | |
|
665 | if (r.hbusreq = '1' or v_burstreq = '1') and | |
|
666 | ahbi.hgrant(hindex) = '1' then | |
|
667 | -- Immediately start next burst. | |
|
668 | v.burststat := bs_setup; | |
|
669 | else | |
|
670 | v.burststat := bs_idle; | |
|
671 | end if; | |
|
672 | end if; | |
|
673 | ||
|
674 | end case; | |
|
675 | ||
|
676 | ||
|
677 | -- | |
|
678 | -- Drive output signals. | |
|
679 | -- | |
|
680 | ahbo.hbusreq <= r.hbusreq; | |
|
681 | if r.burststat = bs_setup then | |
|
682 | ahbo.htrans <= HTRANS_NONSEQ; | |
|
683 | elsif r.burststat = bs_active then | |
|
684 | ahbo.htrans <= HTRANS_SEQ; | |
|
685 | else | |
|
686 | ahbo.htrans <= HTRANS_IDLE; | |
|
687 | end if; | |
|
688 | ahbo.haddr <= r.haddr & "00"; | |
|
689 | ahbo.hwrite <= r.hwrite; | |
|
690 | ahbo.hwdata <= ahbdrivedata(r.hwdata); | |
|
691 | ahbo.hlock <= '0'; -- never lock the bus | |
|
692 | ahbo.hsize <= HSIZE_WORD; -- always 32-bit words | |
|
693 | ahbo.hburst <= HBURST_INCR; -- undetermined incremental burst | |
|
694 | ahbo.hprot <= "0011"; -- not cacheable, privileged, data | |
|
695 | ahbo.hirq <= (others => '0'); -- no interrupts via AHB bus | |
|
696 | ahbo.hconfig <= hconfig; -- AHB plug&play data | |
|
697 | ahbo.hindex <= hindex; -- index feedback | |
|
698 | ||
|
699 | msto.rxdma_act <= r.rxdma_act; | |
|
700 | msto.txdma_act <= r.txdma_act; | |
|
701 | msto.ahberror <= r.ahberror; | |
|
702 | msto.int_rxdesc <= r.int_rxdesc; | |
|
703 | msto.int_txdesc <= r.int_txdesc; | |
|
704 | msto.int_rxpacket <= r.int_rxpacket; | |
|
705 | msto.rxdesc_next <= r.rxdesc_next; | |
|
706 | msto.rxdesc_wrap <= r.rxdesc_next and r.rxdes_wr; | |
|
707 | msto.txdesc_next <= r.txdesc_next; | |
|
708 | msto.txdesc_wrap <= r.txdesc_next and r.txdes_wr; | |
|
709 | msto.rxfifo_read <= v_rxfifo_read; | |
|
710 | msto.txfifo_write <= v_txfifo_write; | |
|
711 | msto.txfifo_wdata <= v_txfifo_wdata; | |
|
712 | ||
|
713 | ||
|
714 | -- | |
|
715 | -- Reset. | |
|
716 | -- | |
|
717 | if rstn = '0' then | |
|
718 | v := regs_reset; | |
|
719 | end if; | |
|
720 | ||
|
721 | ||
|
722 | -- | |
|
723 | -- Update registers. | |
|
724 | -- | |
|
725 | rin <= v; | |
|
726 | end process; | |
|
727 | ||
|
728 | ||
|
729 | -- | |
|
730 | -- Synchronous process: update registers. | |
|
731 | -- | |
|
732 | process (clk) is | |
|
733 | begin | |
|
734 | if rising_edge(clk) then | |
|
735 | r <= rin; | |
|
736 | end if; | |
|
737 | end process; | |
|
738 | ||
|
739 | end architecture spwahbmst_arch; |
This diff has been collapsed as it changes many lines, (886 lines changed) Show them Hide them | |||
@@ -0,0 +1,886 | |||
|
1 | -- | |
|
2 | -- SpaceWire core with AMBA interface. | |
|
3 | -- | |
|
4 | -- APB registers: | |
|
5 | -- | |
|
6 | -- Address 0x00: Control Register | |
|
7 | -- bit 0 Reset spwamba core (auto-clear) | |
|
8 | -- bit 1 Reset DMA engines (auto-clear) | |
|
9 | -- bit 2 Link start | |
|
10 | -- bit 3 Link autostart | |
|
11 | -- bit 4 Link disable | |
|
12 | -- bit 5 Enable timecode transmission through tick_in signal | |
|
13 | -- bit 6 Start RX DMA (auto-clear) | |
|
14 | -- bit 7 Start TX DMA (auto-clear) | |
|
15 | -- bit 8 Cancel TX DMA and discard TX data queue (auto-clear) | |
|
16 | -- bit 9 Enable interrupt on link up/down | |
|
17 | -- bit 10 Enable interrupt on time code received | |
|
18 | -- bit 11 Enable interrupt on RX descriptor | |
|
19 | -- bit 12 Enable interrupt on TX descriptor | |
|
20 | -- bit 13 Enable interrupt on RX packet | |
|
21 | -- bit 27:24 desctablesize (read-only) | |
|
22 | -- | |
|
23 | -- Address 0x04: Status Register | |
|
24 | -- bit 1:0 Link status: 0=off, 1=started, 2=connecting, 3=run | |
|
25 | -- bit 2 Got disconnect error (sticky) | |
|
26 | -- bit 3 Got parity error (sticky) | |
|
27 | -- bit 4 Got escape error (sticky) | |
|
28 | -- bit 5 Got credit error (sticky) | |
|
29 | -- bit 6 RX DMA enabled | |
|
30 | -- bit 7 TX DMA enabled | |
|
31 | -- bit 8 AHB error occurred (reset DMA engine to clear) | |
|
32 | -- bit 9 Reserved | |
|
33 | -- bit 10 Received timecode (sticky) | |
|
34 | -- bit 11 Finished RX descriptor with IE='1' (sticky) | |
|
35 | -- bit 12 Finished TX descriptor with IE='1' (sticky) | |
|
36 | -- bit 13 Received packet (sticky) | |
|
37 | -- bit 14 RX buffer empty after packet | |
|
38 | -- | |
|
39 | -- Sticky bits are reset by writing a '1' bit to the corresponding | |
|
40 | -- bit position(s). | |
|
41 | -- | |
|
42 | -- Address 0x08: Transmission Clock Scaler | |
|
43 | -- bit 7:0 txclk division factor minus 1 | |
|
44 | -- | |
|
45 | -- Address 0x0c: Timecode Register | |
|
46 | -- bit 5:0 Last received timecode value (read-only) | |
|
47 | -- bit 7:6 Control bits received with last timecode (read-only) | |
|
48 | -- bit 13:8 Timecode value to send on next tick_in (auto-increment) | |
|
49 | -- bit 15:14 Reserved (write as zero) | |
|
50 | -- bit 16 Write '1' to send a timecode (auto-clear) | |
|
51 | -- | |
|
52 | -- Address 0x10: Descriptor pointer for RX DMA | |
|
53 | -- bit 2:0 Reserved, write as zero | |
|
54 | -- bit desctablesize+2:3 Descriptor index (auto-increment) | |
|
55 | -- bit 31:desctablesize+3 Fixed address bits of descriptor table | |
|
56 | -- | |
|
57 | -- For example, if desctablesize = 10, a 8192-byte area is | |
|
58 | -- determined by bits 31:13. This area has room for 1024 descriptors | |
|
59 | -- of 8 bytes each. Bits 12:3 point to the current descriptor within | |
|
60 | -- the table. | |
|
61 | -- | |
|
62 | -- Address 0x14: Descriptor pointer for TX DMA | |
|
63 | -- bit 2:0 Reserved, write as zero | |
|
64 | -- bit desctablesize+2:3 Descriptor index (auto-increment) | |
|
65 | -- bit 31:desctablesize+3 Fixed address bits of descriptor table | |
|
66 | -- | |
|
67 | ||
|
68 | library ieee; | |
|
69 | use ieee.std_logic_1164.all; | |
|
70 | use ieee.numeric_std.all; | |
|
71 | library techmap; | |
|
72 | use techmap.gencomp.all; | |
|
73 | library grlib; | |
|
74 | use grlib.amba.all; | |
|
75 | use grlib.devices.all; | |
|
76 | use grlib.stdlib.all; | |
|
77 | use work.spwpkg.all; | |
|
78 | use work.spwambapkg.all; | |
|
79 | ||
|
80 | entity spwamba is | |
|
81 | ||
|
82 | generic ( | |
|
83 | -- Technology selection for FIFO memories. | |
|
84 | tech: integer range 0 to NTECH := DEFFABTECH; | |
|
85 | ||
|
86 | -- AHB master index. | |
|
87 | hindex: integer; | |
|
88 | ||
|
89 | -- APB slave index. | |
|
90 | pindex: integer; | |
|
91 | ||
|
92 | -- Bits 19 to 8 of the APB address range. | |
|
93 | paddr: integer; | |
|
94 | ||
|
95 | -- Mask for APB address bits 19 to 8. | |
|
96 | pmask: integer := 16#fff#; | |
|
97 | ||
|
98 | -- Index of the interrupt request line. | |
|
99 | pirq: integer; | |
|
100 | ||
|
101 | -- System clock frequency in Hz. | |
|
102 | -- This must be set to the frequency of "clk". It is used to setup | |
|
103 | -- counters for reset timing, disconnect timeout and to transmit | |
|
104 | -- at 10 Mbit/s during the link handshake. | |
|
105 | sysfreq: real; | |
|
106 | ||
|
107 | -- Transmit clock frequency in Hz (only if tximpl = impl_fast). | |
|
108 | -- This must be set to the frequency of "txclk". It is used to | |
|
109 | -- transmit at 10 Mbit/s during the link handshake. | |
|
110 | txclkfreq: real := 0.0; | |
|
111 | ||
|
112 | -- Selection of a receiver front-end implementation. | |
|
113 | rximpl: spw_implementation_type := impl_generic; | |
|
114 | ||
|
115 | -- Maximum number of bits received per system clock | |
|
116 | -- (must be 1 in case of impl_generic). | |
|
117 | rxchunk: integer range 1 to 4 := 1; | |
|
118 | ||
|
119 | -- Selection of a transmitter implementation. | |
|
120 | tximpl: spw_implementation_type := impl_generic; | |
|
121 | ||
|
122 | -- Enable capability to generate time-codes. | |
|
123 | timecodegen: boolean := true; | |
|
124 | ||
|
125 | -- Size of the receive FIFO as the 2-logarithm of the number of words. | |
|
126 | -- Must be at least 6 (64 words = 256 bytes). | |
|
127 | rxfifosize: integer range 6 to 12 := 8; | |
|
128 | ||
|
129 | -- Size of the transmit FIFO as the 2-logarithm of the number of words. | |
|
130 | txfifosize: integer range 2 to 12 := 8; | |
|
131 | ||
|
132 | -- Size of the DMA descriptor tables as the 2-logarithm of the number | |
|
133 | -- of descriptors. | |
|
134 | desctablesize: integer range 4 to 14 := 10; | |
|
135 | ||
|
136 | -- Maximum burst length as the 2-logarithm of the number of words (default 8 words). | |
|
137 | maxburst: integer range 1 to 8 := 3 | |
|
138 | ); | |
|
139 | ||
|
140 | port ( | |
|
141 | -- System clock. | |
|
142 | clk: in std_logic; | |
|
143 | ||
|
144 | -- Receiver sample clock (only for impl_fast) | |
|
145 | rxclk: in std_logic; | |
|
146 | ||
|
147 | -- Transmit clock (only for impl_fast) | |
|
148 | txclk: in std_logic; | |
|
149 | ||
|
150 | -- Synchronous reset (active-low). | |
|
151 | rstn: in std_logic; | |
|
152 | ||
|
153 | -- APB slave input signals. | |
|
154 | apbi: in apb_slv_in_type; | |
|
155 | ||
|
156 | -- APB slave output signals. | |
|
157 | apbo: out apb_slv_out_type; | |
|
158 | ||
|
159 | -- AHB master input signals. | |
|
160 | ahbi: in ahb_mst_in_type; | |
|
161 | ||
|
162 | -- AHB master output signals. | |
|
163 | ahbo: out ahb_mst_out_type; | |
|
164 | ||
|
165 | -- Pulse for TimeCode generation. | |
|
166 | tick_in: in std_logic; | |
|
167 | ||
|
168 | -- High for one clock cycle if a TimeCode was just received. | |
|
169 | tick_out: out std_logic; | |
|
170 | ||
|
171 | -- Data In signal from SpaceWire bus. | |
|
172 | spw_di: in std_logic; | |
|
173 | ||
|
174 | -- Strobe In signal from SpaceWire bus. | |
|
175 | spw_si: in std_logic; | |
|
176 | ||
|
177 | -- Data Out signal to SpaceWire bus. | |
|
178 | spw_do: out std_logic; | |
|
179 | ||
|
180 | -- Strobe Out signal to SpaceWire bus. | |
|
181 | spw_so: out std_logic | |
|
182 | ); | |
|
183 | ||
|
184 | end entity spwamba; | |
|
185 | ||
|
186 | architecture spwamba_arch of spwamba is | |
|
187 | ||
|
188 | -- Reset time (6.4 us) in system clocks | |
|
189 | constant reset_time: integer := integer(sysfreq * 6.4e-6); | |
|
190 | ||
|
191 | -- Disconnect time (850 ns) in system clocks | |
|
192 | constant disconnect_time: integer := integer(sysfreq * 850.0e-9); | |
|
193 | ||
|
194 | -- Initial tx clock scaler (10 Mbit). | |
|
195 | type impl_to_real_type is array(spw_implementation_type) of real; | |
|
196 | constant tximpl_to_txclk_freq: impl_to_real_type := | |
|
197 | (impl_generic => sysfreq, impl_fast => txclkfreq); | |
|
198 | constant effective_txclk_freq: real := tximpl_to_txclk_freq(tximpl); | |
|
199 | constant default_divcnt: std_logic_vector(7 downto 0) := | |
|
200 | std_logic_vector(to_unsigned(integer(effective_txclk_freq / 10.0e6 - 1.0), 8)); | |
|
201 | ||
|
202 | -- Registers. | |
|
203 | type regs_type is record | |
|
204 | -- packet state | |
|
205 | rxpacket: std_logic; -- '1' when receiving a packet | |
|
206 | rxeep: std_logic; -- '1' when rx EEP character pending | |
|
207 | txpacket: std_logic; -- '1' when transmitting a packet | |
|
208 | txdiscard: std_logic; -- '1' when discarding a tx packet | |
|
209 | -- RX fifo state | |
|
210 | rxfifo_raddr: std_logic_vector(rxfifosize-1 downto 0); | |
|
211 | rxfifo_waddr: std_logic_vector(rxfifosize-1 downto 0); | |
|
212 | rxfifo_wdata: std_logic_vector(35 downto 0); | |
|
213 | rxfifo_write: std_ulogic; | |
|
214 | rxfifo_empty: std_ulogic; | |
|
215 | rxfifo_bytemsk: std_logic_vector(2 downto 0); | |
|
216 | rxroom: std_logic_vector(5 downto 0); | |
|
217 | -- TX fifo state | |
|
218 | txfifo_raddr: std_logic_vector(txfifosize-1 downto 0); | |
|
219 | txfifo_waddr: std_logic_vector(txfifosize-1 downto 0); | |
|
220 | txfifo_empty: std_ulogic; | |
|
221 | txfifo_nxfull: std_ulogic; | |
|
222 | txfifo_highw: std_ulogic; | |
|
223 | txfifo_bytepos: std_logic_vector(1 downto 0); | |
|
224 | -- APB registers | |
|
225 | ctl_reset: std_ulogic; | |
|
226 | ctl_resetdma: std_ulogic; | |
|
227 | ctl_linkstart: std_ulogic; | |
|
228 | ctl_autostart: std_ulogic; | |
|
229 | ctl_linkdis: std_ulogic; | |
|
230 | ctl_ticken: std_ulogic; | |
|
231 | ctl_rxstart: std_ulogic; | |
|
232 | ctl_txstart: std_ulogic; | |
|
233 | ctl_txcancel: std_ulogic; | |
|
234 | ctl_ielink: std_ulogic; | |
|
235 | ctl_ietick: std_ulogic; | |
|
236 | ctl_ierxdesc: std_ulogic; | |
|
237 | ctl_ietxdesc: std_ulogic; | |
|
238 | ctl_ierxpacket: std_ulogic; | |
|
239 | sta_link: std_logic_vector(1 downto 0); | |
|
240 | sta_errdisc: std_ulogic; | |
|
241 | sta_errpar: std_ulogic; | |
|
242 | sta_erresc: std_ulogic; | |
|
243 | sta_errcred: std_ulogic; | |
|
244 | sta_gottick: std_ulogic; | |
|
245 | sta_rxdesc: std_ulogic; | |
|
246 | sta_txdesc: std_ulogic; | |
|
247 | sta_rxpacket: std_ulogic; | |
|
248 | sta_rxempty: std_ulogic; | |
|
249 | txdivcnt: std_logic_vector(7 downto 0); | |
|
250 | time_in: std_logic_vector(5 downto 0); | |
|
251 | tick_in: std_ulogic; | |
|
252 | rxdesc_ptr: std_logic_vector(31 downto 3); | |
|
253 | txdesc_ptr: std_logic_vector(31 downto 3); | |
|
254 | -- APB interrupt request | |
|
255 | irq: std_ulogic; | |
|
256 | end record; | |
|
257 | ||
|
258 | constant regs_reset: regs_type := ( | |
|
259 | rxpacket => '0', | |
|
260 | rxeep => '0', | |
|
261 | txpacket => '0', | |
|
262 | txdiscard => '0', | |
|
263 | rxfifo_raddr => (others => '0'), | |
|
264 | rxfifo_waddr => (others => '0'), | |
|
265 | rxfifo_wdata => (others => '0'), | |
|
266 | rxfifo_write => '0', | |
|
267 | rxfifo_empty => '1', | |
|
268 | rxfifo_bytemsk => "111", | |
|
269 | rxroom => (others => '1'), | |
|
270 | txfifo_raddr => (others => '0'), | |
|
271 | txfifo_waddr => (others => '0'), | |
|
272 | txfifo_empty => '1', | |
|
273 | txfifo_nxfull => '0', | |
|
274 | txfifo_highw => '0', | |
|
275 | txfifo_bytepos => "00", | |
|
276 | ctl_reset => '0', | |
|
277 | ctl_resetdma => '0', | |
|
278 | ctl_linkstart => '0', | |
|
279 | ctl_autostart => '0', | |
|
280 | ctl_linkdis => '0', | |
|
281 | ctl_ticken => '0', | |
|
282 | ctl_rxstart => '0', | |
|
283 | ctl_txstart => '0', | |
|
284 | ctl_txcancel => '0', | |
|
285 | ctl_ielink => '0', | |
|
286 | ctl_ietick => '0', | |
|
287 | ctl_ierxdesc => '0', | |
|
288 | ctl_ietxdesc => '0', | |
|
289 | ctl_ierxpacket => '0', | |
|
290 | sta_link => "00", | |
|
291 | sta_errdisc => '0', | |
|
292 | sta_errpar => '0', | |
|
293 | sta_erresc => '0', | |
|
294 | sta_errcred => '0', | |
|
295 | sta_gottick => '0', | |
|
296 | sta_rxdesc => '0', | |
|
297 | sta_txdesc => '0', | |
|
298 | sta_rxpacket => '0', | |
|
299 | sta_rxempty => '1', | |
|
300 | txdivcnt => default_divcnt, | |
|
301 | time_in => (others => '0'), | |
|
302 | tick_in => '0', | |
|
303 | rxdesc_ptr => (others => '0'), | |
|
304 | txdesc_ptr => (others => '0'), | |
|
305 | irq => '0' ); | |
|
306 | ||
|
307 | signal r: regs_type := regs_reset; | |
|
308 | signal rin: regs_type; | |
|
309 | ||
|
310 | -- Component interface signals. | |
|
311 | signal recv_rxen: std_logic; | |
|
312 | signal recvo: spw_recv_out_type; | |
|
313 | signal recv_inact: std_logic; | |
|
314 | signal recv_inbvalid: std_logic; | |
|
315 | signal recv_inbits: std_logic_vector(rxchunk-1 downto 0); | |
|
316 | signal xmit_rst: std_logic; | |
|
317 | signal xmiti: spw_xmit_in_type; | |
|
318 | signal xmito: spw_xmit_out_type; | |
|
319 | signal xmit_divcnt: std_logic_vector(7 downto 0); | |
|
320 | signal link_rst: std_logic; | |
|
321 | signal linki: spw_link_in_type; | |
|
322 | signal linko: spw_link_out_type; | |
|
323 | signal msti: spw_ahbmst_in_type; | |
|
324 | signal msto: spw_ahbmst_out_type; | |
|
325 | signal ahbmst_rstn: std_logic; | |
|
326 | ||
|
327 | -- Memory interface signals. | |
|
328 | signal s_rxfifo_raddr: std_logic_vector(rxfifosize-1 downto 0); | |
|
329 | signal s_rxfifo_rdata: std_logic_vector(35 downto 0); | |
|
330 | signal s_rxfifo_wen: std_logic; | |
|
331 | signal s_rxfifo_waddr: std_logic_vector(rxfifosize-1 downto 0); | |
|
332 | signal s_rxfifo_wdata: std_logic_vector(35 downto 0); | |
|
333 | signal s_txfifo_raddr: std_logic_vector(txfifosize-1 downto 0); | |
|
334 | signal s_txfifo_rdata: std_logic_vector(35 downto 0); | |
|
335 | signal s_txfifo_wen: std_logic; | |
|
336 | signal s_txfifo_waddr: std_logic_vector(txfifosize-1 downto 0); | |
|
337 | signal s_txfifo_wdata: std_logic_vector(35 downto 0); | |
|
338 | ||
|
339 | ||
|
340 | -- APB slave plug&play configuration | |
|
341 | constant REVISION: integer := 0; | |
|
342 | constant pconfig: apb_config_type := ( | |
|
343 | 0 => ahb_device_reg(VENDOR_OPENCORES, DEVICE_SPACEWIRELIGHT, 0, REVISION, pirq), | |
|
344 | 1 => apb_iobar(paddr, pmask) ); | |
|
345 | ||
|
346 | -- AHB master plug&play configuration | |
|
347 | constant hconfig: ahb_config_type := ( | |
|
348 | 0 => ahb_device_reg(VENDOR_OPENCORES, DEVICE_SPACEWIRELIGHT, 0, REVISION, 0), | |
|
349 | others => zero32 ); | |
|
350 | ||
|
351 | begin | |
|
352 | ||
|
353 | -- Instantiate link controller. | |
|
354 | link_inst: spwlink | |
|
355 | generic map ( | |
|
356 | reset_time => reset_time ) | |
|
357 | port map ( | |
|
358 | clk => clk, | |
|
359 | rst => link_rst, | |
|
360 | linki => linki, | |
|
361 | linko => linko, | |
|
362 | rxen => recv_rxen, | |
|
363 | recvo => recvo, | |
|
364 | xmiti => xmiti, | |
|
365 | xmito => xmito ); | |
|
366 | ||
|
367 | -- Instantiate receiver. | |
|
368 | recv_inst: spwrecv | |
|
369 | generic map( | |
|
370 | disconnect_time => disconnect_time, | |
|
371 | rxchunk => rxchunk ) | |
|
372 | port map ( | |
|
373 | clk => clk, | |
|
374 | rxen => recv_rxen, | |
|
375 | recvo => recvo, | |
|
376 | inact => recv_inact, | |
|
377 | inbvalid => recv_inbvalid, | |
|
378 | inbits => recv_inbits ); | |
|
379 | ||
|
380 | -- Instantiate receiver front-end. | |
|
381 | recvfront_sel0: if rximpl = impl_generic generate | |
|
382 | recvfront_generic_inst: spwrecvfront_generic | |
|
383 | port map ( | |
|
384 | clk => clk, | |
|
385 | rxen => recv_rxen, | |
|
386 | inact => recv_inact, | |
|
387 | inbvalid => recv_inbvalid, | |
|
388 | inbits => recv_inbits, | |
|
389 | spw_di => spw_di, | |
|
390 | spw_si => spw_si ); | |
|
391 | end generate; | |
|
392 | recvfront_sel1: if rximpl = impl_fast generate | |
|
393 | recvfront_fast_inst: spwrecvfront_fast | |
|
394 | generic map ( | |
|
395 | rxchunk => rxchunk ) | |
|
396 | port map ( | |
|
397 | clk => clk, | |
|
398 | rxclk => rxclk, | |
|
399 | rxen => recv_rxen, | |
|
400 | inact => recv_inact, | |
|
401 | inbvalid => recv_inbvalid, | |
|
402 | inbits => recv_inbits, | |
|
403 | spw_di => spw_di, | |
|
404 | spw_si => spw_si ); | |
|
405 | end generate; | |
|
406 | ||
|
407 | -- Instantiate transmitter. | |
|
408 | xmit_sel0: if tximpl = impl_generic generate | |
|
409 | xmit_inst: spwxmit | |
|
410 | port map ( | |
|
411 | clk => clk, | |
|
412 | rst => xmit_rst, | |
|
413 | divcnt => xmit_divcnt, | |
|
414 | xmiti => xmiti, | |
|
415 | xmito => xmito, | |
|
416 | spw_do => spw_do, | |
|
417 | spw_so => spw_so ); | |
|
418 | end generate; | |
|
419 | xmit_sel1: if tximpl = impl_fast generate | |
|
420 | xmit_fast_inst: spwxmit_fast | |
|
421 | port map ( | |
|
422 | clk => clk, | |
|
423 | txclk => txclk, | |
|
424 | rst => xmit_rst, | |
|
425 | divcnt => xmit_divcnt, | |
|
426 | xmiti => xmiti, | |
|
427 | xmito => xmito, | |
|
428 | spw_do => spw_do, | |
|
429 | spw_so => spw_so ); | |
|
430 | end generate; | |
|
431 | ||
|
432 | -- Instantiate RX FIFO. | |
|
433 | rxfifo: syncram_2p | |
|
434 | generic map ( | |
|
435 | tech => tech, | |
|
436 | abits => rxfifosize, | |
|
437 | dbits => 36, | |
|
438 | sepclk => 0 ) | |
|
439 | port map ( | |
|
440 | rclk => clk, | |
|
441 | renable => '1', | |
|
442 | raddress => s_rxfifo_raddr, | |
|
443 | dataout => s_rxfifo_rdata, | |
|
444 | wclk => clk, | |
|
445 | write => s_rxfifo_wen, | |
|
446 | waddress => s_rxfifo_waddr, | |
|
447 | datain => s_rxfifo_wdata ); | |
|
448 | ||
|
449 | -- Instantiate TX FIFO. | |
|
450 | txfifo: syncram_2p | |
|
451 | generic map ( | |
|
452 | tech => tech, | |
|
453 | abits => txfifosize, | |
|
454 | dbits => 36, | |
|
455 | sepclk => 0 ) | |
|
456 | port map ( | |
|
457 | rclk => clk, | |
|
458 | renable => '1', | |
|
459 | raddress => s_txfifo_raddr, | |
|
460 | dataout => s_txfifo_rdata, | |
|
461 | wclk => clk, | |
|
462 | write => s_txfifo_wen, | |
|
463 | waddress => s_txfifo_waddr, | |
|
464 | datain => s_txfifo_wdata ); | |
|
465 | ||
|
466 | -- Instantiate AHB master. | |
|
467 | ahbmst: spwahbmst | |
|
468 | generic map ( | |
|
469 | hindex => hindex, | |
|
470 | hconfig => hconfig, | |
|
471 | maxburst => maxburst ) | |
|
472 | port map ( | |
|
473 | clk => clk, | |
|
474 | rstn => ahbmst_rstn, | |
|
475 | msti => msti, | |
|
476 | msto => msto, | |
|
477 | ahbi => ahbi, | |
|
478 | ahbo => ahbo ); | |
|
479 | ||
|
480 | ||
|
481 | -- | |
|
482 | -- Combinatorial process | |
|
483 | -- | |
|
484 | process (r, linko, msto, s_rxfifo_rdata, s_txfifo_rdata, rstn, apbi, tick_in) is | |
|
485 | variable v: regs_type; | |
|
486 | variable v_tmprxroom: unsigned(rxfifosize-1 downto 0); | |
|
487 | variable v_prdata: std_logic_vector(31 downto 0); | |
|
488 | variable v_irq: std_logic_vector(NAHBIRQ-1 downto 0); | |
|
489 | variable v_txfifo_bytepos: integer range 0 to 3; | |
|
490 | begin | |
|
491 | v := r; | |
|
492 | v_tmprxroom := to_unsigned(0, rxfifosize); | |
|
493 | v_prdata := (others => '0'); | |
|
494 | v_irq := (others => '0'); | |
|
495 | v_irq(pirq) := r.irq; | |
|
496 | ||
|
497 | -- Convert RX/TX byte index to integer. | |
|
498 | v_txfifo_bytepos := to_integer(unsigned(r.txfifo_bytepos)); | |
|
499 | ||
|
500 | -- Reset auto-clearing registers. | |
|
501 | v.ctl_reset := '0'; | |
|
502 | v.ctl_resetdma := '0'; | |
|
503 | v.ctl_rxstart := '0'; | |
|
504 | v.ctl_txstart := '0'; | |
|
505 | ||
|
506 | -- Register external timecode trigger (if enabled). | |
|
507 | if timecodegen and r.ctl_ticken = '1' then | |
|
508 | v.tick_in := tick_in; | |
|
509 | else | |
|
510 | v.tick_in := '0'; | |
|
511 | end if; | |
|
512 | ||
|
513 | -- Auto-increment timecode counter. | |
|
514 | if r.tick_in = '1' then | |
|
515 | v.time_in := std_logic_vector(unsigned(r.time_in) + 1); | |
|
516 | end if; | |
|
517 | ||
|
518 | -- Keep track of whether we are sending and/or receiving a packet. | |
|
519 | if linko.rxchar = '1' then | |
|
520 | -- got character | |
|
521 | v.rxpacket := not linko.rxflag; | |
|
522 | end if; | |
|
523 | if linko.txack = '1' then | |
|
524 | -- send character | |
|
525 | v.txpacket := not s_txfifo_rdata(35-v_txfifo_bytepos); | |
|
526 | end if; | |
|
527 | ||
|
528 | -- Accumulate a word to write to the RX fifo. | |
|
529 | -- Note: If the EOP/EEP marker falls in the middle of a word, | |
|
530 | -- subsequent bytes must be a copy of the marker, otherwise | |
|
531 | -- the AHB master may not work correctly. | |
|
532 | v.rxfifo_write := '0'; | |
|
533 | for i in 3 downto 0 loop | |
|
534 | if (i = 0) or (r.rxfifo_bytemsk(i-1) = '1') then | |
|
535 | if r.rxeep = '1' then | |
|
536 | v.rxfifo_wdata(32+i) := '1'; | |
|
537 | v.rxfifo_wdata(7+8*i downto 8*i) := "00000001"; | |
|
538 | else | |
|
539 | v.rxfifo_wdata(32+i) := linko.rxflag; | |
|
540 | v.rxfifo_wdata(7+8*i downto 8*i) := linko.rxdata; | |
|
541 | end if; | |
|
542 | end if; | |
|
543 | end loop; | |
|
544 | if linko.rxchar = '1' or (r.rxeep = '1' and unsigned(r.rxroom) /= 0) then | |
|
545 | v.rxeep := '0'; | |
|
546 | if r.rxfifo_bytemsk(0) = '0' or linko.rxflag = '1' or r.rxeep = '1' then | |
|
547 | -- Flush the current word to the FIFO. | |
|
548 | v.rxfifo_write := '1'; | |
|
549 | v.rxfifo_bytemsk := "111"; | |
|
550 | else | |
|
551 | -- Store one byte. | |
|
552 | v.rxfifo_bytemsk := '0' & r.rxfifo_bytemsk(2 downto 1); | |
|
553 | end if; | |
|
554 | end if; | |
|
555 | ||
|
556 | -- Read from TX fifo. | |
|
557 | if (r.txfifo_empty = '0') and (linko.txack = '1' or r.txdiscard = '1') then | |
|
558 | -- Update byte pointer. | |
|
559 | if r.txfifo_bytepos = "11" or | |
|
560 | s_txfifo_rdata(35-v_txfifo_bytepos) = '1' or | |
|
561 | (v_txfifo_bytepos < 3 and | |
|
562 | s_txfifo_rdata(34-v_txfifo_bytepos) = '1' and | |
|
563 | s_txfifo_rdata(23-8*v_txfifo_bytepos) = '1') then | |
|
564 | -- This is the last byte in the current word; | |
|
565 | -- OR the current byte is an EOP/EEP marker; | |
|
566 | -- OR the next byte in the current word is a non-EOP end-of-frame marker. | |
|
567 | v.txfifo_bytepos := "00"; | |
|
568 | v.txfifo_raddr := std_logic_vector(unsigned(r.txfifo_raddr) + 1); | |
|
569 | else | |
|
570 | -- Move to next byte. | |
|
571 | v.txfifo_bytepos := std_logic_vector(unsigned(r.txfifo_bytepos) + 1); | |
|
572 | end if; | |
|
573 | -- Clear discard flag when past EOP. | |
|
574 | if s_txfifo_rdata(35-v_txfifo_bytepos) = '1' then | |
|
575 | v.txdiscard := '0'; | |
|
576 | end if; | |
|
577 | end if; | |
|
578 | ||
|
579 | -- Update RX fifo pointers. | |
|
580 | if msto.rxfifo_read = '1' then | |
|
581 | -- Read one word. | |
|
582 | v.rxfifo_raddr := std_logic_vector(unsigned(r.rxfifo_raddr) + 1); | |
|
583 | end if; | |
|
584 | if r.rxfifo_write = '1' then | |
|
585 | -- Write one word. | |
|
586 | v.rxfifo_waddr := std_logic_vector(unsigned(r.rxfifo_waddr) + 1); | |
|
587 | end if; | |
|
588 | ||
|
589 | -- Detect RX fifo empty (using new value of rxfifo_raddr). | |
|
590 | -- Note: The FIFO is empty if head and tail pointer are equal. | |
|
591 | v.rxfifo_empty := conv_std_logic(v.rxfifo_raddr = r.rxfifo_waddr); | |
|
592 | ||
|
593 | -- Indicate RX fifo room for SpaceWire flow control. | |
|
594 | -- The flow control window is normally expressed as a number of bytes, | |
|
595 | -- but we don't know how many bytes we can fit in each word because | |
|
596 | -- some words are only partially used. So we report FIFO room as if | |
|
597 | -- each FIFO word can hold only one byte, which is an overly | |
|
598 | -- pessimistic estimate. | |
|
599 | -- (Use the new value of rxfifo_waddr.) | |
|
600 | v_tmprxroom := unsigned(r.rxfifo_raddr) - unsigned(v.rxfifo_waddr) - 1; | |
|
601 | if v_tmprxroom > 63 then | |
|
602 | -- at least 64 bytes room. | |
|
603 | v.rxroom := "111111"; | |
|
604 | else | |
|
605 | -- less than 64 bytes room. | |
|
606 | -- If linko.rxchar = '1', decrease rxroom by one to account for | |
|
607 | -- the pipeline delay through r.rxfifo_write. | |
|
608 | v.rxroom := std_logic_vector(v_tmprxroom(5 downto 0) - | |
|
609 | to_unsigned(conv_integer(linko.rxchar), 6)); | |
|
610 | end if; | |
|
611 | ||
|
612 | -- Update TX fifo write pointer. | |
|
613 | if msto.txfifo_write = '1' then | |
|
614 | -- write one word. | |
|
615 | v.txfifo_waddr := std_logic_vector(unsigned(r.txfifo_waddr) + 1); | |
|
616 | end if; | |
|
617 | ||
|
618 | -- Detect TX fifo empty. | |
|
619 | -- Note: The FIFO may be either full or empty if head and tail pointer | |
|
620 | -- are equal, hence the additional test for txfifo_nxfull. | |
|
621 | v.txfifo_empty := conv_std_logic(v.txfifo_raddr = r.txfifo_waddr) and not r.txfifo_nxfull; | |
|
622 | ||
|
623 | -- Detect TX fifo full after one more write. | |
|
624 | if unsigned(r.txfifo_raddr) - unsigned(r.txfifo_waddr) = to_unsigned(2, txfifosize) then | |
|
625 | -- currently exactly 2 words left. | |
|
626 | v.txfifo_nxfull := msto.txfifo_write; | |
|
627 | end if; | |
|
628 | ||
|
629 | -- Detect TX fifo high water mark. | |
|
630 | if txfifosize > maxburst then | |
|
631 | -- Indicate high water when there is no room for a maximum burst. | |
|
632 | if unsigned(r.txfifo_raddr) - unsigned(r.txfifo_waddr) = to_unsigned(2**maxburst + 1, txfifosize) then | |
|
633 | -- currently room for exactly one maximum burst. | |
|
634 | v.txfifo_highw := msto.txfifo_write; | |
|
635 | end if; | |
|
636 | else | |
|
637 | -- Indicate high water when more than half full. | |
|
638 | if unsigned(r.txfifo_raddr) - unsigned(r.txfifo_waddr) = to_unsigned(2**(txfifosize-1), txfifosize) then | |
|
639 | -- currently exactly half full. | |
|
640 | v.txfifo_highw := msto.txfifo_write; | |
|
641 | end if; | |
|
642 | end if; | |
|
643 | ||
|
644 | -- Update descriptor pointers. | |
|
645 | if msto.rxdesc_next = '1' then | |
|
646 | if msto.rxdesc_wrap = '1' then | |
|
647 | v.rxdesc_ptr(desctablesize+2 downto 3) := (others => '0'); | |
|
648 | else | |
|
649 | v.rxdesc_ptr(desctablesize+2 downto 3) := | |
|
650 | std_logic_vector(unsigned(r.rxdesc_ptr(desctablesize+2 downto 3)) + 1); | |
|
651 | end if; | |
|
652 | end if; | |
|
653 | if msto.txdesc_next = '1' then | |
|
654 | if msto.txdesc_wrap = '1' then | |
|
655 | v.txdesc_ptr(desctablesize+2 downto 3) := (others => '0'); | |
|
656 | else | |
|
657 | v.txdesc_ptr(desctablesize+2 downto 3) := | |
|
658 | std_logic_vector(unsigned(r.txdesc_ptr(desctablesize+2 downto 3)) + 1); | |
|
659 | end if; | |
|
660 | end if; | |
|
661 | ||
|
662 | -- If the link is lost, set a flag to discard the current packet. | |
|
663 | if linko.running = '0' then | |
|
664 | v.rxeep := v.rxeep or v.rxpacket; -- use new value of rxpacket | |
|
665 | v.txdiscard := v.txdiscard or v.txpacket; -- use new value of txpacket | |
|
666 | v.rxpacket := '0'; | |
|
667 | v.txpacket := '0'; | |
|
668 | end if; | |
|
669 | ||
|
670 | -- Clear the discard flag when the link is explicitly disabled. | |
|
671 | if r.ctl_linkdis = '1' then | |
|
672 | v.txdiscard := '0'; | |
|
673 | end if; | |
|
674 | ||
|
675 | -- Extend TX cancel command until TX DMA has stopped. | |
|
676 | if msto.txdma_act = '0' then | |
|
677 | v.ctl_txcancel := '0'; | |
|
678 | end if; | |
|
679 | ||
|
680 | -- Update status registers. | |
|
681 | v.sta_link(0) := linko.running or linko.started; | |
|
682 | v.sta_link(1) := linko.running or linko.connecting; | |
|
683 | if linko.errdisc = '1' then v.sta_errdisc := '1'; end if; | |
|
684 | if linko.errpar = '1' then v.sta_errpar := '1'; end if; | |
|
685 | if linko.erresc = '1' then v.sta_erresc := '1'; end if; | |
|
686 | if linko.errcred = '1' then v.sta_errcred := '1'; end if; | |
|
687 | if linko.tick_out = '1' then v.sta_gottick := '1'; end if; | |
|
688 | if msto.int_rxdesc = '1' then v.sta_rxdesc := '1'; end if; | |
|
689 | if msto.int_txdesc = '1' then v.sta_txdesc := '1'; end if; | |
|
690 | if msto.int_rxpacket = '1' then v.sta_rxpacket := '1'; end if; | |
|
691 | if msto.int_rxpacket = '1' and r.rxfifo_empty = '1' then | |
|
692 | v.sta_rxempty := '1'; | |
|
693 | elsif r.rxfifo_empty = '0' then | |
|
694 | v.sta_rxempty := '0'; | |
|
695 | end if; | |
|
696 | ||
|
697 | -- Generate interrupt requests. | |
|
698 | v.irq := | |
|
699 | (r.ctl_ielink and (linko.running xor (r.sta_link(0) and r.sta_link(1)))) or | |
|
700 | (r.ctl_ietick and linko.tick_out) or | |
|
701 | (r.ctl_ierxdesc and msto.int_rxdesc) or | |
|
702 | (r.ctl_ietxdesc and msto.int_txdesc) or | |
|
703 | (r.ctl_ierxpacket and msto.int_rxpacket); | |
|
704 | ||
|
705 | -- APB read access. | |
|
706 | if apbi.psel(pindex) = '1' then | |
|
707 | case apbi.paddr(4 downto 2) is | |
|
708 | when "000" => -- read control register | |
|
709 | v_prdata(0) := '0'; | |
|
710 | v_prdata(1) := '0'; | |
|
711 | v_prdata(2) := r.ctl_linkstart; | |
|
712 | v_prdata(3) := r.ctl_autostart; | |
|
713 | v_prdata(4) := r.ctl_linkdis; | |
|
714 | v_prdata(5) := r.ctl_ticken; | |
|
715 | v_prdata(6) := '0'; | |
|
716 | v_prdata(7) := '0'; | |
|
717 | v_prdata(8) := r.ctl_txcancel; | |
|
718 | v_prdata(9) := r.ctl_ielink; | |
|
719 | v_prdata(10) := r.ctl_ietick; | |
|
720 | v_prdata(11) := r.ctl_ierxdesc; | |
|
721 | v_prdata(12) := r.ctl_ietxdesc; | |
|
722 | v_prdata(13) := r.ctl_ierxpacket; | |
|
723 | v_prdata(27 downto 24) := std_logic_vector(to_unsigned(desctablesize, 4)); | |
|
724 | when "001" => -- read status register | |
|
725 | v_prdata(1 downto 0) := r.sta_link; | |
|
726 | v_prdata(2) := r.sta_errdisc; | |
|
727 | v_prdata(3) := r.sta_errpar; | |
|
728 | v_prdata(4) := r.sta_erresc; | |
|
729 | v_prdata(5) := r.sta_errcred; | |
|
730 | v_prdata(6) := msto.rxdma_act; | |
|
731 | v_prdata(7) := msto.txdma_act; | |
|
732 | v_prdata(8) := msto.ahberror; | |
|
733 | v_prdata(10) := r.sta_gottick; | |
|
734 | v_prdata(11) := r.sta_rxdesc; | |
|
735 | v_prdata(12) := r.sta_txdesc; | |
|
736 | v_prdata(13) := r.sta_rxpacket; | |
|
737 | v_prdata(14) := r.sta_rxempty; | |
|
738 | when "010" => -- read transmission clock scaler | |
|
739 | v_prdata(7 downto 0) := r.txdivcnt; | |
|
740 | when "011" => -- read timecode register | |
|
741 | v_prdata(5 downto 0) := linko.time_out; | |
|
742 | v_prdata(7 downto 6) := linko.ctrl_out; | |
|
743 | v_prdata(13 downto 8) := r.time_in; | |
|
744 | v_prdata(16 downto 14) := "000"; | |
|
745 | when "100" => -- read rx descriptor pointer | |
|
746 | v_prdata(2 downto 0) := (others => '0'); | |
|
747 | v_prdata(31 downto 3) := r.rxdesc_ptr; | |
|
748 | when "101" => -- read tx descriptor pointer | |
|
749 | v_prdata(2 downto 0) := (others => '0'); | |
|
750 | v_prdata(31 downto 3) := r.txdesc_ptr; | |
|
751 | when others => | |
|
752 | null; | |
|
753 | end case; | |
|
754 | end if; | |
|
755 | ||
|
756 | -- APB write access. | |
|
757 | if (apbi.psel(pindex) and apbi.penable and apbi.pwrite) = '1' then | |
|
758 | case apbi.paddr(4 downto 2) is | |
|
759 | when "000" => -- write control register | |
|
760 | v.ctl_reset := apbi.pwdata(0); | |
|
761 | v.ctl_resetdma := apbi.pwdata(1); | |
|
762 | v.ctl_linkstart := apbi.pwdata(2); | |
|
763 | v.ctl_autostart := apbi.pwdata(3); | |
|
764 | v.ctl_linkdis := apbi.pwdata(4); | |
|
765 | v.ctl_ticken := apbi.pwdata(5); | |
|
766 | v.ctl_rxstart := apbi.pwdata(6); | |
|
767 | v.ctl_txstart := apbi.pwdata(7); | |
|
768 | if apbi.pwdata(8) = '1' then v.ctl_txcancel := '1'; end if; | |
|
769 | v.ctl_ielink := apbi.pwdata(9); | |
|
770 | v.ctl_ietick := apbi.pwdata(10); | |
|
771 | v.ctl_ierxdesc := apbi.pwdata(11); | |
|
772 | v.ctl_ietxdesc := apbi.pwdata(12); | |
|
773 | v.ctl_ierxpacket := apbi.pwdata(13); | |
|
774 | when "001" => -- write status register | |
|
775 | if apbi.pwdata(2) = '1' then v.sta_errdisc := '0'; end if; | |
|
776 | if apbi.pwdata(3) = '1' then v.sta_errpar := '0'; end if; | |
|
777 | if apbi.pwdata(4) = '1' then v.sta_erresc := '0'; end if; | |
|
778 | if apbi.pwdata(5) = '1' then v.sta_errcred := '0'; end if; | |
|
779 | if apbi.pwdata(10) = '1' then v.sta_gottick := '0'; end if; | |
|
780 | if apbi.pwdata(11) = '1' then v.sta_rxdesc := '0'; end if; | |
|
781 | if apbi.pwdata(12) = '1' then v.sta_txdesc := '0'; end if; | |
|
782 | if apbi.pwdata(13) = '1' then v.sta_rxpacket := '0'; end if; | |
|
783 | when "010" => -- write transmission clock scaler | |
|
784 | v.txdivcnt := apbi.pwdata(7 downto 0); | |
|
785 | when "011" => -- write timecode register | |
|
786 | v.time_in := apbi.pwdata(13 downto 8); | |
|
787 | if apbi.pwdata(16) = '1' then v.tick_in := '1'; end if; | |
|
788 | when "100" => -- write rx descriptor pointer | |
|
789 | v.rxdesc_ptr := apbi.pwdata(31 downto 3); | |
|
790 | when "101" => -- write tx descriptor pointer | |
|
791 | v.txdesc_ptr := apbi.pwdata(31 downto 3); | |
|
792 | when others => | |
|
793 | null; | |
|
794 | end case; | |
|
795 | end if; | |
|
796 | ||
|
797 | -- Drive control signals to RX fifo. | |
|
798 | s_rxfifo_raddr <= v.rxfifo_raddr; -- new value of rxfifo_raddr | |
|
799 | s_rxfifo_wen <= r.rxfifo_write; | |
|
800 | s_rxfifo_waddr <= r.rxfifo_waddr; | |
|
801 | s_rxfifo_wdata <= r.rxfifo_wdata; | |
|
802 | ||
|
803 | -- Drive control signals to TX fifo. | |
|
804 | s_txfifo_raddr <= v.txfifo_raddr; -- new value of txfifo_raddr | |
|
805 | s_txfifo_wen <= msto.txfifo_write; | |
|
806 | s_txfifo_waddr <= r.txfifo_waddr; | |
|
807 | s_txfifo_wdata <= msto.txfifo_wdata; | |
|
808 | ||
|
809 | -- Drive inputs to spwlink. | |
|
810 | linki.autostart <= r.ctl_autostart; | |
|
811 | linki.linkstart <= r.ctl_linkstart; | |
|
812 | linki.linkdis <= r.ctl_linkdis; | |
|
813 | linki.rxroom <= r.rxroom; | |
|
814 | linki.tick_in <= r.tick_in; | |
|
815 | linki.ctrl_in <= "00"; | |
|
816 | linki.time_in <= r.time_in; | |
|
817 | linki.txwrite <= (not r.txfifo_empty) and (not r.txdiscard); | |
|
818 | linki.txflag <= s_txfifo_rdata(35-v_txfifo_bytepos); | |
|
819 | linki.txdata <= s_txfifo_rdata(31-8*v_txfifo_bytepos downto 24-8*v_txfifo_bytepos); | |
|
820 | ||
|
821 | -- Drive divcnt input to spwxmit. | |
|
822 | if linko.running = '1' then | |
|
823 | xmit_divcnt <= r.txdivcnt; | |
|
824 | else | |
|
825 | xmit_divcnt <= default_divcnt; | |
|
826 | end if; | |
|
827 | ||
|
828 | -- Drive inputs to AHB master. | |
|
829 | msti.rxdma_start <= r.ctl_rxstart; | |
|
830 | msti.txdma_start <= r.ctl_txstart; | |
|
831 | msti.txdma_cancel <= r.ctl_txcancel; | |
|
832 | msti.rxdesc_ptr <= r.rxdesc_ptr; | |
|
833 | msti.txdesc_ptr <= r.txdesc_ptr; | |
|
834 | msti.rxfifo_rdata <= s_rxfifo_rdata; | |
|
835 | msti.rxfifo_empty <= r.rxfifo_empty; | |
|
836 | msti.rxfifo_nxempty <= v.rxfifo_empty; -- new value of rxfifo_empty | |
|
837 | msti.txfifo_nxfull <= r.txfifo_nxfull; | |
|
838 | msti.txfifo_highw <= r.txfifo_highw; | |
|
839 | ||
|
840 | -- Pass tick_out signal to output port. | |
|
841 | tick_out <= linko.tick_out; | |
|
842 | ||
|
843 | -- Drive APB output signals. | |
|
844 | apbo.prdata <= v_prdata; | |
|
845 | apbo.pirq <= v_irq; | |
|
846 | apbo.pconfig <= pconfig; | |
|
847 | apbo.pindex <= pindex; | |
|
848 | ||
|
849 | -- Reset components. | |
|
850 | ahbmst_rstn <= rstn and (not r.ctl_reset) and (not r.ctl_resetdma); | |
|
851 | link_rst <= (not rstn) or r.ctl_reset; | |
|
852 | xmit_rst <= not rstn; | |
|
853 | ||
|
854 | -- Clear TX fifo on cancel request. | |
|
855 | if r.ctl_txcancel = '1' then | |
|
856 | v.txfifo_raddr := (others => '0'); | |
|
857 | v.txfifo_waddr := (others => '0'); | |
|
858 | v.txfifo_empty := '1'; | |
|
859 | v.txfifo_nxfull := '0'; | |
|
860 | v.txfifo_highw := '0'; | |
|
861 | v.txfifo_bytepos := "00"; | |
|
862 | v.txpacket := '0'; | |
|
863 | v.txdiscard := '0'; | |
|
864 | end if; | |
|
865 | ||
|
866 | -- Reset registers. | |
|
867 | if rstn = '0' or r.ctl_reset = '1' then | |
|
868 | v := regs_reset; | |
|
869 | end if; | |
|
870 | ||
|
871 | -- Update registers. | |
|
872 | rin <= v; | |
|
873 | end process; | |
|
874 | ||
|
875 | ||
|
876 | -- | |
|
877 | -- Update registers. | |
|
878 | -- | |
|
879 | process (clk) is | |
|
880 | begin | |
|
881 | if rising_edge(clk) then | |
|
882 | r <= rin; | |
|
883 | end if; | |
|
884 | end process; | |
|
885 | ||
|
886 | end architecture spwamba_arch; |
@@ -0,0 +1,159 | |||
|
1 | -- | |
|
2 | -- VHDL package for SpaceWire AMBA interface. | |
|
3 | -- | |
|
4 | -- This package depends on Gaisler GRLIB. | |
|
5 | -- | |
|
6 | ||
|
7 | library ieee; | |
|
8 | use ieee.std_logic_1164.all; | |
|
9 | library grlib; | |
|
10 | use grlib.amba.all; | |
|
11 | library techmap; | |
|
12 | use techmap.gencomp.all; | |
|
13 | use work.spwpkg.all; | |
|
14 | ||
|
15 | package spwambapkg is | |
|
16 | ||
|
17 | ||
|
18 | -- AMBA plug&play device id | |
|
19 | constant DEVICE_SPACEWIRELIGHT: amba_device_type := 16#131#; | |
|
20 | ||
|
21 | ||
|
22 | -- Signals from SpaceWire core to AHB master. | |
|
23 | type spw_ahbmst_in_type is record | |
|
24 | ||
|
25 | -- Pulse high to start the RX DMA engine. | |
|
26 | rxdma_start: std_ulogic; | |
|
27 | ||
|
28 | -- Pulse high to start the TX DMA engine. | |
|
29 | txdma_start: std_ulogic; | |
|
30 | ||
|
31 | -- Stop TX DMA engine (at end of current burst). | |
|
32 | txdma_cancel: std_ulogic; | |
|
33 | ||
|
34 | -- Address of current RX descriptor (8-byte aligned). | |
|
35 | rxdesc_ptr: std_logic_vector(31 downto 3); | |
|
36 | ||
|
37 | -- Address of current TX descriptor (8-byte aligned). | |
|
38 | txdesc_ptr: std_logic_vector(31 downto 3); | |
|
39 | ||
|
40 | -- Read port of RX FIFO. | |
|
41 | rxfifo_rdata: std_logic_vector(35 downto 0); | |
|
42 | ||
|
43 | -- High if RX FIFO is empty. | |
|
44 | rxfifo_empty: std_ulogic; | |
|
45 | ||
|
46 | -- High if RX FIFO will be empty after one read. | |
|
47 | -- May combinatorially depend on spw_ahbmst_out_type.rxfifo_read. | |
|
48 | rxfifo_nxempty: std_ulogic; | |
|
49 | ||
|
50 | -- High if TX FIFO is full or has room for at most one word. | |
|
51 | txfifo_nxfull: std_ulogic; | |
|
52 | ||
|
53 | -- High if TX FIFO is close to full (blocks refill). | |
|
54 | txfifo_highw: std_ulogic; | |
|
55 | end record; | |
|
56 | ||
|
57 | -- Signals from AHB master to SpaceWire core. | |
|
58 | type spw_ahbmst_out_type is record | |
|
59 | ||
|
60 | -- High if the RX DMA engine is enabled. | |
|
61 | rxdma_act: std_ulogic; | |
|
62 | ||
|
63 | -- High if the TX DMA engine is enabled. | |
|
64 | txdma_act: std_ulogic; | |
|
65 | ||
|
66 | -- High if an error occurred on the AHB bus. | |
|
67 | ahberror: std_ulogic; | |
|
68 | ||
|
69 | -- Pulsed high to trigger an RX descriptor interrupt. | |
|
70 | int_rxdesc: std_ulogic; | |
|
71 | ||
|
72 | -- Pulsed high to trigger a TX descriptor interrupt. | |
|
73 | int_txdesc: std_ulogic; | |
|
74 | ||
|
75 | -- Pulsed high when a complete packet has been received. | |
|
76 | int_rxpacket: std_ulogic; | |
|
77 | ||
|
78 | -- Pulsed high to request the next RX descriptor address. | |
|
79 | -- (rxdesc_ptr must be updated in the next clock cycle). | |
|
80 | rxdesc_next: std_ulogic; | |
|
81 | ||
|
82 | -- Pulsed high together with rxdesc_next to wrap the RX descriptor pointer. | |
|
83 | rxdesc_wrap: std_ulogic; | |
|
84 | ||
|
85 | -- Pulsed high to request the next TX descriptor address. | |
|
86 | -- (txdesc_ptr must be updated in the next clock cycle). | |
|
87 | txdesc_next: std_ulogic; | |
|
88 | ||
|
89 | -- Pulsed high together with txdesc_next to wrap the TX descriptor pointer. | |
|
90 | txdesc_wrap: std_ulogic; | |
|
91 | ||
|
92 | -- Read strobe to RX fifo. | |
|
93 | rxfifo_read: std_ulogic; | |
|
94 | ||
|
95 | -- Write enable to TX fifo. | |
|
96 | txfifo_write: std_ulogic; | |
|
97 | ||
|
98 | -- Input port of TX fifo. | |
|
99 | txfifo_wdata: std_logic_vector(35 downto 0); | |
|
100 | end record; | |
|
101 | ||
|
102 | ||
|
103 | -- SpaceWire core with AMBA interface. | |
|
104 | component spwamba is | |
|
105 | generic ( | |
|
106 | tech: integer range 0 to NTECH := DEFFABTECH; | |
|
107 | hindex: integer; -- AHB master index | |
|
108 | pindex: integer; -- APB slave index | |
|
109 | paddr: integer; -- APB address range | |
|
110 | pmask: integer := 16#fff#; -- APB address mask | |
|
111 | pirq: integer; -- interrupt number | |
|
112 | sysfreq: real; -- system clock frequency in Hz | |
|
113 | txclkfreq: real := 0.0; -- txclk frequency in Hz | |
|
114 | rximpl: spw_implementation_type := impl_generic; | |
|
115 | rxchunk: integer range 1 to 4 := 1; | |
|
116 | tximpl: spw_implementation_type := impl_generic; | |
|
117 | timecodegen: boolean := true; -- support timecode generation | |
|
118 | rxfifosize: integer range 6 to 12 := 8; -- size of receive FIFO (2-log of words) | |
|
119 | txfifosize: integer range 2 to 12 := 8; -- size of transmit FIFO (2-log of words) | |
|
120 | desctablesize: integer range 4 to 14 := 10; -- size of the DMA descriptor tables (2-log of descriptors) | |
|
121 | maxburst: integer range 1 to 8 := 3 -- max burst length (2-log of words) | |
|
122 | ); | |
|
123 | port ( | |
|
124 | clk: in std_logic; -- system clock. | |
|
125 | rxclk: in std_logic; -- receiver sample clock | |
|
126 | txclk: in std_logic; -- transmit clock | |
|
127 | rstn: in std_logic; -- synchronous reset (active-low) | |
|
128 | apbi: in apb_slv_in_type; -- APB slave input signals | |
|
129 | apbo: out apb_slv_out_type; -- APB slave output signals | |
|
130 | ahbi: in ahb_mst_in_type; -- AHB master input signals | |
|
131 | ahbo: out ahb_mst_out_type; -- AHB master output signals | |
|
132 | tick_in: in std_logic; -- pulse for timecode generation | |
|
133 | tick_out: out std_logic; -- timecode received | |
|
134 | spw_di: in std_logic; -- Data In signal from SpaceWire bus | |
|
135 | spw_si: in std_logic; -- Strobe In signal from SpaceWire bus | |
|
136 | spw_do: out std_logic; -- Data Out signal to SpaceWire bus | |
|
137 | spw_so: out std_logic -- Strobe Out signal to SpaceWire bus | |
|
138 | ); | |
|
139 | end component spwamba; | |
|
140 | ||
|
141 | ||
|
142 | -- AHB master for AMBA interface. | |
|
143 | component spwahbmst is | |
|
144 | generic ( | |
|
145 | hindex: integer; -- AHB master index | |
|
146 | hconfig: ahb_config_type; -- AHB plug&play information | |
|
147 | maxburst: integer range 1 to 8 -- 2log of max burst length | |
|
148 | ); | |
|
149 | port ( | |
|
150 | clk: in std_logic; -- system clock | |
|
151 | rstn: in std_logic; -- synchronous reset (active-low) | |
|
152 | msti: in spw_ahbmst_in_type; -- inputs from SpaceWire core | |
|
153 | msto: out spw_ahbmst_out_type; -- outputs to SpaceWire core | |
|
154 | ahbi: in ahb_mst_in_type; -- AHB master input signals | |
|
155 | ahbo: out ahb_mst_out_type -- AHB master output signals | |
|
156 | ); | |
|
157 | end component spwahbmst; | |
|
158 | ||
|
159 | end package; |
@@ -0,0 +1,286 | |||
|
1 | -- | |
|
2 | -- SpaceWire Exchange Level Controller. | |
|
3 | -- | |
|
4 | -- This entity implements exchange level aspects of the SpaceWire protocol. | |
|
5 | -- It handles connection setup, error detection and flow control. | |
|
6 | -- | |
|
7 | ||
|
8 | library ieee; | |
|
9 | use ieee.std_logic_1164.all; | |
|
10 | use ieee.numeric_std.all; | |
|
11 | use work.spwpkg.all; | |
|
12 | ||
|
13 | entity spwlink is | |
|
14 | ||
|
15 | generic ( | |
|
16 | -- Reset time expressed in system clock cycles. | |
|
17 | -- Should be 6.4 us (5.82 us .. 7.2 us) according to the standard. | |
|
18 | reset_time: integer | |
|
19 | ); | |
|
20 | ||
|
21 | port ( | |
|
22 | -- System clock. | |
|
23 | clk: in std_logic; | |
|
24 | ||
|
25 | -- Synchronous reset (active-high). | |
|
26 | -- Disconnects, resets error conditions, puts the link state machine | |
|
27 | -- in state ErrorReset. | |
|
28 | rst: in std_logic; | |
|
29 | ||
|
30 | -- Link level inputs. | |
|
31 | linki: in spw_link_in_type; | |
|
32 | ||
|
33 | -- Link level outputs. | |
|
34 | linko: out spw_link_out_type; | |
|
35 | ||
|
36 | -- Receiver enable signal to spwrecv. | |
|
37 | rxen: out std_logic; | |
|
38 | ||
|
39 | -- Output signals from spwrecv. | |
|
40 | recvo: in spw_recv_out_type; | |
|
41 | ||
|
42 | -- Input signals for spwxmit. | |
|
43 | xmiti: out spw_xmit_in_type; | |
|
44 | ||
|
45 | -- Output signals from spwxmit. | |
|
46 | xmito: in spw_xmit_out_type | |
|
47 | ); | |
|
48 | ||
|
49 | end entity spwlink; | |
|
50 | ||
|
51 | architecture spwlink_arch of spwlink is | |
|
52 | ||
|
53 | -- Convert boolean to std_logic. | |
|
54 | type bool_to_logic_type is array(boolean) of std_ulogic; | |
|
55 | constant bool_to_logic: bool_to_logic_type := (false => '0', true => '1'); | |
|
56 | ||
|
57 | -- State machine. | |
|
58 | type state_type is ( | |
|
59 | S_ErrorReset, S_ErrorWait, S_Ready, S_Started, S_Connecting, S_Run ); | |
|
60 | ||
|
61 | -- Registers | |
|
62 | type regs_type is record | |
|
63 | -- state machine | |
|
64 | state: state_type; | |
|
65 | -- credit accounting | |
|
66 | tx_credit: unsigned(5 downto 0); | |
|
67 | rx_credit: unsigned(5 downto 0); | |
|
68 | errcred: std_ulogic; | |
|
69 | -- reset timer | |
|
70 | timercnt: unsigned(10 downto 0); | |
|
71 | timerdone: std_ulogic; | |
|
72 | -- signal to transmitter | |
|
73 | xmit_fct_in: std_ulogic; | |
|
74 | end record; | |
|
75 | ||
|
76 | -- Initial state | |
|
77 | constant regs_reset: regs_type := ( | |
|
78 | state => S_ErrorReset, | |
|
79 | tx_credit => "000000", | |
|
80 | rx_credit => "000000", | |
|
81 | errcred => '0', | |
|
82 | timercnt => to_unsigned(reset_time, 11), | |
|
83 | timerdone => '0', | |
|
84 | xmit_fct_in => '0' ); | |
|
85 | ||
|
86 | signal r: regs_type := regs_reset; | |
|
87 | signal rin: regs_type; | |
|
88 | ||
|
89 | begin | |
|
90 | ||
|
91 | -- Combinatorial process | |
|
92 | process (r, rst, linki, recvo, xmito) is | |
|
93 | variable v: regs_type; | |
|
94 | variable v_timerrst: std_logic; | |
|
95 | begin | |
|
96 | v := r; | |
|
97 | v_timerrst := '0'; | |
|
98 | ||
|
99 | -- State machine. | |
|
100 | case r.state is | |
|
101 | ||
|
102 | when S_ErrorReset => | |
|
103 | -- Wait for timer. | |
|
104 | if r.timercnt = 0 then | |
|
105 | v.state := S_ErrorWait; | |
|
106 | v_timerrst := '1'; | |
|
107 | end if; | |
|
108 | v.errcred := '0'; | |
|
109 | v.xmit_fct_in := '0'; | |
|
110 | ||
|
111 | when S_ErrorWait => | |
|
112 | -- Wait for 2 timer periods. | |
|
113 | if ((recvo.errdisc or recvo.errpar or recvo.erresc) = '1') or | |
|
114 | ((recvo.gotfct or recvo.tick_out or recvo.rxchar) = '1') then | |
|
115 | -- Note: spwrecv will never issue errpar, erresc, gotfct, | |
|
116 | -- tick_out or rxchar before the first NULL has been seen. | |
|
117 | -- Therefore it's ok here to bail on those conditions | |
|
118 | -- without explicitly testing got_null. | |
|
119 | v.state := S_ErrorReset; -- error, go back to reset | |
|
120 | v_timerrst := '1'; | |
|
121 | elsif r.timercnt = 0 then | |
|
122 | if r.timerdone = '1' then | |
|
123 | v.state := S_Ready; | |
|
124 | v_timerrst := '1'; | |
|
125 | end if; | |
|
126 | end if; | |
|
127 | ||
|
128 | when S_Ready => | |
|
129 | -- Wait for link start. | |
|
130 | if ((recvo.errdisc or recvo.errpar or recvo.erresc) = '1') or | |
|
131 | ((recvo.gotfct or recvo.tick_out or recvo.rxchar) = '1') then | |
|
132 | v.state := S_ErrorReset; -- error, go back to reset | |
|
133 | v_timerrst := '1'; | |
|
134 | elsif (linki.linkdis = '0') and (r.xmit_fct_in = '1') and | |
|
135 | ((linki.linkstart or (linki.autostart and recvo.gotnull)) = '1') then | |
|
136 | v.state := S_Started; -- link enabled; start sending NULL | |
|
137 | v_timerrst := '1'; | |
|
138 | end if; | |
|
139 | ||
|
140 | when S_Started => | |
|
141 | -- Wait for NULL. | |
|
142 | if ((recvo.errdisc or recvo.errpar or recvo.erresc) = '1') or | |
|
143 | ((recvo.gotfct or recvo.tick_out or recvo.rxchar) = '1') or | |
|
144 | ((r.timercnt = 0) and r.timerdone = '1') then | |
|
145 | v.state := S_ErrorReset; -- error, go back to reset | |
|
146 | v_timerrst := '1'; | |
|
147 | elsif recvo.gotnull = '1' then | |
|
148 | v.state := S_Connecting; -- received null, continue | |
|
149 | v_timerrst := '1'; | |
|
150 | end if; | |
|
151 | ||
|
152 | when S_Connecting => | |
|
153 | -- Wait for FCT. | |
|
154 | if ((recvo.errdisc or recvo.errpar or recvo.erresc) = '1') or | |
|
155 | ((recvo.tick_out or recvo.rxchar) = '1') or | |
|
156 | ((r.timercnt = 0) and r.timerdone = '1') then | |
|
157 | v.state := S_ErrorReset; -- error, go back to reset | |
|
158 | v_timerrst := '1'; | |
|
159 | elsif recvo.gotfct = '1' then | |
|
160 | v.state := S_Run; -- got FCT, init completed | |
|
161 | end if; | |
|
162 | ||
|
163 | when S_Run => | |
|
164 | -- All is well. | |
|
165 | if ((recvo.errdisc or recvo.errpar or recvo.erresc) = '1') or | |
|
166 | (r.errcred = '1') or | |
|
167 | (linki.linkdis = '1') then | |
|
168 | v.state := S_ErrorReset; -- error, go back to reset | |
|
169 | v_timerrst := '1'; | |
|
170 | end if; | |
|
171 | ||
|
172 | when others => | |
|
173 | v.state := S_ErrorReset; -- recover from invalid state | |
|
174 | v_timerrst := '1'; | |
|
175 | ||
|
176 | end case; | |
|
177 | ||
|
178 | -- Update credit counters. | |
|
179 | if r.state = S_ErrorReset then | |
|
180 | ||
|
181 | -- reset credit | |
|
182 | v.tx_credit := to_unsigned(0, v.tx_credit'length); | |
|
183 | v.rx_credit := to_unsigned(0, v.rx_credit'length); | |
|
184 | ||
|
185 | else | |
|
186 | ||
|
187 | -- update TX credit | |
|
188 | if recvo.gotfct = '1' then | |
|
189 | -- just received a FCT token | |
|
190 | v.tx_credit := v.tx_credit + to_unsigned(8, v.tx_credit'length); | |
|
191 | if r.tx_credit > 48 then | |
|
192 | -- received too many FCT tokens | |
|
193 | v.errcred := '1'; | |
|
194 | end if; | |
|
195 | end if; | |
|
196 | if xmito.txack = '1' then | |
|
197 | -- just sent one byte | |
|
198 | v.tx_credit := v.tx_credit - to_unsigned(1, v.tx_credit'length); | |
|
199 | end if; | |
|
200 | ||
|
201 | -- update RX credit after sending FCT | |
|
202 | if xmito.fctack = '1' then | |
|
203 | -- just sent a FCT token | |
|
204 | v.rx_credit := v.rx_credit + to_unsigned(8, v.rx_credit'length); | |
|
205 | end if; | |
|
206 | ||
|
207 | -- decide about sending FCT tokens | |
|
208 | v.xmit_fct_in := bool_to_logic( (v.rx_credit <= 48) and | |
|
209 | (v.rx_credit + to_unsigned(8, v.rx_credit'length) <= unsigned(linki.rxroom)) ); | |
|
210 | ||
|
211 | -- update RX credit after receiving character | |
|
212 | if recvo.rxchar = '1' then | |
|
213 | -- just received a character | |
|
214 | v.rx_credit := v.rx_credit - to_unsigned(1, v.rx_credit'length); | |
|
215 | if r.rx_credit = 0 then | |
|
216 | -- remote transmitter violated its credit | |
|
217 | v.errcred := '1'; | |
|
218 | end if; | |
|
219 | end if; | |
|
220 | ||
|
221 | end if; | |
|
222 | ||
|
223 | -- Update the initializaton reset timer. | |
|
224 | if v_timerrst = '1' then | |
|
225 | v.timercnt := to_unsigned(reset_time, v.timercnt'length); | |
|
226 | v.timerdone := '0'; | |
|
227 | else | |
|
228 | if r.timercnt = 0 then | |
|
229 | v.timercnt := to_unsigned(reset_time, v.timercnt'length); | |
|
230 | v.timerdone := '1'; | |
|
231 | else | |
|
232 | v.timercnt := r.timercnt - 1; | |
|
233 | end if; | |
|
234 | end if; | |
|
235 | ||
|
236 | -- Reset | |
|
237 | if rst = '1' then | |
|
238 | v := regs_reset; | |
|
239 | end if; | |
|
240 | ||
|
241 | -- Drive link level outputs. | |
|
242 | linko.started <= bool_to_logic(r.state = S_Started); | |
|
243 | linko.connecting <= bool_to_logic(r.state = S_Connecting); | |
|
244 | linko.running <= bool_to_logic(r.state = S_Run); | |
|
245 | linko.errdisc <= recvo.errdisc and bool_to_logic(r.state = S_Run); | |
|
246 | linko.errpar <= recvo.errpar and bool_to_logic(r.state = S_Run); | |
|
247 | linko.erresc <= recvo.erresc and bool_to_logic(r.state = S_Run); | |
|
248 | linko.errcred <= r.errcred; | |
|
249 | linko.txack <= xmito.txack; | |
|
250 | linko.tick_out <= recvo.tick_out and bool_to_logic(r.state = S_Run); | |
|
251 | linko.ctrl_out <= recvo.ctrl_out; | |
|
252 | linko.time_out <= recvo.time_out; | |
|
253 | linko.rxchar <= recvo.rxchar and bool_to_logic(r.state = S_Run); | |
|
254 | linko.rxflag <= recvo.rxflag; | |
|
255 | linko.rxdata <= recvo.rxdata; | |
|
256 | ||
|
257 | -- Drive receiver inputs. | |
|
258 | rxen <= bool_to_logic(r.state /= S_ErrorReset); | |
|
259 | ||
|
260 | -- Drive transmitter input signals. | |
|
261 | xmiti.txen <= bool_to_logic(r.state = S_Started or | |
|
262 | r.state = S_Connecting or | |
|
263 | r.state = S_Run); | |
|
264 | xmiti.stnull <= bool_to_logic(r.state = S_Started); | |
|
265 | xmiti.stfct <= bool_to_logic(r.state = S_Connecting); | |
|
266 | xmiti.fct_in <= r.xmit_fct_in; | |
|
267 | xmiti.tick_in <= linki.tick_in and bool_to_logic(r.state = S_Run); | |
|
268 | xmiti.ctrl_in <= linki.ctrl_in; | |
|
269 | xmiti.time_in <= linki.time_in; | |
|
270 | xmiti.txwrite <= linki.txwrite and bool_to_logic(r.tx_credit /= 0); | |
|
271 | xmiti.txflag <= linki.txflag; | |
|
272 | xmiti.txdata <= linki.txdata; | |
|
273 | ||
|
274 | -- Update registers. | |
|
275 | rin <= v; | |
|
276 | end process; | |
|
277 | ||
|
278 | -- Update registers. | |
|
279 | process (clk) is | |
|
280 | begin | |
|
281 | if rising_edge(clk) then | |
|
282 | r <= rin; | |
|
283 | end if; | |
|
284 | end process; | |
|
285 | ||
|
286 | end architecture spwlink_arch; |
@@ -0,0 +1,403 | |||
|
1 | -- | |
|
2 | -- SpaceWire VHDL package | |
|
3 | -- | |
|
4 | ||
|
5 | library ieee; | |
|
6 | use ieee.std_logic_1164.all; | |
|
7 | ||
|
8 | package spwpkg is | |
|
9 | ||
|
10 | ||
|
11 | -- Indicates a platform-specific implementation. | |
|
12 | type spw_implementation_type is ( impl_generic, impl_fast ); | |
|
13 | ||
|
14 | ||
|
15 | -- Input signals to spwlink. | |
|
16 | type spw_link_in_type is record | |
|
17 | ||
|
18 | -- Enables automatic link start on receipt of a NULL character. | |
|
19 | autostart: std_logic; | |
|
20 | ||
|
21 | -- Enables link start once the Ready state is reached. | |
|
22 | -- Without either "autostart" or "linkstart", the link remains in | |
|
23 | -- state Ready. | |
|
24 | linkstart: std_logic; | |
|
25 | ||
|
26 | -- Do not start link (overrides "linkstart" and "autostart") and/or | |
|
27 | -- disconnect the currently running link. | |
|
28 | linkdis: std_logic; | |
|
29 | ||
|
30 | -- Number of bytes available in the receive buffer. Used to for | |
|
31 | -- flow-control operation. At least 8 bytes must be available | |
|
32 | -- initially, otherwise the link can not start. Values larger than 63 | |
|
33 | -- are irrelevant and may be presented as 63. The available room may | |
|
34 | -- decrease by one byte due to the reception of an N-Char; in that case | |
|
35 | -- the "rxroom" signal must be updated on the clock following the clock | |
|
36 | -- on which "rxchar" is high. Under no other circumstances may "rxroom" | |
|
37 | -- be decreased. | |
|
38 | rxroom: std_logic_vector(5 downto 0); | |
|
39 | ||
|
40 | -- High for one clock cycle to request transmission of a TimeCode. | |
|
41 | -- The request is registered inside spwxmit until it can be processed. | |
|
42 | tick_in: std_logic; | |
|
43 | ||
|
44 | -- Control bits of the TimeCode to be sent. | |
|
45 | -- Must be valid while tick_in is high. | |
|
46 | ctrl_in: std_logic_vector(1 downto 0); | |
|
47 | ||
|
48 | -- Counter value of the TimeCode to be sent. | |
|
49 | -- Must be valid while tick_in is high. | |
|
50 | time_in: std_logic_vector(5 downto 0); | |
|
51 | ||
|
52 | -- Requests transmission of an N-Char. | |
|
53 | -- Keep this signal high until confirmed by "txack". | |
|
54 | txwrite: std_logic; | |
|
55 | ||
|
56 | -- Control flag to be sent with the next N-Char. | |
|
57 | -- Must be valid while "txwrite" is high. | |
|
58 | txflag: std_logic; | |
|
59 | ||
|
60 | -- Byte to be sent, or "00000000" for EOP or "00000001" for EEP. | |
|
61 | -- Must be valid while "txwrite" is high. | |
|
62 | txdata: std_logic_vector(7 downto 0); | |
|
63 | end record; | |
|
64 | ||
|
65 | ||
|
66 | -- Output signals from spwlink. | |
|
67 | type spw_link_out_type is record | |
|
68 | ||
|
69 | -- High if the link state machine is currently in state Started. | |
|
70 | started: std_logic; | |
|
71 | ||
|
72 | -- High if the link state machine is currently in state Connecting. | |
|
73 | connecting: std_logic; | |
|
74 | ||
|
75 | -- High if the link state machine is currently in state Run. | |
|
76 | running: std_logic; | |
|
77 | ||
|
78 | -- Disconnect detected in state Run. Triggers a reset and reconnect. | |
|
79 | -- This indication is auto-clearing. | |
|
80 | errdisc: std_logic; | |
|
81 | ||
|
82 | -- Parity error detected in state Run. Triggers a reset and reconnect. | |
|
83 | -- This indication is auto-clearing. | |
|
84 | errpar: std_logic; | |
|
85 | ||
|
86 | -- Invalid escape sequence detected in state Run. | |
|
87 | -- Triggers a reset and reconnect; auto-clearing. | |
|
88 | erresc: std_logic; | |
|
89 | ||
|
90 | -- Credit error detected. Triggers a reset and reconnect. | |
|
91 | -- This indication is auto-clearing. | |
|
92 | errcred: std_logic; | |
|
93 | ||
|
94 | -- High to confirm the transmission of an N-Char. | |
|
95 | -- This is a Wishbone-style handshake signal. It has a combinatorial | |
|
96 | -- dependency on "txwrite". | |
|
97 | txack: std_logic; | |
|
98 | ||
|
99 | -- High for one clock cycle if a TimeCode was just received. | |
|
100 | -- Verification of the TimeCode as described in 8.12.2 of ECSS-E-50 | |
|
101 | -- is not implemented; all received timecodes are reported. | |
|
102 | tick_out: std_logic; | |
|
103 | ||
|
104 | -- Control bits of last received TimeCode. | |
|
105 | ctrl_out: std_logic_vector(1 downto 0); | |
|
106 | ||
|
107 | -- Counter value of last received TimeCode. | |
|
108 | time_out: std_logic_vector(5 downto 0); | |
|
109 | ||
|
110 | -- High for one clock cycle if an N-Char (data byte or EOP or EEP) was | |
|
111 | -- just received. The data bits must be accepted immediately from | |
|
112 | -- "rxflag" and "rxdata". | |
|
113 | rxchar: std_logic; | |
|
114 | ||
|
115 | -- High if the received character is EOP or EEP, low if it is a data | |
|
116 | -- byte. Valid when "rxchar" is high. | |
|
117 | rxflag: std_logic; | |
|
118 | ||
|
119 | -- Received byte, or "00000000" for EOP or "00000001" for EEP. | |
|
120 | -- Valid when "rxchar" is high. | |
|
121 | rxdata: std_logic_vector(7 downto 0); | |
|
122 | end record; | |
|
123 | ||
|
124 | ||
|
125 | -- Output signals from spwrecv to spwlink. | |
|
126 | type spw_recv_out_type is record | |
|
127 | ||
|
128 | -- High if at least one signal change was seen since enable. | |
|
129 | -- Resets to low when rxen is low. | |
|
130 | gotbit: std_logic; | |
|
131 | ||
|
132 | -- High if at least one valid NULL pattern was detected since enable. | |
|
133 | -- Resets to low when rxen is low. | |
|
134 | gotnull: std_logic; | |
|
135 | ||
|
136 | -- High for one clock cycle if an FCT token was just received. | |
|
137 | gotfct: std_logic; | |
|
138 | ||
|
139 | -- High for one clock cycle if a TimeCode was just received. | |
|
140 | tick_out: std_logic; | |
|
141 | ||
|
142 | -- Control bits of last received TimeCode. | |
|
143 | ctrl_out: std_logic_vector(1 downto 0); | |
|
144 | ||
|
145 | -- Counter value of last received TimeCode. | |
|
146 | time_out: std_logic_vector(5 downto 0); | |
|
147 | ||
|
148 | -- High for one clock cycle if an N-Char (data byte or EOP/EEP) was just received. | |
|
149 | rxchar: std_logic; | |
|
150 | ||
|
151 | -- High if rxchar is high and the received character is EOP or EEP. | |
|
152 | -- Low if rxchar is high and the received character is a data byte. | |
|
153 | rxflag: std_logic; | |
|
154 | ||
|
155 | -- Received byte, or "00000000" for EOP or "00000001" for EEP. | |
|
156 | -- Valid when "rxchar" is high. | |
|
157 | rxdata: std_logic_vector(7 downto 0); | |
|
158 | ||
|
159 | -- Disconnect detected (after a signal change was seen). | |
|
160 | -- Resets to low when rxen is low or when a signal change is seen. | |
|
161 | errdisc: std_logic; | |
|
162 | ||
|
163 | -- Parity error detected (after a valid NULL pattern was seen). | |
|
164 | -- Sticky; resets to low when rxen is low. | |
|
165 | errpar: std_logic; | |
|
166 | ||
|
167 | -- Escape sequence error detected (after a valid NULL pattern was seen). | |
|
168 | -- Sticky; resets to low when rxen is low. | |
|
169 | erresc: std_logic; | |
|
170 | end record; | |
|
171 | ||
|
172 | ||
|
173 | -- Input signals to spwxmit from spwlink. | |
|
174 | type spw_xmit_in_type is record | |
|
175 | ||
|
176 | -- High to enable transmitter; low to disable and reset transmitter. | |
|
177 | txen: std_logic; | |
|
178 | ||
|
179 | -- Indicates that only NULL characters may be transmitted. | |
|
180 | stnull: std_logic; | |
|
181 | ||
|
182 | -- Indicates that only NULL and/or FCT characters may be transmitted. | |
|
183 | stfct: std_logic; | |
|
184 | ||
|
185 | -- Requests transmission of an FCT character. | |
|
186 | -- Keep this signal high until confirmed by "fctack". | |
|
187 | fct_in: std_logic; | |
|
188 | ||
|
189 | -- High for one clock cycle to request transmission of a TimeCode. | |
|
190 | -- The request is registered inside spwxmit until it can be processed. | |
|
191 | tick_in: std_logic; | |
|
192 | ||
|
193 | -- Control bits of the TimeCode to be sent. | |
|
194 | -- Must be valid while "tick_in" is high. | |
|
195 | ctrl_in: std_logic_vector(1 downto 0); | |
|
196 | ||
|
197 | -- Counter value of the TimeCode to be sent. | |
|
198 | -- Must be valid while "tick_in" is high. | |
|
199 | time_in: std_logic_vector(5 downto 0); | |
|
200 | ||
|
201 | -- Request transmission of an N-Char. | |
|
202 | -- Keep this signal high until confirmed by "txack". | |
|
203 | txwrite: std_logic; | |
|
204 | ||
|
205 | -- Control flag to be sent with the next N-Char. | |
|
206 | -- Must be valid while "txwrite" is high. | |
|
207 | txflag: std_logic; | |
|
208 | ||
|
209 | -- Byte to send, or "00000000" for EOP or "00000001" for EEP. | |
|
210 | -- Must be valid while "txwrite" is high. | |
|
211 | txdata: std_logic_vector(7 downto 0); | |
|
212 | end record; | |
|
213 | ||
|
214 | ||
|
215 | -- Output signals from spwxmit to spwlink. | |
|
216 | type spw_xmit_out_type is record | |
|
217 | ||
|
218 | -- High to confirm transmission on an FCT character. | |
|
219 | -- This is a Wishbone-style handshaking signal; it is combinatorially | |
|
220 | -- dependent on "fct_in". | |
|
221 | fctack: std_logic; | |
|
222 | ||
|
223 | -- High to confirm transmission of an N-Char. | |
|
224 | -- This is a Wishbone-style handshaking signal; it is combinatorially | |
|
225 | -- dependent on both "fct_in" and "txwrite". | |
|
226 | txack: std_logic; | |
|
227 | end record; | |
|
228 | ||
|
229 | ||
|
230 | -- Character-stream interface | |
|
231 | component spwstream is | |
|
232 | generic ( | |
|
233 | sysfreq: real; -- clk freq in Hz | |
|
234 | txclkfreq: real := 0.0; -- txclk freq in Hz | |
|
235 | rximpl: spw_implementation_type := impl_generic; | |
|
236 | rxchunk: integer range 1 to 4 := 1; -- max bits per clk | |
|
237 | tximpl: spw_implementation_type := impl_generic; | |
|
238 | rxfifosize_bits: integer range 6 to 14 := 11; -- rx fifo size | |
|
239 | txfifosize_bits: integer range 2 to 14 := 11 -- tx fifo size | |
|
240 | ); | |
|
241 | port ( | |
|
242 | clk: in std_logic; -- system clock | |
|
243 | rxclk: in std_logic; -- receiver sample clock | |
|
244 | txclk: in std_logic; -- transmit clock | |
|
245 | rst: in std_logic; -- synchronous reset | |
|
246 | autostart: in std_logic; -- automatic link start | |
|
247 | linkstart: in std_logic; -- forced link start | |
|
248 | linkdis: in std_logic; -- stop link | |
|
249 | txdivcnt: in std_logic_vector(7 downto 0); -- tx scale factor | |
|
250 | tick_in: in std_logic; -- request timecode xmit | |
|
251 | ctrl_in: in std_logic_vector(1 downto 0); | |
|
252 | time_in: in std_logic_vector(5 downto 0); | |
|
253 | txwrite: in std_logic; -- request character xmit | |
|
254 | txflag: in std_logic; -- control flag of tx char | |
|
255 | txdata: in std_logic_vector(7 downto 0); | |
|
256 | txrdy: out std_logic; -- room in tx fifo | |
|
257 | txhalff: out std_logic; -- tx fifo half full | |
|
258 | tick_out: out std_logic; -- timecode received | |
|
259 | ctrl_out: out std_logic_vector(1 downto 0); | |
|
260 | time_out: out std_logic_vector(5 downto 0); | |
|
261 | rxvalid: out std_logic; -- rx fifo not empty | |
|
262 | rxhalff: out std_logic; -- rx fifo half full | |
|
263 | rxflag: out std_logic; -- control flag of rx char | |
|
264 | rxdata: out std_logic_vector(7 downto 0); | |
|
265 | rxread: in std_logic; -- accept rx character | |
|
266 | started: out std_logic; -- link in Started state | |
|
267 | connecting: out std_logic; -- link in Connecting state | |
|
268 | running: out std_logic; -- link in Run state | |
|
269 | errdisc: out std_logic; -- disconnect error | |
|
270 | errpar: out std_logic; -- parity error | |
|
271 | erresc: out std_logic; -- escape error | |
|
272 | errcred: out std_logic; -- credit error | |
|
273 | spw_di: in std_logic; | |
|
274 | spw_si: in std_logic; | |
|
275 | spw_do: out std_logic; | |
|
276 | spw_so: out std_logic | |
|
277 | ); | |
|
278 | end component spwstream; | |
|
279 | ||
|
280 | ||
|
281 | -- Link Level Interface | |
|
282 | component spwlink is | |
|
283 | generic ( | |
|
284 | reset_time: integer -- reset time in clocks (6.4 us) | |
|
285 | ); | |
|
286 | port ( | |
|
287 | clk: in std_logic; -- system clock | |
|
288 | rst: in std_logic; -- synchronous reset (active-high) | |
|
289 | linki: in spw_link_in_type; | |
|
290 | linko: out spw_link_out_type; | |
|
291 | rxen: out std_logic; | |
|
292 | recvo: in spw_recv_out_type; | |
|
293 | xmiti: out spw_xmit_in_type; | |
|
294 | xmito: in spw_xmit_out_type | |
|
295 | ); | |
|
296 | end component spwlink; | |
|
297 | ||
|
298 | ||
|
299 | -- Receiver | |
|
300 | component spwrecv is | |
|
301 | generic ( | |
|
302 | disconnect_time: integer range 1 to 255; -- disconnect period in system clock cycles | |
|
303 | rxchunk: integer range 1 to 4 -- nr of bits per system clock | |
|
304 | ); | |
|
305 | port ( | |
|
306 | clk: in std_logic; -- system clock | |
|
307 | rxen: in std_logic; -- receiver enabled | |
|
308 | recvo: out spw_recv_out_type; | |
|
309 | inact: in std_logic; | |
|
310 | inbvalid: in std_logic; | |
|
311 | inbits: in std_logic_vector(rxchunk-1 downto 0) | |
|
312 | ); | |
|
313 | end component spwrecv; | |
|
314 | ||
|
315 | ||
|
316 | -- Transmitter (generic implementation) | |
|
317 | component spwxmit is | |
|
318 | port ( | |
|
319 | clk: in std_logic; -- system clock | |
|
320 | rst: in std_logic; -- synchronous reset (active-high) | |
|
321 | divcnt: in std_logic_vector(7 downto 0); | |
|
322 | xmiti: in spw_xmit_in_type; | |
|
323 | xmito: out spw_xmit_out_type; | |
|
324 | spw_do: out std_logic; -- tx data to SPW bus | |
|
325 | spw_so: out std_logic -- tx strobe to SPW bus | |
|
326 | ); | |
|
327 | end component spwxmit; | |
|
328 | ||
|
329 | ||
|
330 | -- Transmitter (separate tx clock domain) | |
|
331 | component spwxmit_fast is | |
|
332 | port ( | |
|
333 | clk: in std_logic; -- system clock | |
|
334 | txclk: in std_logic; -- transmit clock | |
|
335 | rst: in std_logic; -- synchronous reset (active-high) | |
|
336 | divcnt: in std_logic_vector(7 downto 0); | |
|
337 | xmiti: in spw_xmit_in_type; | |
|
338 | xmito: out spw_xmit_out_type; | |
|
339 | spw_do: out std_logic; -- tx data to SPW bus | |
|
340 | spw_so: out std_logic -- tx strobe to SPW bus | |
|
341 | ); | |
|
342 | end component spwxmit_fast; | |
|
343 | ||
|
344 | ||
|
345 | -- Front-end for SpaceWire Receiver (generic implementation) | |
|
346 | component spwrecvfront_generic is | |
|
347 | port ( | |
|
348 | clk: in std_logic; -- system clock | |
|
349 | rxen: in std_logic; -- high to enable receiver | |
|
350 | inact: out std_logic; -- high if activity on input | |
|
351 | inbvalid: out std_logic; -- high if inbits contains a valid received bit | |
|
352 | inbits: out std_logic_vector(0 downto 0); -- received bit | |
|
353 | spw_di: in std_logic; -- Data In signal from SpaceWire bus | |
|
354 | spw_si: in std_logic -- Strobe In signal from SpaceWire bus | |
|
355 | ); | |
|
356 | end component spwrecvfront_generic; | |
|
357 | ||
|
358 | ||
|
359 | -- Front-end for SpaceWire Receiver (separate rx clock domain) | |
|
360 | component spwrecvfront_fast is | |
|
361 | generic ( | |
|
362 | rxchunk: integer range 1 to 4 -- max number of bits per system clock | |
|
363 | ); | |
|
364 | port ( | |
|
365 | clk: in std_logic; -- system clock | |
|
366 | rxclk: in std_logic; -- sample clock (DDR) | |
|
367 | rxen: in std_logic; -- high to enable receiver | |
|
368 | inact: out std_logic; -- high if activity on input | |
|
369 | inbvalid: out std_logic; -- high if inbits contains a valid group of received bits | |
|
370 | inbits: out std_logic_vector(rxchunk-1 downto 0); -- received bits | |
|
371 | spw_di: in std_logic; -- Data In signal from SpaceWire bus | |
|
372 | spw_si: in std_logic -- Strobe In signal from SpaceWire bus | |
|
373 | ); | |
|
374 | end component spwrecvfront_fast; | |
|
375 | ||
|
376 | ||
|
377 | -- Synchronous two-port memory. | |
|
378 | component spwram is | |
|
379 | generic ( | |
|
380 | abits: integer; | |
|
381 | dbits: integer ); | |
|
382 | port ( | |
|
383 | rclk: in std_logic; | |
|
384 | wclk: in std_logic; | |
|
385 | ren: in std_logic; | |
|
386 | raddr: in std_logic_vector(abits-1 downto 0); | |
|
387 | rdata: out std_logic_vector(dbits-1 downto 0); | |
|
388 | wen: in std_logic; | |
|
389 | waddr: in std_logic_vector(abits-1 downto 0); | |
|
390 | wdata: in std_logic_vector(dbits-1 downto 0) ); | |
|
391 | end component spwram; | |
|
392 | ||
|
393 | ||
|
394 | -- Double flip-flop synchronizer. | |
|
395 | component syncdff is | |
|
396 | port ( | |
|
397 | clk: in std_logic; -- clock (destination domain) | |
|
398 | rst: in std_logic; -- asynchronous reset, active-high | |
|
399 | di: in std_logic; -- input data | |
|
400 | do: out std_logic ); -- output data | |
|
401 | end component syncdff; | |
|
402 | ||
|
403 | end package; |
@@ -0,0 +1,58 | |||
|
1 | -- | |
|
2 | -- Synchronous two-port RAM with separate clocks for read and write ports. | |
|
3 | -- The synthesizer for Xilinx Spartan-3 will infer Block RAM for this entity. | |
|
4 | -- | |
|
5 | ||
|
6 | library ieee; | |
|
7 | use ieee.std_logic_1164.all; | |
|
8 | use ieee.numeric_std.all; | |
|
9 | ||
|
10 | entity spwram is | |
|
11 | ||
|
12 | generic ( | |
|
13 | abits: integer; | |
|
14 | dbits: integer ); | |
|
15 | ||
|
16 | port ( | |
|
17 | rclk: in std_logic; | |
|
18 | wclk: in std_logic; | |
|
19 | ren: in std_logic; | |
|
20 | raddr: in std_logic_vector(abits-1 downto 0); | |
|
21 | rdata: out std_logic_vector(dbits-1 downto 0); | |
|
22 | wen: in std_logic; | |
|
23 | waddr: in std_logic_vector(abits-1 downto 0); | |
|
24 | wdata: in std_logic_vector(dbits-1 downto 0) ); | |
|
25 | ||
|
26 | end entity spwram; | |
|
27 | ||
|
28 | architecture spwram_arch of spwram is | |
|
29 | ||
|
30 | type mem_type is array(0 to (2**abits - 1)) of | |
|
31 | std_logic_vector(dbits-1 downto 0); | |
|
32 | ||
|
33 | signal s_mem: mem_type; | |
|
34 | ||
|
35 | begin | |
|
36 | ||
|
37 | -- read process | |
|
38 | process (rclk) is | |
|
39 | begin | |
|
40 | if rising_edge(rclk) then | |
|
41 | if ren = '1' then | |
|
42 | rdata <= s_mem(to_integer(unsigned(raddr))); | |
|
43 | end if; | |
|
44 | end if; | |
|
45 | end process; | |
|
46 | ||
|
47 | -- write process | |
|
48 | process (wclk) is | |
|
49 | begin | |
|
50 | if rising_edge(wclk) then | |
|
51 | if wen = '1' then | |
|
52 | s_mem(to_integer(unsigned(waddr))) <= wdata; | |
|
53 | end if; | |
|
54 | end if; | |
|
55 | end process; | |
|
56 | ||
|
57 | end architecture; | |
|
58 |
@@ -0,0 +1,267 | |||
|
1 | -- | |
|
2 | -- SpaceWire Receiver | |
|
3 | -- | |
|
4 | -- This entity decodes the sequence of incoming data bits into tokens. | |
|
5 | -- Data bits are passed to this entity from the Receiver Front-end | |
|
6 | -- in groups of rxchunk bits at a time. | |
|
7 | -- | |
|
8 | -- The bitrate of the incoming SpaceWire signal must be strictly less | |
|
9 | -- than rxchunk times the system clock frequency. | |
|
10 | -- | |
|
11 | ||
|
12 | library ieee; | |
|
13 | use ieee.std_logic_1164.all, ieee.numeric_std.all; | |
|
14 | use work.spwpkg.all; | |
|
15 | ||
|
16 | entity spwrecv is | |
|
17 | ||
|
18 | generic ( | |
|
19 | -- Disconnect timeout, expressed in system clock cycles. | |
|
20 | -- Should be 850 ns (727 ns .. 1000 ns) according to the standard. | |
|
21 | disconnect_time: integer range 1 to 255; | |
|
22 | ||
|
23 | -- Nr of bits sampled per system clock. | |
|
24 | rxchunk: integer range 1 to 4 | |
|
25 | ); | |
|
26 | ||
|
27 | port ( | |
|
28 | -- System clock. | |
|
29 | clk: in std_logic; | |
|
30 | ||
|
31 | -- High to enable receiver; low to disable and reset receiver. | |
|
32 | rxen: in std_logic; | |
|
33 | ||
|
34 | -- Output signals to spwlink. | |
|
35 | recvo: out spw_recv_out_type; | |
|
36 | ||
|
37 | -- High if there has been recent activity on the input lines. | |
|
38 | inact: in std_logic; | |
|
39 | ||
|
40 | -- High if inbits contains a valid group of received bits. | |
|
41 | inbvalid: in std_logic; | |
|
42 | ||
|
43 | -- Received bits from receiver front-end. | |
|
44 | inbits: in std_logic_vector(rxchunk-1 downto 0) | |
|
45 | ); | |
|
46 | ||
|
47 | end entity spwrecv; | |
|
48 | ||
|
49 | architecture spwrecv_arch of spwrecv is | |
|
50 | ||
|
51 | -- registers | |
|
52 | type regs_type is record | |
|
53 | -- receiver state | |
|
54 | bit_seen: std_ulogic; -- got a bit transition | |
|
55 | null_seen: std_ulogic; -- got a NULL token | |
|
56 | -- input shift register | |
|
57 | bitshift: std_logic_vector(8 downto 0); | |
|
58 | bitcnt: std_logic_vector(9 downto 0); -- one-hot counter | |
|
59 | -- parity flag | |
|
60 | parity: std_ulogic; | |
|
61 | -- decoding | |
|
62 | control: std_ulogic; -- next code is control code | |
|
63 | escaped: std_ulogic; -- last code was ESC | |
|
64 | -- output registers | |
|
65 | gotfct: std_ulogic; | |
|
66 | tick_out: std_ulogic; | |
|
67 | rxchar: std_ulogic; | |
|
68 | rxflag: std_ulogic; | |
|
69 | timereg: std_logic_vector(7 downto 0); | |
|
70 | datareg: std_logic_vector(7 downto 0); | |
|
71 | -- disconnect timer | |
|
72 | disccnt: unsigned(7 downto 0); | |
|
73 | -- error flags | |
|
74 | errpar: std_ulogic; | |
|
75 | erresc: std_ulogic; | |
|
76 | end record; | |
|
77 | ||
|
78 | -- Initial state | |
|
79 | constant regs_reset: regs_type := ( | |
|
80 | bit_seen => '0', | |
|
81 | null_seen => '0', | |
|
82 | bitshift => (others => '1'), | |
|
83 | bitcnt => (others => '0'), | |
|
84 | parity => '0', | |
|
85 | control => '0', | |
|
86 | escaped => '0', | |
|
87 | gotfct => '0', | |
|
88 | tick_out => '0', | |
|
89 | rxchar => '0', | |
|
90 | rxflag => '0', | |
|
91 | timereg => (others => '0'), | |
|
92 | datareg => (others => '0'), | |
|
93 | disccnt => "00000000", | |
|
94 | errpar => '0', | |
|
95 | erresc => '0' ); | |
|
96 | ||
|
97 | -- registers | |
|
98 | signal r: regs_type := regs_reset; | |
|
99 | signal rin: regs_type; | |
|
100 | ||
|
101 | begin | |
|
102 | ||
|
103 | -- combinatorial process | |
|
104 | process (r, rxen, inact, inbvalid, inbits) | |
|
105 | variable v: regs_type; | |
|
106 | variable v_inbit: std_ulogic; | |
|
107 | begin | |
|
108 | v := r; | |
|
109 | v_inbit := '0'; | |
|
110 | ||
|
111 | -- disconnect timer | |
|
112 | if inact = '1' then | |
|
113 | -- activity on input; reset timer | |
|
114 | v.disccnt := to_unsigned(disconnect_time, v.disccnt'length); | |
|
115 | elsif r.disccnt /= 0 then | |
|
116 | -- count down | |
|
117 | v.disccnt := r.disccnt - 1; | |
|
118 | end if; | |
|
119 | ||
|
120 | -- assume no new token | |
|
121 | v.gotfct := '0'; | |
|
122 | v.tick_out := '0'; | |
|
123 | v.rxchar := '0'; | |
|
124 | ||
|
125 | if inbvalid = '1' then | |
|
126 | ||
|
127 | -- process incoming bits | |
|
128 | for i in 0 to rxchunk-1 loop | |
|
129 | v_inbit := inbits(i); | |
|
130 | ||
|
131 | -- got a bit transition | |
|
132 | v.bit_seen := '1'; | |
|
133 | ||
|
134 | if v.bitcnt(0) = '1' then | |
|
135 | -- received new token | |
|
136 | -- note that this will not happen before null_seen='1' | |
|
137 | if (v.parity xor v_inbit) = '0' then | |
|
138 | -- Parity check failed. | |
|
139 | v.errpar := '1'; | |
|
140 | else | |
|
141 | if v.control = '1' then | |
|
142 | -- received control code | |
|
143 | case v.bitshift(7 downto 6) is | |
|
144 | when "00" => -- FCT or NULL | |
|
145 | v.gotfct := not r.escaped; | |
|
146 | v.escaped := '0'; | |
|
147 | when "10" => -- EOP | |
|
148 | if r.escaped = '1' then | |
|
149 | v.erresc := '1'; | |
|
150 | end if; | |
|
151 | v.escaped := '0'; | |
|
152 | v.rxchar := not r.escaped; | |
|
153 | v.rxflag := '1'; | |
|
154 | v.datareg := "00000000"; | |
|
155 | when "01" => -- EEP | |
|
156 | if r.escaped = '1' then | |
|
157 | v.erresc := '1'; | |
|
158 | end if; | |
|
159 | v.escaped := '0'; | |
|
160 | v.rxchar := not r.escaped; | |
|
161 | v.rxflag := '1'; | |
|
162 | v.datareg := "00000001"; | |
|
163 | when others => -- ESC | |
|
164 | if r.escaped = '1' then | |
|
165 | v.erresc := '1'; | |
|
166 | end if; | |
|
167 | v.escaped := '1'; | |
|
168 | end case; | |
|
169 | else | |
|
170 | -- received 8-bit character | |
|
171 | if r.escaped = '1' then | |
|
172 | -- received Time-Code | |
|
173 | v.tick_out := '1'; | |
|
174 | v.timereg := v.bitshift(7 downto 0); | |
|
175 | else | |
|
176 | -- received data character | |
|
177 | v.rxflag := '0'; | |
|
178 | v.rxchar := '1'; | |
|
179 | v.datareg := v.bitshift(7 downto 0); | |
|
180 | end if; | |
|
181 | v.escaped := '0'; | |
|
182 | end if; | |
|
183 | end if; | |
|
184 | -- prepare for next code | |
|
185 | v.parity := '0'; | |
|
186 | v.control := v_inbit; | |
|
187 | if v_inbit = '1' then | |
|
188 | -- next word will be control code. | |
|
189 | v.bitcnt := (3 => '1', others => '0'); | |
|
190 | else | |
|
191 | -- next word will be a data byte. | |
|
192 | v.bitcnt := (9 => '1', others => '0'); | |
|
193 | end if; | |
|
194 | else | |
|
195 | -- wait until next code is completely received; | |
|
196 | -- accumulate parity | |
|
197 | v.bitcnt := '0' & v.bitcnt(9 downto 1); | |
|
198 | v.parity := v.parity xor v_inbit; | |
|
199 | end if; | |
|
200 | ||
|
201 | -- detect first NULL | |
|
202 | if v.null_seen = '0' then | |
|
203 | if v.bitshift = "000101110" then | |
|
204 | -- got first NULL pattern | |
|
205 | v.null_seen := '1'; | |
|
206 | v.control := v_inbit; -- should always be '1' | |
|
207 | v.parity := '0'; | |
|
208 | v.bitcnt := (3 => '1', others => '0'); | |
|
209 | end if; | |
|
210 | end if; | |
|
211 | ||
|
212 | -- shift new bit into register. | |
|
213 | v.bitshift := v_inbit & v.bitshift(v.bitshift'high downto 1); | |
|
214 | ||
|
215 | end loop; | |
|
216 | end if; | |
|
217 | ||
|
218 | -- synchronous reset | |
|
219 | if rxen = '0' then | |
|
220 | v.bit_seen := '0'; | |
|
221 | v.null_seen := '0'; | |
|
222 | v.bitshift := "111111111"; | |
|
223 | v.bitcnt := (others => '0'); | |
|
224 | v.gotfct := '0'; | |
|
225 | v.tick_out := '0'; | |
|
226 | v.rxchar := '0'; | |
|
227 | v.rxflag := '0'; | |
|
228 | v.escaped := '0'; | |
|
229 | v.timereg := "00000000"; | |
|
230 | v.datareg := "00000000"; | |
|
231 | v.disccnt := to_unsigned(0, v.disccnt'length); | |
|
232 | v.errpar := '0'; | |
|
233 | v.erresc := '0'; | |
|
234 | end if; | |
|
235 | ||
|
236 | -- drive outputs | |
|
237 | recvo.gotbit <= r.bit_seen; | |
|
238 | recvo.gotnull <= r.null_seen; | |
|
239 | recvo.gotfct <= r.gotfct; | |
|
240 | recvo.tick_out <= r.tick_out; | |
|
241 | recvo.ctrl_out <= r.timereg(7 downto 6); | |
|
242 | recvo.time_out <= r.timereg(5 downto 0); | |
|
243 | recvo.rxchar <= r.rxchar; | |
|
244 | recvo.rxflag <= r.rxflag; | |
|
245 | recvo.rxdata <= r.datareg; | |
|
246 | if r.bit_seen = '1' and r.disccnt = 0 then | |
|
247 | recvo.errdisc <= '1'; | |
|
248 | else | |
|
249 | recvo.errdisc <= '0'; | |
|
250 | end if; | |
|
251 | recvo.errpar <= r.errpar; | |
|
252 | recvo.erresc <= r.erresc; | |
|
253 | ||
|
254 | -- update registers | |
|
255 | rin <= v; | |
|
256 | ||
|
257 | end process; | |
|
258 | ||
|
259 | -- update registers on rising edge of system clock | |
|
260 | process (clk) is | |
|
261 | begin | |
|
262 | if rising_edge(clk) then | |
|
263 | r <= rin; | |
|
264 | end if; | |
|
265 | end process; | |
|
266 | ||
|
267 | end architecture spwrecv_arch; |
@@ -0,0 +1,424 | |||
|
1 | -- | |
|
2 | -- Front-end for SpaceWire Receiver | |
|
3 | -- | |
|
4 | -- This entity samples the input signals DataIn and StrobeIn to detect | |
|
5 | -- valid bit transitions. Received bits are handed to the application | |
|
6 | -- in groups of "rxchunk" bits at a time, synchronous to the system clock. | |
|
7 | -- | |
|
8 | -- This receiver is based on synchronous oversampling of the input signals. | |
|
9 | -- Inputs are sampled on the rising and falling edges of an externally | |
|
10 | -- supplied sample clock "rxclk". Therefore the maximum bitrate of the | |
|
11 | -- incoming signal must be significantly lower than two times the "rxclk" | |
|
12 | -- clock frequency. The maximum incoming bitrate must also be strictly | |
|
13 | -- lower than rxchunk times the system clock frequency. | |
|
14 | -- | |
|
15 | -- This code is tuned for implementation on Xilinx Spartan-3. | |
|
16 | -- | |
|
17 | -- Details | |
|
18 | -- ------- | |
|
19 | -- | |
|
20 | -- Stage A: The inputs "spw_di" and "spw_si" are handled as DDR signals, | |
|
21 | -- synchronously sampled on both edges of "rxclk". | |
|
22 | -- | |
|
23 | -- Stage B: The input signals are re-registered on the rising edge of "rxclk" | |
|
24 | -- for further processing. This implies that every rising edge of "rxclk" | |
|
25 | -- produces two new samples of "spw_di" and two new samples of "spw_si". | |
|
26 | -- | |
|
27 | -- Stage C: Transitions in input signals are detected by comparing the XOR | |
|
28 | -- of data and strobe to the XOR of the previous data and strobe samples. | |
|
29 | -- If there is a difference, we know that either data or strobe has changed | |
|
30 | -- and the new value of data is a valid new bit. Every rising edge of "rxclk" | |
|
31 | -- thus produces either zero, or one or two new data bits. | |
|
32 | -- | |
|
33 | -- Stage D: Received bits are collected in groups of "rxchunk" bits | |
|
34 | -- (unless rxchunk=1, in which case groups of 2 bits are used). Complete | |
|
35 | -- groups are pushed into an 8-deep cyclic buffer. A 3-bit counter "headptr" | |
|
36 | -- indicates the current position in the cyclic buffer. | |
|
37 | -- | |
|
38 | -- The system clock domain reads bit groups from the cyclic buffer. A tail | |
|
39 | -- pointer indicates the next location to read from the buffer. A comparison | |
|
40 | -- between the "tailptr" and a re-synchronized copy of the "headptr" determines | |
|
41 | -- whether valid bits are available in the buffer. | |
|
42 | -- | |
|
43 | -- Activity detection is based on a 3-bit counter "bitcnt". This counter is | |
|
44 | -- incremented whenever the rxclk domain receives 1 or 2 new bits. The system | |
|
45 | -- clock domain monitors a re-synchronized copy of the activity counter to | |
|
46 | -- determine whether it has been updated since the previous system clock cycle. | |
|
47 | -- | |
|
48 | -- Implementation guidelines | |
|
49 | -- ------------------------- | |
|
50 | -- | |
|
51 | -- IOB flip-flops must be used to sample spw_di and spw_si. | |
|
52 | -- Clock skew between the IOBs for spw_di and spw_si must be minimized. | |
|
53 | -- | |
|
54 | -- "rxclk" must be at least as fast as the system clock; | |
|
55 | -- "rxclk" does not need to be phase-related to the system clock; | |
|
56 | -- it is allowed for "rxclk" to be equal to the system clock. | |
|
57 | -- | |
|
58 | -- The following timing constraints are needed: | |
|
59 | -- * PERIOD constraint on the system clock; | |
|
60 | -- * PERIOD constraint on "rxclk"; | |
|
61 | -- * FROM-TO constraint from "rxclk" to system clock, equal to one "rxclk" period; | |
|
62 | -- * FROM-TO constraint from system clock to "rxclk", equal to one "rxclk" period. | |
|
63 | -- | |
|
64 | ||
|
65 | library ieee; | |
|
66 | use ieee.std_logic_1164.all; | |
|
67 | use ieee.numeric_std.all; | |
|
68 | use work.spwpkg.all; | |
|
69 | ||
|
70 | entity spwrecvfront_fast is | |
|
71 | ||
|
72 | generic ( | |
|
73 | -- Number of bits to pass to the application per system clock. | |
|
74 | rxchunk: integer range 1 to 4 ); | |
|
75 | ||
|
76 | port ( | |
|
77 | -- System clock. | |
|
78 | clk: in std_logic; | |
|
79 | ||
|
80 | -- Sample clock. | |
|
81 | rxclk: in std_logic; | |
|
82 | ||
|
83 | -- High to enable receiver; low to disable and reset receiver. | |
|
84 | rxen: in std_logic; | |
|
85 | ||
|
86 | -- High if there has been recent activity on the input lines. | |
|
87 | inact: out std_logic; | |
|
88 | ||
|
89 | -- High if inbits contains a valid group of received bits. | |
|
90 | -- If inbvalid='1', the application must sample inbits on | |
|
91 | -- the rising edge of clk. | |
|
92 | inbvalid: out std_logic; | |
|
93 | ||
|
94 | -- Received bits (bit 0 is the earliest received bit). | |
|
95 | inbits: out std_logic_vector(rxchunk-1 downto 0); | |
|
96 | ||
|
97 | -- Data In signal from SpaceWire bus. | |
|
98 | spw_di: in std_logic; | |
|
99 | ||
|
100 | -- Strobe In signal from SpaceWire bus. | |
|
101 | spw_si: in std_logic ); | |
|
102 | ||
|
103 | -- Turn off FSM extraction. | |
|
104 | -- Without this, XST will happily apply one-hot encoding to rrx.headptr. | |
|
105 | attribute FSM_EXTRACT: string; | |
|
106 | attribute FSM_EXTRACT of spwrecvfront_fast: entity is "NO"; | |
|
107 | ||
|
108 | end entity spwrecvfront_fast; | |
|
109 | ||
|
110 | architecture spwrecvfront_arch of spwrecvfront_fast is | |
|
111 | ||
|
112 | -- width of bit groups in cyclic buffer; | |
|
113 | -- typically equal to rxchunk, except when rxchunk = 1 | |
|
114 | type memwidth_array_type is array(1 to 4) of integer; | |
|
115 | constant chunk_to_memwidth: memwidth_array_type := ( 2, 2, 3, 4 ); | |
|
116 | constant memwidth: integer := chunk_to_memwidth(rxchunk); | |
|
117 | ||
|
118 | -- registers in rxclk domain | |
|
119 | type rxregs_type is record | |
|
120 | -- stage B: re-register input samples | |
|
121 | b_di0: std_ulogic; | |
|
122 | b_si0: std_ulogic; | |
|
123 | b_di1: std_ulogic; | |
|
124 | b_si1: std_ulogic; | |
|
125 | -- stage C: data/strobe decoding | |
|
126 | c_bit: std_logic_vector(1 downto 0); | |
|
127 | c_val: std_logic_vector(1 downto 0); | |
|
128 | c_xor1: std_ulogic; | |
|
129 | -- stage D: collect groups of memwidth bits | |
|
130 | d_shift: std_logic_vector(memwidth-1 downto 0); | |
|
131 | d_count: std_logic_vector(memwidth-1 downto 0); | |
|
132 | -- cyclic buffer access | |
|
133 | bufdata: std_logic_vector(memwidth-1 downto 0); | |
|
134 | bufwrite: std_ulogic; | |
|
135 | headptr: std_logic_vector(2 downto 0); | |
|
136 | -- activity detection | |
|
137 | bitcnt: std_logic_vector(2 downto 0); | |
|
138 | end record; | |
|
139 | ||
|
140 | -- registers in system clock domain | |
|
141 | type regs_type is record | |
|
142 | -- data path from buffer to output | |
|
143 | tailptr: std_logic_vector(2 downto 0); | |
|
144 | inbvalid: std_ulogic; | |
|
145 | -- split 2-bit groups if rxchunk=1 | |
|
146 | splitbit: std_ulogic; | |
|
147 | splitinx: std_ulogic; | |
|
148 | splitvalid: std_ulogic; | |
|
149 | -- activity detection | |
|
150 | bitcntp: std_logic_vector(2 downto 0); | |
|
151 | inact: std_ulogic; | |
|
152 | -- reset signal towards rxclk domain | |
|
153 | rxdis: std_ulogic; | |
|
154 | end record; | |
|
155 | ||
|
156 | constant regs_reset: regs_type := ( | |
|
157 | tailptr => "000", | |
|
158 | inbvalid => '0', | |
|
159 | splitbit => '0', | |
|
160 | splitinx => '0', | |
|
161 | splitvalid => '0', | |
|
162 | bitcntp => "000", | |
|
163 | inact => '0', | |
|
164 | rxdis => '1' ); | |
|
165 | ||
|
166 | -- Signals that are re-synchronized from rxclk to system clock domain. | |
|
167 | type syncsys_type is record | |
|
168 | headptr: std_logic_vector(2 downto 0); -- pointer in cyclic buffer | |
|
169 | bitcnt: std_logic_vector(2 downto 0); -- activity detection | |
|
170 | end record; | |
|
171 | ||
|
172 | -- Registers. | |
|
173 | signal r: regs_type := regs_reset; | |
|
174 | signal rin: regs_type; | |
|
175 | signal rrx, rrxin: rxregs_type; | |
|
176 | ||
|
177 | -- Synchronized signals after crossing clock domains. | |
|
178 | signal syncrx_rstn: std_logic; | |
|
179 | signal syncsys: syncsys_type; | |
|
180 | ||
|
181 | -- Output data from cyclic buffer. | |
|
182 | signal s_bufdout: std_logic_vector(memwidth-1 downto 0); | |
|
183 | ||
|
184 | -- stage A: input flip-flops for rising/falling rxclk | |
|
185 | signal s_a_di0: std_logic; | |
|
186 | signal s_a_si0: std_logic; | |
|
187 | signal s_a_di1: std_logic; | |
|
188 | signal s_a_si1: std_logic; | |
|
189 | signal s_a_di2: std_logic; | |
|
190 | signal s_a_si2: std_logic; | |
|
191 | ||
|
192 | -- force use of IOB flip-flops | |
|
193 | attribute IOB: string; | |
|
194 | attribute IOB of s_a_di1: signal is "TRUE"; | |
|
195 | attribute IOB of s_a_si1: signal is "TRUE"; | |
|
196 | attribute IOB of s_a_di2: signal is "TRUE"; | |
|
197 | attribute IOB of s_a_si2: signal is "TRUE"; | |
|
198 | ||
|
199 | begin | |
|
200 | ||
|
201 | -- Cyclic data buffer. | |
|
202 | bufmem: spwram | |
|
203 | generic map ( | |
|
204 | abits => 3, | |
|
205 | dbits => memwidth ) | |
|
206 | port map ( | |
|
207 | rclk => clk, | |
|
208 | wclk => rxclk, | |
|
209 | ren => '1', | |
|
210 | raddr => r.tailptr, | |
|
211 | rdata => s_bufdout, | |
|
212 | wen => rrx.bufwrite, | |
|
213 | waddr => rrx.headptr, | |
|
214 | wdata => rrx.bufdata ); | |
|
215 | ||
|
216 | -- Synchronize reset signal for rxclk domain. | |
|
217 | syncrx_reset: syncdff | |
|
218 | port map ( clk => rxclk, rst => r.rxdis, di => '1', do => syncrx_rstn ); | |
|
219 | ||
|
220 | -- Synchronize signals from rxclk domain to system clock domain. | |
|
221 | syncsys_headptr0: syncdff | |
|
222 | port map ( clk => clk, rst => r.rxdis, di => rrx.headptr(0), do => syncsys.headptr(0) ); | |
|
223 | syncsys_headptr1: syncdff | |
|
224 | port map ( clk => clk, rst => r.rxdis, di => rrx.headptr(1), do => syncsys.headptr(1) ); | |
|
225 | syncsys_headptr2: syncdff | |
|
226 | port map ( clk => clk, rst => r.rxdis, di => rrx.headptr(2), do => syncsys.headptr(2) ); | |
|
227 | syncsys_bitcnt0: syncdff | |
|
228 | port map ( clk => clk, rst => r.rxdis, di => rrx.bitcnt(0), do => syncsys.bitcnt(0) ); | |
|
229 | syncsys_bitcnt1: syncdff | |
|
230 | port map ( clk => clk, rst => r.rxdis, di => rrx.bitcnt(1), do => syncsys.bitcnt(1) ); | |
|
231 | syncsys_bitcnt2: syncdff | |
|
232 | port map ( clk => clk, rst => r.rxdis, di => rrx.bitcnt(2), do => syncsys.bitcnt(2) ); | |
|
233 | ||
|
234 | -- sample inputs on rising edge of rxclk | |
|
235 | process (rxclk) is | |
|
236 | begin | |
|
237 | if rising_edge(rxclk) then | |
|
238 | s_a_di1 <= spw_di; | |
|
239 | s_a_si1 <= spw_si; | |
|
240 | end if; | |
|
241 | end process; | |
|
242 | ||
|
243 | -- sample inputs on falling edge of rxclk | |
|
244 | process (rxclk) is | |
|
245 | begin | |
|
246 | if falling_edge(rxclk) then | |
|
247 | s_a_di2 <= spw_di; | |
|
248 | s_a_si2 <= spw_si; | |
|
249 | -- reregister inputs in fabric flip-flops | |
|
250 | s_a_di0 <= s_a_di2; | |
|
251 | s_a_si0 <= s_a_si2; | |
|
252 | end if; | |
|
253 | end process; | |
|
254 | ||
|
255 | -- combinatorial process | |
|
256 | process (r, rrx, rxen, syncrx_rstn, syncsys, s_bufdout, s_a_di0, s_a_si0, s_a_di1, s_a_si1) | |
|
257 | variable v: regs_type; | |
|
258 | variable vrx: rxregs_type; | |
|
259 | begin | |
|
260 | v := r; | |
|
261 | vrx := rrx; | |
|
262 | ||
|
263 | -- ---- SAMPLE CLOCK DOMAIN ---- | |
|
264 | ||
|
265 | -- stage B: re-register input samples | |
|
266 | vrx.b_di0 := s_a_di0; | |
|
267 | vrx.b_si0 := s_a_si0; | |
|
268 | vrx.b_di1 := s_a_di1; | |
|
269 | vrx.b_si1 := s_a_si1; | |
|
270 | ||
|
271 | -- stage C: decode data/strobe and detect valid bits | |
|
272 | if (rrx.b_di0 xor rrx.b_si0 xor rrx.c_xor1) = '1' then | |
|
273 | vrx.c_bit(0) := rrx.b_di0; | |
|
274 | else | |
|
275 | vrx.c_bit(0) := rrx.b_di1; | |
|
276 | end if; | |
|
277 | vrx.c_bit(1) := rrx.b_di1; | |
|
278 | vrx.c_val(0) := (rrx.b_di0 xor rrx.b_si0 xor rrx.c_xor1) or | |
|
279 | (rrx.b_di0 xor rrx.b_si0 xor rrx.b_di1 xor rrx.b_si1); | |
|
280 | vrx.c_val(1) := (rrx.b_di0 xor rrx.b_si0 xor rrx.c_xor1) and | |
|
281 | (rrx.b_di0 xor rrx.b_si0 xor rrx.b_di1 xor rrx.b_si1); | |
|
282 | vrx.c_xor1 := rrx.b_di1 xor rrx.b_si1; | |
|
283 | ||
|
284 | -- Note: | |
|
285 | -- c_val = "00" if no new bits are received | |
|
286 | -- c_val = "01" if one new bit is received; the new bit is in c_bit(0) | |
|
287 | -- c_val = "11" if two new bits are received | |
|
288 | ||
|
289 | -- stage D: collect groups of memwidth bits | |
|
290 | if rrx.c_val(0) = '1' then | |
|
291 | ||
|
292 | -- shift incoming bits into register | |
|
293 | if rrx.c_val(1) = '1' then | |
|
294 | vrx.d_shift := rrx.c_bit & rrx.d_shift(memwidth-1 downto 2); | |
|
295 | else | |
|
296 | vrx.d_shift := rrx.c_bit(0) & rrx.d_shift(memwidth-1 downto 1); | |
|
297 | end if; | |
|
298 | ||
|
299 | -- prepare to store a group of memwidth bits | |
|
300 | if rrx.d_count(0) = '1' then | |
|
301 | -- only one more bit needed | |
|
302 | vrx.bufdata := rrx.c_bit(0) & rrx.d_shift(memwidth-1 downto 1); | |
|
303 | else | |
|
304 | vrx.bufdata := rrx.c_bit & rrx.d_shift(memwidth-1 downto 2); | |
|
305 | end if; | |
|
306 | ||
|
307 | -- countdown nr of needed bits (one-hot counter) | |
|
308 | if rrx.c_val(1) = '1' then | |
|
309 | vrx.d_count := rrx.d_count(1 downto 0) & rrx.d_count(memwidth-1 downto 2); | |
|
310 | else | |
|
311 | vrx.d_count := rrx.d_count(0 downto 0) & rrx.d_count(memwidth-1 downto 1); | |
|
312 | end if; | |
|
313 | ||
|
314 | end if; | |
|
315 | ||
|
316 | -- stage D: store groups of memwidth bits | |
|
317 | vrx.bufwrite := rrx.c_val(0) and (rrx.d_count(0) or (rrx.c_val(1) and rrx.d_count(1))); | |
|
318 | ||
|
319 | -- Increment head pointer. | |
|
320 | if rrx.bufwrite = '1' then | |
|
321 | vrx.headptr := std_logic_vector(unsigned(rrx.headptr) + 1); | |
|
322 | end if; | |
|
323 | ||
|
324 | -- Activity detection. | |
|
325 | if rrx.c_val(0) = '1' then | |
|
326 | vrx.bitcnt := std_logic_vector(unsigned(rrx.bitcnt) + 1); | |
|
327 | end if; | |
|
328 | ||
|
329 | -- Synchronous reset of rxclk domain. | |
|
330 | if syncrx_rstn = '0' then | |
|
331 | vrx.c_val := "00"; | |
|
332 | vrx.c_xor1 := '0'; | |
|
333 | vrx.d_count := (others => '0'); | |
|
334 | vrx.d_count(memwidth-1) := '1'; | |
|
335 | vrx.bufwrite := '0'; | |
|
336 | vrx.headptr := "000"; | |
|
337 | vrx.bitcnt := "000"; | |
|
338 | end if; | |
|
339 | ||
|
340 | -- ---- SYSTEM CLOCK DOMAIN ---- | |
|
341 | ||
|
342 | -- Compare tailptr to headptr to decide whether there is new data. | |
|
343 | -- If the values are equal, we are about to read a location which has | |
|
344 | -- not yet been written by the rxclk domain. | |
|
345 | if r.tailptr = syncsys.headptr then | |
|
346 | -- No more data in cyclic buffer. | |
|
347 | v.inbvalid := '0'; | |
|
348 | else | |
|
349 | -- Reading valid data from cyclic buffer. | |
|
350 | v.inbvalid := '1'; | |
|
351 | -- Increment tail pointer. | |
|
352 | if rxchunk /= 1 then | |
|
353 | v.tailptr := std_logic_vector(unsigned(r.tailptr) + 1); | |
|
354 | end if; | |
|
355 | end if; | |
|
356 | ||
|
357 | -- If rxchunk=1, split 2-bit groups into separate bits. | |
|
358 | if rxchunk = 1 then | |
|
359 | -- Select one of the two bits. | |
|
360 | if r.splitinx = '0' then | |
|
361 | v.splitbit := s_bufdout(0); | |
|
362 | else | |
|
363 | v.splitbit := s_bufdout(1); | |
|
364 | end if; | |
|
365 | -- Indicate valid bit. | |
|
366 | v.splitvalid := r.inbvalid; | |
|
367 | -- Increment tail pointer. | |
|
368 | if r.inbvalid = '1' then | |
|
369 | v.splitinx := not r.splitinx; | |
|
370 | if r.splitinx = '0' then | |
|
371 | v.tailptr := std_logic_vector(unsigned(r.tailptr) + 1); | |
|
372 | end if; | |
|
373 | end if; | |
|
374 | end if; | |
|
375 | ||
|
376 | -- Activity detection. | |
|
377 | v.bitcntp := syncsys.bitcnt; | |
|
378 | if r.bitcntp = syncsys.bitcnt then | |
|
379 | v.inact := '0'; | |
|
380 | else | |
|
381 | v.inact := '1'; | |
|
382 | end if; | |
|
383 | ||
|
384 | -- Synchronous reset of system clock domain. | |
|
385 | if rxen = '0' then | |
|
386 | v := regs_reset; | |
|
387 | end if; | |
|
388 | ||
|
389 | -- Register rxen to ensure glitch-free signal to rxclk domain | |
|
390 | v.rxdis := not rxen; | |
|
391 | ||
|
392 | -- drive outputs | |
|
393 | inact <= r.inact; | |
|
394 | if rxchunk = 1 then | |
|
395 | inbvalid <= r.splitvalid; | |
|
396 | inbits(0) <= r.splitbit; | |
|
397 | else | |
|
398 | inbvalid <= r.inbvalid; | |
|
399 | inbits <= s_bufdout; | |
|
400 | end if; | |
|
401 | ||
|
402 | -- update registers | |
|
403 | rrxin <= vrx; | |
|
404 | rin <= v; | |
|
405 | ||
|
406 | end process; | |
|
407 | ||
|
408 | -- update registers on rising edge of rxclk | |
|
409 | process (rxclk) is | |
|
410 | begin | |
|
411 | if rising_edge(rxclk) then | |
|
412 | rrx <= rrxin; | |
|
413 | end if; | |
|
414 | end process; | |
|
415 | ||
|
416 | -- update registers on rising edge of system clock | |
|
417 | process (clk) is | |
|
418 | begin | |
|
419 | if rising_edge(clk) then | |
|
420 | r <= rin; | |
|
421 | end if; | |
|
422 | end process; | |
|
423 | ||
|
424 | end architecture spwrecvfront_arch; |
@@ -0,0 +1,96 | |||
|
1 | -- | |
|
2 | -- Front-end for SpaceWire Receiver | |
|
3 | -- | |
|
4 | -- This entity samples the input signals DataIn and StrobeIn to detect | |
|
5 | -- valid bit transitions. Received bits are handed to the application. | |
|
6 | -- | |
|
7 | -- Inputs are sampled on the rising edge of the system clock, therefore | |
|
8 | -- the maximum bitrate of the incoming signal must be significantly lower | |
|
9 | -- than system clock frequency. | |
|
10 | -- | |
|
11 | ||
|
12 | library ieee; | |
|
13 | use ieee.std_logic_1164.all; | |
|
14 | use ieee.numeric_std.all; | |
|
15 | ||
|
16 | entity spwrecvfront_generic is | |
|
17 | ||
|
18 | port ( | |
|
19 | -- System clock. | |
|
20 | clk: in std_logic; | |
|
21 | ||
|
22 | -- High to enable receiver; low to disable and reset receiver. | |
|
23 | rxen: in std_logic; | |
|
24 | ||
|
25 | -- High if there has been recent activity on the input lines. | |
|
26 | inact: out std_logic; | |
|
27 | ||
|
28 | -- High if inbits contains a valid received bit. | |
|
29 | -- If inbvalid='1', the application must sample inbits on | |
|
30 | -- the rising edge of clk. | |
|
31 | inbvalid: out std_logic; | |
|
32 | ||
|
33 | -- Received bit | |
|
34 | inbits: out std_logic_vector(0 downto 0); | |
|
35 | ||
|
36 | -- Data In signal from SpaceWire bus. | |
|
37 | spw_di: in std_logic; | |
|
38 | ||
|
39 | -- Strobe In signal from SpaceWire bus. | |
|
40 | spw_si: in std_logic ); | |
|
41 | ||
|
42 | end entity spwrecvfront_generic; | |
|
43 | ||
|
44 | architecture spwrecvfront_arch of spwrecvfront_generic is | |
|
45 | ||
|
46 | -- input flip-flops | |
|
47 | signal s_spwdi1: std_ulogic; | |
|
48 | signal s_spwsi1: std_ulogic; | |
|
49 | signal s_spwdi2: std_ulogic; | |
|
50 | signal s_spwsi2: std_ulogic; | |
|
51 | ||
|
52 | -- data/strobe decoding | |
|
53 | signal s_spwsi3: std_ulogic; | |
|
54 | ||
|
55 | -- output registers | |
|
56 | signal s_inbvalid: std_ulogic; | |
|
57 | signal s_inbit: std_ulogic; | |
|
58 | ||
|
59 | begin | |
|
60 | ||
|
61 | -- drive outputs | |
|
62 | inact <= s_inbvalid; | |
|
63 | inbvalid <= s_inbvalid; | |
|
64 | inbits(0) <= s_inbit; | |
|
65 | ||
|
66 | -- synchronous process | |
|
67 | process (clk) is | |
|
68 | begin | |
|
69 | if rising_edge(clk) then | |
|
70 | ||
|
71 | -- sample input signal | |
|
72 | s_spwdi1 <= spw_di; | |
|
73 | s_spwsi1 <= spw_si; | |
|
74 | ||
|
75 | -- more flip-flops for safe synchronization | |
|
76 | s_spwdi2 <= s_spwdi1; | |
|
77 | s_spwsi2 <= s_spwsi1; | |
|
78 | ||
|
79 | -- keep strobe signal for data/strobe decoding | |
|
80 | s_spwsi3 <= s_spwsi2; | |
|
81 | ||
|
82 | -- keep data bit for data/strobe decoding | |
|
83 | s_inbit <= s_spwdi2; | |
|
84 | ||
|
85 | if rxen = '1' then | |
|
86 | -- data/strobe decoding | |
|
87 | s_inbvalid <= s_spwdi2 xor s_spwsi2 xor s_inbit xor s_spwsi3; | |
|
88 | else | |
|
89 | -- reset receiver | |
|
90 | s_inbvalid <= '0'; | |
|
91 | end if; | |
|
92 | ||
|
93 | end if; | |
|
94 | end process; | |
|
95 | ||
|
96 | end architecture spwrecvfront_arch; |
This diff has been collapsed as it changes many lines, (547 lines changed) Show them Hide them | |||
@@ -0,0 +1,547 | |||
|
1 | -- | |
|
2 | -- SpaceWire core with character-stream interface. | |
|
3 | -- | |
|
4 | -- This entity provides a SpaceWire core with a character-stream interface. | |
|
5 | -- The interface provides means for connection initiation, sending and | |
|
6 | -- receiving of N-Chars and TimeCodes, and error reporting. | |
|
7 | -- | |
|
8 | -- This entity instantiates spwlink, spwrecv, spwxmit and one of the | |
|
9 | -- spwrecvfront implementations. It also implements a receive FIFO and | |
|
10 | -- a transmit FIFO. | |
|
11 | -- | |
|
12 | -- The SpaceWire standard requires that each transceiver use an initial | |
|
13 | -- signalling rate of 10 Mbit/s. This implies that the system clock frequency | |
|
14 | -- must be a multiple of 10 MHz. See the manual for further details on | |
|
15 | -- bitrates and clocking. | |
|
16 | -- | |
|
17 | ||
|
18 | library ieee; | |
|
19 | use ieee.std_logic_1164.all; | |
|
20 | use ieee.numeric_std.all; | |
|
21 | use work.spwpkg.all; | |
|
22 | ||
|
23 | entity spwstream is | |
|
24 | ||
|
25 | generic ( | |
|
26 | -- System clock frequency in Hz. | |
|
27 | -- This must be set to the frequency of "clk". It is used to setup | |
|
28 | -- counters for reset timing, disconnect timeout and to transmit | |
|
29 | -- at 10 Mbit/s during the link handshake. | |
|
30 | sysfreq: real; | |
|
31 | ||
|
32 | -- Transmit clock frequency in Hz (only if tximpl = impl_fast). | |
|
33 | -- This must be set to the frequency of "txclk". It is used to | |
|
34 | -- transmit at 10 Mbit/s during the link handshake. | |
|
35 | txclkfreq: real := 0.0; | |
|
36 | ||
|
37 | -- Selection of a receiver front-end implementation. | |
|
38 | rximpl: spw_implementation_type := impl_generic; | |
|
39 | ||
|
40 | -- Maximum number of bits received per system clock | |
|
41 | -- (must be 1 in case of impl_generic). | |
|
42 | rxchunk: integer range 1 to 4 := 1; | |
|
43 | ||
|
44 | -- Selection of a transmitter implementation. | |
|
45 | tximpl: spw_implementation_type := impl_generic; | |
|
46 | ||
|
47 | -- Size of the receive FIFO as the 2-logarithm of the number of bytes. | |
|
48 | -- Must be at least 6 (64 bytes). | |
|
49 | rxfifosize_bits: integer range 6 to 14 := 11; | |
|
50 | ||
|
51 | -- Size of the transmit FIFO as the 2-logarithm of the number of bytes. | |
|
52 | txfifosize_bits: integer range 2 to 14 := 11 | |
|
53 | ); | |
|
54 | ||
|
55 | port ( | |
|
56 | -- System clock. | |
|
57 | clk: in std_logic; | |
|
58 | ||
|
59 | -- Receiver sample clock (only for impl_fast) | |
|
60 | rxclk: in std_logic; | |
|
61 | ||
|
62 | -- Transmit clock (only for impl_fast) | |
|
63 | txclk: in std_logic; | |
|
64 | ||
|
65 | -- Synchronous reset (active-high). | |
|
66 | rst: in std_logic; | |
|
67 | ||
|
68 | -- Enables automatic link start on receipt of a NULL character. | |
|
69 | autostart: in std_logic; | |
|
70 | ||
|
71 | -- Enables link start once the Ready state is reached. | |
|
72 | -- Without autostart or linkstart, the link remains in state Ready. | |
|
73 | linkstart: in std_logic; | |
|
74 | ||
|
75 | -- Do not start link (overrides linkstart and autostart) and/or | |
|
76 | -- disconnect a running link. | |
|
77 | linkdis: in std_logic; | |
|
78 | ||
|
79 | -- Scaling factor minus 1, used to scale the transmit base clock into | |
|
80 | -- the transmission bit rate. The system clock (for impl_generic) or | |
|
81 | -- the txclk (for impl_fast) is divided by (unsigned(txdivcnt) + 1). | |
|
82 | -- Changing this signal will immediately change the transmission rate. | |
|
83 | -- During link setup, the transmission rate is always 10 Mbit/s. | |
|
84 | txdivcnt: in std_logic_vector(7 downto 0); | |
|
85 | ||
|
86 | -- High for one clock cycle to request transmission of a TimeCode. | |
|
87 | -- The request is registered inside the entity until it can be processed. | |
|
88 | tick_in: in std_logic; | |
|
89 | ||
|
90 | -- Control bits of the TimeCode to be sent. Must be valid while tick_in is high. | |
|
91 | ctrl_in: in std_logic_vector(1 downto 0); | |
|
92 | ||
|
93 | -- Counter value of the TimeCode to be sent. Must be valid while tick_in is high. | |
|
94 | time_in: in std_logic_vector(5 downto 0); | |
|
95 | ||
|
96 | -- Pulled high by the application to write an N-Char to the transmit | |
|
97 | -- queue. If "txwrite" and "txrdy" are both high on the rising edge | |
|
98 | -- of "clk", a character is added to the transmit queue. | |
|
99 | -- This signal has no effect if "txrdy" is low. | |
|
100 | txwrite: in std_logic; | |
|
101 | ||
|
102 | -- Control flag to be sent with the next N_Char. | |
|
103 | -- Must be valid while txwrite is high. | |
|
104 | txflag: in std_logic; | |
|
105 | ||
|
106 | -- Byte to be sent, or "00000000" for EOP or "00000001" for EEP. | |
|
107 | -- Must be valid while txwrite is high. | |
|
108 | txdata: in std_logic_vector(7 downto 0); | |
|
109 | ||
|
110 | -- High if the entity is ready to accept an N-Char for transmission. | |
|
111 | txrdy: out std_logic; | |
|
112 | ||
|
113 | -- High if the transmission queue is at least half full. | |
|
114 | txhalff: out std_logic; | |
|
115 | ||
|
116 | -- High for one clock cycle if a TimeCode was just received. | |
|
117 | tick_out: out std_logic; | |
|
118 | ||
|
119 | -- Control bits of the last received TimeCode. | |
|
120 | ctrl_out: out std_logic_vector(1 downto 0); | |
|
121 | ||
|
122 | -- Counter value of the last received TimeCode. | |
|
123 | time_out: out std_logic_vector(5 downto 0); | |
|
124 | ||
|
125 | -- High if "rxflag" and "rxdata" contain valid data. | |
|
126 | -- This signal is high unless the receive FIFO is empty. | |
|
127 | rxvalid: out std_logic; | |
|
128 | ||
|
129 | -- High if the receive FIFO is at least half full. | |
|
130 | rxhalff: out std_logic; | |
|
131 | ||
|
132 | -- High if the received character is EOP or EEP; low if the received | |
|
133 | -- character is a data byte. Valid if "rxvalid" is high. | |
|
134 | rxflag: out std_logic; | |
|
135 | ||
|
136 | -- Received byte, or "00000000" for EOP or "00000001" for EEP. | |
|
137 | -- Valid if "rxvalid" is high. | |
|
138 | rxdata: out std_logic_vector(7 downto 0); | |
|
139 | ||
|
140 | -- Pulled high by the application to accept a received character. | |
|
141 | -- If "rxvalid" and "rxread" are both high on the rising edge of "clk", | |
|
142 | -- a character is removed from the receive FIFO and "rxvalid", "rxflag" | |
|
143 | -- and "rxdata" are updated. | |
|
144 | -- This signal has no effect if "rxvalid" is low. | |
|
145 | rxread: in std_logic; | |
|
146 | ||
|
147 | -- High if the link state machine is currently in the Started state. | |
|
148 | started: out std_logic; | |
|
149 | ||
|
150 | -- High if the link state machine is currently in the Connecting state. | |
|
151 | connecting: out std_logic; | |
|
152 | ||
|
153 | -- High if the link state machine is currently in the Run state, indicating | |
|
154 | -- that the link is fully operational. If none of started, connecting or running | |
|
155 | -- is high, the link is in an initial state and the transmitter is not yet enabled. | |
|
156 | running: out std_logic; | |
|
157 | ||
|
158 | -- Disconnect detected in state Run. Triggers a reset and reconnect of the link. | |
|
159 | -- This indication is auto-clearing. | |
|
160 | errdisc: out std_logic; | |
|
161 | ||
|
162 | -- Parity error detected in state Run. Triggers a reset and reconnect of the link. | |
|
163 | -- This indication is auto-clearing. | |
|
164 | errpar: out std_logic; | |
|
165 | ||
|
166 | -- Invalid escape sequence detected in state Run. Triggers a reset and reconnect of | |
|
167 | -- the link. This indication is auto-clearing. | |
|
168 | erresc: out std_logic; | |
|
169 | ||
|
170 | -- Credit error detected. Triggers a reset and reconnect of the link. | |
|
171 | -- This indication is auto-clearing. | |
|
172 | errcred: out std_logic; | |
|
173 | ||
|
174 | -- Data In signal from SpaceWire bus. | |
|
175 | spw_di: in std_logic; | |
|
176 | ||
|
177 | -- Strobe In signal from SpaceWire bus. | |
|
178 | spw_si: in std_logic; | |
|
179 | ||
|
180 | -- Data Out signal to SpaceWire bus. | |
|
181 | spw_do: out std_logic; | |
|
182 | ||
|
183 | -- Strobe Out signal to SpaceWire bus. | |
|
184 | spw_so: out std_logic | |
|
185 | ); | |
|
186 | ||
|
187 | end entity spwstream; | |
|
188 | ||
|
189 | architecture spwstream_arch of spwstream is | |
|
190 | ||
|
191 | -- Convert boolean to std_logic. | |
|
192 | type bool_to_logic_type is array(boolean) of std_ulogic; | |
|
193 | constant bool_to_logic: bool_to_logic_type := (false => '0', true => '1'); | |
|
194 | ||
|
195 | -- Reset time (6.4 us) in system clocks | |
|
196 | constant reset_time: integer := integer(sysfreq * 6.4e-6); | |
|
197 | ||
|
198 | -- Disconnect time (850 ns) in system clocks | |
|
199 | constant disconnect_time: integer := integer(sysfreq * 850.0e-9); | |
|
200 | ||
|
201 | -- Initial tx clock scaler (10 Mbit). | |
|
202 | type impl_to_real_type is array(spw_implementation_type) of real; | |
|
203 | constant tximpl_to_txclk_freq: impl_to_real_type := | |
|
204 | (impl_generic => sysfreq, impl_fast => txclkfreq); | |
|
205 | constant effective_txclk_freq: real := tximpl_to_txclk_freq(tximpl); | |
|
206 | constant default_divcnt: std_logic_vector(7 downto 0) := | |
|
207 | std_logic_vector(to_unsigned(integer(effective_txclk_freq / 10.0e6 - 1.0), 8)); | |
|
208 | ||
|
209 | -- Registers. | |
|
210 | type regs_type is record | |
|
211 | -- packet state | |
|
212 | rxpacket: std_logic; -- '1' when receiving a packet | |
|
213 | rxeep: std_logic; -- '1' when rx EEP character pending | |
|
214 | txpacket: std_logic; -- '1' when transmitting a packet | |
|
215 | txdiscard: std_logic; -- '1' when discarding a tx packet | |
|
216 | -- FIFO pointers | |
|
217 | rxfifo_raddr: std_logic_vector(rxfifosize_bits-1 downto 0); | |
|
218 | rxfifo_waddr: std_logic_vector(rxfifosize_bits-1 downto 0); | |
|
219 | txfifo_raddr: std_logic_vector(txfifosize_bits-1 downto 0); | |
|
220 | txfifo_waddr: std_logic_vector(txfifosize_bits-1 downto 0); | |
|
221 | -- FIFO state | |
|
222 | rxfifo_rvalid: std_logic; -- '1' if s_rxfifo_rdata is valid | |
|
223 | txfifo_rvalid: std_logic; -- '1' if s_txfifo_rdata is valid | |
|
224 | rxfull: std_logic; -- '1' if RX fifo is full | |
|
225 | rxhalff: std_logic; -- '1' if RX fifo is at least half full | |
|
226 | txfull: std_logic; -- '1' if TX fifo is full | |
|
227 | txhalff: std_logic; -- '1' if TX fifo is at least half full | |
|
228 | rxroom: std_logic_vector(5 downto 0); | |
|
229 | end record; | |
|
230 | ||
|
231 | constant regs_reset: regs_type := ( | |
|
232 | rxpacket => '0', | |
|
233 | rxeep => '0', | |
|
234 | txpacket => '0', | |
|
235 | txdiscard => '0', | |
|
236 | rxfifo_raddr => (others => '0'), | |
|
237 | rxfifo_waddr => (others => '0'), | |
|
238 | txfifo_raddr => (others => '0'), | |
|
239 | txfifo_waddr => (others => '0'), | |
|
240 | rxfifo_rvalid => '0', | |
|
241 | txfifo_rvalid => '0', | |
|
242 | rxfull => '0', | |
|
243 | rxhalff => '0', | |
|
244 | txfull => '0', | |
|
245 | txhalff => '0', | |
|
246 | rxroom => (others => '0') ); | |
|
247 | ||
|
248 | signal r: regs_type := regs_reset; | |
|
249 | signal rin: regs_type; | |
|
250 | ||
|
251 | -- Interface signals to components. | |
|
252 | signal recv_rxen: std_logic; | |
|
253 | signal recvo: spw_recv_out_type; | |
|
254 | signal recv_inact: std_logic; | |
|
255 | signal recv_inbvalid: std_logic; | |
|
256 | signal recv_inbits: std_logic_vector(rxchunk-1 downto 0); | |
|
257 | signal xmiti: spw_xmit_in_type; | |
|
258 | signal xmito: spw_xmit_out_type; | |
|
259 | signal xmit_divcnt: std_logic_vector(7 downto 0); | |
|
260 | signal linki: spw_link_in_type; | |
|
261 | signal linko: spw_link_out_type; | |
|
262 | ||
|
263 | -- Memory interface signals. | |
|
264 | signal s_rxfifo_raddr: std_logic_vector(rxfifosize_bits-1 downto 0); | |
|
265 | signal s_rxfifo_rdata: std_logic_vector(8 downto 0); | |
|
266 | signal s_rxfifo_wen: std_logic; | |
|
267 | signal s_rxfifo_waddr: std_logic_vector(rxfifosize_bits-1 downto 0); | |
|
268 | signal s_rxfifo_wdata: std_logic_vector(8 downto 0); | |
|
269 | signal s_txfifo_raddr: std_logic_vector(txfifosize_bits-1 downto 0); | |
|
270 | signal s_txfifo_rdata: std_logic_vector(8 downto 0); | |
|
271 | signal s_txfifo_wen: std_logic; | |
|
272 | signal s_txfifo_waddr: std_logic_vector(txfifosize_bits-1 downto 0); | |
|
273 | signal s_txfifo_wdata: std_logic_vector(8 downto 0); | |
|
274 | ||
|
275 | begin | |
|
276 | ||
|
277 | -- Instantiate link controller. | |
|
278 | link_inst: spwlink | |
|
279 | generic map ( | |
|
280 | reset_time => reset_time ) | |
|
281 | port map ( | |
|
282 | clk => clk, | |
|
283 | rst => rst, | |
|
284 | linki => linki, | |
|
285 | linko => linko, | |
|
286 | rxen => recv_rxen, | |
|
287 | recvo => recvo, | |
|
288 | xmiti => xmiti, | |
|
289 | xmito => xmito ); | |
|
290 | ||
|
291 | -- Instantiate receiver. | |
|
292 | recv_inst: spwrecv | |
|
293 | generic map( | |
|
294 | disconnect_time => disconnect_time, | |
|
295 | rxchunk => rxchunk ) | |
|
296 | port map ( | |
|
297 | clk => clk, | |
|
298 | rxen => recv_rxen, | |
|
299 | recvo => recvo, | |
|
300 | inact => recv_inact, | |
|
301 | inbvalid => recv_inbvalid, | |
|
302 | inbits => recv_inbits ); | |
|
303 | ||
|
304 | -- Instantiate transmitter. | |
|
305 | xmit_sel0: if tximpl = impl_generic generate | |
|
306 | xmit_inst: spwxmit | |
|
307 | port map ( | |
|
308 | clk => clk, | |
|
309 | rst => rst, | |
|
310 | divcnt => xmit_divcnt, | |
|
311 | xmiti => xmiti, | |
|
312 | xmito => xmito, | |
|
313 | spw_do => spw_do, | |
|
314 | spw_so => spw_so ); | |
|
315 | end generate; | |
|
316 | xmit_sel1: if tximpl = impl_fast generate | |
|
317 | xmit_fast_inst: spwxmit_fast | |
|
318 | port map ( | |
|
319 | clk => clk, | |
|
320 | txclk => txclk, | |
|
321 | rst => rst, | |
|
322 | divcnt => xmit_divcnt, | |
|
323 | xmiti => xmiti, | |
|
324 | xmito => xmito, | |
|
325 | spw_do => spw_do, | |
|
326 | spw_so => spw_so ); | |
|
327 | end generate; | |
|
328 | ||
|
329 | -- Instantiate receiver front-end. | |
|
330 | recvfront_sel0: if rximpl = impl_generic generate | |
|
331 | recvfront_generic_inst: spwrecvfront_generic | |
|
332 | port map ( | |
|
333 | clk => clk, | |
|
334 | rxen => recv_rxen, | |
|
335 | inact => recv_inact, | |
|
336 | inbvalid => recv_inbvalid, | |
|
337 | inbits => recv_inbits, | |
|
338 | spw_di => spw_di, | |
|
339 | spw_si => spw_si ); | |
|
340 | end generate; | |
|
341 | recvfront_sel1: if rximpl = impl_fast generate | |
|
342 | recvfront_fast_inst: spwrecvfront_fast | |
|
343 | generic map ( | |
|
344 | rxchunk => rxchunk ) | |
|
345 | port map ( | |
|
346 | clk => clk, | |
|
347 | rxclk => rxclk, | |
|
348 | rxen => recv_rxen, | |
|
349 | inact => recv_inact, | |
|
350 | inbvalid => recv_inbvalid, | |
|
351 | inbits => recv_inbits, | |
|
352 | spw_di => spw_di, | |
|
353 | spw_si => spw_si ); | |
|
354 | end generate; | |
|
355 | ||
|
356 | -- Instantiate RX memory. | |
|
357 | rxmem: spwram | |
|
358 | generic map ( | |
|
359 | abits => rxfifosize_bits, | |
|
360 | dbits => 9 ) | |
|
361 | port map ( | |
|
362 | rclk => clk, | |
|
363 | wclk => clk, | |
|
364 | ren => '1', | |
|
365 | raddr => s_rxfifo_raddr, | |
|
366 | rdata => s_rxfifo_rdata, | |
|
367 | wen => s_rxfifo_wen, | |
|
368 | waddr => s_rxfifo_waddr, | |
|
369 | wdata => s_rxfifo_wdata ); | |
|
370 | ||
|
371 | -- Instantiate TX memory. | |
|
372 | txmem: spwram | |
|
373 | generic map ( | |
|
374 | abits => txfifosize_bits, | |
|
375 | dbits => 9 ) | |
|
376 | port map ( | |
|
377 | rclk => clk, | |
|
378 | wclk => clk, | |
|
379 | ren => '1', | |
|
380 | raddr => s_txfifo_raddr, | |
|
381 | rdata => s_txfifo_rdata, | |
|
382 | wen => s_txfifo_wen, | |
|
383 | waddr => s_txfifo_waddr, | |
|
384 | wdata => s_txfifo_wdata ); | |
|
385 | ||
|
386 | -- Combinatorial process | |
|
387 | process (r, linko, s_rxfifo_rdata, s_txfifo_rdata, rst, autostart, linkstart, linkdis, txdivcnt, tick_in, ctrl_in, time_in, txwrite, txflag, txdata, rxread) is | |
|
388 | variable v: regs_type; | |
|
389 | variable v_tmprxroom: unsigned(rxfifosize_bits-1 downto 0); | |
|
390 | variable v_tmptxroom: unsigned(txfifosize_bits-1 downto 0); | |
|
391 | begin | |
|
392 | v := r; | |
|
393 | v_tmprxroom := to_unsigned(0, v_tmprxroom'length); | |
|
394 | v_tmptxroom := to_unsigned(0, v_tmptxroom'length); | |
|
395 | ||
|
396 | -- Keep track of whether we are sending and/or receiving a packet. | |
|
397 | if linko.rxchar = '1' then | |
|
398 | -- got character | |
|
399 | v.rxpacket := not linko.rxflag; | |
|
400 | end if; | |
|
401 | if linko.txack = '1' then | |
|
402 | -- send character | |
|
403 | v.txpacket := not s_txfifo_rdata(8); | |
|
404 | end if; | |
|
405 | ||
|
406 | -- Update RX fifo pointers. | |
|
407 | if (rxread = '1') and (r.rxfifo_rvalid = '1') then | |
|
408 | -- read from fifo | |
|
409 | v.rxfifo_raddr := std_logic_vector(unsigned(r.rxfifo_raddr) + 1); | |
|
410 | end if; | |
|
411 | if r.rxfull = '0' then | |
|
412 | if (linko.rxchar = '1') or (r.rxeep = '1') then | |
|
413 | -- write to fifo (received char or pending EEP) | |
|
414 | v.rxfifo_waddr := std_logic_vector(unsigned(r.rxfifo_waddr) + 1); | |
|
415 | end if; | |
|
416 | v.rxeep := '0'; | |
|
417 | end if; | |
|
418 | ||
|
419 | -- Keep track of whether the RX fifo contains valid data. | |
|
420 | -- (use new value of rxfifo_raddr) | |
|
421 | v.rxfifo_rvalid := bool_to_logic(v.rxfifo_raddr /= r.rxfifo_waddr); | |
|
422 | ||
|
423 | -- Update room in RX fifo (use new value of rxfifo_waddr). | |
|
424 | v_tmprxroom := unsigned(r.rxfifo_raddr) - unsigned(v.rxfifo_waddr) - 1; | |
|
425 | v.rxfull := bool_to_logic(v_tmprxroom = 0); | |
|
426 | v.rxhalff := not v_tmprxroom(v_tmprxroom'high); | |
|
427 | if v_tmprxroom > 63 then | |
|
428 | v.rxroom := (others => '1'); | |
|
429 | else | |
|
430 | v.rxroom := std_logic_vector(v_tmprxroom(5 downto 0)); | |
|
431 | end if; | |
|
432 | ||
|
433 | -- Update TX fifo pointers. | |
|
434 | if (r.txfifo_rvalid = '1') and ((linko.txack = '1') or (r.txdiscard = '1')) then | |
|
435 | -- read from fifo | |
|
436 | v.txfifo_raddr := std_logic_vector(unsigned(r.txfifo_raddr) + 1); | |
|
437 | if s_txfifo_rdata(8) = '1' then | |
|
438 | v.txdiscard := '0'; -- got EOP/EEP, stop discarding data | |
|
439 | end if; | |
|
440 | end if; | |
|
441 | if (r.txfull = '0') and (txwrite = '1') then | |
|
442 | -- write to fifo | |
|
443 | v.txfifo_waddr := std_logic_vector(unsigned(r.txfifo_waddr) + 1); | |
|
444 | end if; | |
|
445 | ||
|
446 | -- Keep track of whether the TX fifo contains valid data. | |
|
447 | -- (use new value of txfifo_raddr) | |
|
448 | v.txfifo_rvalid := bool_to_logic(v.txfifo_raddr /= r.txfifo_waddr); | |
|
449 | ||
|
450 | -- Update room in TX fifo (use new value of txfifo_waddr). | |
|
451 | v_tmptxroom := unsigned(r.txfifo_raddr) - unsigned(v.txfifo_waddr) - 1; | |
|
452 | v.txfull := bool_to_logic(v_tmptxroom = 0); | |
|
453 | v.txhalff := not v_tmptxroom(v_tmptxroom'high); | |
|
454 | ||
|
455 | -- If the link is lost, set a flag to discard the current packet. | |
|
456 | if linko.running = '0' then | |
|
457 | v.rxeep := v.rxeep or v.rxpacket; -- use new value of rxpacket | |
|
458 | v.txdiscard := v.txdiscard or v.txpacket; -- use new value of txpacket | |
|
459 | v.rxpacket := '0'; | |
|
460 | v.txpacket := '0'; | |
|
461 | end if; | |
|
462 | ||
|
463 | -- Clear the discard flag when the link is explicitly disabled. | |
|
464 | if linkdis = '1' then | |
|
465 | v.txdiscard := '0'; | |
|
466 | end if; | |
|
467 | ||
|
468 | -- Drive control signals to RX fifo. | |
|
469 | s_rxfifo_raddr <= v.rxfifo_raddr; -- using new value of rxfifo_raddr | |
|
470 | s_rxfifo_wen <= (not r.rxfull) and (linko.rxchar or r.rxeep); | |
|
471 | s_rxfifo_waddr <= r.rxfifo_waddr; | |
|
472 | if r.rxeep = '1' then | |
|
473 | s_rxfifo_wdata <= "100000001"; | |
|
474 | else | |
|
475 | s_rxfifo_wdata <= linko.rxflag & linko.rxdata; | |
|
476 | end if; | |
|
477 | ||
|
478 | -- Drive control signals to TX fifo. | |
|
479 | s_txfifo_raddr <= v.txfifo_raddr; -- using new value of txfifo_raddr | |
|
480 | s_txfifo_wen <= (not r.txfull) and txwrite; | |
|
481 | s_txfifo_waddr <= r.txfifo_waddr; | |
|
482 | s_txfifo_wdata <= txflag & txdata; | |
|
483 | ||
|
484 | -- Drive inputs to spwlink. | |
|
485 | linki.autostart <= autostart; | |
|
486 | linki.linkstart <= linkstart; | |
|
487 | linki.linkdis <= linkdis; | |
|
488 | linki.rxroom <= r.rxroom; | |
|
489 | linki.tick_in <= tick_in; | |
|
490 | linki.ctrl_in <= ctrl_in; | |
|
491 | linki.time_in <= time_in; | |
|
492 | linki.txwrite <= r.txfifo_rvalid and not r.txdiscard; | |
|
493 | linki.txflag <= s_txfifo_rdata(8); | |
|
494 | linki.txdata <= s_txfifo_rdata(7 downto 0); | |
|
495 | ||
|
496 | -- Drive divcnt input to spwxmit. | |
|
497 | if linko.running = '1' then | |
|
498 | xmit_divcnt <= txdivcnt; | |
|
499 | else | |
|
500 | xmit_divcnt <= default_divcnt; | |
|
501 | end if; | |
|
502 | ||
|
503 | -- Drive outputs. | |
|
504 | txrdy <= not r.txfull; | |
|
505 | txhalff <= r.txhalff; | |
|
506 | tick_out <= linko.tick_out; | |
|
507 | ctrl_out <= linko.ctrl_out; | |
|
508 | time_out <= linko.time_out; | |
|
509 | rxvalid <= r.rxfifo_rvalid; | |
|
510 | rxhalff <= r.rxhalff; | |
|
511 | rxflag <= s_rxfifo_rdata(8); | |
|
512 | rxdata <= s_rxfifo_rdata(7 downto 0); | |
|
513 | started <= linko.started; | |
|
514 | connecting <= linko.connecting; | |
|
515 | running <= linko.running; | |
|
516 | errdisc <= linko.errdisc; | |
|
517 | errpar <= linko.errpar; | |
|
518 | erresc <= linko.erresc; | |
|
519 | errcred <= linko.errcred; | |
|
520 | ||
|
521 | -- Reset. | |
|
522 | if rst = '1' then | |
|
523 | v.rxpacket := '0'; | |
|
524 | v.rxeep := '0'; | |
|
525 | v.txpacket := '0'; | |
|
526 | v.txdiscard := '0'; | |
|
527 | v.rxfifo_raddr := (others => '0'); | |
|
528 | v.rxfifo_waddr := (others => '0'); | |
|
529 | v.txfifo_raddr := (others => '0'); | |
|
530 | v.txfifo_waddr := (others => '0'); | |
|
531 | v.rxfifo_rvalid := '0'; | |
|
532 | v.txfifo_rvalid := '0'; | |
|
533 | end if; | |
|
534 | ||
|
535 | -- Update registers. | |
|
536 | rin <= v; | |
|
537 | end process; | |
|
538 | ||
|
539 | -- Update registers. | |
|
540 | process (clk) is | |
|
541 | begin | |
|
542 | if rising_edge(clk) then | |
|
543 | r <= rin; | |
|
544 | end if; | |
|
545 | end process; | |
|
546 | ||
|
547 | end architecture spwstream_arch; |
@@ -0,0 +1,249 | |||
|
1 | -- | |
|
2 | -- SpaceWire Transmitter | |
|
3 | -- | |
|
4 | -- This entity translates outgoing characters and tokens into | |
|
5 | -- data-strobe signalling. | |
|
6 | -- | |
|
7 | ||
|
8 | library ieee; | |
|
9 | use ieee.std_logic_1164.all; | |
|
10 | use ieee.numeric_std.all; | |
|
11 | use work.spwpkg.all; | |
|
12 | ||
|
13 | entity spwxmit is | |
|
14 | ||
|
15 | port ( | |
|
16 | -- System clock. | |
|
17 | clk: in std_logic; | |
|
18 | ||
|
19 | -- Synchronous reset (active-high). | |
|
20 | rst: in std_logic; | |
|
21 | ||
|
22 | -- Scaling factor minus 1, used to scale the system clock into the | |
|
23 | -- transmission bit rate. The system clock is divided by | |
|
24 | -- (unsigned(divcnt) + 1). Changing this signal will immediately | |
|
25 | -- change the transmission rate. | |
|
26 | divcnt: in std_logic_vector(7 downto 0); | |
|
27 | ||
|
28 | -- Input signals from spwlink. | |
|
29 | xmiti: in spw_xmit_in_type; | |
|
30 | ||
|
31 | -- Output signals to spwlink. | |
|
32 | xmito: out spw_xmit_out_type; | |
|
33 | ||
|
34 | -- Data Out signal to SpaceWire bus. | |
|
35 | spw_do: out std_logic; | |
|
36 | ||
|
37 | -- Strobe Out signal to SpaceWire bus. | |
|
38 | spw_so: out std_logic | |
|
39 | ); | |
|
40 | ||
|
41 | end entity spwxmit; | |
|
42 | ||
|
43 | architecture spwxmit_arch of spwxmit is | |
|
44 | ||
|
45 | -- Registers | |
|
46 | type regs_type is record | |
|
47 | -- tx clock | |
|
48 | txclken: std_ulogic; -- high if a bit must be transmitted | |
|
49 | txclkcnt: unsigned(7 downto 0); | |
|
50 | -- output shift register | |
|
51 | bitshift: std_logic_vector(12 downto 0); | |
|
52 | bitcnt: unsigned(3 downto 0); | |
|
53 | -- output signals | |
|
54 | out_data: std_ulogic; | |
|
55 | out_strobe: std_ulogic; | |
|
56 | -- parity flag | |
|
57 | parity: std_ulogic; | |
|
58 | -- pending time tick | |
|
59 | pend_tick: std_ulogic; | |
|
60 | pend_time: std_logic_vector(7 downto 0); | |
|
61 | -- transmitter mode | |
|
62 | allow_fct: std_ulogic; -- allowed to send FCTs | |
|
63 | allow_char: std_ulogic; -- allowed to send data and time | |
|
64 | sent_null: std_ulogic; -- sent at least one NULL token | |
|
65 | sent_fct: std_ulogic; -- sent at least one FCT token | |
|
66 | end record; | |
|
67 | ||
|
68 | -- Initial state | |
|
69 | constant regs_reset: regs_type := ( | |
|
70 | txclken => '0', | |
|
71 | txclkcnt => "00000000", | |
|
72 | bitshift => (others => '0'), | |
|
73 | bitcnt => "0000", | |
|
74 | out_data => '0', | |
|
75 | out_strobe => '0', | |
|
76 | parity => '0', | |
|
77 | pend_tick => '0', | |
|
78 | pend_time => (others => '0'), | |
|
79 | allow_fct => '0', | |
|
80 | allow_char => '0', | |
|
81 | sent_null => '0', | |
|
82 | sent_fct => '0' ); | |
|
83 | ||
|
84 | -- Registers | |
|
85 | signal r: regs_type := regs_reset; | |
|
86 | signal rin: regs_type; | |
|
87 | ||
|
88 | begin | |
|
89 | ||
|
90 | -- Combinatorial process | |
|
91 | process (r, rst, divcnt, xmiti) is | |
|
92 | variable v: regs_type; | |
|
93 | begin | |
|
94 | v := r; | |
|
95 | ||
|
96 | -- Generate TX clock. | |
|
97 | if r.txclkcnt = 0 then | |
|
98 | v.txclkcnt := unsigned(divcnt); | |
|
99 | v.txclken := '1'; | |
|
100 | else | |
|
101 | v.txclkcnt := r.txclkcnt - 1; | |
|
102 | v.txclken := '0'; | |
|
103 | end if; | |
|
104 | ||
|
105 | if xmiti.txen = '0' then | |
|
106 | ||
|
107 | -- Transmitter disabled; reset state. | |
|
108 | v.bitcnt := "0000"; | |
|
109 | v.parity := '0'; | |
|
110 | v.pend_tick := '0'; | |
|
111 | v.allow_fct := '0'; | |
|
112 | v.allow_char := '0'; | |
|
113 | v.sent_null := '0'; | |
|
114 | v.sent_fct := '0'; | |
|
115 | ||
|
116 | -- Gentle reset of spacewire bus signals | |
|
117 | if r.txclken = '1' then | |
|
118 | v.out_data := r.out_data and r.out_strobe; | |
|
119 | v.out_strobe := '0'; | |
|
120 | end if; | |
|
121 | ||
|
122 | else | |
|
123 | -- Transmitter enabled. | |
|
124 | ||
|
125 | v.allow_fct := (not xmiti.stnull) and r.sent_null; | |
|
126 | v.allow_char := (not xmiti.stnull) and r.sent_null and | |
|
127 | (not xmiti.stfct) and r.sent_fct; | |
|
128 | ||
|
129 | -- On tick of transmission clock, put next bit on the output. | |
|
130 | if r.txclken = '1' then | |
|
131 | ||
|
132 | if r.bitcnt = 0 then | |
|
133 | ||
|
134 | -- Need to start a new character. | |
|
135 | if (r.allow_char = '1') and (r.pend_tick = '1') then | |
|
136 | -- Send Time-Code. | |
|
137 | v.out_data := r.parity; | |
|
138 | v.bitshift(12 downto 5) := r.pend_time; | |
|
139 | v.bitshift(4 downto 0) := "01111"; | |
|
140 | v.bitcnt := to_unsigned(13, v.bitcnt'length); | |
|
141 | v.parity := '0'; | |
|
142 | v.pend_tick := '0'; | |
|
143 | elsif (r.allow_fct = '1') and (xmiti.fct_in = '1') then | |
|
144 | -- Send FCT. | |
|
145 | v.out_data := r.parity; | |
|
146 | v.bitshift(2 downto 0) := "001"; | |
|
147 | v.bitcnt := to_unsigned(3, v.bitcnt'length); | |
|
148 | v.parity := '1'; | |
|
149 | v.sent_fct := '1'; | |
|
150 | elsif (r.allow_char = '1') and (xmiti.txwrite = '1') then | |
|
151 | -- Send N-Char. | |
|
152 | v.bitshift(0) := xmiti.txflag; | |
|
153 | v.parity := xmiti.txflag; | |
|
154 | if xmiti.txflag = '0' then | |
|
155 | -- Data byte | |
|
156 | v.out_data := not r.parity; | |
|
157 | v.bitshift(8 downto 1) := xmiti.txdata; | |
|
158 | v.bitcnt := to_unsigned(9, v.bitcnt'length); | |
|
159 | else | |
|
160 | -- EOP or EEP | |
|
161 | v.out_data := r.parity; | |
|
162 | v.bitshift(1) := xmiti.txdata(0); | |
|
163 | v.bitshift(2) := not xmiti.txdata(0); | |
|
164 | v.bitcnt := to_unsigned(3, v.bitcnt'length); | |
|
165 | end if; | |
|
166 | else | |
|
167 | -- Send NULL. | |
|
168 | v.out_data := r.parity; | |
|
169 | v.bitshift(6 downto 0) := "0010111"; | |
|
170 | v.bitcnt := to_unsigned(7, v.bitcnt'length); | |
|
171 | v.parity := '0'; | |
|
172 | v.sent_null := '1'; | |
|
173 | end if; | |
|
174 | ||
|
175 | else | |
|
176 | ||
|
177 | -- Shift next bit to the output. | |
|
178 | v.out_data := r.bitshift(0); | |
|
179 | v.parity := r.parity xor r.bitshift(0); | |
|
180 | v.bitshift(r.bitshift'high-1 downto 0) := r.bitshift(r.bitshift'high downto 1); | |
|
181 | v.bitcnt := r.bitcnt - 1; | |
|
182 | ||
|
183 | end if; | |
|
184 | ||
|
185 | -- Data-Strobe encoding. | |
|
186 | v.out_strobe := not (r.out_strobe xor r.out_data xor v.out_data); | |
|
187 | ||
|
188 | end if; | |
|
189 | ||
|
190 | -- Store requests for time tick transmission. | |
|
191 | if xmiti.tick_in = '1' then | |
|
192 | v.pend_tick := '1'; | |
|
193 | v.pend_time := xmiti.ctrl_in & xmiti.time_in; | |
|
194 | end if; | |
|
195 | ||
|
196 | end if; | |
|
197 | ||
|
198 | -- Synchronous reset | |
|
199 | if rst = '1' then | |
|
200 | v := regs_reset; | |
|
201 | end if; | |
|
202 | ||
|
203 | -- Drive outputs. | |
|
204 | -- Note: the outputs are combinatorially dependent on certain inputs. | |
|
205 | ||
|
206 | -- Set fctack high if (transmitter enabled) AND | |
|
207 | -- (ready for token) AND (FCTs allowed) AND | |
|
208 | -- ((characters not allowed) OR (no timecode pending)) AND | |
|
209 | -- (FCT requested) | |
|
210 | if (xmiti.txen = '1') and | |
|
211 | (r.txclken = '1') and (r.bitcnt = 0) and (r.allow_fct = '1') and | |
|
212 | ((r.allow_char = '0') or (r.pend_tick = '0')) then | |
|
213 | xmito.fctack <= xmiti.fct_in; | |
|
214 | else | |
|
215 | xmito.fctack <= '0'; | |
|
216 | end if; | |
|
217 | ||
|
218 | -- Set txrdy high if (transmitter enabled) AND | |
|
219 | -- (ready for token) AND (characters enabled) AND | |
|
220 | -- (no timecode pending) AND (no FCT requested) AND | |
|
221 | -- (character requested) | |
|
222 | if (xmiti.txen = '1') and | |
|
223 | (r.txclken = '1') and (r.bitcnt = 0) and (r.allow_char = '1') and | |
|
224 | (r.pend_tick = '0') and (xmiti.fct_in = '0') then | |
|
225 | xmito.txack <= xmiti.txwrite; | |
|
226 | else | |
|
227 | xmito.txack <= '0'; | |
|
228 | end if; | |
|
229 | ||
|
230 | -- Update registers | |
|
231 | rin <= v; | |
|
232 | end process; | |
|
233 | ||
|
234 | -- Synchronous process | |
|
235 | process (clk) is | |
|
236 | begin | |
|
237 | if rising_edge(clk) then | |
|
238 | ||
|
239 | -- Update registers | |
|
240 | r <= rin; | |
|
241 | ||
|
242 | -- Drive spacewire output signals | |
|
243 | spw_do <= r.out_data; | |
|
244 | spw_so <= r.out_strobe; | |
|
245 | ||
|
246 | end if; | |
|
247 | end process; | |
|
248 | ||
|
249 | end architecture spwxmit_arch; |
This diff has been collapsed as it changes many lines, (721 lines changed) Show them Hide them | |||
@@ -0,0 +1,721 | |||
|
1 | -- | |
|
2 | -- SpaceWire Transmitter | |
|
3 | -- | |
|
4 | -- This entity translates outgoing characters and tokens into | |
|
5 | -- data-strobe signalling. | |
|
6 | -- | |
|
7 | -- The output stage is driven by a separate transmission clock "txclk" which | |
|
8 | -- will typically be faster than the system clock. The actual transmission | |
|
9 | -- rate is determined by dividing the transmission clock by an integer factor. | |
|
10 | -- | |
|
11 | -- The code is tuned for implementation on Xilinx Spartan-3. | |
|
12 | -- | |
|
13 | -- Concept | |
|
14 | -- ------- | |
|
15 | -- | |
|
16 | -- Logic in the system clock domain generates a stream of tokens to be | |
|
17 | -- transmitted. These tokens are encoded as instances of the token_type | |
|
18 | -- record. Tokens are queued in a two-slot FIFO buffer (r.token0 and r.token1) | |
|
19 | -- with a 1-bit pointer (r.tokmux) pointing to the head of the queue. | |
|
20 | -- When a token is pushed into the buffer, a flag register is flipped | |
|
21 | -- (r.sysflip0 and r.sysflip1) to indicate to the txclk domain that the | |
|
22 | -- buffer slot has been refilled. | |
|
23 | -- | |
|
24 | -- The txclk domain pulls tokens from the FIFO buffer, flipping flag | |
|
25 | -- registers (rtx.txflip0 and rtx.txflip1) to indicate to the system clock | |
|
26 | -- domain that a token has been pulled. When the system clock domain detects | |
|
27 | -- that a token has been consumed, it refills the buffer slot with a new | |
|
28 | -- token (assuming that there are tokens waiting to be transmitted). | |
|
29 | -- Whenever the FIFO buffer is empty, the txclk domain sends NULLs instead. | |
|
30 | -- This can happen either when there are no tokens to send, or when the | |
|
31 | -- system clock domain is late to refill the buffer. | |
|
32 | -- | |
|
33 | -- Details | |
|
34 | -- ------- | |
|
35 | -- | |
|
36 | -- Logic in the system clock domain accepts transmission requests through | |
|
37 | -- the external interface of the entity. Pending requests are translated | |
|
38 | -- into a stream of tokens. The tokens are pushed to the txclk domain through | |
|
39 | -- the FIFO buffer as described above. | |
|
40 | -- | |
|
41 | -- The data path through the txclk domain is divided into stages B through F | |
|
42 | -- in a half-hearted attempt to keep things simple. | |
|
43 | -- | |
|
44 | -- Stage B takes a token from the FIFO buffer and updates a buffer status | |
|
45 | -- flag to indicate that the buffer slot needs to be refilled. If the FIFO | |
|
46 | -- is empty, a NULL is inserted. Stage B is triggered one clock after | |
|
47 | -- stage E switches to a new token. If the previous token was ESC, stage B | |
|
48 | -- skips a turn because stage C will already know what to do. | |
|
49 | -- | |
|
50 | -- Stage C takes a token from stage B and translates it into a bit pattern. | |
|
51 | -- Time codes and NULL tokens are broken into two separate tokens starting | |
|
52 | -- with ESC. Stage C is triggered one clock after the shift buffer in | |
|
53 | -- stage E drops to 3 tokens. | |
|
54 | -- | |
|
55 | -- Stage D completes the task of translating tokens to bit patterns and | |
|
56 | -- distinguishes between 10-bit and 4-bit tokens. It is not explicitly | |
|
57 | -- triggered but simply follows stage C. | |
|
58 | -- | |
|
59 | -- Stage E is the bit shift register. It shifts when "txclken" is high. | |
|
60 | -- A one-hot counter keeps track of the number of bits remaining in | |
|
61 | -- the register. When the register falls empty, it loads a new 10-bit or | |
|
62 | -- 4-bit pattern as prepared by stage D. Stage E also computes parity. | |
|
63 | -- | |
|
64 | -- Stage F performs data strobe encoding. When the transmitter is disabled, | |
|
65 | -- the outputs of stage F fall to zero in a controlled way. | |
|
66 | -- | |
|
67 | -- To generate the transmission bit clock, the txclk is divided by an | |
|
68 | -- integer factor (divcnt+1) using an 8-bit down counter. The implementation | |
|
69 | -- of this counter has become quite complicated in order to meet timing goals. | |
|
70 | -- The counter consists of 4 blocks of two bits each (txclkcnt), with a | |
|
71 | -- carry-save concept used between blocks (txclkcy). Detection of terminal | |
|
72 | -- count (txclkdone) has a pipeline delay of two cycles. Therefore a separate | |
|
73 | -- concept is used if the initial count is less than 2 (txdivnorm). This is | |
|
74 | -- all glued together in the final assignment to txclken. | |
|
75 | -- | |
|
76 | -- The initial count for txclk division (divcnt) comes from the system clock | |
|
77 | -- domain and thus needs to be synchronized for use in the txclk domain. | |
|
78 | -- To facilitate this, the system clock domain latches the value of divcnt | |
|
79 | -- once every 6 sysclk cycles and sets a flag to indicate when the latched | |
|
80 | -- value can safely be used by the txclk domain. | |
|
81 | -- | |
|
82 | -- A tricky aspect of the design is the initial state of the txclk logic. | |
|
83 | -- When the transmitter is enabled (txen goes high), the txclk logic starts | |
|
84 | -- with the first ESC pattern already set up in stage D, and stage C ready | |
|
85 | -- to produce the FCT part of the first NULL. | |
|
86 | -- | |
|
87 | -- The following guidelines are used to get good timing for the txclk domain: | |
|
88 | -- * The new value of a register depends on at most 4 inputs (single LUT), | |
|
89 | -- or in a few cases on 5 inputs (two LUTs and F5MUX). | |
|
90 | -- * Synchronous resets may be used, but only if the reset signal comes | |
|
91 | -- directly from a register (no logic in set/reset path); | |
|
92 | -- * Clock enables may be used, but only if the enable signal comes directly | |
|
93 | -- from a register (no logic in clock enable path). | |
|
94 | -- | |
|
95 | -- Synchronization issues | |
|
96 | -- ---------------------- | |
|
97 | -- | |
|
98 | -- There is a two-slot FIFO buffer between the system and txclk domains. | |
|
99 | -- After the txclk domain pulls a token from the buffer, the system clock | |
|
100 | -- domain should ideally refill the buffer before the txclk domain again | |
|
101 | -- tries to pull from the same buffer slot. If the refill occurs late, | |
|
102 | -- the txclk domain needs to insert a NULL token which is inefficient | |
|
103 | -- use of bandwidth. | |
|
104 | -- | |
|
105 | -- Assuming the transmission consists of a stream of data characters, | |
|
106 | -- 10 bits per character, there are exactly 2*10 bit periods between | |
|
107 | -- successive reads from the same buffer slot by the txclk logic. | |
|
108 | -- | |
|
109 | -- The time needed for the system clock logic to refill a buffer slot = | |
|
110 | -- 1 txclk period (update of rtx.txflipN) | |
|
111 | -- + 1 txclk period (routing delay between domains) | |
|
112 | -- + 2 sysclk periods (synchronizer for txflipN) | |
|
113 | -- + 1 sysclk period (refill buffer slot and update r.sysflipN) | |
|
114 | -- + 1 txclk period (routing delay between domains) | |
|
115 | -- + 2 txclk periods (synchronizer for sysflipN) | |
|
116 | -- = 5 txclk periods + 3 sysclk periods | |
|
117 | -- | |
|
118 | -- If for example txclk is 4 times as fast as sysclk, this amounts to | |
|
119 | -- 5 txclk + 3 sysclk = 5 + 3*4 txclk = 17 txclk | |
|
120 | -- is less than 20 bit periods even at maximum transmission rate, so | |
|
121 | -- no problem there. | |
|
122 | -- | |
|
123 | -- This is different when the data stream includes 4-bit tokens. | |
|
124 | -- See the manual for further comments. | |
|
125 | -- | |
|
126 | -- Implementation guidelines | |
|
127 | -- ------------------------- | |
|
128 | -- | |
|
129 | -- To minimize clock skew, IOB flip-flops should be used to drive | |
|
130 | -- spw_do and spw_so. | |
|
131 | -- | |
|
132 | -- "txclk" must be at least as fast as the system clock; | |
|
133 | -- "txclk" does not need to be phase-related to the system clock; | |
|
134 | -- it is allowed for "txclk" to be equal to "clk". | |
|
135 | -- | |
|
136 | -- The following timing constraints are needed: | |
|
137 | -- * PERIOD constraint on the system clock; | |
|
138 | -- * PERIOD constraint on "txclk"; | |
|
139 | -- * FROM-TO constraint from "txclk" to the system clock, equal to | |
|
140 | -- one "txclk" period; | |
|
141 | -- * FROM-TO constraint from the system clock to "txclk", equal to | |
|
142 | -- one "txclk" period. | |
|
143 | -- | |
|
144 | ||
|
145 | library ieee; | |
|
146 | use ieee.std_logic_1164.all; | |
|
147 | use ieee.numeric_std.all; | |
|
148 | use work.spwpkg.all; | |
|
149 | ||
|
150 | entity spwxmit_fast is | |
|
151 | ||
|
152 | port ( | |
|
153 | -- System clock. | |
|
154 | clk: in std_logic; | |
|
155 | ||
|
156 | -- Transmit clock. | |
|
157 | txclk: in std_logic; | |
|
158 | ||
|
159 | -- Synchronous reset (active-high) | |
|
160 | -- Used asynchronously by fast clock domain (must be glitch-free). | |
|
161 | rst: in std_logic; | |
|
162 | ||
|
163 | -- Scaling factor minus 1, used to scale the system clock into the | |
|
164 | -- transmission bit rate. The system clock is divided by | |
|
165 | -- (unsigned(divcnt) + 1). Changing this signal will immediately | |
|
166 | -- change the transmission rate. | |
|
167 | divcnt: in std_logic_vector(7 downto 0); | |
|
168 | ||
|
169 | -- Input signals from spwlink. | |
|
170 | xmiti: in spw_xmit_in_type; | |
|
171 | ||
|
172 | -- Output signals to spwlink. | |
|
173 | xmito: out spw_xmit_out_type; | |
|
174 | ||
|
175 | -- Data Out signal to SpaceWire bus. | |
|
176 | spw_do: out std_logic; | |
|
177 | ||
|
178 | -- Strobe Out signal to SpaceWire bus. | |
|
179 | spw_so: out std_logic | |
|
180 | ); | |
|
181 | ||
|
182 | -- Turn off FSM extraction to avoid synchronization problems. | |
|
183 | attribute FSM_EXTRACT: string; | |
|
184 | attribute FSM_EXTRACT of spwxmit_fast: entity is "NO"; | |
|
185 | ||
|
186 | end entity spwxmit_fast; | |
|
187 | ||
|
188 | architecture spwxmit_fast_arch of spwxmit_fast is | |
|
189 | ||
|
190 | -- Convert boolean to std_logic. | |
|
191 | type bool_to_logic_type is array(boolean) of std_ulogic; | |
|
192 | constant bool_to_logic: bool_to_logic_type := (false => '0', true => '1'); | |
|
193 | ||
|
194 | -- Data records passed between clock domains. | |
|
195 | type token_type is record | |
|
196 | tick: std_ulogic; -- send time code | |
|
197 | fct: std_ulogic; -- send FCT | |
|
198 | fctpiggy: std_ulogic; -- send FCT and N-char | |
|
199 | flag: std_ulogic; -- send EOP or EEP | |
|
200 | char: std_logic_vector(7 downto 0); -- character or time code | |
|
201 | end record; | |
|
202 | ||
|
203 | -- Registers in txclk domain | |
|
204 | type txregs_type is record | |
|
205 | -- sync to system clock domain | |
|
206 | txflip0: std_ulogic; | |
|
207 | txflip1: std_ulogic; | |
|
208 | -- stage B | |
|
209 | b_update: std_ulogic; | |
|
210 | b_mux: std_ulogic; | |
|
211 | b_txflip: std_ulogic; | |
|
212 | b_valid: std_ulogic; | |
|
213 | b_token: token_type; | |
|
214 | -- stage C | |
|
215 | c_update: std_ulogic; | |
|
216 | c_busy: std_ulogic; | |
|
217 | c_esc: std_ulogic; | |
|
218 | c_fct: std_ulogic; | |
|
219 | c_bits: std_logic_vector(8 downto 0); | |
|
220 | -- stage D | |
|
221 | d_bits: std_logic_vector(8 downto 0); | |
|
222 | d_cnt4: std_ulogic; | |
|
223 | d_cnt10: std_ulogic; | |
|
224 | -- stage E | |
|
225 | e_valid: std_ulogic; | |
|
226 | e_shift: std_logic_vector(9 downto 0); | |
|
227 | e_count: std_logic_vector(9 downto 0); | |
|
228 | e_parity: std_ulogic; | |
|
229 | -- stage F | |
|
230 | f_spwdo: std_ulogic; | |
|
231 | f_spwso: std_ulogic; | |
|
232 | -- tx clock enable logic | |
|
233 | txclken: std_ulogic; | |
|
234 | txclkpre: std_ulogic; | |
|
235 | txclkcnt: std_logic_vector(7 downto 0); | |
|
236 | txclkcy: std_logic_vector(2 downto 0); | |
|
237 | txclkdone: std_logic_vector(1 downto 0); | |
|
238 | txclkdiv: std_logic_vector(7 downto 0); | |
|
239 | txdivnorm: std_ulogic; | |
|
240 | end record; | |
|
241 | ||
|
242 | -- Registers in system clock domain | |
|
243 | type regs_type is record | |
|
244 | -- sync status to txclk domain | |
|
245 | txenreg: std_ulogic; | |
|
246 | txdivreg: std_logic_vector(7 downto 0); | |
|
247 | txdivnorm: std_ulogic; | |
|
248 | txdivtmp: std_logic_vector(1 downto 0); | |
|
249 | txdivsafe: std_ulogic; | |
|
250 | -- data stream to txclk domain | |
|
251 | sysflip0: std_ulogic; | |
|
252 | sysflip1: std_ulogic; | |
|
253 | token0: token_type; | |
|
254 | token1: token_type; | |
|
255 | tokmux: std_ulogic; | |
|
256 | -- transmitter management | |
|
257 | pend_fct: std_ulogic; -- '1' if an outgoing FCT is pending | |
|
258 | pend_char: std_ulogic; -- '1' if an outgoing N-Char is pending | |
|
259 | pend_data: std_logic_vector(8 downto 0); -- control flag and data bits of pending char | |
|
260 | pend_tick: std_ulogic; -- '1' if an outgoing time tick is pending | |
|
261 | pend_time: std_logic_vector(7 downto 0); -- data bits of pending time tick | |
|
262 | allow_fct: std_ulogic; -- '1' when allowed to send FCTs | |
|
263 | allow_char: std_ulogic; -- '1' when allowed to send data and time | |
|
264 | sent_fct: std_ulogic; -- '1' when at least one FCT token was sent | |
|
265 | end record; | |
|
266 | ||
|
267 | -- Initial state of system clock domain | |
|
268 | constant token_reset: token_type := ( | |
|
269 | tick => '0', | |
|
270 | fct => '0', | |
|
271 | fctpiggy => '0', | |
|
272 | flag => '0', | |
|
273 | char => (others => '0') ); | |
|
274 | constant regs_reset: regs_type := ( | |
|
275 | txenreg => '0', | |
|
276 | txdivreg => (others => '0'), | |
|
277 | txdivnorm => '0', | |
|
278 | txdivtmp => "00", | |
|
279 | txdivsafe => '0', | |
|
280 | sysflip0 => '0', | |
|
281 | sysflip1 => '0', | |
|
282 | token0 => token_reset, | |
|
283 | token1 => token_reset, | |
|
284 | tokmux => '0', | |
|
285 | pend_fct => '0', | |
|
286 | pend_char => '0', | |
|
287 | pend_data => (others => '0'), | |
|
288 | pend_tick => '0', | |
|
289 | pend_time => (others => '0'), | |
|
290 | allow_fct => '0', | |
|
291 | allow_char => '0', | |
|
292 | sent_fct => '0' ); | |
|
293 | ||
|
294 | -- Signals that are re-synchronized from system clock to txclk domain. | |
|
295 | type synctx_type is record | |
|
296 | rstn: std_ulogic; | |
|
297 | sysflip0: std_ulogic; | |
|
298 | sysflip1: std_ulogic; | |
|
299 | txen: std_ulogic; | |
|
300 | txdivsafe: std_ulogic; | |
|
301 | end record; | |
|
302 | ||
|
303 | -- Signals that are re-synchronized from txclk to system clock domain. | |
|
304 | type syncsys_type is record | |
|
305 | txflip0: std_ulogic; | |
|
306 | txflip1: std_ulogic; | |
|
307 | end record; | |
|
308 | ||
|
309 | -- Registers | |
|
310 | signal rtx: txregs_type; | |
|
311 | signal rtxin: txregs_type; | |
|
312 | signal r: regs_type := regs_reset; | |
|
313 | signal rin: regs_type; | |
|
314 | ||
|
315 | -- Synchronized signals after crossing clock domains. | |
|
316 | signal synctx: synctx_type; | |
|
317 | signal syncsys: syncsys_type; | |
|
318 | ||
|
319 | -- Output flip-flops | |
|
320 | signal s_spwdo: std_logic; | |
|
321 | signal s_spwso: std_logic; | |
|
322 | ||
|
323 | -- Force use of IOB flip-flops | |
|
324 | attribute IOB: string; | |
|
325 | attribute IOB of s_spwdo: signal is "TRUE"; | |
|
326 | attribute IOB of s_spwso: signal is "TRUE"; | |
|
327 | ||
|
328 | begin | |
|
329 | ||
|
330 | -- Reset synchronizer for txclk domain. | |
|
331 | synctx_rst: syncdff | |
|
332 | port map ( clk => txclk, rst => rst, di => '1', do => synctx.rstn ); | |
|
333 | ||
|
334 | -- Synchronize signals from system clock domain to txclk domain. | |
|
335 | synctx_sysflip0: syncdff | |
|
336 | port map ( clk => txclk, rst => rst, di => r.sysflip0, do => synctx.sysflip0 ); | |
|
337 | synctx_sysflip1: syncdff | |
|
338 | port map ( clk => txclk, rst => rst, di => r.sysflip1, do => synctx.sysflip1 ); | |
|
339 | synctx_txen: syncdff | |
|
340 | port map ( clk => txclk, rst => rst, di => r.txenreg, do => synctx.txen ); | |
|
341 | synctx_txdivsafe: syncdff | |
|
342 | port map ( clk => txclk, rst => rst, di => r.txdivsafe, do => synctx.txdivsafe ); | |
|
343 | ||
|
344 | -- Synchronize signals from txclk domain to system clock domain. | |
|
345 | syncsys_txflip0: syncdff | |
|
346 | port map ( clk => clk, rst => rst, di => rtx.txflip0, do => syncsys.txflip0 ); | |
|
347 | syncsys_txflip1: syncdff | |
|
348 | port map ( clk => clk, rst => rst, di => rtx.txflip1, do => syncsys.txflip1 ); | |
|
349 | ||
|
350 | -- Drive SpaceWire output signals | |
|
351 | spw_do <= s_spwdo; | |
|
352 | spw_so <= s_spwso; | |
|
353 | ||
|
354 | -- Combinatorial process | |
|
355 | process (r, rtx, rst, divcnt, xmiti, synctx, syncsys) is | |
|
356 | variable v: regs_type; | |
|
357 | variable vtx: txregs_type; | |
|
358 | variable v_needtoken: std_ulogic; | |
|
359 | variable v_havetoken: std_ulogic; | |
|
360 | variable v_token: token_type; | |
|
361 | begin | |
|
362 | v := r; | |
|
363 | vtx := rtx; | |
|
364 | v_needtoken := '0'; | |
|
365 | v_havetoken := '0'; | |
|
366 | v_token := token_reset; | |
|
367 | ||
|
368 | -- ---- FAST CLOCK DOMAIN ---- | |
|
369 | ||
|
370 | -- Stage B: Multiplex tokens from system clock domain. | |
|
371 | -- Update stage B three bit periods after updating stage C | |
|
372 | -- (i.e. in time for the next update of stage C). | |
|
373 | -- Do not update stage B if stage C is indicating that it needs to | |
|
374 | -- send a second token to complete its task. | |
|
375 | vtx.b_update := rtx.txclken and rtx.e_count(0) and (not rtx.c_busy); | |
|
376 | if rtx.b_mux = '0' then | |
|
377 | vtx.b_txflip := rtx.txflip0; | |
|
378 | else | |
|
379 | vtx.b_txflip := rtx.txflip1; | |
|
380 | end if; | |
|
381 | if rtx.b_update = '1' then | |
|
382 | if rtx.b_mux = '0' then | |
|
383 | -- get token from slot 0 | |
|
384 | vtx.b_valid := synctx.sysflip0 xor rtx.b_txflip; | |
|
385 | vtx.b_token := r.token0; | |
|
386 | -- update mux flag if we got a valid token | |
|
387 | vtx.b_mux := synctx.sysflip0 xor rtx.b_txflip; | |
|
388 | vtx.txflip0 := synctx.sysflip0; | |
|
389 | vtx.txflip1 := rtx.txflip1; | |
|
390 | else | |
|
391 | -- get token from slot 1 | |
|
392 | vtx.b_valid := synctx.sysflip1 xor rtx.b_txflip; | |
|
393 | vtx.b_token := r.token1; | |
|
394 | -- update mux flag if we got a valid token | |
|
395 | vtx.b_mux := not (synctx.sysflip1 xor rtx.b_txflip); | |
|
396 | vtx.txflip0 := rtx.txflip0; | |
|
397 | vtx.txflip1 := synctx.sysflip1; | |
|
398 | end if; | |
|
399 | end if; | |
|
400 | ||
|
401 | -- Stage C: Prepare to transmit EOP, EEP or a data character. | |
|
402 | vtx.c_update := rtx.txclken and rtx.e_count(3); | |
|
403 | if rtx.c_update = '1' then | |
|
404 | ||
|
405 | -- NULL is broken into two tokens: ESC + FCT. | |
|
406 | -- Time-codes are broken into two tokens: ESC + char. | |
|
407 | ||
|
408 | -- Enable c_esc on the first pass of a NULL or a time-code. | |
|
409 | vtx.c_esc := (rtx.b_token.tick or (not rtx.b_valid)) and | |
|
410 | (not rtx.c_esc); | |
|
411 | ||
|
412 | -- Enable c_fct on the first pass of an FCT and on | |
|
413 | -- the second pass of a NULL (also the first pass, but c_esc | |
|
414 | -- is stronger than c_fct). | |
|
415 | vtx.c_fct := (rtx.b_token.fct and (not rtx.c_busy)) or | |
|
416 | (not rtx.b_valid); | |
|
417 | ||
|
418 | -- Enable c_busy on the first pass of a NULL or a time-code | |
|
419 | -- or a piggy-backed FCT. This will tell stage B that we are | |
|
420 | -- not done yet. | |
|
421 | vtx.c_busy := (rtx.b_token.tick or (not rtx.b_valid) or | |
|
422 | rtx.b_token.fctpiggy) and (not rtx.c_busy); | |
|
423 | ||
|
424 | if rtx.b_token.flag = '1' then | |
|
425 | if rtx.b_token.char(0) = '0' then | |
|
426 | -- prepare to send EOP | |
|
427 | vtx.c_bits := "000000101"; -- EOP = P101 | |
|
428 | else | |
|
429 | -- prepare to send EEP | |
|
430 | vtx.c_bits := "000000011"; -- EEP = P110 | |
|
431 | end if; | |
|
432 | else | |
|
433 | -- prepare to send data char | |
|
434 | vtx.c_bits := rtx.b_token.char & '0'; | |
|
435 | end if; | |
|
436 | end if; | |
|
437 | ||
|
438 | -- Stage D: Prepare to transmit FCT, ESC, or the stuff from stage C. | |
|
439 | if rtx.c_esc = '1' then | |
|
440 | -- prepare to send ESC | |
|
441 | vtx.d_bits := "000000111"; -- ESC = P111 | |
|
442 | vtx.d_cnt4 := '1'; -- 3 bits + implicit parity bit | |
|
443 | vtx.d_cnt10 := '0'; | |
|
444 | elsif rtx.c_fct = '1' then | |
|
445 | -- prepare to send FCT | |
|
446 | vtx.d_bits := "000000001"; -- FCT = P100 | |
|
447 | vtx.d_cnt4 := '1'; -- 3 bits + implicit parity bit | |
|
448 | vtx.d_cnt10 := '0'; | |
|
449 | else | |
|
450 | -- send the stuff from stage C. | |
|
451 | vtx.d_bits := rtx.c_bits; | |
|
452 | vtx.d_cnt4 := rtx.c_bits(0); | |
|
453 | vtx.d_cnt10 := not rtx.c_bits(0); | |
|
454 | end if; | |
|
455 | ||
|
456 | -- Stage E: Shift register. | |
|
457 | if rtx.txclken = '1' then | |
|
458 | if rtx.e_count(0) = '1' then | |
|
459 | -- reload shift register; output parity bit | |
|
460 | vtx.e_valid := '1'; | |
|
461 | vtx.e_shift(vtx.e_shift'high downto 1) := rtx.d_bits; | |
|
462 | vtx.e_shift(0) := not (rtx.e_parity xor rtx.d_bits(0)); | |
|
463 | vtx.e_count := rtx.d_cnt10 & "00000" & rtx.d_cnt4 & "000"; | |
|
464 | vtx.e_parity := rtx.d_bits(0); | |
|
465 | else | |
|
466 | -- shift bits to output; update parity bit | |
|
467 | vtx.e_shift := '0' & rtx.e_shift(rtx.e_shift'high downto 1); | |
|
468 | vtx.e_count := '0' & rtx.e_count(rtx.e_count'high downto 1); | |
|
469 | vtx.e_parity := rtx.e_parity xor rtx.e_shift(1); | |
|
470 | end if; | |
|
471 | end if; | |
|
472 | ||
|
473 | -- Stage F: Data/strobe encoding. | |
|
474 | if rtx.txclken = '1' then | |
|
475 | if rtx.e_valid = '1' then | |
|
476 | -- output next data/strobe bits | |
|
477 | vtx.f_spwdo := rtx.e_shift(0); | |
|
478 | vtx.f_spwso := not (rtx.e_shift(0) xor rtx.f_spwdo xor rtx.f_spwso); | |
|
479 | else | |
|
480 | -- gentle reset of spacewire signals | |
|
481 | vtx.f_spwdo := rtx.f_spwdo and rtx.f_spwso; | |
|
482 | vtx.f_spwso := '0'; | |
|
483 | end if; | |
|
484 | end if; | |
|
485 | ||
|
486 | -- Generate tx clock enable | |
|
487 | -- An 8-bit counter decrements on every clock. A txclken pulse is | |
|
488 | -- produced 2 cycles after the counter reaches value 2. Counter reload | |
|
489 | -- values of 0 and 1 are handled as special cases. | |
|
490 | -- count down in blocks of two bits | |
|
491 | vtx.txclkcnt(1 downto 0) := std_logic_vector(unsigned(rtx.txclkcnt(1 downto 0)) - 1); | |
|
492 | vtx.txclkcnt(3 downto 2) := std_logic_vector(unsigned(rtx.txclkcnt(3 downto 2)) - unsigned(rtx.txclkcy(0 downto 0))); | |
|
493 | vtx.txclkcnt(5 downto 4) := std_logic_vector(unsigned(rtx.txclkcnt(5 downto 4)) - unsigned(rtx.txclkcy(1 downto 1))); | |
|
494 | vtx.txclkcnt(7 downto 6) := std_logic_vector(unsigned(rtx.txclkcnt(7 downto 6)) - unsigned(rtx.txclkcy(2 downto 2))); | |
|
495 | -- propagate carry in blocks of two bits | |
|
496 | vtx.txclkcy(0) := bool_to_logic(rtx.txclkcnt(1 downto 0) = "00"); | |
|
497 | vtx.txclkcy(1) := rtx.txclkcy(0) and bool_to_logic(rtx.txclkcnt(3 downto 2) = "00"); | |
|
498 | vtx.txclkcy(2) := rtx.txclkcy(1) and bool_to_logic(rtx.txclkcnt(5 downto 4) = "00"); | |
|
499 | -- detect value 2 in counter | |
|
500 | vtx.txclkdone(0) := bool_to_logic(rtx.txclkcnt(3 downto 0) = "0010"); | |
|
501 | vtx.txclkdone(1) := bool_to_logic(rtx.txclkcnt(7 downto 4) = "0000"); | |
|
502 | -- trigger txclken | |
|
503 | vtx.txclken := (rtx.txclkdone(0) and rtx.txclkdone(1)) or rtx.txclkpre; | |
|
504 | vtx.txclkpre := (not rtx.txdivnorm) and ((not rtx.txclkpre) or (not rtx.txclkdiv(0))); | |
|
505 | -- reload counter | |
|
506 | if rtx.txclken = '1' then | |
|
507 | vtx.txclkcnt := rtx.txclkdiv; | |
|
508 | vtx.txclkcy := "000"; | |
|
509 | vtx.txclkdone := "00"; | |
|
510 | end if; | |
|
511 | ||
|
512 | -- Synchronize txclkdiv | |
|
513 | if synctx.txdivsafe = '1' then | |
|
514 | vtx.txclkdiv := r.txdivreg; | |
|
515 | vtx.txdivnorm := r.txdivnorm; | |
|
516 | end if; | |
|
517 | ||
|
518 | -- Transmitter disabled. | |
|
519 | if synctx.txen = '0' then | |
|
520 | vtx.txflip0 := '0'; | |
|
521 | vtx.txflip1 := '0'; | |
|
522 | vtx.b_update := '0'; | |
|
523 | vtx.b_mux := '0'; | |
|
524 | vtx.b_valid := '0'; | |
|
525 | vtx.c_update := '0'; | |
|
526 | vtx.c_busy := '1'; | |
|
527 | vtx.c_esc := '1'; -- need to send 2nd part of NULL | |
|
528 | vtx.c_fct := '1'; | |
|
529 | vtx.d_bits := "000000111"; -- ESC = P111 | |
|
530 | vtx.d_cnt4 := '1'; -- 3 bits + implicit parity bit | |
|
531 | vtx.d_cnt10 := '0'; | |
|
532 | vtx.e_valid := '0'; | |
|
533 | vtx.e_parity := '0'; | |
|
534 | vtx.e_count := (0 => '1', others => '0'); | |
|
535 | end if; | |
|
536 | ||
|
537 | -- Reset. | |
|
538 | if synctx.rstn = '0' then | |
|
539 | vtx.f_spwdo := '0'; | |
|
540 | vtx.f_spwso := '0'; | |
|
541 | vtx.txclken := '0'; | |
|
542 | vtx.txclkpre := '1'; | |
|
543 | vtx.txclkcnt := (others => '0'); | |
|
544 | vtx.txclkdiv := (others => '0'); | |
|
545 | vtx.txdivnorm := '0'; | |
|
546 | end if; | |
|
547 | ||
|
548 | -- ---- SYSTEM CLOCK DOMAIN ---- | |
|
549 | ||
|
550 | -- Hold divcnt and txen for use by txclk domain. | |
|
551 | v.txdivtmp := std_logic_vector(unsigned(r.txdivtmp) - 1); | |
|
552 | if r.txdivtmp = "00" then | |
|
553 | if r.txdivsafe = '0' then | |
|
554 | -- Latch the current value of divcnt and txen. | |
|
555 | v.txdivsafe := '1'; | |
|
556 | v.txdivtmp := "01"; | |
|
557 | v.txdivreg := divcnt; | |
|
558 | if unsigned(divcnt(divcnt'high downto 1)) = 0 then | |
|
559 | v.txdivnorm := '0'; | |
|
560 | else | |
|
561 | v.txdivnorm := '1'; | |
|
562 | end if; | |
|
563 | v.txenreg := xmiti.txen; | |
|
564 | else | |
|
565 | -- Drop the txdivsafe flag but keep latched values. | |
|
566 | v.txdivsafe := '0'; | |
|
567 | end if; | |
|
568 | end if; | |
|
569 | ||
|
570 | -- Pass falling edge of txen signal as soon as possible. | |
|
571 | if xmiti.txen = '0' then | |
|
572 | v.txenreg := '0'; | |
|
573 | end if; | |
|
574 | ||
|
575 | -- Store requests for FCT transmission. | |
|
576 | if xmiti.fct_in = '1' and r.allow_fct = '1' then | |
|
577 | v.pend_fct := '1'; | |
|
578 | end if; | |
|
579 | ||
|
580 | if xmiti.txen = '0' then | |
|
581 | ||
|
582 | -- Transmitter disabled; reset state. | |
|
583 | v.sysflip0 := '0'; | |
|
584 | v.sysflip1 := '0'; | |
|
585 | v.tokmux := '0'; | |
|
586 | v.pend_fct := '0'; | |
|
587 | v.pend_char := '0'; | |
|
588 | v.pend_tick := '0'; | |
|
589 | v.allow_fct := '0'; | |
|
590 | v.allow_char := '0'; | |
|
591 | v.sent_fct := '0'; | |
|
592 | ||
|
593 | else | |
|
594 | ||
|
595 | -- Determine if a new token is needed. | |
|
596 | if r.tokmux = '0' then | |
|
597 | if r.sysflip0 = syncsys.txflip0 then | |
|
598 | v_needtoken := '1'; | |
|
599 | end if; | |
|
600 | else | |
|
601 | if r.sysflip1 = syncsys.txflip1 then | |
|
602 | v_needtoken := '1'; | |
|
603 | end if; | |
|
604 | end if; | |
|
605 | ||
|
606 | -- Prepare new token. | |
|
607 | if r.allow_char = '1' and r.pend_tick = '1' then | |
|
608 | -- prepare to send time code | |
|
609 | v_token.tick := '1'; | |
|
610 | v_token.fct := '0'; | |
|
611 | v_token.fctpiggy := '0'; | |
|
612 | v_token.flag := '0'; | |
|
613 | v_token.char := r.pend_time; | |
|
614 | v_havetoken := '1'; | |
|
615 | if v_needtoken = '1' then | |
|
616 | v.pend_tick := '0'; | |
|
617 | end if; | |
|
618 | else | |
|
619 | if r.allow_fct = '1' and (xmiti.fct_in = '1' or r.pend_fct = '1') then | |
|
620 | -- prepare to send FCT | |
|
621 | v_token.fct := '1'; | |
|
622 | v_havetoken := '1'; | |
|
623 | if v_needtoken = '1' then | |
|
624 | v.pend_fct := '0'; | |
|
625 | v.sent_fct := '1'; | |
|
626 | end if; | |
|
627 | end if; | |
|
628 | if r.allow_char = '1' and r.pend_char = '1' then | |
|
629 | -- prepare to send N-Char | |
|
630 | -- Note: it is possible to send an FCT and an N-Char | |
|
631 | -- together by enabling the fctpiggy flag. | |
|
632 | v_token.fctpiggy := v_token.fct; | |
|
633 | v_token.flag := r.pend_data(8); | |
|
634 | v_token.char := r.pend_data(7 downto 0); | |
|
635 | v_havetoken := '1'; | |
|
636 | if v_needtoken = '1' then | |
|
637 | v.pend_char := '0'; | |
|
638 | end if; | |
|
639 | end if; | |
|
640 | end if; | |
|
641 | ||
|
642 | -- Put new token in slot. | |
|
643 | if v_havetoken = '1' then | |
|
644 | if r.tokmux = '0' then | |
|
645 | if r.sysflip0 = syncsys.txflip0 then | |
|
646 | v.sysflip0 := not r.sysflip0; | |
|
647 | v.token0 := v_token; | |
|
648 | v.tokmux := '1'; | |
|
649 | end if; | |
|
650 | else | |
|
651 | if r.sysflip1 = syncsys.txflip1 then | |
|
652 | v.sysflip1 := not r.sysflip1; | |
|
653 | v.token1 := v_token; | |
|
654 | v.tokmux := '0'; | |
|
655 | end if; | |
|
656 | end if; | |
|
657 | end if; | |
|
658 | ||
|
659 | -- Determine whether we are allowed to send FCTs and characters | |
|
660 | v.allow_fct := not xmiti.stnull; | |
|
661 | v.allow_char := (not xmiti.stnull) and (not xmiti.stfct) and r.sent_fct; | |
|
662 | ||
|
663 | -- Store request for data transmission. | |
|
664 | if xmiti.txwrite = '1' and r.allow_char = '1' and r.pend_char = '0' then | |
|
665 | v.pend_char := '1'; | |
|
666 | v.pend_data := xmiti.txflag & xmiti.txdata; | |
|
667 | end if; | |
|
668 | ||
|
669 | -- Store requests for time tick transmission. | |
|
670 | if xmiti.tick_in = '1' then | |
|
671 | v.pend_tick := '1'; | |
|
672 | v.pend_time := xmiti.ctrl_in & xmiti.time_in; | |
|
673 | end if; | |
|
674 | ||
|
675 | end if; | |
|
676 | ||
|
677 | -- Synchronous reset of system clock domain. | |
|
678 | if rst = '1' then | |
|
679 | v := regs_reset; | |
|
680 | end if; | |
|
681 | ||
|
682 | -- Drive outputs. | |
|
683 | -- Note: the outputs are combinatorially dependent on certain inputs. | |
|
684 | ||
|
685 | -- Set fctack high if (FCT requested) and (FCTs allowed) AND | |
|
686 | -- (no FCT pending) | |
|
687 | xmito.fctack <= xmiti.fct_in and xmiti.txen and r.allow_fct and | |
|
688 | (not r.pend_fct); | |
|
689 | ||
|
690 | -- Set txrdy high if (character requested) AND (characters allowed) AND | |
|
691 | -- (no character pending) | |
|
692 | xmito.txack <= xmiti.txwrite and xmiti.txen and r.allow_char and | |
|
693 | (not r.pend_char); | |
|
694 | ||
|
695 | -- Update registers. | |
|
696 | rin <= v; | |
|
697 | rtxin <= vtx; | |
|
698 | end process; | |
|
699 | ||
|
700 | -- Synchronous process in txclk domain | |
|
701 | process (txclk) is | |
|
702 | begin | |
|
703 | if rising_edge(txclk) then | |
|
704 | -- drive spacewire output signals | |
|
705 | s_spwdo <= rtx.f_spwdo; | |
|
706 | s_spwso <= rtx.f_spwso; | |
|
707 | -- update registers | |
|
708 | rtx <= rtxin; | |
|
709 | end if; | |
|
710 | end process; | |
|
711 | ||
|
712 | -- Synchronous process in system clock domain | |
|
713 | process (clk) is | |
|
714 | begin | |
|
715 | if rising_edge(clk) then | |
|
716 | -- update registers | |
|
717 | r <= rin; | |
|
718 | end if; | |
|
719 | end process; | |
|
720 | ||
|
721 | end architecture spwxmit_fast_arch; |
@@ -0,0 +1,446 | |||
|
1 | -- | |
|
2 | -- Test application for spwstream. | |
|
3 | -- | |
|
4 | -- This entity implements one spwstream instance with SpaceWire signals | |
|
5 | -- routed to external ports. The SpaceWire port is assumed to be looped back | |
|
6 | -- to itself externally, either directly (tx pins wired to rx pins) or | |
|
7 | -- through a remote SpaceWire device which is programmed to echo anything | |
|
8 | -- it receives. | |
|
9 | -- | |
|
10 | -- This entity submits a series of test patterns to the transmit side of | |
|
11 | -- spwstream. At the same time it monitors the receive side of spwstream | |
|
12 | -- and verifies that received data matches the transmitted data pattern. | |
|
13 | -- | |
|
14 | -- Link mode and tx bit rate may be programmed through digital inputs | |
|
15 | -- (presumably connected to switches or buttons). Link state and progress of | |
|
16 | -- the test are reported through digital outputs (presumably connected to | |
|
17 | -- LEDs). | |
|
18 | -- | |
|
19 | -- Note: there is no check on the integrity of the first packet received | |
|
20 | -- after the link goes up. | |
|
21 | -- | |
|
22 | ||
|
23 | library ieee; | |
|
24 | use ieee.std_logic_1164.all; | |
|
25 | use ieee.numeric_std.all; | |
|
26 | use work.spwpkg.all; | |
|
27 | ||
|
28 | entity streamtest is | |
|
29 | ||
|
30 | generic ( | |
|
31 | -- System clock frequency in Hz. | |
|
32 | sysfreq: real; | |
|
33 | ||
|
34 | -- txclk frequency in Hz (if tximpl = impl_fast). | |
|
35 | txclkfreq: real; | |
|
36 | ||
|
37 | -- 2-log of division factor from system clock freq to timecode freq. | |
|
38 | tickdiv: integer range 12 to 24 := 20; | |
|
39 | ||
|
40 | -- Receiver front-end implementation. | |
|
41 | rximpl: spw_implementation_type := impl_generic; | |
|
42 | ||
|
43 | -- Maximum number of bits received per system clock (impl_fast only). | |
|
44 | rxchunk: integer range 1 to 4 := 1; | |
|
45 | ||
|
46 | -- Transmitter implementation. | |
|
47 | tximpl: spw_implementation_type := impl_generic; | |
|
48 | ||
|
49 | -- Size of receive FIFO. | |
|
50 | rxfifosize_bits: integer range 6 to 14 := 11; | |
|
51 | ||
|
52 | -- Size of transmit FIFO. | |
|
53 | txfifosize_bits: integer range 2 to 14 := 11 ); | |
|
54 | ||
|
55 | port ( | |
|
56 | -- System clock. | |
|
57 | clk: in std_logic; | |
|
58 | ||
|
59 | -- Receiver sample clock (only for impl_fast). | |
|
60 | rxclk: in std_logic; | |
|
61 | ||
|
62 | -- Transmit clock (only for impl_fast). | |
|
63 | txclk: in std_logic; | |
|
64 | ||
|
65 | -- Synchronous reset (active-high). | |
|
66 | rst: in std_logic; | |
|
67 | ||
|
68 | -- Enables spontaneous link start. | |
|
69 | linkstart: in std_logic; | |
|
70 | ||
|
71 | -- Enables automatic link start on receipt of a NULL token. | |
|
72 | autostart: in std_logic; | |
|
73 | ||
|
74 | -- Do not start link and/or disconnect current link. | |
|
75 | linkdisable: in std_logic; | |
|
76 | ||
|
77 | -- Enable sending test patterns to spwstream. | |
|
78 | senddata: in std_logic; | |
|
79 | ||
|
80 | -- Enable sending time codes to spwstream. | |
|
81 | sendtick: in std_logic; | |
|
82 | ||
|
83 | -- Scaling factor minus 1 for TX bitrate. | |
|
84 | txdivcnt: in std_logic_vector(7 downto 0); | |
|
85 | ||
|
86 | -- Link in state Started. | |
|
87 | linkstarted: out std_logic; | |
|
88 | ||
|
89 | -- Link in state Connecting. | |
|
90 | linkconnecting: out std_logic; | |
|
91 | ||
|
92 | -- Link in state Run. | |
|
93 | linkrun: out std_logic; | |
|
94 | ||
|
95 | -- Link error (one cycle pulse, not directly suitable for LED) | |
|
96 | linkerror: out std_logic; | |
|
97 | ||
|
98 | -- High when taking a byte from the receive FIFO. | |
|
99 | gotdata: out std_logic; | |
|
100 | ||
|
101 | -- Incorrect or unexpected data received (sticky). | |
|
102 | dataerror: out std_logic; | |
|
103 | ||
|
104 | -- Incorrect or unexpected time code received (sticky). | |
|
105 | tickerror: out std_logic; | |
|
106 | ||
|
107 | -- SpaceWire signals. | |
|
108 | spw_di: in std_logic; | |
|
109 | spw_si: in std_logic; | |
|
110 | spw_do: out std_logic; | |
|
111 | spw_so: out std_logic ); | |
|
112 | ||
|
113 | end entity streamtest; | |
|
114 | ||
|
115 | architecture streamtest_arch of streamtest is | |
|
116 | ||
|
117 | -- Update 16-bit maximum length LFSR by 8 steps | |
|
118 | function lfsr16(x: in std_logic_vector) return std_logic_vector is | |
|
119 | variable y: std_logic_vector(15 downto 0); | |
|
120 | begin | |
|
121 | -- poly = x^16 + x^14 + x^13 + x^11 + 1 | |
|
122 | -- tap positions = x(0), x(2), x(3), x(5) | |
|
123 | y(7 downto 0) := x(15 downto 8); | |
|
124 | y(15 downto 8) := x(7 downto 0) xor x(9 downto 2) xor x(10 downto 3) xor x(12 downto 5); | |
|
125 | return y; | |
|
126 | end function; | |
|
127 | ||
|
128 | -- Sending side state. | |
|
129 | type tx_state_type is ( txst_idle, txst_prepare, txst_data ); | |
|
130 | ||
|
131 | -- Receiving side state. | |
|
132 | type rx_state_type is ( rxst_idle, rxst_data ); | |
|
133 | ||
|
134 | -- Registers. | |
|
135 | type regs_type is record | |
|
136 | tx_state: tx_state_type; | |
|
137 | tx_timecnt: std_logic_vector((tickdiv-1) downto 0); | |
|
138 | tx_quietcnt: std_logic_vector(15 downto 0); | |
|
139 | tx_pktlen: std_logic_vector(15 downto 0); | |
|
140 | tx_lfsr: std_logic_vector(15 downto 0); | |
|
141 | tx_enabledata: std_ulogic; | |
|
142 | rx_state: rx_state_type; | |
|
143 | rx_quietcnt: std_logic_vector(15 downto 0); | |
|
144 | rx_enabledata: std_ulogic; | |
|
145 | rx_gottick: std_ulogic; | |
|
146 | rx_expecttick: std_ulogic; | |
|
147 | rx_expectglitch: unsigned(5 downto 0); | |
|
148 | rx_badpacket: std_ulogic; | |
|
149 | rx_pktlen: std_logic_vector(15 downto 0); | |
|
150 | rx_prev: std_logic_vector(15 downto 0); | |
|
151 | rx_lfsr: std_logic_vector(15 downto 0); | |
|
152 | running: std_ulogic; | |
|
153 | tick_in: std_ulogic; | |
|
154 | time_in: std_logic_vector(5 downto 0); | |
|
155 | txwrite: std_ulogic; | |
|
156 | txflag: std_ulogic; | |
|
157 | txdata: std_logic_vector(7 downto 0); | |
|
158 | rxread: std_ulogic; | |
|
159 | gotdata: std_ulogic; | |
|
160 | dataerror: std_ulogic; | |
|
161 | tickerror: std_ulogic; | |
|
162 | end record; | |
|
163 | ||
|
164 | -- Reset state. | |
|
165 | constant regs_reset: regs_type := ( | |
|
166 | tx_state => txst_idle, | |
|
167 | tx_timecnt => (others => '0'), | |
|
168 | tx_quietcnt => (others => '0'), | |
|
169 | tx_pktlen => (others => '0'), | |
|
170 | tx_lfsr => (1 => '1', others => '0'), | |
|
171 | tx_enabledata => '0', | |
|
172 | rx_state => rxst_idle, | |
|
173 | rx_quietcnt => (others => '0'), | |
|
174 | rx_enabledata => '0', | |
|
175 | rx_gottick => '0', | |
|
176 | rx_expecttick => '0', | |
|
177 | rx_expectglitch => "000001", | |
|
178 | rx_badpacket => '0', | |
|
179 | rx_pktlen => (others => '0'), | |
|
180 | rx_prev => (others => '0'), | |
|
181 | rx_lfsr => (others => '0'), | |
|
182 | running => '0', | |
|
183 | tick_in => '0', | |
|
184 | time_in => (others => '0'), | |
|
185 | txwrite => '0', | |
|
186 | txflag => '0', | |
|
187 | txdata => (others => '0'), | |
|
188 | rxread => '0', | |
|
189 | gotdata => '0', | |
|
190 | dataerror => '0', | |
|
191 | tickerror => '0' ); | |
|
192 | ||
|
193 | signal r: regs_type := regs_reset; | |
|
194 | signal rin: regs_type; | |
|
195 | ||
|
196 | -- Interface signals. | |
|
197 | signal s_txrdy: std_logic; | |
|
198 | signal s_tickout: std_logic; | |
|
199 | signal s_timeout: std_logic_vector(5 downto 0); | |
|
200 | signal s_rxvalid: std_logic; | |
|
201 | signal s_rxflag: std_logic; | |
|
202 | signal s_rxdata: std_logic_vector(7 downto 0); | |
|
203 | signal s_running: std_logic; | |
|
204 | signal s_errdisc: std_logic; | |
|
205 | signal s_errpar: std_logic; | |
|
206 | signal s_erresc: std_logic; | |
|
207 | signal s_errcred: std_logic; | |
|
208 | ||
|
209 | begin | |
|
210 | ||
|
211 | -- spwstream instance | |
|
212 | spwstream_inst: spwstream | |
|
213 | generic map ( | |
|
214 | sysfreq => sysfreq, | |
|
215 | txclkfreq => txclkfreq, | |
|
216 | rximpl => rximpl, | |
|
217 | rxchunk => rxchunk, | |
|
218 | tximpl => tximpl, | |
|
219 | rxfifosize_bits => rxfifosize_bits, | |
|
220 | txfifosize_bits => txfifosize_bits ) | |
|
221 | port map ( | |
|
222 | clk => clk, | |
|
223 | rxclk => rxclk, | |
|
224 | txclk => txclk, | |
|
225 | rst => rst, | |
|
226 | autostart => autostart, | |
|
227 | linkstart => linkstart, | |
|
228 | linkdis => linkdisable, | |
|
229 | txdivcnt => txdivcnt, | |
|
230 | tick_in => r.tick_in, | |
|
231 | ctrl_in => (others => '0'), | |
|
232 | time_in => r.time_in, | |
|
233 | txwrite => r.txwrite, | |
|
234 | txflag => r.txflag, | |
|
235 | txdata => r.txdata, | |
|
236 | txrdy => s_txrdy, | |
|
237 | txhalff => open, | |
|
238 | tick_out => s_tickout, | |
|
239 | ctrl_out => open, | |
|
240 | time_out => s_timeout, | |
|
241 | rxvalid => s_rxvalid, | |
|
242 | rxhalff => open, | |
|
243 | rxflag => s_rxflag, | |
|
244 | rxdata => s_rxdata, | |
|
245 | rxread => r.rxread, | |
|
246 | started => linkstarted, | |
|
247 | connecting => linkconnecting, | |
|
248 | running => s_running, | |
|
249 | errdisc => s_errdisc, | |
|
250 | errpar => s_errpar, | |
|
251 | erresc => s_erresc, | |
|
252 | errcred => s_errcred, | |
|
253 | spw_di => spw_di, | |
|
254 | spw_si => spw_si, | |
|
255 | spw_do => spw_do, | |
|
256 | spw_so => spw_so ); | |
|
257 | ||
|
258 | -- Drive status indications. | |
|
259 | linkrun <= s_running; | |
|
260 | linkerror <= s_errdisc or s_errpar or s_erresc or s_errcred; | |
|
261 | gotdata <= r.gotdata; | |
|
262 | dataerror <= r.dataerror; | |
|
263 | tickerror <= r.tickerror; | |
|
264 | ||
|
265 | process (r, rst, senddata, sendtick, s_txrdy, s_tickout, s_timeout, s_rxvalid, s_rxflag, s_rxdata, s_running) is | |
|
266 | variable v: regs_type; | |
|
267 | begin | |
|
268 | v := r; | |
|
269 | ||
|
270 | -- Initiate timecode transmissions. | |
|
271 | v.tx_timecnt := std_logic_vector(unsigned(r.tx_timecnt) + 1); | |
|
272 | if unsigned(v.tx_timecnt) = 0 then | |
|
273 | v.tick_in := sendtick; | |
|
274 | else | |
|
275 | v.tick_in := '0'; | |
|
276 | end if; | |
|
277 | if r.tick_in = '1' then | |
|
278 | v.time_in := std_logic_vector(unsigned(r.time_in) + 1); | |
|
279 | v.rx_expecttick := '1'; | |
|
280 | v.rx_gottick := '0'; | |
|
281 | end if; | |
|
282 | ||
|
283 | -- Turn data generator on/off at regular intervals. | |
|
284 | v.tx_quietcnt := std_logic_vector(unsigned(r.tx_quietcnt) + 1); | |
|
285 | if unsigned(r.tx_quietcnt) = 61000 then | |
|
286 | v.tx_quietcnt := (others => '0'); | |
|
287 | end if; | |
|
288 | v.tx_enabledata := senddata and (not r.tx_quietcnt(15)); | |
|
289 | ||
|
290 | -- Generate data packets. | |
|
291 | case r.tx_state is | |
|
292 | when txst_idle => | |
|
293 | -- generate packet length | |
|
294 | v.tx_state := txst_prepare; | |
|
295 | v.tx_pktlen := r.tx_lfsr; | |
|
296 | v.txwrite := '0'; | |
|
297 | v.tx_lfsr := lfsr16(r.tx_lfsr); | |
|
298 | when txst_prepare => | |
|
299 | -- generate first byte of packet | |
|
300 | v.tx_state := txst_data; | |
|
301 | v.txwrite := r.tx_enabledata; | |
|
302 | v.txflag := '0'; | |
|
303 | v.txdata := r.tx_lfsr(15 downto 8); | |
|
304 | v.tx_lfsr := lfsr16(r.tx_lfsr); | |
|
305 | when txst_data => | |
|
306 | -- generate data bytes and EOP | |
|
307 | v.txwrite := r.tx_enabledata; | |
|
308 | if r.txwrite = '1' and s_txrdy = '1' then | |
|
309 | -- just sent one byte | |
|
310 | v.tx_pktlen := std_logic_vector(unsigned(r.tx_pktlen) - 1); | |
|
311 | if unsigned(r.tx_pktlen) = 0 then | |
|
312 | -- done with packet | |
|
313 | v.tx_state := txst_idle; | |
|
314 | v.txwrite := '0'; | |
|
315 | elsif unsigned(r.tx_pktlen) = 1 then | |
|
316 | -- generate EOP | |
|
317 | v.txwrite := r.tx_enabledata; | |
|
318 | v.txflag := '1'; | |
|
319 | v.txdata := (others => '0'); | |
|
320 | v.tx_lfsr := lfsr16(r.tx_lfsr); | |
|
321 | else | |
|
322 | -- generate next data byte | |
|
323 | v.txwrite := r.tx_enabledata; | |
|
324 | v.txflag := '0'; | |
|
325 | v.txdata := r.tx_lfsr(15 downto 8); | |
|
326 | v.tx_lfsr := lfsr16(r.tx_lfsr); | |
|
327 | end if; | |
|
328 | end if; | |
|
329 | end case; | |
|
330 | ||
|
331 | -- Blink light when receiving data. | |
|
332 | v.gotdata := s_rxvalid and r.rxread; | |
|
333 | ||
|
334 | -- Detect missing timecodes. | |
|
335 | if r.tick_in = '1' and r.rx_expecttick = '1' then | |
|
336 | -- This is bad; a new timecode is being generated while | |
|
337 | -- we have not even received the previous one yet. | |
|
338 | v.tickerror := '1'; | |
|
339 | end if; | |
|
340 | ||
|
341 | -- Receive and check incoming timecodes. | |
|
342 | if s_tickout = '1' then | |
|
343 | if unsigned(s_timeout) + 1 /= unsigned(r.time_in) then | |
|
344 | -- Received time code does not match last transmitted code. | |
|
345 | v.tickerror := '1'; | |
|
346 | end if; | |
|
347 | if r.rx_gottick = '1' then | |
|
348 | -- Already received the last transmitted time code. | |
|
349 | v.tickerror := '1'; | |
|
350 | end if; | |
|
351 | v.rx_expecttick := '0'; | |
|
352 | v.rx_gottick := '1'; | |
|
353 | end if; | |
|
354 | ||
|
355 | -- Turn data receiving on/off at regular intervals | |
|
356 | v.rx_quietcnt := std_logic_vector(unsigned(r.rx_quietcnt) + 1); | |
|
357 | if unsigned(r.rx_quietcnt) = 55000 then | |
|
358 | v.rx_quietcnt := (others => '0'); | |
|
359 | end if; | |
|
360 | v.rx_enabledata := not r.rx_quietcnt(15); | |
|
361 | ||
|
362 | case r.rx_state is | |
|
363 | when rxst_idle => | |
|
364 | -- get expected packet length | |
|
365 | v.rx_state := rxst_data; | |
|
366 | v.rx_pktlen := r.rx_lfsr; | |
|
367 | v.rx_lfsr := lfsr16(r.rx_lfsr); | |
|
368 | v.rx_prev := (others => '0'); | |
|
369 | when rxst_data => | |
|
370 | v.rxread := r.rx_enabledata; | |
|
371 | if r.rxread = '1' and s_rxvalid = '1' then | |
|
372 | -- got next byte | |
|
373 | v.rx_pktlen := std_logic_vector(unsigned(r.rx_pktlen) - 1); | |
|
374 | v.rx_prev := s_rxdata & r.rx_prev(15 downto 8); | |
|
375 | if s_rxflag = '1' then | |
|
376 | -- got EOP or EEP | |
|
377 | v.rxread := '0'; | |
|
378 | v.rx_state := rxst_idle; | |
|
379 | if s_rxdata = "00000000" then | |
|
380 | -- got EOP | |
|
381 | if unsigned(r.rx_pktlen) /= 0 then | |
|
382 | -- unexpected EOP | |
|
383 | v.rx_badpacket := '1'; | |
|
384 | end if; | |
|
385 | -- count errors against expected glitches | |
|
386 | if v.rx_badpacket = '1' then | |
|
387 | -- got glitch | |
|
388 | if r.rx_expectglitch = 0 then | |
|
389 | v.dataerror := '1'; | |
|
390 | else | |
|
391 | v.rx_expectglitch := r.rx_expectglitch - 1; | |
|
392 | end if; | |
|
393 | end if; | |
|
394 | -- resynchronize LFSR | |
|
395 | v.rx_lfsr := lfsr16(lfsr16(r.rx_prev)); | |
|
396 | else | |
|
397 | -- got EEP | |
|
398 | v.rx_badpacket := '1'; | |
|
399 | end if; | |
|
400 | v.rx_badpacket := '0'; | |
|
401 | else | |
|
402 | -- got next byte | |
|
403 | v.rx_lfsr := lfsr16(r.rx_lfsr); | |
|
404 | if unsigned(r.rx_pktlen) = 0 then | |
|
405 | -- missing EOP | |
|
406 | v.rx_badpacket := '1'; | |
|
407 | end if; | |
|
408 | if s_rxdata /= r.rx_lfsr(15 downto 8) then | |
|
409 | -- bad data | |
|
410 | v.rx_badpacket := '1'; | |
|
411 | end if; | |
|
412 | end if; | |
|
413 | end if; | |
|
414 | end case; | |
|
415 | ||
|
416 | -- If the link goes away, we should expect inconsistency on the receiving side. | |
|
417 | v.running := s_running; | |
|
418 | if r.running = '1' and s_running = '0' then | |
|
419 | if r.rx_expectglitch /= "111111" then | |
|
420 | v.rx_expectglitch := r.rx_expectglitch + 1; | |
|
421 | end if; | |
|
422 | end if; | |
|
423 | ||
|
424 | -- If there is no link, we should not expect to receive time codes. | |
|
425 | if s_running = '0' then | |
|
426 | v.rx_expecttick := '0'; | |
|
427 | end if; | |
|
428 | ||
|
429 | -- Synchronous reset. | |
|
430 | if rst = '1' then | |
|
431 | v := regs_reset; | |
|
432 | end if; | |
|
433 | ||
|
434 | -- Update registers. | |
|
435 | rin <= v; | |
|
436 | end process; | |
|
437 | ||
|
438 | -- Update registers. | |
|
439 | process (clk) is | |
|
440 | begin | |
|
441 | if rising_edge(clk) then | |
|
442 | r <= rin; | |
|
443 | end if; | |
|
444 | end process; | |
|
445 | ||
|
446 | end architecture streamtest_arch; |
@@ -0,0 +1,70 | |||
|
1 | -- | |
|
2 | -- Double flip-flop synchronizer. | |
|
3 | -- | |
|
4 | -- This entity is used to safely capture asynchronous signals. | |
|
5 | -- | |
|
6 | -- An implementation may assign additional constraints to this entity | |
|
7 | -- in order to reduce the probability of meta-stability issues. | |
|
8 | -- For example, an extra tight timing constraint could be placed on | |
|
9 | -- the data path from syncdff_ff1 to syncdff_ff2 to ensure that | |
|
10 | -- meta-stability of ff1 is resolved before ff2 captures the signal. | |
|
11 | -- | |
|
12 | ||
|
13 | library ieee; | |
|
14 | use ieee.std_logic_1164.all; | |
|
15 | ||
|
16 | entity syncdff is | |
|
17 | ||
|
18 | port ( | |
|
19 | clk: in std_logic; -- clock (destination domain) | |
|
20 | rst: in std_logic; -- asynchronous reset, active-high | |
|
21 | di: in std_logic; -- input data | |
|
22 | do: out std_logic -- output data | |
|
23 | ); | |
|
24 | ||
|
25 | -- Turn off register replication in XST. | |
|
26 | attribute REGISTER_DUPLICATION: string; | |
|
27 | attribute REGISTER_DUPLICATION of syncdff: entity is "NO"; | |
|
28 | ||
|
29 | end entity syncdff; | |
|
30 | ||
|
31 | architecture syncdff_arch of syncdff is | |
|
32 | ||
|
33 | -- flip-flops | |
|
34 | signal syncdff_ff1: std_ulogic := '0'; | |
|
35 | signal syncdff_ff2: std_ulogic := '0'; | |
|
36 | ||
|
37 | -- Turn of shift-register extraction in XST. | |
|
38 | attribute SHIFT_EXTRACT: string; | |
|
39 | attribute SHIFT_EXTRACT of syncdff_ff1: signal is "NO"; | |
|
40 | attribute SHIFT_EXTRACT of syncdff_ff2: signal is "NO"; | |
|
41 | ||
|
42 | -- Tell XST to place both flip-flops in the same slice. | |
|
43 | attribute RLOC: string; | |
|
44 | attribute RLOC of syncdff_ff1: signal is "X0Y0"; | |
|
45 | attribute RLOC of syncdff_ff2: signal is "X0Y0"; | |
|
46 | ||
|
47 | -- Tell XST to keep the flip-flop net names to be used in timing constraints. | |
|
48 | attribute KEEP: string; | |
|
49 | attribute KEEP of syncdff_ff1: signal is "SOFT"; | |
|
50 | attribute KEEP of syncdff_ff2: signal is "SOFT"; | |
|
51 | ||
|
52 | begin | |
|
53 | ||
|
54 | -- second flip-flop drives the output signal | |
|
55 | do <= syncdff_ff2; | |
|
56 | ||
|
57 | process (clk, rst) is | |
|
58 | begin | |
|
59 | if rst = '1' then | |
|
60 | -- asynchronous reset | |
|
61 | syncdff_ff1 <= '0'; | |
|
62 | syncdff_ff2 <= '0'; | |
|
63 | elsif rising_edge(clk) then | |
|
64 | -- data synchronization | |
|
65 | syncdff_ff1 <= di; | |
|
66 | syncdff_ff2 <= syncdff_ff1; | |
|
67 | end if; | |
|
68 | end process; | |
|
69 | ||
|
70 | end architecture syncdff_arch; |
@@ -0,0 +1,84 | |||
|
1 | VHDLIB=../.. | |
|
2 | SCRIPTSDIR=$(VHDLIB)/scripts/ | |
|
3 | GRLIB := $(shell sh $(VHDLIB)/scripts/lpp_relpath.sh) | |
|
4 | TOP=testbench | |
|
5 | BOARD=LFR-EQM | |
|
6 | include $(VHDLIB)/boards/$(BOARD)/Makefile_RTAX.inc | |
|
7 | DEVICE=$(PART)-$(PACKAGE)$(SPEED) | |
|
8 | UCF= | |
|
9 | QSF= | |
|
10 | EFFORT=high | |
|
11 | XSTOPT= | |
|
12 | SYNPOPT= | |
|
13 | VHDLSYNFILES= | |
|
14 | VHDLSIMFILES= tb.vhd $(VHDLIB)/boards/designs/LFR-EQM-RTAX/LFR-EQM.vhd | |
|
15 | SIMTOP=testbench | |
|
16 | CLEAN=soft-clean | |
|
17 | ||
|
18 | TECHLIBS = axcelerator | |
|
19 | ||
|
20 | LIBSKIP = core1553bbc core1553brm core1553brt gr1553 corePCIF \ | |
|
21 | tmtc openchip hynix ihp gleichmann micron usbhc opencores fmf ftlib gsi | |
|
22 | ||
|
23 | DIRSKIP = b1553 pcif leon2 leon3v3 leon2ft crypto satcan ddr usb ata i2c \ | |
|
24 | pci grusbhc haps slink ascs can pwm greth coremp7 spi ac97 srmmu atf \ | |
|
25 | grlfpc \ | |
|
26 | ./dsp/lpp_fft_rtax \ | |
|
27 | ./amba_lcd_16x2_ctrlr \ | |
|
28 | ./general_purpose/lpp_AMR \ | |
|
29 | ./general_purpose/lpp_balise \ | |
|
30 | ./general_purpose/lpp_delay \ | |
|
31 | ./lpp_bootloader \ | |
|
32 | ./lfr_management \ | |
|
33 | ./lpp_sim/CY7C1061DV33 \ | |
|
34 | ./lpp_cna \ | |
|
35 | ./lpp_uart \ | |
|
36 | ./lpp_usb \ | |
|
37 | ./dsp/lpp_fft \ | |
|
38 | ./lpp_leon3_soc \ | |
|
39 | ./lpp_debug_lfr | |
|
40 | ||
|
41 | FILESKIP = i2cmst.vhd \ | |
|
42 | APB_MULTI_DIODE.vhd \ | |
|
43 | APB_MULTI_DIODE.vhd \ | |
|
44 | Top_MatrixSpec.vhd \ | |
|
45 | APB_FFT.vhd \ | |
|
46 | lpp_lfr_ms_FFT.vhd \ | |
|
47 | lpp_lfr_apbreg.vhd \ | |
|
48 | CoreFFT.vhd \ | |
|
49 | lpp_lfr_ms.vhd \ | |
|
50 | lpp_lfr_sim_pkg.vhd \ | |
|
51 | mtie_maps.vhd \ | |
|
52 | ftsrctrlc.vhd \ | |
|
53 | ftsdctrl.vhd \ | |
|
54 | ftsrctrl8.vhd \ | |
|
55 | ftmctrl.vhd \ | |
|
56 | ftsdctrl64.vhd \ | |
|
57 | ftahbram.vhd \ | |
|
58 | ftahbram2.vhd \ | |
|
59 | sramft.vhd \ | |
|
60 | nandfctrlx.vhd | |
|
61 | ||
|
62 | include $(GRLIB)/bin/Makefile | |
|
63 | include $(GRLIB)/software/leon3/Makefile | |
|
64 | ||
|
65 | ################## project specific targets ########################## | |
|
66 | distclean:myclean | |
|
67 | vsim:cp_for_vsim | |
|
68 | ||
|
69 | myclean: | |
|
70 | rm -f input.txt output_fx.txt *.log | |
|
71 | rm -rf ./2016* | |
|
72 | ||
|
73 | generate : | |
|
74 | python ./generate.py | |
|
75 | ||
|
76 | cp_for_vsim: generate | |
|
77 | cp ./input.txt simulation/ | |
|
78 | ||
|
79 | archivate: | |
|
80 | xonsh ./archivate.xsh | |
|
81 | ||
|
82 | test: | generate ghdl ghdl-run archivate | |
|
83 | ||
|
84 |
@@ -0,0 +1,254 | |||
|
1 | ||
|
2 | LIBRARY ieee; | |
|
3 | USE ieee.std_logic_1164.ALL; | |
|
4 | USE ieee.numeric_std.ALL; | |
|
5 | USE IEEE.std_logic_signed.ALL; | |
|
6 | USE IEEE.MATH_real.ALL; | |
|
7 | ||
|
8 | LIBRARY techmap; | |
|
9 | USE techmap.gencomp.ALL; | |
|
10 | ||
|
11 | LIBRARY std; | |
|
12 | USE std.textio.ALL; | |
|
13 | ||
|
14 | LIBRARY lpp; | |
|
15 | USE lpp.iir_filter.ALL; | |
|
16 | USE lpp.lpp_ad_conv.ALL; | |
|
17 | USE lpp.FILTERcfg.ALL; | |
|
18 | USE lpp.lpp_lfr_filter_coeff.ALL; | |
|
19 | USE lpp.general_purpose.ALL; | |
|
20 | USE lpp.data_type_pkg.ALL; | |
|
21 | USE lpp.lpp_lfr_pkg.ALL; | |
|
22 | USE lpp.general_purpose.ALL; | |
|
23 | USE lpp.lpp_sim_pkg.ALL; | |
|
24 | USE lpp.lpp_waveform_pkg.ALL; | |
|
25 | ||
|
26 | ENTITY testbench IS | |
|
27 | GENERIC( | |
|
28 | tech : INTEGER := 0; --axcel,0 | |
|
29 | Mem_use : INTEGER := use_CEL --use_RAM,use_CEL | |
|
30 | ); | |
|
31 | END; | |
|
32 | ||
|
33 | ARCHITECTURE behav OF testbench IS | |
|
34 | ||
|
35 | ||
|
36 | COMPONENT LFR_EQM IS | |
|
37 | GENERIC ( | |
|
38 | Mem_use : INTEGER := use_RAM; | |
|
39 | USE_BOOTLOADER : INTEGER := 0; | |
|
40 | USE_ADCDRIVER : INTEGER := 1; | |
|
41 | tech : INTEGER := inferred; | |
|
42 | tech_leon : INTEGER := inferred; | |
|
43 | DEBUG_FORCE_DATA_DMA : INTEGER := 0; | |
|
44 | USE_DEBUG_VECTOR : INTEGER := 0 | |
|
45 | ); | |
|
46 | ||
|
47 | PORT ( | |
|
48 | clk50MHz : IN STD_ULOGIC; | |
|
49 | clk49_152MHz : IN STD_ULOGIC; | |
|
50 | reset : IN STD_ULOGIC; | |
|
51 | ||
|
52 | TAG : INOUT STD_LOGIC_VECTOR(9 DOWNTO 1); | |
|
53 | ||
|
54 | address : OUT STD_LOGIC_VECTOR(18 DOWNTO 0); | |
|
55 | data : INOUT STD_LOGIC_VECTOR(31 DOWNTO 0); | |
|
56 | ||
|
57 | nSRAM_MBE : INOUT STD_LOGIC; -- new | |
|
58 | nSRAM_E1 : OUT STD_LOGIC; -- new | |
|
59 | nSRAM_E2 : OUT STD_LOGIC; -- new | |
|
60 | -- nSRAM_SCRUB : OUT STD_LOGIC; -- new | |
|
61 | nSRAM_W : OUT STD_LOGIC; -- new | |
|
62 | nSRAM_G : OUT STD_LOGIC; -- new | |
|
63 | nSRAM_BUSY : IN STD_LOGIC; -- new | |
|
64 | -- SPW -------------------------------------------------------------------- | |
|
65 | spw1_en : OUT STD_LOGIC; -- new | |
|
66 | spw1_din : IN STD_LOGIC; | |
|
67 | spw1_sin : IN STD_LOGIC; | |
|
68 | spw1_dout : OUT STD_LOGIC; | |
|
69 | spw1_sout : OUT STD_LOGIC; | |
|
70 | spw2_en : OUT STD_LOGIC; -- new | |
|
71 | spw2_din : IN STD_LOGIC; | |
|
72 | spw2_sin : IN STD_LOGIC; | |
|
73 | spw2_dout : OUT STD_LOGIC; | |
|
74 | spw2_sout : OUT STD_LOGIC; | |
|
75 | -- ADC -------------------------------------------------------------------- | |
|
76 | bias_fail_sw : OUT STD_LOGIC; | |
|
77 | ADC_OEB_bar_CH : OUT STD_LOGIC_VECTOR(7 DOWNTO 0); | |
|
78 | ADC_smpclk : OUT STD_LOGIC; | |
|
79 | ADC_data : IN STD_LOGIC_VECTOR(13 DOWNTO 0); | |
|
80 | -- DAC -------------------------------------------------------------------- | |
|
81 | DAC_SDO : OUT STD_LOGIC; | |
|
82 | DAC_SCK : OUT STD_LOGIC; | |
|
83 | DAC_SYNC : OUT STD_LOGIC; | |
|
84 | DAC_CAL_EN : OUT STD_LOGIC; | |
|
85 | -- HK --------------------------------------------------------------------- | |
|
86 | HK_smpclk : OUT STD_LOGIC; | |
|
87 | ADC_OEB_bar_HK : OUT STD_LOGIC; | |
|
88 | HK_SEL : OUT STD_LOGIC_VECTOR(1 DOWNTO 0) | |
|
89 | ); | |
|
90 | ||
|
91 | END LFR_EQM; | |
|
92 | ||
|
93 | ||
|
94 | SIGNAL TSTAMP : INTEGER := 0; | |
|
95 | SIGNAL clk : STD_LOGIC := '0'; | |
|
96 | SIGNAL clk_24576Hz : STD_LOGIC := '0'; | |
|
97 | SIGNAL clk_24576Hz_r : STD_LOGIC := '0'; | |
|
98 | SIGNAL rstn : STD_LOGIC; | |
|
99 | ||
|
100 | SIGNAL signal_gen : sample_vector(0 to ChanelCount-1,17 downto 0); | |
|
101 | SIGNAL sample_fx_wdata : Samples(ChanelCount-1 DOWNTO 0); | |
|
102 | SIGNAL signal_rec : sample_vector(0 to ChanelCount-1,15 downto 0); | |
|
103 | ||
|
104 | SIGNAL end_of_simu : STD_LOGIC := '0'; | |
|
105 | ||
|
106 | CONSTANT half_samplig_period : time := 20345052 ps; --INTEGER( REAL(1000**4) / REAL(2.0*24576.0)) * 1 ps; | |
|
107 | ||
|
108 | BEGIN | |
|
109 | ||
|
110 | ----------------------------------------------------------------------------- | |
|
111 | -- CLOCK and RESET | |
|
112 | ----------------------------------------------------------------------------- | |
|
113 | PROCESS | |
|
114 | BEGIN -- PROCESS | |
|
115 | WAIT UNTIL clk = '1'; | |
|
116 | rstn <= '0'; | |
|
117 | WAIT UNTIL clk = '1'; | |
|
118 | WAIT UNTIL clk = '1'; | |
|
119 | WAIT UNTIL clk = '1'; | |
|
120 | rstn <= '1'; | |
|
121 | WAIT UNTIL end_of_simu = '1'; | |
|
122 | WAIT FOR 10 ps; | |
|
123 | assert false report "end of test" severity note; | |
|
124 | -- Wait forever; this will finish the simulation. | |
|
125 | wait; | |
|
126 | END PROCESS; | |
|
127 | ----------------------------------------------------------------------------- | |
|
128 | ||
|
129 | ||
|
130 | clk_24576Hz_gen:PROCESS | |
|
131 | BEGIN | |
|
132 | IF end_of_simu /= '1' THEN | |
|
133 | clk_24576Hz <= NOT clk_24576Hz; | |
|
134 | WAIT FOR half_samplig_period; | |
|
135 | ELSE | |
|
136 | WAIT FOR 10 ps; | |
|
137 | assert false report "end of test" severity note; | |
|
138 | WAIT; | |
|
139 | END IF; | |
|
140 | END PROCESS; | |
|
141 | ||
|
142 | clk_25M_gen:PROCESS | |
|
143 | BEGIN | |
|
144 | IF end_of_simu /= '1' THEN | |
|
145 | clk <= NOT clk; | |
|
146 | TSTAMP <= TSTAMP+20; | |
|
147 | WAIT FOR 20 ns; | |
|
148 | ELSE | |
|
149 | WAIT FOR 10 ps; | |
|
150 | assert false report "end of test" severity note; | |
|
151 | WAIT; | |
|
152 | END IF; | |
|
153 | END PROCESS; | |
|
154 | ||
|
155 | ||
|
156 | ----------------------------------------------------------------------------- | |
|
157 | -- LPP_LFR_FILTER f1 | |
|
158 | ----------------------------------------------------------------------------- | |
|
159 | ||
|
160 | IIR_CEL_f0_to_f1 : IIR_CEL_CTRLR_v2 | |
|
161 | GENERIC MAP ( | |
|
162 | tech => tech, | |
|
163 | Mem_use => Mem_use, -- use_RAM | |
|
164 | Sample_SZ => 18, | |
|
165 | Coef_SZ => f0_to_f1_COEFFICIENT_SIZE, | |
|
166 | Coef_Nb => f0_to_f1_CEL_NUMBER*5, | |
|
167 | Coef_sel_SZ => 5, | |
|
168 | Cels_count => f0_to_f1_CEL_NUMBER, | |
|
169 | ChanelsCount => ChanelCount, | |
|
170 | FILENAME => "" | |
|
171 | ) | |
|
172 | PORT MAP ( | |
|
173 | rstn => rstn, | |
|
174 | clk => clk, | |
|
175 | virg_pos => f0_to_f1_POINT_POSITION, | |
|
176 | coefs => coefs_iir_cel_f0_to_f1, | |
|
177 | ||
|
178 | sample_in_val => sample_val, | |
|
179 | sample_in => sample, | |
|
180 | sample_out_val => sample_fx_val, | |
|
181 | sample_out => sample_fx); | |
|
182 | ||
|
183 | ----------------------------------------------------------------------------- | |
|
184 | ||
|
185 | ||
|
186 | ----------------------------------------------------------------------------- | |
|
187 | -- SAMPLE GENERATION | |
|
188 | ----------------------------------------------------------------------------- | |
|
189 | ||
|
190 | ||
|
191 | PROCESS (clk, rstn) | |
|
192 | BEGIN -- PROCESS | |
|
193 | IF rstn = '0' THEN -- asynchronous reset (active low) | |
|
194 | sample_val <= '0'; | |
|
195 | clk_24576Hz_r <= '0'; | |
|
196 | ELSIF clk'EVENT AND clk = '1' THEN -- rising clock edge | |
|
197 | clk_24576Hz_r <= clk_24576Hz; | |
|
198 | IF clk_24576Hz = '1' AND clk_24576Hz_r = '0' THEN | |
|
199 | sample_val <= '1'; | |
|
200 | ELSE | |
|
201 | sample_val <= '0'; | |
|
202 | END IF; | |
|
203 | END IF; | |
|
204 | END PROCESS; | |
|
205 | ----------------------------------------------------------------------------- | |
|
206 | ||
|
207 | ChanelLoop : FOR i IN 0 TO ChanelCount-1 GENERATE | |
|
208 | SampleLoop : FOR j IN 0 TO 15 GENERATE | |
|
209 | sample_fx_wdata(i)(j) <= sample_fx(i,j); | |
|
210 | signal_rec(i,j) <= sample_fx_wdata(i)(j); | |
|
211 | sample(i,j) <= signal_gen(i,j); | |
|
212 | END GENERATE; | |
|
213 | sample(i,16) <= signal_gen(i,16); | |
|
214 | sample(i,17) <= signal_gen(i,17); | |
|
215 | END GENERATE; | |
|
216 | ||
|
217 | ||
|
218 | ||
|
219 | ----------------------------------------------------------------------------- | |
|
220 | -- READ INPUT SIGNALS | |
|
221 | ----------------------------------------------------------------------------- | |
|
222 | ||
|
223 | gen: sig_reader | |
|
224 | GENERIC MAP( | |
|
225 | FNAME => "input.txt", | |
|
226 | WIDTH => ChanelCount, | |
|
227 | RESOLUTION => 18, | |
|
228 | GAIN => 1.0 | |
|
229 | ) | |
|
230 | PORT MAP( | |
|
231 | clk => sample_val, | |
|
232 | end_of_simu => end_of_simu, | |
|
233 | out_signal => signal_gen | |
|
234 | ); | |
|
235 | ||
|
236 | ||
|
237 | ----------------------------------------------------------------------------- | |
|
238 | -- RECORD OUTPUT SIGNALS | |
|
239 | ----------------------------------------------------------------------------- | |
|
240 | ||
|
241 | rec : sig_recorder | |
|
242 | GENERIC MAP( | |
|
243 | FNAME => "output_fx.txt", | |
|
244 | WIDTH => ChanelCount, | |
|
245 | RESOLUTION => 16 | |
|
246 | ) | |
|
247 | PORT MAP( | |
|
248 | clk => sample_fx_val, | |
|
249 | end_of_simu => end_of_simu, | |
|
250 | timestamp => TSTAMP, | |
|
251 | input_signal => signal_rec | |
|
252 | ); | |
|
253 | ||
|
254 | END; |
@@ -9,3 +9,9 MANUFACTURER=Xilinx | |||
|
9 | 9 | MGCPART=XC6SLX25$(PACKAGE) |
|
10 | 10 | MGCTECHNOLOGY=SPARTAN-6 |
|
11 | 11 | MGCPACKAGE=$(PACKAGE) |
|
12 | ||
|
13 | config_USB_as_FIFO: | |
|
14 | ftdi_eeprom --flash-eeprom $(VHDLIB)/boards/$(BOARD)/ft2232h_JTAG_FIFO.conf | |
|
15 | ||
|
16 | config_USB_as_UART: | |
|
17 | ftdi_eeprom --flash-eeprom $(VHDLIB)/boards/$(BOARD)/ft2232h_JTAG_UART.conf |
@@ -1,64 +1,133 | |||
|
1 | 1 | # Clocks |
|
2 |
NET "CLK50" PERIOD = 20 ns | |
|
|
2 | NET "CLK50" PERIOD = 20 ns |LOC = "K3"; | |
|
3 | 3 | #NET "CLK32" PERIOD = 31.25 ns | LOC = "J4"; |
|
4 | ||
|
5 | 4 | # LEDs |
|
6 |
NET "LEDS<0>" LOC="P11" | |
|
|
7 |
NET "LEDS<1>" LOC="N9" | |
|
|
8 |
NET "LEDS<2>" LOC="M9" | |
|
|
9 |
NET "LEDS<3>" LOC="P9" | |
|
|
10 |
NET "LEDS<4>" LOC="T8" | |
|
|
11 |
NET "LEDS<5>" LOC="N8" | |
|
|
12 |
NET "LEDS<6>" LOC="P8" | |
|
|
13 |
NET "LEDS<7>" LOC="P7" | |
|
|
5 | NET "LEDS<0>" LOC="P11" |IOSTANDARD=LVTTL |DRIVE=8 |SLEW=SLOW; | |
|
6 | NET "LEDS<1>" LOC="N9" |IOSTANDARD=LVTTL |DRIVE=8 |SLEW=SLOW; | |
|
7 | NET "LEDS<2>" LOC="M9" |IOSTANDARD=LVTTL |DRIVE=8 |SLEW=SLOW; | |
|
8 | NET "LEDS<3>" LOC="P9" |IOSTANDARD=LVTTL |DRIVE=8 |SLEW=SLOW; | |
|
9 | NET "LEDS<4>" LOC="T8" |IOSTANDARD=LVTTL |DRIVE=8 |SLEW=SLOW; | |
|
10 | NET "LEDS<5>" LOC="N8" |IOSTANDARD=LVTTL |DRIVE=8 |SLEW=SLOW; | |
|
11 | NET "LEDS<6>" LOC="P8" |IOSTANDARD=LVTTL |DRIVE=8 |SLEW=SLOW; | |
|
12 | NET "LEDS<7>" LOC="P7" |IOSTANDARD=LVTTL |DRIVE=8 |SLEW=SLOW; | |
|
14 | 13 | |
|
15 | 14 | # DIP Switches |
|
16 |
NET "SW<1>" LOC="L1" | |
|
|
17 |
NET "SW<2>" LOC="L3" | |
|
|
18 |
NET "SW<3>" LOC="L4" | |
|
|
19 |
NET "SW<4>" LOC="L5" | |
|
|
15 | NET "SW<1>" LOC="L1" |IOSTANDARD=LVTTL |PULLUP; | |
|
16 | NET "SW<2>" LOC="L3" |IOSTANDARD=LVTTL |PULLUP; | |
|
17 | NET "SW<3>" LOC="L4" |IOSTANDARD=LVTTL |PULLUP; | |
|
18 | NET "SW<4>" LOC="L5" |IOSTANDARD=LVTTL |PULLUP; | |
|
20 | 19 | |
|
21 |
NET "uart_rxd" LOC="M7" | |
|
|
22 |
NET "uart_txd" LOC="N6" | |
|
|
20 | NET "uart_rxd" LOC="M7" |IOSTANDARD=LVTTL; | |
|
21 | NET "uart_txd" LOC="N6" |IOSTANDARD=LVTTL; | |
|
23 | 22 | |
|
24 | 23 | # SDRAM |
|
25 |
NET "dram_udqm" LOC="F15" | |
|
|
26 |
NET "dram_clk" LOC="G16" | |
|
|
27 |
NET "dram_cke" LOC="H16" | |
|
|
28 |
NET "dram_ba_1" LOC="T14" | |
|
|
29 |
NET "dram_ba_0" LOC="R14" | |
|
|
30 |
NET "dram_cs_n" LOC="R1" | |
|
|
31 |
NET "dram_ras_n" LOC="R2" | |
|
|
32 |
NET "dram_cas_n" LOC="T4" | |
|
|
33 |
NET "dram_we_n" LOC="R5" | |
|
|
34 |
NET "dram_ldqm" LOC="T5" | |
|
|
35 |
NET "dram_addr<0>" LOC="T15" | |
|
|
36 |
NET "dram_addr<1>" LOC="R16" | |
|
|
37 |
NET "dram_addr<2>" LOC="P15" | |
|
|
38 |
NET "dram_addr<3>" LOC="P16" | |
|
|
39 |
NET "dram_addr<4>" LOC="N16" | |
|
|
40 |
NET "dram_addr<5>" LOC="M15" | |
|
|
41 |
NET "dram_addr<6>" LOC="M16" | |
|
|
42 |
NET "dram_addr<7>" LOC="L16" | |
|
|
43 |
NET "dram_addr<8>" LOC="K15" | |
|
|
44 |
NET "dram_addr<9>" LOC="K16" | |
|
|
45 |
NET "dram_addr<10>" LOC="R15" | |
|
|
46 |
NET "dram_addr<11>" LOC="J16" | |
|
|
47 |
NET "dram_addr<12>" LOC="H15" | |
|
|
48 |
NET "dram_dq<0>" LOC="T13" | |
|
|
49 |
NET "dram_dq<1>" LOC="T12" | |
|
|
50 |
NET "dram_dq<2>" LOC="R12" | |
|
|
51 |
NET "dram_dq<3>" LOC="T9" | |
|
|
52 |
NET "dram_dq<4>" LOC="R9" | |
|
|
53 |
NET "dram_dq<5>" LOC="T7" | |
|
|
54 |
NET "dram_dq<6>" LOC="R7" | |
|
|
55 |
NET "dram_dq<7>" LOC="T6" | |
|
|
56 |
NET "dram_dq<8>" LOC="F16" | |
|
|
57 |
NET "dram_dq<9>" LOC="E15" | |
|
|
58 |
NET "dram_dq<10>" LOC="E16" | |
|
|
59 |
NET "dram_dq<11>" LOC="D16" | |
|
|
60 |
NET "dram_dq<12>" LOC="B16" | |
|
|
61 |
NET "dram_dq<13>" LOC="B15" | |
|
|
62 |
NET "dram_dq<14>" LOC="C16" | |
|
|
63 |
NET "dram_dq<15>" LOC="C15" | |
|
|
64 | ||
|
24 | NET "dram_udqm" LOC="F15" |IOSTANDARD=LVTTL; | |
|
25 | NET "dram_clk" LOC="G16" |IOSTANDARD=LVTTL; | |
|
26 | NET "dram_cke" LOC="H16" |IOSTANDARD=LVTTL; | |
|
27 | NET "dram_ba_1" LOC="T14" |IOSTANDARD=LVTTL; | |
|
28 | NET "dram_ba_0" LOC="R14" |IOSTANDARD=LVTTL; | |
|
29 | NET "dram_cs_n" LOC="R1" |IOSTANDARD=LVTTL; | |
|
30 | NET "dram_ras_n" LOC="R2" |IOSTANDARD=LVTTL; | |
|
31 | NET "dram_cas_n" LOC="T4" |IOSTANDARD=LVTTL; | |
|
32 | NET "dram_we_n" LOC="R5" |IOSTANDARD=LVTTL; | |
|
33 | NET "dram_ldqm" LOC="T5" |IOSTANDARD=LVTTL; | |
|
34 | NET "dram_addr<0>" LOC="T15" |IOSTANDARD=LVTTL; | |
|
35 | NET "dram_addr<1>" LOC="R16" |IOSTANDARD=LVTTL; | |
|
36 | NET "dram_addr<2>" LOC="P15" |IOSTANDARD=LVTTL; | |
|
37 | NET "dram_addr<3>" LOC="P16" |IOSTANDARD=LVTTL; | |
|
38 | NET "dram_addr<4>" LOC="N16" |IOSTANDARD=LVTTL; | |
|
39 | NET "dram_addr<5>" LOC="M15" |IOSTANDARD=LVTTL; | |
|
40 | NET "dram_addr<6>" LOC="M16" |IOSTANDARD=LVTTL; | |
|
41 | NET "dram_addr<7>" LOC="L16" |IOSTANDARD=LVTTL; | |
|
42 | NET "dram_addr<8>" LOC="K15" |IOSTANDARD=LVTTL; | |
|
43 | NET "dram_addr<9>" LOC="K16" |IOSTANDARD=LVTTL; | |
|
44 | NET "dram_addr<10>" LOC="R15" |IOSTANDARD=LVTTL; | |
|
45 | NET "dram_addr<11>" LOC="J16" |IOSTANDARD=LVTTL; | |
|
46 | NET "dram_addr<12>" LOC="H15" |IOSTANDARD=LVTTL; | |
|
47 | NET "dram_dq<0>" LOC="T13" |IOSTANDARD=LVTTL; | |
|
48 | NET "dram_dq<1>" LOC="T12" |IOSTANDARD=LVTTL; | |
|
49 | NET "dram_dq<2>" LOC="R12" |IOSTANDARD=LVTTL; | |
|
50 | NET "dram_dq<3>" LOC="T9" |IOSTANDARD=LVTTL; | |
|
51 | NET "dram_dq<4>" LOC="R9" |IOSTANDARD=LVTTL; | |
|
52 | NET "dram_dq<5>" LOC="T7" |IOSTANDARD=LVTTL; | |
|
53 | NET "dram_dq<6>" LOC="R7" |IOSTANDARD=LVTTL; | |
|
54 | NET "dram_dq<7>" LOC="T6" |IOSTANDARD=LVTTL; | |
|
55 | NET "dram_dq<8>" LOC="F16" |IOSTANDARD=LVTTL; | |
|
56 | NET "dram_dq<9>" LOC="E15" |IOSTANDARD=LVTTL; | |
|
57 | NET "dram_dq<10>" LOC="E16" |IOSTANDARD=LVTTL; | |
|
58 | NET "dram_dq<11>" LOC="D16" |IOSTANDARD=LVTTL; | |
|
59 | NET "dram_dq<12>" LOC="B16" |IOSTANDARD=LVTTL; | |
|
60 | NET "dram_dq<13>" LOC="B15" |IOSTANDARD=LVTTL; | |
|
61 | NET "dram_dq<14>" LOC="C16" |IOSTANDARD=LVTTL; | |
|
62 | NET "dram_dq<15>" LOC="C15" |IOSTANDARD=LVTTL; | |
|
63 | #Created by Constraints Editor (xc6slx25-ftg256-3) - 2016/12/08 | |
|
64 | INST "dram_addr(0)" TNM = dram_addr; | |
|
65 | INST "dram_addr(1)" TNM = dram_addr; | |
|
66 | INST "dram_addr(2)" TNM = dram_addr; | |
|
67 | INST "dram_addr(3)" TNM = dram_addr; | |
|
68 | INST "dram_addr(4)" TNM = dram_addr; | |
|
69 | INST "dram_addr(5)" TNM = dram_addr; | |
|
70 | INST "dram_addr(6)" TNM = dram_addr; | |
|
71 | INST "dram_addr(7)" TNM = dram_addr; | |
|
72 | INST "dram_addr(8)" TNM = dram_addr; | |
|
73 | INST "dram_addr(9)" TNM = dram_addr; | |
|
74 | INST "dram_addr(10)" TNM = dram_addr; | |
|
75 | INST "dram_addr(11)" TNM = dram_addr; | |
|
76 | INST "dram_addr(12)" TNM = dram_addr; | |
|
77 | INST "dram_addr(0)" TNM = dram_out; | |
|
78 | INST "dram_addr(1)" TNM = dram_out; | |
|
79 | INST "dram_addr(2)" TNM = dram_out; | |
|
80 | INST "dram_addr(3)" TNM = dram_out; | |
|
81 | INST "dram_addr(4)" TNM = dram_out; | |
|
82 | INST "dram_addr(5)" TNM = dram_out; | |
|
83 | INST "dram_addr(6)" TNM = dram_out; | |
|
84 | INST "dram_addr(7)" TNM = dram_out; | |
|
85 | INST "dram_addr(8)" TNM = dram_out; | |
|
86 | INST "dram_addr(9)" TNM = dram_out; | |
|
87 | INST "dram_addr(10)" TNM = dram_out; | |
|
88 | INST "dram_addr(11)" TNM = dram_out; | |
|
89 | INST "dram_addr(12)" TNM = dram_out; | |
|
90 | INST "dram_ba_0" TNM = dram_out; | |
|
91 | INST "dram_ba_1" TNM = dram_out; | |
|
92 | INST "dram_cas_n" TNM = dram_out; | |
|
93 | INST "dram_cke" TNM = dram_out; | |
|
94 | #INST "dram_clk" TNM = dram_out; | |
|
95 | INST "dram_cs_n" TNM = dram_out; | |
|
96 | INST "dram_dq(0)" TNM = dram_out; | |
|
97 | INST "dram_dq(1)" TNM = dram_out; | |
|
98 | INST "dram_dq(2)" TNM = dram_out; | |
|
99 | INST "dram_dq(3)" TNM = dram_out; | |
|
100 | INST "dram_dq(4)" TNM = dram_out; | |
|
101 | INST "dram_dq(5)" TNM = dram_out; | |
|
102 | INST "dram_dq(6)" TNM = dram_out; | |
|
103 | INST "dram_dq(7)" TNM = dram_out; | |
|
104 | INST "dram_dq(8)" TNM = dram_out; | |
|
105 | INST "dram_dq(9)" TNM = dram_out; | |
|
106 | INST "dram_dq(10)" TNM = dram_out; | |
|
107 | INST "dram_dq(11)" TNM = dram_out; | |
|
108 | INST "dram_dq(12)" TNM = dram_out; | |
|
109 | INST "dram_dq(13)" TNM = dram_out; | |
|
110 | INST "dram_dq(14)" TNM = dram_out; | |
|
111 | INST "dram_dq(15)" TNM = dram_out; | |
|
112 | INST "dram_ldqm" TNM = dram_out; | |
|
113 | INST "dram_ras_n" TNM = dram_out; | |
|
114 | INST "dram_udqm" TNM = dram_out; | |
|
115 | INST "dram_we_n" TNM = dram_out; | |
|
116 | TIMEGRP "dram_out" OFFSET = OUT 12 ns AFTER "CLK50"; | |
|
117 | INST "dram_dq(0)" TNM = dram_in; | |
|
118 | INST "dram_dq(1)" TNM = dram_in; | |
|
119 | INST "dram_dq(2)" TNM = dram_in; | |
|
120 | INST "dram_dq(3)" TNM = dram_in; | |
|
121 | INST "dram_dq(4)" TNM = dram_in; | |
|
122 | INST "dram_dq(5)" TNM = dram_in; | |
|
123 | INST "dram_dq(6)" TNM = dram_in; | |
|
124 | INST "dram_dq(7)" TNM = dram_in; | |
|
125 | INST "dram_dq(8)" TNM = dram_in; | |
|
126 | INST "dram_dq(9)" TNM = dram_in; | |
|
127 | INST "dram_dq(10)" TNM = dram_in; | |
|
128 | INST "dram_dq(11)" TNM = dram_in; | |
|
129 | INST "dram_dq(12)" TNM = dram_in; | |
|
130 | INST "dram_dq(13)" TNM = dram_in; | |
|
131 | INST "dram_dq(14)" TNM = dram_in; | |
|
132 | INST "dram_dq(15)" TNM = dram_in; | |
|
133 | TIMEGRP "dram_in" OFFSET = IN 3 ns BEFORE "CLK50" RISING; |
@@ -47,4 +47,6 PACKAGE apb_devices_list IS | |||
|
47 | 47 | CONSTANT LPP_APB_ADVANCED_TRIGGER : amba_device_type := 16#A3#; |
|
48 | 48 | CONSTANT LPP_APB_ADVANCED_TRIGGER_v : amba_device_type := 16#A4#; |
|
49 | 49 | |
|
50 | CONSTANT LPP_AHB_FTDI_FIFO : amba_device_type := 16#A5#; | |
|
51 | ||
|
50 | 52 | END; |
@@ -1,4 +1,5 | |||
|
1 | 1 | lpp_sim_pkg.vhd |
|
2 | 2 | sig_reader.vhd |
|
3 | 3 | sig_recorder.vhd |
|
4 | lpp_sim_pkg.vhd | |
|
4 | 5 | lpp_lfr_sim_pkg.vhd |
@@ -24,6 +24,8 use ieee.std_logic_1164.all; | |||
|
24 | 24 | library grlib; |
|
25 | 25 | use grlib.amba.all; |
|
26 | 26 | use std.textio.all; |
|
27 | library gaisler; | |
|
28 | use gaisler.libdcom.all; | |
|
27 | 29 | library lpp; |
|
28 | 30 | use lpp.lpp_amba.all; |
|
29 | 31 | |
@@ -31,6 +33,71 use lpp.lpp_amba.all; | |||
|
31 | 33 | |
|
32 | 34 | package lpp_usb is |
|
33 | 35 | |
|
36 | component ahb_ftdi_fifo is | |
|
37 | generic ( | |
|
38 | oepol : integer := 0; | |
|
39 | hindex : integer := 0 | |
|
40 | ); | |
|
41 | port ( | |
|
42 | clk : in std_logic; | |
|
43 | rstn : in std_logic; | |
|
44 | ||
|
45 | ahbi : in ahb_mst_in_type; | |
|
46 | ahbo : out ahb_mst_out_type; | |
|
47 | ||
|
48 | FTDI_RXF : in std_logic; | |
|
49 | FTDI_TXE : in std_logic; | |
|
50 | FTDI_SIWUA : out std_logic; | |
|
51 | FTDI_WR : out std_logic; | |
|
52 | FTDI_RD : out std_logic; | |
|
53 | FTDI_D_in : in std_logic_vector(7 downto 0); | |
|
54 | FTDI_D_out : out std_logic_vector(7 downto 0); | |
|
55 | FTDI_D_drive : out std_logic | |
|
56 | ); | |
|
57 | end component; | |
|
58 | ||
|
59 | component ftdi_async_fifo is | |
|
60 | generic ( | |
|
61 | oepol : integer := 0 | |
|
62 | ); | |
|
63 | port ( | |
|
64 | clk : in std_logic; | |
|
65 | rstn : in std_logic; | |
|
66 | ||
|
67 | dcom_in : in dcom_uart_in_type; | |
|
68 | dcom_out : out dcom_uart_out_type; | |
|
69 | ||
|
70 | FTDI_RXF : in std_logic; | |
|
71 | FTDI_TXE : in std_logic; | |
|
72 | FTDI_SIWUA : out std_logic; | |
|
73 | FTDI_WR : out std_logic; | |
|
74 | FTDI_RD : out std_logic; | |
|
75 | FTDI_D_in : in std_logic_vector(7 downto 0); | |
|
76 | FTDI_D_out : out std_logic_vector(7 downto 0); | |
|
77 | FTDI_D_drive : out std_logic | |
|
78 | ); | |
|
79 | end component; | |
|
80 | ||
|
81 | component ftdi_async_fifo_loopback is | |
|
82 | generic ( | |
|
83 | oepol : integer := 0 | |
|
84 | ); | |
|
85 | port ( | |
|
86 | clk : in std_logic; | |
|
87 | rstn : in std_logic; | |
|
88 | ||
|
89 | ||
|
90 | FTDI_RXF : in std_logic; | |
|
91 | FTDI_TXE : in std_logic; | |
|
92 | FTDI_SIWUA : out std_logic; | |
|
93 | FTDI_WR : out std_logic; | |
|
94 | FTDI_RD : out std_logic; | |
|
95 | FTDI_D_in : in std_logic_vector(7 downto 0); | |
|
96 | FTDI_D_out : out std_logic_vector(7 downto 0); | |
|
97 | FTDI_D_drive : out std_logic | |
|
98 | ); | |
|
99 | end component; | |
|
100 | ||
|
34 | 101 | component FX2_Driver is |
|
35 | 102 | port( |
|
36 | 103 | clk : in STD_LOGIC; |
@@ -120,4 +187,4 end component; | |||
|
120 | 187 | ); |
|
121 | 188 | end component; |
|
122 | 189 | |
|
123 | end package; No newline at end of file | |
|
190 | end package; |
@@ -39,10 +39,15 if [ -d "$GRLIBPATH" ]; then | |||
|
39 | 39 | |
|
40 | 40 | echo "Patch $1/lib/libs.txt..." |
|
41 | 41 | if(grep -q $LPP_PATCHPATH/lib/lpp $1/lib/libs.txt); then |
|
42 |
echo "No need to |
|
|
42 | echo "No need to add lpp in $1/lib/libs.txt..." | |
|
43 | 43 | else |
|
44 | 44 | echo $LPP_PATCHPATH/lib/lpp >>$1/lib/libs.txt |
|
45 | 45 | fi |
|
46 | if(grep -q $LPP_PATCHPATH/lib/opencores $1/lib/libs.txt); then | |
|
47 | echo "No need to add opencores in $1/lib/libs.txt..." | |
|
48 | else | |
|
49 | echo $LPP_PATCHPATH/lib/opencores >>$1/lib/libs.txt | |
|
50 | fi | |
|
46 | 51 | echo |
|
47 | 52 | echo |
|
48 | 53 | echo |
|
1 | NO CONTENT: file was removed |
|
1 | NO CONTENT: file was removed |
|
1 | NO CONTENT: file was removed |
|
1 | NO CONTENT: file was removed |
|
1 | NO CONTENT: file was removed |
|
1 | NO CONTENT: file was removed |
|
1 | NO CONTENT: file was removed |
|
1 | NO CONTENT: file was removed |
|
1 | NO CONTENT: file was removed |
|
1 | NO CONTENT: file was removed |
|
1 | NO CONTENT: file was removed |
|
1 | NO CONTENT: file was removed |
|
1 | NO CONTENT: file was removed |
|
1 | NO CONTENT: file was removed |
|
1 | NO CONTENT: file was removed |
|
1 | NO CONTENT: file was removed |
|
1 | NO CONTENT: file was removed |
|
1 | NO CONTENT: file was removed |
|
1 | NO CONTENT: file was removed |
|
1 | NO CONTENT: file was removed |
|
1 | NO CONTENT: file was removed |
|
1 | NO CONTENT: file was removed |
|
1 | NO CONTENT: file was removed |
|
1 | NO CONTENT: file was removed | |
This diff has been collapsed as it changes many lines, (521 lines changed) Show them Hide them |
|
1 | NO CONTENT: file was removed |
|
1 | NO CONTENT: file was removed |
|
1 | NO CONTENT: file was removed |
|
1 | NO CONTENT: file was removed |
|
1 | NO CONTENT: file was removed |
|
1 | NO CONTENT: file was removed |
|
1 | NO CONTENT: file was removed |
|
1 | NO CONTENT: file was removed |
|
1 | NO CONTENT: file was removed |
|
1 | NO CONTENT: file was removed |
|
1 | NO CONTENT: file was removed |
|
1 | NO CONTENT: file was removed |
|
1 | NO CONTENT: file was removed |
|
1 | NO CONTENT: file was removed |
|
1 | NO CONTENT: file was removed |
General Comments 0
You need to be logged in to leave comments.
Login now