Added signed rca circuit.

This commit is contained in:
honzastor 2021-02-09 20:53:53 +01:00
parent ee73047199
commit de127e8c46
3 changed files with 146 additions and 44 deletions

View File

@ -3,13 +3,16 @@ from logic_gates_generator import and_gate, xor_gate, or_gate
import sys import sys
# ARITMETICKE OBVODY """ ARITHMETIC CIRCUITS """
class arithmetic_circuit(): class arithmetic_circuit():
def __init__(self): def __init__(self):
self.components = [] self.components = []
self.circuit_wires = [] self.circuit_wires = []
self.c_data_type = "uint64_t" self.c_data_type = "uint64_t"
# TODO delete?
self.input_N = 0 self.input_N = 0
self.carry_out_gate = None self.carry_out_gate = None
self.sum_out_gates = [] self.sum_out_gates = []
@ -26,12 +29,13 @@ class arithmetic_circuit():
def get_carry_wire(self): def get_carry_wire(self):
return self.out.get_wire(1) return self.out.get_wire(1)
# FLAT C GENERATION #
@staticmethod @staticmethod
def get_includes_c(): def get_includes_c():
return f"#include <stdio.h>\n#include <stdint.h>\n\n" return f"#include <stdio.h>\n#include <stdint.h>\n\n"
def get_prototype_c(self): def get_prototype_c(self):
return f"{self.c_data_type} {self.prefix}({self.c_data_type} {self.a.prefix}, {self.c_data_type} {self.b.prefix})" + "{" + '\n' return f"uint64_t {self.prefix}({self.c_data_type} {self.a.prefix}, {self.c_data_type} {self.b.prefix})" + "{" + '\n'
def get_declaration_c(self): def get_declaration_c(self):
return f"".join([c.get_declaration_c() for c in self.components]) return f"".join([c.get_declaration_c() for c in self.components])
@ -45,18 +49,21 @@ class arithmetic_circuit():
def get_function_carry_c(self): def get_function_carry_c(self):
return f"{self.get_previous_component().get_function_carry_c(offset=self.out.N-1)}" return f"{self.get_previous_component().get_function_carry_c(offset=self.out.N-1)}"
# Generovani aritmetickeho obvodu do jazyka C # Generating flat C code representation of circuit
def get_c_code(self, file_object): def get_c_code(self, file_object):
file_object.write(self.get_includes_c()) file_object.write(self.get_includes_c())
file_object.write(self.get_prototype_c()) file_object.write(self.get_prototype_c())
file_object.write(self.out.get_declaration_c()) file_object.write(self.out.get_declaration_c())
file_object.write(self.get_declaration_c()) file_object.write(self.get_declaration_c()+"\n")
file_object.write(self.get_initialization_c()) file_object.write(self.get_initialization_c()+"\n")
file_object.write(self.get_function_sum_c()) file_object.write(self.get_function_sum_c())
file_object.write(self.get_function_carry_c()) file_object.write(self.get_function_carry_c())
file_object.write(f" return {self.out.prefix}"+";\n}") file_object.write(f" return {self.out.prefix}"+";\n}")
file_object.close() file_object.close()
# HIERARCHICAL C GENERATION #
# TODO
class half_adder(arithmetic_circuit): class half_adder(arithmetic_circuit):
def __init__(self, a: wire, b: wire, prefix: str = "ha"): def __init__(self, a: wire, b: wire, prefix: str = "ha"):
@ -65,25 +72,28 @@ class half_adder(arithmetic_circuit):
self.prefix = prefix self.prefix = prefix
self.a = a self.a = a
self.b = b self.b = b
# 2 draty pro vystupy komponenty (sum, cout) # 2 wires for component's bus output (sum, cout)
self.out = bus("out", 2) self.out = bus("out", 2)
# Sum # Sum
# XOR hradlo pro vypocet jednobitového souctu (sum) # XOR gate for calculation of 1-bit sum
obj_xor_gate = xor_gate(a, b, prefix, outid=0) obj_xor_gate = xor_gate(a, b, prefix, outid=0)
self.add_component(obj_xor_gate) self.add_component(obj_xor_gate)
self.out.connect(0, obj_xor_gate.output) self.out.connect(0, obj_xor_gate.output)
# Cout # Cout
# AND hradlo pro vypocet jednobitoveho priznaku prenosu do vyssiho radu (cout)jednobitového souctu (sum) # AND gate for calculation of 1-bit cout
obj_and_gate = and_gate(a, b, prefix, outid=1) obj_and_gate = and_gate(a, b, prefix, outid=1)
self.add_component(obj_and_gate) self.add_component(obj_and_gate)
self.out.connect(1, obj_and_gate.output) self.out.connect(1, obj_and_gate.output)
# FLAT C GENERATION #
# Half adder function prototype with two inputs
def get_prototype_c(self): def get_prototype_c(self):
return f"{self.c_data_type} {self.prefix}({self.c_data_type} {self.a.name}, {self.c_data_type} {self.b.name})" + "{" + '\n' return f"{self.c_data_type} {self.prefix}({self.c_data_type} {self.a.name}, {self.c_data_type} {self.b.name})" + "{" + '\n'
# Ziskani vsech unikatnich vodicu obvodu ze vsech hradel k zajisteni neopakujicich se deklaraci stejnych vodicu # Obtaining list of all the unique circuit wires from all contained logic gates
# to ensure non-recurring declaration of same wires
def get_declaration_c(self): def get_declaration_c(self):
for component in self.components: for component in self.components:
if not [item for item in self.circuit_wires if item[1] == component.a.name]: if not [item for item in self.circuit_wires if item[1] == component.a.name]:
@ -95,10 +105,10 @@ class half_adder(arithmetic_circuit):
if not [item for item in self.circuit_wires if item[1] == component.output.name]: if not [item for item in self.circuit_wires if item[1] == component.output.name]:
self.circuit_wires.append((component.output, component.output.name)) self.circuit_wires.append((component.output, component.output.name))
# Unikatni deklarace vsech propoju obvodu # Unique declaration of all circuit's interconnections
return "".join([c[0].get_declaration_c() for c in self.circuit_wires]) return "".join([c[0].get_declaration_c() for c in self.circuit_wires])
# Inicializace hodnot vodicu polovicni scitacky # Half adder wires values initialization
def get_initialization_c(self): def get_initialization_c(self):
return f" {self.components[0].a.name} = {self.a.get_wire_value_c(offset=self.a.index)};\n" + \ return f" {self.components[0].a.name} = {self.a.get_wire_value_c(offset=self.a.index)};\n" + \
f" {self.components[0].b.name} = {self.b.get_wire_value_c(offset=self.b.index)};\n" + \ f" {self.components[0].b.name} = {self.b.get_wire_value_c(offset=self.b.index)};\n" + \
@ -120,23 +130,23 @@ class full_adder(arithmetic_circuit):
self.a = a self.a = a
self.b = b self.b = b
self.c = c self.c = c
# 2 draty pro vystupy komponenty (sum, cout) # 2 wires for component's bus output (sum, cout)
self.out = bus("out", 2) self.out = bus("out", 2)
# PG logika # PG logic
propagate_xor_gate1 = xor_gate(a, b, prefix, outid=0) propagate_xor_gate1 = xor_gate(a, b, prefix, outid=0)
self.add_component(propagate_xor_gate1) self.add_component(propagate_xor_gate1)
generate_and_gate1 = and_gate(a, b, prefix, outid=1) generate_and_gate1 = and_gate(a, b, prefix, outid=1)
self.add_component(generate_and_gate1) self.add_component(generate_and_gate1)
# Sum # Sum
# XOR hradlo pro vypocet jednobitového souctu (sum) # XOR gate for calculation of 1-bit sum
obj_xor_gate2 = xor_gate(propagate_xor_gate1.output, c, prefix, outid=2) obj_xor_gate2 = xor_gate(propagate_xor_gate1.output, c, prefix, outid=2)
self.add_component(obj_xor_gate2) self.add_component(obj_xor_gate2)
self.out.connect(0, obj_xor_gate2.output) self.out.connect(0, obj_xor_gate2.output)
# Cout # Cout
# AND hradlo pro vypocet jednobitoveho priznaku prenosu do vyssiho radu (cout)jednobitového souctu (sum) # AND gate for calculation of 1-bit cout
obj_and_gate2 = and_gate(propagate_xor_gate1.output, c, prefix, outid=3) obj_and_gate2 = and_gate(propagate_xor_gate1.output, c, prefix, outid=3)
self.add_component(obj_and_gate2) self.add_component(obj_and_gate2)
@ -145,14 +155,17 @@ class full_adder(arithmetic_circuit):
self.out.connect(1, obj_or_gate.output) self.out.connect(1, obj_or_gate.output)
# TODO nechat do budoucna? # TODO delete or leave?
self.propagate = propagate_xor_gate1.output self.propagate = propagate_xor_gate1.output
self.generate = generate_and_gate1.output self.generate = generate_and_gate1.output
# 3 vstupy spolu s carry in # FLAT C GENERATION #
# Full adder function prototype with three inputs
def get_prototype_c(self): def get_prototype_c(self):
return f"{self.c_data_type} {self.prefix}({self.c_data_type} {self.a.name}, {self.c_data_type} {self.b.name}, {self.c_data_type} {self.c.name})" + "{" + '\n' return f"{self.c_data_type} {self.prefix}({self.c_data_type} {self.a.name}, {self.c_data_type} {self.b.name}, {self.c_data_type} {self.c.name})" + "{" + '\n'
# Obtaining list of all the unique circuit wires from all contained logic gates
# to ensure non-recurring declaration of same wires
def get_declaration_c(self): def get_declaration_c(self):
for component in self.components: for component in self.components:
if not [item for item in self.circuit_wires if item[1] == component.a.name]: if not [item for item in self.circuit_wires if item[1] == component.a.name]:
@ -164,10 +177,10 @@ class full_adder(arithmetic_circuit):
if not [item for item in self.circuit_wires if item[1] == component.output.name]: if not [item for item in self.circuit_wires if item[1] == component.output.name]:
self.circuit_wires.append((component.output, component.output.name)) self.circuit_wires.append((component.output, component.output.name))
# Unikatni deklarace vsech propoju obvodu # Unique declaration of all circuit's interconnections
return "".join([c[0].get_declaration_c() for c in self.circuit_wires]) return "".join([c[0].get_declaration_c() for c in self.circuit_wires])
# Inicializace hodnot vodicu uplne scitacky # Full adder wires values initialization
def get_initialization_c(self): def get_initialization_c(self):
return f" {self.components[0].a.name} = {self.a.get_wire_value_c(offset=self.a.index)};\n" + \ return f" {self.components[0].a.name} = {self.a.get_wire_value_c(offset=self.a.index)};\n" + \
f" {self.components[0].b.name} = {self.b.get_wire_value_c(offset=self.b.index)};\n" + \ f" {self.components[0].b.name} = {self.b.get_wire_value_c(offset=self.b.index)};\n" + \
@ -185,44 +198,123 @@ class full_adder(arithmetic_circuit):
return f" {self.out.prefix} |= {self.components[4].output.return_wire_value_c(offset = offset)};\n" return f" {self.out.prefix} |= {self.components[4].output.return_wire_value_c(offset = offset)};\n"
class ripple_carry_adder(arithmetic_circuit): class signed_ripple_carry_adder(arithmetic_circuit):
def __init__(self, a: bus, b: bus, prefix: str = "rca"): def __init__(self, a: bus, b: bus, prefix: str = "s_rca"):
super().__init__() super().__init__()
N = max(a.N, b.N) self.N = max(a.N, b.N)
self.prefix = prefix+str(N) self.c_data_type = "int64_t"
# Bus sign extension in case buses have different lengths
a.sign_extend(self.N)
b.sign_extend(self.N)
self.a = a self.a = a
self.b = b self.b = b
if prefix == "s_rca":
self.prefix = prefix+str(self.N)
else:
self.prefix = prefix
# Vystupni draty pro N souctu a vystupni priznak prenosu do vyssiho radu (cout) # Output wires for N sum bits and additional cout bit
self.out = bus("out", N+1) self.out = bus("out", self.N+1)
# Postupne pridani jednobitovych scitacek # Gradual addition of 1-bit adder components
for input_index in range(N): for input_index in range(self.N):
# Prvni je polovicni scitacka # First one is a half adder
if input_index == 0: if input_index == 0:
obj_ha = half_adder(a.get_wire(input_index), b.get_wire(input_index), prefix=self.prefix+"_ha") obj_ha = half_adder(a.get_wire(input_index), b.get_wire(input_index), prefix=self.prefix+"_ha")
self.add_component(obj_ha) self.add_component(obj_ha)
self.out.connect(input_index, obj_ha) self.out.connect(input_index, obj_ha)
# Rest are full adders
else: else:
obj_fa = full_adder(a.get_wire(input_index), b.get_wire(input_index), self.get_previous_component().get_carry_wire(), prefix=self.prefix+"_fa"+str(input_index)) obj_fa = full_adder(a.get_wire(input_index), b.get_wire(input_index), self.get_previous_component().get_carry_wire(), prefix=self.prefix+"_fa"+str(input_index))
self.add_component(obj_fa) self.add_component(obj_fa)
self.out.connect(input_index, obj_fa.get_sum_wire()) self.out.connect(input_index, obj_fa.get_sum_wire())
if input_index == (N-1): if input_index == (self.N-1):
self.out.connect(N, obj_fa.get_carry_wire()) self.out.connect(self.N, obj_fa.get_carry_wire())
# Additional XOR gates to ensure correct sign extension in case of sign addition
sign_xor_1 = xor_gate(self.get_previous_component().a, self.get_previous_component().b, prefix=self.prefix+"_xor_1")
sign_xor_2 = xor_gate(sign_xor_1.output, self.get_previous_component().get_carry_wire(), prefix=self.prefix+"_xor_2")
self.add_component(sign_xor_1)
self.add_component(sign_xor_2)
# FLAT C GENERATION #
# Initialization of 1-bit adders and sign extension XOR gates
def get_initialization_c(self):
return f"".join([c.get_initialization_c() for c in self.components[:-2]]) + \
f" {self.components[-2].a.name} = {self.a.get_wire_value_c(offset=self.N-1)};\n" + \
f" {self.components[-2].b.name} = {self.b.get_wire_value_c(offset=self.N-1)};\n" + \
f" {self.components[-2].output.name} = {self.components[-2].get_initialization_c()};\n" + \
f" {self.components[-1].a.name} = {self.components[-2].output.get_wire_value_c()};\n" + \
f" {self.components[-1].b.name} = {self.components[-3].get_carry_wire().get_wire_value_c()};\n" + \
f" {self.components[-1].output.name} = {self.components[-1].get_initialization_c()};\n"
def get_function_sum_c(self):
return "".join([c.get_function_sum_c(self.components.index(c)) for c in self.components[:-2]])
def get_function_carry_c(self):
return f" {self.out.prefix} |= {self.get_previous_component().output.return_wire_value_c(offset = self.N)};\n"
class unsigned_ripple_carry_adder(arithmetic_circuit):
def __init__(self, a: bus, b: bus, prefix: str = "u_rca"):
super().__init__()
self.N = max(a.N, b.N)
# Bus sign extension in case buses have different lengths
a.sign_extend(self.N)
b.sign_extend(self.N)
self.a = a
self.b = b
if prefix == "u_rca":
self.prefix = prefix+str(self.N)
else:
self.prefix = prefix
# Output wires for N sum bits and additional cout bit
self.out = bus("out", self.N+1)
# Gradual addition of 1-bit adder components
for input_index in range(self.N):
# First one is a half adder
if input_index == 0:
obj_ha = half_adder(a.get_wire(input_index), b.get_wire(input_index), prefix=self.prefix+"_ha")
self.add_component(obj_ha)
self.out.connect(input_index, obj_ha)
# Rest are full adders
else:
obj_fa = full_adder(a.get_wire(input_index), b.get_wire(input_index), self.get_previous_component().get_carry_wire(), prefix=self.prefix+"_fa"+str(input_index))
self.add_component(obj_fa)
self.out.connect(input_index, obj_fa.get_sum_wire())
if input_index == (self.N-1):
self.out.connect(self.N, obj_fa.get_carry_wire())
if __name__ == "__main__": if __name__ == "__main__":
# Vytvoreni obvodu 8 bitove postupne scitacky a = bus(N=8, prefix="a")
b = bus(N=8, prefix="b")
rca = signed_ripple_carry_adder(a, b)
rca.get_c_code(open("s_rca8.c", "w"))
w1 = wire(name="a")
w2 = wire(name="b")
w3 = wire(name="cin")
fa = full_adder(w1, w2, w3)
fa.get_c_code(open("fa.c", "w"))
"""
# Generation of 8-bit rca
a = bus(N=8, prefix="a") a = bus(N=8, prefix="a")
b = bus(N=8, prefix="b") b = bus(N=8, prefix="b")
rca = ripple_carry_adder(a, b) rca = ripple_carry_adder(a, b)
# Export do jazyka C (flat) # Export to C code (flat) and save to file
rca.get_c_code(open("rca_8.c", "w")) rca.get_c_code(open("rca_8.c", "w"))
# Vytvoreni logickeho hradla OR # Generation of OR logic gate
# Hodnoty pouze pro otestovani funcnosti v Pythonu # Values just for testing functionality within Python
a1 = wire(name="a", value=1) a1 = wire(name="a", value=1)
b1 = wire(name="b", value=0) b1 = wire(name="b", value=0)
xor = xor_gate(a1, b1) xor = xor_gate(a1, b1)
# Vypis v jazyke C (flat) na standardni vystup # Export to C code (flat) and display to stdout
xor.get_c_code(sys.stdout) xor.get_c_code(sys.stdout)
"""

View File

@ -1,13 +1,16 @@
from wire_components import wire from wire_components import wire
# KOMPONENTY HRADEL """ LOGIC GATE COMPONENTS """
class logic_gate(): class logic_gate():
def __init__(self, a: wire, b: wire, prefix: str = "w"): def __init__(self, a: wire, b: wire, prefix: str = "w"):
self.a = wire(prefix+"_"+a.name.replace(prefix+"_", ''), a.value) self.a = wire(prefix+"_"+a.name.replace(prefix+"_", ''), a.value)
self.b = wire(prefix+"_"+b.name.replace(prefix+"_", ''), b.value) self.b = wire(prefix+"_"+b.name.replace(prefix+"_", ''), b.value)
self.prefix = prefix self.prefix = prefix
# FLAT C GENERATION #
@staticmethod @staticmethod
def get_includes_c(): def get_includes_c():
return f"#include <stdio.h>\n#include <stdint.h>\n\n" return f"#include <stdio.h>\n#include <stdint.h>\n\n"
@ -26,15 +29,19 @@ class logic_gate():
self.b.name = self.b.name.replace(self.prefix+"_", '') self.b.name = self.b.name.replace(self.prefix+"_", '')
return f"{self.a.get_wire_value_c()} {self.operator} {self.b.get_wire_value_c(0)}" return f"{self.a.get_wire_value_c()} {self.operator} {self.b.get_wire_value_c(0)}"
# Generovani samostatneho obvodu logickeho hradla do jazyka C # Generating flat C code representation of separate logic gate
# (i.e. not as a component of bigger circuit)
def get_c_code(self, file_object): def get_c_code(self, file_object):
file_object.write(self.get_includes_c()) file_object.write(self.get_includes_c())
file_object.write(self.get_prototype_c()) file_object.write(self.get_prototype_c())
file_object.write(" return "+(self.get_function_c())+";\n}") file_object.write(" return "+(self.get_function_c())+";\n}")
file_object.close() file_object.close()
# HIERARCHICAL C GENERATION #
# TODO
# Jednovstupa
# Single-input
class not_gate(logic_gate): class not_gate(logic_gate):
def __init__(self, a: wire, prefix: str = "w", outid: int = 0): def __init__(self, a: wire, prefix: str = "w", outid: int = 0):
self.gate_type = 'not_gate' self.gate_type = 'not_gate'
@ -61,7 +68,7 @@ class not_gate(logic_gate):
return f"{self.operator}{self.a.get_wire_value_c()} & 0x01 << 0" return f"{self.operator}{self.a.get_wire_value_c()} & 0x01 << 0"
# Dvouvstupa # Two-input
class and_gate(logic_gate): class and_gate(logic_gate):
def __init__(self, a: wire, b: wire, prefix: str = "w", outid: int = 0): def __init__(self, a: wire, b: wire, prefix: str = "w", outid: int = 0):
super().__init__(a, b, prefix) super().__init__(a, b, prefix)

View File

@ -1,4 +1,4 @@
# KOMPONENTY PROPOJU """ WIRE COMPONENTS """
class wire(): class wire():
@ -18,7 +18,6 @@ class wire():
class bus(): class bus():
# Inicializace sbernice
def __init__(self, prefix: str = "bus", N: int = 1): def __init__(self, prefix: str = "bus", N: int = 1):
self.bus = [wire(name=prefix, index=i) for i in range(N)] self.bus = [wire(name=prefix, index=i) for i in range(N)]
self.prefix = prefix self.prefix = prefix
@ -27,13 +26,13 @@ class bus():
def __index__(self, wire): def __index__(self, wire):
return self.bus.index(wire) return self.bus.index(wire)
# Pripojeni vystupniho vodice vnitrni komponenty na vstup jine komponenty # Connecting output wire of the inner circuit component to the input of another component
# (nebo drat vystupni sbernice obvodu) # (or to the wire of the circuit's output bus)
def connect(self, out_wire_index: int, inner_component_out_wire: wire): def connect(self, out_wire_index: int, inner_component_out_wire: wire):
self.bus[out_wire_index] = inner_component_out_wire self.bus[out_wire_index] = inner_component_out_wire
def get_wire_value_c(self, offset: int = 0): def get_wire_value_c(self, offset: int = 0):
self.bus[offset].get_wire_value_c(offset) return self.bus[offset].get_wire_value_c(offset=offset)
def return_wire_value_c(self, offset: int = 0): def return_wire_value_c(self, offset: int = 0):
self.bus[offset].return_wire_value_c(offset) self.bus[offset].return_wire_value_c(offset)
@ -46,3 +45,7 @@ class bus():
def get_wire(self, wire_index: int): def get_wire(self, wire_index: int):
return self.bus[wire_index] return self.bus[wire_index]
def sign_extend(self, N: int):
self.bus = [wire(name=self.prefix, index=i) for i in range(N)]
self.N = N