У меня есть ПЛИС Spartan-6, подключенная к интерфейсу памяти AEMIF на SoC TI DaVinci DM365, которым я управляю. AEMIF настроен в режиме Select Strobe. Я пытаюсь реализовать чтение/запись памяти на FPGA через этот интерфейс, но это не работает. Аппаратное обеспечение работает, и эта функциональность работала до того, как была написана на VHDL (не мной). Я новичок в HDL, поэтому, возможно, здесь есть что-то явно поддельное.
Трудно сказать, что на самом деле происходит, поскольку тактовая частота составляет 60 МГц, а мой осциллограф/логический анализатор изо всех сил пытается работать так быстро.
Изменить: с тех пор у меня это работает. Установка drive_data комбинаторным способом означала, что при чтении старое значение памяти выбрасывалось на шину данных, а затем последовательная логика подбирала новый адрес и изменяла данные в течение цикла.
module main(
input EM_A_3,
input EM_A_7,
input EM_CLK,
inout [15:0] EM_D,
input EM_nCE1,
input EM_nOE,
input EM_nWE
);
wire [1:0] em_addr;
/* temporary storage for emif "registers" */
reg [15:0] mem [0:3];
reg [15:0] em_outdata;
supply0 rst; // reset always 0 for now
wire drive_data;
initial
begin: FOO
integer i;
for (i = 0; i < 4; i = i + 1) begin
mem[i] = 8'b0;
end
em_outdata = 8'b1;
end
// drive EM_D when CE1, OE are low, and WE is high
assign drive_data = !EM_nCE1 && !EM_nOE && EM_nWE;
assign EM_D = drive_data ? em_outdata : 8'bz;
assign em_addr = {EM_A_7, EM_A_3};
// clocked version (not working yet)
always @ (posedge EM_CLK)
begin
if (!EM_nCE1 && !EM_nWE) begin
mem[em_addr] <= EM_D;
end
if (!EM_nCE1 && !EM_nOE && EM_nWE) begin
em_outdata <= mem[em_addr];
end
end
endmodule
У меня это работает, с одним конкретным изменением, хотя, честно говоря, некоторые другие правки тоже могли помочь.
Я думал о том, как настраивается drive_data с помощью комбинаторной логики, но регистр outdata тактируется. Подтверждено поведенческим моделированием, это означает, что устаревшие данные удаляются в течение первой части цикла чтения, прежде чем адрес будет зафиксирован.
Я «исправил» это, изменив блок always, который устанавливает outdata, чтобы он делал это каждый такт, что означает, что правильные данные поступают туда во время фазы установки, пока адрес действителен на шине, до того, как появится строб OE.
Я также преобразовал обработку шины памяти в подмодуль (инвертируя управляющие сигналы).
module emif(
input clk,
input [1:0] addr,
inout [15:0] data,
input ce, // note these signals are active high
input we, // (opposite to the PCB signals)
input oe
);
wire drive_data;
reg [15:0] mem [0:3];
reg [15:0] em_outdata;
assign drive_data = ce && oe && !we;
assign data = drive_data ? em_outdata : 16'bz;
// writes data to small mem
always @ (posedge clk)
begin
if (ce && we) begin
mem[addr] <= data;
end
end
// reads data from small mem
always @ (posedge clk)
begin
em_outdata <= mem[addr];
end
endmodule
Я не уверен в точных таймингах SDRAM, но просто комментирую ваш стиль Verilog, может помочь несколько вещей. Вам нужно начать думать с точки зрения аппаратного обеспечения. Это может быть легче понять.
assign EM_D = drive_data ? em_outdata : 16'bz;
assign drive_data = !EM_nCE1 & !EM_nOE & EM_nWE;
// writes data to small mem
always @ (posedge EM_CLK)
begin
if (!EM_nCE1 && !EM_nWE) begin
mem[em_addr] <= EM_D;
end
end
// reads data from small mem
always @ (posedge EM_CLK)
begin
if (!EM_nCE1 && !EM_nOE && EM_nWE) begin
em_outdata <= mem[em_addr];
end
end
// see any problem? please change this logic. it doesn't seem to go anywhere.
always @ (posedge EM_CLK)
begin
if (!EM_nCE1 && !EM_nWE) begin
outbit <= 1;
end else if (!EM_nCE1 && !EM_nOE && EM_nWE) begin
outbit <= 0;
end else
outbit <= X; // *** Not sure what's the default/reset cond is.
end
Кроме того, вы можете захотеть переместить свой блок initial-begin из этого файла, так как он обычно является конструкцией моделирования, и в этом случае он в любом случае не будет синтезируемым. Обычно лучше отделить моделируемые конструкции от синтезируемых конструкций.
Если вы хотите сбросить содержимое ОЗУ, вы можете либо использовать инструмент FPGA для установки начального содержимого ОЗУ, либо разработать небольшой блок, который сбрасывает ОЗУ при включении питания.
Удачи. И дайте мне знать, если это поможет. :)
initial
блоки могут быть синтезированы для ПЛИС. Они сообщают компилятору, какое состояние должно быть в конце настройки, а это не то же самое, что сброс.Трудно сказать, что на самом деле происходит, поскольку тактовая частота составляет 60 МГц, а мой осциллограф/логический анализатор изо всех сил пытается работать так быстро.
Используйте ChipScope (Xilinx) или SignalTap (Altera). Это отлично подходит для этого и может дать вам много ширины, если не глубины.
Мартин Томпсон
Кевин Вермеер
синее смещение