Внешний входной сигнал SCK, например от интерфейса SPI, и внутренний системный сигнал CLK микросхемы FPGA являются асинхронными друг относительно друга. Поэтому в какие-то моменты времени может возникать ситуация, когда переключения сигналов возникают в одно и тоже время. Т.е. фронт сигнала CLK, по которому работает логика в FPGA, совпадает с фронтом/спадом внешнего сигнала.
В таких случаях D-триггер не может достоверно "захватить" входной сигнал, возникает неопределенность на его выходе - напряжение не "0" и не "1". Это неопределенное состояние не может длиться долго, и через некоторое время за счет внутренних токов выход уплывет либо в "0", либо в "1". Но, в течение этого времени нельзя неопределенное состояние пропускать дальше в схему. Поэтому, используется второй и более D-триггеров в цепочке, которые не пропускают эту неопределенность дальше. Предполагается, что к моменту выхода из цепочки D-триггеров неопределенность должна исчезнуть.
module spi_slave( input clk, input SCK, ... ); reg [2:0] SCK_sync; always @(posedge clk) SCK_sync <= {SCK_sync[1:0], SCK}; wire SCK_rising_edge = (SCK_sync[2:1]==2'b01); // detect SCK rising edges wire SCK_falling_edge = (SCK_sync[2:1]==2'b10); // detect SCK falling edges ... endmodule
Links:
Непрерывное присваивание, =
wire [1:0] a; wire [1:0] b = 2'b10; assign a = b + 2'b01;
Неблокирующее присваивание, ⇐
reg [1:0] a; reg [1:0] b; always @(posedge clk) begin if (swap_en) begin a <= b; b <= a; end; end
Блокирующее присваивание, =
always @(posedge clk) begin x = x + 1; y = x; end равнозначно always @(posedge clk) begin x <= x + 1; y <= x + 1; end
Links:
Регистровый тип является логической сущностью Верилога и не всегда превращается в физический регистр при синтезе. Иногда регистровый тип нужен для того, чтобы обойти некоторые ограничения синтаксиса языка.
reg [7:0] data_in; always case ({cpu_memr,cpu_inport,interrupt}) 3'b100: data_in <= ram_data; 3'b010: data_in <= io_data; 3'b001: data_in <= 8'hFF; default: data_in <= 8'hZZ; endcase
Несмотря на то, что переменная data_in формально является регистром, она будет синтезирована как обычная шина типа wire, а присоединена эта шина будет к выходу описанного оператором case мультиплексора. Переменная регистрового типа превращается в регистр только тогда, когда её присваивание происходит по перепаду тактового сигнала. В противном же случае она фактически является эквивалентом переменной типа wire.
Links:
clog2(N) = ceil(log2(N))
Функция $clog2(N) возвращает количество бит, необходимых для хранения N значений. Или можно считать что это количество бит адреса, для памяти размером N.
Важно, что само число N может и не влезть в полученное количество бит! Например, $clog2(8) = 3. Эти три бита позволяют хранить 8-мь значений от 0 (3'b000) до 7 (3'b111), но само число 8 требует 4 бита для представления.
Поэтому для хранения самого числа N необходимо использовать $clog2(N+1):
N | $clog2(N) | $clog2(N+1) | N Binary |
---|---|---|---|
0 | 0 | 0 | 1'b0 |
1 | 0 | 1 | 1'b0 |
2 | 1 | 2 | 2'b10 |
3 | 2 | 2 | 2'b11 |
4 | 2 | 3 | 3'b100 |
5 | 3 | 3 | 3'b101 |
6 | 3 | 3 | 3'b110 |
7 | 3 | 3 | 3'b111 |
8 | 3 | 4 | 4'b1000 |
9 | 4 | 4 | 4'b1001 |
Прочие функции: verilog-math-functions
module CLK_Div_Period #( parameter CLK_PERIOD = 2 ) ( input clk, input rst_n, output o_clk ); localparam CNT_BITS = $clog2(CLK_PERIOD+1); reg [CNT_BITS-1:0] count; reg r_dv; assign o_clk = r_dv; always @(posedge clk or negedge rst_n) begin if (~rst_n) begin count <= {CNT_BITS{1'b0}}; r_dv <= 1'b0; end else begin if (count == (CLK_PERIOD - 1)) begin count <= {CNT_BITS{1'b0}}; r_dv <= 1'b1; end else begin count <= count + 1'b1; r_dv <= 1'b0; end end end endmodule
Если верить этой ссылке Stackoverflow: Adding large numbers in FPGA in one clock cycle, то асинхронная схема дает меньшее быстродействие. Потому что, входные сигналы приходят на сумматор откуда-то "издалека" (где они формируются), и выходные сигналы уходят куда-то "вдаль", туда где они используются дальше. Эти задержки распространения снижают максимальную частоту работы схемы.
В случае с синхронной логикой, результат сложения "сохраняется" в ближайший регистр. Поэтому сумматор может работать на большей частоте.
Это относится не только к сумматору, но и к любой другой коммутационной схеме.
wire [Y_DATA_BITS-1:0] y_max = {{1'b0},{Y_DATA_BITS-1{1'b1}}}; wire [Y_DATA_BITS-1:0] y_min = {{1'b1},{Y_DATA_BITS-1{1'b0}}};
При сравнении чисел разной разрядности будет расширено число с меньшей разрядностью. Старшим битом, если число знаковое, и 0-м если число беззнаковое.
Warning: (vsim-3016) Port type is incompatible with connection (port 'clock').
Warning выскочил при назначении сигнала clk на вход clock модуля altsyncram (мегафункция встроенной памяти). Решение нашлось тут: link
// =========== SinMem.v (Generated by Quartus megafunction) ============= module SinMem ( address, clock, q); input [11:0] address; input clock; output [15:0] q; `ifndef ALTERA_RESERVED_QIS // synopsys translate_off `endif tri1 clock; `ifndef ALTERA_RESERVED_QIS // synopsys translate_on `endif wire [15:0] sub_wire0; wire [15:0] q = sub_wire0[15:0]; altsyncram altsyncram_component ( .address_a (address), .clock0 (clock), .q_a (sub_wire0), .aclr0 (1'b0), .aclr1 (1'b0), .address_b (1'b1), .addressstall_a (1'b0), .addressstall_b (1'b0), .byteena_a (1'b1), .byteena_b (1'b1), .clock1 (1'b1), .clocken0 (1'b1), .clocken1 (1'b1), .clocken2 (1'b1), .clocken3 (1'b1), .data_a ({16{1'b1}}), .data_b (1'b1), .eccstatus (), .q_b (), .rden_a (1'b1), .rden_b (1'b1), .wren_a (1'b0), .wren_b (1'b0)); defparam altsyncram_component.address_aclr_a = "NONE", altsyncram_component.clock_enable_input_a = "BYPASS", altsyncram_component.clock_enable_output_a = "BYPASS", altsyncram_component.init_file = "SinTable.mif", altsyncram_component.intended_device_family = "Cyclone V", altsyncram_component.lpm_hint = "ENABLE_RUNTIME_MOD=NO", altsyncram_component.lpm_type = "altsyncram", altsyncram_component.numwords_a = 4096, altsyncram_component.operation_mode = "ROM", altsyncram_component.outdata_aclr_a = "NONE", altsyncram_component.outdata_reg_a = "CLOCK0", altsyncram_component.widthad_a = 12, altsyncram_component.width_a = 16, altsyncram_component.width_byteena_a = 1; endmodule // ======= Implementation ======= // test.v module test( input rst_n, input clk, ... ); wire clk_fix = clk; SinMem sinTable( .address(addr), .clock (clk_fix), // OK //.clock (clk), - Warning: (vsim-3016) Port type is incompatible with connection (port 'clock'). .q (data) );