Bitwidth Management in Input and Output

Status
Not open for further replies.
Edited from an older reply to a post on the same subject...

What kind of "for loop" do you want? Basically two options:

1 - Do you want something that loops in time?
2 - Do you want to unroll logic, so that you get multiple pieces of logic that execute simultaneously side by side (loop in space)?

Option 1) is typically what people want. And then they try (and fail) to use the for loop keyword in verilog for that. This is precisely NOT how it works.

When you use the for loop construct in verilog you actually get option 2), unrolling logic.

Summarizing: A for loop in verilog does NOT loop temporally. A for loop in verilog loops spatially.

If you want something that loops in time you should use a counter.

Or to put that another way... If you do a for loop of 5 in verilog you will get 5 side-by-side copies of the same logic on the fpga die. If on the other hand you have a counter running 0,1,2,3,4,0,1,2,3,4,.... then you can make something that loops/repeats in time, similar to how you would expect a for loop in a typical imperative programming language to behave.
 
Hi ads-ee one thing is not understandable to me here.
Even I write in this format:
Code:
32_bit_entity <= {adc_value[3], adc_value[2], adc_value[1], adc_value[0]};
The output I am getting in signal Tap:
Code:
32_bit_entity <= {adc_value[2], adc_value[1], adc_value[0], adc_value[3]};
or this format:
Code:
32_bit_entity <= {adc_value[1], adc_value[0], adc_value[3], adc_value[2]};
and in very rare case, the right format too.

Here is the complete code which I used for testing: I just use a counter as ADC_DATA which counts from 0 to 9 and then again set back to 0.
Code:
reg [31:0] 32_bit_entity;
reg [7:0] ADC_DATA = 0; // Continuously coming ADC DATA at 100 MHz Clock
reg [7:0] adc_value [0:3]; 
reg [1:0] idx = 0; //  this will init the register to 2'b00, it also ensures the simulation is non-X

always @ (posedge 100_mhz_clk) 
begin
  ADC_DATA <= ADC_DATA + 1;
	    if (ADC_DATA == 8'b00001010)
					begin
						ADC_DATA <= 0;	
					end
       end


always @ (posedge 100_mhz_clk) begin
  idx <= idx + 1;
end
 
always @ (posedge 100_mhz_clk) begin
  if (idx == 2'b00) begin
    adc_value[0] <= ADC_DATA;
  end
  if (idx == 2'b01) begin
    adc_value[1] <= ADC_DATA;
  end
  if (idx == 2'b10) begin
    adc_value[2] <= ADC_DATA;
  end
  if (idx == 2'b11) begin
    adc_value[3] <= ADC_DATA;
  end
end

always @ (posedge 25_mhz_clk)
	begin
	
				32_bit_entity <= {adc_value[3], adc_value[2], adc_value[1], adc_value[0]};

	end

Although data is right but byte position gets changed unexpectedly in the output?
 

Are you sure it's not expectation value error? As in, I could see how you can confuse yourself easily with the simulateously incrementing counters. The reason I ask is that I don't really see anything problematic with your posted code. Couple of style points, but it looks to be okay. What I usually do to prevent confusing myself is to pick some prime numbers as increment. That way you will not get any "beat notes" so to speak. Or multiplicative annoyance if you will.

So something like this:

Code SystemVerilog - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
module tb_adc_and_counter;
    reg clk_100_mhz = 0;
    reg clk_25_mhz  = 0;
 
    always begin
        # 5 clk_100_mhz <= ~clk_100_mhz;
    end
 
    always @*
    begin
        repeat(4) @clk_100_mhz;
        clk_25_mhz <= ~clk_25_mhz;
    end
    
    adc_and_counter DUT (.*);
endmodule // tb_adc_and_counter
 
 
module adc_and_counter (
        input clk_100_mhz,
        input clk_25_mhz
        ); 
    
    reg [31:0] entity_32_bit;
    reg  [7:0] ADC_DATA = 0;     // Continuously coming ADC DATA at 100 MHz Clock
    reg  [7:0] adc_value [0:3]; 
    reg  [1:0] idx = 0;          // This will init the register to 2'b00, it also ensures the simulation is non-X
 
    always @ (posedge clk_100_mhz) 
    begin
        // ADC_DATA goes through 0 .. 84 in increments of 7, for a total of 13 steps.
        // The reason we pick an increment like 7 (instead of 1) is to make it
        // easier to see where numbers are coming from. Same thing goes for
        // the loop count of 13 (instead of 10).
        if (ADC_DATA == (12*7))
        begin
            ADC_DATA <= 0;  
        end else begin
            ADC_DATA <= ADC_DATA + (1*7);
        end
 
        idx <= idx + 1;
 
        case (idx)
            2'b00: adc_value[0] <= ADC_DATA;
            2'b01: adc_value[1] <= ADC_DATA;
            2'b10: adc_value[2] <= ADC_DATA;
            2'b11: adc_value[3] <= ADC_DATA;
        endcase 
    end
 
    // TODO: replace this with a block clocked by clk_100_mhz, and use a Clock Enable.
    always @ (posedge clk_25_mhz)
    begin
        entity_32_bit <= {adc_value[3], adc_value[2], adc_value[1], adc_value[0]};
    end
endmodule // adc_and_counter



When I simulate that the ADC_DATA ends up where I would expect it to...
 
Your data output pattern depends on the phase relationship between the 25 MHz clock and the 100 MHz clock (there are four possible phase relationships, this is an example of why you should use a single clock domain in a design with enables for the slower logic), you should have used the idx count value to load a single output register that only gets updated every 4 clock cycles after you've loaded all four samples.


Code Verilog - [expand]
1
2
3
4
5
always @ (posedge 100_mhz_clk) begin
  if (idx == 0) begin
    32_bit_entity <= {adc_value[3], adc_value[2], adc_value[1], adc_value[0]};
  end
end



Try that instead of the code you're using, this code should only update the 32_bit_entity when all 4 indices have been updated.
 
// TODO: replace this with a block clocked by clk_100_mhz, and use a Clock Enable.
Now you spoiled the exercise for the reader.

But yes, this is a perfect example of why you want to use clock enables.
 

Now you spoiled the exercise for the reader.

But yes, this is a perfect example of why you want to use clock enables.

Oops, I didn't want to try reading the code on my phone so I ignored what you wrote
 

Try that instead of the code you're using, this code should only update the 32_bit_entity when all 4 indices have been updated.
Hi, Thanks this works fine.

For next step, I made little change in above code to enable fifo_write signal as:

Code Verilog - [expand]
1
2
3
4
5
6
7
always @ (posedge 100_mhz_clk) begin
  if (idx == 0) 
begin
fifo_write <= 1;
    input_to_fifo <= {adc_value[3], adc_value[2], adc_value[1], adc_value[0]};
  end
end



and used following code to write above data in dual clock fifo at 100 MHz:


Code Verilog - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
dcfifo  
    #(
        .intended_device_family ("Cyclone IV"),
        .lpm_numwords(4096),
        .lpm_showahead("OFF"),
        .lpm_type("dcfifo"),
        .lpm_width(32),
        .lpm_widthu(12),
        .overflow_checking("ON"),
        .rdsync_delaypipe(4),
        .read_aclr_synch("ON"),
        .underflow_checking("ON"),
        .use_eab("ON"),
        .write_aclr_synch("ON"),
        .wrsync_delaypipe(4)
    )
    Inst_FIFO (
        .aclr(reset_n),
        .wrclk(test_100_mhz),
        .wrreq(fifo_write),
        .wrfull(fifo_full),
        .data(input_to_fifo),
        .rdclk(test_25_mhz),
        .rdreq(fifo_read),
        .rdempty(fifo_empty),
        .q(output_from_fifo)
    );



and read it at 25 MHz at output as:

Code Verilog - [expand]
1
2
3
4
5
always @ (posedge 25_mhz_clk) begin
    fifo_read <= 1;
    GPIO <= output_from_fifo;
  end
end



and put signal tap at GPIO pin. but unfortunately I don't have expected output. and yes I am missing the concept of controlling fifo_full and fifo_empty signal in this continuous data flow.

Regards
 


Reading from the FIFO requires you generate a fifo_read (read request) and then the data will show up on the next clock cycle, unless the FIFO is in flow through mode then the fifo_read behaves like a read acknowledge.

Also saying you don't have expected output is not going to help us help you. Explain exactly what is wrong with the output, include input and output data if possible.
 

Also saying you don't have expected output is not going to help us help you. Explain exactly what is wrong with the output, include input and output data if possible.
Hi, here is the complete code:


Code Verilog - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
module test(
 
    //////////// CLOCK //////////
    CLOCK_50,
    CLOCK2_50,
    CLOCK3_50,
 
    //////////// LED //////////
    LEDG,
    LEDR,
 
    //////////// KEY //////////
    KEY,
 
    //////////// SW //////////
    SW,
 
    //////////// GPIO, GPIO connect to GPIO Default //////////
    GPIO 
);
 
//////////// CLOCK //////////
input                       CLOCK_50;
input                       CLOCK2_50;
input                       CLOCK3_50;
 
//////////// LED //////////
output           [8:0]      LEDG;
output          [17:0]      LEDR;
 
//////////// KEY //////////
input            [3:0]      KEY;
 
//////////// SW //////////
input           [17:0]      SW;
 
//////////// GPIO, GPIO connect to GPIO Default //////////
inout   reg     [31:0]      GPIO;
 
 
 
wire fifo_rclk;
wire fifo_empty;
reg fifo_read;
reg fifo_write;
wire fifo_full;
wire  test_250_mhz, test_125_mhz, test_100_mhz, test_25_mhz, test_12p5_mhz;
reg [31:0]  output_from_fifo;
 
 
 
reg [31:0] input_to_fifo;
reg [7:0] ADC_DATA = 0; // Continuously coming ADC DATA at 100 MHz Clock
reg [7:0] adc_value [0:3]; // To store 4 values of ADC DATA.
                         
reg [1:0] idx = 0; //  this will init the register to 2'b00, it also ensures the simulation is non-X
 
always @ (posedge test_100_mhz) begin
  ADC_DATA <= ADC_DATA + 1;
        if (ADC_DATA == 8'b00011111)
                    begin
                        ADC_DATA <= 0;  
                    end
       end
 
always @ (posedge test_100_mhz)
 
 begin
  idx <= idx + 1;
  adc_value[idx] <= ADC_DATA;
end
 
always @ (posedge test_100_mhz)
    begin
           if (idx == 0)
             begin  
                
                    if(fifo_full == 1)
                       begin
                            fifo_write <= 0;
                        end
                    else
                      begin 
                          fifo_write <= 1;
                          input_to_fifo <= {adc_value[0], adc_value[1], adc_value[2], adc_value[3]};
                      end
            end
    end
 
    pll_test pll_test (
    .inclk0(CLOCK3_50),
    .c0(test_100_mhz),
    .c1(test_25_mhz),
    .c2(test_12p5_mhz),
    .c3(test_250_mhz),
    .c4(test_125_mhz)
    );
 
 
dcfifo  
    #(
        .intended_device_family ("Cyclone IV"),
        .lpm_numwords(4096),
        .lpm_showahead("OFF"),
        .lpm_type("dcfifo"),
        .lpm_width(32),
        .lpm_widthu(12),
        .overflow_checking("ON"),
        .rdsync_delaypipe(4),
        .read_aclr_synch("ON"),
        .underflow_checking("ON"),
        .use_eab("ON"),
        .write_aclr_synch("ON"),
        .wrsync_delaypipe(4)
    )
    Inst_RxFIFO (
        .aclr(global_reset_n),
        .wrclk(test_100_mhz),
        .wrreq(fifo_write),
        .wrfull(fifo_full),
        .data(input_to_fifo),
        .rdclk(test_100_mhz),
        .rdreq(fifo_read),
        .rdempty(fifo_empty),
        .q(output_from_fifo)
    );  
    
    
    
    
 
always @ (posedge test_25_mhz)
    begin
           
               if (fifo_empty == 1)
                    begin
                        fifo_read <= 0;
                    end
                else
                    begin
                        fifo_read <= 1;
                        GPIO <= output_from_fifo; 
                    end
                    
 
    end
 
 
endmodule



and in attachment, screenshot of signal tap at 25 MHz and 100 MHz.
What I didn't understand in signal tap are:
1. Although I am running signal tap at 25 MHZ, why value in GPIO comes after 3 clock cycles compared to input_to_fifo/data pin of FIFO and why rdclk and wrclk is always high.
2. while running signal tap at 100 MHz, why value in GPIO comes after 2 clock cycles compared to input_to_fifo/data pin of FIFO. and again rdclk and wrclk is always high.
3. How to control wrfull and rdempty of Dual Clock FIFO in case there is continuous flow of data and don't want to loose any data provided input and output running at different clock.
 

Attachments

  • dcfifo_signal_tap_25MHz.jpg
    408.3 KB · Views: 121
  • dcfifo_signal_tap_100MHz.jpg
    388.6 KB · Views: 123


You are sampling the rdclk and wrclk, which you shouldn't do, you are using those clocks to sample the signals, if you want to sample the clocks you better use another clock that is >2x the frequency of the 100 MHz write clock. BUT DON'T ACTUALLY DO THAT. Remove the clocks from signaltap, they are not necessary the clock information is embedded in the samples you capture. Each sample corresponds to a clock edge having occurred.

The delay is due to the latency of the FIFO, the FIFO has synchronization registers inside it to cross the clock domains and there is a register in the address path and another that can be enabled in the data output path too.

For continuous data, it's generally a good idea to not start reading until a couple of words have been written to the FIFO. The following assumes you are using a frequency locked 100 MHz and 25 MHz clocks. If you add an almost empty flag and start when that goes inactive you shouldn't ever see the FIFO empty out unless the data stops being written. Just make sure the logic starts reading on almost empty inactive but keeps reading until empty goes active (otherwise you would end up with stale data if you stop on almost empty active). With frequency locked clocks you will never need more than 3-4 entries in the FIFO, therefore if you reach wrfull that means the reads have stopped and should be considered an error condition.
 

Status
Not open for further replies.
Cookies are required to use this site. You must accept them to continue using the site. Learn more…