/* * Двухтактовая память захвата FPGA: запись и чтение обслуживаются независимыми тактовыми * входами. Чтение регистровое, выход обновляется по rd_clk; одновременный доступ к одному * адресу требует учёта поведения выбранной FPGA-памяти. */ // Portable dual-clock capture RAM for FPGA logic analyzers. // The module intentionally contains no vendor primitives: Quartus infers M9K // blocks on Cyclone IV, while other tools may infer their native block RAM. module la_capture_buffer #( parameter SAMPLE_WIDTH = 16, parameter ADDR_WIDTH = 12 ) ( input wire wr_clk, input wire wr_en, input wire [ADDR_WIDTH-1:0] wr_addr, input wire [SAMPLE_WIDTH-1:0] wr_data, input wire rd_clk, input wire [ADDR_WIDTH-1:0] rd_addr, output reg [SAMPLE_WIDTH-1:0] rd_data ); // ADDR_WIDTH задаёт логарифм ёмкости: каждый дополнительный адресный бит // удваивает число хранимых отсчётов, не меняя разрядность одного отсчёта. localparam DEPTH = (1 << ADDR_WIDTH); reg [SAMPLE_WIDTH-1:0] memory [0:DEPTH-1]; // Разрешение записи действует только на фронте wr_clk. Память не имеет // сброса: до первой записи содержимое адреса не считается определённым. always @(posedge wr_clk) begin if (wr_en) memory[wr_addr] <= wr_data; end // Registered read is supported directly by Cyclone IV M9K blocks. // Нет rd_en: на каждом фронте читается текущий адрес. Согласование // владения областями между доменами частот выполняет внешняя логика. always @(posedge rd_clk) rd_data <= memory[rd_addr]; endmodule