Beispiel #1
0
    def write_sequential(self,
                         obj,
                         start_addr,
                         size,
                         value,
                         when=None,
                         port=0):
        flag = self.m.Reg(compiler._tmp_name('_'.join(['', self.name,
                                                       'flag'])),
                          initval=0)
        self.done_flags.append(flag)

        fsm = FSM(self.m, compiler._tmp_name('_'.join(['', self.name, 'fsm'])),
                  self.clk, self.rst)
        fsm.If(self.start_cond)(flag(0))
        fsm.If(self.start_cond).goto_next()

        done = obj.write_dataflow(port,
                                  start_addr,
                                  value,
                                  size,
                                  cond=fsm,
                                  when=when)
        fsm.goto_next()

        fsm.If(done)(flag(1))

        fsm.If(done).goto_init()

        return 0
Beispiel #2
0
    def read_sequential(self,
                        obj,
                        start_addr,
                        size,
                        point=0,
                        signed=False,
                        port=0,
                        with_last=False):
        flag = self.m.Reg(compiler._tmp_name('_'.join(['', self.name,
                                                       'flag'])),
                          initval=0)
        self.done_flags.append(flag)

        fsm = FSM(self.m, compiler._tmp_name('_'.join(['', self.name, 'fsm'])),
                  self.clk, self.rst)
        fsm.If(self.start_cond)(flag(0))
        fsm.If(self.start_cond).goto_next()

        rdata, rlast, done = obj.read_dataflow(port,
                                               start_addr,
                                               size,
                                               cond=fsm,
                                               point=point,
                                               signed=signed)
        fsm.goto_next()

        fsm.If(done)(flag(1))

        fsm.If(done).goto_init()

        if with_last:
            return rdata, rlast

        return rdata
Beispiel #3
0
    def write_pattern(self, obj, addr, value, pattern, when=None, port=0):

        flag = self.m.Reg(compiler._tmp_name('_'.join(['', self.name,
                                                       'flag'])),
                          initval=0)
        self.done_flags.append(flag)

        fsm = FSM(self.m, compiler._tmp_name('_'.join(['', self.name, 'fsm'])),
                  self.clk, self.rst)
        fsm.If(self.start_cond)(flag(0))
        fsm.If(self.start_cond).goto_next()

        if hasattr(obj, 'write_dataflow_pattern_interleave'):
            done = obj.write_dataflow_pattern_interleave(port,
                                                         addr,
                                                         value,
                                                         pattern,
                                                         cond=fsm,
                                                         when=when)
        else:
            done = obj.write_dataflow_pattern(port,
                                              addr,
                                              value,
                                              pattern,
                                              cond=fsm,
                                              when=when)

        fsm.goto_next()

        fsm.If(done)(flag(1))

        fsm.If(done).goto_init()

        return 0
Beispiel #4
0
    def read_reuse_pattern(self,
                           obj,
                           addr,
                           pattern,
                           reuse_size=1,
                           num_outputs=1,
                           point=0,
                           signed=False,
                           port=0,
                           with_last=False):

        flag = self.m.Reg(compiler._tmp_name('_'.join(['', self.name,
                                                       'flag'])),
                          initval=0)
        self.done_flags.append(flag)

        fsm = FSM(self.m, compiler._tmp_name('_'.join(['', self.name, 'fsm'])),
                  self.clk, self.rst)
        fsm.If(self.start_cond)(flag(0))
        fsm.If(self.start_cond).goto_next()

        if hasattr(obj, 'read_dataflow_reuse_pattern_interleave'):
            ret = obj.read_dataflow_reuse_pattern_interleave(port,
                                                             addr,
                                                             pattern,
                                                             reuse_size,
                                                             num_outputs,
                                                             cond=fsm,
                                                             point=point,
                                                             signed=signed)
        else:
            ret = obj.read_dataflow_reuse_pattern(port,
                                                  addr,
                                                  pattern,
                                                  reuse_size,
                                                  num_outputs,
                                                  cond=fsm,
                                                  point=point,
                                                  signed=signed)

        rdata = ret[:-2]
        done = ret[-1]
        rlast = ret[-2]

        fsm.goto_next()

        fsm.If(done)(flag(1))

        fsm.If(done).goto_init()

        if with_last:
            return tuple(rdata + [rlast])

        if len(rdata) == 1:
            rdata = rdata[0]
        else:
            rdata = tuple(rdata)

        return rdata
Beispiel #5
0
    def _setup_register_lite_fsm(self):
        fsm = FSM(self.m, '_'.join(['', self.name, 'register_fsm']), self.clk,
                  self.rst)

        # request
        addr, readvalid, writevalid = self.pull_request(cond=fsm)

        maskaddr = self.m.TmpReg(self.maskwidth)
        fsm.If(vtypes.Ors(readvalid, writevalid))(maskaddr((addr >> self.shift)
                                                           & self.mask), )

        init_state = fsm.current

        # read
        read_state = fsm.current + 1
        fsm.If(readvalid).goto_from(init_state, read_state)
        fsm.set_index(read_state)

        rdata = self.m.TmpWire(self.datawidth)
        pat = [(maskaddr == i, r) for i, r in enumerate(self.register)]
        pat.append((None, vtypes.IntX()))
        rval = vtypes.PatternMux(pat)
        rdata.assign(rval)

        flag = self.m.TmpWire()
        pat = [(maskaddr == i, r) for i, r in enumerate(self.flag)]
        pat.append((None, vtypes.IntX()))
        rval = vtypes.PatternMux(pat)
        flag.assign(rval)

        resetval = self.m.TmpWire(self.datawidth)
        pat = [(maskaddr == i, r) for i, r in enumerate(self.resetval)]
        pat.append((None, vtypes.IntX()))
        rval = vtypes.PatternMux(pat)
        resetval.assign(rval)

        ack = self.push_read_data(rdata, cond=fsm)

        # flag reset
        state_cond = fsm.state == fsm.current
        for i, r in enumerate(self.register):
            self.seq.If(state_cond, ack, flag,
                        maskaddr == i)(self.register[i](resetval),
                                       self.flag[i](0))

        fsm.If(ack).goto_init()

        # write
        write_state = fsm.current + 1
        fsm.If(writevalid).goto_from(init_state, write_state)
        fsm.set_index(write_state)

        data, mask, valid = self.pull_write_data(cond=fsm)

        state_cond = fsm.state == fsm.current
        for i, r in enumerate(self.register):
            self.seq.If(state_cond, valid,
                        maskaddr == i)(self.register[i](data))
        fsm.goto_init()
Beispiel #6
0
    def read_multidim(self,
                      obj,
                      addr,
                      shape,
                      order=None,
                      point=0,
                      signed=False,
                      port=0,
                      with_last=False):

        flag = self.m.Reg(compiler._tmp_name('_'.join(['', self.name,
                                                       'flag'])),
                          initval=0)
        self.done_flags.append(flag)

        fsm = FSM(self.m, compiler._tmp_name('_'.join(['', self.name, 'fsm'])),
                  self.clk, self.rst)
        fsm.If(self.start_cond)(flag(0))
        fsm.If(self.start_cond).goto_next()

        if hasattr(obj, 'read_dataflow_multidim_interleave'):
            rdata, rlast, done = obj.read_dataflow_multidim_interleave(
                port,
                addr,
                shape,
                order=order,
                cond=fsm,
                point=point,
                signed=signed)
        else:
            rdata, rlast, done = obj.read_dataflow_multidim(port,
                                                            addr,
                                                            shape,
                                                            order=order,
                                                            cond=fsm,
                                                            point=point,
                                                            signed=signed)

        fsm.goto_next()

        fsm.If(done)(flag(1))

        fsm.If(done).goto_init()

        if with_last:
            return rdata, rlast

        return rdata
Beispiel #7
0
def mkUartTx(baudrate=19200, clockfreq=100 * 1000 * 1000):
    m = Module("UartTx")
    waitnum = int(clockfreq / baudrate)

    clk = m.Input('CLK')
    rst = m.Input('RST')

    din = m.Input('din', 8)
    enable = m.Input('enable')
    ready = m.OutputReg('ready', initval=1)
    txd = m.OutputReg('txd', initval=1)

    fsm = FSM(m, 'fsm', clk, rst)

    mem = m.TmpReg(9, initval=0)
    waitcount = m.TmpReg(int(math.log(waitnum, 2)) + 1, initval=0)

    fsm(waitcount(waitnum - 1), txd(1), mem(vtypes.Cat(din, vtypes.Int(0, 1))))

    fsm.If(enable)(ready(0))

    fsm.Then().goto_next()

    for i in range(10):
        fsm.If(waitcount > 0)(waitcount.dec()).Else(
            txd(mem[0]), mem(vtypes.Cat(vtypes.Int(1, 1), mem[1:9])),
            waitcount(waitnum - 1))
        fsm.Then().goto_next()

    fsm(ready(1))

    fsm.goto_init()

    fsm.make_always()

    return m
Beispiel #8
0
def mkUartRx(baudrate=19200, clockfreq=100 * 1000 * 1000):
    m = Module("UartRx")
    waitnum = int(clockfreq / baudrate)

    clk = m.Input('CLK')
    rst = m.Input('RST')

    rxd = m.Input('rxd')
    dout = m.OutputReg('dout', 8, initval=0)
    valid = m.OutputReg('valid', initval=0)

    fsm = FSM(m, 'fsm', clk, rst)

    mem = m.TmpReg(9, initval=0)
    waitcount = m.TmpReg(int(math.log(waitnum, 2)) + 1, initval=0)

    fsm(valid(0), waitcount(int(waitnum / 2) - 1),
        mem(vtypes.Cat(rxd, mem[1:9])))

    fsm.If(rxd == 0).goto_next()

    for i in range(10):
        if i == 0:  # check the start bit again
            fsm.If(vtypes.Ands(waitcount == 1, rxd != 0)).goto_init()

        fsm.If(waitcount > 0)(waitcount.dec()).Else(
            mem(vtypes.Cat(rxd, mem[1:9])), waitcount(waitnum - 1))
        fsm.Then().goto_next()

    fsm(valid(1), dout(mem[0:9]))

    fsm.goto_init()

    fsm.make_always()

    return m
Beispiel #9
0
class Stream(BaseStream):
    __intrinsics__ = ('set_source', 'set_source_pattern', 'set_source_multidim',
                      'set_sink', 'set_sink_pattern', 'set_sink_multidim',
                      'set_sink_empty', 'set_constant',
                      'run', 'join', 'done')

    def __init__(self, m, name, clk, rst, datawidth=32, fsm_sel_width=16):
        BaseStream.__init__(self, module=m, clock=clk, reset=rst,
                            no_hook=True)

        self.name = name
        self.datawidth = datawidth
        self.fsm_sel_width = fsm_sel_width
        self.stream_synthesized = False
        self.fsm_synthesized = False

        self.fsm = FSM(self.module, '_%s_fsm' %
                       self.name, self.clock, self.reset)
        self.start = self.module.Reg(
            '_'.join(['', self.name, 'start']), initval=0)
        self.busy = self.module.Reg(
            '_'.join(['', self.name, 'busy']), initval=0)

        self.reduce_reset = None
        self.reduce_reset_var = None

        self.sources = OrderedDict()
        self.sinks = OrderedDict()
        self.constants = OrderedDict()
        self.substreams = []

        self.var_name_map = OrderedDict()
        self.var_id_map = OrderedDict()
        self.var_id_name_map = OrderedDict()
        self.var_name_id_map = OrderedDict()
        self.var_id_count = 0
        self.source_idle_map = OrderedDict()
        self.sink_when_map = OrderedDict()

        self.fsm_id_map = OrderedDict()
        self.fsm_id_count = 1  # '0' is reserved for idle
        self.var_id_fsm_sel_map = OrderedDict()  # key: var_id, value: fsm_id reg

        self.ram_delay = 4

    def source(self, name=None, datawidth=None, point=0, signed=True):
        if self.stream_synthesized:
            raise ValueError(
                'cannot modify the stream because already synthesized')

        _id = self.var_id_count
        if name is None:
            name = 'source_%d' % _id

        if name in self.var_name_map:
            raise ValueError("'%s' is already defined in stream '%s'" %
                             (name, self.name))

        prefix = self._prefix(name)

        self.var_id_count += 1

        if datawidth is None:
            datawidth = self.datawidth

        var = self.Variable(self._dataname(name), datawidth, point, signed)

        self.sources[name] = var
        self.var_id_map[_id] = var
        self.var_name_map[name] = var
        self.var_id_name_map[_id] = name
        self.var_name_id_map[name] = _id
        self.var_id_fsm_sel_map[_id] = self.module.Reg('_%s_fsm_sel' % prefix,
                                                       self.fsm_sel_width, initval=0)
        self.source_idle_map[name] = self.module.Reg('_%s_idle' % prefix,
                                                     initval=1)

        return var

    def sink(self, data, name=None, when=None, when_name=None):
        if self.stream_synthesized:
            raise ValueError(
                'cannot modify the stream because already synthesized')

        _id = self.var_id_count
        if name is None:
            name = 'sink_%d' % _id

        prefix = self._prefix(name)

        if name in self.var_name_map:
            raise ValueError("'%s' is already defined in stream '%s'" %
                             (name, self.name))
        else:
            data.output(self._dataname(name))

        self.var_id_count += 1

        self.sinks[name] = data
        self.var_id_map[_id] = data
        self.var_name_map[name] = data
        self.var_id_name_map[_id] = name
        self.var_name_id_map[name] = _id
        self.var_id_fsm_sel_map[_id] = self.module.Reg('_%s_fsm_sel' % prefix,
                                                       self.fsm_sel_width, initval=0)

        if when is not None:
            self.sink(when, when_name)
            self.sink_when_map[name] = when

    def constant(self, name=None, datawidth=None, point=0, signed=True):
        if self.stream_synthesized:
            raise ValueError(
                'cannot modify the stream because already synthesized')

        _id = self.var_id_count
        if name is None:
            name = 'constant_%d' % _id

        if name in self.var_name_map:
            raise ValueError("'%s' is already defined in stream '%s'" %
                             (name, self.name))

        prefix = self._prefix(name)

        self.var_id_count += 1

        if datawidth is None:
            datawidth = self.datawidth

        var = self.ParameterVariable(self._dataname(name), datawidth,
                                     point, signed)

        self.constants[name] = var
        self.var_id_map[_id] = var
        self.var_name_map[name] = var
        self.var_id_name_map[_id] = name
        self.var_name_id_map[name] = _id
        self.var_id_fsm_sel_map[_id] = self.module.Reg('_%s_fsm_sel' % prefix,
                                                       self.fsm_sel_width, initval=0)

        return var

    def substream(self, substrm):
        sub = Substream(self.module, self.clock, self.reset, substrm, self)
        self.substreams.append(sub)
        return sub

    def set_source(self, fsm, name, ram, offset, size, stride=1, port=0):
        """ intrinsic method to assign RAM property to a source stream """

        if not self.stream_synthesized:
            self._implement_stream()

        if isinstance(name, str):
            var = self.var_name_map[name]
        elif isinstance(name, vtypes.Str):
            name = name.value
            var = self.var_name_map[name]
        elif isinstance(name, int):
            var = self.var_id_map[name]
        elif isinstance(name, vtypes.Int):
            name = name.value
            var = self.var_id_map[name]
        else:
            raise TypeError('Unsupported index name')

        if name not in self.sources:
            raise NameError("No such stream '%s'" % name)

        prefix = self._prefix(name)

        fsm_id = self.fsm_id_count
        fsm_name = '_%s_fsm_%d' % (prefix, fsm_id)
        source_fsm = FSM(self.module, fsm_name, self.clock, self.reset)
        self.fsm_id_map[fsm_id] = source_fsm
        self.fsm_id_count += 1

        source_idle = self.source_idle_map[name]
        source_offset = self.module.Reg('_%s_offset_%d' % (prefix, fsm_id),
                                        ram.addrwidth, initval=0)
        source_size = self.module.Reg('_%s_size_%d' % (prefix, fsm_id),
                                      ram.addrwidth + 1, initval=0)
        source_stride = self.module.Reg('_%s_stride_%d' % (prefix, fsm_id),
                                        ram.addrwidth, initval=0)
        source_count = self.module.Reg('_%s_count_%d' % (prefix, fsm_id),
                                       ram.addrwidth + 1, initval=0)

        var_id = self.var_name_id_map[name]
        fsm_sel = self.var_id_fsm_sel_map[var_id]

        set_cond = (fsm.state == fsm.current)

        source_fsm.If(set_cond)(
            source_offset(offset),
            source_size(size),
            source_stride(stride)
        )
        self.seq.If(set_cond)(
            fsm_sel(fsm_id)
        )

        self.seq.If(self.start)(
            source_idle(0)
        )

        source_start = vtypes.Ands(
            self.start, fsm_sel == fsm_id, source_size > 0)

        source_fsm.If(source_start)(
            source_count(source_size)
        )
        source_fsm.If(source_start).goto_next()

        raddr = self.module.Reg('_%s_raddr_%d' % (prefix, fsm_id),
                                ram.addrwidth, initval=0)
        renable = self.module.Reg('_%s_renable_%d' % (prefix, fsm_id),
                                  initval=0)

        rdata, rvalid = ram.read_rtl(raddr, port=port, cond=renable)

        wdata = rdata
        wenable = rvalid
        var.write(wdata, wenable)

        source_fsm(
            raddr(source_offset),
            renable(1),
            source_count.dec()
        )
        source_fsm.Delay(1)(
            renable(0)
        )
        self.seq.If(source_fsm.state == source_fsm.current,
                    source_count == 1)(
            source_idle(1)
        )
        source_fsm.If(source_count == 1).goto_init()
        source_fsm.If(source_count > 1).goto_next()

        source_fsm(
            raddr.add(source_stride),
            renable(1),
            source_count.dec()
        )
        source_fsm.Delay(1)(
            renable(0)
        )
        source_fsm.If(source_count == 1).goto_init()

        self.seq.If(source_fsm.state == source_fsm.current,
                    source_count == 1)(
            source_idle(1)
        )

        source_fsm._set_index(0)

        fsm.goto_next()

    def set_source_pattern(self, fsm, name, ram, offset, pattern, port=0):
        """ intrinsic method to assign RAM property to a source stream """

        if not self.stream_synthesized:
            self._implement_stream()

        if isinstance(name, str):
            var = self.var_name_map[name]
        elif isinstance(name, vtypes.Str):
            name = name.value
            var = self.var_name_map[name]
        elif isinstance(name, int):
            var = self.var_id_map[name]
        elif isinstance(name, vtypes.Int):
            name = name.value
            var = self.var_id_map[name]
        else:
            raise TypeError('Unsupported index name')

        if name not in self.sources:
            raise NameError("No such stream '%s'" % name)

        if not isinstance(pattern, (tuple, list)):
            raise TypeError('pattern must be list or tuple.')

        if not pattern:
            raise ValueError(
                'pattern must have one (size, stride) pair at least.')

        if not isinstance(pattern[0], (tuple, list)):
            pattern = (pattern,)

        prefix = self._prefix(name)

        fsm_id = self.fsm_id_count
        fsm_name = '_%s_fsm_%d' % (prefix, fsm_id)
        source_fsm = FSM(self.module, fsm_name, self.clock, self.reset)
        self.fsm_id_map[fsm_id] = source_fsm
        self.fsm_id_count += 1

        source_idle = self.source_idle_map[name]
        source_offset = self.module.Reg('_%s_offset_%d' % (prefix, fsm_id),
                                        ram.addrwidth, initval=0)
        source_pat_offsets = [self.module.Reg('_%s_pat_offset_%d_%d' % (prefix, fsm_id, i),
                                              ram.addrwidth, initval=0)
                              for i, _ in enumerate(pattern)]
        source_pat_sizes = [self.module.Reg('_%s_pat_size_%d_%d' % (prefix, fsm_id, i),
                                            ram.addrwidth + 1, initval=0)
                            for i, _ in enumerate(pattern)]
        source_pat_strides = [self.module.Reg('_%s_pat_stride_%d_%d' % (prefix, fsm_id, i),
                                              ram.addrwidth, initval=0)
                              for i, _ in enumerate(pattern)]
        source_pat_counts = [self.module.Reg('_%s_pat_count_%d_%d' % (prefix, fsm_id, i),
                                             ram.addrwidth + 1, initval=0)
                             for i, _ in enumerate(pattern)]

        var_id = self.var_name_id_map[name]
        fsm_sel = self.var_id_fsm_sel_map[var_id]

        set_cond = (fsm.state == fsm.current)

        source_fsm.If(set_cond)(
            source_offset(offset)
        )
        self.seq.If(set_cond)(
            fsm_sel(fsm_id)
        )

        for source_pat_offset in source_pat_offsets:
            source_fsm.If(set_cond)(
                source_pat_offset(0)
            )

        for (source_pat_size, source_pat_stride, (size, stride)) in zip(
                source_pat_sizes, source_pat_strides, pattern):
            source_fsm.If(set_cond)(
                source_pat_size(size),
                source_pat_stride(stride)
            )

        self.seq.If(self.start)(
            source_idle(0)
        )

        source_start = vtypes.Ands(self.start, fsm_sel == fsm_id)
        for source_pat_size in source_pat_sizes:
            source_start = vtypes.Ands(source_start, source_pat_size > 0)

        for (source_pat_size, source_pat_count) in zip(
                source_pat_sizes, source_pat_counts):
            source_fsm.If(source_start)(
                source_pat_count(source_pat_size - 1)
            )

        source_fsm.If(source_start).goto_next()

        source_all_offset = self.module.Wire('_%s_all_offset_%d' % (prefix, fsm_id),
                                             ram.addrwidth)
        source_all_offset_val = source_offset
        for source_pat_offset in source_pat_offsets:
            source_all_offset_val += source_pat_offset
        source_all_offset.assign(source_all_offset_val)

        raddr = self.module.Reg('_%s_raddr_%d' % (prefix, fsm_id),
                                ram.addrwidth, initval=0)
        renable = self.module.Reg('_%s_renable_%d' % (prefix, fsm_id),
                                  initval=0)

        rdata, rvalid = ram.read_rtl(raddr, port=port, cond=renable)

        wdata = rdata
        wenable = rvalid
        var.write(wdata, wenable)

        source_fsm(
            raddr(source_all_offset),
            renable(1)
        )
        source_fsm.Delay(1)(
            renable(0)
        )

        upcond = None

        for (source_pat_offset, source_pat_size,
             source_pat_stride, source_pat_count) in zip(
                 source_pat_offsets, source_pat_sizes,
                 source_pat_strides, source_pat_counts):
            source_fsm.If(upcond)(
                source_pat_offset.add(source_pat_stride),
                source_pat_count.dec()
            )
            reset_cond = source_pat_count == 0
            source_fsm.If(upcond, reset_cond)(
                source_pat_offset(0),
                source_pat_count(source_pat_size - 1)
            )
            upcond = make_condition(upcond, reset_cond)

        fin_cond = upcond

        source_fsm.If(fin_cond).goto_init()

        self.seq.If(source_fsm.state == source_fsm.current,
                    fin_cond)(
            source_idle(1)
        )

        source_fsm._set_index(0)

        fsm.goto_next()

    def set_source_multidim(self, fsm, name, ram, offset, shape, order=None, port=0):
        """ intrinsic method to assign RAM property to a source stream """

        if order is None:
            order = list(reversed(range(len(shape))))

        pattern = self._to_pattern(shape, order)
        return self.set_source_pattern(fsm, name, ram, offset, pattern, port)

    def set_sink(self, fsm, name, ram, offset, size, stride=1, port=0):
        """ intrinsic method to assign RAM property to a sink stream """

        if not self.stream_synthesized:
            self._implement_stream()

        if isinstance(name, str):
            var = self.var_name_map[name]
        elif isinstance(name, vtypes.Str):
            name = name.value
            var = self.var_name_map[name]
        elif isinstance(name, int):
            var = self.var_id_map[name]
        elif isinstance(name, vtypes.Int):
            name = name.value
            var = self.var_id_map[name]
        else:
            raise TypeError('Unsupported index name')

        if name not in self.sinks:
            raise NameError("No such stream '%s'" % name)

        prefix = self._prefix(name)

        fsm_id = self.fsm_id_count
        fsm_name = '_%s_fsm_%d' % (prefix, fsm_id)
        sink_fsm = FSM(self.module, fsm_name, self.clock, self.reset)
        self.fsm_id_map[fsm_id] = sink_fsm
        self.fsm_id_count += 1

        sink_offset = self.module.Reg('_%s_offset_%d' % (prefix, fsm_id),
                                      ram.addrwidth, initval=0)
        sink_size = self.module.Reg('_%s_size_%d' % (prefix, fsm_id),
                                    ram.addrwidth + 1, initval=0)
        sink_stride = self.module.Reg('_%s_stride_%d' % (prefix, fsm_id),
                                      ram.addrwidth, initval=0)
        sink_count = self.module.Reg('_%s_count_%d' % (prefix, fsm_id),
                                     ram.addrwidth + 1, initval=0)

        var_id = self.var_name_id_map[name]
        fsm_sel = self.var_id_fsm_sel_map[var_id]

        set_cond = (fsm.state == fsm.current)

        sink_fsm.If(set_cond)(
            sink_offset(offset),
            sink_size(size),
            sink_stride(stride)
        )
        self.seq.If(set_cond)(
            fsm_sel(fsm_id)
        )

        sink_start = vtypes.Ands(
            self.start, fsm_sel == fsm_id, sink_size > 0)

        sink_fsm.If(sink_start)(
            sink_count(sink_size)
        )
        sink_fsm.If(sink_start).goto_next()

        num_wdelay = self._write_delay()

        for i in range(num_wdelay):
            sink_fsm.goto_next()

        waddr = self.module.Reg('_%s_waddr_%d' % (prefix, fsm_id),
                                ram.addrwidth, initval=0)
        wenable = self.module.Reg('_%s_wenable_%d' % (prefix, fsm_id),
                                  initval=0)
        wdata = self.module.Reg('_%s_wdata_%d' % (prefix, fsm_id),
                                ram.datawidth, initval=0, signed=True)
        rdata = var.read()

        ram.write_rtl(waddr, wdata, port=port, cond=wenable)

        if name in self.sink_when_map:
            when = self.sink_when_map[name]
            wcond = when.read()
        else:
            wcond = None

        sink_fsm.If(wcond)(
            waddr(sink_offset),
            wdata(rdata),
            wenable(1),
            sink_count.dec()
        )
        sink_fsm.Delay(1)(
            wenable(0)
        )
        sink_fsm.If(wcond, sink_count == 1).goto_init()
        sink_fsm.If(wcond, sink_count > 1).goto_next()

        sink_fsm.If(wcond)(
            waddr.add(sink_stride),
            wdata(rdata),
            wenable(1),
            sink_count.dec()
        )
        sink_fsm.Delay(1)(
            wenable(0)
        )
        sink_fsm.If(wcond, sink_count == 1).goto_init()

        sink_fsm._set_index(0)

        fsm.goto_next()

    def set_sink_pattern(self, fsm, name, ram, offset, pattern, port=0):
        """ intrinsic method to assign RAM property to a sink stream """

        if not self.stream_synthesized:
            self._implement_stream()

        if isinstance(name, str):
            var = self.var_name_map[name]
        elif isinstance(name, vtypes.Str):
            name = name.value
            var = self.var_name_map[name]
        elif isinstance(name, int):
            var = self.var_id_map[name]
        elif isinstance(name, vtypes.Int):
            name = name.value
            var = self.var_id_map[name]
        else:
            raise TypeError('Unsupported index name')

        if name not in self.sinks:
            raise NameError("No such stream '%s'" % name)

        if not isinstance(pattern, (tuple, list)):
            raise TypeError('pattern must be list or tuple.')

        if not pattern:
            raise ValueError(
                'pattern must have one (size, stride) pair at least.')

        if not isinstance(pattern[0], (tuple, list)):
            pattern = (pattern,)

        prefix = self._prefix(name)

        fsm_id = self.fsm_id_count
        fsm_name = '_%s_fsm_%d' % (prefix, fsm_id)
        sink_fsm = FSM(self.module, fsm_name, self.clock, self.reset)
        self.fsm_id_map[fsm_id] = sink_fsm
        self.fsm_id_count += 1

        sink_offset = self.module.Reg('_%s_offset_%d' % (prefix, fsm_id),
                                      ram.addrwidth, initval=0)
        sink_pat_offsets = [self.module.Reg('_%s_pat_offset_%d_%d' % (prefix, fsm_id, i),
                                            ram.addrwidth, initval=0)
                            for i, _ in enumerate(pattern)]
        sink_pat_sizes = [self.module.Reg('_%s_pat_size_%d_%d' % (prefix, fsm_id, i),
                                          ram.addrwidth + 1, initval=0)
                          for i, _ in enumerate(pattern)]
        sink_pat_strides = [self.module.Reg('_%s_pat_stride_%d_%d' % (prefix, fsm_id, i),
                                            ram.addrwidth, initval=0)
                            for i, _ in enumerate(pattern)]
        sink_pat_counts = [self.module.Reg('_%s_pat_count_%d_%d' % (prefix, fsm_id, i),
                                           ram.addrwidth + 1, initval=0)
                           for i, _ in enumerate(pattern)]

        var_id = self.var_name_id_map[name]
        fsm_sel = self.var_id_fsm_sel_map[var_id]

        set_cond = (fsm.state == fsm.current)

        sink_fsm.If(set_cond)(
            sink_offset(offset)
        )
        self.seq.If(set_cond)(
            fsm_sel(fsm_id)
        )

        for sink_pat_offset in sink_pat_offsets:
            sink_fsm.If(set_cond)(
                sink_pat_offset(0)
            )

        for (sink_pat_size, sink_pat_stride, (size, stride)) in zip(
                sink_pat_sizes, sink_pat_strides, pattern):
            sink_fsm.If(set_cond)(
                sink_pat_size(size),
                sink_pat_stride(stride)
            )

        sink_start = vtypes.Ands(self.start, fsm_sel == fsm_id)
        for sink_pat_size in sink_pat_sizes:
            sink_start = vtypes.Ands(sink_start, sink_pat_size > 0)

        for (sink_pat_size, sink_pat_count) in zip(
                sink_pat_sizes, sink_pat_counts):
            sink_fsm.If(sink_start)(
                sink_pat_count(sink_pat_size - 1)
            )

        sink_fsm.If(sink_start).goto_next()

        num_wdelay = self._write_delay()

        for i in range(num_wdelay):
            sink_fsm.goto_next()

        sink_all_offset = self.module.Wire('_%s_all_offset_%d' % (prefix, fsm_id),
                                           ram.addrwidth)
        sink_all_offset_val = sink_offset
        for sink_pat_offset in sink_pat_offsets:
            sink_all_offset_val += sink_pat_offset
        sink_all_offset.assign(sink_all_offset_val)

        waddr = self.module.Reg('_%s_waddr_%d' % (prefix, fsm_id),
                                ram.addrwidth, initval=0)
        wenable = self.module.Reg('_%s_wenable_%d' % (prefix, fsm_id),
                                  initval=0)
        wdata = self.module.Reg('_%s_wdata_%d' % (prefix, fsm_id),
                                ram.datawidth, initval=0, signed=True)
        rdata = var.read()

        ram.write_rtl(waddr, wdata, port=port, cond=wenable)

        if name in self.sink_when_map:
            when = self.sink_when_map[name]
            wcond = when.read()
        else:
            wcond = None

        sink_fsm.If(wcond)(
            waddr(sink_all_offset),
            wdata(rdata),
            wenable(1)
        )
        sink_fsm.Delay(1)(
            wenable(0)
        )

        upcond = None

        for (sink_pat_offset, sink_pat_size,
             sink_pat_stride, sink_pat_count) in zip(
                 sink_pat_offsets, sink_pat_sizes,
                 sink_pat_strides, sink_pat_counts):
            sink_fsm.If(upcond)(
                sink_pat_offset.add(sink_pat_stride),
                sink_pat_count.dec()
            )
            reset_cond = sink_pat_count == 0
            sink_fsm.If(upcond, reset_cond)(
                sink_pat_offset(0),
                sink_pat_count(sink_pat_size - 1)
            )
            upcond = make_condition(upcond, reset_cond)

        fin_cond = upcond

        sink_fsm.If(fin_cond).goto_init()

        sink_fsm._set_index(0)

        fsm.goto_next()

    def set_sink_multidim(self, fsm, name, ram, offset, shape, order=None, port=0):
        """ intrinsic method to assign RAM property to a sink stream """

        if order is None:
            order = list(reversed(range(len(shape))))

        pattern = self._to_pattern(shape, order)
        return self.set_sink_pattern(fsm, name, ram, offset, pattern, port)

    def set_sink_empty(self, fsm, name):
        """ intrinsic method to assign RAM property to a sink stream """

        if not self.stream_synthesized:
            self._implement_stream()

        if isinstance(name, str):
            var = self.var_name_map[name]
        elif isinstance(name, vtypes.Str):
            name = name.value
            var = self.var_name_map[name]
        elif isinstance(name, int):
            var = self.var_id_map[name]
        elif isinstance(name, vtypes.Int):
            name = name.value
            var = self.var_id_map[name]
        else:
            raise TypeError('Unsupported index name')

        if name not in self.sinks:
            raise NameError("No such stream '%s'" % name)

        prefix = self._prefix(name)

        fsm_id = self.fsm_id_count
        fsm_name = '_%s_fsm_%d' % (prefix, fsm_id)
        sink_fsm = None
        self.fsm_id_map[fsm_id] = sink_fsm
        self.fsm_id_count += 1

        var_id = self.var_name_id_map[name]
        fsm_sel = self.var_id_fsm_sel_map[var_id]

        set_cond = (fsm.state == fsm.current)

        self.seq.If(set_cond)(
            fsm_sel(fsm_id)
        )

        fsm.goto_next()

    def set_constant(self, fsm, name, value):
        """ intrinsic method to assign constant value to a constant stream """

        if not self.stream_synthesized:
            self._implement_stream()

        if isinstance(name, str):
            var = self.var_name_map[name]
        elif isinstance(name, vtypes.Str):
            name = name.value
            var = self.var_name_map[name]
        elif isinstance(name, int):
            var = self.var_id_map[name]
        elif isinstance(name, vtypes.Int):
            name = name.value
            var = self.var_id_map[name]
        else:
            raise TypeError('Unsupported index name')

        if name not in self.constants:
            raise NameError("No such stream '%s'" % name)

        set_cond = (fsm.state == fsm.current)

        wdata = value
        wenable = set_cond
        var.write(wdata, wenable)

        fsm.goto_next()

    def run(self, fsm):
        # entry point
        self.fsm._set_index(0)

        start_flag = (fsm.state == fsm.current)

        self.fsm.If(start_flag)(
            self.start(1),
            self.busy(1)
        )
        self.fsm.If(start_flag).Delay(1)(
            self.start(0)
        )

        if self.reduce_reset is not None:
            self.fsm.If(start_flag).Delay(self.ram_delay + 1)(
                self.reduce_reset(0)
            )

        substreams = self._collect_substreams()

        for sub in substreams:
            reset_delay = self.ram_delay + 1 + sub.start_stage
            if sub.substrm.reduce_reset is not None:
                self.fsm.If(start_flag).Delay(reset_delay)(
                    sub.substrm.reduce_reset(0)
                )

            for cond in sub.conds.values():
                self.fsm.If(start_flag)(
                    cond(1)
                )

        self.fsm.If(start_flag).goto_next()

        # after started
        if self.fsm_synthesized:
            fsm.goto_next()
            return

        self.fsm_synthesized = True

        self.fsm.goto_next()

        done_cond = None
        for key, source_idle in sorted(self.source_idle_map.items(),
                                       key=lambda x: x[0]):
            done_cond = make_condition(done_cond, source_idle)

        done = self.module.Wire('_%s_done' % self.name)
        done.assign(done_cond)
        self.fsm.If(done).goto_next()

        depth = self.pipeline_depth()
        num_wdelay = self._write_delay()

        # pipeline delay
        for i in range(depth):
            self.fsm.goto_next()

        self.fsm.goto_next()

        # reset accumulate pipelines
        if self.reduce_reset is not None:
            self.fsm(
                self.reduce_reset(1)
            )

        for sub in substreams:
            reset_delay = sub.start_stage
            if sub.substrm.reduce_reset is not None:
                self.fsm(
                    sub.substrm.reduce_reset(1)
                )

            for cond in sub.conds.values():
                self.fsm(
                    cond(0)
                )

        for i in range(num_wdelay - depth - 1):
            self.fsm.goto_next()

        # finish
        self.fsm(
            self.busy(0)
        )

        self.fsm.goto_init()

        fsm.goto_next()

        return 0

    def join(self, fsm):
        fsm.If(vtypes.Not(self.busy)).goto_next()
        return 0

    def done(self, fsm):
        return vtypes.Not(self.busy)

    def _implement_stream(self):
        self.implement()
        self.stream_synthesized = True

    def _write_delay(self):
        depth = self.pipeline_depth()
        return depth + self.ram_delay

    def _to_pattern(self, shape, order):
        pattern = []
        for p in order:
            if not isinstance(p, int):
                raise TypeError(
                    "Values of 'order' must be 'int', not %s" % str(type(p)))
            size = shape[p]
            basevalue = 1 if isinstance(size, int) else vtypes.Int(1)
            stride = functools.reduce(lambda x, y: x * y,
                                      shape[p + 1:], basevalue)
            pattern.append((size, stride))
        return pattern

    def _prefix(self, name):
        return '%s_%s' % (self.name, name)

    def _dataname(self, name):
        return '%s_data' % self._prefix(name)

    def _collect_substreams(self):
        ret = []

        for sub in self.substreams:
            ret.extend(sub._collect_substreams())

        return ret

    def __getattr__(self, attr):
        f = BaseStream.__getattr__(self, attr)

        if callable(f) and f.__name__.startswith('Reduce'):
            if self.reduce_reset is None:
                self.reduce_reset = self.module.Reg(
                    '_'.join(['', self.name, 'reduce_reset']), initval=1)
                self.reduce_reset_var = self.Variable(
                    self.reduce_reset, width=1)

            return functools.partial(f, reset=self.reduce_reset_var)

        return f
Beispiel #10
0
    def _synthesize_write_fsm(self):

        op_id = 1

        if op_id in self.write_ops:
            """ already synthesized op """
            return

        if self.write_fsm is not None:
            """ new op """
            self.write_ops.append(op_id)
            return

        """ new op and fsm """
        fsm = FSM(self.m, '_'.join(['', self.name, 'write_fsm']),
                  self.clk, self.rst, as_module=self.fsm_as_module)
        self.write_fsm = fsm

        self.write_ops.append(op_id)

        cur_global_addr = self.m.Reg('_'.join(['', self.name, 'write_cur_global_addr']),
                                     self.addrwidth, initval=0)
        cur_size = self.m.Reg('_'.join(['', self.name, 'write_cur_size']),
                              self.addrwidth + 1, initval=0)
        rest_size = self.m.Reg('_'.join(['', self.name, 'write_rest_size']),
                               self.addrwidth + 1, initval=0)
        max_burstlen = 2 ** self.burst_size_width

        # state 0
        if not self.use_global_base_addr:
            gaddr = self.write_global_addr
        else:
            gaddr = self.write_global_addr + self.global_base_addr

        fsm.If(self.write_start)(
            cur_global_addr(self.mask_addr(gaddr)),
            rest_size(self.write_size)
        )
        fsm.If(self.write_start).goto_next()

        # state 1
        check_state = fsm.current
        self._check_4KB_boundary(fsm, max_burstlen,
                                 cur_global_addr, cur_size, rest_size)

        # state 2
        ack, counter = self.write_request_counter(cur_global_addr, cur_size, cond=fsm)
        self.write_data_counter = counter
        fsm.If(ack).goto_next()

        # state 3
        cond = fsm.here
        data, last, _id, user, dest, done = self.in_streamout.read_dataflow(cond=cond)
        done_out = self.write_dataflow(data, counter, cond=cond)
        self.write_data_done.assign(done_out)

        fsm.If(self.write_data_done)(
            cur_global_addr.add(optimize(cur_size * (self.datawidth // 8)))
        )
        fsm.If(self.write_data_done, rest_size > 0).goto(check_state)
        fsm.If(self.write_data_done, rest_size == 0).goto_next()

        # state 4
        set_idle = self._set_flag(fsm)
        self.seq.If(set_idle)(
            self.write_idle(1)
        )

        fsm.goto_init()
Beispiel #11
0
    def _synthesize_read_fsm(self):

        op_id = 1

        if op_id in self.read_ops:
            """ already synthesized op """
            return

        if self.read_fsm is not None:
            """ new op """
            self.read_ops.append(op_id)
            return

        """ new op and fsm """
        fsm = FSM(self.m, '_'.join(['', self.name, 'read_fsm']),
                  self.clk, self.rst, as_module=self.fsm_as_module)
        self.read_fsm = fsm

        self.read_ops.append(op_id)

        cur_global_addr = self.m.Reg('_'.join(['', self.name, 'read_cur_global_addr']),
                                     self.addrwidth, initval=0)
        cur_size = self.m.Reg('_'.join(['', self.name, 'read_cur_size']),
                              self.addrwidth + 1, initval=0)
        rest_size = self.m.Reg('_'.join(['', self.name, 'read_rest_size']),
                               self.addrwidth + 1, initval=0)
        max_burstlen = 2 ** self.burst_size_width

        # state 0
        if not self.use_global_base_addr:
            gaddr = self.read_global_addr
        else:
            gaddr = self.read_global_addr + self.global_base_addr

        fsm.If(self.read_start)(
            cur_global_addr(self.mask_addr(gaddr)),
            rest_size(self.read_size)
        )
        fsm.If(self.read_start).goto_next()

        # state 1
        check_state = fsm.current
        self._check_4KB_boundary(fsm, max_burstlen,
                                 cur_global_addr, cur_size, rest_size)

        # state 2
        ack = self.read_request(cur_global_addr, cur_size, cond=fsm)
        fsm.If(ack).goto_next()

        accept = vtypes.Ands(self.raddr.arvalid, self.raddr.arready)
        fsm.If(accept)(
            cur_global_addr.add(optimize(cur_size * (self.datawidth // 8)))
        )
        fsm.If(accept, rest_size > 0).goto(check_state)
        fsm.If(accept, rest_size == 0).goto_next()

        for _ in range(self.num_data_delay):
            fsm.goto_next()

        # state 3
        set_idle = self._set_flag(fsm)
        self.seq.If(set_idle)(
            self.read_idle(1)
        )

        fsm.goto_init()
Beispiel #12
0
    def _synthesize_read_fsm_same(self, ram, port, ram_method, ram_datawidth):

        op_id = self._get_read_op_id(ram, port, ram_method)
        port = vtypes.to_int(port)

        if op_id in self.read_ops:
            """ already synthesized op """
            return

        if self.read_fsm is not None:
            """ new op """
            self.read_ops.append(op_id)

            fsm = self.read_fsm
            data = self.read_data_wire
            valid = self.read_valid_wire
            rest_size = self.read_rest_size

            # state 0
            fsm.set_index(0)
            wdata, wvalid, w = self._get_op_write_dataflow(ram_datawidth)
            cond = vtypes.Ands(self.read_start, self.read_op_sel == op_id)
            ram_method(port, self.read_local_addr, w, self.read_size,
                       stride=self.read_local_stride, cond=cond)

            fsm.If(cond).goto_next()

            # state 1
            fsm.set_index(1)
            valid_cond = vtypes.Ands(valid, self.read_op_sel == op_id)

            fsm.Delay(1)(
                wvalid(0)
            )
            fsm.If(valid_cond)(
                wdata(data),
                wvalid(1)
            )
            fsm.If(valid_cond)(
                rest_size.dec()
            )

            return

        """ new op and fsm """
        fsm = FSM(self.m, '_'.join(['', self.name, 'read_fsm']),
                  self.clk, self.rst, as_module=self.fsm_as_module)
        self.read_fsm = fsm

        self.read_ops.append(op_id)

        rest_size = self.m.Reg('_'.join(['', self.name, 'read_rest_size']),
                               self.addrwidth + 1, initval=0)
        self.read_rest_size = rest_size

        # state 0
        wdata, wvalid, w = self._get_op_write_dataflow(ram_datawidth)
        cond = vtypes.Ands(self.read_start, self.read_op_sel == op_id)
        ram_method(port, self.read_local_addr, w, self.read_size,
                   stride=self.read_local_stride, cond=cond)

        fsm.If(self.read_start)(
            rest_size(self.read_size)
        )
        fsm.If(cond).goto_next()

        # state 1
        data, last, _id, user, dest, valid = self.read_data(cond=fsm)
        self.read_data_wire = data
        self.read_valid_wire = valid

        valid_cond = vtypes.Ands(valid, self.read_op_sel == op_id)

        fsm.Delay(1)(
            wvalid(0)
        )
        fsm.If(valid_cond)(
            wdata(data),
            wvalid(1),
        )
        fsm.If(valid_cond)(
            rest_size.dec()
        )

        fsm.If(valid, rest_size <= 1).goto_next()

        for _ in range(self.num_data_delay):
            fsm.goto_next()

        # state 2
        set_idle = self._set_flag(fsm)
        self.seq.If(set_idle)(
            self.read_idle(1)
        )

        fsm.goto_init()
Beispiel #13
0
class Stream(BaseStream):
    __intrinsics__ = ('set_source', 'set_source_pattern', 'set_source_multidim',
                      'set_sink', 'set_sink_pattern', 'set_sink_multidim',
                      'set_sink_empty', 'set_constant',
                      'run', 'join', 'done')

    def __init__(self, m, name, clk, rst,
                 datawidth=32, addrwidth=32,
                 max_pattern_length=4, ram_sel_width=8,
                 fsm_as_module=False):

        BaseStream.__init__(self, module=m, clock=clk, reset=rst,
                            no_hook=True)

        self.name = name
        self.datawidth = datawidth
        self.addrwidth = addrwidth

        self.max_pattern_length = max_pattern_length
        self.ram_sel_width = ram_sel_width

        self.fsm_as_module = fsm_as_module

        self.stream_synthesized = False
        self.fsm_synthesized = False

        self.fsm = FSM(self.module, '_%s_fsm' %
                       self.name, self.clock, self.reset,
                       as_module=self.fsm_as_module)
        self.start_flag = self.module.Wire(
            '_'.join(['', self.name, 'start_flag']))
        self.start = self.module.Reg(
            '_'.join(['', self.name, 'start']), initval=0)
        self.busy = self.module.Reg(
            '_'.join(['', self.name, 'busy']), initval=0)

        self.reduce_reset = None
        self.reduce_reset_var = None

        self.sources = OrderedDict()
        self.sinks = OrderedDict()
        self.constants = OrderedDict()
        self.substreams = []

        self.var_name_map = OrderedDict()
        self.var_id_map = OrderedDict()
        self.var_id_name_map = OrderedDict()
        self.var_name_id_map = OrderedDict()
        self.var_id_count = 0

        self.source_idle_map = OrderedDict()
        self.sink_when_map = OrderedDict()

        self.ram_id_count = 1  # '0' is reserved for idle
        self.ram_id_map = OrderedDict()  # key: ran._id(), value: count

        self.fsm_id_count = 0

        self.ram_delay = 4

    def source(self, name=None, datawidth=None, point=0, signed=True):
        if self.stream_synthesized:
            raise ValueError(
                'cannot modify the stream because already synthesized')

        _id = self.var_id_count
        if name is None:
            name = 'source_%d' % _id

        if name in self.var_name_map:
            raise ValueError("'%s' is already defined in stream '%s'" %
                             (name, self.name))

        prefix = self._prefix(name)

        self.var_id_count += 1

        if datawidth is None:
            datawidth = self.datawidth

        var = self.Variable(self._dataname(name), datawidth, point, signed)

        self.sources[name] = var
        self.var_id_map[_id] = var
        self.var_name_map[name] = var
        self.var_id_name_map[_id] = name
        self.var_name_id_map[name] = _id

        var.source_fsm = None
        var.source_pat_fsm = None

        var.source_idle = self.module.Reg('_%s_idle' % prefix, initval=1)
        self.source_idle_map[name] = var.source_idle

        # 0: set_source, 1: set_source_pattern
        var.source_mode = self.module.Reg('_%s_source_mode' % prefix,
                                          initval=0)

        var.source_offset = self.module.Reg('_%s_source_offset' % prefix,
                                            self.addrwidth, initval=0)
        var.source_size = self.module.Reg('_%s_source_size' % prefix,
                                          self.addrwidth + 1, initval=0)
        var.source_stride = self.module.Reg('_%s_source_stride' % prefix,
                                            self.addrwidth, initval=0)
        var.source_count = self.module.Reg('_%s_source_count' % prefix,
                                           self.addrwidth + 1, initval=0)

        var.source_pat_offsets = None
        var.source_pat_sizes = None
        var.source_pat_strides = None
        var.source_pat_counts = None

        var.source_ram_id_map = OrderedDict()
        var.source_ram_sel = self.module.Reg('_%s_source_ram_sel' % prefix,
                                             self.ram_sel_width, initval=0)
        var.source_ram_raddr = self.module.Reg('_%s_source_ram_raddr' % prefix,
                                               self.addrwidth, initval=0)
        var.source_ram_renable = self.module.Reg('_%s_source_ram_renable' % prefix,
                                                 initval=0)
        var.source_ram_rdata = self.module.Wire('_%s_source_ram_rdata' % prefix,
                                                self.datawidth)
        var.source_ram_rvalid = self.module.Reg('_%s_source_ram_rvalid' % prefix,
                                                initval=0)

        return var

    def sink(self, data, name=None, when=None, when_name=None):
        if self.stream_synthesized:
            raise ValueError(
                'cannot modify the stream because already synthesized')

        _id = self.var_id_count
        if name is None:
            name = 'sink_%d' % _id

        if name in self.var_name_map:
            raise ValueError("'%s' is already defined in stream '%s'" %
                             (name, self.name))
        else:
            data.output(self._dataname(name))

        prefix = self._prefix(name)

        self.var_id_count += 1

        self.sinks[name] = data
        self.var_id_map[_id] = data
        self.var_name_map[name] = data
        self.var_id_name_map[_id] = name
        self.var_name_id_map[name] = _id

        data.sink_fsm = None
        data.sink_pat_fsm = None

        # 0: set_sink, 1: set_sink_pattern
        data.sink_mode = self.module.Reg('_%s_sink_mode' % prefix,
                                         initval=0)

        data.sink_offset = self.module.Reg('_%s_sink_offset' % prefix,
                                           self.addrwidth, initval=0)
        data.sink_size = self.module.Reg('_%s_sink_size' % prefix,
                                         self.addrwidth + 1, initval=0)
        data.sink_stride = self.module.Reg('_%s_sink_stride' % prefix,
                                           self.addrwidth, initval=0)
        data.sink_count = self.module.Reg('_%s_sink_count' % prefix,
                                          self.addrwidth + 1, initval=0)

        data.sink_pat_offsets = None
        data.sink_pat_sizes = None
        data.sink_pat_strides = None
        data.sink_pat_counts = None

        data.sink_ram_id_map = OrderedDict()
        data.sink_ram_sel = self.module.Reg('_%s_sink_ram_sel' % prefix,
                                            self.ram_sel_width, initval=0)
        data.sink_ram_waddr = self.module.Reg('_%s_sink_waddr' % prefix,
                                              self.addrwidth, initval=0)
        data.sink_ram_wenable = self.module.Reg('_%s_sink_wenable' % prefix,
                                                initval=0)
        data.sink_ram_wdata = self.module.Reg('_%s_sink_wdata' % prefix,
                                              self.datawidth, initval=0)

        if when is not None:
            self.sink(when, when_name)
            self.sink_when_map[name] = when

    def constant(self, name=None, datawidth=None, point=0, signed=True):
        if self.stream_synthesized:
            raise ValueError(
                'cannot modify the stream because already synthesized')

        _id = self.var_id_count
        if name is None:
            name = 'constant_%d' % _id

        if name in self.var_name_map:
            raise ValueError("'%s' is already defined in stream '%s'" %
                             (name, self.name))

        prefix = self._prefix(name)

        self.var_id_count += 1

        if datawidth is None:
            datawidth = self.datawidth

        var = self.ParameterVariable(self._dataname(name), datawidth,
                                     point, signed)

        self.constants[name] = var
        self.var_id_map[_id] = var
        self.var_name_map[name] = var
        self.var_id_name_map[_id] = name
        self.var_name_id_map[name] = _id

        return var

    def substream(self, substrm):
        sub = Substream(self.module, self.clock, self.reset, substrm, self)
        self.substreams.append(sub)
        return sub

    def set_source(self, fsm, name, ram, offset, size, stride=1, port=0):
        """ intrinsic method to assign RAM property to a source stream """

        if not self.stream_synthesized:
            self._implement_stream()

        if isinstance(name, str):
            var = self.var_name_map[name]
        elif isinstance(name, vtypes.Str):
            name = name.value
            var = self.var_name_map[name]
        elif isinstance(name, int):
            var = self.var_id_map[name]
        elif isinstance(name, vtypes.Int):
            name = name.value
            var = self.var_id_map[name]
        else:
            raise TypeError('Unsupported index name')

        if name not in self.sources:
            raise NameError("No such stream '%s'" % name)

        #set_cond = fsm.here
        set_cond = self._set_flag(fsm)

        self.seq.If(set_cond)(
            var.source_mode(0),
            var.source_offset(offset),
            var.source_size(size),
            var.source_stride(stride)
        )

        port = vtypes.to_int(port)
        self._setup_source_ram(ram, var, port, set_cond)
        self._synthesize_set_source(var, name)

        fsm.goto_next()

    def set_source_pattern(self, fsm, name, ram, offset, pattern, port=0):
        """ intrinsic method to assign RAM property to a source stream """

        if not self.stream_synthesized:
            self._implement_stream()

        if isinstance(name, str):
            var = self.var_name_map[name]
        elif isinstance(name, vtypes.Str):
            name = name.value
            var = self.var_name_map[name]
        elif isinstance(name, int):
            var = self.var_id_map[name]
        elif isinstance(name, vtypes.Int):
            name = name.value
            var = self.var_id_map[name]
        else:
            raise TypeError('Unsupported index name')

        if name not in self.sources:
            raise NameError("No such stream '%s'" % name)

        if not isinstance(pattern, (tuple, list)):
            raise TypeError('pattern must be list or tuple.')

        if not pattern:
            raise ValueError(
                'pattern must have one (size, stride) pair at least.')

        if not isinstance(pattern[0], (tuple, list)):
            pattern = (pattern,)

        pattern = tuple(pattern)

        if len(pattern) > self.max_pattern_length:
            raise ValueError(
                "'pattern' length exceeds maximum pattern length.")

        self._make_source_pattern_vars(var, name)

        #set_cond = fsm.here
        set_cond = self._set_flag(fsm)

        self.seq.If(set_cond)(
            var.source_mode(1),
            var.source_offset(offset)
        )

        pad = tuple([(1, 0)
                     for _ in range(self.max_pattern_length - len(pattern))])

        for (source_pat_size, source_pat_stride,
             (size, stride)) in zip(var.source_pat_sizes, var.source_pat_strides,
                                    pattern + pad):
            self.seq.If(set_cond)(
                source_pat_size(size),
                source_pat_stride(stride)
            )

        port = vtypes.to_int(port)
        self._setup_source_ram(ram, var, port, set_cond)
        self._synthesize_set_source_pattern(var, name)

        fsm.goto_next()

    def set_source_multidim(self, fsm, name, ram, offset, shape, order=None, port=0):
        """ intrinsic method to assign RAM property to a source stream """

        if order is None:
            order = list(reversed(range(len(shape))))

        pattern = self._to_pattern(shape, order)
        return self.set_source_pattern(fsm, name, ram, offset, pattern, port)

    def set_sink(self, fsm, name, ram, offset, size, stride=1, port=0):
        """ intrinsic method to assign RAM property to a sink stream """

        if not self.stream_synthesized:
            self._implement_stream()

        if isinstance(name, str):
            var = self.var_name_map[name]
        elif isinstance(name, vtypes.Str):
            name = name.value
            var = self.var_name_map[name]
        elif isinstance(name, int):
            var = self.var_id_map[name]
        elif isinstance(name, vtypes.Int):
            name = name.value
            var = self.var_id_map[name]
        else:
            raise TypeError('Unsupported index name')

        if name not in self.sinks:
            raise NameError("No such stream '%s'" % name)

        #set_cond = fsm.here
        set_cond = self._set_flag(fsm)

        self.seq.If(set_cond)(
            var.sink_mode(0),
            var.sink_offset(offset),
            var.sink_size(size),
            var.sink_stride(stride)
        )

        port = vtypes.to_int(port)
        self._setup_sink_ram(ram, var, port, set_cond)
        self._synthesize_set_sink(var, name)

        fsm.goto_next()

    def set_sink_pattern(self, fsm, name, ram, offset, pattern, port=0):
        """ intrinsic method to assign RAM property to a sink stream """

        if not self.stream_synthesized:
            self._implement_stream()

        if isinstance(name, str):
            var = self.var_name_map[name]
        elif isinstance(name, vtypes.Str):
            name = name.value
            var = self.var_name_map[name]
        elif isinstance(name, int):
            var = self.var_id_map[name]
        elif isinstance(name, vtypes.Int):
            name = name.value
            var = self.var_id_map[name]
        else:
            raise TypeError('Unsupported index name')

        if name not in self.sinks:
            raise NameError("No such stream '%s'" % name)

        if not isinstance(pattern, (tuple, list)):
            raise TypeError('pattern must be list or tuple.')

        if not pattern:
            raise ValueError(
                'pattern must have one (size, stride) pair at least.')

        if not isinstance(pattern[0], (tuple, list)):
            pattern = (pattern,)

        pattern = tuple(pattern)

        if len(pattern) > self.max_pattern_length:
            raise ValueError(
                "'pattern' length exceeds maximum pattern length.")

        self._make_sink_pattern_vars(var, name)

        #set_cond = fsm.here
        set_cond = self._set_flag(fsm)

        self.seq.If(set_cond)(
            var.sink_mode(1),
            var.sink_offset(offset)
        )

        pad = tuple([(1, 0)
                     for _ in range(self.max_pattern_length - len(pattern))])

        for (sink_pat_size, sink_pat_stride,
             (size, stride)) in zip(var.sink_pat_sizes, var.sink_pat_strides,
                                    pattern + pad):
            self.seq.If(set_cond)(
                sink_pat_size(size),
                sink_pat_stride(stride)
            )

        port = vtypes.to_int(port)
        self._setup_sink_ram(ram, var, port, set_cond)
        self._synthesize_set_sink_pattern(var, name)

        fsm.goto_next()

    def set_sink_multidim(self, fsm, name, ram, offset, shape, order=None, port=0):
        """ intrinsic method to assign RAM property to a sink stream """

        if order is None:
            order = list(reversed(range(len(shape))))

        pattern = self._to_pattern(shape, order)
        return self.set_sink_pattern(fsm, name, ram, offset, pattern, port)

    def set_sink_empty(self, fsm, name):
        """ intrinsic method to assign RAM property to a sink stream """

        if not self.stream_synthesized:
            self._implement_stream()

        if isinstance(name, str):
            var = self.var_name_map[name]
        elif isinstance(name, vtypes.Str):
            name = name.value
            var = self.var_name_map[name]
        elif isinstance(name, int):
            var = self.var_id_map[name]
        elif isinstance(name, vtypes.Int):
            name = name.value
            var = self.var_id_map[name]
        else:
            raise TypeError('Unsupported index name')

        if name not in self.sinks:
            raise NameError("No such stream '%s'" % name)

        #set_cond = fsm.here
        set_cond = self._set_flag(fsm)

        ram_sel = var.sink_ram_sel

        self.seq.If(set_cond)(
            ram_sel(0)  # '0' is reserved for empty
        )

        fsm.goto_next()

    def set_constant(self, fsm, name, value):
        """ intrinsic method to assign constant value to a constant stream """

        if not self.stream_synthesized:
            self._implement_stream()

        if isinstance(name, str):
            var = self.var_name_map[name]
        elif isinstance(name, vtypes.Str):
            name = name.value
            var = self.var_name_map[name]
        elif isinstance(name, int):
            var = self.var_id_map[name]
        elif isinstance(name, vtypes.Int):
            name = name.value
            var = self.var_id_map[name]
        else:
            raise TypeError('Unsupported index name')

        if name not in self.constants:
            raise NameError("No such stream '%s'" % name)

        #set_cond = fsm.here
        set_cond = self._set_flag(fsm)

        wdata = value
        wenable = set_cond
        var.write(wdata, wenable)

        fsm.goto_next()

    def run(self, fsm):
        # entry point
        self.fsm._set_index(0)

        #cond = fsm.here
        cond = self._set_flag(fsm)
        add_mux(self.start_flag, cond, 1)

        # after started
        if self.fsm_synthesized:
            fsm.goto_next()
            fsm.goto_next()
            return

        self.fsm_synthesized = True

        num_wdelay = self._write_delay()

        self.fsm.If(self.start_flag)(
            self.start(1),
            self.busy(1)
        )

        if self.reduce_reset is not None:
            self.fsm.seq.If(self.seq.Prev(self.start_flag, self.ram_delay + 1))(
                self.reduce_reset(0)
            )

        substreams = self._collect_substreams()

        for sub in substreams:
            reset_delay = self.ram_delay + 1 + sub.start_stage + sub.reset_delay
            sub_fsm = sub.substrm.fsm
            sub_fsm._set_index(0)

            if sub.substrm.reduce_reset is not None:
                sub_fsm.seq.If(self.seq.Prev(self.start_flag, reset_delay))(
                    sub.substrm.reduce_reset(0)
                )

            for cond in sub.conds.values():
                sub_fsm.If(self.start_flag)(
                    cond(1)
                )

        self.fsm.If(self.start_flag).goto_next()

        self.fsm(
            self.start(0)
        )
        self.fsm.goto_next()

        done_cond = None
        for key, source_idle in sorted(self.source_idle_map.items(),
                                       key=lambda x: x[0]):
            done_cond = make_condition(done_cond, source_idle)

        done = self.module.Wire('_%s_done' % self.name)
        done.assign(done_cond)

        self.fsm.If(done).goto_next()

        depth = self.pipeline_depth()
        for _ in range(depth):
            self.fsm.goto_next()

        self.fsm.goto_next()

        # reset accumulate pipelines
        if self.reduce_reset is not None:
            self.fsm(
                self.reduce_reset(1)
            )

        end_flag = self.fsm.here

        for sub in substreams:
            sub_fsm = sub.substrm.fsm
            sub_fsm._set_index(0)
            if sub.substrm.reduce_reset is not None:
                sub_fsm.If(end_flag)(
                    sub.substrm.reduce_reset(1)
                )

            for cond in sub.conds.values():
                sub_fsm.If(end_flag)(
                    cond(0)
                )

        self.fsm.goto_next()

        self.fsm(
            self.busy(0)
        )

        self.fsm.goto_init()

        fsm.goto_next()
        fsm.goto_next()

        return 0

    def join(self, fsm):
        fsm.If(vtypes.Not(self.busy)).goto_next()
        return 0

    def done(self, fsm):
        return vtypes.Not(self.busy)

    def _setup_source_ram(self, ram, var, port, set_cond):
        if ram._id() in var.source_ram_id_map:
            ram_id = var.source_ram_id_map[ram._id()]
            self.seq.If(set_cond)(
                var.source_ram_sel(ram_id)
            )
            return

        if ram._id() not in self.ram_id_map:
            ram_id = self.ram_id_count
            self.ram_id_count += 1
            self.ram_id_map[ram._id()] = ram_id
        else:
            ram_id = self.ram_id_map[ram._id()]

        var.source_ram_id_map[ram._id()] = ram_id

        self.seq.If(set_cond)(
            var.source_ram_sel(ram_id)
        )

        ram_cond = (var.source_ram_sel == ram_id)
        renable = vtypes.Ands(var.source_ram_renable, ram_cond)

        d, v = ram.read_rtl(var.source_ram_raddr, port=port, cond=renable)
        add_mux(var.source_ram_rdata, ram_cond, d)

        self.seq(
            var.source_ram_rvalid(self.seq.Prev(renable, 1))
        )

    def _synthesize_set_source(self, var, name):
        if var.source_fsm is not None:
            return

        wdata = var.source_ram_rdata
        wenable = var.source_ram_rvalid
        var.write(wdata, wenable)

        source_start = vtypes.Ands(self.start, var.source_mode == 0,
                                   var.source_size > 0)

        self.seq.If(source_start)(
            var.source_idle(0)
        )

        fsm_id = self.fsm_id_count
        self.fsm_id_count += 1

        prefix = self._prefix(name)

        fsm_name = '_%s_source_fsm_%d' % (prefix, fsm_id)
        var.source_fsm = FSM(self.module, fsm_name, self.clock, self.reset,
                             as_module=self.fsm_as_module)

        var.source_fsm.If(source_start).goto_next()

        self.seq.If(var.source_fsm.here)(
            var.source_ram_raddr(var.source_offset),
            var.source_ram_renable(1),
            var.source_count(var.source_size)
        )

        var.source_fsm.goto_next()

        self.seq.If(var.source_fsm.here)(
            var.source_ram_raddr.add(var.source_stride),
            var.source_ram_renable(1),
            var.source_count.dec()
        )
        self.seq.If(var.source_fsm.here, var.source_count == 1)(
            var.source_ram_renable(0),
            var.source_idle(1)
        )

        var.source_fsm.If(var.source_count == 1).goto_init()

    def _make_source_pattern_vars(self, var, name):
        if var.source_pat_offsets is not None:
            return

        prefix = self._prefix(name)

        var.source_pat_offsets = [self.module.Reg('_source_%s_pat_offset_%d' % (prefix, i),
                                                  self.addrwidth, initval=0)
                                  for i in range(self.max_pattern_length)]
        var.source_pat_sizes = [self.module.Reg('_source_%s_pat_size_%d' % (prefix, i),
                                                self.addrwidth + 1, initval=0)
                                for i in range(self.max_pattern_length)]
        var.source_pat_strides = [self.module.Reg('_source_%s_pat_stride_%d' % (prefix, i),
                                                  self.addrwidth, initval=0)
                                  for i in range(self.max_pattern_length)]
        var.source_pat_counts = [self.module.Reg('_source_%s_pat_count_%d' % (prefix, i),
                                                 self.addrwidth + 1, initval=0)
                                 for i in range(self.max_pattern_length)]

    def _synthesize_set_source_pattern(self, var, name):
        if var.source_pat_fsm is not None:
            return

        wdata = var.source_ram_rdata
        wenable = var.source_ram_rvalid
        var.write(wdata, wenable)

        source_start = vtypes.Ands(self.start, var.source_mode == 1)
        for source_pat_size in var.source_pat_sizes:
            source_start = vtypes.Ands(source_start, source_pat_size > 0)

        self.seq.If(source_start)(
            var.source_idle(0)
        )

        for source_pat_offset in var.source_pat_offsets:
            self.seq.If(source_start)(
                source_pat_offset(0)
            )

        for (source_pat_size, source_pat_count) in zip(
                var.source_pat_sizes, var.source_pat_counts):
            self.seq.If(source_start)(
                source_pat_count(source_pat_size - 1)
            )

        fsm_id = self.fsm_id_count
        self.fsm_id_count += 1

        prefix = self._prefix(name)

        fsm_name = '_%s_source_pat_fsm_%d' % (prefix, fsm_id)
        var.source_pat_fsm = FSM(self.module, fsm_name,
                                 self.clock, self.reset,
                                 as_module=self.fsm_as_module)

        var.source_pat_fsm.If(source_start).goto_next()

        source_all_offset = self.module.Wire('_%s_source_pat_all_offset' % prefix,
                                             self.addrwidth)
        source_all_offset_val = var.source_offset
        for source_pat_offset in var.source_pat_offsets:
            source_all_offset_val += source_pat_offset
        source_all_offset.assign(source_all_offset_val)

        self.seq.If(var.source_pat_fsm.here)(
            var.source_ram_raddr(source_all_offset),
            var.source_ram_renable(1)
        )

        upcond = None

        for (source_pat_offset, source_pat_size,
             source_pat_stride, source_pat_count) in zip(
                 var.source_pat_offsets, var.source_pat_sizes,
                 var.source_pat_strides, var.source_pat_counts):

            self.seq.If(var.source_pat_fsm.here, upcond)(
                source_pat_offset.add(source_pat_stride),
                source_pat_count.dec()
            )

            reset_cond = source_pat_count == 0
            self.seq.If(var.source_pat_fsm.here, upcond, reset_cond)(
                source_pat_offset(0),
                source_pat_count(source_pat_size - 1)
            )
            upcond = make_condition(upcond, reset_cond)

        fin_cond = upcond

        var.source_pat_fsm.If(fin_cond).goto_next()

        self.seq.If(var.source_pat_fsm.here)(
            var.source_ram_renable(0),
            var.source_idle(1)
        )

        var.source_pat_fsm.goto_init()

    def _setup_sink_ram(self, ram, var, port, set_cond):
        if ram._id() in var.sink_ram_id_map:
            ram_id = var.sink_ram_id_map[ram._id()]
            self.seq.If(set_cond)(
                var.sink_ram_sel(ram_id)
            )
            return

        if ram._id() not in self.ram_id_map:
            ram_id = self.ram_id_count
            self.ram_id_count += 1
            self.ram_id_map[ram._id()] = ram_id
        else:
            ram_id = self.ram_id_map[ram._id()]

        var.sink_ram_id_map[ram._id()] = ram_id

        self.seq.If(set_cond)(
            var.sink_ram_sel(ram_id)
        )

        ram_cond = (var.sink_ram_sel == ram_id)
        wenable = vtypes.Ands(var.sink_ram_wenable, ram_cond)
        ram.write_rtl(var.sink_ram_waddr, var.sink_ram_wdata,
                      port=port, cond=wenable)

    def _synthesize_set_sink(self, var, name):
        if var.sink_fsm is not None:
            return

        sink_start = vtypes.Ands(self.start, var.sink_mode == 0,
                                 var.sink_size > 0)

        fsm_id = self.fsm_id_count
        self.fsm_id_count += 1

        prefix = self._prefix(name)

        fsm_name = '_%s_sink_fsm_%d' % (prefix, fsm_id)
        var.sink_fsm = FSM(self.module, fsm_name, self.clock, self.reset,
                           as_module=self.fsm_as_module)

        self.seq.If(var.sink_fsm.here)(
            var.sink_ram_wenable(0)
        )

        var.sink_fsm.If(sink_start).goto_next()

        self.seq.If(var.sink_fsm.here)(
            var.sink_ram_waddr(var.sink_offset - var.sink_stride),
            var.sink_count(var.sink_size)
        )

        num_wdelay = self._write_delay()
        for _ in range(num_wdelay):
            var.sink_fsm.goto_next()

        if name in self.sink_when_map:
            when = self.sink_when_map[name]
            wcond = when.read()
        else:
            wcond = None

        rdata = var.read()

        self.seq.If(var.sink_fsm.here)(
            var.sink_ram_wenable(0)
        )
        self.seq.If(var.sink_fsm.here, wcond)(
            var.sink_ram_waddr.add(var.sink_stride),
            var.sink_ram_wdata(rdata),
            var.sink_ram_wenable(1),
            var.sink_count.dec()
        )

        var.sink_fsm.If(wcond, var.sink_count == 1).goto_init()

    def _make_sink_pattern_vars(self, var, name):
        if var.sink_pat_offsets is not None:
            return

        prefix = self._prefix(name)

        var.sink_pat_offsets = [self.module.Reg('_sink_%s_pat_offset_%d' % (prefix, i),
                                                self.addrwidth, initval=0)
                                for i in range(self.max_pattern_length)]
        var.sink_pat_sizes = [self.module.Reg('_sink_%s_pat_size_%d' % (prefix, i),
                                              self.addrwidth + 1, initval=0)
                              for i in range(self.max_pattern_length)]
        var.sink_pat_strides = [self.module.Reg('_sink_%s_pat_stride_%d' % (prefix, i),
                                                self.addrwidth, initval=0)
                                for i in range(self.max_pattern_length)]
        var.sink_pat_counts = [self.module.Reg('_sink_%s_pat_count_%d' % (prefix, i),
                                               self.addrwidth + 1, initval=0)
                               for i in range(self.max_pattern_length)]

    def _synthesize_set_sink_pattern(self, var, name):
        if var.sink_pat_fsm is not None:
            return

        sink_start = vtypes.Ands(self.start, var.sink_mode == 1)
        for sink_pat_size in var.sink_pat_sizes:
            sink_start = vtypes.Ands(sink_start, sink_pat_size > 0)

        fsm_id = self.fsm_id_count
        self.fsm_id_count += 1

        prefix = self._prefix(name)

        fsm_name = '_%s_sink_pat_fsm_%d' % (prefix, fsm_id)
        var.sink_pat_fsm = FSM(self.module, fsm_name,
                               self.clock, self.reset,
                               as_module=self.fsm_as_module)

        self.seq.If(var.sink_pat_fsm.here)(
            var.sink_ram_wenable(0)
        )

        var.sink_pat_fsm.If(sink_start).goto_next()

        self.seq.If(var.sink_pat_fsm.here)(
            var.sink_ram_waddr(var.sink_offset - var.sink_stride)
        )

        for sink_pat_offset in var.sink_pat_offsets:
            self.seq.If(var.sink_pat_fsm.here)(
                sink_pat_offset(0)
            )

        for (sink_pat_size, sink_pat_count) in zip(
                var.sink_pat_sizes, var.sink_pat_counts):
            self.seq.If(var.sink_pat_fsm.here)(
                sink_pat_count(sink_pat_size - 1)
            )

        num_wdelay = self._write_delay()
        for _ in range(num_wdelay):
            var.sink_pat_fsm.goto_next()

        if name in self.sink_when_map:
            when = self.sink_when_map[name]
            wcond = when.read()
        else:
            wcond = None

        sink_all_offset = self.module.Wire('_%s_sink_pat_all_offset' % prefix,
                                           self.addrwidth)
        sink_all_offset_val = var.sink_offset
        for sink_pat_offset in var.sink_pat_offsets:
            sink_all_offset_val += sink_pat_offset
        sink_all_offset.assign(sink_all_offset_val)

        if name in self.sink_when_map:
            when = self.sink_when_map[name]
            wcond = when.read()
        else:
            wcond = None

        rdata = var.read()

        self.seq.If(var.sink_pat_fsm.here)(
            var.sink_ram_wenable(0)
        )
        self.seq.If(var.sink_pat_fsm.here, wcond)(
            var.sink_ram_waddr(sink_all_offset),
            var.sink_ram_wdata(rdata),
            var.sink_ram_wenable(1)
        )

        upcond = None

        for (sink_pat_offset, sink_pat_size,
             sink_pat_stride, sink_pat_count) in zip(
                 var.sink_pat_offsets, var.sink_pat_sizes,
                 var.sink_pat_strides, var.sink_pat_counts):

            self.seq.If(var.sink_pat_fsm.here, upcond)(
                sink_pat_offset.add(sink_pat_stride),
                sink_pat_count.dec()
            )

            reset_cond = sink_pat_count == 0
            self.seq.If(var.sink_pat_fsm.here, upcond, reset_cond)(
                sink_pat_offset(0),
                sink_pat_count(sink_pat_size - 1)
            )
            upcond = make_condition(upcond, reset_cond)

        fin_cond = upcond

        var.sink_pat_fsm.If(fin_cond).goto_init()

    def _set_flag(self, fsm, prefix='_set_flag'):
        flag = self.module.TmpReg(initval=0, prefix=prefix)
        cond = fsm.here

        self.seq(
            flag(0)
        )
        self.seq.If(cond)(
            flag(1)
        )

        return flag

    def _implement_stream(self):
        self.implement()
        self.stream_synthesized = True

    def _write_delay(self):
        depth = self.pipeline_depth()
        return depth + self.ram_delay

    def _to_pattern(self, shape, order):
        pattern = []
        for p in order:
            if not isinstance(p, int):
                raise TypeError(
                    "Values of 'order' must be 'int', not %s" % str(type(p)))
            size = shape[p]
            basevalue = 1 if isinstance(size, int) else vtypes.Int(1)
            stride = functools.reduce(lambda x, y: x * y,
                                      shape[p + 1:], basevalue)
            pattern.append((size, stride))
        return tuple(pattern)

    def _prefix(self, name):
        return '%s_%s' % (self.name, name)

    def _dataname(self, name):
        return '%s_data' % self._prefix(name)

    def _collect_substreams(self):
        ret = []

        for sub in self.substreams:
            ret.extend(sub._collect_substreams())

        return ret

    def __getattr__(self, attr):
        f = BaseStream.__getattr__(self, attr)

        if callable(f) and f.__name__.startswith('Reduce'):
            if self.reduce_reset is None:
                self.reduce_reset = self.module.Reg(
                    '_'.join(['', self.name, 'reduce_reset']), initval=1)
                self.reduce_reset_var = self.Variable(
                    self.reduce_reset, width=1)

            return functools.partial(f, reset=self.reduce_reset_var)

        return f
Beispiel #14
0
    def _synthesize_read_fsm_narrow(self, ram, port, ram_method, ram_datawidth):
        """ axi.datawidth < ram.datawidth """

        if ram_datawidth % self.datawidth != 0:
            raise ValueError(
                'ram_datawidth must be multiple number of axi.datawidth')

        pack_size = ram_datawidth // self.datawidth
        dma_size = (self.read_size << int(math.log(pack_size, 2))
                    if math.log(pack_size, 2) % 1.0 == 0.0 else
                    self.read_size * pack_size)

        op_id = self._get_read_op_id(ram, port, ram_method)
        port = vtypes.to_int(port)

        if op_id in self.read_ops:
            """ already synthesized op """
            return

        if pack_size in self.read_narrow_fsms:
            """ new op """
            self.read_ops.append(op_id)

            fsm = self.read_narrow_fsms[pack_size]
            pack_count = self.read_narrow_pack_counts[pack_size]
            data = self.read_narrow_data_wires[pack_size]
            valid = self.read_narrow_valid_wires[pack_size]
            rest_size = self.read_narrow_rest_size_wires[pack_size]

            # state 0
            fsm.set_index(0)
            wdata, wvalid, w = self._get_op_write_dataflow(ram_datawidth)
            cond = vtypes.Ands(self.read_start, self.read_op_sel == op_id)
            ram_method(port, self.read_local_addr, w, self.read_size,
                       stride=self.read_local_stride, cond=cond)

            fsm.If(cond).goto_next()

            # state 1
            fsm.set_index(1)
            valid_cond = vtypes.Ands(valid, self.read_op_sel == op_id)

            fsm.Delay(1)(
                wvalid(0)
            )
            fsm.If(rest_size == 0, pack_count > 0)(
                wdata(vtypes.Cat(data, wdata[self.datawidth:ram_datawidth])),
                wvalid(0),
                pack_count.inc()
            )
            fsm.If(valid_cond)(
                wdata(vtypes.Cat(data, wdata[self.datawidth:ram_datawidth])),
                wvalid(0),
                pack_count.inc()
            )
            fsm.If(rest_size == 0, pack_count == pack_size - 1)(
                wdata(vtypes.Cat(data, wdata[self.datawidth:ram_datawidth])),
                wvalid(1),
                pack_count(0)
            )
            fsm.If(valid_cond, pack_count == pack_size - 1)(
                wdata(vtypes.Cat(data, wdata[self.datawidth:ram_datawidth])),
                wvalid(1),
                pack_count(0)
            )
            fsm.If(valid_cond)(
                rest_size.dec()
            )

            return

        """ new op and fsm """
        fsm = FSM(self.m, '_'.join(['', self.name,
                                    'read_narrow', str(pack_size),
                                    'fsm']),
                  self.clk, self.rst, as_module=self.fsm_as_module)
        self.read_narrow_fsms[pack_size] = fsm

        self.read_ops.append(op_id)

        rest_size = self.m.Reg('_'.join(['', self.name,
                                         'read_narrow', str(pack_size),
                                         'rest_size']),
                               self.addrwidth + 1, initval=0)
        self.read_narrow_rest_size_wires[pack_size] = rest_size

        # state 0
        wdata, wvalid, w = self._get_op_write_dataflow(ram_datawidth)
        cond = vtypes.Ands(self.read_start, self.read_op_sel == op_id)
        ram_method(port, self.read_local_addr, w, self.read_size,
                   stride=self.read_local_stride, cond=cond)

        fsm.If(self.read_start)(
            rest_size(dma_size)
        )
        fsm.If(cond).goto_next()

        # state 1
        pack_count = self.m.Reg('_'.join(['', self.name,
                                          'read_narrow', str(pack_size),
                                          'pack_count']),
                                int(math.ceil(math.log(pack_size, 2))), initval=0)
        self.read_narrow_pack_counts[pack_size] = pack_count

        data, last, _id, user, dest, valid = self.read_data(cond=fsm)
        self.read_narrow_data_wires[pack_size] = data
        self.read_narrow_valid_wires[pack_size] = valid

        valid_cond = vtypes.Ands(valid, self.read_op_sel == op_id)

        fsm.Delay(1)(
            wvalid(0)
        )
        fsm.If(rest_size == 0, pack_count > 0)(
            wdata(vtypes.Cat(data, wdata[self.datawidth:ram_datawidth])),
            wvalid(0),
            pack_count.inc()
        )
        fsm.If(valid_cond)(
            wdata(vtypes.Cat(data, wdata[self.datawidth:ram_datawidth])),
            wvalid(0),
            pack_count.inc()
        )
        fsm.If(rest_size == 0, pack_count == pack_size - 1)(
            wdata(vtypes.Cat(data, wdata[self.datawidth:ram_datawidth])),
            wvalid(1),
            pack_count(0)
        )
        fsm.If(valid_cond, pack_count == pack_size - 1)(
            wdata(vtypes.Cat(data, wdata[self.datawidth:ram_datawidth])),
            wvalid(1),
            pack_count(0)
        )
        fsm.If(valid_cond)(
            rest_size.dec()
        )

        fsm.If(wvalid, rest_size == 0).goto_next()

        for _ in range(self.num_data_delay):
            fsm.goto_next()

        # state 2
        set_idle = self._set_flag(fsm)
        self.seq.If(set_idle)(
            self.read_idle(1)
        )

        fsm.goto_init()
Beispiel #15
0
    def _synthesize_read_fsm_wide(self, ram, port, ram_method, ram_datawidth):
        """ axi.datawidth > ram.datawidth """

        if self.datawidth % ram_datawidth != 0:
            raise ValueError(
                'axi.datawidth must be multiple number of ram_datawidth')

        pack_size = self.datawidth // ram_datawidth
        shamt = int(math.log(pack_size, 2))
        res = vtypes.Mux(
            vtypes.And(self.read_size, 2 ** shamt - 1) > 0, 1, 0)
        dma_size = (self.read_size >> shamt) + res

        actual_read_size = dma_size << shamt

        op_id = self._get_read_op_id(ram, port, ram_method)
        port = vtypes.to_int(port)

        if op_id in self.read_ops:
            """ already synthesized op """
            return

        if pack_size in self.read_wide_fsms:
            """ new op """
            self.read_ops.append(op_id)

            fsm = self.read_wide_fsms[pack_size]
            pack_count = self.read_wide_pack_counts[pack_size]
            data = self.read_wide_data_wires[pack_size]
            valid = self.read_wide_valid_wires[pack_size]
            rest_size = self.read_wide_rest_size_wires[pack_size]

            # state 0
            fsm.set_index(0)
            wdata, wvalid, w = self._get_op_write_dataflow(ram_datawidth)
            cond = vtypes.Ands(self.read_start, self.read_op_sel == op_id)
            ram_method(port, self.read_local_addr, w, actual_read_size,
                       stride=self.read_local_stride, cond=cond)

            fsm.If(cond).goto_next()

            # state 1
            fsm.set_index(1)
            valid_cond = vtypes.Ands(valid, self.read_op_sel == op_id)
            stay_cond = self.read_op_sel == op_id

            fsm.Delay(1)(
                wvalid(0)
            )
            fsm.If(pack_count == 0, valid_cond)(
                wdata(data),
                wvalid(1),
                pack_count.inc()
            )
            fsm.If(pack_count > 0, stay_cond)(
                wdata(wdata >> ram_datawidth),
                wvalid(1),
                pack_count.inc()
            )
            fsm.If(valid_cond)(
                rest_size.dec()
            )

            return

        """ new op and fsm """
        fsm = FSM(self.m, '_'.join(['', self.name,
                                    'read_wide', str(pack_size),
                                    'fsm']),
                  self.clk, self.rst, as_module=self.fsm_as_module)
        self.read_wide_fsms[pack_size] = fsm

        self.read_ops.append(op_id)

        rest_size = self.m.Reg('_'.join(['', self.name,
                                         'read_wide', str(pack_size),
                                         'rest_size']),
                               self.addrwidth + 1, initval=0)
        self.read_wide_rest_size_wires[pack_size] = rest_size

        # state 0
        wdata, wvalid, w = self._get_op_write_dataflow(ram_datawidth)
        cond = vtypes.Ands(self.read_start, self.read_op_sel == op_id)
        ram_method(port, self.read_local_addr, w, actual_read_size,
                   stride=self.read_local_stride, cond=cond)

        fsm.If(self.read_start)(
            rest_size(dma_size)
        )
        fsm.If(cond).goto_next()

        # state 1
        pack_count = self.m.Reg('_'.join(['', self.name,
                                          'read_wide', str(pack_size),
                                          'pack_count']),
                                int(math.ceil(math.log(pack_size, 2))), initval=0)
        self.read_wide_pack_counts[pack_size] = pack_count

        cond = vtypes.Ands(fsm.here, pack_count == 0)
        data, last, _id, user, dest, valid = self.read_data(cond=cond)
        self.read_wide_data_wires[pack_size] = data
        self.read_wide_valid_wires[pack_size] = valid

        valid_cond = vtypes.Ands(valid, self.read_op_sel == op_id)
        stay_cond = self.read_op_sel == op_id

        wlast = self.m.Reg('_'.join(['', self.name,
                                     'read_wide', str(pack_size),
                                     'wlast']),
                           initval=0)

        fsm.Delay(1)(
            wvalid(0)
        )
        fsm.If(pack_count == 0, valid_cond)(
            wdata(data),
            wvalid(1),
            wlast(last),
            pack_count.inc()
        )
        fsm.If(pack_count > 0, stay_cond)(
            wdata(wdata >> ram_datawidth),
            wvalid(1),
            pack_count.inc()
        )
        fsm.If(pack_count == pack_size - 1)(
            pack_count(0)
        )

        fsm.If(pack_count == 0, valid_cond)(
            rest_size.dec()
        )

        fsm.If(pack_count == pack_size - 1, rest_size == 0).goto_next()

        for _ in range(self.num_data_delay):
            fsm.goto_next()

        # state 2
        set_idle = self._set_flag(fsm)
        self.seq.If(set_idle)(
            self.read_idle(1)
        )

        fsm.goto_init()
Beispiel #16
0
    def set_source(self, fsm, name, ram, offset, size, stride=1, port=0):
        """ intrinsic method to assign RAM property to a source stream """

        if not self.stream_synthesized:
            self._implement_stream()

        if isinstance(name, str):
            var = self.var_name_map[name]
        elif isinstance(name, vtypes.Str):
            name = name.value
            var = self.var_name_map[name]
        elif isinstance(name, int):
            var = self.var_id_map[name]
        elif isinstance(name, vtypes.Int):
            name = name.value
            var = self.var_id_map[name]
        else:
            raise TypeError('Unsupported index name')

        if name not in self.sources:
            raise NameError("No such stream '%s'" % name)

        prefix = self._prefix(name)

        fsm_id = self.fsm_id_count
        fsm_name = '_%s_fsm_%d' % (prefix, fsm_id)
        source_fsm = FSM(self.module, fsm_name, self.clock, self.reset)
        self.fsm_id_map[fsm_id] = source_fsm
        self.fsm_id_count += 1

        source_idle = self.source_idle_map[name]
        source_offset = self.module.Reg('_%s_offset_%d' % (prefix, fsm_id),
                                        ram.addrwidth, initval=0)
        source_size = self.module.Reg('_%s_size_%d' % (prefix, fsm_id),
                                      ram.addrwidth + 1, initval=0)
        source_stride = self.module.Reg('_%s_stride_%d' % (prefix, fsm_id),
                                        ram.addrwidth, initval=0)
        source_count = self.module.Reg('_%s_count_%d' % (prefix, fsm_id),
                                       ram.addrwidth + 1, initval=0)

        var_id = self.var_name_id_map[name]
        fsm_sel = self.var_id_fsm_sel_map[var_id]

        set_cond = (fsm.state == fsm.current)

        source_fsm.If(set_cond)(
            source_offset(offset),
            source_size(size),
            source_stride(stride)
        )
        self.seq.If(set_cond)(
            fsm_sel(fsm_id)
        )

        self.seq.If(self.start)(
            source_idle(0)
        )

        source_start = vtypes.Ands(
            self.start, fsm_sel == fsm_id, source_size > 0)

        source_fsm.If(source_start)(
            source_count(source_size)
        )
        source_fsm.If(source_start).goto_next()

        raddr = self.module.Reg('_%s_raddr_%d' % (prefix, fsm_id),
                                ram.addrwidth, initval=0)
        renable = self.module.Reg('_%s_renable_%d' % (prefix, fsm_id),
                                  initval=0)

        rdata, rvalid = ram.read_rtl(raddr, port=port, cond=renable)

        wdata = rdata
        wenable = rvalid
        var.write(wdata, wenable)

        source_fsm(
            raddr(source_offset),
            renable(1),
            source_count.dec()
        )
        source_fsm.Delay(1)(
            renable(0)
        )
        self.seq.If(source_fsm.state == source_fsm.current,
                    source_count == 1)(
            source_idle(1)
        )
        source_fsm.If(source_count == 1).goto_init()
        source_fsm.If(source_count > 1).goto_next()

        source_fsm(
            raddr.add(source_stride),
            renable(1),
            source_count.dec()
        )
        source_fsm.Delay(1)(
            renable(0)
        )
        source_fsm.If(source_count == 1).goto_init()

        self.seq.If(source_fsm.state == source_fsm.current,
                    source_count == 1)(
            source_idle(1)
        )

        source_fsm._set_index(0)

        fsm.goto_next()
Beispiel #17
0
    def _synthesize_read_fsm_fifo_same(self, fifo, fifo_datawidth):

        op_id = self._get_read_op_id_fifo(fifo)

        if op_id in self.read_ops:
            """ already synthesized op """
            return

        if self.read_fsm is not None:
            """ new op """
            self.read_ops.append(op_id)

            fsm = self.read_fsm
            data = self.read_data_wire
            valid = self.read_valid_wire
            rest_size = self.read_rest_size

            # state 0
            fsm.set_index(0)
            cond = vtypes.Ands(self.read_start, self.read_op_sel == op_id)

            fsm.If(cond).goto_next()

            # state 1
            fsm.set_index(1)
            valid_cond = vtypes.Ands(valid, self.read_op_sel == op_id)

            ack, _ = fifo.enq_rtl(data, cond=valid_cond)

            fsm.If(valid_cond)(
                rest_size.dec()
            )

            return

        """ new op and fsm """
        fsm = FSM(self.m, '_'.join(['', self.name, 'read_fsm']),
                  self.clk, self.rst, as_module=self.fsm_as_module)
        self.read_fsm = fsm

        self.read_ops.append(op_id)

        rest_size = self.m.Reg('_'.join(['', self.name, 'read_rest_size']),
                               self.addrwidth + 1, initval=0)
        self.read_rest_size = rest_size

        # state 0
        cond = vtypes.Ands(self.read_start, self.read_op_sel == op_id)

        fsm.If(self.read_start)(
            rest_size(self.read_size)
        )
        fsm.If(cond).goto_next()

        # state 1
        ready = vtypes.Not(fifo.almost_full)
        read_cond = vtypes.Ands(fsm.here, ready)

        data, last, _id, user, dest, valid = self.read_data(cond=read_cond)
        self.read_data_wire = data
        self.read_valid_wire = valid

        valid_cond = vtypes.Ands(valid, self.read_op_sel == op_id)

        ack, _ = fifo.enq_rtl(data, cond=valid_cond)

        fsm.If(valid_cond)(
            rest_size.dec()
        )

        fsm.If(valid, rest_size <= 1).goto_next()

        # state 2
        set_idle = self._set_flag(fsm)
        self.seq.If(set_idle)(
            self.read_idle(1)
        )

        fsm.goto_init()
Beispiel #18
0
    def _synthesize_read_fsm_fifo_narrow(self, fifo, fifo_datawidth):
        """ axi.datawidth < fifo.datawidth """

        if fifo_datawidth % self.datawidth != 0:
            raise ValueError(
                'fifo_datawidth must be multiple number of axi.datawidth')

        pack_size = fifo_datawidth // self.datawidth
        dma_size = (self.read_size << int(math.log(pack_size, 2))
                    if math.log(pack_size, 2) % 1.0 == 0.0 else
                    self.read_size * pack_size)

        op_id = self._get_read_op_id_fifo(fifo)

        if op_id in self.read_ops:
            """ already synthesized op """
            return

        if pack_size in self.read_narrow_fsms:
            """ new op """
            self.read_ops.append(op_id)

            fsm = self.read_narrow_fsms[pack_size]
            pack_count = self.read_narrow_pack_counts[pack_size]
            data = self.read_narrow_data_wires[pack_size]
            valid = self.read_narrow_valid_wires[pack_size]
            rest_size = self.read_narrow_rest_size_wires[pack_size]

            # state 0
            fsm.set_index(0)
            cond = vtypes.Ands(self.read_start, self.read_op_sel == op_id)

            fsm.If(cond).goto_next()

            # state 1
            fsm.set_index(1)

            wdata = self.m.Reg('_'.join(['', self.name,
                                         'read_narrow', str(pack_size),
                                         'wdata']),
                               fifo_datawidth, initval=0)
            wvalid = self.m.Reg('_'.join(['', self.name,
                                          'read_narrow', str(pack_size),
                                          'wvalid']))

            valid_cond = vtypes.Ands(valid, self.read_op_sel == op_id)
            ack, _ = fifo.enq_rtl(wdata, cond=wvalid)

            fsm.Delay(1)(
                wvalid(0)
            )
            fsm.If(rest_size == 0, pack_count > 0)(
                wdata(vtypes.Cat(data, wdata[self.datawidth:fifo_datawidth])),
                wvalid(0),
                pack_count.inc()
            )
            fsm.If(valid_cond)(
                wdata(vtypes.Cat(data, wdata[self.datawidth:fifo_datawidth])),
                wvalid(0),
                pack_count.inc()
            )
            fsm.If(rest_size == 0, pack_count == pack_size - 1)(
                wdata(vtypes.Cat(data, wdata[self.datawidth:fifo_datawidth])),
                wvalid(1),
                pack_count(0)
            )
            fsm.If(valid_cond, pack_count == pack_size - 1)(
                wdata(vtypes.Cat(data, wdata[self.datawidth:fifo_datawidth])),
                wvalid(1),
                pack_count(0)
            )
            fsm.If(valid_cond)(
                rest_size.dec()
            )

            return

        """ new op and fsm """
        fsm = FSM(self.m, '_'.join(['', self.name,
                                    'read_narrow', str(pack_size),
                                    'fsm']),
                  self.clk, self.rst, as_module=self.fsm_as_module)
        self.read_narrow_fsms[pack_size] = fsm

        self.read_ops.append(op_id)

        rest_size = self.m.Reg('_'.join(['', self.name,
                                         'read_narrow', str(pack_size),
                                         'rest_size']),
                               self.addrwidth + 1, initval=0)
        self.read_narrow_rest_size_wires[pack_size] = rest_size

        # state 0
        cond = vtypes.Ands(self.read_start, self.read_op_sel == op_id)

        fsm.If(self.read_start)(
            rest_size(dma_size)
        )
        fsm.If(cond).goto_next()

        # state 1
        pack_count = self.m.Reg('_'.join(['', self.name,
                                          'read_narrow', str(pack_size),
                                          'pack_count']),
                                int(math.ceil(math.log(pack_size, 2))), initval=0)
        self.read_narrow_pack_counts[pack_size] = pack_count

        ready = vtypes.Not(fifo.almost_full)
        read_cond = vtypes.Ands(fsm.here, ready)

        data, last, _id, user, dest, valid = self.read_data(cond=read_cond)
        self.read_narrow_data_wires[pack_size] = data
        self.read_narrow_valid_wires[pack_size] = valid

        wdata = self.m.Reg('_'.join(['', self.name,
                                     'read_narrow', str(pack_size),
                                     'wdata']),
                           fifo_datawidth, initval=0)
        wvalid = self.m.Reg('_'.join(['', self.name,
                                      'read_narrow', str(pack_size),
                                      'wvalid']))

        valid_cond = vtypes.Ands(valid, self.read_op_sel == op_id)
        ack, _ = fifo.enq_rtl(wdata, cond=wvalid)

        fsm.Delay(1)(
            wvalid(0)
        )
        fsm.If(rest_size == 0, pack_count > 0)(
            wdata(vtypes.Cat(data, wdata[self.datawidth:fifo_datawidth])),
            wvalid(0),
            pack_count.inc()
        )
        fsm.If(valid_cond)(
            wdata(vtypes.Cat(data, wdata[self.datawidth:fifo_datawidth])),
            wvalid(0),
            pack_count.inc()
        )
        fsm.If(rest_size == 0, pack_count == pack_size - 1)(
            wdata(vtypes.Cat(data, wdata[self.datawidth:fifo_datawidth])),
            wvalid(1),
            pack_count(0)
        )
        fsm.If(valid_cond, pack_count == pack_size - 1)(
            wdata(vtypes.Cat(data, wdata[self.datawidth:fifo_datawidth])),
            wvalid(1),
            pack_count(0)
        )
        fsm.If(valid_cond)(
            rest_size.dec()
        )

        fsm.If(wvalid, rest_size == 0).goto_next()

        # state 2
        set_idle = self._set_flag(fsm)
        self.seq.If(set_idle)(
            self.read_idle(1)
        )

        fsm.goto_init()
Beispiel #19
0
    def set_sink(self, fsm, name, ram, offset, size, stride=1, port=0):
        """ intrinsic method to assign RAM property to a sink stream """

        if not self.stream_synthesized:
            self._implement_stream()

        if isinstance(name, str):
            var = self.var_name_map[name]
        elif isinstance(name, vtypes.Str):
            name = name.value
            var = self.var_name_map[name]
        elif isinstance(name, int):
            var = self.var_id_map[name]
        elif isinstance(name, vtypes.Int):
            name = name.value
            var = self.var_id_map[name]
        else:
            raise TypeError('Unsupported index name')

        if name not in self.sinks:
            raise NameError("No such stream '%s'" % name)

        prefix = self._prefix(name)

        fsm_id = self.fsm_id_count
        fsm_name = '_%s_fsm_%d' % (prefix, fsm_id)
        sink_fsm = FSM(self.module, fsm_name, self.clock, self.reset)
        self.fsm_id_map[fsm_id] = sink_fsm
        self.fsm_id_count += 1

        sink_offset = self.module.Reg('_%s_offset_%d' % (prefix, fsm_id),
                                      ram.addrwidth, initval=0)
        sink_size = self.module.Reg('_%s_size_%d' % (prefix, fsm_id),
                                    ram.addrwidth + 1, initval=0)
        sink_stride = self.module.Reg('_%s_stride_%d' % (prefix, fsm_id),
                                      ram.addrwidth, initval=0)
        sink_count = self.module.Reg('_%s_count_%d' % (prefix, fsm_id),
                                     ram.addrwidth + 1, initval=0)

        var_id = self.var_name_id_map[name]
        fsm_sel = self.var_id_fsm_sel_map[var_id]

        set_cond = (fsm.state == fsm.current)

        sink_fsm.If(set_cond)(
            sink_offset(offset),
            sink_size(size),
            sink_stride(stride)
        )
        self.seq.If(set_cond)(
            fsm_sel(fsm_id)
        )

        sink_start = vtypes.Ands(
            self.start, fsm_sel == fsm_id, sink_size > 0)

        sink_fsm.If(sink_start)(
            sink_count(sink_size)
        )
        sink_fsm.If(sink_start).goto_next()

        num_wdelay = self._write_delay()

        for i in range(num_wdelay):
            sink_fsm.goto_next()

        waddr = self.module.Reg('_%s_waddr_%d' % (prefix, fsm_id),
                                ram.addrwidth, initval=0)
        wenable = self.module.Reg('_%s_wenable_%d' % (prefix, fsm_id),
                                  initval=0)
        wdata = self.module.Reg('_%s_wdata_%d' % (prefix, fsm_id),
                                ram.datawidth, initval=0, signed=True)
        rdata = var.read()

        ram.write_rtl(waddr, wdata, port=port, cond=wenable)

        if name in self.sink_when_map:
            when = self.sink_when_map[name]
            wcond = when.read()
        else:
            wcond = None

        sink_fsm.If(wcond)(
            waddr(sink_offset),
            wdata(rdata),
            wenable(1),
            sink_count.dec()
        )
        sink_fsm.Delay(1)(
            wenable(0)
        )
        sink_fsm.If(wcond, sink_count == 1).goto_init()
        sink_fsm.If(wcond, sink_count > 1).goto_next()

        sink_fsm.If(wcond)(
            waddr.add(sink_stride),
            wdata(rdata),
            wenable(1),
            sink_count.dec()
        )
        sink_fsm.Delay(1)(
            wenable(0)
        )
        sink_fsm.If(wcond, sink_count == 1).goto_init()

        sink_fsm._set_index(0)

        fsm.goto_next()
Beispiel #20
0
    def set_sink_pattern(self, fsm, name, ram, offset, pattern, port=0):
        """ intrinsic method to assign RAM property to a sink stream """

        if not self.stream_synthesized:
            self._implement_stream()

        if isinstance(name, str):
            var = self.var_name_map[name]
        elif isinstance(name, vtypes.Str):
            name = name.value
            var = self.var_name_map[name]
        elif isinstance(name, int):
            var = self.var_id_map[name]
        elif isinstance(name, vtypes.Int):
            name = name.value
            var = self.var_id_map[name]
        else:
            raise TypeError('Unsupported index name')

        if name not in self.sinks:
            raise NameError("No such stream '%s'" % name)

        if not isinstance(pattern, (tuple, list)):
            raise TypeError('pattern must be list or tuple.')

        if not pattern:
            raise ValueError(
                'pattern must have one (size, stride) pair at least.')

        if not isinstance(pattern[0], (tuple, list)):
            pattern = (pattern,)

        prefix = self._prefix(name)

        fsm_id = self.fsm_id_count
        fsm_name = '_%s_fsm_%d' % (prefix, fsm_id)
        sink_fsm = FSM(self.module, fsm_name, self.clock, self.reset)
        self.fsm_id_map[fsm_id] = sink_fsm
        self.fsm_id_count += 1

        sink_offset = self.module.Reg('_%s_offset_%d' % (prefix, fsm_id),
                                      ram.addrwidth, initval=0)
        sink_pat_offsets = [self.module.Reg('_%s_pat_offset_%d_%d' % (prefix, fsm_id, i),
                                            ram.addrwidth, initval=0)
                            for i, _ in enumerate(pattern)]
        sink_pat_sizes = [self.module.Reg('_%s_pat_size_%d_%d' % (prefix, fsm_id, i),
                                          ram.addrwidth + 1, initval=0)
                          for i, _ in enumerate(pattern)]
        sink_pat_strides = [self.module.Reg('_%s_pat_stride_%d_%d' % (prefix, fsm_id, i),
                                            ram.addrwidth, initval=0)
                            for i, _ in enumerate(pattern)]
        sink_pat_counts = [self.module.Reg('_%s_pat_count_%d_%d' % (prefix, fsm_id, i),
                                           ram.addrwidth + 1, initval=0)
                           for i, _ in enumerate(pattern)]

        var_id = self.var_name_id_map[name]
        fsm_sel = self.var_id_fsm_sel_map[var_id]

        set_cond = (fsm.state == fsm.current)

        sink_fsm.If(set_cond)(
            sink_offset(offset)
        )
        self.seq.If(set_cond)(
            fsm_sel(fsm_id)
        )

        for sink_pat_offset in sink_pat_offsets:
            sink_fsm.If(set_cond)(
                sink_pat_offset(0)
            )

        for (sink_pat_size, sink_pat_stride, (size, stride)) in zip(
                sink_pat_sizes, sink_pat_strides, pattern):
            sink_fsm.If(set_cond)(
                sink_pat_size(size),
                sink_pat_stride(stride)
            )

        sink_start = vtypes.Ands(self.start, fsm_sel == fsm_id)
        for sink_pat_size in sink_pat_sizes:
            sink_start = vtypes.Ands(sink_start, sink_pat_size > 0)

        for (sink_pat_size, sink_pat_count) in zip(
                sink_pat_sizes, sink_pat_counts):
            sink_fsm.If(sink_start)(
                sink_pat_count(sink_pat_size - 1)
            )

        sink_fsm.If(sink_start).goto_next()

        num_wdelay = self._write_delay()

        for i in range(num_wdelay):
            sink_fsm.goto_next()

        sink_all_offset = self.module.Wire('_%s_all_offset_%d' % (prefix, fsm_id),
                                           ram.addrwidth)
        sink_all_offset_val = sink_offset
        for sink_pat_offset in sink_pat_offsets:
            sink_all_offset_val += sink_pat_offset
        sink_all_offset.assign(sink_all_offset_val)

        waddr = self.module.Reg('_%s_waddr_%d' % (prefix, fsm_id),
                                ram.addrwidth, initval=0)
        wenable = self.module.Reg('_%s_wenable_%d' % (prefix, fsm_id),
                                  initval=0)
        wdata = self.module.Reg('_%s_wdata_%d' % (prefix, fsm_id),
                                ram.datawidth, initval=0, signed=True)
        rdata = var.read()

        ram.write_rtl(waddr, wdata, port=port, cond=wenable)

        if name in self.sink_when_map:
            when = self.sink_when_map[name]
            wcond = when.read()
        else:
            wcond = None

        sink_fsm.If(wcond)(
            waddr(sink_all_offset),
            wdata(rdata),
            wenable(1)
        )
        sink_fsm.Delay(1)(
            wenable(0)
        )

        upcond = None

        for (sink_pat_offset, sink_pat_size,
             sink_pat_stride, sink_pat_count) in zip(
                 sink_pat_offsets, sink_pat_sizes,
                 sink_pat_strides, sink_pat_counts):
            sink_fsm.If(upcond)(
                sink_pat_offset.add(sink_pat_stride),
                sink_pat_count.dec()
            )
            reset_cond = sink_pat_count == 0
            sink_fsm.If(upcond, reset_cond)(
                sink_pat_offset(0),
                sink_pat_count(sink_pat_size - 1)
            )
            upcond = make_condition(upcond, reset_cond)

        fin_cond = upcond

        sink_fsm.If(fin_cond).goto_init()

        sink_fsm._set_index(0)

        fsm.goto_next()
Beispiel #21
0
class Thread(vtypes.VeriloggenNode):
    __intrinsics__ = ('run', 'join', 'done', 'reset', 'ret')

    def __init__(self,
                 m,
                 name,
                 clk,
                 rst,
                 targ,
                 datawidth=32,
                 point=16,
                 tid=None,
                 fsm_as_module=False):

        self.m = m
        self.name = name
        self.clk = clk
        self.rst = rst
        self.targ = targ
        self.datawidth = datawidth
        self.point = point
        self.tid = tid
        self.fsm_as_module = fsm_as_module

        self.function_lib = OrderedDict()
        self.intrinsic_functions = OrderedDict()
        self.intrinsic_methods = OrderedDict()

        self.fsm = None
        self.is_child = False
        self.start_state = None
        self.end_state = None
        self.return_value = None
        self.start_frame = None
        self.args_dict = OrderedDict()
        self.vararg_regs = []
        self.vararg_set = False
        self.called = None

    def start(self, *args, **kwargs):
        """ build up a new FSM based on the arguments """

        if self.is_child:
            raise ValueError('already started as a child thread')

        if self.end_state is not None:
            raise ValueError('already started')

        frame = inspect.currentframe()
        self.start_frame = frame.f_back

        self.fsm = FSM(self.m,
                       self.name,
                       self.clk,
                       self.rst,
                       as_module=self.fsm_as_module)

        self.start_state = self.fsm.current
        self._synthesize_start_fsm(args, kwargs)
        self.end_state = self.fsm.current

        return self.fsm

    def extend(self, fsm, *args, **kwargs):
        """ extend a given thread FSM """

        frame = inspect.currentframe()
        self.start_frame = frame.f_back

        self._synthesize_start_fsm(args, kwargs, fsm)

        return fsm

    def _embed_thread(self, fsm, *args, **kwargs):
        """ extend a given thread FSM (for embed_thread func) """

        frame = inspect.currentframe()
        self.start_frame = frame.f_back.f_back

        self._synthesize_start_fsm(args, kwargs, fsm)

        return fsm

    def run(self, fsm, *args, **kwargs):
        """ start as a child thread """

        if not self.is_child and self.end_state is not None:
            raise ValueError('already started')

        if self.fsm is None:
            self.fsm = FSM(self.m,
                           self.name,
                           self.clk,
                           self.rst,
                           as_module=self.fsm_as_module)

        self.is_child = True

        if self.start_state is not None:
            self.fsm._set_index(self.start_state)
        else:
            self.start_state = self.fsm.current

        self._synthesize_run_fsm(fsm, args, kwargs)

        if self.end_state is None:
            self.end_state = self.fsm.current

        start_flag = (self.fsm.state == self.start_state)

        return start_flag

    def join(self, fsm):
        """ wait for the completion """

        if self.end_state is None:
            raise ValueError('not started')

        end_flag = (self.fsm.state == self.end_state)
        fsm.If(end_flag).goto_next()

        return 0

    def done(self, fsm):
        """ check whethe the thread is running """

        if self.end_state is None:
            raise ValueError('not started')

        end_flag = (self.fsm.state == self.end_state)

        return end_flag

    def reset(self, fsm):
        """ reset the FSM counter to the initial state """

        if self.end_state is None:
            raise ValueError('not started')

        reset_flag = (fsm.state == fsm.current)
        self.fsm._set_index(self.end_state)

        if self.called is not None:

            self.fsm.If(reset_flag)(self.called(0))

        self.fsm.goto_from(self.end_state, self.start_state, reset_flag)
        self.fsm._set_index(self.start_state)

        return 0

    def ret(self, fsm):
        """ return value """

        return self.return_value

    #--------------------------------------------------------------------------
    def add_function(self, func):
        name = func.__name__
        if name in self.function_lib:
            raise ValueError('Function {} is already defined'.format(name))
        self.function_lib[name] = func
        return func

    def add_intrinsics(self, *funcs):
        for func in funcs:
            self.intrinsic(func)

    def add_intrinsic_method_prefix(self, obj, prefix):
        funcs = [
            method
            for name, method in inspect.getmembers(obj, inspect.ismethod)
            if name.startswith(prefix)
        ]
        self.add_intrinsics(*funcs)

    def intrinsic(self, func):
        if inspect.isfunction(func):
            return self._add_intrinsic_function(func)
        if inspect.ismethod(func):
            return self._add_intrinsic_method(func)
        raise TypeError("'%s' object is not supported" % str(type(func)))

    def _add_intrinsic_function(self, func):
        name = func.__name__
        if name in self.intrinsic_functions:
            raise ValueError(
                'Intrinsic function {} is already defined'.format(name))
        self.intrinsic_functions[name] = func
        return func

    def _add_intrinsic_method(self, func):
        name = str(func)
        if name in self.intrinsic_methods:
            raise ValueError(
                'Intrinsic method {} is already defined'.format(name))
        self.intrinsic_methods[name] = func
        return func

    def _synthesize_start_fsm(self, args, kwargs, fsm=None):
        if fsm is None:
            fsm = self.fsm

        functions = self._get_functions()

        cvisitor = compiler.CompileVisitor(self.m,
                                           self.name,
                                           self.clk,
                                           self.rst,
                                           fsm,
                                           functions,
                                           self.intrinsic_functions,
                                           self.intrinsic_methods,
                                           self.start_frame,
                                           datawidth=self.datawidth,
                                           point=self.point)

        text = textwrap.dedent(inspect.getsource(self.targ))
        tree = ast.parse(text).body[0]

        # stack a new scope frame
        cvisitor.pushScope(ftype='call')

        # args -> scope variable (pass by reference)
        args_code = []
        rest_args = []
        for pos, arg in enumerate(args):
            baseobj = tree.args.args[pos]
            argname = (
                baseobj.id if isinstance(baseobj, ast.Name)  # python 2
                else baseobj.arg)  # python 3
            cvisitor.scope.addVariable(argname, arg)
            args_code.append(argname)

        # kwargs -> scope variable (pass by reference)
        kwargs_code = []
        for key, val in sorted(kwargs.items(), key=lambda x: x[0]):
            cvisitor.scope.addVariable(key, val)
            kwargs_code.append('{}={}'.format(key, key))

        # call AST
        args_text = ', '.join(args_code + kwargs_code)
        call_code = ''.join([self.targ.__name__, '(', args_text, ')'])
        _call_ast = ast.parse(call_code)

        # start visit
        self.return_value = cvisitor.visit(_call_ast.body[0].value)

        # clean-up jump conditions
        cvisitor.clearBreak()
        cvisitor.clearContinue()
        cvisitor.clearReturn()
        cvisitor.clearReturnVariable()

        # return to the previous scope frame
        cvisitor.popScope()

        return self.return_value

    def _synthesize_run_fsm(self, parent_fsm, args, kwargs, cond=None):
        start_flag = (parent_fsm.state == parent_fsm.current)

        if self.called is None:
            self.called = self.m.Reg('_'.join(['', self.name, 'called']),
                                     initval=0)

        if cond is not None:
            self.fsm.If(cond)

        self.fsm.If(start_flag)(self.called(1))

        functions = self._get_functions()

        cvisitor = compiler.CompileVisitor(self.m,
                                           self.name,
                                           self.clk,
                                           self.rst,
                                           self.fsm,
                                           functions,
                                           self.intrinsic_functions,
                                           self.intrinsic_methods,
                                           self.start_frame,
                                           datawidth=self.datawidth)

        text = textwrap.dedent(inspect.getsource(self.targ))
        tree = ast.parse(text).body[0]

        # stack a new scope frame
        cvisitor.pushScope(ftype='call')

        used_args = []

        # args
        args_code = []
        for pos, arginfo in enumerate(tree.args.args):
            argname = (
                arginfo.id if isinstance(arginfo, ast.Name)  # python 2
                else arginfo.arg)  # python 3

            # actual values can be assigned later in default value section
            args_code.append(argname)

            # regular args
            if pos < len(args):
                arg = args[pos]
                used_args.append(argname)

                if isinstance(arg, vtypes.numerical_types):  # pass by value
                    if argname not in self.args_dict:
                        name = compiler._tmp_name('_'.join(
                            ['', self.name, argname]))
                        v = self.m.Reg(name,
                                       self.datawidth,
                                       initval=0,
                                       signed=True)
                        cvisitor.scope.addVariable(argname, v)
                        self.args_dict[argname] = v
                    else:
                        v = self.args_dict[argname]

                    # binding
                    if cond is not None:
                        self.fsm.If(cond)

                    self.fsm.If(start_flag)(v(arg))

                else:  # pass by reference
                    if argname not in self.args_dict:
                        cvisitor.scope.addVariable(argname, arg)
                        self.args_dict[argname] = arg
                    elif id(self.args_dict[argname]) == id(arg):
                        pass
                    else:
                        raise ValueError(
                            'same object must be passed for non-numeric argument'
                        )

        # variable length args
        if tree.args.vararg is None and len(args) > len(tree.args.args):
            raise TypeError('takes %d positional arguments but %d were given' %
                            (len(tree.args.args), len(args)))

        if tree.args.vararg is not None and not self.vararg_set:
            baseobj = tree.args.vararg
            varargname = (
                baseobj.id if isinstance(baseobj, ast.Name)  # python 2
                else baseobj.arg)  # python 3
            cvisitor.scope.addVariable(varargname, self.vararg_regs)

        if len(args) > len(tree.args.args):
            used_args.append(varargname)
            raise ValueError(
                'variable length argument is not supported in dynamic thread execution'
            )

            #num_vararg_vars = len(args) - len(tree.args.args)
            # if num_vararg_vars > len(self.vararg_regs):
            #    for i in range(num_vararg_vars - len(self.vararg_regs)):
            #        name = compiler._tmp_name('_'.join(['', self.name, varargname]))
            #        v = self.m.Reg(name, self.datawidth, initval=0, signed=True)
            #        self.vararg_regs.append(v)
            #        args_code.append(varargname)
            # for i, arg in enumerate(args[-num_vararg_vars:]):
            #    if not isinstance(arg, vtypes.numerical_types):
            #        raise TypeError('variable length argument support no non-numeric values')
            #    v = self.vararg_regs[i]
            #    # binding
            #    if cond is not None:
            #        self.fsm.If(cond)
            #    self.fsm.If(start_flag)(
            #        v(arg)
            #    )

        # kwargs
        kwargs_code = []
        for argname, arg in sorted(kwargs.items(), key=lambda x: x[0]):
            if argname in used_args:
                raise TypeError("got multiple values for argument '%s'" %
                                argname)

            used_args.append(argname)

            if isinstance(arg, vtypes.numerical_types):  # pass by value
                if argname not in self.args_dict:
                    name = compiler._tmp_name('_'.join(
                        ['', self.name, argname]))
                    v = self.m.Reg(name,
                                   self.datawidth,
                                   initval=0,
                                   signed=True)
                    cvisitor.scope.addVariable(argname, v)
                    self.args_dict[argname] = v
                else:
                    v = self.args_dict[argname]

                # binding
                if cond is not None:
                    self.fsm.If(cond)

                self.fsm.If(start_flag)(v(arg))

            else:  # pass by reference
                if argname not in self.args_dict:
                    cvisitor.scope.addVariable(argname, arg)
                    self.args_dict[argname] = arg
                elif id(self.args_dict[argname]) == id(arg):
                    pass
                else:
                    raise ValueError(
                        'same object must be passed for non-numeric argument')

            kwargs_code.append('{}={}'.format(key, key))

        # defaults
        defaults_size = len(tree.args.defaults)
        if defaults_size > 0:
            for arg, val in zip(tree.args.args[-defaults_size:],
                                tree.args.defaults):
                argname = (
                    arg.id if isinstance(arg, ast.Name)  # python 2
                    else arg.arg)  # python 3

                if argname not in self.args_dict:
                    name = compiler._tmp_name('_'.join(
                        ['', self.name, argname]))
                    v = self.m.Reg(name,
                                   self.datawidth,
                                   initval=0,
                                   signed=True)
                    cvisitor.scope.addVariable(argname, v)
                    self.args_dict[argname] = v
                else:
                    v = self.args_dict[argname]

                if argname not in used_args:
                    right = cvisitor.visit(val)

                    # binding
                    if cond is not None:
                        self.fsm.If(cond)

                    self.fsm.If(start_flag)(v(right))

        c = start_flag
        if cond is not None:
            c = vtypes.Land(c, cond)

        self.fsm.goto_from(self.start_state, self.start_state + 1, c)
        self.fsm._set_index(self.start_state + 1)

        parent_fsm.goto_next()

        # if already synthesized
        if self.end_state is not None:
            return self.return_value

        # call AST
        args_text = ', '.join(args_code + kwargs_code)
        call_code = ''.join([self.targ.__name__, '(', args_text, ')'])
        _call_ast = ast.parse(call_code)

        # start visit
        self.return_value = cvisitor.visit(_call_ast.body[0].value)

        # clean-up jump conditions
        cvisitor.clearBreak()
        cvisitor.clearContinue()
        cvisitor.clearReturn()
        cvisitor.clearReturnVariable()

        # return to the previous scope frame
        cvisitor.popScope()

        return self.return_value

    def _get_functions(self):
        codes = []

        for func_name, func in self.function_lib.items():
            codes.append(textwrap.dedent(inspect.getsource(func)))

        if self.targ.__name__ not in self.function_lib:
            codes.append(textwrap.dedent(inspect.getsource(self.targ)))

        text = '\n'.join(codes)
        _ast = ast.parse(text)

        functionvisitor = compiler.FunctionVisitor()
        functionvisitor.visit(_ast)
        functions = functionvisitor.getFunctions()

        return functions
Beispiel #22
0
    def _synthesize_read_fsm_fifo_wide(self, fifo, fifo_datawidth):
        """ axi.datawidth > fifo.datawidth """

        if self.datawidth % fifo_datawidth != 0:
            raise ValueError(
                'axi.datawidth must be multiple number of fifo_datawidth')

        pack_size = self.datawidth // fifo_datawidth
        shamt = int(math.log(pack_size, 2))
        res = vtypes.Mux(
            vtypes.And(self.read_size, 2 ** shamt - 1) > 0, 1, 0)
        dma_size = (self.read_size >> shamt) + res

        actual_read_size = dma_size << shamt

        op_id = self._get_read_op_id_fifo(fifo)

        if op_id in self.read_ops:
            """ already synthesized op """
            return

        if pack_size in self.read_wide_fsms:
            """ new op """
            self.read_ops.append(op_id)

            fsm = self.read_wide_fsms[pack_size]
            pack_count = self.read_wide_pack_counts[pack_size]
            data = self.read_wide_data_wires[pack_size]
            valid = self.read_wide_valid_wires[pack_size]
            rest_size = self.read_wide_rest_size_wires[pack_size]

            # state 0
            fsm.set_index(0)
            cond = vtypes.Ands(self.read_start, self.read_op_sel == op_id)
            fsm.If(cond).goto_next()

            # state 1
            fsm.set_index(1)
            valid_cond = vtypes.Ands(valid, self.read_op_sel == op_id)
            stay_cond = self.read_op_sel == op_id

            fsm.Delay(1)(
                wvalid(0)
            )
            fsm.If(pack_count == 0, valid_cond)(
                wdata(data),
                wvalid(1),
                pack_count.inc()
            )
            fsm.If(pack_count > 0, stay_cond)(
                wdata(wdata >> fifo_datawidth),
                wvalid(1),
                pack_count.inc()
            )
            fsm.If(valid_cond)(
                rest_size.dec()
            )

            return

        """ new op and fsm """
        fsm = FSM(self.m, '_'.join(['', self.name,
                                    'read_wide', str(pack_size),
                                    'fsm']),
                  self.clk, self.rst, as_module=self.fsm_as_module)
        self.read_wide_fsms[pack_size] = fsm

        self.read_ops.append(op_id)

        rest_size = self.m.Reg('_'.join(['', self.name,
                                         'read_wide', str(pack_size),
                                         'rest_size']),
                               self.addrwidth + 1, initval=0)
        self.read_wide_rest_size_wires[pack_size] = rest_size

        # state 0
        cond = vtypes.Ands(self.read_start, self.read_op_sel == op_id)

        fsm.If(self.read_start)(
            rest_size(dma_size)
        )
        fsm.If(cond).goto_next()

        # state 1
        pack_count = self.m.Reg('_'.join(['', self.name,
                                          'read_wide', str(pack_size),
                                          'pack_count']),
                                int(math.ceil(math.log(pack_size, 2))), initval=0)
        self.read_wide_pack_counts[pack_size] = pack_count

        ready = vtypes.Not(fifo.almost_full)
        read_cond = vtypes.Ands(fsm.here, ready)

        cond = vtypes.Ands(fsm.here, pack_count == 0, read_cond)
        data, last, _id, user, dest, valid = self.read_data(cond=cond)
        self.read_wide_data_wires[pack_size] = data
        self.read_wide_valid_wires[pack_size] = valid

        wdata = self.m.Reg('_'.join(['', self.name,
                                     'read_wide', str(pack_size),
                                     'wdata']),
                           self.datawidth, initval=0)
        wvalid = self.m.Reg('_'.join(['', self.name,
                                      'read_wide', str(pack_size),
                                      'wvalid']))

        valid_cond = vtypes.Ands(valid, self.read_op_sel == op_id)
        stay_cond = self.read_op_sel == op_id

        ack, _ = fifo.enq_rtl(wdata, cond=wvalid)

        wlast = self.m.Reg('_'.join(['', self.name,
                                     'read_wide', str(pack_size),
                                     'wlast']),
                           initval=0)

        fsm.Delay(1)(
            wvalid(0)
        )
        fsm.If(pack_count == 0, valid_cond)(
            wdata(data),
            wvalid(1),
            wlast(last),
            pack_count.inc()
        )
        fsm.If(pack_count > 0, stay_cond)(
            wdata(wdata >> fifo_datawidth),
            wvalid(1),
            pack_count.inc()
        )
        fsm.If(pack_count == pack_size - 1)(
            pack_count(0)
        )

        fsm.If(pack_count == 0, valid_cond)(
            rest_size.dec()
        )

        fsm.If(pack_count == pack_size - 1, rest_size == 0).goto_next()

        # state 2
        set_idle = self._set_flag(fsm)
        self.seq.If(set_idle)(
            self.read_idle(1)
        )

        fsm.goto_init()