Source code for caf_verilog.dot_product

from . quantizer import quantize
import os
import numpy as np
from jinja2 import Environment, FileSystemLoader, Template
from shutil import copy
from .caf_verilog_base import CafVerilogBase
from .io_helper import write_quantized_output
from .cpx_multiply import CpxMultiply

filedir = os.path.dirname(os.path.realpath(__file__))
dot_product_tb_module_path = os.path.join(filedir, '..', 'src')


[docs] class DotProduct(CafVerilogBase): def __init__(self, x, y, x_i_bits=12, x_q_bits=0, y_i_bits=12, y_q_bits=0, output_dir='.'): """ :param x: :param y: :param x_i_bits: :param x_q_bits: :param y_i_bits: :param y_q_bits: :param output_dir: """ self.x = x self.y = y self.cpx_input_length_check() self.length = len(list(zip(self.x,self.y))) self.x_i_bits = x_i_bits self.x_q_bits = x_q_bits if x_q_bits else self.x_i_bits self.y_i_bits = y_i_bits self.y_q_bits = y_q_bits if y_q_bits else self.y_i_bits self.sum_i_bits = (self.x_i_bits + self.y_i_bits) + np.ceil(np.log2(self.length)) self.sum_i_bits = int(self.sum_i_bits) self.sum_q_bits = (self.x_q_bits + self.y_q_bits) + np.ceil(np.log2(self.length)) self.sum_q_bits = int(self.sum_q_bits) self.x_quant = quantize(self.x, self.x_i_bits, self.x_q_bits) self.y_quant = quantize(self.y, self.y_i_bits, self.y_q_bits) self.output_dir = output_dir dot_product_module_path = os.path.join(filedir, '..', 'src', '%s.v' % (self.module_name())) self.tb_filename = '%s_tb.v' % (self.module_name()) self.test_value_filename = '%s_input_values.txt' % (self.module_name()) self.test_output_filename = '%s_output_values.txt' % (self.module_name()) self.submodules = self.gen_submodules() copy(dot_product_module_path, self.output_dir)
[docs] def gen_submodules(self): submodules = dict() submodules['cpx_multiply'] = CpxMultiply(self.x, self.y, self.x_i_bits, self.x_q_bits, self.y_i_bits, self.y_q_bits, output_dir=self.output_dir) return submodules
[docs] def gen_tb(self): write_quantized_output(self.output_dir, self.test_value_filename, self.x_quant, self.y_quant) self.write_dot_product_tb_module()
[docs] def params_dict(self) -> dict: return {'xi_bits': self.x_i_bits, 'xq_bits': self.x_q_bits, 'yi_bits': self.y_i_bits, 'yq_bits': self.y_q_bits, 'dot_length': self.length, 'sum_i_bits': self.sum_i_bits, 'sum_q_bits': self.sum_q_bits}
[docs] def template_dict(self, inst_name=None): t_dict = self.params_dict() t_dict['dot_prod_input'] = os.path.abspath(os.path.join(self.output_dir, self.test_value_filename)) t_dict['dot_prod_output'] = os.path.abspath(os.path.join(self.output_dir, self.test_output_filename)) t_dict['dot_prod_name'] = inst_name if inst_name else '%s_tb' % self.module_name() return t_dict
[docs] def write_dot_product_tb_module(self): """ Write out a testbench file to test the dot_product module. :return: """ out_tb = None t_dict = self.template_dict("%s_tb" % (self.module_name())) template_loader = FileSystemLoader(searchpath=dot_product_tb_module_path) env = Environment(loader=template_loader) template = env.get_template('%s_tb.v' % (self.module_name())) out_tb = template.render(**t_dict) with open(os.path.join(self.output_dir, self.tb_filename), 'w+') as tb_file: tb_file.write(out_tb)
[docs] def dot_product(a, b): """ Perform the dot product of a and b. This method performs the dot product using a multiply and accumulate. Therefore, it is subject to Python 3's int implementation rule when being used with quantized values. :param a: Vector of length n. :param b: Vector of length n. :return: """ if not len(a) == len(b): raise ValueError("a and b must have the same length") product = 0 for ia, ib in zip(a, b): product += ia * ib return product