class SyncRAMManager(object): def __init__(self, m, name, clk, rst, datawidth=32, addrwidth=10, numports=1, nodataflow=False): self.m = m self.name = name self.clk = clk self.rst = rst self.datawidth = datawidth self.addrwidth = addrwidth self.interfaces = [ RAMInterface(m, name + '_%d' % i, datawidth, addrwidth) for i in range(numports) ] self.definition = mkRAMDefinition(name, datawidth, addrwidth, numports) self.inst = self.m.Instance(self.definition, 'inst_' + name, ports=m.connect_ports(self.definition)) self.seq = Seq(m, name, clk, rst) if nodataflow: self.df = None else: self.df = DataflowManager(self.m, self.clk, self.rst) self._write_disabled = [False for i in range(numports)] def __getitem__(self, index): return self.interfaces[index] def disable_write(self, port): self.seq(self.interfaces[port].wdata(0), self.interfaces[port].wenable(0)) self._write_disabled[port] = True def write(self, port, addr, wdata, cond=None): """ @return None """ if self._write_disabled[port]: raise TypeError('Write disabled.') if cond is not None: self.seq.If(cond) self.seq(self.interfaces[port].addr(addr), self.interfaces[port].wdata(wdata), self.interfaces[port].wenable(1)) self.seq.Then().Delay(1)(self.interfaces[port].wenable(0)) def write_dataflow(self, port, addr, data, length=1, cond=None, when=None): """ @return done """ if self._write_disabled[port]: raise TypeError('Write disabled.') counter = self.m.TmpReg(length.bit_length() + 1, initval=0) last = self.m.TmpReg(initval=0) ext_cond = make_condition(cond) data_cond = make_condition(counter > 0, vtypes.Not(last)) all_cond = make_condition(data_cond, ext_cond) raw_data, raw_valid = data.read(cond=data_cond) when_cond = make_condition(when, ready=data_cond) if when_cond is not None: raw_valid = vtypes.Ands(when_cond, raw_valid) self.seq.If(make_condition(ext_cond, counter == 0))( self.interfaces[port].addr(addr - 1), counter(length), ) self.seq.If(make_condition( raw_valid, counter > 0))(self.interfaces[port].addr.inc(), self.interfaces[port].wdata(raw_data), self.interfaces[port].wenable(1), counter.dec()) self.seq.If(make_condition(raw_valid, counter == 1))(last(1)) # de-assert self.seq.Delay(1)(self.interfaces[port].wenable(0), last(0)) done = last return done def read(self, port, addr, cond=None): """ @return data, valid """ if cond is not None: self.seq.If(cond) self.seq(self.interfaces[port].addr(addr)) rdata = self.interfaces[port].rdata rvalid = self.m.TmpReg(initval=0) self.seq.Then().Delay(1)(rvalid(1)) self.seq.Then().Delay(2)(rvalid(0)) return rdata, rvalid def read_dataflow(self, port, addr, length=1, cond=None): """ @return data, last, done """ data_valid = self.m.TmpReg(initval=0) last_valid = self.m.TmpReg(initval=0) data_ready = self.m.TmpWire() last_ready = self.m.TmpWire() data_ready.assign(1) last_ready.assign(1) data_ack = vtypes.Ors(data_ready, vtypes.Not(data_valid)) last_ack = vtypes.Ors(last_ready, vtypes.Not(last_valid)) ext_cond = make_condition(cond) data_cond = make_condition(data_ack, last_ack) prev_data_cond = self.seq.Prev(data_cond, 1) all_cond = make_condition(data_cond, ext_cond) data = self.m.TmpWireLike(self.interfaces[port].rdata) prev_data = self.seq.Prev(data, 1) data.assign( vtypes.Mux(prev_data_cond, self.interfaces[port].rdata, prev_data)) counter = self.m.TmpReg(length.bit_length() + 1, initval=0) next_valid_on = self.m.TmpReg(initval=0) next_valid_off = self.m.TmpReg(initval=0) next_last = self.m.TmpReg(initval=0) last = self.m.TmpReg(initval=0) self.seq.If(make_condition(data_cond, next_valid_off))(last(0), data_valid(0), last_valid(0), next_valid_off(0)) self.seq.If(make_condition(data_cond, next_valid_on))(data_valid(1), last_valid(1), last(next_last), next_last(0), next_valid_on(0), next_valid_off(1)) self.seq.If( make_condition(ext_cond, counter == 0, vtypes.Not(next_last), vtypes.Not(last)))( self.interfaces[port].addr(addr), counter(length - 1), next_valid_on(1), ) self.seq.If(make_condition(data_cond, counter > 0))( self.interfaces[port].addr.inc(), counter.dec(), next_valid_on(1), next_last(0)) self.seq.If(make_condition(data_cond, counter == 1))(next_last(1)) df = self.df if self.df is not None else dataflow df_data = df.Variable(data, data_valid, data_ready) df_last = df.Variable(last, last_valid, last_ready, width=1) done = last return df_data, df_last, done
class SyncRAMManager(object): def __init__(self, m, name, clk, rst, datawidth=32, addrwidth=10, numports=1, nodataflow=False): self.m = m self.name = name self.clk = clk self.rst = rst self.datawidth = datawidth self.addrwidth = addrwidth self.numports = numports self.interfaces = [ RAMInterface(m, name + '_%d' % i, datawidth, addrwidth) for i in range(numports) ] self.definition = mkRAMDefinition(name, datawidth, addrwidth, numports) self.inst = self.m.Instance(self.definition, 'inst_' + name, ports=m.connect_ports(self.definition)) self.seq = Seq(m, name, clk, rst) if nodataflow: self.df = None else: self.df = DataflowManager(self.m, self.clk, self.rst) self._write_disabled = [False for i in range(numports)] self._port_disabled = [False for i in range(numports)] def __getitem__(self, index): return self.interfaces[index] def disable_write(self, port): self.seq(self.interfaces[port].wdata(0), self.interfaces[port].wenable(0)) self._write_disabled[port] = True def disable_port(self, port): self.seq(self.interfaces[port].addr(0), ) self._port_disabled[port] = True def read(self, port, addr, cond=None): """ @return data, valid """ return self.read_data(port, addr, cond) def read_data(self, port, addr, cond=None): """ @return data, valid """ if cond is not None: self.seq.If(cond) self.seq(self.interfaces[port].addr(addr)) rdata = self.interfaces[port].rdata rvalid = self.m.TmpReg(initval=0) self.seq.Then().Delay(1)(rvalid(1)) self.seq.Then().Delay(2)(rvalid(0)) return rdata, rvalid def read_dataflow(self, port, addr, length=1, stride=1, cond=None, point=0, signed=False): """ @return data, last, done """ data_valid = self.m.TmpReg(initval=0) last_valid = self.m.TmpReg(initval=0) data_ready = self.m.TmpWire() last_ready = self.m.TmpWire() data_ready.assign(1) last_ready.assign(1) data_ack = vtypes.Ors(data_ready, vtypes.Not(data_valid)) last_ack = vtypes.Ors(last_ready, vtypes.Not(last_valid)) ext_cond = make_condition(cond) data_cond = make_condition(data_ack, last_ack) prev_data_cond = self.seq.Prev(data_cond, 1) data = self.m.TmpWireLike(self.interfaces[port].rdata) prev_data = self.seq.Prev(data, 1) data.assign( vtypes.Mux(prev_data_cond, self.interfaces[port].rdata, prev_data)) next_valid_on = self.m.TmpReg(initval=0) next_valid_off = self.m.TmpReg(initval=0) next_last = self.m.TmpReg(initval=0) last = self.m.TmpReg(initval=0) counter = self.m.TmpReg(length.bit_length() + 1, initval=0) self.seq.If(data_cond, next_valid_off)(last(0), data_valid(0), last_valid(0), next_valid_off(0)) self.seq.If(data_cond, next_valid_on)(data_valid(1), last_valid(1), last(next_last), next_last(0), next_valid_on(0), next_valid_off(1)) self.seq.If(ext_cond, counter == 0, vtypes.Not(next_last), vtypes.Not(last))( self.interfaces[port].addr(addr), counter(length - 1), next_valid_on(1), ) self.seq.If(data_cond, counter > 0)( self.interfaces[port].addr(self.interfaces[port].addr + stride), counter.dec(), next_valid_on(1), next_last(0)) self.seq.If(data_cond, counter == 1)(next_last(1)) df = self.df if self.df is not None else dataflow df_data = df.Variable(data, data_valid, data_ready, width=self.datawidth, point=point, signed=signed) df_last = df.Variable(last, last_valid, last_ready, width=1) done = last return df_data, df_last, done def read_dataflow_pattern(self, port, addr, pattern, cond=None, point=0, signed=False): """ @return data, last, done """ 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, ) data_valid = self.m.TmpReg(initval=0) last_valid = self.m.TmpReg(initval=0) data_ready = self.m.TmpWire() last_ready = self.m.TmpWire() data_ready.assign(1) last_ready.assign(1) data_ack = vtypes.Ors(data_ready, vtypes.Not(data_valid)) last_ack = vtypes.Ors(last_ready, vtypes.Not(last_valid)) ext_cond = make_condition(cond) data_cond = make_condition(data_ack, last_ack) prev_data_cond = self.seq.Prev(data_cond, 1) data = self.m.TmpWireLike(self.interfaces[port].rdata) prev_data = self.seq.Prev(data, 1) data.assign( vtypes.Mux(prev_data_cond, self.interfaces[port].rdata, prev_data)) next_valid_on = self.m.TmpReg(initval=0) next_valid_off = self.m.TmpReg(initval=0) next_last = self.m.TmpReg(initval=0) last = self.m.TmpReg(initval=0) running = self.m.TmpReg(initval=0) next_addr = self.m.TmpWire(self.addrwidth) offset_addr = self.m.TmpWire(self.addrwidth) offsets = [ self.m.TmpReg(self.addrwidth, initval=0) for _ in pattern[1:] ] offset_addr_value = addr for offset in offsets: offset_addr_value = offset + offset_addr_value offset_addr.assign(offset_addr_value) offsets.insert(0, None) count_list = [ self.m.TmpReg(out_size.bit_length() + 1, initval=0) for (out_size, out_stride) in pattern ] self.seq.If(data_cond, next_valid_off)(last(0), data_valid(0), last_valid(0), next_valid_off(0)) self.seq.If(data_cond, next_valid_on)(data_valid(1), last_valid(1), last(next_last), next_last(0), next_valid_on(0), next_valid_off(1)) self.seq.If(ext_cond, vtypes.Not(running), vtypes.Not(next_last), vtypes.Not(last))(self.interfaces[port].addr(addr), running(1), next_valid_on(1)) self.seq.If(data_cond, running)(self.interfaces[port].addr(next_addr), next_valid_on(1), next_last(0)) update_count = None update_offset = None update_addr = None last_one = None stride_value = None carry = None for offset, count, (out_size, out_stride) in zip(offsets, count_list, pattern): self.seq.If(ext_cond, vtypes.Not(running), vtypes.Not(next_last), vtypes.Not(last))(count(out_size - 1)) self.seq.If(data_cond, running, update_count)(count.dec()) self.seq.If(data_cond, running, update_count, count == 0)(count(out_size - 1)) if offset is not None: self.seq.If(ext_cond, vtypes.Not(running), vtypes.Not(next_last), vtypes.Not(last))(offset(0)) self.seq.If(data_cond, running, update_offset, vtypes.Not(carry))(offset(offset + out_stride)) self.seq.If(data_cond, running, update_offset, count == 0)(offset(0)) if update_count is None: update_count = count == 0 else: update_count = vtypes.Ands(update_count, count == 0) if update_offset is None: update_offset = vtypes.Mux(out_size == 1, 1, count == 1) else: update_offset = vtypes.Ands(update_offset, count == carry) if update_addr is None: update_addr = count == 0 else: update_addr = vtypes.Mux(carry, count == 0, update_addr) if last_one is None: last_one = count == 0 else: last_one = vtypes.Ands(last_one, count == 0) if stride_value is None: stride_value = out_stride else: stride_value = vtypes.Mux(carry, out_stride, stride_value) if carry is None: carry = out_size == 1 else: carry = vtypes.Ands(carry, out_size == 1) next_addr.assign( vtypes.Mux(update_addr, offset_addr, self.interfaces[port].addr + stride_value)) self.seq.If(data_cond, running, last_one)(running(0), next_last(1)) df = self.df if self.df is not None else dataflow df_data = df.Variable(data, data_valid, data_ready, width=self.datawidth, point=point, signed=signed) df_last = df.Variable(last, last_valid, last_ready, width=1) done = last return df_data, df_last, done def read_dataflow_multidim(self, port, addr, shape, order=None, cond=None, point=0, signed=False): """ @return data, last, done """ if order is None: order = list(range(len(shape))) pattern = self._to_pattern(shape, order) return self.read_dataflow_pattern(port, addr, pattern, cond=cond, point=point, signed=signed) def read_dataflow_reuse(self, port, addr, length=1, stride=1, reuse_size=1, num_outputs=1, cond=None, point=0, signed=False): """ @return data, last, done """ if not isinstance(num_outputs, int): raise TypeError('num_outputs must be int') data_valid = [self.m.TmpReg(initval=0) for _ in range(num_outputs)] last_valid = self.m.TmpReg(initval=0) data_ready = [self.m.TmpWire() for _ in range(num_outputs)] last_ready = self.m.TmpWire() for r in data_ready: r.assign(1) last_ready.assign(1) data_ack = vtypes.Ands(*[ vtypes.Ors(r, vtypes.Not(v)) for v, r in zip(data_valid, data_ready) ]) last_ack = vtypes.Ors(last_ready, vtypes.Not(last_valid)) ext_cond = make_condition(cond) data_cond = make_condition(data_ack, last_ack) counter = self.m.TmpReg(length.bit_length() + 1, initval=0) last = self.m.TmpReg(initval=0) reuse_data = [ self.m.TmpReg(self.datawidth, initval=0) for _ in range(num_outputs) ] next_reuse_data = [ self.m.TmpReg(self.datawidth, initval=0) for _ in range(num_outputs) ] reuse_count = self.m.TmpReg(reuse_size.bit_length() + 1, initval=0) fill_reuse_count = self.m.TmpReg(initval=0) fetch_done = self.m.TmpReg(initval=0) fsm = TmpFSM(self.m, self.clk, self.rst) # initial state fsm.If(ext_cond)(self.interfaces[port].addr(addr - stride), fetch_done(0), counter(length)) fsm.If(ext_cond, length > 0).goto_next() # initial prefetch state for n in next_reuse_data: fsm( self.interfaces[port].addr(self.interfaces[port].addr + stride), counter(vtypes.Mux(counter > 0, counter - 1, counter))) fsm.Delay(2)(n(self.interfaces[port].rdata)) fsm.goto_next() fsm.goto_next() fsm.goto_next() # initial update state for n, r in zip(next_reuse_data, reuse_data): fsm(r(n)) fsm(fill_reuse_count(1), fetch_done(counter == 0)) fsm.Delay(1)(fill_reuse_count(0)) fsm.goto_next() # prefetch state read_start_state = fsm.current for n in next_reuse_data: fsm( self.interfaces[port].addr(self.interfaces[port].addr + stride), counter(vtypes.Mux(counter > 0, counter - 1, counter))) fsm.Delay(2)(n(self.interfaces[port].rdata)) fsm.goto_next() fsm.goto_next() fsm.goto_next() # update state for n, r in zip(next_reuse_data, reuse_data): fsm.If(data_cond, reuse_count == 0)(r(n)) fsm.If(data_cond, reuse_count == 0)(fill_reuse_count(vtypes.Not(fetch_done)), fetch_done(counter == 0)) fsm.Delay(1)(fill_reuse_count(0)) # next -> prefetch state or initial state fsm.If(data_cond, reuse_count == 0, counter == 0).goto_init() fsm.If(data_cond, reuse_count == 0, counter > 0).goto(read_start_state) # output signal control self.seq.If(data_cond, last_valid)(last(0), [d(0) for d in data_valid], last_valid(0)) self.seq.If(fill_reuse_count)(reuse_count(reuse_size)) self.seq.If(data_cond, reuse_count > 0)(reuse_count.dec(), [d(1) for d in data_valid], last_valid(1), last(0)) self.seq.If(data_cond, reuse_count == 1, fetch_done)(last(1)) df = self.df if self.df is not None else dataflow df_last = df.Variable(last, last_valid, last_ready, width=1) done = last df_reuse_data = [ df.Variable(d, v, r, width=self.datawidth, point=point, signed=signed) for d, v, r in zip(reuse_data, data_valid, data_ready) ] return tuple(df_reuse_data + [df_last, done]) def read_dataflow_reuse_pattern(self, port, addr, pattern, reuse_size=1, num_outputs=1, cond=None, point=0, signed=False): """ @return data, last, done """ 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, ) if not isinstance(num_outputs, int): raise TypeError('num_outputs must be int') data_valid = [self.m.TmpReg(initval=0) for _ in range(num_outputs)] last_valid = self.m.TmpReg(initval=0) data_ready = [self.m.TmpWire() for _ in range(num_outputs)] last_ready = self.m.TmpWire() for r in data_ready: r.assign(1) last_ready.assign(1) data_ack = vtypes.Ands(*[ vtypes.Ors(r, vtypes.Not(v)) for v, r in zip(data_valid, data_ready) ]) last_ack = vtypes.Ors(last_ready, vtypes.Not(last_valid)) ext_cond = make_condition(cond) data_cond = make_condition(data_ack, last_ack) next_addr = self.m.TmpWire(self.addrwidth) offset_addr = self.m.TmpWire(self.addrwidth) offsets = [ self.m.TmpReg(self.addrwidth, initval=0) for _ in pattern[1:] ] offset_addr_value = addr for offset in offsets: offset_addr_value = offset + offset_addr_value offset_addr.assign(offset_addr_value) offsets.insert(0, None) count_list = [ self.m.TmpReg(out_size.bit_length() + 1, initval=0) for (out_size, out_stride) in pattern ] last = self.m.TmpReg(initval=0) reuse_data = [ self.m.TmpReg(self.datawidth, initval=0) for _ in range(num_outputs) ] next_reuse_data = [ self.m.TmpReg(self.datawidth, initval=0) for _ in range(num_outputs) ] reuse_count = self.m.TmpReg(reuse_size.bit_length() + 1, initval=0) fill_reuse_count = self.m.TmpReg(initval=0) prefetch_done = self.m.TmpReg(initval=0) fetch_done = self.m.TmpReg(initval=0) update_addr = None stride_value = None carry = None for offset, count, (out_size, out_stride) in zip(offsets, count_list, pattern): if update_addr is None: update_addr = count == 0 else: update_addr = vtypes.Mux(carry, count == 0, update_addr) if stride_value is None: stride_value = out_stride else: stride_value = vtypes.Mux(carry, out_stride, stride_value) if carry is None: carry = out_size == 1 else: carry = vtypes.Ands(carry, out_size == 1) next_addr.assign( vtypes.Mux(update_addr, offset_addr, self.interfaces[port].addr + stride_value)) fsm = TmpFSM(self.m, self.clk, self.rst) # initial state fsm.If(ext_cond)(self.interfaces[port].addr(addr - stride_value), prefetch_done(0), fetch_done(0)) first = True for offset, count, (out_size, out_stride) in zip(offsets, count_list, pattern): fsm.If(ext_cond)(count(out_size) if first else count(out_size - 1), ) if offset is not None: fsm.If(ext_cond)(offset(0)) first = False fsm.If(ext_cond).goto_next() # initial prefetch state for n in next_reuse_data: update_count = None update_offset = None last_one = None carry = None for offset, count, (out_size, out_stride) in zip(offsets, count_list, pattern): fsm.If(update_count)(count.dec()) fsm.If(update_count, count == 0)(count(out_size - 1)) fsm(self.interfaces[port].addr(next_addr)) fsm.Delay(2)(n(self.interfaces[port].rdata)) if offset is not None: fsm.If(update_offset, vtypes.Not(carry))(offset(offset + out_stride)) fsm.If(update_offset, count == 0)(offset(0)) if update_count is None: update_count = count == 0 else: update_count = vtypes.Ands(update_count, count == 0) if update_offset is None: update_offset = vtypes.Mux(out_size == 1, 1, count == 1) else: update_offset = vtypes.Ands(update_offset, count == carry) if last_one is None: last_one = count == 0 else: last_one = vtypes.Ands(last_one, count == 0) if carry is None: carry = out_size == 1 else: carry = vtypes.Ands(carry, out_size == 1) fsm.goto_next() fsm.If(last_one)(prefetch_done(1)) fsm.goto_next() fsm.goto_next() # initial update state for r, n in zip(reuse_data, next_reuse_data): fsm(r(n)) fsm(fetch_done(prefetch_done), fill_reuse_count(vtypes.Not(fetch_done))) fsm.Delay(1)(fill_reuse_count(0)) fsm.goto_next() # prefetch state read_start_state = fsm.current for n in next_reuse_data: update_count = None update_offset = None last_one = None carry = None for offset, count, (out_size, out_stride) in zip(offsets, count_list, pattern): fsm.If(update_count)(count.dec()) fsm.If(update_count, count == 0)(count(out_size - 1)) fsm(self.interfaces[port].addr(next_addr)) fsm.Delay(2)(n(self.interfaces[port].rdata)) if offset is not None: fsm.If(update_offset, vtypes.Not(carry))(offset(offset + out_stride)) fsm.If(update_offset, count == 0)(offset(0)) if update_count is None: update_count = count == 0 else: update_count = vtypes.Ands(update_count, count == 0) if update_offset is None: update_offset = vtypes.Mux(out_size == 1, 1, count == 1) else: update_offset = vtypes.Ands(update_offset, count == carry) if last_one is None: last_one = count == 0 else: last_one = vtypes.Ands(last_one, count == 0) if carry is None: carry = out_size == 1 else: carry = vtypes.Ands(carry, out_size == 1) fsm.goto_next() fsm.If(last_one)(prefetch_done(1)) fsm.goto_next() fsm.goto_next() # update state for r, n in zip(reuse_data, next_reuse_data): fsm.If(data_cond, reuse_count == 0)(r(n)) fsm.If(data_cond, reuse_count == 0)(fetch_done(prefetch_done), fill_reuse_count(vtypes.Not(fetch_done))) fsm.Delay(1)(fill_reuse_count(0)) # next -> prefetch state or initial state fsm.If(data_cond, reuse_count == 0, fetch_done).goto_init() fsm.If(data_cond, reuse_count == 0, vtypes.Not(fetch_done)).goto(read_start_state) # output signal control self.seq.If(data_cond, last_valid)(last(0), [d(0) for d in data_valid], last_valid(0)) self.seq.If(fill_reuse_count)(reuse_count(reuse_size)) self.seq.If(data_cond, reuse_count > 0)(reuse_count.dec(), [d(1) for d in data_valid], last_valid(1), last(0)) self.seq.If(data_cond, reuse_count == 1, fetch_done)(last(1)) df = self.df if self.df is not None else dataflow df_last = df.Variable(last, last_valid, last_ready, width=1) done = last df_reuse_data = [ df.Variable(d, v, r, width=self.datawidth, point=point, signed=signed) for d, v, r in zip(reuse_data, data_valid, data_ready) ] return tuple(df_reuse_data + [df_last, done]) def read_dataflow_reuse_multidim(self, port, addr, shape, order=None, reuse_size=1, num_outputs=1, cond=None, point=0, signed=False): """ @return data, last, done """ if order is None: order = list(range(len(shape))) pattern = self._to_pattern(shape, order) return self.read_dataflow_pattern(port, addr, pattern, reuse_size, num_outputs, cond=cond, point=point, signed=signed) def write(self, port, addr, wdata, cond=None): """ @return None """ return self.write_data(port, addr, wdata, cond) def write_data(self, port, addr, wdata, cond=None): """ @return None """ if self._write_disabled[port]: raise TypeError('Write disabled.') if cond is not None: self.seq.If(cond) self.seq(self.interfaces[port].addr(addr), self.interfaces[port].wdata(wdata), self.interfaces[port].wenable(1)) self.seq.Then().Delay(1)(self.interfaces[port].wenable(0)) def write_dataflow(self, port, addr, data, length=1, stride=1, cond=None, when=None): """ @return done 'data' and 'when' must be dataflow variables """ if self._write_disabled[port]: raise TypeError('Write disabled.') counter = self.m.TmpReg(length.bit_length() + 1, initval=0) last = self.m.TmpReg(initval=0) ext_cond = make_condition(cond) data_cond = make_condition(counter > 0, vtypes.Not(last)) if when is None or not isinstance(when, df_numeric): raw_data, raw_valid = data.read(cond=data_cond) else: data_list, raw_valid = read_multi(self.m, data, when, cond=data_cond) raw_data = data_list[0] when = data_list[1] when_cond = make_condition(when, ready=data_cond) if when_cond is not None: raw_valid = vtypes.Ands(when_cond, raw_valid) self.seq.If(ext_cond, counter == 0)( self.interfaces[port].addr(addr - stride), counter(length), ) self.seq.If(raw_valid, counter > 0)( self.interfaces[port].addr(self.interfaces[port].addr + stride), self.interfaces[port].wdata(raw_data), self.interfaces[port].wenable(1), counter.dec()) self.seq.If(raw_valid, counter == 1)(last(1)) # de-assert self.seq.Delay(1)(self.interfaces[port].wenable(0), last(0)) done = last return done def write_dataflow_pattern(self, port, addr, data, pattern, cond=None, when=None): """ @return done 'data' and 'when' must be dataflow variables """ if self._write_disabled[port]: raise TypeError('Write disabled.') 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, ) last = self.m.TmpReg(initval=0) running = self.m.TmpReg(initval=0) ext_cond = make_condition(cond) data_cond = make_condition(running, vtypes.Not(last)) if when is None or not isinstance(when, df_numeric): raw_data, raw_valid = data.read(cond=data_cond) else: data_list, raw_valid = read_multi(self.m, data, when, cond=data_cond) raw_data = data_list[0] when = data_list[1] when_cond = make_condition(when, ready=data_cond) if when_cond is not None: raw_valid = vtypes.Ands(when_cond, raw_valid) offset_addr = self.m.TmpWire(self.addrwidth) offsets = [self.m.TmpReg(self.addrwidth, initval=0) for _ in pattern] offset_addr_value = addr for offset in offsets: offset_addr_value = offset + offset_addr_value offset_addr.assign(offset_addr_value) count_list = [ self.m.TmpReg(out_size.bit_length() + 1, initval=0) for (out_size, out_stride) in pattern ] self.seq.If(ext_cond, vtypes.Not(running))(running(1)) self.seq.If(raw_valid, running)(self.interfaces[port].addr(offset_addr), self.interfaces[port].wdata(raw_data), self.interfaces[port].wenable(1)) update_count = None last_one = None for offset, count, (out_size, out_stride) in zip(offsets, count_list, pattern): self.seq.If(ext_cond, vtypes.Not(running))(count(out_size - 1), offset(0)) self.seq.If(raw_valid, running, update_count)(count.dec(), offset(offset + out_stride)) self.seq.If(raw_valid, running, update_count, count == 0)(count(out_size - 1), offset(0)) if update_count is None: update_count = count == 0 else: update_count = vtypes.Ands(update_count, count == 0) if last_one is None: last_one = count == 0 else: last_one = vtypes.Ands(last_one, count == 0) self.seq.If(raw_valid, last_one)(running(0), last(1)) # de-assert self.seq.Delay(1)(self.interfaces[port].wenable(0), last(0)) done = last return done def write_dataflow_multidim(self, port, addr, data, shape, order=None, cond=None, when=None): """ @return done 'data' and 'when' must be dataflow variables """ if order is None: order = list(range(len(shape))) pattern = self._to_pattern(shape, order) return self.write_dataflow_pattern(port, addr, data, pattern, cond=cond, when=when) 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], basevalue) if p > 0 else basevalue pattern.append((size, stride)) return pattern
class FSM(vtypes.VeriloggenNode): """ Finite State Machine Generator """ def __init__(self, m, name, clk, rst, width=32, initname='init', nohook=False, as_module=False): self.m = m self.name = name self.clk = clk self.rst = rst self.width = width self.state_count = 0 self.state = self.m.Reg(name, width) # set initval later self.mark = collections.OrderedDict() # key:index self._set_mark(0, self.name + '_' + initname) self.state.initval = self._get_mark(0) self.body = collections.defaultdict(list) self.jump = collections.defaultdict(list) self.delay_amount = 0 self.delayed_state = collections.OrderedDict() # key:delay self.delayed_body = collections.defaultdict( functools.partial(collections.defaultdict, list)) # key:delay self.delayed_cond = collections.OrderedDict() # key:name self.tmp_count = 0 self.dst_var = collections.OrderedDict() self.dst_visitor = SubstDstVisitor() self.reset_visitor = ResetVisitor() self.seq = Seq(self.m, self.name + '_par', clk, rst, nohook=True) self.done = False self.last_cond = [] self.last_kwargs = {} self.last_if_statement = None self.elif_cond = None self.next_kwargs = {} self.as_module = as_module if not nohook: self.m.add_hook(self.implement) #------------------------------------------------------------------------- def goto(self, dst, cond=None, else_dst=None): if cond is None and 'cond' in self.next_kwargs: cond = self.next_kwargs['cond'] self._clear_next_kwargs() self._clear_last_if_statement() self._clear_last_cond() src = self.current return self._go(src, dst, cond, else_dst) def goto_init(self, cond=None): if cond is None and 'cond' in self.next_kwargs: cond = self.next_kwargs['cond'] self._clear_next_kwargs() self._clear_last_if_statement() self._clear_last_cond() src = self.current dst = 0 return self._go(src, dst, cond) def goto_next(self, cond=None): if cond is None and 'cond' in self.next_kwargs: cond = self.next_kwargs['cond'] self._clear_next_kwargs() self._clear_last_if_statement() self._clear_last_cond() src = self.current dst = self.current + 1 ret = self._go(src, dst, cond=cond) self.inc() return ret def goto_from(self, src, dst, cond=None, else_dst=None): if cond is None and 'cond' in self.next_kwargs: cond = self.next_kwargs['cond'] self._clear_next_kwargs() self._clear_last_if_statement() self._clear_last_cond() return self._go(src, dst, cond, else_dst) def inc(self): self._set_index(None) #------------------------------------------------------------------------- def add(self, *statement, **kwargs): """ add new assignments """ kwargs.update(self.next_kwargs) self.last_kwargs = kwargs self._clear_next_kwargs() # if there is no attributes, Elif object is reused. has_args = not (len(kwargs) == 0 or # has no args (len(kwargs) == 1 and 'cond' in kwargs) ) # has only 'cond' if self.elif_cond is not None and not has_args: next_call = self.last_if_statement.Elif(self.elif_cond) next_call(*statement) self.last_if_statement = next_call self._add_dst_var(statement) self._clear_elif_cond() return self self._clear_last_if_statement() return self._add_statement(statement, **kwargs) #------------------------------------------------------------------------- def Prev(self, var, delay, initval=0, cond=None, prefix=None): return self.seq.Prev(var, delay, initval, cond, prefix) #------------------------------------------------------------------------- def If(self, *cond): self._clear_elif_cond() cond = make_condition(*cond) if cond is None: return self if 'cond' not in self.next_kwargs: self.next_kwargs['cond'] = cond else: self.next_kwargs['cond'] = vtypes.Ands(self.next_kwargs['cond'], cond) self.last_cond = [self.next_kwargs['cond']] return self def Else(self, *statement, **kwargs): self._clear_elif_cond() if len(self.last_cond) == 0: raise ValueError("No previous condition for Else.") old = self.last_cond.pop() self.last_cond.append(vtypes.Not(old)) # if the true-statement has delay attributes, # Else statement is separated. if 'delay' in self.last_kwargs and self.last_kwargs['delay'] > 0: prev_cond = self.last_cond ret = self.Then()(*statement) self.last_cond = prev_cond return ret # if there is additional attribute, Else statement is separated. has_args = not (len(self.next_kwargs) == 0 or # has no args (len(self.next_kwargs) == 1 and 'cond' in kwargs) ) # has only 'cond' if has_args: prev_cond = self.last_cond ret = self.Then()(*statement) self.last_cond = prev_cond return ret if not isinstance(self.last_if_statement, vtypes.If): raise ValueError("Last if-statement is not If") self.last_if_statement.Else(*statement) self._add_dst_var(statement) return self def Elif(self, *cond): if len(self.last_cond) == 0: raise ValueError("No previous condition for Else.") cond = make_condition(*cond) old = self.last_cond.pop() self.last_cond.append(vtypes.Not(old)) self.last_cond.append(cond) # if the true-statement has delay attributes, Else statement is # separated. if 'delay' in self.last_kwargs and self.last_kwargs['delay'] > 0: prev_cond = self.last_cond ret = self.Then() self.last_cond = prev_cond return ret if not isinstance(self.last_if_statement, vtypes.If): raise ValueError("Last if-statement is not If") self.elif_cond = cond cond = self._make_cond(self.last_cond) self.next_kwargs['cond'] = cond return self def Delay(self, delay): self.next_kwargs['delay'] = delay return self def Keep(self, keep): self.next_kwargs['keep'] = keep return self def Then(self): cond = self._make_cond(self.last_cond) self._clear_last_cond() self.If(cond) return self def LazyCond(self, value=True): self.next_kwargs['lazy_cond'] = value return self def EagerVal(self, value=True): self.next_kwargs['eager_val'] = value return self def Clear(self): self._clear_next_kwargs() self._clear_last_if_statement() self._clear_last_cond() self._clear_elif_cond() return self #------------------------------------------------------------------------- @property def current(self): return self.state_count @property def next(self): return self.current + 1 @property def current_delay(self): if 'delay' in self.next_kwargs: return self.next_kwargs['delay'] return 0 @property def last_delay(self): if 'delay' in self.last_kwargs: return self.last_kwargs['delay'] return 0 @property def current_condition(self): cond = self.next_kwargs['cond'] if 'cond' in self.next_kwargs else None if cond is not None: cond = vtypes.AndList(self.state == self.state_count, cond) else: cond = self.state == self.state_count return cond @property def last_condition(self): cond = self._make_cond(self.last_cond) if cond is not None: cond = vtypes.AndList(self.state == self.state_count, cond) else: cond = self.state == self.state_count return cond @property def then(self): return self.last_condition @property def here(self): return self.state == self.current #------------------------------------------------------------------------- def implement(self): if self.as_module: self.make_module() return self.make_always() #------------------------------------------------------------------------- def make_always(self, reset=(), body=(), case=True): if self.done: #raise ValueError('make_always() has been already called.') return self.done = True part_reset = self.make_reset(reset) part_body = list(body) + list( self.make_case() if case else self.make_if()) self.m.Always(vtypes.Posedge(self.clk))(vtypes.If(self.rst)( part_reset, )(part_body, ))
class FIFO(_MutexFunction): __intrinsics__ = ('enq', 'deq', 'try_enq', 'try_deq', 'is_empty', 'is_almost_empty', 'is_full', 'is_almost_full') + _MutexFunction.__intrinsics__ def __init__(self, m, name, clk, rst, datawidth=32, addrwidth=4): self.m = m self.name = name self.clk = clk self.rst = rst self.datawidth = datawidth self.addrwidth = addrwidth self.wif = FifoWriteInterface(self.m, name, datawidth, itype='Wire', otype='Wire') self.rif = FifoReadInterface(self.m, name, datawidth, itype='Wire', otype='Wire') self.definition = mkFifoDefinition(name, datawidth, addrwidth) self.inst = self.m.Instance(self.definition, 'inst_' + name, ports=m.connect_ports(self.definition)) self.seq = Seq(m, name, clk, rst) # entry counter self._max_size = (2 ** self.addrwidth - 1 if isinstance(self.addrwidth, int) else vtypes.Int(2) ** self.addrwidth - 1) self._count = self.m.Reg( 'count_' + name, self.addrwidth + 1, initval=0) self.seq.If( vtypes.Ands(vtypes.Ands(self.wif.enq, vtypes.Not(self.wif.full)), vtypes.Ands(self.rif.deq, vtypes.Not(self.rif.empty))))( self._count(self._count) ).Elif(vtypes.Ands(self.wif.enq, vtypes.Not(self.wif.full)))( self._count.inc() ).Elif(vtypes.Ands(self.rif.deq, vtypes.Not(self.rif.empty)))( self._count.dec() ) self._enq_disabled = False self._deq_disabled = False self.mutex = None def _id(self): return id(self) def disable_enq(self): self.seq( self.wif.enq(0) ) self._enq_disabled = True def disable_deq(self): self.rif.deq.assign(0) self._deq_disabled = True def enq_rtl(self, wdata, cond=None): """ Enque """ if self._enq_disabled: raise TypeError('Enq disabled.') cond = make_condition(cond) ready = vtypes.Not(self.wif.almost_full) if cond is not None: enq_cond = vtypes.Ands(cond, ready) enable = cond else: enq_cond = ready enable = vtypes.Int(1, 1) util.add_mux(self.wif.wdata, enable, wdata) util.add_enable_cond(self.wif.enq, enable, enq_cond) ack = self.seq.Prev(ready, 1) return ack, ready def deq_rtl(self, cond=None): """ Deque """ if self._deq_disabled: raise TypeError('Deq disabled.') cond = make_condition(cond) ready = vtypes.Not(self.rif.empty) if cond is not None: deq_cond = vtypes.Ands(cond, ready) else: deq_cond = ready util.add_enable_cond(self.rif.deq, deq_cond, 1) data = self.rif.rdata valid = self.seq.Prev(deq_cond, 1) return data, valid, ready @property def wdata(self): return self.wif.wdata @property def empty(self): return self.rif.empty @property def almost_empty(self): return self.rif.almost_empty @property def rdata(self): return self.rif.rdata @property def full(self): return self.wif.full @property def almost_full(self): return self.wif.almost_full @property def count(self): return self._count @property def space(self): if isinstance(self._max_size, int): return vtypes.Int(self._max_size) - self.count return self._max_size - self.count def has_space(self, num=1): if num < 1: return True return (self._count + num < self._max_size) def enq(self, fsm, wdata): cond = fsm.state == fsm.current ack, ready = self.enq_rtl(wdata, cond=cond) fsm.If(ready).goto_next() return 0 def deq(self, fsm): cond = fsm.state == fsm.current rdata, rvalid, rready = self.deq_rtl(cond=cond) fsm.If(rready).goto_next() rdata_reg = self.m.TmpReg(self.datawidth, initval=0, signed=True) fsm.If(rvalid)( rdata_reg(rdata) ) fsm.If(rvalid).goto_next() return rdata_reg def try_enq(self, fsm, wdata): cond = fsm.state == fsm.current ack, ready = self.enq_rtl(wdata, cond=cond) fsm.goto_next() ack_reg = self.m.TmpReg(initval=0) fsm( ack_reg(ack) ) fsm.goto_next() return ack_reg def try_deq(self, fsm): cond = fsm.state == fsm.current rdata, rvalid, rready = self.deq_rtl(cond=cond) fsm.goto_next() rdata_reg = self.m.TmpReg(self.datawidth, initval=0, signed=True) rvalid_reg = self.m.TmpReg(initval=0) fsm( rdata_reg(rdata), rvalid_reg(rvalid) ) fsm.goto_next() return rdata_reg, rvalid_reg def is_almost_empty(self, fsm): fsm.goto_next() return self.almost_empty def is_empty(self, fsm): fsm.goto_next() return self.empty def is_almost_full(self, fsm): fsm.goto_next() return self.almost_full def is_full(self, fsm): fsm.goto_next() return self.full