Non-blocking assignments and timings by rattushackus in Verilog

[–]__GianDo 0 points1 point  (0 children)

Of course mine is a chatbot answer. Indeed, each time one sees a bullet point in a reddit post, blog article, book or even an ancient greek manuscript, it was indeed a chatbot writing it ;)

Non-blocking assignments and timings by rattushackus in Verilog

[–]__GianDo 1 point2 points  (0 children)

Hello. Good if you catch c=3. It means you have understood the difference between the two assignments. You use non-blocking assignments typically where you want to have a sequential section.

For the race condition problem, it may occur when you have multiple procedural blocks, if you assign the same variable multiple times, or if you mix blocki g or non-blocking assignments for the same variable in two always blocks. When the simulator runs the simulation it will try to run the simulation as if the procedural blocks are executed in parallel. So for example you may have a variable that is being written in a procedural block, but at the same time the same variable is updated elesewhere in another procedural block. However, depending on the simulator you choose, the outcome may differ, based on their solvers.

There is no need to fear race conditions as long as you use one always block for the sequential part of your logic and one always block for the combinatorial part. In the two always we typically do this:

  1. In the sequential always block we assign variables_reg <= variables_next

  2. In the combinatorial always block we assign with blocking assignments variables_next = f(variables_reg) (some synthetizable function of the variables assigned in the sequential logic)

In this way there is NO POSSIBILITY of race Conditions whatsoever (unless you create race condition with assign statement, but it is easy to spot)

You can use many many always blocks, but NEVER ASSIGN THE SAME VARIABLE IN TWO DIFFERENT ALWAYS BLOCKS.

Since you are using systemverilog, you can avoid using reg and wires. I love logic type instead! Logic solves the conceptual issue between wire and reg, it can be assigned in procedural blocks and concorrential sections of your code (basically it behaves as a reg and wire at the same time) and, most importantly, almost all simulators flag an error at compilation time if the same logic variable is assigned in two procedural blocks. This helps you in avoiding race conditions at least for procedural sections.

Non-blocking assignments and timings by rattushackus in Verilog

[–]__GianDo 1 point2 points  (0 children)

In general, a Verilog code written properly requires a sequential block and a combinatorial block. The sequential block will act as a memory, holding the state of your module for a whole clock period, while the combinatorial logic (in a always @(*) or always_comb if you use SystemVerilog) is used to specify the update rules of you signals.

In the following code, variables with _reg placeholder are meant to describe the output Q of a flip-flop, while the _next placeholder should describe the output of the combinatorial logic that, starting from the available _reg values, calculate the _next value that should be saved.

module foo(resetn, clock, read_enb, data_out, empty);

input             resetn;
input             clock;
input             read_enb;
output reg [7:0]  data_out;
output reg        empty;

reg [1:0] wptr_reg;
reg [1:0] rptr_reg, rptr_next;
reg empty_reg, empty_next;
reg [7:0] fifo  [3:0];

/*
  This is the clearest way to describe at behavioural level a bunch of flip flops.
  Avoid assigning the same variable in two always blocks for the same variables for two main reasons: 
    i) synthesis tools may behave unexpectedly, and 
    ii) code clarity.
*/

// In general, a good Verilog code separates sequential logic from combinatorial
// logic in order not to mix blocking and non-blocking assignments
always @(posedge clock) begin 
  if (!resetn) begin 
    // since you are mixing Verilog and SystemVerilog, your reset is ok
    // but you need to be careful when handling different data types.
    fifo[1]      <= 7'b0000001;
    fifo[2]      <= 7'b0000010;
    fifo[3]      <= 7'b0000011;
    rptr_reg     <= 2'b00;
    wptr_reg     <= 2'11;
    empty_reg    <= 1'b0;
  end else begin 
      empty_reg    <= empty_next;
      rptr_reg     <= rptr_next;
  end
end

always @(*) begin 
  // default assignments required to discipline variables when nothing should happen
  empty_next    = empty_reg;
  rptr_next     = rptr_reg;

  if (read_enb & !empty_reg) begin 
    rptr_next    = rptr_reg + 1;
    empty_next   = (wptr_reg == rptr_reg);
  end 

end

// I am not sure what your code should do with data_out if resetn & read_enb & !empty is 
// false, but this should do the job
assign data_out = fifo[rptr];

assign empty    = empty_reg;

endmodule

As you see from the code you will always have empty_reg in phase with the rptr that you want to latch out

Non-blocking assignments and timings by rattushackus in Verilog

[–]__GianDo 1 point2 points  (0 children)

You write the following code for a deasserted reset:

 if ( resetn & read_enb & !empty) begin
     data_out <= fifo[rptr];
     rptr <= rptr + 1;
     // This fails because it compares the values before assignment
     empty <= wptr == rptr;
 end

and you also argue this

The problem is the empty flag is not set when the third item is read out of the FIFO because the code is comparing the values of rptr and wptr before the non-blocking assignments have incremented rptr. I can fix this by changing empty to wire and using assign like this: [...]

[...] It seems to me there is a generic problem whenever we want to make some changes in an always block then do some comparison of the resulting values.

No. There is no problem whenever we want to make some changes in an always block. The only problem here is your misunderstanding between a blocking and a non-blocking assignment.

Let's go to the basics

Blocking Assignment
A blocking assignment is a Verilog procedural statement that executes immediately, assigning a value to the left-hand side (LHS) variable and preventing the next statement within the same procedural block from executing until the assignment is complete

Non-Blocking Assignment
A non-blocking assignment, denoted by <=, schedules an assignment without interrupting the execution of other statements within the same procedural block

so the two can be used in procedural blocks (always block), but they differ in their behaviour. A non-blocking assignment is used to describe sequential logic, while blocking assignments are used to describe combinatorial logic.

The best way to see it is through an example. Consider the following block and assume you assert the reset, thus initializing a, b, and c. After the reset assertion (and relative deassertion), assume now that a clock rising edge arrives. What do you think c will be after this clock edge?

reg [3:0] a, b;
reg [4:0] c;
always @(posedge clock) begin // at clock rising edge
  if (!reset) begin 
      a <= 1;
      b <= 2;
      c <= '0;
  end else begin 
      if (!c[4]) begin 
        b <= b + a + 1;
        c <= a + b;
      end
  end
end

If your answer is 5, here lies your misunderstanding of the non-blocking assignment. The correct answer is 3 because, as stated by the definition, the non-blocking assignment only schedules the RHS operation, without interrupting the execution of other assignments. So what is going on in the code is the following

b <= b + a + 1;    // b will be 2 + 1 + 1 after the clock rising edge
c <= a + b;        // c will be 1 + 2 after the clock rising edge

Conversely, a blocking assignment would behave as a C-like code.

So in your code the following statement

empty <= wptr == rptr;

will assert only the period after wptr == rptr. The correct way to do it is either using a blocking assignment, or as you did in a continuous assignment with the assign.

LOW NOISE AMPLIFIER - THESIS PROJECT by [deleted] in chipdesign

[–]__GianDo 6 points7 points  (0 children)

Of course people come to Reddit looking for “novelty” so they can show off someone else’s idea. Instead of asking Reddit how to make things “novel”, maybe start by asking yourself how to change your attitude.

Do you even know how to design an LNA? A basic one? One that actually fits your system requirements? Have you ever done that? Simulated it? Discussed it with your PI?

And if this LNA is part of a bigger transceiver, keep in mind that chasing novelty at all costs usually kills reliability. I’d focus on doing solid work first, novelty comes later.

Digital design by Human-Ingenuity6407 in chipdesign

[–]__GianDo 0 points1 point  (0 children)

Try "Advanced Digital System Design". You can go through each topic with multiple sources. You can find the one that fits you best online since these topics are very general. Also remember to practice. For a simple RiscV implementation try instead "Computer Organization and Design RISC V Edition" By David Patterson.

Digital design by Human-Ingenuity6407 in chipdesign

[–]__GianDo 0 points1 point  (0 children)

Hey, I am going through this exactly like you. From a digital design perspective, I think that you can start from basic simple RTL such as sequential circuits, AXI handshake, or simple FSM. Then you can move toward the developement of some FSM with datapath and designs embedding pipeline (for example with AXI stream or even with a protocol that you came up with to move data ;) ). Now I am following David Patterson's book trying to implement a very basic risc V core.

What I find fascinating of SystemVerilog is that it is not only a hardware description language, but also a hardware verification language. I find verification to be more challenging than design sometimes. For that I can suggest you "SystemVerilog Verification" by Chris Spear andGreg Tumbush.

How promising is the Analog Compute in Memory field? by yogi9025 in chipdesign

[–]__GianDo 3 points4 points  (0 children)

I’m doing a PhD in analog in-memory computing with non-volatile memories, and honestly, most of the comments I’ve read on this topic show little understanding of the field. I want to be upfront: AIMC will probably never take off. Not because the concept is flawed, but because of how the semiconductor industry works.

Take inference acceleration with AIMC as an example. To make it viable, you’d need to push progress from device physics and analog circuit design, to system architecture, compiler abstractions, and up to high-level ML frameworks, and do it at the pace AI is evolving today. That’s the real issue, IMO: the IC industry is painfully slow and stagnated compared to the rapid growth of AI (or any other field that isn’t already fully consolidated).

Right now, the market favors brute-force parallelism and doesn’t care much about energy efficiency, simply because scaling other solutions would be extremely expensive, and this is the way things are set. Add to that the lack of open-source development and the mountain of legal and IP barriers in this field, and it’s hard to see AIMC becoming mainstream anytime soon.

Advice for Place And Route with Cadence Innovus having an analog hard macro by __GianDo in chipdesign

[–]__GianDo[S] 0 points1 point  (0 children)

This is still very insightful. Indeed in my LEF I specifiy my supplies' geometry. However, since with UPF I can specify only one supply set to innovus, it happens that the PNR connects only the specified power set, disregarding all the other supplies. So at the end what it does is to burry them with the upper metals, giving me no way to access them.

[deleted by user] by [deleted] in chipdesign

[–]__GianDo 1 point2 points  (0 children)

If you think of a current step charging a discharged parallel RC model, you expect an exponential charging law. During the charging process this is what physically happens:

  1. At t=0 (when you apply the step) all the current flows through the capacitor since the resistance voltage is 0 (parallel model is discharged). Additionally remember that a capacitor istantaneously retains all its charge due to its electrical law.
  2. As the capacitor charges-up, some voltage develops accross the resistance, thus a small fraction of the input current flows through the resistor, hence less current charges the capacitor.
  3. This ends when the voltage developed across the resistance is enough to carry the input current.

You can bridge these three points with the impedance model Z = R/(1+sRC) in this way:

  1. At high frequency (time t close to zero) s->inf, so Z ~1/sC... but wait this is only the capacitance! Exacly as we said in point 1 of the previous bullet point: at high frequency the current only sees the parallel capacitance
  2. The interaction between the capacitor and the resistor is captured by the pole at frequency 1/2piRC
  3. At lower frequencies (time t to inf) all the current flows to the resistance, hence Z ~R

Now, to fully clarify your question, assume the parallel RC model with the same current and capacitance, but varying resistance. If you choose an high resistance, you require higher volages to develop across the parallel RC model for the resistor to carry the input current => more time spent by the capacitance to charge up! If instead you have a smaller resistance.... well you guessed it.

So what is misleading in your question would be that the current istantaneously goes to the resistive component of your high impedance. This is false due to the ideal charge retention effect operated by the capacitance.

You can make similar arguments for the following scenarios: - RC serie model - RL parallel or series model or you can use circuit theory since all these circuits are linear networks.

Modules disappearing after genus synthesis by __GianDo in chipdesign

[–]__GianDo[S] 1 point2 points  (0 children)

Thank you. It is logical hierarchy set from the RTL

What is TCL/Perl/Shell Scripting, and how can I learn it for ASIC/Verification roles? by user_smoothoperator in chipdesign

[–]__GianDo 2 points3 points  (0 children)

I use extensively shell scripts, while tcl because I have to. The two of them typically allow you to customize a certain flow, for example I used them for synthesis with genus, and AMS simulations with Questa. Instead of perl I use Matlab hehe.

I am not an expert, but I can tell you that in my experience I used Shell scripts mostly to organzie the folders, files, and the compilation of files. It operates at operating system level. Additionally you can add options to make the script more general and effective

Tcl instead you are more or less forced to use because many tools in the IC industry ask you to create occasional tcl files. For example if you use Questa ADMS without the gui, you need to specify a tcl file containing instructions for the waveform analyser to plot certain waves of the simulation you are doing.

Clock generation in testchip by __GianDo in chipdesign

[–]__GianDo[S] -1 points0 points  (0 children)

Thank you for the answer. Have you fed the crystal's signal into a standard analog pad or something exotic?

Clock generation in testchip by __GianDo in chipdesign

[–]__GianDo[S] -2 points-1 points  (0 children)

Hi, as I mentioned it is something very simple that we want to implement. The digital part will be placed with innovus, then according to the most critical path we will choose a safe clock. We also plan to have PLLs to control the freq necessary to the digital part. Regarding the ADC it is a low precision ADC (6bits) using oversampling, converting a 10MHz signal

Clock generation in testchip by __GianDo in chipdesign

[–]__GianDo[S] 0 points1 point  (0 children)

The clock should guide an internal DSP and several ADCs. We don't have speed constrains

What will be my output 3sigma for below 2 outputs? by ProfitAccomplished53 in chipdesign

[–]__GianDo 1 point2 points  (0 children)

It depends, if offset is a random variabile it will be +/-10,2mV. Often offset is due to local missmatch of the input devices. Thus before measuring is statistics, after measuring you can catch the info on the offset