Jump to content

    

Dantist2k17

Участник
  • Content Count

    47
  • Joined

  • Last visited

Community Reputation

0 Обычный

About Dantist2k17

  • Rank
    Участник

Recent Profile Visitors

555 profile views
  1. Спасибо, попробую. Про DC не поспоришь.
  2. Была (есть) проблема, связанная с тем, что Yosys ругался на lib триггера, в котором при описании ff (IQ,IQB) { ... } next_state определяется выражением, например: next_state: (CE*D + !CE*IQ); а не просто как: next_state: D; Как мне рассказали программисты, проанализировавшие исходный код Yosys, там явно указано о том, что подобные выражения текущая версия не поддерживает, мол в разработке. Так что судя по всему дело не в либах. Однако сам Yosys имеет на вооружении команду dff2dffe, которая оптимизирует схему, выявляя ff с мультиплексорами в обратной связи и заменяя их на ffe. При этом в выходной netlist пишутся примитивы \$_DFFE_PP_. Всегда можно сделать автозамену, но это как-то...
  3. Добрый день. Разыскивается пример lib файла с описание FDE триггера для Yosys. Есть ли на форуме те, кто может проконсультировать по работе в Yosys?
  4. Добрый день. Собственно вопрос в названии темы. Необходимо, чтобы синтезатор не использовал инверсный выход триггеров, использую DC. Каким образом это можно реализовать? Надеялся на set_dont_use, но не прокатило.
  5. Большое спасибо, помогли. В DC я писал в файл и затем читал из него. Оказывается все просто...
  6. Приветствую! Стоит задача получить список связанных с net-ом ячеек. Не могу/не знаю как передать результат команды get_cells в переменную. Как пробовал... encounter 51> get_cells -of_objects [get_nets n400] U526 U525 U524 0x15 encounter 52> set a [get_cells -of_objects [get_nets n400]] 0x17 encounter 53> puts $a 0x17 encounter 54> get_cells -of_objects [get_nets n400] > 456 Usage: get_cells [-help] [-filter <expr>] [-hierarchical] [-hsc <char>] [-leaf] [-nocase] [-quiet] [-regexp] [ <patterns> | -of_objects <object_list> ] **ERROR: (ENCTCM-48): "456" is not a legal option for command "get_cells". Either the current option or an option prior to it is not specified correctly. encounter 55> exec echo [get_cells -of_objects [get_nets n400]] > 123 В файл 123 записывается "0x1a". Что посоветуете?
  7. И правда, спасибо. Какие еще общепризнанные методики (кроме использования кода Грея) используются при реализации FIFO? В Google не забанили, просто по запросу dual clock fifo ничего другого найти не удалось.
  8. Так я и и оперся на то, что сигнал инкрементальный, оперся при обнаружения факта ошибки распространения сигнала. Ошибка есть следствие метастабильности. Или ваша мысль в том, что код Грея лишь снижает вероятность появления ошибки, по той причине что только один бит переключается, а анализировать "историю" переключений особого смысла не имеет?
  9. Вернулся к работе и впал в ступор. Изменение 2 бит приведет к ошибочному формированию флагов FIFO, независимо от соотношения частот, ведь это фактически нарушение работы счетчика (чтения или записи) при синхронизации, следовательно флаги fifo нельзя считать достоверными...
  10. Не понял вопроса. Сами данные в FIFO никак не пострадают от этого, пострадает логика формирования флагов full и empty.
  11. Соглашусь, что не гарантирует, но почему же контроль не имеет смысла? Если я знаю, что отличие должно быть только в одном бите, то проверяя этот факт, имею право сделать вывод о возникновении сбоя... Мне видится вполне логичным.
  12. Разумеется что накладывает ограничения, ограничения сознательны. Для начала решил сделать так, следующий вариант уже будет отвязан от соотношения частот. Зачем "error" регистры? Для подстраховки, строгой нужды в них нет, просто пришла в голову идея их реализации вот и сделал. По-поводу задачи я согласен, корректная запись данных, а точнее корректное формирование флагов fifo и empty обеспечивается самой реализацией (логикой ее работы) с использованием кода Грея. Таким образом, способ реализации отвечает за то чтобы fifo работало корректно, а регистры error сигнализируют о том, что реализация не отработала (например под воздействием условий работы: изменение напряжения питания, температуры и т.д.), а следовательно данные нельзя считать достоверными. Что будет если найдена ошибка, это уже решать пользователю fifo, например не воспринимать только что прочитанные данные и подать сигнал сброса на fifo.
  13. Приветствую, рассчитываю получить компетентную оценку представленного verilog описания асинхронного FIFO. Интересы замечания к аппаратному исполнению, а также к "стилю" описания. Что касается условий использования такого FIFO: подразумевается что частоты сигналов clk_wr и clk_rd приблизительно равны, но асинхронны. Сама по себе идея построения FIFO классическая, от себя добавил два способа обнаружения ошибок, которые могут иметь место при синхронизации. Способ 1 основан на проверке утверждения о том, что "соседние" состояния счетчика в коде Грея отличаются на один бит, следовательно побитовое исключающее ИЛИ должно принимать значения равные степени двойки. Способ 2 основан на проверке того, что разность "соседних" значений счетчика в бинарном коде должна быть равна единице. Кто-нибудь практиковал подобные проверки? Имеет ли смысл тратить на это ресурсы? `timescale 1ns/1ps module fifo_tb; parameter WIDTH = 8; parameter DEPTH = 16; parameter real PER_clk_wr = 10.0; parameter real PER_clk_rd = 11.0; wire [WIDTH-1:0] data_out; wire fifo_empty; wire fifo_full; reg [WIDTH-1:0] data_in; reg write; reg read; reg clk_wr; reg clk_rd; reg reset; fifo #(WIDTH,DEPTH) UUT (.*); reg clk; reg double_read_write; initial begin data_in = '0; write = 1'b0; read = 1'b0; clk_wr = 1'b0; clk_rd = 1'b0; reset = 1'b1; // clk = 1'b0; double_read_write = 1'b0; end always #(PER_clk_wr/2) clk_wr <= ~clk_wr; always #(PER_clk_rd/2) clk_rd <= ~clk_rd; always #(PER_clk_rd >= PER_clk_wr ? PER_clk_rd/2 : PER_clk_wr/2) clk <= ~clk; initial begin repeat(3) @(posedge clk); reset = 1'b0; //write data to fifo while !full repeat(DEPTH) begin fifo_write; end wait(fifo_full); //read data from fifo while !empty repeat(DEPTH) begin fifo_read; end wait(fifo_empty); //write data to fifo, partly repeat($urandom_range(DEPTH/2,DEPTH/3)) begin fifo_write; end //write data to fifo, partly repeat($urandom_range(DEPTH/3,DEPTH/4)) begin fifo_read; end //write data to fifo, partly repeat($urandom_range(DEPTH/2,DEPTH/3)) begin fifo_write; end //read data from fifo while !empty while(!fifo_empty) begin fifo_read; @(posedge clk); end //write data to fifo, partly repeat($urandom_range(DEPTH/2,DEPTH/3)) begin fifo_write; end //"at the same time" write/read double_read_write = 1'b1; repeat(10) @(posedge clk); //read data from fifo while !empty while(!fifo_empty) begin fifo_read; @(posedge clk); end $finish; end task fifo_write; begin @(posedge clk_wr) begin write <= 1'b1; data_in <= $random; end @(posedge clk_wr) write <= 1'b0; end endtask task fifo_read; begin @(posedge clk_rd) read <= 1'b1; @(posedge clk_rd) read <= 1'b0; end endtask always@(posedge double_read_write) fifo_read; always@(posedge double_read_write) fifo_write; endmodule `timescale 1ns/1ps module fifo #( parameter WIDTH = 8, parameter DEPTH = 128) ( output reg [WIDTH-1:0] data_out, output reg fifo_empty, output reg fifo_full, input [WIDTH-1:0] data_in, input write, input read, input clk_wr, input clk_rd, input reset); reg [$clog2(DEPTH):0] pointer_write_bin; reg [$clog2(DEPTH):0] pointer_write_gray; reg [$clog2(DEPTH):0] pointer_read_bin; reg [$clog2(DEPTH):0] pointer_read_gray; reg [$clog2(DEPTH):0] register_wr_rd [2:0]; reg [$clog2(DEPTH):0] register_rd_wr [2:0]; reg [WIDTH-1:0] mem [DEPTH-1:0]; integer i; //pointer write always@(posedge clk_wr) begin if(reset) pointer_write_bin <= 0; else if(write & !fifo_full) pointer_write_bin <= pointer_write_bin + 1'b1; end always@(posedge clk_wr) begin if(reset) pointer_write_gray <= 0; else pointer_write_gray <= (pointer_write_bin >> 1) ^ pointer_write_bin; end //pointer read always@(posedge clk_rd) begin if(reset) pointer_read_bin <= 0; else if(read & !fifo_empty) pointer_read_bin <= pointer_read_bin + 1'b1; end always@(posedge clk_rd) begin if(reset) pointer_read_gray <= 0; else pointer_read_gray <= (pointer_read_bin >> 1) ^ pointer_read_bin; end //write and read register always@(posedge clk_wr) begin if(write & !fifo_full) mem[pointer_write_bin[$clog2(DEPTH)-1:0]] <= data_in; end always@(posedge clk_rd) begin if(reset) data_out <= 0; else if(read & !fifo_empty) data_out <= mem[pointer_read_bin[$clog2(DEPTH)-1:0]]; end //transmit pointer through clock domain, value have code Gray always@(posedge clk_wr) begin if(reset) for(i = 0;i < 3;i = i + 1) begin register_rd_wr[i] <= 0; end else for(i = 0;i < 3;i = i + 1) begin if(i != 0) register_rd_wr[i] <= register_rd_wr[i-1]; else register_rd_wr[i] <= pointer_read_gray; end end always@(posedge clk_rd) begin if(reset) for(i = 0;i < 3;i = i + 1) begin register_wr_rd[i] <= 0; end else for(i = 0;i < 3;i = i + 1) begin if(i != 0) register_wr_rd[i] <= register_wr_rd[i-1]; else register_wr_rd[i] <= pointer_write_gray; end end //register flags full and empty always@(posedge clk_rd) begin if(reset) fifo_empty <= 1'b1; else begin if(read & (register_wr_rd[1] == (((pointer_read_bin + 1) >> 1) ^ (pointer_read_bin + 1 )))) fifo_empty <= 1'b1; else if(register_wr_rd[1] != ((pointer_read_bin >> 1) ^ pointer_read_bin)) fifo_empty <= 1'b0; end end always@(posedge clk_wr) begin if(reset) fifo_full <= 1'b0; else begin if(write & ({~register_rd_wr[1][$clog2(DEPTH):$clog2(DEPTH)-1],register_rd_wr[1][$clog2(DEPTH)-2:0]} == (((pointer_write_bin + 1) >> 1) ^ (pointer_write_bin + 1)))) fifo_full <= 1'b1; else if({~register_rd_wr[1][$clog2(DEPTH):$clog2(DEPTH)-1],register_rd_wr[1][$clog2(DEPTH)-2:0]} != (((pointer_write_bin) >> 1) ^ (pointer_write_bin))) fifo_full <= 1'b0; end end //Detect error, method 1 reg error_writer_m1; reg error_reader_m1; reg [$clog2(DEPTH):0] register_compare_writer; reg [$clog2(DEPTH):0] register_compare_reader; integer k; always@(*) begin for(k = 0;k <= $clog2(DEPTH);k = k + 1) begin if((register_rd_wr[2] ^ register_rd_wr[1]) == 2**k) register_compare_writer[k] <= 1'b1; else register_compare_writer[k] <= 1'b0; end end always@(*) begin for(k = 0;k <= $clog2(DEPTH);k = k + 1) begin if((register_wr_rd[2] ^ register_wr_rd[1]) == 2**k) register_compare_reader[k] <= 1'b1; else register_compare_reader[k] <= 1'b0; end end always@(posedge clk_wr) begin if(reset) error_writer_m1 <= 1'b0; else if(register_rd_wr[2] != register_rd_wr[1]) error_writer_m1 <= !(|register_compare_writer); end always@(posedge clk_rd) begin if(reset) error_reader_m1 <= 1'b0; else if(register_wr_rd[2] != register_wr_rd[1]) error_reader_m1 <= !(|register_compare_reader); end //Detect error, method 2 reg error_writer_m2; reg error_reader_m2; reg [$clog2(DEPTH):0] grey2bin_writer_old; reg [$clog2(DEPTH):0] grey2bin_writer_cur; reg [$clog2(DEPTH):0] grey2bin_reader_old; reg [$clog2(DEPTH):0] grey2bin_reader_cur; always@(*) begin for(k = 0; k <= $clog2(DEPTH);k = k + 1) grey2bin_writer_old[k] = ^(register_rd_wr[2] >> k); end always@(*) begin for(k = 0; k <= $clog2(DEPTH);k = k + 1) grey2bin_writer_cur[k] = ^(register_rd_wr[1] >> k); end always@(*) begin for(k = 0; k <= $clog2(DEPTH);k = k + 1) grey2bin_reader_old[k] = ^(register_wr_rd[2] >> k); end always@(*) begin for(k = 0; k <= $clog2(DEPTH);k = k + 1) grey2bin_reader_cur[k] = ^(register_wr_rd[1] >> k); end always@(posedge clk_wr) begin if(reset) error_writer_m2 <= 1'b0; else if(register_rd_wr[2] != register_rd_wr[1]) error_writer_m2 <= (grey2bin_writer_old + 1) != grey2bin_writer_cur; end always@(posedge clk_rd) begin if(reset) error_reader_m2 <= 1'b0; else if(register_wr_rd[2] != register_wr_rd[1]) error_reader_m2 <= (grey2bin_reader_old + 1) != grey2bin_reader_cur; end endmodule
  14. В моем случае была "свой атмосфера" схема описывалась на verilog, при этом разводилась руками. Была необходимость не плодить модули, а всегда обращаться к одному. О том, что нет информации по окружению пока не сделан полный синтез, я тогда по правде сказать и не задумывался.