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:
input a, b, x,
Ok, we have a module. That's all fine. Now what does it do?
always @(a or b or x)
xor21 x1 (.a(a), .b(b), .c(c));
and21 a1 (.a(a), .b(b), .c(c));
That code says "Whenever
x changes: If
x is high, instantiate a new piece of hardware called
xor21, otherwise instantiate a different piece of hardware called
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:
input a, b, x,
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
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;
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.