UPGRADE YOUR BROWSER

We have detected your current browser version is not the latest one. Xilinx.com uses the latest web technologies to bring you the best online experience possible. Please upgrade to a Xilinx.com supported browser:Chrome, Firefox, Internet Explorer 11, Safari. Thank you!

cancel
Showing results for 
Search instead for 
Did you mean: 
Observer alexrp92
Observer
340 Views
Registered: ‎07-16-2019

address with negative value

Hi all! 

I am starting in the FPGA world, I am doing a tutorial (http://antonpotocnik.com/?p=514765) which tries to communicate the fpga with the BRAMs. 

I am trying to understand why in this code displayed below the value of the address which is pointing to a particular register of the BRAM is negative (-2) line 146. I think that this value is the next-to-last address of the BRAM (applying complement 2) but I don't get that in the next clock step, this value is added 1 and is converted to the register 0 instead the last register of the BRAM.. in the simulation provided in the tuto is shown this behaviour.

The BRAM is initialize as TRUE dual port RAM, with a 32 bits with and 1024 depth (so addresses with 10 bits), in the other hand, the AXI bus described in the code below is saying that the address can be up to 16 bits so in the code -2 means the address 1111 1111 1111 1110 but this address is out of range from the memory which can be 11 1111 1111 (1023), why in the simulation the register int_addrA_reg is 2047 when putting that register to -2?

 

Thanks!!

Sim2_a.png`timescale 1 ns / 1 ps
 
 
// BRAM PORTA for writing
// BRAM PORTB for reading, this one will be shared with bram_reader
 
module axis_averager #
(
  parameter integer AXIS_TDATA_WIDTH = 32,
  parameter integer BRAM_DATA_WIDTH = 32,
  parameter integer BRAM_ADDR_WIDTH = 16,  // 2^15 = 32768 positions
  parameter integer AVERAGES_WIDTH = 32
)
(
  // System signals
  input  wire                        aclk,
  input  wire                        aresetn,
  
  // Averager specific ports
  input  wire trig,
  input  wire user_reset,
  input  wire [15:0] nsamples,
  input  wire [AVERAGES_WIDTH-1:0] naverages,
  output wire finished,
  output wire [AVERAGES_WIDTH-1:0] averages_out,
  
  // Slave side
  output wire                        s_axis_tready,
  input  wire [AXIS_TDATA_WIDTH-1:0] s_axis_tdata,
  input  wire                        s_axis_tvalid,
 
  // BRAM PORT A
  output wire                        bram_porta_clk,
  output wire                        bram_porta_rst,
  output wire [BRAM_ADDR_WIDTH-1:0]  bram_porta_addr,
  output wire [BRAM_DATA_WIDTH-1:0]  bram_porta_wrdata,
  input  wire [BRAM_DATA_WIDTH-1:0]  bram_porta_rddata,
  output wire                        bram_porta_we,
  
  // BRAM PORT B
  output wire                        bram_portb_clk,
  output wire                        bram_portb_rst,
  output wire [BRAM_ADDR_WIDTH-1:0]  bram_portb_addr,
  output wire [BRAM_DATA_WIDTH-1:0]  bram_portb_wrdata,
  input  wire [BRAM_DATA_WIDTH-1:0]  bram_portb_rddata,
  output wire                        bram_portb_we
);
 
 
  reg [BRAM_ADDR_WIDTH-1:0] int_addrA_reg, int_addrA_next;
  reg [BRAM_ADDR_WIDTH-1:0] int_addrB_reg, int_addrB_next;
  reg [2:0] int_case_reg, int_case_next;
  reg int_wren_reg, int_wren_next;
  reg [AVERAGES_WIDTH-1:0] int_averages_reg, int_averages_next;
  reg int_finished_reg, int_finished_next;
  reg [BRAM_DATA_WIDTH-1:0] int_data_reg, int_data_next;
  reg d_trig;
  wire trigger;  
  
  
  assign s_axis_tready = 1;
  assign finished = int_finished_reg;
  assign averages_out = int_averages_reg;
  
  assign bram_porta_clk = aclk;
  assign bram_porta_rst = ~aresetn;
  assign bram_porta_addr = int_addrA_reg;
  assign bram_porta_wrdata = int_data_reg;
  assign bram_porta_we = int_wren_reg;
   
  assign bram_portb_clk = aclk;
  assign bram_portb_rst = ~aresetn;
  assign bram_portb_addr = int_addrB_reg;
  assign bram_portb_wrdata = {(BRAM_DATA_WIDTH){1'b0}};
  assign bram_portb_we = 1'b0;
  
  
  always@(posedge aclk) begin
if (user_reset) d_trig <= 0;
else d_trig <= trig;
  end
  assign trigger = (trig == 1) && (d_trig == 0) ? 1 : 0;
 
  
  always @(posedge aclk)
  begin
    if(~aresetn || user_reset)
    begin
      int_addrA_reg <= {(BRAM_ADDR_WIDTH){1'b0}};
 int_addrB_reg <= {(BRAM_ADDR_WIDTH){1'b0}};
      int_case_reg <= 3'd0;
 int_averages_reg <= {(AVERAGES_WIDTH){1'b0}};
      int_wren_reg <= 1'b0;
      int_data_reg <= {(BRAM_DATA_WIDTH){1'b0}};
      int_finished_reg <= 1'b0;
    end
    else
    begin
      int_addrA_reg <= int_addrA_next;
      int_addrB_reg <= int_addrB_next;
      int_case_reg <= int_case_next;
      int_wren_reg <= int_wren_next;
 int_averages_reg <= int_averages_next;
 int_data_reg <= int_data_next;
 int_finished_reg <= int_finished_next;
    end
  end
 
  
  always @*
  begin
    int_addrA_next = int_addrA_reg;
int_addrB_next = int_addrB_reg;
    int_case_next = int_case_reg;
    int_wren_next = int_wren_reg;
int_averages_next = int_averages_reg;
int_data_next = int_data_reg;
int_finished_next = int_finished_reg;
 
    case(int_case_reg)
      0:    // Begin state
      begin
        int_addrA_next = {(BRAM_ADDR_WIDTH){1'b0}};
int_addrB_next = {(BRAM_ADDR_WIDTH){1'b0}};
int_averages_next = {(AVERAGES_WIDTH){1'b0}};
int_case_next = 3'd1;
int_wren_next = 1'b1;
int_finished_next = 1'b0;
int_data_next = {(BRAM_DATA_WIDTH){1'b0}};
      end
      1:    // Clear BRAM state
      begin
        int_addrA_next = int_addrA_reg + 1'b1;
        if(int_addrA_reg == nsamples-1) // clear until all the addresses are zero
        begin
          int_case_next = 3'd2;
 int_wren_next = 1'b0;
        end
      end
      2:    // Wait for trigger
      begin
        int_addrA_next = -2;
        int_addrB_next = 0;
        int_wren_next = 1'b0;
        if(trigger)
        begin
 int_averages_next = int_averages_reg + 1;
 if (int_averages_reg == naverages)
int_case_next = 3'd4;
 else
int_case_next = 3'd3;          
        end
      end
 3:    // Measure
      begin
        if(s_axis_tvalid)
        begin
          int_addrA_next = int_addrA_reg + 1;
 int_addrB_next = int_addrB_reg + 1;
 int_data_next = bram_portb_rddata + s_axis_tdata;
 int_wren_next = 1'b1;
 if (int_addrA_reg == nsamples-2)
int_case_next = 3'd2;
        end
else
 int_wren_next = 1'b0;
      end
      4: // finished
      begin
        int_finished_next = 1;
      end
 
    endcase
  end
 
 
 
endmodule

 

0 Kudos
11 Replies
Moderator
Moderator
303 Views
Registered: ‎04-24-2013

Re: address with negative value

Hi @alexrp92 ,

I had a quick look at the page that you referenced and this question has been answered there.

They said: If you look at the simulation results (projects/5_averager/sim/Sim2_a.png) you can see that this results in the correct behavior, so that after next increment the address is 0

Best Regards
Aidan

 

------------------------------------------------------------------------------------------------------------------
Please mark the Answer as "Accept as solution" if this answered your question
Give Kudos to a post which you think is helpful and may help other users
------------------------------------------------------------------------------------------------------------------
0 Kudos
295 Views
Registered: ‎07-23-2019

Re: address with negative value

@alexrp92 

 

right-click on the address signal, then Radix > Unsigned decimal?

0 Kudos
Observer alexrp92
Observer
293 Views
Registered: ‎07-16-2019

Re: address with negative value

Hi Aidan, 

I've already checked that. My question is why it goes from -2 to 0 in 1 cycle, without taking a -1 value.

I want to understand the process involved to get that.. I want to know why if you take -2, the address is 2047 instead of 1023 cause the address memory is set with 10 bits not 11 

0 Kudos
289 Views
Registered: ‎07-23-2019

Re: address with negative value

@alexrp92 

could it be you are reading, say, an int16, and your memory maps bytes?

some ARM processors, for example, have 32-bit alignment so it jumps by 4 bytes and read words.

0 Kudos
Observer alexrp92
Observer
280 Views
Registered: ‎07-16-2019

Re: address with negative value

Hi! The simulation image is an image loaded from the tutorial, and the file to simulate that is not provided.. Is my first week working with FPGAs so I still don't have how to simulate a specific block of the whole system..

0 Kudos
Observer alexrp92
Observer
276 Views
Registered: ‎07-16-2019

Re: address with negative value

I thought something like that but in the graph state shown in the code I put in m first post says that the address is increased 1 by 1. 

The RAM is a true dual port RAM with 32 bits length and 1024 depth.. so I understand that each address (from 0 to 1023) save 32 bits of data

0 Kudos
236 Views
Registered: ‎07-23-2019

Re: address with negative value

If your depth is 1024, it doesn't make sense an address of -2047, that has at least 12 bits.

I think the problem is you cast the address into a type with more than 10 bits, the extra ones show as '1' and are interpreted as a minus sign. Still not clear why they don't increase by one, though, but that could be fixed with a proper translation of the address.

0 Kudos
Observer alexrp92
Observer
228 Views
Registered: ‎07-16-2019

Re: address with negative value

Hi,

Just to clarify, this is a tutorial and it works perfectly, the thing is, I want to understand what is happening..

About the addess.. I think that at the beggining although the AXI address bus is set to 16 bits as we limit the memory to have 1024 locations, the register where the address is saved goes up to 10 bits, until the state case reach 2. At this moment the register detects a negative number so an extra bit is added (10 to 11 bits) and therefore it goes up to 2048 locations. Assuming this is correct, I don't understand that a -2 which is saved as 111 1111 1110  (Complement 2) goes to 000 0000 0000 in the next clock cycle.. it should take the 111 1111 1111 value. Isn't it? Or the last location of a true dual port memory is reserved for other things? 

0 Kudos
221 Views
Registered: ‎07-23-2019

Re: address with negative value

"the register detects a negative number so an extra bit is added (10 to 11 bits)"

No, no, and no. Registers are neither that smart or allowed to modify its width.

"111 1111 1110  (Complement 2) goes to 000 0000 0000 in the next clock cycle"

If your depth is 10 bit and you show 11 bits, there must be one unused. Could it be the LSb then your jump is from "111 1111 111" to "000 0000 000" and it all makes sense? I know it sounds a bit of a dodgy explanation but if you have specified your depth as 10-bit you cannot have 11-bit addresses otherwise you would have more memory than what you stated.

0 Kudos
Observer alexrp92
Observer
210 Views
Registered: ‎07-16-2019

Re: address with negative value

"If your depth is 10 bit and you show 11 bits, there must be one unused. Could it be the LSb then your jump is from "111 1111 111" to "000 0000 000" and it all makes sense? I know it sounds a bit of a dodgy explanation but if you have specified your depth as 10-bit you cannot have 11-bit addresses otherwise you would have more memory than what you stated."

I don't know.. looking into the specs(page 45) says that the architecture Zynq with the promitive 8kx2  (the algorithm used is minimum area) can use promitives of 8kx2 or 16kx2. So assumingthat there are 2 memories of 16k (it has a total of 32 k --> 2^15 ) it can be divided in 10 bits for adderssing and 5 bits for the width of each register (divided in 2 register?) So it could be that the LSB indicates the memory (between 2 of them) and the 10 MSB indicates the address? so it keeps increment 1 by 1 but for adderssing only is important the 10 MSB?

If this is true, if you put the register to -2 --> 111 1111 1110 and you add 1 to the address part you will get overflow and coming back to 000 0000 0000 

does it make any sense?

000 0000 000    

000 0000 0001 

000 0000 0010

000 0000 0011

000 0000 0101

000 0000 0110

111 1111 1110

111 1111 1111

 

not taking into account the LSB

000 0000 000    

000 0000 0010

000 0000 0101

111 1111 1110

 

...

 

0 Kudos
202 Views
Registered: ‎07-23-2019

Re: address with negative value

ok.... tbh I didn't read the code (how many people do you expect to go through a 100+ lines code?) or went to the tutorial...

So your question is actually philosophical about how the code is written, not an actual error in firmware (I though you found that -2 in the simulation you attached)

Well, in that case, the answer is simple: ask the author instead of having third party people analyzing that code.

If you want more, and without putting anyone down, it's an amateur page, what can you expect? I have seen so many freebies that they even don't work out of the box...

Sometimes, we tweak things 'to get them to work' and don't care about the beauty of the technique. At the end of the day, is not code what we deliver. I haven't dived that code but my suspicion is that -2 is some reset value that gets incremented by 2 before it's used the first time.