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 be sync (for synchronous) or async (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.