From c1f32e8a5583ee3500b4d00be549612ccaa468ce Mon Sep 17 00:00:00 2001
From: Lukas Plevac <lukas@plevac.eu>
Date: Thu, 19 Sep 2024 13:29:27 +0200
Subject: [PATCH] Basic implemenation

---
 README.md | 38 +++++++++++++++++++++++++
 tt.py     | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 121 insertions(+)
 create mode 100644 tt.py

diff --git a/README.md b/README.md
index e69de29..63130af 100644
--- a/README.md
+++ b/README.md
@@ -0,0 +1,38 @@
+# Truth table generator for CGP
+
+Simple truth table generator python implementation. It can generate circuic definition
+for openmp-cgp. It iplemented in python3 and need only default python libraries.
+
+## Using
+
+```
+usage: tt.py [-h] [--inputWidth INPUTWIDTH] [--outputWidth OUTPUTWIDTH] [--file FILE] exp [exp ...]
+
+Simple TT file generator for CGP.
+
+positional arguments:
+  exp                   expression for TT
+
+options:
+  -h, --help            show this help message and exit
+  --inputWidth INPUTWIDTH
+                        Bit width of all inputs (default 1)
+  --outputWidth OUTPUTWIDTH
+                        Bit width of all outputs (default 1)
+  --file FILE           File to save TT if not set STDOUT used
+```
+
+### example - generate TT for 8b adder
+```sh
+python tt.py "a+b" --inputWidth 8 --outputWidth 8 --file "8badder.txt"
+```
+
+### example - generate TT for 4b parity
+```sh
+python tt.py "a^b^c^d" --file "4bparity.txt"
+```
+
+### example - generate TT for 8b multiplier
+```sh
+python tt.py "a*b" --inputWidth 8 --outputWidth 16 --file "8bmul.txt"
+```
\ No newline at end of file
diff --git a/tt.py b/tt.py
new file mode 100644
index 0000000..a54fc52
--- /dev/null
+++ b/tt.py
@@ -0,0 +1,83 @@
+import argparse
+
+parser = argparse.ArgumentParser(description='Simple TT file generator for CGP.')
+parser.add_argument('expression', metavar='exp', type=str, nargs='+', help='expression for TT')
+parser.add_argument('--inputWidth',  type=int, help='Bit width of all inputs (default 1)',  default=1)
+parser.add_argument('--outputWidth', type=int, help='Bit width of all outputs (default 1)', default=1)
+parser.add_argument('--file',        type=str, help='File to save TT if not set STDOUT used')
+
+ARGS_VARS = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]
+
+args      = parser.parse_args()
+expr      = " ".join(args.expression).lower()
+exprArgs  = []
+
+for s in expr:
+    if s in ARGS_VARS and s not in exprArgs:
+        exprArgs.append(s)
+
+# TT computation
+combinations = pow(2, args.inputWidth * len(exprArgs))
+
+print(f"Generating TT for {combinations} combinations")
+
+line = f"{args.inputWidth * len(exprArgs)} {args.outputWidth} # generated by tt.py; inputs are {exprArgs} on {args.inputWidth} bits; output are {expr}"
+
+# print header
+if args.file is None:
+    print()
+    print(line)
+else:
+    with open(args.file, 'w') as the_file:
+        the_file.write(f"{line}\n")
+
+# init table with bits
+bits = []
+exprArgsVals = []
+for inp in range(len(exprArgs)):
+    bits.append([])
+    exprArgsVals.append(0)
+    for bit in range(args.inputWidth):
+        bits[-1].append(0)
+
+# compute combinations
+for i in range(combinations):
+    line = ""
+    overFlow = True
+    for inp in range(len(exprArgs)):
+        
+        exprArgsVals[inp] = 0
+        
+        for bit in range(args.inputWidth):
+            
+            line              += f"{bits[inp][bit]} "
+            exprArgsVals[inp] |= bits[inp][bit] << bit
+
+            if overFlow:
+                if bits[inp][bit] == 1:
+                    bits[inp][bit] = 0
+                    overFlow       = True
+                else:
+                    bits[inp][bit] = 1
+                    overFlow       = False
+
+    # build expr
+    combinationExpr = expr
+    for inp in range(len(exprArgs)):
+        combinationExpr = combinationExpr.replace(exprArgs[inp], str(exprArgsVals[inp]))
+
+    #compute expr output
+    out = int(eval(combinationExpr))
+    
+    line += "| "
+
+    for bit in range(args.outputWidth):
+            
+        line              += f"{out & 0b1} "
+        out = out >> 1
+
+    if args.file is None:
+        print(line)
+    else:
+        with open(args.file, 'a') as the_file:
+            the_file.write(f"{line}\n")
\ No newline at end of file