Programmable Logic Array (PLA) Tasks in Verilog and SystemVerilog
Programmable Logic Arrays (PLAs) are essential components of digital system design. Verilog and SystemVerilog provide system tasks for modeling PLAs, offering a versatile approach to manage digital logic tasks. This guide will explore these tasks, their operations, and illustrate practical examples.
PLA System Tasks Syntax
System tasks in Verilog and SystemVerilog follow a distinct syntax: $arrayType$logic$format
. In this construction:
arrayType
could besync
(for synchronous) orasync
(for asynchronous).logic
indicates the type of logic operation (and, or, nand, nor).format
denotes the personality format (array or plane).
Consider this format in action: $sync$and$array(memoryId, inputTerms, outputTerms)
. Here, memoryId
refers to the particular memory, inputTerms
are the input expressions, and outputTerms
are the output variables.
Synchronous vs. Asynchronous Tasks
These two types of tasks differ based on timing. Asynchronous tasks activate as soon as the input terms or memory words change. In contrast, synchronous tasks allow control over when the logic array is evaluated and the output terms are updated.
Here's a quick look at each in code:
Asynchronous Example
module AsynchronousMagic(
input wire[7:1] aWire,
output logic[3:1] bReg
);
$async$and$array(memoryId, aWire, bReg);
endmodule
Synchronous Example
module SynchronousMagic(
input wire clk,
input wire[7:1] aWire,
output logic[3:1] bReg,
);
always @(posedge clk) begin
$sync$or$plane(memoryId, aWire, bReg);
end
endmodule
In the synchronous example, operations occur at the positive edge of the clock.
Logic Array Types in System Tasks
The four logic array types usable in SystemVerilog PLA tasks are AND, OR, NAND, and NOR. These types specify the kind of logic operation within the PLA task. For instance, the $sync$and$array
task performs a synchronous AND operation, whereas $async$nand$plane
executes an asynchronous NAND operation.
Sample Logic Array Types
module LogicArrayFun(input wire[7:1] aWire, output logic[3:1] bReg);
$sync$or$array(memoryId, aWire, bReg);
$async$nand$plane(memoryId, aWire, bReg);
endmodule
Declaring and Loading Logic Array Personalities
The personality of the logic array is declared as an array of variables. This personality can be loaded from a text data file using the $readmemb
or $readmemh
system tasks. Alternatively, the personality data can be directly written into the memory using assignment statements.
module LoadPersonality(input wire[7:1] aWire, output logic[3:1] bReg);
logic [1:7] memoryId[1:3];
initial begin
$readmemb("memoryData.dat", memoryId);
$async$and$array(memoryId, aWire, bReg);
end
endmodule
Here, the personality is loaded from a file named "memoryData.dat".
Array and Plane System Calls
The array and plane system calls are two distinct ways to script the PLA tasks. The array system call uses a straightforward approach with a 1 for taking the input value and a 0 for ignoring it. The plane system call enables the expression of complemented input values, true input values, worst-case input values, and "do not care" conditions.
Implementing a Full Adder with PLA Tasks
PLA tasks in SystemVerilog are employed to create a full adder, providing an effective example of these tasks in action.
Logical Expression for a Full Adder
The logical expressions for the sum and carry out of a full adder are as follows:
Sum: A B' C_in' + A' B C_in' + A' B' C_in
Carry out: A B + A C_in + B C_in
Full Adder Example with Array Tasks
Consider a scenario with inputs {A A' B B' C_in C_in'}
. Here is an example of implementing a full adder using these inputs:
module FullAdder1 (
input logic a, b, cIn,
output logic sum, cOut
);
bit [5:0] memProduct[7]; // Memory for storing product terms
bit [6:0] memSum[2]; // Memory for storing sum terms
logic [6:0] internal;
initial begin
memProduct[0] = 6'b100101; // A B' Cin'
memProduct[1] = 6'b011001; // A' B C_in'
memProduct[2] = 6'b010110; // A' B' C_in
memProduct[3] = 6'b101010; // A B C_in
memProduct[4] = 6'b101000; // A B
memProduct[5] = 6'b100010; // A C_in
memProduct[6] = 6'b001010; // B C_in
memSum[0] = 7'b1111000; // OR plane for sum
memSum[1] = 7'b0000111; // OR plane for cOut
end
$async$and$array(memProduct, {a, ~a, b, ~b, cIn, ~cIn}, internal);
$async$or$array(memSum, internal, {cOut, sum});
endmodule
Full Adder Implementation with Plane Tasks
An alternative way of implementing a full adder uses plane tasks, specifically the $async$and$plane
and $async$or$plane
tasks. The input pattern in this case is simpler: {A B C_in}
.
module FullAdder2 (
input logic a, b, cIn,
output logic sum, cOut
);
bit [2:0] memProduct[7]; // Memory for storing product terms
bit [6:0] memSum[2]; // Memory for storing sum terms
logic [6:0] internal;
initial begin
memProduct[0] = 3'b100; // A B' Cin'
memProduct[1] = 3'b010; // A' B C_in'
memProduct[2] = 3'b001; // A' B' C_in
memProduct[3] = 3'b111; // A B C_in
memProduct[4] = 3'b11?; // A B
memProduct[5] = 3'b1?1; // A C_in
memProduct[6] = 3'b?11; // B C_in
memSum[0] = 7'b1111???; // OR plane for sum
memSum[1] = 7'b????111; // OR plane for cOut
end
$async$and$plane(memProduct, {a, b, cIn}, internal);
$async$or$plane(memSum, internal, {cOut, sum});
endmodule
In digital system design, Programmable Logic Array (PLA) tasks in Verilog and SystemVerilog are fundamental tools. The asynchronous and synchronous tasks, array and plane formats, and the four logic array types - AND, OR, NAND, and NOR - provide a robust and versatile set of options for modelling complex systems. PLA tasks, while initially complex, become more manageable and intuitive with practice. They form the basis for a wide range of digital logic designs and as such, are worth learning thoroughly. Understanding and mastering these tasks offer significant opportunities for effective and efficient digital system design.