При чтении данные выставляются по заднему фронту, а по документации должны по переднему.
Специально для проверки altsyncram собрал простой проект:
Параметризованное ПЗУ, AHDL
Код
INCLUDE "altsyncram.inc";
FUNCTION mROM_256x18_1port( clock, address[7..0] ) returns( q[17..0] );
PARAMETERS ( FILE_MIF = "FILE.MIF" );
SUBDESIGN mROM_256x18_1port
(
address[7..0] : INPUT;
clock : INPUT;
q[17..0] : OUTPUT;
)
VARIABLE
altsyncram_component : altsyncram WITH (
ADDRESS_ACLR_A = "NONE",
CLOCK_ENABLE_INPUT_A = "BYPASS",
CLOCK_ENABLE_OUTPUT_A = "BYPASS",
INIT_FILE = FILE_MIF,
INTENDED_DEVICE_FAMILY = "Cyclone V",
LPM_HINT = "ENABLE_RUNTIME_MOD=NO",
LPM_TYPE = "altsyncram",
NUMWORDS_A = 256,
OPERATION_MODE = "ROM",
OUTDATA_ACLR_A = "NONE",
OUTDATA_REG_A = "UNREGISTERED",
WIDTHAD_A = 8,
WIDTH_A = 18,
WIDTH_BYTEENA_A = 1
);
BEGIN
q[17..0] = altsyncram_component.q_a[17..0];
altsyncram_component.clock0 = clock;
altsyncram_component.address_a[7..0] = address[7..0];
END;
FUNCTION mROM_256x18_1port( clock, address[7..0] ) returns( q[17..0] );
PARAMETERS ( FILE_MIF = "FILE.MIF" );
SUBDESIGN mROM_256x18_1port
(
address[7..0] : INPUT;
clock : INPUT;
q[17..0] : OUTPUT;
)
VARIABLE
altsyncram_component : altsyncram WITH (
ADDRESS_ACLR_A = "NONE",
CLOCK_ENABLE_INPUT_A = "BYPASS",
CLOCK_ENABLE_OUTPUT_A = "BYPASS",
INIT_FILE = FILE_MIF,
INTENDED_DEVICE_FAMILY = "Cyclone V",
LPM_HINT = "ENABLE_RUNTIME_MOD=NO",
LPM_TYPE = "altsyncram",
NUMWORDS_A = 256,
OPERATION_MODE = "ROM",
OUTDATA_ACLR_A = "NONE",
OUTDATA_REG_A = "UNREGISTERED",
WIDTHAD_A = 8,
WIDTH_A = 18,
WIDTH_BYTEENA_A = 1
);
BEGIN
q[17..0] = altsyncram_component.q_a[17..0];
altsyncram_component.clock0 = clock;
altsyncram_component.address_a[7..0] = address[7..0];
END;
Проект для синтеза на SystemVerilog, чтобы получить netlist :
Код
module ROM_Coeff_AHDL(address,
data_out,
clock
);
input wire [7:0] address;
output reg [17:0] data_out;
input wire clock;
mROM_256x18_1port #(
.FILE_MIF ("filt_triangle.mif")
) inst_mROM_256x18_1port
(
.clock (clock),
.address (address),
.q (data_out)
);
endmodule
data_out,
clock
);
input wire [7:0] address;
output reg [17:0] data_out;
input wire clock;
mROM_256x18_1port #(
.FILE_MIF ("filt_triangle.mif")
) inst_mROM_256x18_1port
(
.clock (clock),
.address (address),
.q (data_out)
);
endmodule
Testbench на SystemVerilog, перебирает адреса:
Код
`timescale 1 ps/ 1 ps
module memory_short_tb();
wire [7:0] address;
wire [17:0] data_out;
reg clk;
reg [7:0] addr_counter;
ROM_Coeff_AHDL U_memory(
.address (address),
.data_out (data_out),
.clock (clk)
);
initial begin
clk = 0;
addr_counter = 0;
end
always #1 clk = ~clk;
always @ (posedge clk) begin
addr_counter++;
end // always
assign address = addr_counter;
endmodule
module memory_short_tb();
wire [7:0] address;
wire [17:0] data_out;
reg clk;
reg [7:0] addr_counter;
ROM_Coeff_AHDL U_memory(
.address (address),
.data_out (data_out),
.clock (clk)
);
initial begin
clk = 0;
addr_counter = 0;
end
always #1 clk = ~clk;
always @ (posedge clk) begin
addr_counter++;
end // always
assign address = addr_counter;
endmodule
Получилось так:

Данные изменяются по спаду, а не по фронту тактовых импульсов.
Согласно документации https://www.altera.com/content/dam/altera-w.../ug_ram_rom.pdf на стр. 3-2 данные должны изменяться с "Rising clock edges"
В чём дело? Кто-нибудь сталкивался с таким?