예제 #1
0
    def make_array(self, expr: Array):
        # make the output signal that will hold the results
        output = Signal(name=next(self.namer), format_=expr.format_)
        self.make_signal(output)

        # compile the array elements and address to signals
        elements = [self.expr_to_signal(element) for element in expr.elements]
        address  = self.expr_to_signal(expr.address)

        # extra step for analog signals -- they must be aligned to the output format
        if isinstance(expr.format_, RealFormat):
            # rename the elements list to indicate these values are not aligned to the output format
            non_aligned_elements = elements

            # created an "aligned" version of each signal
            elements = [Signal(name=next(self.namer), format_=expr.format_) for _ in range(len(expr))]
            for element, non_aligned_element in zip(elements, non_aligned_elements):
                self.make_signal(element)
                self.make_assign(input_=non_aligned_element, output=element)

        # now create the array
        case_statment(gen=self, sel=address.name, var=output.name, values=signal_names(elements), default=0)

        # and last return the output signal
        return output
예제 #2
0
    def make_constant_array_mul_signal(self, expr: Product):
        # figure out which operand is the constant array and which is the signal (note: if both are constant arrays,
        # that is not handled in a special fashion.  although that shouldn't usually occur due to the way that
        # expressions are built up.)
        if isinstance(expr.operands[0], Array) and expr.operands[0].all_constants:
            constant_array = expr.operands[0]
            signal = self.expr_to_signal(expr.operands[1])
        elif isinstance(expr.operands[1], Array) and expr.operands[1].all_constants:
            constant_array = expr.operands[1]
            signal = self.expr_to_signal(expr.operands[0])
        else:
            raise Exception(f'This expression does not represent a constant array times a signal: {expr}.')

        # create the output signal
        output = Signal(name=next(self.namer), format_=expr.format_)

        # create a short real variable to be assigned the selected value from the array
        array_name = next(self.namer)
        self.macro_call('MAKE_SHORT_REAL', array_name, compile_range_expr(constant_array.format_.range_))

        # perform the multiplication
        self.macro_call('MUL_REAL', array_name, signal.name, output.name)

        # compile the array address to a signal
        address = self.expr_to_signal(constant_array.address)

        # compute the valuess to go in the array
        values = [f'`FROM_REAL({element.value}, {array_name})' for element in constant_array.elements]

        # create the array itself
        case_statment(gen=self, sel=address.name, var=array_name, values=values, default=0)

        # return the output signal
        return output
예제 #3
0
    def make_constant(self, expr: Constant):
        output = Signal(name=next(self.namer), format_=expr.format_)

        if isinstance(expr.format_, RealFormat):
            # compile the range, width, and exponent expressions.
            if isinstance(expr.value, Integral):
                # avoid a synthesis corner-case:
                # https://forums.xilinx.com/t5/Synthesis/Possible-synthesis-bug-casting-integer-to-real-in-a-function/td-p/1140910
                const = str(float(expr.value))
            else:
                const = str(expr.value)
            range = compile_range_expr(expr.format_.range_)
            width = compile_width_expr(expr.format_.width)
            exponent = compile_exponent_expr(expr.format_.exponent)

            # call the appropriate macro
            if width is None:
                self.macro_call('MAKE_CONST_REAL', const, output.name)
            elif exponent is None:
                self.macro_call('MAKE_GENERIC_CONST_REAL', const, output.name, width)
            else:
                self.macro_call('MAKE_FORMAT_REAL', output.name, range, width, exponent)
                self.macro_call('ASSIGN_CONST_REAL', const, output.name)
        elif isinstance(expr.format_, IntFormat):
            self.make_signal(output)
            self.digital_assignment(output, expr.value)
        else:
            raise ValueError(f'Unknown expression format type: ' + expr.format_.__class__.__name__)

        return output
예제 #4
0
    def make_constant_mul_signal(self, expr: Product):
        # figure out which operand is the constant and which is the signal (note: if both are constants, that is
        # not handled in a special fashion.  although that shouldn't usually occur due to the way that expressions
        # are built up.)
        if isinstance(expr.operands[0], Constant):
            constant = expr.operands[0]
            signal = self.expr_to_signal(expr.operands[1])
        elif isinstance(expr.operands[1], Constant):
            constant = expr.operands[1]
            signal = self.expr_to_signal(expr.operands[0])
        else:
            raise Exception(f'This expression does not represent a constant times a signal: {expr}.')

        # create the output signal
        output = Signal(name=next(self.namer), format_=expr.format_)

        # call the special multiplication macro, avoiding a synthesis corner-case:
        # https://forums.xilinx.com/t5/Synthesis/Possible-synthesis-bug-casting-integer-to-real-in-a-function/td-p/1140910
        if isinstance(constant.value, Integral):
            # avoid a synthesis corner-case:
            # https://forums.xilinx.com/t5/Synthesis/Possible-synthesis-bug-casting-integer-to-real-in-a-function/td-p/1140910
            const_as_str = str(float(constant.value))
        else:
            const_as_str = str(constant.value)
        self.macro_call('MUL_CONST_REAL', const_as_str, signal.name, output.name)

        # return the output signal
        return output
예제 #5
0
파일: verilog.py 프로젝트: xlchan/msdsl
    def make_constant(self, expr: Constant):
        output = Signal(name=next(self.namer), format_=expr.format_)

        if isinstance(expr.format_, RealFormat):
            # compile the range, width, and exponent expressions
            const = str(expr.value)
            range = compile_range_expr(expr.format_.range_)
            width = compile_width_expr(expr.format_.width)
            exponent = compile_exponent_expr(expr.format_.exponent)

            # call the appropriate macro
            if width is None:
                self.macro_call('MAKE_CONST_REAL', const, output.name)
            elif exponent is None:
                self.macro_call('MAKE_GENERIC_CONST_REAL', const, output.name, width)
            else:
                self.macro_call('MAKE_FORMAT_REAL', output.name, range, width, exponent)
                self.macro_call('ASSIGN_CONST_REAL', const, output.name)
        elif isinstance(expr.format_, IntFormat):
            self.make_signal(output)
            self.digital_assignment(output, expr.value)
        else:
            raise ValueError(f'Unknown expression format type: ' + expr.format_.__class__.__name__)

        return output
예제 #6
0
    def make_bitwise_inv(self, expr: BitwiseInv):
        output = Signal(name=next(self.namer), format_=expr.format_)
        self.make_signal(output)

        input_ = self.expr_to_signal(expr.operand)
        value = f'~{input_.name}'
        self.digital_assignment(signal=output, value=value)

        return output
예제 #7
0
    def make_concatenation(self, expr: Concatenate):
        output = Signal(name=next(self.namer), format_=expr.format_)
        self.make_signal(output)

        inputs_ = [self.expr_to_signal(operand) for operand in expr.operands]
        value = '{' + ', '.join(signal_names(inputs_)) + '}'
        self.digital_assignment(signal=output, value=value)

        return output
예제 #8
0
    def make_arithmetic_shift(self, expr: ArithmeticShift):
        output = Signal(name=next(self.namer), format_=expr.format_)
        self.make_signal(output)

        input_ = self.expr_to_signal(expr.operand)
        value = f'{input_.name} {SHIFT_OP[type(expr)]} {expr.shift}'
        self.digital_assignment(signal=output, value=value)

        return output
예제 #9
0
    def make_bitwise_operator(self, expr: BitwiseOperator):
        output = Signal(name=next(self.namer), format_=expr.format_)
        self.make_signal(output)

        inputs = [self.expr_to_signal(operand) for operand in expr.operands]
        value = BITWISE_OP[type(expr)].join(signal_names(inputs))
        self.digital_assignment(signal=output, value=value)

        return output
예제 #10
0
    def make_bitwise_access(self, expr: BitwiseAccess):
        output = Signal(name=next(self.namer), format_=expr.format_)
        self.make_signal(output)

        input_ = self.expr_to_signal(expr.operand)
        value = f'{input_.name}[{expr.msb}:{expr.lsb}]'
        self.digital_assignment(signal=output, value=value)

        return output
예제 #11
0
    def make_type_conversion(self, expr: TypeConversion):
        # make the output signal
        output = Signal(name=next(self.namer), format_=expr.format_)

        # compile the input expression to a signal
        input_ = self.expr_to_signal(expr.operand)

        # handle the various cases
        if isinstance(expr, SIntToReal):
            self.macro_call('INT_TO_REAL', input_.name,
                            str(input_.format_.width), output.name)
        elif isinstance(expr, RealToSInt):
            self.macro_call('REAL_TO_INT', input_.name,
                            str(output.format_.width), output.name)
        elif isinstance(expr, UIntToSInt):
            # sanity check
            assert output.format_.width >= input_.format_.width+1, \
                f'Output SInt width ({output.format_.width}) is not at least one greater than the input UInt width ({input_.format_.width}).'

            # make the output signal
            self.make_signal(output)

            # construct string representation of new SInt
            num_zeros = output.format_.width - input_.format_.width
            value = f'{{{self.zero_const(num_zeros)}, {input_.name}}}'

            # make the assignment
            self.digital_assignment(signal=output,
                                    value=value,
                                    comment='UInt -> SInt')
        elif isinstance(expr, SIntToUInt):
            # sanity check
            assert output.format_.width >= input_.format_.width-1, \
                f'Output UInt width ({output.format_.width}) is not at least one less than the input SInt width ({input_.format_.width}).'

            # make the output signal
            self.make_signal(output)

            # then trim off the sign bit
            value = f'{input_.name}[{input_.format_.width-2}:0]'

            # pad with zeros if necessary
            num_zeros = output.format_.width - (input_.format_.width - 1)
            if num_zeros > 0:
                value = f'{{{self.zero_const(num_zeros)}, {value}}}'

            # make the assignment
            self.digital_assignment(signal=output,
                                    value=value,
                                    comment='SInt -> UInt')
        else:
            raise ValueError(
                f'Unknown type conversion: {expr.__class__.__name__}')

        return output
예제 #12
0
    def make_random_integer(self, expr: RandomInteger):
        # validate input
        assert expr.format_.width == 32, 'Only width 32 is supported at this time.'

        # set defaults

        if expr.clk is None:
            clk = '`CLK_MSDSL'
        elif isinstance(expr.clk, str):
            clk = expr.clk
        else:
            clk = expr.clk.name

        if expr.rst is None:
            rst = '`RST_MSDSL'
        elif isinstance(expr.rst, str):
            rst = expr.rst
        else:
            rst = expr.rst.name

        if expr.cke is None:
            cke = "1'b1"
        elif isinstance(expr.cke, str):
            cke = expr.cke
        else:
            cke = expr.cke.name

        if expr.seed is None:
            seed = random.randint(0, (1<<expr.format_.width)-1)
            seed = self.hex_format(seed, expr.format_.width)
        elif isinstance(expr.seed, Integral):
            assert 0 <= expr.seed <= ((1<<expr.format_.width)-1), \
                'Seed is out of range.'
            seed = self.hex_format(expr.seed, expr.format_.width)
        elif isinstance(expr.seed, str):
            seed = expr.seed
        else:
            seed = expr.seed.name

        # determine the parameters of the output signal
        name = next(self.namer)
        output = Signal(name=name, format_=expr.format_)

        # assign the result
        if isinstance(expr, MT19937):
            self.macro_call('MT19937', clk, rst, cke, seed, output.name)
        elif isinstance(expr, LCG):
            self.macro_call('LCG_MSDSL', clk, rst, cke, seed, output.name)
        else:
            raise Exception(f'Unsupported expression: {expr}')

        # return the resulting signal
        return output
예제 #13
0
    def make_compress_uint(self, expr: CompressUInt):
        # compile the input to a signal
        input_ = self.expr_to_signal(expr.operand)

        # determine the parameters of the output signal
        name = next(self.namer)
        format_ = expr.format_
        output = Signal(name=name, format_=format_)

        # assign the result
        self.macro_call('COMPRESS_UINT', input_.name, str(input_.format_.width), output.name)

        # return the resulting signal
        return output
예제 #14
0
    def make_comparison_operator(self, expr: ComparisonOperator):
        output = Signal(name=next(self.namer), format_=expr.format_)

        lhs = self.expr_to_signal(expr.lhs)
        rhs = self.expr_to_signal(expr.rhs)

        if isinstance(lhs.format_, RealFormat) and isinstance(rhs.format_, RealFormat):
            self.macro_call(REAL_COMP_OP[type(expr)], lhs.name, rhs.name, output.name)
        elif isinstance(lhs.format_, IntFormat) and isinstance(rhs.format_, IntFormat):
            # make the output signal
            self.make_signal(output)

            # assign the output signal
            value = f"({lhs} {INT_COMP_OP[type(expr)]} {rhs}) ? 1'b1 : 1'b0"
            self.digital_assignment(signal=output, value=value)
        else:
            raise ValueError(f'Unknown format type combination for LHS and RHS: {lhs.format_.__class__.__name__} and {rhs.format_.__class__.__name__}.')

        return output
예제 #15
0
    def set_this_cycle(self, signal: Union[Signal, str], expr: ModelExpr):
        """
        The behavior of this function is essentially a blocking assignment (in Verilog nomenclature). The provided
        expression is continuously written to the provided signal.

        :param signal:  Signal object being assigned
        :param expr:    Value of the expression to assign
        :return:
        """

        if isinstance(signal, str):
            expr = wrap_constant(expr)
            signal = self.add_signal(Signal(name=signal, format_=expr.format_))
            assignment_cls = BindingAssignment
        elif isinstance(signal, Signal):
            assignment_cls = ThisCycleAssignment
        else:
            raise Exception(f'Invalid signal type: {type(signal)}.')

        return self.add_assignment(assignment_cls(signal=signal, expr=expr))
예제 #16
0
        def operator(a, b):
            # determine the parameters of the output signal
            name = next(self.namer)
            format_ = expr.function(a.format_, b.format_)

            # create the output signal
            c = Signal(name=name, format_=format_)

            # assign the result
            if isinstance(expr.format_, RealFormat):
                self.macro_call(REAL_ARITH_OP[type(expr)], a.name, b.name, c.name)
            elif isinstance(expr.format_, IntFormat):
                self.make_signal(c)
                value = INT_ARITH_OP[type(expr)](a.name, b.name)
                self.digital_assignment(signal=c, value=value)
            else:
                raise Exception(f'Unknown expression format type: {expr.format_.__class__.__name__}')

            # return the output signal
            return c
예제 #17
0
파일: verilog.py 프로젝트: xlchan/msdsl
    def make_constant_mul_signal(self, expr: Product):
        # figure out which operand is the constant and which is the signal (note: if both are constants, that is
        # not handled in a special fashion.  although that shouldn't usually occur due to the way that expressions
        # are built up.)
        if isinstance(expr.operands[0], Constant):
            constant = expr.operands[0]
            signal = self.expr_to_signal(expr.operands[1])
        elif isinstance(expr.operands[1], Constant):
            constant = expr.operands[1]
            signal = self.expr_to_signal(expr.operands[0])
        else:
            raise Exception(f'This expression does not represent a constant times a signal: {expr}.')

        # create the output signal
        output = Signal(name=next(self.namer), format_=expr.format_)

        # call the special multiplication macro
        self.macro_call('MUL_CONST_REAL', str(constant.value), signal.name, output.name)

        # return the output signal
        return output