diff --git a/.github/workflows/generate.yml b/.github/workflows/generate.yml index 38c8b3d..7f628b1 100644 --- a/.github/workflows/generate.yml +++ b/.github/workflows/generate.yml @@ -53,6 +53,12 @@ jobs: run: | cd tests bash test_circuits.sh + cd .. + - name: Run 8b CGP testing + run: | + cd tests + bash test_circuits_cgp.sh + cd .. # Only on main thread documentation: diff --git a/.gitignore b/.gitignore index e4529d9..285bb0b 100644 --- a/.gitignore +++ b/.gitignore @@ -7,5 +7,6 @@ build/ dist/ test_circuits/ tests/tmp.exe +tests/tmp.c *.egg-info \ No newline at end of file diff --git a/ariths_gen/core/arithmetic_circuits/arithmetic_circuit.py b/ariths_gen/core/arithmetic_circuits/arithmetic_circuit.py index 3c721d9..17468e3 100644 --- a/ariths_gen/core/arithmetic_circuits/arithmetic_circuit.py +++ b/ariths_gen/core/arithmetic_circuits/arithmetic_circuit.py @@ -687,7 +687,7 @@ class ArithmeticCircuit(): Returns: str: List of arithmetic circuit's output wire indexes. """ - return "(" + ",".join([str(self.get_circuit_wire_index(o)) for o in self.out.bus[::-1]]) + ")" + return "(" + ",".join([str(self.get_circuit_wire_index(o)) for o in self.out.bus]) + ")" # Generating flat CGP chromosome representation of circuit def get_cgp_code_flat(self, file_object): diff --git a/chr2c.py b/chr2c.py index 403ea49..457824c 100644 --- a/chr2c.py +++ b/chr2c.py @@ -1,15 +1,16 @@ +#!/usr/bin/python3 # A simple script to convert the input CGP chromosome to the corresponding output in C code # Script originally written by Vojtech Mrazek # Modifications to suite the appropriate needs of ArithsGen made by Jan Klhufek -# Requires python2! import sys import re import numpy as np +import argparse # Parse all nodes present in input CGP def parse_node(n): - return map(int, re.match(r"(\d+),(\d+),(\d+)", n).groups()) + return list(map(int, re.match(r"(\d+),(\d+),(\d+)", n).groups())) # Recursively detect wires required to get the result wire with id 'id' and activate them (will be generated) @@ -30,26 +31,26 @@ def activate(id, act, c_in, cdata_dict): # Declare new output logic gate's wire if it has not been declared yet (and then assign it the result of corresponding logical function) # Or return previously declared wire (which is used as an input into corresponding logical function) def get_sig(name, trans, create=False): - if create is True and int(name) not in trans.keys(): + if create is True and int(name) not in list(trans.keys()): trans[name] = "sig_%d" % name return trans[name] -# Parse and convert the input CGP chromosome to output C code representation -if __name__ == "__main__": +def parse_chromosome(chromosome, signed=False, function=None): + # Load input CGP - f = open(sys.argv[1], "r") + f = open(chromosome, "r") chrom = "\n".join([x for x in f]) f.close() - print "// ", sys.argv[1] + output = ["// " + chromosome] # Splitting input representation into three parts preamble, data, outputs = re.match(r"\{(.*)\}\((.*)\)\(([^\)]+)\)", chrom).groups() # Parsing CGP preamble parameters - c_in, c_out, c_rows, c_cols, c_ni, c_no, c_lback = map(int, preamble.split(",")) + c_in, c_out, c_rows, c_cols, c_ni, c_no, c_lback = list(map(int, preamble.split(","))) # Parsing all present nodes - cdata = map(parse_node, data.split(")(")) + cdata = list(map(parse_node, data.split(")("))) # Parse position and corresponding information regarding each chromosome cdata_dict = [None for i in range(0, c_cols * c_rows)] @@ -69,27 +70,36 @@ if __name__ == "__main__": act[1] = True # Obtaining all output wires (MSB to LSB) - outs = map(int, outputs.split(",")) + outs = list(map(int, outputs.split(","))) # Recursively activate all (node) wires needed to obtain the corresponding result wire for o in outs: activate(o, act, c_in, cdata_dict) # Export converted input declarations into C code function header / body start - print "#include " - print "uint64_t circuit%d(uint64_t a, uint64_t b) {" % (c_in / 2) - print " int wa[%d];" % (c_in/2) - print " int wb[%d];" % (c_in/2) - print " uint64_t y = 0;" + output.append("#include ") + + if not function: + function = f"circuit{c_in/2:.0f}" + + if signed: + dtype = "int64_t" + else: + dtype = "uint64_t" + + output.append(f"{dtype} {function}({dtype} a, {dtype} b) {{") + output.append(" int wa[%d];" % int(c_in/2)) + output.append(" int wb[%d];" % int(c_in/2)) + output.append(" uint64_t y = 0;") # Export converted input assignments into C code function body trans = {} trans[0] = "0x00" trans[1] = "0x01" - for i in range(0, (c_in/2)): + for i in range(0, int(c_in/2)): trans[i+2] = "wa[%d]" % i - print " wa[%d] = (a >> %d) & 0x01;" % (i, i) + output.append(" wa[%d] = (a >> %d) & 0x01;" % (i, i)) trans[i + (c_in/2)+2] = "wb[%d]" % i - print " wb[%d] = (b >> %d) & 0x01;" % (i, i) + output.append(" wb[%d] = (b >> %d) & 0x01;" % (i, i)) # Lists representing individual nodes (lines), output wires (lines_end) lines = [] @@ -119,11 +129,26 @@ if __name__ == "__main__": # Export converted outputs into C code function body for i in range(0, c_out): if outs[i] in trans: - lines_end.append(" y |= (%s & 0x01) << %d; // default output" % (trans[outs[i]], (len(outs)-1) - i)) + lines_end.append(" y |= (%s & 0x01) << %d; // default output" % (trans[outs[i]], i)) else: assert False # Print final result return in C code function body and close it - lines_end.append(" return y;") - print "\n".join(lines + lines_end) - print "}" + lines_end.append(" return y;") + output += lines + output += lines_end; + output.append("}") + + return "\n".join(output) + +# Parse and convert the input CGP chromosome to output C code representation +if __name__ == "__main__": + argparse.ArgumentParser() + parser = argparse.ArgumentParser() + + parser.add_argument("chromosome", help="Path to CGP file") + parser.add_argument("--signed", action="store_true") + parser.add_argument("--function", default=None) + args = parser.parse_args() + print(parse_chromosome(**vars(args))) + \ No newline at end of file diff --git a/tests/test_circuits_cgp.sh b/tests/test_circuits_cgp.sh new file mode 100755 index 0000000..1002f31 --- /dev/null +++ b/tests/test_circuits_cgp.sh @@ -0,0 +1,100 @@ +#!/usr/bin/bash + +valid=1 + +test_circuit () { + local type=$1 + local circuit=$2 + + + mode="flat" + echo -e "===== Testing CGP version \e[33m$circuit\e[0m ($mode) ======" + + s="" + if [[ $type == *"_signed" ]]; then + s="--signed" + fi + python3 ../chr2c.py $s ../test_circuits/cgp_circuits/$mode/$circuit.cgp > tmp.c + + + g++ -std=c++11 -pedantic -g -std=c++11 -pedantic -DCNAME="circuit8" $type.c tmp.c -o tmp.exe + if ./tmp.exe ; then + echo -e "[\e[32mok\e[0m]" + else + echo -e "[\e[31mfail\e[0m]" + valid=0 + fi +} + + + +test_circuit "adder_signed" "s_rca8" +test_circuit "adder_signed" "s_pg_rca8" +test_circuit "adder_signed" "s_cska8" +test_circuit "adder_signed" "s_cla8" + +test_circuit "adder_unsigned" "u_rca8" +test_circuit "adder_unsigned" "u_pg_rca8" +test_circuit "adder_unsigned" "u_cska8" +test_circuit "adder_unsigned" "u_cla8" + + +test_circuit "multiplier_signed" "s_arrmul8" +test_circuit "multiplier_signed" "s_wallace_cla8" +test_circuit "multiplier_signed" "s_wallace_rca8" +test_circuit "multiplier_signed" "s_wallace_pg_rca8" +test_circuit "multiplier_signed" "s_wallace_cska8" +test_circuit "multiplier_signed" "s_dadda_cla8" +test_circuit "multiplier_signed" "s_dadda_rca8" +test_circuit "multiplier_signed" "s_dadda_pg_rca8" +test_circuit "multiplier_signed" "s_dadda_cska8" + + +test_circuit "multiplier_unsigned" "u_arrmul8" +test_circuit "multiplier_unsigned" "u_wallace_cla8" +test_circuit "multiplier_unsigned" "u_wallace_rca8" +test_circuit "multiplier_unsigned" "u_wallace_pg_rca8" +test_circuit "multiplier_unsigned" "u_wallace_cska8" +test_circuit "multiplier_unsigned" "u_dadda_cla8" +test_circuit "multiplier_unsigned" "u_dadda_rca8" +test_circuit "multiplier_unsigned" "u_dadda_pg_rca8" +test_circuit "multiplier_unsigned" "u_dadda_cska8" + + + +if [ $valid -eq 1 ]; then + echo "all tests passed" + exit 0 +else + echo "some of tests failed" + exit 1 +fi + + +# exporting s_rca8 +# exporting s_pg_rca8 +# exporting s_cska8 +# exporting s_cla8 +# exporting s_arrmul8 +# exporting s_wallace_cla8 +# exporting s_wallace_rca8 +# exporting s_wallace_pg_rca8 +# exporting s_wallace_cska8 +# exporting s_dadda_cla8 +# exporting s_dadda_rca8 +# exporting s_dadda_pg_rca8 +# exporting s_dadda_cska8 +# exporting u_rca8 +# exporting u_pg_rca8 +# exporting u_cska8 +# exporting u_cla8 +# exporting u_arrmul8 +# exporting u_wallace_cla8 +# exporting u_wallace_rca8 +# exporting u_wallace_pg_rca8 +# exporting u_wallace_cska8 +# exporting u_dadda_cla8 +# exporting u_dadda_rca8 +# exporting u_dadda_pg_rca8 +# exporting u_dadda_cska8 +# exporting arrdiv8