-
Notifications
You must be signed in to change notification settings - Fork 69
/
Copy pathSdramCntl.vhd
1356 lines (1216 loc) · 73.2 KB
/
SdramCntl.vhd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
--**********************************************************************
-- Copyright (c) 2001-2014 by XESS Corp <http://www.xess.com>.
-- All rights reserved.
--
-- This library is free software; you can redistribute it and/or
-- modify it under the terms of the GNU Lesser General Public
-- License as published by the Free Software Foundation; either
-- version 3.0 of the License, or (at your option) any later version.
--
-- This library is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-- Lesser General Public License for more details.
--
-- You should have received a copy of the GNU Lesser General Public
-- License along with this library. If not, see
-- <http://www.gnu.org/licenses/>.
--**********************************************************************
--*********************************************************************
-- SDRAM controller and dual-port interface.
--*********************************************************************
library IEEE, XESS;
use IEEE.std_logic_1164.all;
use XESS.CommonPckg.all;
use work.XessBoardPckg.all;
package SdramCntlPckg is
component SdramCntl is
generic(
FREQ_G : real := SDRAM_FREQ_C; -- Operating frequency in MHz.
IN_PHASE_G : boolean := SDRAM_IN_PHASE_C; -- SDRAM and controller XESS on same or opposite clock edge.
PIPE_EN_G : boolean := SDRAM_PIPE_EN_C; -- If true, enable pipelined read operations.
MAX_NOP_G : natural := SDRAM_MAX_NOP_C; -- Number of NOPs before entering self-refresh.
ENABLE_REFRESH_G : boolean := SDRAM_ENABLE_REFRESH_C; -- If true, row refreshes are automatically inserted.
MULTIPLE_ACTIVE_ROWS_G : boolean := SDRAM_MULTIPLE_ACTIVE_ROWS_C; -- If true, allow an active row in each bank.
-- Parameters for SDRAM.
DATA_WIDTH_G : natural := SDRAM_DATA_WIDTH_C; -- Host & SDRAM data width.
NROWS_G : natural := SDRAM_NROWS_C; -- Number of rows in SDRAM array.
NCOLS_G : natural := SDRAM_NCOLS_C; -- Number of columns in SDRAM array.
HADDR_WIDTH_G : natural := SDRAM_HADDR_WIDTH_C; -- Host-side address width.
SADDR_WIDTH_G : natural := SDRAM_SADDR_WIDTH_C; -- SDRAM-side address width.
T_INIT_G : real := SDRAM_T_INIT_C; -- min initialization interval (ns).
T_RAS_G : real := SDRAM_T_RAS_C; -- min interval between active to precharge commands (ns).
T_RCD_G : real := SDRAM_T_RCD_C; -- min interval between active and R/W commands (ns).
T_REF_G : real := SDRAM_T_REF_C; -- maximum refresh interval (ns).
T_RFC_G : real := SDRAM_T_RFC_C; -- duration of refresh operation (ns).
T_RP_G : real := SDRAM_T_RP_C; -- min precharge command duration (ns).
T_XSR_G : real := SDRAM_T_XSR_C -- exit self-refresh time (ns).
);
port(
-- Host side.
clk_i : in std_logic; -- Master clock.
lock_i : in std_logic := YES; -- True if clock is stable.
rst_i : in std_logic := NO; -- Reset.
rd_i : in std_logic := NO; -- Initiate read operation.
wr_i : in std_logic := NO; -- Initiate write operation.
earlyOpBegun_o : out std_logic; -- Read/write/self-refresh op has begun (async).
opBegun_o : out std_logic; -- Read/write/self-refresh op has begun (clocked).
rdPending_o : out std_logic; -- True if read operation(s) are still in the pipeline.
done_o : out std_logic; -- Read or write operation is done_o.
rdDone_o : out std_logic; -- Read operation is done_o and data is available.
addr_i : in std_logic_vector(HADDR_WIDTH_G-1 downto 0) := (others => ZERO); -- Address from host to SDRAM.
data_i : in std_logic_vector(DATA_WIDTH_G-1 downto 0) := (others => ZERO); -- Data from host to SDRAM.
data_o : out std_logic_vector(DATA_WIDTH_G-1 downto 0); -- Data from SDRAM to host.
status_o : out std_logic_vector(3 downto 0); -- Diagnostic status of the FSM .
-- SDRAM side.
sdCke_o : out std_logic; -- Clock-enable to SDRAM.
sdCe_bo : out std_logic; -- Chip-select to SDRAM.
sdRas_bo : out std_logic; -- SDRAM row address strobe.
sdCas_bo : out std_logic; -- SDRAM column address strobe.
sdWe_bo : out std_logic; -- SDRAM write enable.
sdBs_o : out std_logic_vector(1 downto 0); -- SDRAM bank address.
sdAddr_o : out std_logic_vector(SADDR_WIDTH_G-1 downto 0); -- SDRAM row/column address.
sdData_io : inout std_logic_vector(DATA_WIDTH_G-1 downto 0); -- Data to/from SDRAM.
sdDqmh_o : out std_logic; -- Enable upper-byte of SDRAM databus if true.
sdDqml_o : out std_logic -- Enable lower-byte of SDRAM databus if true.
);
end component;
component DualPort is
generic(
PIPE_EN_G : boolean := SDRAM_PIPE_EN_C; -- enable pipelined read operations.
PORT_TIME_SLOTS_G : std_logic_vector(15 downto 0) := "1111000011110000";
DATA_WIDTH_G : natural := SDRAM_DATA_WIDTH_C; -- host & SDRAM data width.
HADDR_WIDTH_G : natural := SDRAM_HADDR_WIDTH_C -- host-side address width.
);
port(
clk_i : in std_logic; -- master clock.
-- Host-side port 0.
rst0_i : in std_logic := NO; -- reset.
rd0_i : in std_logic := NO; -- initiate read operation.
wr0_i : in std_logic := NO; -- initiate write operation.
earlyOpBegun0_o : out std_logic; -- read/write op has begun (async).
opBegun0_o : out std_logic := NO; -- read/write op has begun (clocked).
rdPending0_o : out std_logic; -- true if read operation(s) are still in the pipeline.
done0_o : out std_logic; -- read or write operation is done_i.
rdDone0_o : out std_logic; -- read operation is done_i and data is available.
addr0_i : in std_logic_vector(HADDR_WIDTH_G-1 downto 0) := (others => ZERO); -- address from host to SDRAM.
data0_i : in std_logic_vector(DATA_WIDTH_G-1 downto 0) := (others => ZERO); -- data from host to SDRAM.
data0_o : out std_logic_vector(DATA_WIDTH_G-1 downto 0) := (others => ZERO); -- data from SDRAM to host.
status0_o : out std_logic_vector(3 downto 0); -- diagnostic status of the SDRAM controller FSM .
-- Host-side port 1.
rst1_i : in std_logic := NO;
rd1_i : in std_logic := NO;
wr1_i : in std_logic := NO;
earlyOpBegun1_o : out std_logic;
opBegun1_o : out std_logic := NO;
rdPending1_o : out std_logic;
done1_o : out std_logic;
rdDone1_o : out std_logic;
addr1_i : in std_logic_vector(HADDR_WIDTH_G-1 downto 0) := (others => ZERO);
data1_i : in std_logic_vector(DATA_WIDTH_G-1 downto 0) := (others => ZERO);
data1_o : out std_logic_vector(DATA_WIDTH_G-1 downto 0) := (others => ZERO);
status1_o : out std_logic_vector(3 downto 0);
-- SDRAM controller host-side port.
rst_o : out std_logic;
rd_o : out std_logic;
wr_o : out std_logic;
earlyOpBegun_i : in std_logic;
opBegun_i : in std_logic;
rdPending_i : in std_logic;
done_i : in std_logic;
rdDone_i : in std_logic;
addr_o : out std_logic_vector(HADDR_WIDTH_G-1 downto 0);
data_o : out std_logic_vector(DATA_WIDTH_G-1 downto 0);
data_i : in std_logic_vector(DATA_WIDTH_G-1 downto 0);
status_i : in std_logic_vector(3 downto 0)
);
end component;
component DualPortSdram is
generic(
PORT_TIME_SLOTS_G : std_logic_vector(15 downto 0) := "1111000011110000";
FREQ_G : real := SDRAM_FREQ_C; -- Operating frequency in MHz.
IN_PHASE_G : boolean := SDRAM_IN_PHASE_C; -- SDRAM and controller XESS on same or opposite clock edge.
PIPE_EN_G : boolean := SDRAM_PIPE_EN_C; -- If true, enable pipelined read operations.
MAX_NOP_G : natural := SDRAM_MAX_NOP_C; -- Number of NOPs before entering self-refresh.
ENABLE_REFRESH_G : boolean := SDRAM_ENABLE_REFRESH_C; -- If true, row refreshes are automatically inserted.
MULTIPLE_ACTIVE_ROWS_G : boolean := SDRAM_MULTIPLE_ACTIVE_ROWS_C; -- If true, allow an active row in each bank.
-- Parameters for SDRAM.
DATA_WIDTH_G : natural := SDRAM_DATA_WIDTH_C; -- Host & SDRAM data width.
NROWS_G : natural := SDRAM_NROWS_C; -- Number of rows in SDRAM array.
NCOLS_G : natural := SDRAM_NCOLS_C; -- Number of columns in SDRAM array.
HADDR_WIDTH_G : natural := SDRAM_HADDR_WIDTH_C; -- Host-side address width.
SADDR_WIDTH_G : natural := SDRAM_SADDR_WIDTH_C; -- SDRAM-side address width.
T_INIT_G : real := SDRAM_T_INIT_C; -- min initialization interval (ns).
T_RAS_G : real := SDRAM_T_RAS_C; -- min interval between active to precharge commands (ns).
T_RCD_G : real := SDRAM_T_RCD_C; -- min interval between active and R/W commands (ns).
T_REF_G : real := SDRAM_T_REF_C; -- maximum refresh interval (ns).
T_RFC_G : real := SDRAM_T_RFC_C; -- duration of refresh operation (ns).
T_RP_G : real := SDRAM_T_RP_C; -- min precharge command duration (ns).
T_XSR_G : real := SDRAM_T_XSR_C -- exit self-refresh time (ns).
);
port(
clk_i : in std_logic; -- master clock.
-- Host-side port 0.
rst0_i : in std_logic := NO; -- reset.
rd0_i : in std_logic := NO; -- initiate read operation.
wr0_i : in std_logic := NO; -- initiate write operation.
earlyOpBegun0_o : out std_logic; -- read/write op has begun (async).
opBegun0_o : out std_logic := NO; -- read/write op has begun (clocked).
rdPending0_o : out std_logic; -- true if read operation(s) are still in the pipeline.
done0_o : out std_logic; -- read or write operation is done_i.
rdDone0_o : out std_logic; -- read operation is done_i and data is available.
addr0_i : in std_logic_vector(HADDR_WIDTH_G-1 downto 0) := (others => ZERO); -- address from host to SDRAM.
data0_i : in std_logic_vector(DATA_WIDTH_G-1 downto 0) := (others => ZERO); -- data from host to SDRAM.
data0_o : out std_logic_vector(DATA_WIDTH_G-1 downto 0) := (others => ZERO); -- data from SDRAM to host.
status0_o : out std_logic_vector(3 downto 0); -- diagnostic status of the SDRAM controller FSM .
-- Host-side port 1.
rst1_i : in std_logic := NO;
rd1_i : in std_logic := NO;
wr1_i : in std_logic := NO;
earlyOpBegun1_o : out std_logic;
opBegun1_o : out std_logic := NO;
rdPending1_o : out std_logic;
done1_o : out std_logic;
rdDone1_o : out std_logic;
addr1_i : in std_logic_vector(HADDR_WIDTH_G-1 downto 0) := (others => ZERO);
data1_i : in std_logic_vector(DATA_WIDTH_G-1 downto 0) := (others => ZERO);
data1_o : out std_logic_vector(DATA_WIDTH_G-1 downto 0) := (others => ZERO);
status1_o : out std_logic_vector(3 downto 0);
-- SDRAM side.
sdCke_o : out std_logic; -- Clock-enable to SDRAM.
sdCe_bo : out std_logic; -- Chip-select to SDRAM.
sdRas_bo : out std_logic; -- SDRAM row address strobe.
sdCas_bo : out std_logic; -- SDRAM column address strobe.
sdWe_bo : out std_logic; -- SDRAM write enable.
sdBs_o : out std_logic_vector(1 downto 0); -- SDRAM bank address.
sdAddr_o : out std_logic_vector(SADDR_WIDTH_G-1 downto 0); -- SDRAM row/column address.
sdData_io : inout std_logic_vector(DATA_WIDTH_G-1 downto 0); -- Data to/from SDRAM.
sdDqmh_o : out std_logic; -- Enable upper-byte of SDRAM databus if true.
sdDqml_o : out std_logic -- Enable lower-byte of SDRAM databus if true.
);
end component;
component RWHandshake is
port (
rd_i : in std_logic; -- Read control signal.
rd_o : out std_logic; -- Read control signal that goes to host-side of SDRAM controller.
wr_i : in std_logic; -- Write control signal.
wr_o : out std_logic; -- Write control signal that goes to host-side of SDRAM controller.
done_i : in std_logic; -- R/W op done signal from host-side of SDRAM controller.
done_o : out std_logic -- R/W done status signal.
);
end component;
end package;
--*********************************************************************
-- SDRAM controller.
--*********************************************************************
library IEEE, UNISIM, XESS;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_unsigned.all;
use IEEE.numeric_std.all;
use IEEE.math_real.all;
use XESS.CommonPckg.all;
use work.XessBoardPckg.all;
entity SdramCntl is
generic(
FREQ_G : real := SDRAM_FREQ_C; -- Operating frequency in MHz.
IN_PHASE_G : boolean := SDRAM_IN_PHASE_C; -- SDRAM and controller XESS on same or opposite clock edge.
PIPE_EN_G : boolean := SDRAM_PIPE_EN_C; -- If true, enable pipelined read operations.
MAX_NOP_G : natural := SDRAM_MAX_NOP_C; -- Number of NOPs before entering self-refresh.
ENABLE_REFRESH_G : boolean := SDRAM_ENABLE_REFRESH_C; -- If true, row refreshes are automatically inserted.
MULTIPLE_ACTIVE_ROWS_G : boolean := SDRAM_MULTIPLE_ACTIVE_ROWS_C; -- If true, allow an active row in each bank.
-- Parameters for SDRAM.
DATA_WIDTH_G : natural := SDRAM_DATA_WIDTH_C; -- Host & SDRAM data width.
NROWS_G : natural := SDRAM_NROWS_C; -- Number of rows in SDRAM array.
NCOLS_G : natural := SDRAM_NCOLS_C; -- Number of columns in SDRAM array.
HADDR_WIDTH_G : natural := SDRAM_HADDR_WIDTH_C; -- Host-side address width.
SADDR_WIDTH_G : natural := SDRAM_SADDR_WIDTH_C; -- SDRAM-side address width.
T_INIT_G : real := SDRAM_T_INIT_C; -- min initialization interval (ns).
T_RAS_G : real := SDRAM_T_RAS_C; -- min interval between active to precharge commands (ns).
T_RCD_G : real := SDRAM_T_RCD_C; -- min interval between active and R/W commands (ns).
T_REF_G : real := SDRAM_T_REF_C; -- maximum refresh interval (ns).
T_RFC_G : real := SDRAM_T_RFC_C; -- duration of refresh operation (ns).
T_RP_G : real := SDRAM_T_RP_C; -- min precharge command duration (ns).
T_XSR_G : real := SDRAM_T_XSR_C -- exit self-refresh time (ns).
);
port(
-- Host side.
clk_i : in std_logic; -- Master clock.
lock_i : in std_logic := YES; -- True if clock is stable.
rst_i : in std_logic := NO; -- Reset.
rd_i : in std_logic := NO; -- Initiate read operation.
wr_i : in std_logic := NO; -- Initiate write operation.
earlyOpBegun_o : out std_logic; -- Read/write/self-refresh op has begun (async).
opBegun_o : out std_logic; -- Read/write/self-refresh op has begun (clocked).
rdPending_o : out std_logic; -- True if read operation(s) are still in the pipeline.
done_o : out std_logic; -- Read or write operation is done_o.
rdDone_o : out std_logic; -- Read operation is done_o and data is available.
addr_i : in std_logic_vector(HADDR_WIDTH_G-1 downto 0) := (others => ZERO); -- Address from host to SDRAM.
data_i : in std_logic_vector(DATA_WIDTH_G-1 downto 0) := (others => ZERO); -- Data from host to SDRAM.
data_o : out std_logic_vector(DATA_WIDTH_G-1 downto 0); -- Data from SDRAM to host.
status_o : out std_logic_vector(3 downto 0); -- Diagnostic status of the FSM .
-- SDRAM side.
sdCke_o : out std_logic; -- Clock-enable to SDRAM.
sdCe_bo : out std_logic; -- Chip-select to SDRAM.
sdRas_bo : out std_logic; -- SDRAM row address strobe.
sdCas_bo : out std_logic; -- SDRAM column address strobe.
sdWe_bo : out std_logic; -- SDRAM write enable.
sdBs_o : out std_logic_vector(1 downto 0); -- SDRAM bank address.
sdAddr_o : out std_logic_vector(SADDR_WIDTH_G-1 downto 0); -- SDRAM row/column address.
sdData_io : inout std_logic_vector(DATA_WIDTH_G-1 downto 0); -- Data to/from SDRAM.
sdDqmh_o : out std_logic; -- Enable upper-byte of SDRAM databus if true.
sdDqml_o : out std_logic -- Enable lower-byte of SDRAM databus if true.
);
end entity;
architecture arch of SdramCntl is
constant OUTPUT_C : std_logic := '1'; -- direction of dataflow w.r.t. this controller.
constant INPUT_C : std_logic := '0';
constant NOP_C : std_logic := '0'; -- no operation.
constant READ_C : std_logic := '1'; -- read operation.
constant WRITE_C : std_logic := '1'; -- write operation.
-- SDRAM timing parameters converted into clock cycles (based on FREQ_G).
constant FREQ_GHZ_C : real := FREQ_G/1000.0; -- GHz = 1/ns.
constant INIT_CYCLES_C : natural := integer(ceil(T_INIT_G*FREQ_GHZ_C)); -- SDRAM power-on initialization interval.
constant RAS_CYCLES_C : natural := integer(ceil(T_RAS_G*FREQ_GHZ_C)); -- active-to-precharge interval.
constant RCD_CYCLES_C : natural := integer(ceil(T_RCD_G*FREQ_GHZ_C)); -- active-to-R/W interval.
constant REF_CYCLES_C : natural := integer(ceil(T_REF_G*FREQ_GHZ_C/real(NROWS_G))); -- interval between row refreshes.
constant RFC_CYCLES_C : natural := integer(ceil(T_RFC_G*FREQ_GHZ_C)); -- refresh operation interval.
constant RP_CYCLES_C : natural := integer(ceil(T_RP_G*FREQ_GHZ_C)); -- precharge operation interval.
constant WR_CYCLES_C : natural := 2; -- write recovery time.
constant XSR_CYCLES_C : natural := integer(ceil(T_XSR_G*FREQ_GHZ_C)); -- exit self-refresh time.
constant MODE_CYCLES_C : natural := 2; -- mode register setup time.
constant CAS_CYCLES_C : natural := 3; -- CAS latency.
constant RFSH_OPS_C : natural := 8; -- number of refresh operations needed to init SDRAM.
-- timer registers that count down times for various SDRAM operations.
signal timer_r, timer_x : natural range 0 to INIT_CYCLES_C := 0; -- current SDRAM op time.
signal rasTimer_r, rasTimer_x : natural range 0 to RAS_CYCLES_C := 0; -- active-to-precharge time.
signal wrTimer_r, wrTimer_x : natural range 0 to WR_CYCLES_C := 0; -- write-to-precharge time.
signal refTimer_r, refTimer_x : natural range 0 to REF_CYCLES_C := REF_CYCLES_C; -- time between row refreshes.
signal rfshCntr_r, rfshCntr_x : natural range 0 to NROWS_G := 0; -- counts refreshes that are neede.
signal nopCntr_r, nopCntr_x : natural range 0 to MAX_NOP_G := 0; -- counts consecutive NOP_C operations.
signal doSelfRfsh_s : std_logic; -- active when the NOP counter hits zero and self-refresh can start.
-- states of the SDRAM controller state machine.
type CntlStateType is (
INITWAIT, -- initialization - waiting for power-on initialization to complete.
INITPCHG, -- initialization - initial precharge of SDRAM banks.
INITSETMODE, -- initialization - set SDRAM mode.
INITRFSH, -- initialization - do initial refreshes.
RW, -- read/write/refresh the SDRAM.
ACTIVATE, -- open a row of the SDRAM for reading/writing.
REFRESHROW, -- refresh a row of the SDRAM.
SELFREFRESH -- keep SDRAM in self-refresh mode with CKE low.
);
signal state_r, state_x : CntlStateType := INITWAIT; -- state register and next state.
-- commands that are sent to the SDRAM to make it perform certain operations.
-- commands use these SDRAM input pins (ce_bo,ras_bo,cas_bo,we_bo,dqmh_o,dqml_o).
subtype sdramCmdType is unsigned(5 downto 0);
constant NOP_CMD_C : SdramCmdType := "011100";
constant ACTIVE_CMD_C : SdramCmdType := "001100";
constant READ_CMD_C : SdramCmdType := "010100";
constant WRITE_CMD_C : SdramCmdType := "010000";
constant PCHG_CMD_C : SdramCmdType := "001000";
constant MODE_CMD_C : SdramCmdType := "000000";
constant RFSH_CMD_C : SdramCmdType := "000100";
-- SDRAM mode register.
-- the SDRAM is placed in a non-burst mode (burst length = 1) with a 3-cycle CAS.
subtype SdramModeType is std_logic_vector(11 downto 0);
constant MODE_C : SdramModeType := "00" & "0" & "00" & "011" & "0" & "000";
-- the host address is decomposed into these sets of SDRAM address components.
constant ROW_LEN_C : natural := Log2(NROWS_G); -- number of row address bits.
constant COL_LEN_C : natural := Log2(NCOLS_G); -- number of column address bits.
signal bank_s : std_logic_vector(sdBs_o'range); -- bank address bits.
signal row_s : std_logic_vector(ROW_LEN_C - 1 downto 0); -- row address within bank.
signal col_s : std_logic_vector(sdAddr_o'range); -- column address within row.
-- registers that store the currently active row in each bank of the SDRAM.
constant NUM_ACTIVE_ROWS_C : integer := IntSelect(MULTIPLE_ACTIVE_ROWS_G = false, 1, 2**sdBs_o'length);
type ActiveRowType is array(0 to NUM_ACTIVE_ROWS_C-1) of std_logic_vector(row_s'range);
signal activeRow_r, activeRow_x : ActiveRowType;
signal activeFlag_r, activeFlag_x : std_logic_vector(0 to NUM_ACTIVE_ROWS_C-1) := (others => NO); -- indicates that some row in a bank is active.
signal bankIndex_s : natural range 0 to NUM_ACTIVE_ROWS_C-1; -- bank address bits.
signal activeBank_r, activeBank_x : std_logic_vector(sdBs_o'range); -- indicates the bank with the active row.
signal doActivate_s : std_logic; -- indicates when a new row in a bank needs to be activated.
-- there is a command bit embedded within the SDRAM column address.
constant CMDBIT_POS_C : natural := 10; -- position of command bit.
constant AUTO_PCHG_ON_C : std_logic := '1'; -- CMDBIT value to auto-precharge the bank.
constant AUTO_PCHG_OFF_C : std_logic := '0'; -- CMDBIT value to disable auto-precharge.
constant ONE_BANK_C : std_logic := '0'; -- CMDBIT value to select one bank.
constant ALL_BANKS_C : std_logic := '1'; -- CMDBIT value to select all banks.
-- status signals that indicate when certain operations are in progress.
signal wrInProgress_s : std_logic; -- write operation in progress.
signal rdInProgress_s : std_logic; -- read operation in progress.
signal activateInProgress_s : std_logic; -- row activation is in progress.
-- these registers track the progress of read and write operations.
signal rdPipeline_r, rdPipeline_x : std_logic_vector(CAS_CYCLES_C+1 downto 0) := (others => '0'); -- pipeline of read ops in progress.
signal wrPipeline_r, wrPipeline_x : std_logic_vector(0 downto 0) := (others => '0'); -- pipeline of write ops (only need 1 cycle).
-- registered outputs to host.
signal opBegun_r, opBegun_x : std_logic := NO; -- true when SDRAM read or write operation is started.
signal sdramData_r, sdramData_x : std_logic_vector(data_o'range) := (others => '0'); -- holds data read from SDRAM and sent to the host.
signal sdramDataOppPhase_r, sdramDataOppPhase_x : std_logic_vector(data_o'range); -- holds data read from SDRAM on opposite clock edge.
-- registered outputs to SDRAM.
signal cke_r, cke_x : std_logic := NO; -- Clock-enable bit.
signal cmd_r, cmd_x : SdramCmdType := NOP_CMD_C; -- SDRAM command bits.
signal ba_r, ba_x : std_logic_vector(sdBs_o'range) := (others => '0'); -- SDRAM bank address bits.
signal sAddr_r, sAddr_x : std_logic_vector(sdAddr_o'range) := (others => '0'); -- SDRAM row/column address.
signal sData_r, sData_x : std_logic_vector(sdData_io'range) := (others => '0'); -- SDRAM out databus.
signal sDataDir_r, sDataDir_x : std_logic := INPUT_C; -- SDRAM databus direction control bit.
begin
--*********************************************************************
-- attach some internal signals to the I/O ports
--*********************************************************************
-- attach registered SDRAM control signals to SDRAM input pins
(sdCe_bo, sdRas_bo, sdCas_bo, sdWe_bo, sdDqmh_o, sdDqml_o) <= cmd_r; -- SDRAM operation control bits
sdCke_o <= cke_r; -- SDRAM clock enable
sdBs_o <= ba_r; -- SDRAM bank address
sdAddr_o <= sAddr_r; -- SDRAM address
sdData_io <= sData_r when sDataDir_r = OUTPUT_C else (others => 'Z'); -- SDRAM output data bus
-- attach some port signals
data_o <= sdramData_r; -- data back to host
opBegun_o <= opBegun_r; -- true if requested operation has begun
--*********************************************************************
-- compute the next state and outputs
--*********************************************************************
combinatorial : process(rd_i, wr_i, addr_i, data_i, sdramData_r, sdData_io, state_r, opBegun_x,
activeFlag_r, activeRow_r, activeBank_r, rdPipeline_r, wrPipeline_r,
wrInProgress_s, rdInProgress_s, activateInProgress_s, doActivate_s, doSelfRfsh_s,
sdramDataOppPhase_r, nopCntr_r, lock_i, rfshCntr_r, timer_r, rasTimer_r,
wrTimer_r, refTimer_r, cmd_r, row_s, col_s, ba_r, ba_x, bank_s, bankIndex_s, cke_r)
begin
--*********************************************************************
-- setup default values for signals
--*********************************************************************
opBegun_x <= NO; -- no operations have begun
earlyOpBegun_o <= opBegun_x;
cke_x <= YES; -- enable SDRAM clock
cmd_x <= NOP_CMD_C; -- set SDRAM command to no-operation
sDataDir_x <= INPUT_C; -- accept data from the SDRAM
sData_x <= data_i(sData_x'range); -- output data from host to SDRAM
state_x <= state_r; -- reload these registers and flags
activeFlag_x <= activeFlag_r; -- with their existing values
activeRow_x <= activeRow_r;
activeBank_x <= activeBank_r;
rfshCntr_x <= rfshCntr_r;
--*********************************************************************
-- setup default value for the SDRAM address
--*********************************************************************
-- extract bank field from host address
ba_x <= addr_i(sdBs_o'length + ROW_LEN_C + COL_LEN_C - 1 downto ROW_LEN_C + COL_LEN_C);
if MULTIPLE_ACTIVE_ROWS_G = true then
bank_s <= (others => '0');
bankIndex_s <= CONV_INTEGER(ba_x);
else
bank_s <= ba_x;
bankIndex_s <= 0;
end if;
-- extract row, column fields from host address
row_s <= addr_i(ROW_LEN_C + COL_LEN_C - 1 downto COL_LEN_C);
-- extend column (if needed) until it is as large as the (SDRAM address bus - 1)
col_s <= (others => '0'); -- set it to all zeroes
col_s(COL_LEN_C-1 downto 0) <= addr_i(COL_LEN_C-1 downto 0);
-- by default, set SDRAM address to the column address with interspersed
-- command bit set to disable auto-precharge
sAddr_x <= col_s(col_s'high-1 downto CMDBIT_POS_C) & AUTO_PCHG_OFF_C
& col_s(CMDBIT_POS_C-1 downto 0);
--*********************************************************************
-- manage the read and write operation pipelines
--*********************************************************************
-- determine if read operations are in progress by the presence of
-- READ flags in the read pipeline
if rdPipeline_r(rdPipeline_r'high downto 1) /= 0 then
rdInProgress_s <= YES;
else
rdInProgress_s <= NO;
end if;
rdPending_o <= rdInProgress_s; -- tell the host if read operations are in progress
-- enter NOPs into the read and write pipeline shift registers by default
rdPipeline_x <= NOP_C & rdPipeline_r(rdPipeline_r'high downto 1);
wrPipeline_x(0) <= NOP_C;
-- transfer data from SDRAM to the host data register if a read flag has exited the pipeline
-- (the transfer occurs 1 cycle before we tell the host the read operation is done)
if rdPipeline_r(1) = READ_C then
sdramDataOppPhase_x <= sdData_io(data_o'range); -- gets value on the SDRAM databus on the opposite phase
if IN_PHASE_G then
-- get the SDRAM data for the host directly from the SDRAM if the controller and SDRAM are in-phase
sdramData_x <= sdData_io(data_o'range);
else
-- otherwise get the SDRAM data that was gathered on the previous opposite clock edge
sdramData_x <= sdramDataOppPhase_r(data_o'range);
end if;
else
-- retain contents of host data registers if no data from the SDRAM has arrived yet
sdramDataOppPhase_x <= sdramDataOppPhase_r;
sdramData_x <= sdramData_r;
end if;
done_o <= rdPipeline_r(0) or wrPipeline_r(0); -- a read or write operation is done
rdDone_o <= rdPipeline_r(0); -- SDRAM data available when a READ flag exits the pipeline
--*********************************************************************
-- manage row activation
--*********************************************************************
-- request a row activation operation if the row of the current address
-- does not match the currently active row in the bank, or if no row
-- in the bank is currently active
if (bank_s /= activeBank_r) or (row_s /= activeRow_r(bankIndex_s)) or (activeFlag_r(bankIndex_s) = NO) then
doActivate_s <= YES;
else
doActivate_s <= NO;
end if;
--*********************************************************************
-- manage self-refresh
--*********************************************************************
-- enter self-refresh if neither a read or write is requested for MAX_NOP consecutive cycles.
if (rd_i = YES) or (wr_i = YES) then
-- any read or write resets NOP counter and exits self-refresh state
nopCntr_x <= 0;
doSelfRfsh_s <= NO;
elsif nopCntr_r /= MAX_NOP_G then
-- increment NOP counter whenever there is no read or write operation
nopCntr_x <= nopCntr_r + 1;
doSelfRfsh_s <= NO;
else
-- start self-refresh when counter hits maximum NOP count and leave counter unchanged
nopCntr_x <= nopCntr_r;
doSelfRfsh_s <= YES;
end if;
--*********************************************************************
-- update the timers
--*********************************************************************
-- row activation timer
if rasTimer_r /= 0 then
-- decrement a non-zero timer and set the flag
-- to indicate the row activation is still inprogress
rasTimer_x <= rasTimer_r - 1;
activateInProgress_s <= YES;
else
-- on timeout, keep the timer at zero and reset the flag
-- to indicate the row activation operation is done
rasTimer_x <= rasTimer_r;
activateInProgress_s <= NO;
end if;
-- write operation timer
if wrTimer_r /= 0 then
-- decrement a non-zero timer and set the flag
-- to indicate the write operation is still inprogress
wrTimer_x <= wrTimer_r - 1;
wrInPRogress_s <= YES;
else
-- on timeout, keep the timer at zero and reset the flag that
-- indicates a write operation is in progress
wrTimer_x <= wrTimer_r;
wrInPRogress_s <= NO;
end if;
-- refresh timer
if refTimer_r /= 0 then
refTimer_x <= refTimer_r - 1;
else
-- on timeout, reload the timer with the interval between row refreshes
-- and increment the counter for the number of row refreshes that are needed
refTimer_x <= REF_CYCLES_C;
if ENABLE_REFRESH_G then
rfshCntr_x <= rfshCntr_r + 1;
else
rfshCntr_x <= 0; -- refresh never occurs if this counter never gets above zero
end if;
end if;
-- main timer for sequencing SDRAM operations
if timer_r /= 0 then
-- decrement the timer and do nothing else since the previous operation has not completed yet.
timer_x <= timer_r - 1;
status_o <= "0000";
else
-- the previous operation has completed once the timer hits zero
timer_x <= timer_r; -- by default, leave the timer at zero
--*********************************************************************
-- compute the next state and outputs
--*********************************************************************
case state_r is
--*********************************************************************
-- let clock stabilize and then wait for the SDRAM to initialize
--*********************************************************************
when INITWAIT =>
if lock_i = YES then
-- wait for SDRAM power-on initialization once the clock is stable
timer_x <= INIT_CYCLES_C; -- set timer for initialization duration
state_x <= INITPCHG;
else
-- disable SDRAM clock and return to this state if the clock is not stable
-- this insures the clock is stable before enabling the SDRAM
-- it also insures a clean startup if the SDRAM is currently in self-refresh mode
cke_x <= NO;
end if;
status_o <= "0001";
--*********************************************************************
-- precharge all SDRAM banks after power-on initialization
--*********************************************************************
when INITPCHG =>
cmd_x <= PCHG_CMD_C;
sAddr_x(CMDBIT_POS_C) <= ALL_BANKS_C; -- precharge all banks
timer_x <= RP_CYCLES_C; -- set timer for precharge operation duration
rfshCntr_x <= RFSH_OPS_C; -- set counter for refresh ops needed after precharge
state_x <= INITRFSH;
status_o <= "0010";
--*********************************************************************
-- refresh the SDRAM a number of times after initial precharge
--*********************************************************************
when INITRFSH =>
cmd_x <= RFSH_CMD_C;
timer_x <= RFC_CYCLES_C; -- set timer to refresh operation duration
rfshCntr_x <= rfshCntr_r - 1; -- decrement refresh operation counter
if rfshCntr_r = 1 then
state_x <= INITSETMODE; -- set the SDRAM mode once all refresh ops are done
end if;
status_o <= "0011";
--*********************************************************************
-- set the mode register of the SDRAM
--*********************************************************************
when INITSETMODE =>
cmd_x <= MODE_CMD_C;
sAddr_x <= (others => '0');
sAddr_x(MODE_C'range) <= MODE_C; -- output mode register bits on the SDRAM address bits
timer_x <= MODE_CYCLES_C; -- set timer for mode setting operation duration
state_x <= RW;
status_o <= "0100";
--*********************************************************************
-- process read/write/refresh operations after initialization is done
--*********************************************************************
when RW =>
--*********************************************************************
-- highest priority operation: row refresh
-- do a refresh operation if the refresh counter is non-zero
--*********************************************************************
if rfshCntr_r /= 0 then
-- wait for any row activations, writes or reads to finish before doing a precharge
if (activateInProgress_s = NO) and (wrInProgress_s = NO) and (rdInProgress_s = NO) then
cmd_x <= PCHG_CMD_C; -- initiate precharge of the SDRAM
sAddr_x(CMDBIT_POS_C) <= ALL_BANKS_C; -- precharge all banks
timer_x <= RP_CYCLES_C; -- set timer for this operation
activeFlag_x <= (others => NO); -- all rows are inactive after a precharge operation
state_x <= REFRESHROW; -- refresh the SDRAM after the precharge
end if;
status_o <= "0101";
--*********************************************************************
-- do a host-initiated read operation
--*********************************************************************
elsif rd_i = YES then
-- Wait one clock cycle if the bank address has just changed and each bank has its own active row.
-- This gives extra time for the row activation circuitry.
if (ba_x = ba_r) or (MULTIPLE_ACTIVE_ROWS_G = false) then
-- activate a new row if the current read is outside the active row or bank
if doActivate_s = YES then
-- activate new row only if all previous activations, writes, reads are done
if (activateInProgress_s = NO) and (wrInProgress_s = NO) and (rdInProgress_s = NO) then
cmd_x <= PCHG_CMD_C; -- initiate precharge of the SDRAM
sAddr_x(CMDBIT_POS_C) <= ONE_BANK_C; -- precharge this bank
timer_x <= RP_CYCLES_C; -- set timer for this operation
activeFlag_x(bankIndex_s) <= NO; -- rows in this bank are inactive after a precharge operation
state_x <= ACTIVATE; -- activate the new row after the precharge is done
end if;
-- read from the currently active row if no previous read operation
-- is in progress or if pipeline reads are enabled
-- we can always initiate a read even if a write is already in progress
elsif (rdInProgress_s = NO) or PIPE_EN_G then
cmd_x <= READ_CMD_C; -- initiate a read of the SDRAM
-- insert a flag into the pipeline shift register that will exit the end
-- of the shift register when the data from the SDRAM is available
rdPipeline_x <= READ_C & rdPipeline_r(rdPipeline_r'high downto 1);
opBegun_x <= YES; -- tell the host the requested operation has begun
end if;
end if;
status_o <= "0110";
--*********************************************************************
-- do a host-initiated write operation
--*********************************************************************
elsif wr_i = YES then
-- Wait one clock cycle if the bank address has just changed and each bank has its own active row.
-- This gives extra time for the row activation circuitry.
if (ba_x = ba_r) or (MULTIPLE_ACTIVE_ROWS_G = false) then
-- activate a new row if the current write is outside the active row or bank
if doActivate_s = YES then
-- activate new row only if all previous activations, writes, reads are done
if (activateInProgress_s = NO) and (wrInProgress_s = NO) and (rdInProgress_s = NO) then
cmd_x <= PCHG_CMD_C; -- initiate precharge of the SDRAM
sAddr_x(CMDBIT_POS_C) <= ONE_BANK_C; -- precharge this bank
timer_x <= RP_CYCLES_C; -- set timer for this operation
activeFlag_x(bankIndex_s) <= NO; -- rows in this bank are inactive after a precharge operation
state_x <= ACTIVATE; -- activate the new row after the precharge is done
end if;
-- write to the currently active row if no previous read operations are in progress
elsif rdInProgress_s = NO then
cmd_x <= WRITE_CMD_C; -- initiate the write operation
sDataDir_x <= OUTPUT_C; -- turn on drivers to send data to SDRAM
-- set timer so precharge doesn't occur too soon after write operation
wrTimer_x <= WR_CYCLES_C;
-- insert a flag into the 1-bit pipeline shift register that will exit on the
-- next cycle. The write into SDRAM is not actually done by that time, but
-- this doesn't matter to the host
wrPipeline_x(0) <= WRITE_C;
opBegun_x <= YES; -- tell the host the requested operation has begun
end if;
end if;
status_o <= "0111";
--*********************************************************************
-- do a host-initiated self-refresh operation
--*********************************************************************
elsif doSelfRfsh_s = YES then
-- wait until all previous activations, writes, reads are done
if (activateInProgress_s = NO) and (wrInProgress_s = NO) and (rdInProgress_s = NO) then
cmd_x <= PCHG_CMD_C; -- initiate precharge of the SDRAM
sAddr_x(CMDBIT_POS_C) <= ALL_BANKS_C; -- precharge all banks
timer_x <= RP_CYCLES_C; -- set timer for this operation
activeFlag_x <= (others => NO); -- all rows are inactive after a precharge operation
state_x <= SELFREFRESH; -- self-refresh the SDRAM after the precharge
end if;
status_o <= "1000";
--*********************************************************************
-- no operation
--*********************************************************************
else
state_x <= RW; -- continue to look for SDRAM operations to execute
status_o <= "1001";
end if;
--*********************************************************************
-- activate a row of the SDRAM
--*********************************************************************
when ACTIVATE =>
cmd_x <= ACTIVE_CMD_C;
sAddr_x <= (others => '0'); -- output the address for the row to be activated
sAddr_x(row_s'range) <= row_s;
activeBank_x <= bank_s;
activeRow_x(bankIndex_s) <= row_s; -- store the new active SDRAM row address
activeFlag_x(bankIndex_s) <= YES; -- the SDRAM is now active
rasTimer_x <= RAS_CYCLES_C; -- minimum time before another precharge can occur
timer_x <= RCD_CYCLES_C; -- minimum time before a read/write operation can occur
state_x <= RW; -- return to do read/write operation that initiated this activation
status_o <= "1010";
--*********************************************************************
-- refresh a row of the SDRAM
--*********************************************************************
when REFRESHROW =>
cmd_x <= RFSH_CMD_C;
timer_x <= RFC_CYCLES_C; -- refresh operation interval
rfshCntr_x <= rfshCntr_r - 1; -- decrement the number of needed row refreshes
state_x <= RW; -- process more SDRAM operations after refresh is done
status_o <= "1011";
--*********************************************************************
-- place the SDRAM into self-refresh and keep it there until further notice
--*********************************************************************
when SELFREFRESH =>
if (doSelfRfsh_s = YES) or (lock_i = NO) then
-- keep the SDRAM in self-refresh mode as long as requested and until there is a stable clock
cmd_x <= RFSH_CMD_C; -- output the refresh command; this is only needed on the first clock cycle
cke_x <= NO; -- disable the SDRAM clock
else
-- else exit self-refresh mode and start processing read and write operations
cke_x <= YES; -- restart the SDRAM clock
rfshCntr_x <= 0; -- no refreshes are needed immediately after leaving self-refresh
activeFlag_x <= (others => NO); -- self-refresh deactivates all rows
timer_x <= XSR_CYCLES_C; -- wait this long until read and write operations can resume
state_x <= RW;
end if;
status_o <= "1100";
--*********************************************************************
-- unknown state
--*********************************************************************
when others =>
state_x <= INITWAIT; -- reset state if in erroneous state
status_o <= "1101";
end case;
end if;
end process combinatorial;
--*********************************************************************
-- update registers on the appropriate clock edge
--*********************************************************************
update : process(rst_i, clk_i)
begin
if rst_i = YES then
-- asynchronous reset
state_r <= INITWAIT;
activeFlag_r <= (others => NO);
rfshCntr_r <= 0;
timer_r <= 0;
refTimer_r <= REF_CYCLES_C;
rasTimer_r <= 0;
wrTimer_r <= 0;
nopCntr_r <= 0;
opBegun_r <= NO;
rdPipeline_r <= (others => '0');
wrPipeline_r <= (others => '0');
cke_r <= NO;
cmd_r <= NOP_CMD_C;
ba_r <= (others => '0');
sAddr_r <= (others => '0');
sData_r <= (others => '0');
sDataDir_r <= INPUT_C;
sdramData_r <= (others => '0');
elsif rising_edge(clk_i) then
state_r <= state_x;
activeBank_r <= activeBank_x;
activeRow_r <= activeRow_x;
activeFlag_r <= activeFlag_x;
rfshCntr_r <= rfshCntr_x;
timer_r <= timer_x;
refTimer_r <= refTimer_x;
rasTimer_r <= rasTimer_x;
wrTimer_r <= wrTimer_x;
nopCntr_r <= nopCntr_x;
opBegun_r <= opBegun_x;
rdPipeline_r <= rdPipeline_x;
wrPipeline_r <= wrPipeline_x;
cke_r <= cke_x;
cmd_r <= cmd_x;
ba_r <= ba_x;
sAddr_r <= sAddr_x;
sData_r <= sData_x;
sDataDir_r <= sDataDir_x;
sdramData_r <= sdramData_x;
end if;
-- The register that gets data from the SDRAM and holds it for the host
-- is clocked on the opposite edge. We don't use this register if IN_PHASE_G=TRUE.
if rst_i = YES then
sdramDataOppPhase_r <= (others => '0');
elsif falling_edge(clk_i) then
sdramDataOppPhase_r <= sdramDataOppPhase_x;
end if;
end process update;
end architecture;
--*********************************************************************
-- Handshake circuit for SDRAM controller R/W control signals.
--
-- This circuit transforms the R/W/done control signals into a handshake
-- interface: you have to raise the control (rd_i or wr_i), then wait for
-- the done_o signal to go high, then lower the control signal, and then
-- the done_o signal goes low. Meanwhile, the control signals that go to
-- the SDRAM controller (rd_o and wr_o) are sequenced so that there is no
-- chance of doing a double read or write, and the one-cycle done_i signal
-- from the SDRAM controller is held high by the handshake circuit so the
-- initiator has a chance to see it.
--
-- R/W_i _____/--------------------------\_____
-- R/W_o _____/--------------\_________________
-- done_i ____________________/--\______________
-- done_o ____________________/-----------\_____
--*********************************************************************
library IEEE, XESS;
use IEEE.std_logic_1164.all;
use XESS.CommonPckg.all;
use XESS.MiscPckg.all;
use work.XessBoardPckg.all;
entity RWHandshake is
port (
rd_i : in std_logic; -- Read control signal.
rd_o : out std_logic; -- Read control signal that goes to host-side of SDRAM controller.
wr_i : in std_logic; -- Write control signal.
wr_o : out std_logic; -- Write control signal that goes to host-side of SDRAM controller.
done_i : in std_logic; -- R/W op done signal from host-side of SDRAM controller.
done_o : out std_logic -- R/W done status signal.
);
end entity;
architecture arch of RWHandshake is
signal rdDone_s : std_logic;
signal wrDone_s : std_logic;
begin
uRead : HandshakeIntfc
port map(
ctrl_i => rd_i,
ctrl_o => rd_o,
done_i => done_i,
done_o => rdDone_s
);
uWrite : HandshakeIntfc
port map(
ctrl_i => wr_i,
ctrl_o => wr_o,
done_i => done_i,
done_o => wrDone_s
);
-- Read and write operations never occur simultaneously, so we can present a
-- single, unified done signal to the initiator.
done_o <= rdDone_s or wrDone_s;
end architecture;
--*********************************************************************
-- Dual-port interface to SDRAM controller.
--*********************************************************************
library IEEE, UNISIM, XESS;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_unsigned.all;
use IEEE.numeric_std.all;
use XESS.CommonPckg.all;
use work.XessBoardPckg.all;
entity DualPort is
generic(
PIPE_EN_G : boolean := SDRAM_PIPE_EN_C; -- enable pipelined read operations.
PORT_TIME_SLOTS_G : std_logic_vector(15 downto 0) := "1111000011110000";
DATA_WIDTH_G : natural := SDRAM_DATA_WIDTH_C; -- host & SDRAM data width.
HADDR_WIDTH_G : natural := SDRAM_HADDR_WIDTH_C -- host-side address width.
);
port(
clk_i : in std_logic; -- master clock.
-- Host-side port 0.
rst0_i : in std_logic := NO; -- reset.
rd0_i : in std_logic := NO; -- initiate read operation.
wr0_i : in std_logic := NO; -- initiate write operation.
earlyOpBegun0_o : out std_logic; -- read/write op has begun (async).
opBegun0_o : out std_logic := NO; -- read/write op has begun (clocked).
rdPending0_o : out std_logic; -- true if read operation(s) are still in the pipeline.
done0_o : out std_logic; -- read or write operation is done_i.
rdDone0_o : out std_logic; -- read operation is done_i and data is available.
addr0_i : in std_logic_vector(HADDR_WIDTH_G-1 downto 0) := (others => ZERO); -- address from host to SDRAM.
data0_i : in std_logic_vector(DATA_WIDTH_G-1 downto 0) := (others => ZERO); -- data from host to SDRAM.
data0_o : out std_logic_vector(DATA_WIDTH_G-1 downto 0) := (others => ZERO); -- data from SDRAM to host.
status0_o : out std_logic_vector(3 downto 0); -- diagnostic status of the SDRAM controller FSM .
-- Host-side port 1.
rst1_i : in std_logic := NO;
rd1_i : in std_logic := NO;
wr1_i : in std_logic := NO;
earlyOpBegun1_o : out std_logic;
opBegun1_o : out std_logic := NO;
rdPending1_o : out std_logic;
done1_o : out std_logic;
rdDone1_o : out std_logic;
addr1_i : in std_logic_vector(HADDR_WIDTH_G-1 downto 0) := (others => ZERO);
data1_i : in std_logic_vector(DATA_WIDTH_G-1 downto 0) := (others => ZERO);
data1_o : out std_logic_vector(DATA_WIDTH_G-1 downto 0) := (others => ZERO);
status1_o : out std_logic_vector(3 downto 0);
-- SDRAM controller host-side port.
rst_o : out std_logic;
rd_o : out std_logic;
wr_o : out std_logic;
earlyOpBegun_i : in std_logic;
opBegun_i : in std_logic;
rdPending_i : in std_logic;
done_i : in std_logic;
rdDone_i : in std_logic;
addr_o : out std_logic_vector(HADDR_WIDTH_G-1 downto 0);
data_o : out std_logic_vector(DATA_WIDTH_G-1 downto 0);
data_i : in std_logic_vector(DATA_WIDTH_G-1 downto 0);
status_i : in std_logic_vector(3 downto 0)
);
end entity;
architecture arch of DualPort is
-- The door signal controls whether the read/write signal from the active port
-- is allowed through to the read/write inputs of the SDRAM controller.
type DoorStateType is (OPENED_C, CLOSED_C);
signal door_r, door_x : DoorStateType := CLOSED_C;
-- The port signal indicates which port is connected to the SDRAM controller.
type PortStateType is (PORT0_C, PORT1_C);
signal port_r, port_x : PortStateType := PORT0_C;