1

I am new to Verilog (and, to a lesser extent, programming) and am trying to create a program that finds the absolute value of a set of numbers and then calculates for a running average. The running average is 5 points wide, and goes across a data set that is about 40 numbers wide.

I am having trouble with the running average (lines 14-17 design, 24-28 test-bench) and am receiving the errors "o2/out is not a valid l-value in tb.avg." and "o2/out is declared here as a wire". How should I fix this?

Here is my design:

module absolute_value(i1,o1);
  input signed [11:0] i1;
  output signed [11:0] o1;

  assign o1 = i1[11] ? -i1 : i1;
endmodule 

module moving_average(k1,k2,k3,k3,k4,o2,out);
  input k1, k2, k3, k4, k5;
  output [11:0] o2;
  output [11:0] out;
  integer t;

  always begin
    assign o2 = (k1 + k2 + k3 + k4 + k5) / 5;
    assign out = o2;
  end
endmodule

And here is my test-bench:

module tb;
  reg signed [11:0] i1;
  wire signed [11:0] o1;

  reg k1;
  reg k2;
  reg k3;
  reg k4;
  reg k5;
  wire [11:0] o2;
  wire [11:0] out;

  absolute_value abs(i1,o1);  
  moving_average avg(k1,k2,k3,k4,k5,o2,out);

  integer t;

  initial begin
    for (t = -10; t < 30; t = t + 1) begin
      #1
      i1 <= t;
      $display("i1 = %d, o1 = %d", i1, o1);

      assign k5 = k4 ? k4 : o1;
      assign k4 = k3 ? k3 : o1;
      assign k3 = k2 ? k2 : o1;
      assign k2 = k1 ? k1 : o1;
      assign k1 = o1;

      $display("out = %d", out);

      $moniter($time, "i1 = %d, o1 = %d, o2 = %d, out = %d k1 = %d, k2 = %d, k3 = %d, k4 = %d, k5 = %d", i1, o1, o2, out, k1, k2, k3, k4, k5);
    end
  end
endmodule

I'd bet that there are other errors in my program too, so any help is much appreciated.

CD4
  • 15
  • 1
  • 4
  • A `wire` type is, as said, not an `l-value`. This means that you cannot assign to it. You try to assign to it. – Vivick Jul 05 '18 at 23:19
  • But even as a reg, there are still the errors "o2/out is not a valid l-value" and "o2/out is declared here as a wire". – CD4 Jul 05 '18 at 23:44
  • 1
    You should't use `assign` inside an `always` block. `assign` already means a continuous evaluation of the right expression. The assignments in the testbench are probably problematic, too. – Hans Lehnert Jul 06 '18 at 00:04
  • Thanks @HansLehnert, but that still does not fix my problem. I changed o2 and out to be `wire` and removed the `assign` statements, but still receive the "not valid l-value" and "declared here as a wire" errors. What other part of my code could be producing those errors? – CD4 Jul 06 '18 at 00:18
  • 1
    That's also wrong, you can't assign a `wire` in an `always` block either since wires don't have a state. The options would be are: (1) Move the assigns outside of the always block (2) Declare your outputs as `reg` and use a simple blocking assignment inside the always block (i.e. `out = o2;`) – Hans Lehnert Jul 06 '18 at 00:24
  • Possible duplicate of [not a valid l-value - verilog compiler error](https://stackoverflow.com/questions/5636055/not-a-valid-l-value-verilog-compiler-error) – Qiu Jul 06 '18 at 05:55
  • Thanks, @HansLehnert! I changed them to `reg` and created a blocking assignment statement instead of non-blocking, but now I am receiving an error on the second line of my testbench that says "syntax error". I reviewed it to the best of my knowledge, but couldn't find anything. The code is... `module tb( reg signed [11:0] i1, o1, k1, k2, k3, k4, k5, o2, out );` ... and there is also the errors "implicit definition of wire for each port when I instantiate the modules a few lines below. Why do I get this error? – CD4 Jul 06 '18 at 18:57

1 Answers1

2

As mentioned in the comments:

Remove the always and keep the output [11:0] out
or
Change to:

reg [11:0] o2;
reg [11:0] out;
always @( * )
begin
  o2 = (k1 + k2 + k3 + k4 + k5) / 5;
  out = o2;
end

Second error: Your port uses k1, k2, k3, k3, k4 and is missing k5.

Thirdly: please don't use the port style from last century. I advise you to switch to the new format:

module moving_average(
  input k1, k2, k3, k4, k5,
  output signed [11:0] o2,out
);

Or for the second case: output signed reg [11:0] o2,out

Fourth: it is $monitor, not $moniter

toolic
  • 57,801
  • 17
  • 75
  • 117
Oldfart
  • 6,104
  • 2
  • 13
  • 15
  • Thanks, but as I said in the comments, I am still receiving errors in the test-bench. Any suggestions? – CD4 Jul 06 '18 at 19:01
  • After I made the necessary changes it compiled for me. I did not run or check the simulation as there are many things in there which do not make sense. e.g. adding 5 bits K1..K5 to put them in an 11 bit result.Output the same outputs o2, out, The divide-by-5 may cause problems in synthesis as not all tools support it. (They will support divide by 4) – Oldfart Jul 06 '18 at 19:12
  • Thanks @Oldfart! I'm trying to go through the code and debug, but as I said, I'm quite new to this. Would you mind stating which other things don't make sense? I'm going through the examples you said now, but any other help would be much appreciated. – CD4 Jul 06 '18 at 20:34