diff --git a/nmigen_stdio/spiflash.py b/nmigen_stdio/spiflash.py index 31f2d4a..a9eba5e 100644 --- a/nmigen_stdio/spiflash.py +++ b/nmigen_stdio/spiflash.py @@ -99,6 +99,7 @@ def __init__(self, *, protocol, data_width=32, granularity=8, # (Note: DQ pins are both input/output only for Dual or Quad SPI protocols) self.shreg = None self.counter = Signal.like(self.divisor) + self.counter_en = Signal() self.clk_posedge_next = Signal() self.clk_negedge_next = Signal() @@ -109,6 +110,7 @@ def _add_spi_hardware_logic(self, platform, module): raise NotImplementedError("Shift register shreg has not been defined!") shreg = self.shreg counter = self.counter + counter_en = self.counter_en if self._pins is not None: module.d.comb += [ @@ -153,13 +155,15 @@ def _add_spi_hardware_logic(self, platform, module): # Countdown logic for counter based on divisor # Also implements MISO logic dq_i = Signal(self.spi_width) - # Enable SCLK only when CS: - with module.If(self.cs): + # When counter is enabled: + with module.If(counter_en): # When countdown is half-way done, clock edge goes up (positive): # - MISO latches bit/byte from slave # - slave has been latching from MOSI mid-way (since previous negedge) with module.If(counter == (self.divisor+1) >> 1): - module.d.sync += self.clk.eq(1) + # Enable SCLK only when CS: + with module.If(self.cs): + module.d.sync += self.clk.eq(1) # Indicate imminent posedge module.d.comb += self.clk_posedge_next.eq(1) if self._protocol == "standard": @@ -170,16 +174,19 @@ def _add_spi_hardware_logic(self, platform, module): # - MOSI latches from shreg by "pushing" old data out from the left of shreg; # - slave has been outputting MISO mid-way (since previous posedge) with module.If(counter == 0): - module.d.sync += [ - self.clk.eq(0), - counter.eq(self.divisor) - ] + # Enable SCLK only when CS: + with module.If(self.cs): + module.d.sync += self.clk.eq(0) + module.d.sync += counter.eq(self.divisor) # Indicate imminent negedge module.d.comb += self.clk_negedge_next.eq(1) module.d.sync += shreg.eq(Cat(dq_i, shreg[:-self.spi_width])) # Normal countdown with module.Else(): module.d.sync += counter.eq(counter - 1) + # When counter is disabled, reset: + with module.Else(): + module.d.sync += counter.eq(self.divisor) # MOSI logic for Standard SPI protocol: # MOSI always output the leftmost bit of shreg @@ -222,6 +229,7 @@ def elaborate(self, platform): shreg = self.shreg counter = self.counter + counter_en = self.counter_en # fcmd: get formatted command based on cmd_dict fcmd = self._format_cmd() @@ -244,6 +252,7 @@ def elaborate(self, platform): with m.If(self.ack): m.d.sync += [ counter.eq(0), + counter_en.eq(1), self.clk.eq(0) ] m.next = "SLOWREAD-CS" @@ -292,11 +301,14 @@ def elaborate(self, platform): # State: Send r_rdy (for 1 clock period), and then Wait with m.State("SLOWREAD-RDYWAIT"): with m.If((state_counter == 0) & self.clk_negedge_next): - m.d.sync += self.r_rdy.eq(1) + m.d.sync += [ + self.cs.eq(0), + self.r_rdy.eq(1) + ] # Early check to skip 1 clock period of doing nothing with m.If((state_counter == state_durations["SLOWREAD-RDYWAIT"] - 1) & self.clk_posedge_next): - m.d.sync += self.cs.eq(0) + m.d.sync += counter_en.eq(0) m.next = "SLOWREAD-IDLE" with m.Elif(self.clk_posedge_next): m.d.sync += state_counter.eq(state_counter + 1) @@ -328,6 +340,7 @@ def elaborate(self, platform): shreg = self.shreg counter = self.counter + counter_en = self.counter_en # fcmd: get formatted command based on cmd_dict fcmd = self._format_cmd() @@ -350,6 +363,7 @@ def elaborate(self, platform): with m.If(self.ack): m.d.sync += [ counter.eq(0), + counter_en.eq(1), self.clk.eq(0) ] m.next = "FASTREAD-CS" @@ -398,11 +412,14 @@ def elaborate(self, platform): # State: Send r_rdy (for 1 clock period), and then Wait with m.State("FASTREAD-RDYWAIT"): with m.If((state_counter == 0) & self.clk_negedge_next): - m.d.sync += self.r_rdy.eq(1) + m.d.sync += [ + self.cs.eq(0), + self.r_rdy.eq(1) + ] # Early check to skip 1 clock period of doing nothing with m.If((state_counter == state_durations["FASTREAD-RDYWAIT"] - 1) & self.clk_posedge_next): - m.d.sync += self.cs.eq(0) + m.d.sync += counter_en.eq(0) m.next = "FASTREAD-IDLE" with m.Elif(self.clk_posedge_next): m.d.sync += state_counter.eq(state_counter + 1) diff --git a/nmigen_stdio/test/test_spiflash.py b/nmigen_stdio/test/test_spiflash.py index e2404d3..89b5887 100644 --- a/nmigen_stdio/test/test_spiflash.py +++ b/nmigen_stdio/test/test_spiflash.py @@ -47,11 +47,11 @@ def elaborate(self, platform): with m.State("INIT"): m.d.sync += data_sig.eq(self.data) with m.If(self.dut.cs): - with m.If(self.dut.counter == self.dut.divisor >> 1): + with m.If(self.dut.clk_posedge_next): m.d.comb += recv_data.w_en.eq(1) with m.Else(): m.d.comb += recv_data.w_en.eq(0) - with m.If(~recv_data.w_rdy & stored_data.w_rdy & (self.dut.counter == 0)): + with m.If(~recv_data.w_rdy & stored_data.w_rdy & self.dut.clk_negedge_next): m.next = "PUT-DATA" with m.State("PUT-DATA"): with m.If(stored_data_num_left != 0): @@ -66,9 +66,9 @@ def elaborate(self, platform): ] with m.Else(): m.d.comb += stored_data.w_en.eq(0) - with m.If((dummy_counter != 0) & (self.dut.counter == 0)): + with m.If((dummy_counter != 0) & self.dut.clk_negedge_next): m.d.sync += dummy_counter.eq(dummy_counter - 1) - with m.Elif((dummy_counter == 0) & (self.dut.counter == 0)): + with m.Elif((dummy_counter == 0) & self.dut.clk_negedge_next): m.d.comb += stored_data.r_en.eq(1) m.next = "RETURN-DATA" with m.State("RETURN-DATA"):