You need to go back to basics.
Verilog is a hardware description language, not a programming language. Your code is describing hardware.
Let's see what your code is trying to infer:
module top(
input a, b, x,
output c
);
Ok, we have a module. That's all fine. Now what does it do?
always @(a or b or x)
begin
if(x)
xor21 x1 (.a(a), .b(b), .c(c));
else
and21 a1 (.a(a), .b(b), .c(c));
end
That code says "Whenever a
, b
, or x
changes: If x
is high, instantiate a new piece of hardware called xor21
, otherwise instantiate a different piece of hardware called and21
".
Hmm, that means that if the value of x
changes, bits of your hardware suddenly disappear, and other bits of hardware appear from nowhere. This cannot happen. The whole design needs to be known when the design is synthesized.
In otherwords, you cannot instantiate a module in a procedural block.
Instead, you need to think about what you hardware you need. You decide, well I need an and21
module, and an xor21
module. So lets instantiate one of each:
module top(
input a, b, x,
output c
);
wire xor21_output;
wire and21_output;
xor21 x1 (.a(a), .b(b), .c(xor21_output));
and21 x1 (.a(a), .b(b), .c(and21_output));
Cool. Now we have a our module, and it contains our two submodules. Now we need to work out the behaviour of the output c
.
Well, if x
is high, we want the output from xor21
, and if x
is low, we need the output from and21
. So that means we need a multiplexer. Well, we can either do this in continuous assignment using the ternary operator (?
), or we can use an always block. Let's look at both. First the ternary:
assign c = x ? xor21_output : and21_output;
Then the always block (see note):
always @ (x) begin
if (x) begin
c = xor21_output;
end else begin
c = and21_output;
end
end
And voila. We now have a module with the required behaviour, in which the required hardware is known when the design is synthesised.
(note) - if you are assigning a value in an procedural block (such as always or initial), the target must be a storage type, such as reg
. You cannot assign a wire
type in a procedural block. So we would have to change the module definition to output reg c
.