예제 #1
0
    def make_file_read(self, i, action):
        assert file_mode_allows_reading(action.file.mode), \
            f'File mode {action.file.mode} is not compatible with reading.'

        idx = 'i'
        fd = self.fd_var(action.file)
        in_ = self.in_var(action.file)
        err_msg = f'Reached end of file {action.file.name_without_ext}'

        return self.generate_action_code(i, [
            Loop(loop_var=idx,
                 n_iter=action.file.chunk_size,
                 count='down' if action.file.endianness == 'big' else 'up',
                 actions=[
                     f'int result = fgetc({fd});',
                     If(f'result == EOF',
                        [f'std::cout << "{err_msg}" << std::endl;', 'break;']),
                     f'{in_}[{idx}] = result;'
                 ])
        ])
예제 #2
0
    def make_file_write(self, i, action):
        assert file_mode_allows_writing(action.file.mode), \
            f'File mode {action.file.mode} is not compatible with writing.'

        idx = 'i'
        fd = self.fd_var(action.file)
        value = f'top->{verilator_name(action.value.name)}'
        byte_expr = f'({value} >> ({idx} * 8)) & 0xFF'
        err_msg = f'Error writing to {action.file.name_without_ext}'

        return self.generate_action_code(i, [
            Loop(loop_var=idx,
                 n_iter=action.file.chunk_size,
                 count='down' if action.file.endianness == 'big' else 'up',
                 actions=[
                     'int result = ' + self.write_byte(fd, byte_expr) + ';',
                     If(f'result == EOF',
                        [f'std::cout << "{err_msg}" << std::endl;', 'break;']),
                 ])
        ])
예제 #3
0
    def make_file_open(self, i, action):
        # make sure the file mode is supported
        if not is_valid_file_mode(action.file.mode):
            raise NotImplementedError(action.file.mode)

        # declare the file read variable if the file mode allows reading
        if file_mode_allows_reading(action.file.mode):
            in_ = self.in_var(action.file)
            decl_rd_var = [f'char {in_}[{action.file.chunk_size}] = {{0}};']
        else:
            decl_rd_var = []

        fd = self.fd_var(action.file)
        err_msg = f'Could not open file {action.file.name}'

        return self.generate_action_code(
            i, decl_rd_var + [
                f'FILE *{fd} = fopen("{action.file.name}", "{action.file.mode}");',
                If(f'{fd} == NULL',
                   [f'std::cout << "{err_msg}" << std::endl;', f'return 1;'])
            ])
예제 #4
0
 def _if(self, cond):
     if_tester = IfTester(self._circuit, self.clock)
     self.actions.append(If(cond, if_tester.actions,
                            if_tester.else_actions))
     return if_tester
예제 #5
0
    def make_expect(self, i, action):
        # don't do anything if any value is OK
        if value_utils.is_any(action.value):
            return []

        # determine the exact name of the signal
        name = self.make_name(action.port)

        # TODO: add something like "make_read_name" and "make_write_name"
        # so that reading inout signals has more uniform behavior across
        # expect, peek, etc.
        if actions.is_inout(action.port):
            name = self.input_wire(name)

        # determine the name of the signal for debugging purposes
        if isinstance(action.port, SelectPath):
            debug_name = action.port[-1].name
        elif isinstance(action.port, fault.WrappedVerilogInternalPort):
            debug_name = name
        else:
            debug_name = action.port.name

        # determine the value to be checked
        value = self.process_value(action.port, action.value)

        # determine the condition and error body
        err_hdr = ''
        err_hdr += f'Failed on action={i} checking port {debug_name}'
        if action.traceback is not None:
            err_hdr += f' with traceback {action.traceback}'
        if action.above is not None:
            if action.below is not None:
                # must be in range
                cond = f'(({action.above} <= {name}) && ({name} <= {action.below}))'  # noqa
                err_msg = 'Expected %0f to %0f, got %0f'
                err_args = [action.above, action.below, name]
            else:
                # must be above
                cond = f'({action.above} <= {name})'
                err_msg = 'Expected above %0f, got %0f'
                err_args = [action.above, name]
        else:
            if action.below is not None:
                # must be below
                cond = f'({name} <= {action.below})'
                err_msg = 'Expected below %0f, got %0f'
                err_args = [action.below, name]
            else:
                # equality comparison
                if action.strict:
                    cond = f'({name} === {value})'
                else:
                    cond = f'({name} == {value})'
                err_msg = 'Expected %x, got %x'
                err_args = [value, name]
        if action.msg is not None:
            if isinstance(action.msg, str):
                err_msg += "\\n" + action.msg
            else:
                assert isinstance(action.msg, tuple)
                err_msg += "\\n" + action.msg[0]
                err_args += self._make_print_args(action.msg[1:])

        # construct the body of the $error call
        err_fmt_str = f'"{err_hdr}.  {err_msg}."'
        err_body = [err_fmt_str] + err_args
        err_body = ', '.join([str(elem) for elem in err_body])

        if self.use_sva:
            return [f'assert ({cond}) else $error({err_body});']
        else:
            # return a snippet of verilog implementing the assertion
            return self.make_if(i, If(f'!{cond}', [f'$error({err_body});']))