Crossing clock domain for rarly changing data - clock

I need to connect a configuration module (running at slower clock) to a worker which runs at higher speed. Standard answer seems to be a FIFO but I thought I come up with a simpler solution which consumes less resources - with drawback of having much higher latency. Benefit for me is that I don't need to regenerate FIFO IP for each possible size of data. In RTL simulation it seems to work (I run into troubles using post-synthesis one unrelated to question).
Am I missing something or is the following code correct:
module fifo_int#( // This is bad name. I haven't come up with better yet
parameter type DATA = logic [31:0]
)(
input logic rst,
input logic clk_in,
input DATA din,
input logic clk_out,
output DATA dout
);
DATA dreg;
enum logic [1:0] {
IN,
STABLE,
WAIT_OUT
} in_state;
enum logic [1:0] {
WAIT_IN,
WRITE,
INV
} out_state;
logic in_output[3], out_output[3];
initial begin
in_state <= IN;
out_state <= WAIT_IN;
for (int i = 0; i < 3; i++) begin
in_output[i] <= 0;
out_output[i] <= 0;
end
end
always #(posedge clk_in)
begin
case (in_state)
IN: begin
dreg <= din;
in_state <= STABLE;
end
STABLE: begin
in_state <= WAIT_OUT;
in_output[0] <= ~in_output[0];
end
WAIT_OUT: begin
in_state <= (in_output[0] == out_output[2]) ? IN : WAIT_OUT;
end
endcase
out_output[1] <= out_output[0];
out_output[2] <= out_output[1];
end
always #(posedge clk_out)
begin
case (out_state)
WAIT_IN: begin
out_state <= (in_output[2] == out_output[0]) ? WAIT_IN : WRITE;
end
WRITE: begin
dout <= dreg;
out_state <= INV;
end
INV: begin
out_output[0] <= ~out_output[0];
out_state <= WAIT_IN;
end
endcase
in_output[1] <= in_output[0];
in_output[2] <= in_output[1];
end
endmodule

If your clocks are asynchronous, you're going to need synchronization.
For synchronous clocks, since your slow side is the one producing the data, you don't need any buffering. Data is anyway held stable for multiple (fast) clock cycles, so you don't really need any logic between the domains.

Related

I couldn't find the error in my binary search function

I don't know why this function I made in pascal only gives the index of the number I'm searching for (n) and doesn't give -1 when it doesnt find it..
(i checked theres no problem with other functions the only problem is that is doesnt print the message 'num is not here' when it doesnt exist) i would also appreciate it if someone points out where my code could have been more efficient.
`
Function binary_search(L : Array Of Integer; n : Integer) : Integer;
Var
i, p, middle, first, last : Integer;
Begin
first := 0;
binary_search := -1;
last := Sizeof(L) Div Sizeof(L[0]);
While (first <= last) Do
Begin
middle := (first + last) Div 2;
If (middle = n) Then
Begin
binary_search := middle;
break;
End;
If (middle < n) Then first := middle +1;
If (middle > n) Then last := middle -1;
End;
End;
Begin
Write('num of elements in array : ');
read(m);
fillup(arr, m);
For i :=0 To m-1 Do
Begin
permutarr[i] := arr[i];
End;
Write('the num youre looking for : ');
read(A);
sort(arr, 1, m);
If (binary_search(arr, A)= -1) Then Writeln('the number isnt here') //this doesnt work
Else
Begin
For i:=0 To m-1 Do
Begin
If (permutarr[i] = binary_search(arr, A)) Then
Begin
Writeln('index : ', i);
break;
End;
End;
End;
End.
`
I am not familiar with your dialect of Pascal (it's been 15 years since I did any serious programming), but I'm quite sure that the chief problem is that
Your code is not looking at the entries of the array L at all!
All the comparisons in the function binary_search only involve the indices, middle, first, last. The first thing I would try is to edit all the comparisons with middle to use L[middle] instead (on lines 11, 16 and 17). Then your code will, at least, actually be looking at the array :-)
Other things:
I'm not 100 per cent sure that your code handles arrays of all lengths correctly (can't test right now). It might happen that first and last never meet. I'm probably wrong about this, because then your code would get stuck in an endless loop.
When I was coding I took care never to assign a value to the function_name, here binary_search prematurely. In other words, I would not be surprised to learn that your function always returns $-1$, because I fully expect the execution of a function to end the instant anything is assigned to it, so here at the line binary_search:=-1;. As I said, my dialect was different, and the recollection is "dated" at best.
Anyway, the problem in bold fits your description of the problematic behavior. You can test my theory by giving A a value that exceeds the length of the array. Then it should be unable to find it with your current code.

How to write consecutive case statements?

I got an assignment to make a 4-bit booth multiplier with unsigned inputs in Verilog.
I've only used verilog a few times before this, so I'm not too familiar in writing case statements in it.
module booth(ina,inb,out);
input [3:0] ina, inb;
output[7:0] out;
reg[2:0] p1,p2;
reg[5:0] temp1, temp2;
assign p1={inb[2],inb[1],0};
assign p2={inb[3],inb[2],inb[1]};
always #(*)
begin
out = 8'b00000000;
case(p1)
3'b000: temp1=0;
3'b010: temp1=ina;
3'b100:temp1=-2 * ina;
3'b110:temp1= -ina;
endcase
end
begin
case(p2)
3'b000,3'b111: temp2=0;
3'b001,3'b010: temp2=ina;
3'b011:temp2=2 * ina;
3'b100:temp2=-2 * ina;
3'b101,3'b110:temp2= -ina;
endcase
temp2 = temp2<<2;
end
assign out=temp1+temp2;
endmodule
How am I supposed to write two case statements in a row?
I get a syntax error:
syntax error near text: "begin"; expecting "endmodule". Check for and fix any syntax errors that appear immediately before or at the specified keyword.
There are several compile errors.
Your error message probably refers to the 2 consecutive begin/end blocks after your always statement. One way to fix this is to add a 2nd always statement. It is a good idea to separate the temp1 and temp2 logic this way.
I also get an error for p1 because you make a continuous assignment to it with an assign statement. You should declare the signal as a wire, not a reg. Change:
reg [2:0] p1,p2;
to:
wire [2:0] p1,p2;
Another problem is that you make multiple assignments to the out signal. I think you probably want to remove it from the always block.
Lastly, you need to use a sized constant for 0 in the p1 statement. Change:
assign p1={inb[2],inb[1],0};
to:
assign p1={inb[2],inb[1],1'b0};
This code compiles cleanly for me:
module booth (ina, inb, out);
input [3:0] ina, inb;
output [7:0] out;
wire [2:0] p1,p2;
reg [5:0] temp1, temp2;
assign p1 = {inb[2], inb[1], 1'b0};
assign p2 = {inb[3], inb[2], inb[1]};
always #(*) begin
case (p1)
3'b000: temp1 = 0;
3'b010: temp1 = ina;
3'b100: temp1 = -2 * ina;
3'b110: temp1 = -ina;
endcase
end
always #(*) begin
case(p2)
3'b000,3'b111: temp2 = 0;
3'b001,3'b010: temp2 = ina;
3'b011: temp2 = 2 * ina;
3'b100: temp2 = -2 * ina;
3'b101,3'b110: temp2 = -ina;
endcase
temp2 = temp2<<2;
end
assign out = temp1+temp2;
endmodule

Wrong use of bind variable in WHEN of a trigger

I'm fairly new in SQL and I'm trying to set up a TRIGGER for an exercise I have. I can't seem to find the solution. Here is the code:
CREATE TRIGGER C3
BEFORE UPDATE OF rate ON Magazines
FOR EACH ROW
WHEN(:NEW.rate < :OLD.rate*0.75)
BEGIN
IF :NEW.rate < 0 THEN
:NEW.rate = 0;
RAISE_APPLICATION_ERROR(-20003, 'Rate should never be below 0.');
ELSE
:NEW.rate = :OLD.rate*0.75;
END;
/
When I try to compile, it shows me this error :
Non valid use of bind variable in WHEN of a trigger
I tried to remove the : before NEW and OLD but instead it gives me another compiler error.
Any ideas?
Thanks a lot!
The assignment operation in pl/sql is :=
CREATE TRIGGER C3
BEFORE UPDATE OF rate ON Magazines
FOR EACH ROW
WHEN(:NEW.rate < :OLD.rate*0.75)
BEGIN
IF :NEW.rate < 0 THEN
:NEW.rate := 0;
RAISE_APPLICATION_ERROR(-20003, 'Rate should never be below 0.');
ELSE
:NEW.rate := :OLD.rate*0.75;
END;
You first need to remove the colons from the WHEN clause only. Then you will also need colons in front of the equals signs for assignment in the trigger body.
CREATE TRIGGER C3
BEFORE UPDATE OF rate ON Magazines
FOR EACH ROW
WHEN(NEW.rate < OLD.rate*0.75)
BEGIN
IF :NEW.rate < 0 THEN
:NEW.rate := 0;
RAISE_APPLICATION_ERROR(-20003, 'Rate should never be below 0.');
ELSE
:NEW.rate := :OLD.rate*0.75;
END;
/
Per the documentation:
In the trigger_body of a simple trigger or the tps_body of a compound trigger, a correlation name is a placeholder for a bind variable. Reference the field of a pseudorecord with this syntax:
:pseudorecord_name.field_name
In the WHEN clause of a conditional trigger, a correlation name is not a placeholder for a bind variable. Therefore, omit the colon in the preceding syntax.

Counter inside FSM in VHDL

I have got a small problem with my finite state machine which I have
written in VHDL recently. I tried to create "intelligent" counter
triggered by clock with frequency 2 Hz.
This counter is built in one state of FSM and is started by pushing a
button on DE2 board.
Firstly, whole system is in IDLE state and if I push this button, state is
changed to COUNTING and counter begin to be incremented and his current
value is shown on LED display. After it reach value of modulo, the state
COUNTING is left back to IDLE and the counter is set up to zero.
My problem is that the counter doesn´t work correctly - the counting
value was too great. So I tried to solve it with this construction: if
(clk_tick´event and clk_tick = 1) then.... , there are some errors by
synthesis:
Error (10822): HDL error at Citac_FSM.vhd(57): couldn't implement
registers for assignments on this clock edge
Error (10821): HDL error at Citac_FSM.vhd(62): can't infer register for
"AUTOMAT:flg" because its behavior does not match any supported register
model
Please, does somebody have an idea to solve it? And what is it correct way
to write clock triggered FSM with two (or more) clock sources?
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_unsigned.all;
ENTITY Counter_FSM IS
GENERIC (
REGSIZE : integer := 8; -- range of counter
MODULO : natural := 50 -- modulo value
);
PORT (
CLK : IN STD_LOGIC; -- puls 50 MHz
CLK_tick : IN STD_LOGIC; -- puls 2 Hz
RESET : IN STD_LOGIC; -- reset
READY : OUT STD_LOGIC; -- counter is ready to start
START_C : IN STD_LOGIC; -- start of counting
DOUT : OUT STD_LOGIC_VECTOR(REGSIZE - 1 downto 0) --out
);
END Counter_FSM;
ARCHITECTURE Behavior OF Counter_FSM is
type counterState is (IDLE, COUNTING); -- states of FSM
signal currCounterState : counterState; -- current state
signal nextCounterState : counterState; -- next state
signal cnt : std_logic_vector(REGSIZE - 1 downto 0); -- counter
begin
UPDATE: process(RESET, CLK)
begin
if (RESET = '0') then
currCounterState <= IDLE;
elsif (CLK'event and CLK = '1') then
currCounterState <= nextCounterState;
end if;
end process;
COMBI: process (clk_tick, start_c, currCounterState)
variable flg : std_logic := '0';
begin
if (clk_tick'event and clk_tick = '1') then
flg := '1';
end if;
case currCounterState is
when IDLE =>
cnt <= (others => '0'); -- counter value = zero
READY <= '1'; -- we can start
if (start_c = '1') then -- if button is pushed
nextCounterState <= COUNTING; -- go to COUNTING
end if;
when COUNTING =>
READY <= '0';
if (flg = '1') then -- Was there impuls of 2 Hz?
cnt <= cnt + 1; -- yes -> incrementing
flg := '0';
if (cnt = MODULO) then -- if cnt = MODULO
cnt <= (others => '0'); -- then cnt = zero
nextCounterState <= IDLE;
end if;
end if;
when others =>
nextCounterState <= IDLE;
end case;
-- OUTPUT
douT <= cnt;
end process;
end Behavior;
Thank you very much.
Mirek
P.S.: I am sorry my English is not so good.
First of all you should not use clk_tick as a second clock signal.
What you should do is to save the previous value of clk_tick, then compare the current value of clk_tick to the previous value to detect a rinsing edge. Depending on how clk_tick is generated you might need to synchronize clk_tick to the clock domain of CLK.
You could write something like this:
when COUNTING =>
nextCounterState <= COUNTING;
READY <= '0';
if (prev_clk_tick = '0' and clk_tick = '1') then
next_cnt <= cnt + 1; -- yes -> incrementing
if (cnt = MODULO) then
next_cnt <= (others => '0');
nextCounterState <= IDLE;
end if;
end if;
I will leave it to you to add the extra registers.
I have already solved my problem :-). I have moved the counter into separate process and then attached witch signals to FSM. So, it works very well.
By reading of button I am using two D flip-flops to synchronize it at the moment.
I have to make an observation on style of VHDL programming - it is too different to "normal" programming like C language :-D
Nice day!

Signals and Variables in VHDL

I want to ask about the signals and variables in VHDL, I know the difference between them, but I want to see the difference at simulation.
I used this simple program in Quartus Tool to see the difference between them:
ENTITY test IS PORT (
a : IN bit;
y : OUT bit);
END test;
ARCHITECTURE beh OF test IS
SIGNAL x : BIT;
BEGIN
PROCESS (a)
BEGIN
x <= '1';
IF x = '1' THEN y <= '0' AFTER 8 ns;
ELSE y <= '1' AFTER 5 ns;
END IF;
END PROCESS;
END BEH;
for signals and this for variables:
entity test1 is port (
a : IN bit;
y : OUT bit);
end test1;
architecture beh of test1 is
begin
process (a)
variable x : bit;
begin
x := '1';
if x = '1' then y <= '0' after 8 ns;
else y <= '1' after 5 ns;
end if;
end process;
end beh;
the i created waveform to see the difference in the first program (y)value should be set to 1 at 5ns,but it doesn't change..Why?
Thank you in advance.
You don't see the difference in waveforms, as the waveform viewer only shows the values of variables at the end of a delta cycle (ie when some real time passes). If you single-step the code, or add report statements mid process, you can see intermediate values on a variable:
signal s:integer := 0;
process
variable v:integer := 0;
begin
report "Signal="&integer'image(s)&" variable="&integer'image(v);
s <= 1; v := 1;
report "Signal="&integer'image(s)&" variable="&integer'image(v);
wait for 0 ps; -- end the delta cycle, even 0ps counts as "time passing"
report "Signal="&integer'image(s)&" variable="&integer'image(v);
wait;
end process;
You put signal "a" on sensitive list then it lead to a "latch".
For update y, you should put "x" on sensitive list or change "a" like a trigger signal.
In your case, signal and variable is similar because you fixed it as a constant.
For addition, you should upload your testbench with behaviour of signal "a".
Edit: I'm wrong about put "x" in sensitive list. Thanks to #damage
This piece of code should illustrate the difference b/w signals and variables.
I inserted the processes directly into the testbench, so the code can be directly simulated with a HDL simulator of your choice.
After 10 ns the start event is fired and both processes are evaluated.
You should then see the expected result, namely sig_outgoing high after another 20 ns, whereas var_out should be high after only 10 ns.
library ieee;
use ieee.std_logic_1164.all;
entity sigvartest is
end entity sigvartest;
architecture behav of sigvartest is
signal start : std_logic := '0'; -- event to start simulation
signal x_sig : std_logic := '0'; -- signal tested in SIGPROCESS
signal sig_out : std_logic := '0'; -- output of SIGPROCESS
signal var_out : std_logic := '0'; -- output of VARPROCESS
begin
start <= '0', '1' after 10 ns; -- pretty self-explanatory, start goes high after 10 ns
SIGPROCESS:
process(start) is
begin
if(rising_edge(start)) then
x_sig <= '1'; -- signal is scheduled to be assigned its new value, no immediate change!
if(x_sig = '1') then
sig_out <= '1' after 10 ns;
else
sig_out <= '1' after 20 ns; -- this part will execute
end if;
end if;
end process;
VARPROCESS:
process(start) is
variable x_var : std_logic := '0';
begin
if(rising_edge(start)) then
x_var := '1'; -- variable is assigned immediately
if(x_var = '1') then
var_out <= '1' after 10 ns; -- this part will execute
else
var_out <= '1' after 20 ns;
end if;
end if;
end process;
end architecture;