X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fsoc%2Fexperiment%2Fpi2ls.py;h=501eb55cf59f32892c7758d6c41c621a06ee675b;hb=c2441c6adc201b1acb013ad65b70cc0b0b18123b;hp=b31386b010d90754d67babe1b817684736b82764;hpb=575802fa56d7175ebbdc16bb5c493b556dab9c74;p=soc.git diff --git a/src/soc/experiment/pi2ls.py b/src/soc/experiment/pi2ls.py index b31386b0..501eb55c 100644 --- a/src/soc/experiment/pi2ls.py +++ b/src/soc/experiment/pi2ls.py @@ -41,6 +41,7 @@ class Pi2LSUI(PortInterfaceBase): if lsui is None: lsui = LoadStoreUnitInterface(addr_wid, self.addrbits, data_wid) self.lsui = lsui + self.lsui_busy = Signal() self.valid_l = SRLatch(False, name="valid") def set_wr_addr(self, m, addr, mask): @@ -55,10 +56,10 @@ class Pi2LSUI(PortInterfaceBase): def set_wr_data(self, m, data, wen): # mask already done in addr setup m.d.comb += self.lsui.x_st_data_i.eq(data) - return ~self.lsui.x_busy_o + return (~self.lsui_busy) def get_rd_data(self, m): - return self.lsui.m_ld_data_o, ~self.lsui.x_busy_o + return self.lsui.m_ld_data_o, ~self.lsui_busy def elaborate(self, platform): m = super().elaborate(platform) @@ -71,12 +72,37 @@ class Pi2LSUI(PortInterfaceBase): m.d.comb += lsui.x_ld_i.eq(pi.is_ld_i) m.d.comb += lsui.x_st_i.eq(pi.is_st_i) - # indicate valid at both ends - m.d.comb += self.lsui.m_valid_i.eq(self.valid_l.q) - m.d.comb += self.lsui.x_valid_i.eq(self.valid_l.q) - - # reset the valid latch when not busy - m.d.comb += self.valid_l.r.eq(~pi.busy_o) # self.lsui.x_busy_o) + # ooo how annoying. x_busy_o is set synchronously, i.e. one + # clock too late for this converter to "notice". consequently, + # when trying to wait for ld/st, here: on the first cycle + # it goes "oh, x_busy_o isn't set, the ld/st must have been + # completed already, we must be done" when in fact it hasn't + # started. to "fix" that we actually have to have a full FSM + # tracking from when LD/ST starts, right the way through. sigh. + # first clock busy signal. needed because x_busy_o is sync + with m.FSM() as fsm: + with m.State("IDLE"): + # detect when ld/st starts. set busy *immediately* + with m.If((pi.is_ld_i | pi.is_st_i) & self.valid_l.q): + m.d.comb += self.lsui_busy.eq(1) + m.next = "BUSY" + with m.State("BUSY"): + # detect when busy drops: must then wait for ld/st to end.. + #m.d.comb += self.lsui_busy.eq(self.lsui.x_busy_o) + m.d.comb += self.lsui_busy.eq(1) + with m.If(~self.lsui.x_busy_o): + m.next = "WAITDEASSERT" + with m.State("WAITDEASSERT"): + # when no longer busy: back to start + with m.If(~self.valid_l.q): + m.next = "IDLE" + + # indicate valid at both ends. OR with lsui_busy (stops comb loop) + m.d.comb += self.lsui.m_valid_i.eq(self.valid_l.q | self.lsui_busy) + m.d.comb += self.lsui.x_valid_i.eq(self.valid_l.q | self.lsui_busy) + + # reset the valid latch when not busy. sync to stop loop + m.d.sync += self.valid_l.r.eq(~self.lsui_busy) return m