Автор |
Сообщение |
|
|
Заголовок сообщения: |
Re: Простой контролер SD-RAM на AHDL |
|
|
2 WingLion Спасибо. На выходных займусь с MaxPlus - буду разбираться...
2 WingLion Спасибо. На выходных займусь с MaxPlus - буду разбираться... :)
|
|
|
|
Добавлено: Ср авг 25, 2010 19:26 |
|
|
|
|
|
Заголовок сообщения: |
Re: Простой контролер SD-RAM на AHDL |
|
|
LasyUser писал(а): CAS before RAS Вот этот вариант проще всего: Сначала генерируются периодические CAS и RAS для циклов чтения/записи. Затем формуруется сигнал WE перед спадом RAS (при записи 0, при чтении 1, для регенерации - тоже 1), и в свободные циклы сигналы CAS и RAS меняются местами. t.e. на AHDL что-то вроде: Код: -- предупреждение: схема накидана за 15 минут без всякой проверки и отладки
SUBDESIGN control( CLK : input -- входная частота (шестикратная частота работы памяти) -- для 60нс DRAM - CLK=50MHz, а рабочая частота памяти - ~8MHz WR,RD : input -- сигналы запросов записи и чтения RASout,CASout,WEout : output -- выходные сигналы управления ) VARIABLE CT[2..0] : DFF; RAS,CAS : DFF; WE,REFRESH : DFFE; BEGIN CT[2..0].clk = CLK; CT[] = (CT[] + 1) and (CT[] < 5); CAS.clk = CLK; RAS.clk = CLK; CASE CT[] IS WHEN 0 => RAS = VCC; CAS = VCC; WHEN 1 => RAS = GND; CAS = VCC; WHEN 2,3 => RAS = GND; CAS = GND; WHEN 4 => RAS = VCC; CAS = GND; WHEN others => RAS = VCC; CAS = VCC; END CASE;
REFRESH.clk = CLK; WE.clk = CLK; REFRESH.ena = (CT[] == 1); WE.ena = (CT[] == 1); CASE (RD,WR) IS WHEN B"11" => REFRESH = VCC; WE = VCC; -- цикл регенерации WHEN B"X0" => REFRESH = GND; WE = GND;-- цикл записи WHEN B"01" => REFRESH = GND; WE = VCC; -- цикл чтения END CASE;
IF !REFRESH THEN RASout = RAS; CASout = CAS; -- циклы чтения/записи ELSE -- режим "CAS перед RAS" RASout = CAS; CASout = RAS; -- цикл регенерации END IF; WEout = WE;
END;
[quote="LasyUser"]CAS before RAS[/quote]
Вот этот вариант проще всего:
Сначала генерируются периодические CAS и RAS для циклов чтения/записи. Затем формуруется сигнал WE перед спадом RAS (при записи 0, при чтении 1, для регенерации - тоже 1), и в свободные циклы сигналы CAS и RAS меняются местами.
t.e. на AHDL что-то вроде:
[code] -- предупреждение: схема накидана за 15 минут без всякой проверки и отладки
SUBDESIGN control( CLK : input -- входная частота (шестикратная частота работы памяти) -- для 60нс DRAM - CLK=50MHz, а рабочая частота памяти - ~8MHz WR,RD : input -- сигналы запросов записи и чтения RASout,CASout,WEout : output -- выходные сигналы управления ) VARIABLE CT[2..0] : DFF; RAS,CAS : DFF; WE,REFRESH : DFFE; BEGIN CT[2..0].clk = CLK; CT[] = (CT[] + 1) and (CT[] < 5); CAS.clk = CLK; RAS.clk = CLK; CASE CT[] IS WHEN 0 => RAS = VCC; CAS = VCC; WHEN 1 => RAS = GND; CAS = VCC; WHEN 2,3 => RAS = GND; CAS = GND; WHEN 4 => RAS = VCC; CAS = GND; WHEN others => RAS = VCC; CAS = VCC; END CASE;
REFRESH.clk = CLK; WE.clk = CLK; REFRESH.ena = (CT[] == 1); WE.ena = (CT[] == 1); CASE (RD,WR) IS WHEN B"11" => REFRESH = VCC; WE = VCC; -- цикл регенерации WHEN B"X0" => REFRESH = GND; WE = GND;-- цикл записи WHEN B"01" => REFRESH = GND; WE = VCC; -- цикл чтения END CASE;
IF !REFRESH THEN RASout = RAS; CASout = CAS; -- циклы чтения/записи ELSE -- режим "CAS перед RAS" RASout = CAS; CASout = RAS; -- цикл регенерации END IF; WEout = WE;
END;[/code]
|
|
|
|
Добавлено: Ср авг 25, 2010 18:49 |
|
|
|
|
|
Заголовок сообщения: |
Re: Простой контролер SD-RAM на AHDL |
|
|
... пардон что ввел в заблуждение "кривым" вопросом Посмотрел datasheet http://www.alldatasheet.com/datasheet-pdf/pdf/127338/ETC/NN514256ALJ-60.html- встроенная регенерация в DRAM есть. Хотел прицепить память к Z180 - со "статикой" конечно проще и работать будет пошустрее, но без буфера много не повесишь, поэтому и вспомнил про DRAM (c CPLD и печатная плата должна поменьше быть и разводить попроще ...) - для экспериментов самое то. Режимов регенерации несколько - RAS only, CAS before RAS, hidden refresh ... какой проще с точки зрения реализации ? ... хотел запихнуть логику в EPM7032 - понятно что мультиплексоры адреса можно использовать в виде отдельных корпусов...
... пардон что ввел в заблуждение "кривым" вопросом :oops: Посмотрел datasheet [url]http://www.alldatasheet.com/datasheet-pdf/pdf/127338/ETC/NN514256ALJ-60.html[/url]- встроенная регенерация в DRAM есть. Хотел прицепить память к Z180 - со "статикой" конечно проще и работать будет пошустрее, но без буфера много не повесишь, поэтому и вспомнил про DRAM (c CPLD и печатная плата должна поменьше быть и разводить попроще ...) - для экспериментов самое то. Режимов регенерации несколько - RAS only, CAS before RAS, hidden refresh ... какой проще с точки зрения реализации ? ... хотел запихнуть логику в EPM7032 - понятно что мультиплексоры адреса можно использовать в виде отдельных корпусов...
|
|
|
|
Добавлено: Ср авг 25, 2010 18:17 |
|
|
|
|
|
Заголовок сообщения: |
Re: Простой контролер SD-RAM на AHDL |
|
|
Я поэтому и пишу, что для таких объемов непонятно, есть там регенерация, или нет. Надо все-таки конкретное наименование смотреть.
Я поэтому и пишу, что для таких объемов непонятно, есть там регенерация, или нет. Надо все-таки конкретное наименование смотреть.
|
|
|
|
Добавлено: Вт авг 24, 2010 22:54 |
|
|
|
|
|
Заголовок сообщения: |
Re: Простой контролер SD-RAM на AHDL |
|
|
В РУ5-х режима регенерации по "CAS перед RAS" и не было, для них надо было все столбцы "ручками перебирать" - в смысле отдельным счетчиком. В Z80 для этого есть регистр R, но он годится только для регенерации микросхем с организацией 16Kx1, потому что перебирает только 128 столбцов.
В РУ5-х режима регенерации по "CAS перед RAS" и не было, для них надо было все столбцы "ручками перебирать" - в смысле отдельным счетчиком. В Z80 для этого есть регистр R, но он годится только для регенерации микросхем с организацией 16Kx1, потому что перебирает только 128 столбцов.
|
|
|
|
Добавлено: Вт авг 24, 2010 21:36 |
|
|
|
|
|
Заголовок сообщения: |
Re: Простой контролер SD-RAM на AHDL |
|
|
А в РУ5 я этого не помню, в Z80 был специальный выход, чтобы на регенерацию переключаться.
А в РУ5 я этого не помню, в Z80 был специальный выход, чтобы на регенерацию переключаться.
|
|
|
|
Добавлено: Вт авг 24, 2010 21:09 |
|
|
|
|
|
Заголовок сообщения: |
Re: Простой контролер SD-RAM на AHDL |
|
|
Хищник писал(а): Судя по объему памяти, эти чипы (part number?) вполне могут попадать в оставшиеся 0.01% Врядли. Режим регенерации "CAS перед RAS" работал и в советских 565РУ7 (256Кx1).
[quote="Хищник"]Судя по объему памяти, эти чипы (part number?) вполне могут попадать в оставшиеся 0.01%[/quote]
Врядли. Режим регенерации "CAS перед RAS" работал и в советских 565РУ7 (256Кx1).
|
|
|
|
Добавлено: Вт авг 24, 2010 21:00 |
|
|
|
|
|
Заголовок сообщения: |
Re: Простой контролер SD-RAM на AHDL |
|
|
Судя по объему памяти, эти чипы (part number?) вполне могут попадать в оставшиеся 0.01%
Судя по объему памяти, эти чипы (part number?) вполне могут попадать в оставшиеся 0.01%
|
|
|
|
Добавлено: Вт авг 24, 2010 19:12 |
|
|
|
|
|
Заголовок сообщения: |
Re: Простой контролер SD-RAM на AHDL |
|
|
LasyUser писал(а): DRAM типа 256Kx4, 256Kx16 ... контроллер регенерации? с 99.99% вероятностью эти чипы поддерживают режим автоматической регенерации (со встроенным счётчиком) CAS Before RAS, т.о. остаётся только в свободные от доступа хоста промежутки времени формировать соответствующий цикл, для чего 7032 более чем избыточна ))
[quote="LasyUser"]DRAM типа 256Kx4, 256Kx16 ... контроллер регенерации?[/quote]
с 99.99% вероятностью эти чипы поддерживают режим автоматической регенерации (со встроенным счётчиком) CAS Before RAS, т.о. остаётся только в свободные от доступа хоста промежутки времени формировать соответствующий цикл, для чего 7032 более чем избыточна ))
|
|
|
|
Добавлено: Вт авг 24, 2010 10:11 |
|
|
|
|
|
Заголовок сообщения: |
Re: Простой контролер SD-RAM на AHDL |
|
|
ATF1502, ATF1504 это Atmel-овские аналоги EPM7032, EPM7064 Alter-ы, только стоят раза в 2 дешевле. После того как что-нибудь "сваяешь" в MaxPlus, остается "скормить" *.pof-файл утилите pof2jed.exe и можно заливать jed-файл в Atmel.
ATF1502, ATF1504 это Atmel-овские аналоги EPM7032, EPM7064 Alter-ы, только стоят раза в 2 дешевле. После того как что-нибудь "сваяешь" в MaxPlus, остается "скормить" *.pof-файл утилите pof2jed.exe и можно заливать jed-файл в Atmel.
|
|
|
|
Добавлено: Пн авг 23, 2010 20:03 |
|
|
|
|
|
Заголовок сообщения: |
Re: Простой контролер SD-RAM на AHDL |
|
|
LasyUser писал(а): одскажите хватит ли ресурсов какого-нибудь ATF1502, ATF1504 чтобы слепить на нем контроллер регенерации? Я с этими ПЛИС не работал, потому не смогу подсказать точно. Хотя, для контроллера регенерации (если не включать в него мультиплексор адресов) должно по идее хватить любой современной ПЛИС.
[quote="LasyUser"]одскажите хватит ли ресурсов какого-нибудь ATF1502, ATF1504 чтобы слепить на нем контроллер регенерации?[/quote]
Я с этими ПЛИС не работал, потому не смогу подсказать точно. Хотя, для контроллера регенерации (если не включать в него мультиплексор адресов) должно по идее хватить любой современной ПЛИС.
|
|
|
|
Добавлено: Пн авг 23, 2010 18:53 |
|
|
|
|
|
Заголовок сообщения: |
Re: Простой контролер SD-RAM на AHDL |
|
|
... мои познания в области ПЛИС невелики - немного поделок на WinCupl и MaxPlus. Есть пару десятков корпусов DRAM типа 256Kx4, 256Kx16 - подскажите хватит ли ресурсов какого-нибудь ATF1502, ATF1504 чтобы слепить на нем контроллер регенерации?
... мои познания в области ПЛИС невелики - немного поделок на WinCupl и MaxPlus. Есть пару десятков корпусов DRAM типа 256Kx4, 256Kx16 - подскажите хватит ли ресурсов какого-нибудь ATF1502, ATF1504 чтобы слепить на нем контроллер регенерации?
|
|
|
|
Добавлено: Пн авг 23, 2010 17:27 |
|
|
|
|
|
Заголовок сообщения: |
Re: Простой контролер SD-RAM на AHDL |
|
|
Вот так примерно должна выглядеть картинка симуляции для контроллера SD-RAM: А это в увеличенном виде - как должно выглядеть соотношение MCLK и MCS: к первой картинке: Сначала, в районе 820ns идет процедура инициализации после включения питания: - цикл "предзаряда" (освобождение/сброс банков); - запись управляющего слова; - затем несколько циклов регенерации. после этого SD-RAM готова к работе здесь эта работа показана в виде цикла чтения пакета (из 64) слов и цикла записи пакета слов. Для режима чтения/записи по одному слову контроллер надо существенно перекапывать. Но для этого может оказаться проще использовать готовый Альтеровский контроллер SD-RAM, который сейчас раздается просто так вместе с последней версией Quartus-II
Вот так примерно должна выглядеть картинка симуляции для контроллера SD-RAM:
[img]http://fforum.winglion.ru/att/sdram_sym_1.gif[/img]
А это в увеличенном виде - как должно выглядеть соотношение MCLK и MCS:
[img]http://fforum.winglion.ru/att/sdram_sym_2.gif[/img]
к первой картинке: Сначала, в районе 820ns идет процедура инициализации после включения питания: - цикл "предзаряда" (освобождение/сброс банков); - запись управляющего слова; - затем несколько циклов регенерации. после этого SD-RAM готова к работе здесь эта работа показана в виде цикла чтения пакета (из 64) слов и цикла записи пакета слов. Для режима чтения/записи по одному слову контроллер надо существенно перекапывать. Но для этого может оказаться проще использовать готовый Альтеровский контроллер SD-RAM, который сейчас раздается просто так вместе с последней версией Quartus-II
|
|
|
|
Добавлено: Чт апр 22, 2010 20:11 |
|
|
|
|
|
Заголовок сообщения: |
Re: Обсуждение переезда на phpbb3 |
|
|
Последний вариант AHDL кода этого же контроллера. Главное отличие в том, что сигнал синхронизации для SD-RAM формируется снаружи относительно этой схемы, и в организации раздельных каналов адреса для записи и для чтения (так было нужно для проекта) Код: ----------------------------------- -- Simple SDRAM controller -- page mode burst read/write -- latensy = 3, frq = 50..150MHz -- 2002-2010 (c) Ivan Mak -- E-mail: ivan_mak@mail.ru aka admin@winglion.ru -- http://winglion.ru -----------------------------------
TITLE "SDRAM_controller";
PARAMETERS ( WIDTH = 16, -- SDRAM data WIDTH OUT_SH = "YES", -- "YES" -- 1/2 clk data shift PRIORITY = "WRITE" -- "READ" или "WRITE" );
SUBDESIGN sdram ( CLK : INPUT; CLKs : input; RESET : INPUT;
-- dir signals
DI[WIDTH-1..0] : INPUT = GND; -- input data DO[WIDTH-1..0] : OUTPUT; -- output data
RA[23..0] : INPUT = GND; -- adress RAM WA[23..0] : INPUT = GND; -- adress RAM CS : INPUT = GND; -- select WR : INPUT = VCC; -- write RD : INPUT = VCC; -- read
STOP : INPUT = VCC; -- for sinhronize cycle
-- sdram signals
MD[WIDTH-1..0] : BIDIR; -- RAM data bus
MWE : OUTPUT; -- RAM signal WE MRAS : OUTPUT; -- RAM signal RAS MCAS : OUTPUT; -- RAM signal CAS
MCS : OUTPUT; -- RAM signal CS MBS[1..0] : OUTPUT; -- RAM signals BS1,BS0
MCKE : OUTPUT; -- RAM signal CKE MCLK : BIDIR; -- RAM signal CLK
MA[11..0] : OUTPUT; -- RAM adress bus
MDQM : OUTPUT;
-- return signals
MEM_C : OUTPUT; -- memory cycle WRITE : OUTPUT; -- write data READ : OUTPUT; -- data read VALID : OUTPUT;
) VARIABLE
ARGX[23..0] : DFFE; ARG[23..0] : NODE;
CTT[5..0] : DFFE; TAB[5..0] : DFF;
CTT_2 : NODE; CTT_3 : NODE; CTT_4 : NODE;
CT[3..0] : DFFE; -- counter
MX[11..0] : DFF; -- adress mux
MY[5..3] : DFF; -- dir mux
MDR[WIDTH-1..0] : DFF; -- data reg MDRX[WIDTH-1..0]: DFF; -- data reg MDRY[WIDTH-1..0]: DFF; -- data reg
PA : NODE;
RWC_FIX[2..0] : DFFE;
R/W : NODE;
WRITE_2 : NODE;
-- MCLKX : NODE; -- MCLKY : NODE; -- MCLKZ : NODE;
-- RX_MA[13..0]: DFF; -- RX_MCKE : DFF; -- RX_MBS[1..0]: DFF; -- -- RX_MCS : DFF; -- RX_MRAS : DFF; RX_MCAS : DFF; RX_MWE : DFF;
BEGIN
-- input address register
ARGX[].clk = CLK; -- ARGX[].ena = VCC; -- fixed adress when bank active ARGX[].ena = MEM_C; -- fixed adress when bank active -- IF (PRIORITY != "READ") and (PRIORITY != "WRITE") THEN -- ASSERT "PRIORITY parametr muast be READ or WRITE!"; -- END IF; IF PRIORITY == "WRITE" GENERATE CASE (RD,WR) IS WHEN 3 => ARGX[] = GND; WHEN 1 => ARGX[] = RA[]; WHEN 2,0 => ARGX[] = WA[]; END CASE; R/W = DFFE((!(RWC_FIX[] == B"X00") or !(MY[5..3] == B"011")),CLK,,,CTT_2); END GENERATE;
IF PRIORITY == "READ" GENERATE CASE (RD,WR) IS WHEN 3 => ARGX[] = GND; WHEN 1,0 => ARGX[] = RA[]; WHEN 2 => ARGX[] = WA[]; END CASE; R/W = DFFE(!(!(RWC_FIX[] == B"0X0") or !(MY[5..3] == B"011")),CLK,,,CTT_2); END GENERATE; ARG[] = ARGX[]; -- ARGX[].d = A[];
RWC_FIX[].clk = CLK; RWC_FIX[].ena = MEM_C; RWC_FIX[] = (RD,WR,CS);
-- micro count
CTT[].clk = CLK; CTT[].clrn = RESET; CTT[].ena = DFF((!(CT[] == 8) or STOP),CLK,,);
CTT_2 = DFF(CTT[] == 2,CLK,,); CTT_3 = DFF(CTT[] == 3,CLK,,); CTT_4 = DFF(CTT[] == 4,CLK,,);
IF CTT_2 THEN CTT[] = TAB[]; -- one command period ELSE CTT[] = CTT[] - 1; END IF;
-- SDRAM data
-- mode sdram bit2..0 - 000 - 1byte -- 001 - 2byte -- 010 - 4byte -- 011 - 8byte -- 111 - page -- other - reserved -- bit3 - 0 - seqential -- 1 - interleave -- bit6..4 - 010 - cas latency = 2 -- 011 - cas latency = 3 -- other - reserved -- bit7 - 0 (?test?) -- bit8 - 0 reserved -- bit9 - 0 burst read & burst write -- 1 burst read & single write -- bit11..10 - 00 reserved -- BS[1..0] - 00 reserved
-- sdram commands RAS,CAS,WE -- 000 - mode register write -- 001 - auto refresh -- cken=0 -> self refresh -- -- CS=H -> SR exit -- RCW=110 -> SR exit -- 010 - bank precharge -- A10=0 precharge bank -- -- A10=1 precharge all -- 011 - bank active -- 100 - write -- A10=1 - auto precharge -- 101 - read -- A10=1 - auto precharge -- 110 - burst stop -- 111 - no operation
-- R/W = DFFE((!(RWC_FIX[] == B"X00") or !(MY[5..3] == B"011")),CLK,,,CTT_2);
-- comand counter
CT[].clk = CLK; CT[].clrn = RESET; CT[].ena = CTT_2;
IF DFF((CT[3..0] == 12),CLK,,) THEN CT[] = 8; ELSE CT[] = CT[]+1; END IF;
-- SDRAM command & times table
TAB[].clk = CLK; MY[].clk = CLK;
CASE CT[3..0] IS -- MY[] -- RAS,CAS,WE
-- init commands WHEN 0 => TAB[] = 4; MY[] = B"010"; -- precharge ALL WHEN 1 => TAB[] = 4; MY[] = B"000"; -- set mode register WHEN 2 => TAB[] = 8; MY[] = B"001"; -- autorefresh WHEN 3 => TAB[] = 8; MY[] = B"001"; -- autorefresh WHEN 4 => TAB[] = 8; MY[] = B"001"; -- autorefresh WHEN 5 => TAB[] = 8; MY[] = B"001"; -- autorefresh WHEN 6 => TAB[] = 8; MY[] = B"001"; -- autorefresh WHEN 7 => TAB[] = 8; MY[] = B"001"; -- autorefresh
-- cycle commands (realy 5 items) WHEN 8 => TAB[] = 4; MY[] = B"011"; -- bank active -- ! words count (0->64) WHEN 9 => TAB[] = 0; MY[] = (B"10",R/W); -- bank read/write WHEN 10 => TAB[] = 4; MY[] = B"110"; -- burst stop! WHEN 11 => TAB[] = 4; MY[] = B"010"; -- bank precharge WHEN 12 => TAB[] = 8; MY[] = B"001"; -- autorefresh WHEN 13 => TAB[] = 4; MY[] = B"111"; -- NOP no executed WHEN 14 => TAB[] = 4; MY[] = B"111"; -- NOP no executed WHEN 15 => TAB[] = 4; MY[] = B"111"; -- NOP no executed END CASE;
MCLK = TRI(LCELL(!CLKs),VCC);
-- address MUX
PA = DFF(!(CT[2..0] == 0),CLK,,);
MX[].clk = CLK; CASE (CT3,PA) IS WHEN 0 => MX[] = (B"010000000000"); -- precharge all WHEN 1 => MX[] = (B"000000110111"); -- SDRAM mode WHEN 2 => MX[] = (ARG[21..10]); -- adress RAS -- 4k WHEN 3 => MX[] = (B"00",ARG[9..0]); -- adress CAS -- 1k END CASE;
-- input register
MDR[].clk = CLK; MDR[].d = DI[];
-- WRITE_2 = (DFF(DFF(DFF(WRITE,CLK,,),CLK,,),CLK,,)); WRITE_2 = DFF(DFF(WRITE or DFF(WRITE,CLK,,),CLK,,),CLK,,); -- WRITE_2 = DFF(WRITE,CLK,,);
FOR i IN 0 TO WIDTH-1 GENERATE MD[i] = TRI(MDR[i],WRITE_2); END GENERATE;
-- output register' -- for 1/2 shift
-- MDRX[].clk = !CLK; -- MDRX[].clk = !LCELL(CLK); MDRX[].clk = MCLK; MDRX[].d = MD[];
-- output register
MDRY[].clk = CLK;
IF (OUT_SH == "YES") GENERATE MDRY[].d = MDRX[]; -- 1/2 clk data shift ELSE GENERATE MDRY[].d = MD[]; -- no 1/2 clk data shift END GENERATE;
DO[] = MDRY[];
-- IF (M_REG == "YES") GENERATE -- MA[] = RX_MA[13..0]; ---- MCKE = RX_MCKE; -- MCKE = VCC; -- MBS[1..0] = RX_MBS[1..0]; -- MCS = RX_MCS; -- ---- MRAS = RX_MRAS; ---- MCAS = RX_MCAS; ---- MWE = RX_MWE; -- -- MRAS = DFF(DFF(RX_MRAS,CLK,,),CLK,,); -- MCAS = DFF(DFF(RX_MCAS,CLK,,),CLK,,); -- MWE = DFF(DFF(RX_MWE,CLK,,),CLK,,); -- -- MDQM = GND; -- ELSE GENERATE
MA[] = MX[];
-- (MDQM,MCKE,MRAS,MCAS,MWE,MBS1,MBS0) = (GND,VCC,MY[5..3],ARG[23..22]);
(MDQM,MCKE,MRAS,MCAS,MWE,MBS1,MBS0) = (GND,VCC,RX_MRAS,RX_MCAS,RX_MWE,ARG[23..22]);
-- RX_MRAS,RX_MCAS,RX_MWE
MCS = DFF((!(CTT[] == 1)),CLK,,);
-- END GENERATE; -- (MDQM,MCKE,MRAS,MCAS,MWE,MBS1,MBS0) = (GND,VCC,MY[5..3],ARG[23..22]);
-- RX_MA[13..0]= MX[]; -- RX_MCKE = VCC; -- RX_MBS[1..0]= ARG[23..22]; -- -- RX_MA[13..0].clk = CLK; -- RX_MCKE.clk = CLK; -- RX_MBS[1..0].clk = CLK; -- -- RX_MCS = DFF((!(CTT[] == 1)),CLK,,); RX_MCS.clk = CLK; -- RX_MRAS = MY5; RX_MRAS.clk = CLK; RX_MCAS = MY4; RX_MCAS.clk = CLK; RX_MWE = MY3; RX_MWE.clk = CLK;
-- return signals
-- write cycle -- WRITE = DFFE((MY[5..3] == B"100"),CLK,,,CTT_3); WRITE = DFFE((MY[5..3] == B"100"),CLK,,,CTT_4); -- mem cycle MEM_C = DFFE((MY[5..3] == B"001"),CLK,,,VCC); -- MEM_C = PA; -- read sysle READ = DFFE(((RWC_FIX[] == B"010") & (MY[5..3] == B"101")),CLK,,,CTT_3); -- data valid VALID = DFF(DFF(DFF(DFF(DFF(READ,CLK,,),CLK,,),CLK,,),CLK,,),CLK,,);
END;
Проверялся в работе на реальном проекте на Cyclone-II с рабочей частотой до 150MHz
Последний вариант AHDL кода этого же контроллера. Главное отличие в том, что сигнал синхронизации для SD-RAM формируется снаружи относительно этой схемы, и в организации раздельных каналов адреса для записи и для чтения (так было нужно для проекта)
[code]----------------------------------- -- Simple SDRAM controller -- page mode burst read/write -- latensy = 3, frq = 50..150MHz -- 2002-2010 (c) Ivan Mak -- E-mail: ivan_mak@mail.ru aka admin@winglion.ru -- http://winglion.ru -----------------------------------
TITLE "SDRAM_controller";
PARAMETERS ( WIDTH = 16, -- SDRAM data WIDTH OUT_SH = "YES", -- "YES" -- 1/2 clk data shift PRIORITY = "WRITE" -- "READ" или "WRITE" );
SUBDESIGN sdram ( CLK : INPUT; CLKs : input; RESET : INPUT;
-- dir signals
DI[WIDTH-1..0] : INPUT = GND; -- input data DO[WIDTH-1..0] : OUTPUT; -- output data
RA[23..0] : INPUT = GND; -- adress RAM WA[23..0] : INPUT = GND; -- adress RAM CS : INPUT = GND; -- select WR : INPUT = VCC; -- write RD : INPUT = VCC; -- read
STOP : INPUT = VCC; -- for sinhronize cycle
-- sdram signals
MD[WIDTH-1..0] : BIDIR; -- RAM data bus
MWE : OUTPUT; -- RAM signal WE MRAS : OUTPUT; -- RAM signal RAS MCAS : OUTPUT; -- RAM signal CAS
MCS : OUTPUT; -- RAM signal CS MBS[1..0] : OUTPUT; -- RAM signals BS1,BS0
MCKE : OUTPUT; -- RAM signal CKE MCLK : BIDIR; -- RAM signal CLK
MA[11..0] : OUTPUT; -- RAM adress bus
MDQM : OUTPUT;
-- return signals
MEM_C : OUTPUT; -- memory cycle WRITE : OUTPUT; -- write data READ : OUTPUT; -- data read VALID : OUTPUT;
) VARIABLE
ARGX[23..0] : DFFE; ARG[23..0] : NODE;
CTT[5..0] : DFFE; TAB[5..0] : DFF;
CTT_2 : NODE; CTT_3 : NODE; CTT_4 : NODE;
CT[3..0] : DFFE; -- counter
MX[11..0] : DFF; -- adress mux
MY[5..3] : DFF; -- dir mux
MDR[WIDTH-1..0] : DFF; -- data reg MDRX[WIDTH-1..0]: DFF; -- data reg MDRY[WIDTH-1..0]: DFF; -- data reg
PA : NODE;
RWC_FIX[2..0] : DFFE;
R/W : NODE;
WRITE_2 : NODE;
-- MCLKX : NODE; -- MCLKY : NODE; -- MCLKZ : NODE;
-- RX_MA[13..0]: DFF; -- RX_MCKE : DFF; -- RX_MBS[1..0]: DFF; -- -- RX_MCS : DFF; -- RX_MRAS : DFF; RX_MCAS : DFF; RX_MWE : DFF;
BEGIN
-- input address register
ARGX[].clk = CLK; -- ARGX[].ena = VCC; -- fixed adress when bank active ARGX[].ena = MEM_C; -- fixed adress when bank active -- IF (PRIORITY != "READ") and (PRIORITY != "WRITE") THEN -- ASSERT "PRIORITY parametr muast be READ or WRITE!"; -- END IF; IF PRIORITY == "WRITE" GENERATE CASE (RD,WR) IS WHEN 3 => ARGX[] = GND; WHEN 1 => ARGX[] = RA[]; WHEN 2,0 => ARGX[] = WA[]; END CASE; R/W = DFFE((!(RWC_FIX[] == B"X00") or !(MY[5..3] == B"011")),CLK,,,CTT_2); END GENERATE;
IF PRIORITY == "READ" GENERATE CASE (RD,WR) IS WHEN 3 => ARGX[] = GND; WHEN 1,0 => ARGX[] = RA[]; WHEN 2 => ARGX[] = WA[]; END CASE; R/W = DFFE(!(!(RWC_FIX[] == B"0X0") or !(MY[5..3] == B"011")),CLK,,,CTT_2); END GENERATE; ARG[] = ARGX[]; -- ARGX[].d = A[];
RWC_FIX[].clk = CLK; RWC_FIX[].ena = MEM_C; RWC_FIX[] = (RD,WR,CS);
-- micro count
CTT[].clk = CLK; CTT[].clrn = RESET; CTT[].ena = DFF((!(CT[] == 8) or STOP),CLK,,);
CTT_2 = DFF(CTT[] == 2,CLK,,); CTT_3 = DFF(CTT[] == 3,CLK,,); CTT_4 = DFF(CTT[] == 4,CLK,,);
IF CTT_2 THEN CTT[] = TAB[]; -- one command period ELSE CTT[] = CTT[] - 1; END IF;
-- SDRAM data
-- mode sdram bit2..0 - 000 - 1byte -- 001 - 2byte -- 010 - 4byte -- 011 - 8byte -- 111 - page -- other - reserved -- bit3 - 0 - seqential -- 1 - interleave -- bit6..4 - 010 - cas latency = 2 -- 011 - cas latency = 3 -- other - reserved -- bit7 - 0 (?test?) -- bit8 - 0 reserved -- bit9 - 0 burst read & burst write -- 1 burst read & single write -- bit11..10 - 00 reserved -- BS[1..0] - 00 reserved
-- sdram commands RAS,CAS,WE -- 000 - mode register write -- 001 - auto refresh -- cken=0 -> self refresh -- -- CS=H -> SR exit -- RCW=110 -> SR exit -- 010 - bank precharge -- A10=0 precharge bank -- -- A10=1 precharge all -- 011 - bank active -- 100 - write -- A10=1 - auto precharge -- 101 - read -- A10=1 - auto precharge -- 110 - burst stop -- 111 - no operation
-- R/W = DFFE((!(RWC_FIX[] == B"X00") or !(MY[5..3] == B"011")),CLK,,,CTT_2);
-- comand counter
CT[].clk = CLK; CT[].clrn = RESET; CT[].ena = CTT_2;
IF DFF((CT[3..0] == 12),CLK,,) THEN CT[] = 8; ELSE CT[] = CT[]+1; END IF;
-- SDRAM command & times table
TAB[].clk = CLK; MY[].clk = CLK;
CASE CT[3..0] IS -- MY[] -- RAS,CAS,WE
-- init commands WHEN 0 => TAB[] = 4; MY[] = B"010"; -- precharge ALL WHEN 1 => TAB[] = 4; MY[] = B"000"; -- set mode register WHEN 2 => TAB[] = 8; MY[] = B"001"; -- autorefresh WHEN 3 => TAB[] = 8; MY[] = B"001"; -- autorefresh WHEN 4 => TAB[] = 8; MY[] = B"001"; -- autorefresh WHEN 5 => TAB[] = 8; MY[] = B"001"; -- autorefresh WHEN 6 => TAB[] = 8; MY[] = B"001"; -- autorefresh WHEN 7 => TAB[] = 8; MY[] = B"001"; -- autorefresh
-- cycle commands (realy 5 items) WHEN 8 => TAB[] = 4; MY[] = B"011"; -- bank active -- ! words count (0->64) WHEN 9 => TAB[] = 0; MY[] = (B"10",R/W); -- bank read/write WHEN 10 => TAB[] = 4; MY[] = B"110"; -- burst stop! WHEN 11 => TAB[] = 4; MY[] = B"010"; -- bank precharge WHEN 12 => TAB[] = 8; MY[] = B"001"; -- autorefresh WHEN 13 => TAB[] = 4; MY[] = B"111"; -- NOP no executed WHEN 14 => TAB[] = 4; MY[] = B"111"; -- NOP no executed WHEN 15 => TAB[] = 4; MY[] = B"111"; -- NOP no executed END CASE;
MCLK = TRI(LCELL(!CLKs),VCC);
-- address MUX
PA = DFF(!(CT[2..0] == 0),CLK,,);
MX[].clk = CLK; CASE (CT3,PA) IS WHEN 0 => MX[] = (B"010000000000"); -- precharge all WHEN 1 => MX[] = (B"000000110111"); -- SDRAM mode WHEN 2 => MX[] = (ARG[21..10]); -- adress RAS -- 4k WHEN 3 => MX[] = (B"00",ARG[9..0]); -- adress CAS -- 1k END CASE;
-- input register
MDR[].clk = CLK; MDR[].d = DI[];
-- WRITE_2 = (DFF(DFF(DFF(WRITE,CLK,,),CLK,,),CLK,,)); WRITE_2 = DFF(DFF(WRITE or DFF(WRITE,CLK,,),CLK,,),CLK,,); -- WRITE_2 = DFF(WRITE,CLK,,);
FOR i IN 0 TO WIDTH-1 GENERATE MD[i] = TRI(MDR[i],WRITE_2); END GENERATE;
-- output register' -- for 1/2 shift
-- MDRX[].clk = !CLK; -- MDRX[].clk = !LCELL(CLK); MDRX[].clk = MCLK; MDRX[].d = MD[];
-- output register
MDRY[].clk = CLK;
IF (OUT_SH == "YES") GENERATE MDRY[].d = MDRX[]; -- 1/2 clk data shift ELSE GENERATE MDRY[].d = MD[]; -- no 1/2 clk data shift END GENERATE;
DO[] = MDRY[];
-- IF (M_REG == "YES") GENERATE -- MA[] = RX_MA[13..0]; ---- MCKE = RX_MCKE; -- MCKE = VCC; -- MBS[1..0] = RX_MBS[1..0]; -- MCS = RX_MCS; -- ---- MRAS = RX_MRAS; ---- MCAS = RX_MCAS; ---- MWE = RX_MWE; -- -- MRAS = DFF(DFF(RX_MRAS,CLK,,),CLK,,); -- MCAS = DFF(DFF(RX_MCAS,CLK,,),CLK,,); -- MWE = DFF(DFF(RX_MWE,CLK,,),CLK,,); -- -- MDQM = GND; -- ELSE GENERATE
MA[] = MX[];
-- (MDQM,MCKE,MRAS,MCAS,MWE,MBS1,MBS0) = (GND,VCC,MY[5..3],ARG[23..22]);
(MDQM,MCKE,MRAS,MCAS,MWE,MBS1,MBS0) = (GND,VCC,RX_MRAS,RX_MCAS,RX_MWE,ARG[23..22]);
-- RX_MRAS,RX_MCAS,RX_MWE
MCS = DFF((!(CTT[] == 1)),CLK,,);
-- END GENERATE; -- (MDQM,MCKE,MRAS,MCAS,MWE,MBS1,MBS0) = (GND,VCC,MY[5..3],ARG[23..22]);
-- RX_MA[13..0]= MX[]; -- RX_MCKE = VCC; -- RX_MBS[1..0]= ARG[23..22]; -- -- RX_MA[13..0].clk = CLK; -- RX_MCKE.clk = CLK; -- RX_MBS[1..0].clk = CLK; -- -- RX_MCS = DFF((!(CTT[] == 1)),CLK,,); RX_MCS.clk = CLK; -- RX_MRAS = MY5; RX_MRAS.clk = CLK; RX_MCAS = MY4; RX_MCAS.clk = CLK; RX_MWE = MY3; RX_MWE.clk = CLK;
-- return signals
-- write cycle -- WRITE = DFFE((MY[5..3] == B"100"),CLK,,,CTT_3); WRITE = DFFE((MY[5..3] == B"100"),CLK,,,CTT_4); -- mem cycle MEM_C = DFFE((MY[5..3] == B"001"),CLK,,,VCC); -- MEM_C = PA; -- read sysle READ = DFFE(((RWC_FIX[] == B"010") & (MY[5..3] == B"101")),CLK,,,CTT_3); -- data valid VALID = DFF(DFF(DFF(DFF(DFF(READ,CLK,,),CLK,,),CLK,,),CLK,,),CLK,,);
END;
[/code]
Проверялся в работе на реальном проекте на Cyclone-II с рабочей частотой до 150MHz
|
|
|
|
Добавлено: Чт апр 22, 2010 19:40 |
|
|
|
|
|
Заголовок сообщения: |
Re: Простой контролер SD-RAM на AHDL |
|
|
Цитата: Что нужно переделать в Вашем контроллере SDRAM (viewtopic.php?f=11&t=341) для работы с чипом от Микрона,типа MT48LC4M32B2 ( http://download.micron.com/pdf/datashee ... RAMx32.pdf)? 1. В первую очередь выставить параметр WIDTH =32. 2. Прогнать схему в симуляторе, в конкретном месте (с назначениями пинов), с конкретной ПЛИС, там где предполагается ее использовать. 3. "Поиграться" с установкой дополнительных задержек (на логических ячейках) для сигнала MCLK - синхронизации, подаваемой на SD-RAM с целью получения попадания фронта сигнала синхронизации в серединку импульса сигнала MCS. В идеальном варианте, если используемая ПЛИС имеет PLL, сделать на нем сигналы синхронизации CLK и MCLK со смещением по фазе относительно друг друга.
[quote]Что нужно переделать в Вашем контроллере SDRAM (viewtopic.php?f=11&t=341) для работы с чипом от Микрона,типа MT48LC4M32B2 (http://download.micron.com/pdf/datasheets/dram/sdram/128MbSDRAMx32.pdf)?[/quote]
1. В первую очередь выставить параметр WIDTH =32. 2. Прогнать схему в симуляторе, в конкретном месте (с назначениями пинов), с конкретной ПЛИС, там где предполагается ее использовать. 3. "Поиграться" с установкой дополнительных задержек (на логических ячейках) для сигнала MCLK - синхронизации, подаваемой на SD-RAM с целью получения попадания фронта сигнала синхронизации в серединку импульса сигнала MCS. В идеальном варианте, если используемая ПЛИС имеет PLL, сделать на нем сигналы синхронизации CLK и MCLK со смещением по фазе относительно друг друга.
|
|
|
|
Добавлено: Чт апр 22, 2010 18:58 |
|
|
|
|