From: Sebastien Bourdeauducq Date: Sun, 9 Jun 2013 14:03:22 +0000 (+0200) Subject: bus/lasmibus: add target and initiator X-Git-Tag: 24jan2021_ls180~2099^2~565 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=a836cba790d7e886ceec9f39031edcaf6e28111d;p=litex.git bus/lasmibus: add target and initiator --- diff --git a/migen/bus/lasmibus.py b/migen/bus/lasmibus.py index 728aa27d..24fb2bac 100644 --- a/migen/bus/lasmibus.py +++ b/migen/bus/lasmibus.py @@ -1,4 +1,5 @@ from migen.fhdl.std import * +from migen.bus.transactions import * from migen.genlib import roundrobin from migen.genlib.record import * from migen.genlib.misc import optree @@ -145,3 +146,110 @@ class Crossbar(Module): m_ba.append(ba) m_rca.append(rca) return m_ca, m_ba, m_rca + +class Initiator(Module): + def __init__(self, generator, bus): + self.generator = generator + self.bus = bus + self.transaction_start = 0 + self.transaction = None + self.transaction_end = None + self.done = False + + def do_simulation(self, s): + s.wr(self.bus.dat_w, 0) + s.wr(self.bus.dat_we, 0) + if not self.done: + if self.transaction is not None and s.rd(self.bus.ack): + s.wr(self.bus.stb, 0) + if isinstance(self.transaction, TRead): + self.transaction_end = s.cycle_counter + self.bus.read_latency + else: + self.transaction_end = s.cycle_counter + self.bus.write_latency - 1 + + if self.transaction is None or s.cycle_counter == self.transaction_end: + if self.transaction is not None: + self.transaction.latency = s.cycle_counter - self.transaction_start - 1 + if isinstance(self.transaction, TRead): + self.transaction.data = s.rd(self.bus.dat_r) + else: + s.wr(self.bus.dat_w, self.transaction.data) + s.wr(self.bus.dat_we, self.transaction.sel) + try: + self.transaction = next(self.generator) + except StopIteration: + self.done = True + self.transaction = None + if self.transaction is not None: + self.transaction_start = s.cycle_counter + s.wr(self.bus.stb, 1) + s.wr(self.bus.adr, self.transaction.address) + if isinstance(self.transaction, TRead): + s.wr(self.bus.we, 0) + else: + s.wr(self.bus.we, 1) + +class TargetModel: + def __init__(self): + self.last_bank = 0 + + def read(self, bank, address): + return 0 + + def write(self, bank, address, data, we): + pass + + # Round-robin scheduling + def select_bank(self, pending_banks): + if not pending_banks: + return -1 + self.last_bank += 1 + if self.last_bank > max(pending_banks): + self.last_bank = 0 + while self.last_bank not in pending_banks: + self.last_bank += 1 + return self.last_bank + +class Target(Module): + def __init__(self, model, *ifargs, **ifkwargs): + self.model = model + self.bus = Interface(*ifargs, **ifkwargs) + self.rd_pipeline = [None]*self.bus.read_latency + self.wr_pipeline = [None]*self.bus.write_latency + + def do_simulation(self, s): + # determine banks with pending requests + pending_banks = set() + for nb in range(self.bus.nbanks): + bank = getattr(self.bus, "bank"+str(nb)) + if s.rd(bank.stb) and not s.rd(bank.ack): + pending_banks.add(nb) + + # issue new transactions + selected_bank_n = self.model.select_bank(pending_banks) + for nb in range(self.bus.nbanks): + bank = getattr(self.bus, "bank"+str(nb)) + if nb == selected_bank_n: + s.wr(bank.ack, 1) + else: + s.wr(bank.ack, 0) + + rd_transaction = None + wr_transaction = None + if selected_bank_n >= 0: + selected_bank = getattr(self.bus, "bank"+str(selected_bank_n)) + if s.rd(selected_bank.we): + wr_transaction = selected_bank_n, s.rd(selected_bank.adr) + else: + rd_transaction = selected_bank_n, s.rd(selected_bank.adr) + + # data pipeline + self.rd_pipeline.append(rd_transaction) + self.wr_pipeline.append(wr_transaction) + done_rd_transaction = self.rd_pipeline.pop(0) + done_wr_transaction = self.wr_pipeline.pop(0) + if done_rd_transaction is not None: + s.wr(self.bus.dat_r, self.model.read(done_rd_transaction[0], done_rd_transaction[1])) + if done_wr_transaction is not None: + self.model.write(done_wr_transaction[0], done_wr_transaction[1], + s.rd(self.bus.dat_w), s.rd(self.bus.dat_we))