Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

Verilog: read 2 values from an array at the same time.

Status
Not open for further replies.

Pastel

Member level 3
Joined
Jun 30, 2019
Messages
55
Helped
2
Reputation
4
Reaction score
1
Trophy points
8
Activity points
969
Hello!

I have successfully made a first version of a signal generator, and now I would like to make it dual channel.
If I make an arbitrary signal table, and want to read it from 2 different points at the same time, is it possible,
or do I have to setup 2 tables?
For instance if I use one table, can I have access to 2 elements of an array at the same time?

something like this
Code:
chan1 <= array[i];
chan2 <= array[i+phase];

Thanks for any hint.

Pastel
 

Hi,

If your array are individual registers or if it is a dual port SRAM you may acces them at the same time.

If your array is a simple SRAM architecture, then you can't acces them at the same time
But usually SRAM is fast ... you may read two items one after the other .... and you are free to process or output them at the same time, so it may have the same effect than reading them at the same time.

Klaus
 

What you suggest is feasible although it means doing a calculation (i+phase) during each loop. This uses cpu cycles. Instead you probably want speed when generating waveforms. Therefore it's efficient if you prepare all values beforehand so you don't use excessive cpu cycles. Usually this means creating two arrays, eg., chan1 and chan2.
 

You can synthesize arrays with many/multiple accesses. The tools will do something to make them work. In some cases this means using a dual-port BRAM/DMEM primitive. In some cases it means duplicating the memory. In some cases it means falling back to a DMEM or even register based implementation. The latter leads to large area, low clock rates, and long build times. For best results, you should read the coding style guidelines for your synthesis tool. This should have guidelines for writing BRAM/DMEM based ROMs/RAMs. I don't think any tool ever added a pragma to ensure the tools infer a BRAM, so you'll need to double check your results.
 
  • Like
Reactions: FvM

    FvM

    Points: 2
    Helpful Answer Positive Rating
Hello!

Thanks for your replies.
In the meantime, I tried, and could have the result I wanted.
I made a table of 1024 16-bit values:
reg[15:0] sine[1023:0];
Then I made a script to fill them all, and if I access sine and sin[i + phase], then I get a sine and a cosine
on the scope (I have wired MAX5875 DAC at the output of the FPGA).
So apparently it doesn't eat "cpu cycles" and by the way, I'm not sure I was clear enough, it's a verilog implementation,
not a C program, so there is no loop as such, there is only an always@(posedge clk) block, so yes, it's a kind of hardware
loop. So I just suppose the 2 signals are changing on the same clock but as I'm a real beginner in the FPGA world, I'm
not sure of anything.

What I get:
- The FPGA clock is at 100 MHz. But as I have to set the data, on clock rising edge, and then the DAC clock at the next
rising edge, then the DAC clock is 50 MHz, which should yield 50 MSamples per second. As the table length is 1024, then
I should get 50 kHz or a little bit less.
- At the output, I can see the sine and cosine signals of this simple experiment. I was expecting 50M / 1024 = 48.828
kHz, but my sine waves are at 97 kHz, and I don't understand why for the time being.

Here is the core of what I'm doing. I skip what I do with the LEDs, which is basically lighting them or not. So I send data to
the DAC, and I generate the corresponding clock. So on one rising edge of clk, I check if the dac clock (max_clk) is 0, in which
case I strobe the input data by setting it to 1. If it's already 1, I set the DA and DB to the DAC input and I rearm the clock
to 0 for the next clk rising edge.

- Can anybody explain me why I get 97 kHz instead of 48?
- Is there a way to put my sine array to a dedicated file and keep the top level object reasonably small?

Thanks

Pastel

Code:
module test190803(DA, DB, max_clk, red_led, blue_led, clk) begin
    output reg[15:0] DA, DB; // Data of the DAC
    output reg max_clk;  // Clock of the DAC
    output reg red_led, blue_led; // Some leds for check;
    input clk; // FPGA 100 MHz input clock
    // Some variables
    reg[15:0] sine[0:1023];
    reg[9:0] sinindex;
    reg[9:0] cosindex;
    // Initialization
    initial begin
         sin[0] = xxxxxx; // Long sequence of 1024 initializations
        sinindex = 0;
        cosindex = 256;
    end
    always@(posedge clk) begin
        // Increment the phase counters which will automatically roll back to 0 after overflow.
        sinindex <= sinindex+1;
        cosindex <= cosindex+1;
        // Set the dac clock high, or set the input data and set it low.
        if(max_clk == 0) begin
            max_clk <= 1;
        end
        else begin
            DA <= Sine[sinindex];
            DB <= Sine[cosindex];
            max_clk <= 0;
        end
    end
endmodule

- - - Updated - - -

Hello!

Sorry, I didn't notice your reply.
Ok, I'm an absolute beginner and I'm not sure of what I used. I just wrote some code, it works, more or less.
I don't know what is BRAM, DMEM... just to tell you how newbie I am...

But anyway, I'm able to access more than one element of an array at a time, and it doesn't do it sequencially
otherwise the frequency would drop, and it doesn't. The frequency is even twice what I calculated, and
I don't understand why (see full explanation above).

Thanks,

Pastel
 

why I get 97 kHz instead of 48?
Because you are incrementing the indexes every clock cycle. You want somethink like this.

Code Verilog - [expand]
1
2
3
4
5
6
7
8
9
10
11
always@(posedge clk) begin
        if(max_clk == 0)
            max_clk <= 1;
        else begin
            sinindex <= sinindex+1;
            cosindex <= cosindex+1;
            max_clk <= 0;
        end
        DA <= Sine[sinindex];
        DB <= Sine[cosindex];
      end



- - - Updated - - -

Is there a way to put my sine array to a dedicated file and keep the top level object reasonably small?
Many ways. E.g. using a binary or hex file and $readmemb or $readmemh. Or calculating the initialization values at compile time using $sin() and $cos() system functions. Or write a function that delivers the values.
 

@Pastel: DMEM/BRAM are Xilinx's names for "distributed memory" and "block ram". Intel also has similar blocks. BRAM requires 1+ cycle of read/write latency but is the most dense. DMEM allows async reads but is much less dense. when all else fails the tools have to use registers and muxes. Your design looks like it should be using BRAM as the table is large enough and you don't do anything that would prevent this.
 

Hello!

Thanks for your reply!
And for the solution! It was really a silly question. Indeed, I was incrementing at every step.
It works now.

By the way, I have asked a few times, but how can I format the code with colored syntax?
Is it something only moderators can do?

Thanks,

Pastel

- - - Updated - - -

Hello!

Thanks for your reply!

BRAM requires 1+ cycle of read/write latency but is the most dense.

As far as I can tell, there is not much latency. The clock spins at 100 MHz, and I can output samples at 50 Ms/s.
So yes, 1 cycle to put the data at the DAC input, and the next cycle to latch it. But I think it's the least I can do
to keep the timing safe.

Your design looks like it should be using BRAM as the table is large enough and you don't do anything that would prevent this.

Just to be sure (not english native, sorry). You mean that my design is currently not using BRAM and I
should change it so that it uses BRAM?
Or you mean that looking at the code, it's likely that my design actually uses BRAM?

the table is large enough and you don't do anything that would prevent this.

To prevent the table to be large, or to prevent my design to use BRAM?

By the way, I have another question. I'm using the MAX5875 DAC which can work at 200 Msps.
I have noticed that whatever I do, it works. I mean: this works:
Code:
        if(max_clk == 0) begin
            max_clk <= 1;
        end
        else begin
            DA <= Sine[sinindex];
            DB <= Sine[cosindex];
            max_clk <= 0;
        end

And this also works:
Code:
        if(max_clk == 0) begin
            DA <= Sine[sinindex];
            DB <= Sine[cosindex];
            max_clk <= 1;
        end
        else begin
             max_clk <= 0;
        end

I suppose that if I set the clock and the data at the same time, there is anyway a
delay between the data and the clock, so it works. In one case, the data is latched
immediately, and in the other case, the data from the previous cycle is latched.
There is no difference in matters of noise at the DAC output.
Can anybody tell me why it works in both case (is my explanation right)?

Thanks,

Pastel
 

Or you mean that looking at the code, it's likely that my design actually uses BRAM?

I expect the tools to implement your table in BRAM. This is desirable in this case. You should confirm this in synthesis logs -- the tools sometimes do unexpected things.
 

As for clock to data timing, you should review the MAX5875 specification. The data input must be stable during a window about 0.5 to 2 ns after rising clock edge. In so far both clock phase settings you tried will typically work.

It's however not preferred to generate the DAC clock in logic like you do. You'll better use a crystal or PLL generated clock through a dedicated FPGA clock output. If your application purpose is synthesis of clean RF signals, e.g. for a software defined radio or test generator, you'll even prefer a crystal oscillator directly clocking the DAC for minimal phase noise. FPGA clock jitter is relative large.
 

Status
Not open for further replies.

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top