Defining Custom Gates in Scripts
Learn how to define custom gates using the define...end syntax
Logicarium allows you to define custom gates directly in your script using the define...end syntax. This is powerful for creating reusable logic blocks without switching to the visual editor.
Basic Syntax
define GateName(input1, input2, ...) -> (output1, output2, ...):
output1 = expression
output2 = expression
endPrimitive Operations
Only two operations are built-in primitives:
| Operation | Syntax | Description |
|---|---|---|
| AND | a AND b | Output HIGH if both inputs HIGH |
| NOT | NOT a | Inverts the input signal |
All other gates must be built from these primitives or from previously defined/loaded custom gates.
Tutorial 1: Building Basic Gates
NAND Gate
NAND is simply AND followed by NOT:
define NAND(a, b) -> (out):
t = a AND b
out = NOT t
endOR Gate (De Morgan's Law)
OR can be built using: OR(a,b) = NOT(NOT(a) AND NOT(b))
define OR(a, b) -> (out):
na = NOT a
nb = NOT b
t = na AND nb
out = NOT t
endNOR Gate
NOR is OR followed by NOT, or equivalently: NOR(a,b) = NOT(a) AND NOT(b)
define NOR(a, b) -> (out):
na = NOT a
nb = NOT b
out = na AND nb
endXOR Gate
XOR outputs HIGH when inputs are different: XOR(a,b) = (a AND NOT(b)) OR (NOT(a) AND b)
// First define OR (or load it from a library)
define OR(a, b) -> (out):
na = NOT a
nb = NOT b
t = na AND nb
out = NOT t
end
define XOR(a, b) -> (out):
na = NOT a
nb = NOT b
t1 = a AND nb
t2 = na AND b
out = OR(t1, t2)
endXNOR Gate
XNOR is simply NOT(XOR):
define XNOR(a, b) -> (out):
t = XOR(a, b)
out = NOT t
endTutorial 2: Building Arithmetic Circuits
Half Adder
A half adder adds two bits and produces a sum and carry:
- Sum = A XOR B
- Carry = A AND B
// Assuming OR and XOR are already defined
define HalfAdder(a, b) -> (sum, carry):
sum = XOR(a, b)
carry = a AND b
endFull Adder
A full adder adds three bits (A, B, and Carry-in):
define FullAdder(a, b, cin) -> (sum, cout):
// First half adder
s1 = XOR(a, b)
c1 = a AND b
// Second half adder
sum = XOR(s1, cin)
c2 = s1 AND cin
// Output carry
cout = OR(c1, c2)
endTutorial 3: Using Loaded Gate Libraries
You can use gates loaded from .bin files within your define blocks.
Workflow
- Load your gate library: File > Load Custom Gates...
- Now you can reference those gates in your script
Example
Assume you have a library with a MUX2 (2-input multiplexer) gate:
// MUX2 was loaded from gates.bin
define MUX4(a, b, c, d, s0, s1) -> (out):
// Use loaded MUX2 gates
m1 = MUX2(a, b, s0)
m2 = MUX2(c, d, s0)
out = MUX2(m1, m2, s1)
endTutorial 4: Multiple Outputs
Custom gates can have multiple outputs:
define Decoder2to4(a, b) -> (y0, y1, y2, y3):
na = NOT a
nb = NOT b
y0 = na AND nb // 00
y1 = a AND nb // 01
y2 = na AND b // 10
y3 = a AND b // 11
endUsing a multi-output gate:
Decoder2to4 dec @ 200, 100
In sel0 @ 50, 100
In sel1 @ 50, 200
Out led0 @ 400, 50
Out led1 @ 400, 150
Out led2 @ 400, 250
Out led3 @ 400, 350
sel0 -> dec.in0
sel1 -> dec.in1
dec.out0 -> led0
dec.out1 -> led1
dec.out2 -> led2
dec.out3 -> led3Rules and Limitations
Signal Names
- Must be valid identifiers (letters, numbers, underscores)
- Case-sensitive
- Cannot use reserved words:
define,end,AND,NOT
Order Matters
- Gates must be defined before they are used
- Input/output order in the signature determines slot numbering (
in0,in1,out0,out1)
No Nested Calls
This is NOT allowed:
// WRONG - nested calls
out = NAND(NAND(a, a), NAND(b, b))Use intermediate signals instead:
// CORRECT - intermediate signals
t1 = NAND(a, a)
t2 = NAND(b, b)
out = NAND(t1, t2)No Feedback Loops
Define blocks create combinational logic only. You cannot create feedback loops within a define block.
Complete Example: 4-Bit Ripple Carry Adder
// === Primitive Gates ===
define OR(a, b) -> (out):
na = NOT a
nb = NOT b
t = na AND nb
out = NOT t
end
define XOR(a, b) -> (out):
na = NOT a
nb = NOT b
t1 = a AND nb
t2 = na AND b
out = OR(t1, t2)
end
// === Adder Components ===
define FullAdder(a, b, cin) -> (sum, cout):
s1 = XOR(a, b)
c1 = a AND b
sum = XOR(s1, cin)
c2 = s1 AND cin
cout = OR(c1, c2)
end
// === Use in Circuit ===
FullAdder fa0 @ 200, 100
FullAdder fa1 @ 200, 250
FullAdder fa2 @ 200, 400
FullAdder fa3 @ 200, 550
In a0 @ 50, 50
In b0 @ 50, 100
In a1 @ 50, 200
In b1 @ 50, 250
In a2 @ 50, 350
In b2 @ 50, 400
In a3 @ 50, 500
In b3 @ 50, 550
In cin @ 50, 650
Out s0 @ 400, 75
Out s1 @ 400, 225
Out s2 @ 400, 375
Out s3 @ 400, 525
Out cout @ 400, 625
// Bit 0
a0 -> fa0.in0
b0 -> fa0.in1
cin -> fa0.in2
fa0.out0 -> s0
// Bit 1
a1 -> fa1.in0
b1 -> fa1.in1
fa0.out1 -> fa1.in2
fa1.out0 -> s1
// Bit 2
a2 -> fa2.in0
b2 -> fa2.in1
fa1.out1 -> fa2.in2
fa2.out0 -> s2
// Bit 3
a3 -> fa3.in0
b3 -> fa3.in1
fa2.out1 -> fa3.in2
fa3.out0 -> s3
fa3.out1 -> cout