Jump to content

    

stealthisname

Участник
  • Content Count

    28
  • Joined

  • Last visited

Everything posted by stealthisname


  1. по заданию требуется возможность генерации модуля с разным размером окна и разрешены размеры окна по степеням двойки, поэтому в модуле можно в качестве параметра задавать степень (FIFO_LEN_LOG) и на основе ее рассчитывать размер окна (FIFO_LEN) parameter FIFO_LEN_LOG = 4; localparam FIFO_LEN = (1 << FIFO_LEN_LOG); обьявление, инициализация и работа внутренней памяти (FIFO) останется прежней, но с учетом новых параметров reg [15:0] FIFO [0:FIFO_LEN-1]; integer i; initial begin for(i = FIFO_LEN-1; i >= 0; i=i-1) begin FIFO[i] = 16'd0; end end always @(posedge clk) begin for(i = FIFO_LEN-1; i > 0; i=i-1) begin FIFO[i] <= FIFO[i-1]; end FIFO[0] <= datain; end как было замечено выше в обсуждении темы, для вычисления результата суммирования (fifo_sum) с использованием предыдущего результата рассчета количество сложений может быть уменьшено reg [FIFO_LEN_LOG+15:0] fifo_sum = 0; always @(posedge clk) begin fifo_sum <= fifo_sum + datain - FIFO[FIFO_LEN-1]; end деление результата суммирования также можно записать с учетом параметров assign dataout = fifo_sum >> FIFO_LEN_LOG; весь модуль у меня получился таким модуль проверялся вот таким тестбенчем результаты моделирования сигнал с выхода параметризованного варианта с размером окна как у оригинального повторяет сигнал с выхода оригинального блока, сигнал с выхода параметризованного варианта с большим размером окна отсеивает больше шума
  2. вот такие результаты моделирования получились элементы на границе матрицы не должны рассчитываться по алгоритму и они действительно выдаются не определенными в выходных данных с проверяемого модуля но среди тех значений, которые должны рассчитываться по алгоритму, самый первый рассчитывается точно с ошибкой по сигналам внутри проверяемого модуля видно, что так происходит потому что не загружается нулевой элемент в память входных данных, поэтому не происходит расчета по этому элементу если исправить загрузку входных данных в память, то дальше останется только проверят непосредственно математику расчетов
  3. необходимо написать тестбенч для разрабатываемого модуля. в тетбенче будет установлен проверяемый модуль и сформированы все входные сигналы для проверки работы разрабатываемого модуля (у меня тут проверяемый модуль называется sobel_8x8_top) `timescale 1 ns / 1 ps module sobel_8x8_top_tb(); reg clk = 0; always #(10.0/2) begin clk = ~clk; end reg data_in ; reg data_out ; reg [7:0] element ; wire [7:0] outmatrix ; sobel_8x8_top sobel_8x8_top_i ( .clk (clk), .data_in (data_in ), .data_out (data_out ), .element (element ), .outmatrix(outmatrix ) ); initial begin ... // формирование входных сигналов ... end endmodule в разрабатываемом модуле сигналы загрузки данных используются для сброса счетчиков, поэтому перед загрузкой они выдерживаются с большим запасом // инициализация, сброс счетчиков модуля data_in = 0; data_out = 0; element = 0; repeat(5) @(posedge clk); в самом простом случае для проверки загрузки-выгрузки данных, загружаем рандомные числа // загрузка данных data_in = 1; data_out = 0; repeat(64) begin element = $random; @(posedge clk); end в разрабатываемом модуле расчеты зарегистрены в несколько стадий, поэтому ждем с запасом завершения всех расчетов // ожидание рассчета data_in = 0; data_out = 0; element = 0; repeat(10) @(posedge clk); после завершения расчетов выгружаем данные // выгрузка рассчитанных данных data_in = 0; data_out = 1; element = 0; repeat(64) begin @(posedge clk); end так как тест очень простой и данные загружались рандомные, тут скорее проверяется сам механизм загрузки-выгрузки и выполнения внутренних операций по тактам весь такой простой тестбенч получился примерно таким
  4. есть 2 счетчика. Значение первого счетчика (count1) после определенного события (inp_event) запоминается, второй счетчик (count2) должен генерировать каждые 1/6*count1 тактов сигнал готовности (out_en) для начала требуется написать логику работы первого счетчика (count1), тут он просто со сбросом по резету (reset) always @(posedge clk) begin if (reset) begin count1 <= 0; end else begin count1 <= count1 + 1; end end для второго счетчика (count2) требуется отсчитать 1/6 от первого счетчика (count1), такое значение будет отсчитывать отдельный счетчик (count1_divby_6), отдельный счетчик (count1_divby_6) будет вести отсчет в шесть раз медленнее, по сигналу (cnt6_eq_1) сигнал (cnt6_eq_1) будет формироваться вспомогательным счетчиком (cnt6), который будет отсчитывать по 6 тактов always @(posedge clk) begin if (reset) begin cnt6 <= 0; cnt6_eq_1 <= 0; count1_divby_6 <= 0; end else begin cnt6 <= cnt6 + 1; if (cnt6==5) begin cnt6 <= 0; end cnt6_eq_1 <= (cnt6==1); if(cnt6_eq_1) begin count1_divby_6 <= count1_divby_6 + 1; end end end идея добавления отдельного счетчика (count1_divby_6) состоит в том, что пока первый счетчик (count1) отсчитывает 0,1,2,3,4,5,6,7,8,9 и т.д., вспомогательный счетчик (cnt6) отсчитывает 0,1,2,3,4,5,0,1,2,3 и т.д., отдельный счетчик (count1_divby_6) отсчитывает 0,0,0,1,1,1,1,1,1,2, и т.д., то есть значение отдельного счетчика (count1_divby_6) отсчитываются как 1/6 от первого счетчика (count1), причем значение отдельного счетчика (count1_divby_6) сразу округлено до ближайшего целого примерно вот так: count1 : 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17,18 ... cnt6 : 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0 ... cnt6_eq_1 : 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 ... count1_divby_6: 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3 ... после определенного события (inp_event) при запоминании значения от первого счетчика (count1_event_val), запоминаем и значение, деленное на 6 (count1_divby_6_event_val) always @(posedge clk) begin if (reset) begin count1_event_val <= 0; count1_divby_6_event_val <= 0; end else if (inp_event) begin count1_event_val <= count1; count1_divby_6_event_val <= count1_divby_6; end end второй счетчик (count2) не должен считать до определенного события (inp_event), а значит нужно сформировать сигнал (inp_event_done), определяющий, произошло ли уже определенное событие (inp_event) always @(posedge clk) begin if (reset) begin inp_event_done <= 0; end else if (inp_event) begin inp_event <= 1; end end далее для второго счетчика (count2) мы можем использовать значение, деленное на 6 (count1_divby_6_event_val) always @(posedge clk) begin if (reset) begin count2 <= 0; out_en <= 0; end else if (inp_event_done) begin count2 <= count2 + 1; out_en <= 0; if (count2==(count1_divby_6_event_val-1)) begin count2 <= 0; out_en <= 1; end end end