From: Florent Kermarrec Date: Wed, 19 Apr 2017 08:55:58 +0000 (+0200) Subject: soc/cores: move flash cores to cores directory X-Git-Tag: 24jan2021_ls180~1869 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=9cfc5942801728774de441d9d2b869b02ba5b6a9;p=litex.git soc/cores: move flash cores to cores directory --- diff --git a/litex/boards/targets/kc705.py b/litex/boards/targets/kc705.py index 128d318f..297159d0 100755 --- a/litex/boards/targets/kc705.py +++ b/litex/boards/targets/kc705.py @@ -6,7 +6,6 @@ from litex.gen import * from litex.gen.genlib.resetsync import AsyncResetSynchronizer from litex.boards.platforms import kc705 -from litex.soc.cores.flash import spi_flash from litex.soc.integration.soc_core import mem_decoder from litex.soc.integration.soc_sdram import * from litex.soc.integration.builder import * diff --git a/litex/soc/cores/flash/__init__.py b/litex/soc/cores/flash/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/litex/soc/cores/flash/nor_flash_16.py b/litex/soc/cores/flash/nor_flash_16.py deleted file mode 100644 index 3027882a..00000000 --- a/litex/soc/cores/flash/nor_flash_16.py +++ /dev/null @@ -1,104 +0,0 @@ -from litex.gen import * -from litex.gen.genlib.fsm import FSM, NextState - -from litex.soc.interconnect import wishbone - - -class NorFlash16(Module): - def __init__(self, pads, rd_timing, wr_timing): - self.bus = wishbone.Interface() - - ### - - data = TSTriple(16) - lsb = Signal() - - self.specials += data.get_tristate(pads.d) - self.comb += [ - data.oe.eq(pads.oe_n), - pads.ce_n.eq(0) - ] - - load_lo = Signal() - load_hi = Signal() - store = Signal() - - pads.oe_n.reset, pads.we_n.reset = 1, 1 - self.sync += [ - pads.oe_n.eq(1), - pads.we_n.eq(1), - - # Register data/address to avoid off-chip glitches - If(self.bus.cyc & self.bus.stb, - pads.adr.eq(Cat(lsb, self.bus.adr)), - If(self.bus.we, - # Only 16-bit writes are supported. Assume sel=0011 or 1100. - If(self.bus.sel[0], - data.o.eq(self.bus.dat_w[:16]) - ).Else( - data.o.eq(self.bus.dat_w[16:]) - ) - ).Else( - pads.oe_n.eq(0) - ) - ), - - If(load_lo, self.bus.dat_r[:16].eq(data.i)), - If(load_hi, self.bus.dat_r[16:].eq(data.i)), - If(store, pads.we_n.eq(0)) - ] - - # Typical timing of the flash chips: - # - 110ns address to output - # - 50ns write pulse width - counter = Signal(max=max(rd_timing, wr_timing)+1) - counter_en = Signal() - counter_wr_mode = Signal() - counter_done = Signal() - self.comb += counter_done.eq(counter == Mux(counter_wr_mode, wr_timing, rd_timing)) - self.sync += If(counter_en & ~counter_done, - counter.eq(counter + 1) - ).Else( - counter.eq(0) - ) - - fsm = FSM() - self.submodules += fsm - - fsm.act("IDLE", - If(self.bus.cyc & self.bus.stb, - If(self.bus.we, - NextState("WR") - ).Else( - NextState("RD_HI") - ) - ) - ) - fsm.act("RD_HI", - lsb.eq(0), - counter_en.eq(1), - If(counter_done, - load_hi.eq(1), - NextState("RD_LO") - ) - ) - fsm.act("RD_LO", - lsb.eq(1), - counter_en.eq(1), - If(counter_done, - load_lo.eq(1), - NextState("ACK") - ) - ) - fsm.act("WR", - # supported cases: sel=0011 [lsb=1] and sel=1100 [lsb=0] - lsb.eq(self.bus.sel[0]), - counter_wr_mode.eq(1), - counter_en.eq(1), - store.eq(1), - If(counter_done, NextState("ACK")) - ) - fsm.act("ACK", - self.bus.ack.eq(1), - NextState("IDLE") - ) diff --git a/litex/soc/cores/flash/spi_flash.py b/litex/soc/cores/flash/spi_flash.py deleted file mode 100644 index 14df3a4d..00000000 --- a/litex/soc/cores/flash/spi_flash.py +++ /dev/null @@ -1,197 +0,0 @@ -from litex.gen import * -from litex.gen.genlib.misc import timeline - -from litex.soc.interconnect import wishbone -from litex.soc.interconnect.csr import AutoCSR, CSRStorage, CSRStatus - - -_FAST_READ = 0x0b -_DIOFR = 0xbb -_QIOFR = 0xeb - - -def _format_cmd(cmd, spi_width): - """ - `cmd` is the read instruction. Since everything is transmitted on all - dq lines (cmd, adr and data), extend/interleave cmd to full pads.dq - width even if dq1-dq3 are don't care during the command phase: - For example, for N25Q128, 0xeb is the quad i/o fast read, and - extended to 4 bits (dq1,dq2,dq3 high) is: 0xfffefeff - """ - c = 2**(8*spi_width)-1 - for b in range(8): - if not (cmd>>b)%2: - c &= ~(1<<(b*spi_width)) - return c - - -class SpiFlashDualQuad(Module, AutoCSR): - def __init__(self, pads, dummy=15, div=2): - """ - Simple SPI flash. - Supports multi-bit pseudo-parallel reads (aka Dual or Quad I/O Fast - Read). Only supports mode0 (cpol=0, cpha=0). - """ - self.bus = bus = wishbone.Interface() - spi_width = len(pads.dq) - assert spi_width >= 2 - - # # # - - cs_n = Signal(reset=1) - clk = Signal() - dq_oe = Signal() - wbone_width = len(bus.dat_r) - - - read_cmd_params = { - 4: (_format_cmd(_QIOFR, 4), 4*8), - 2: (_format_cmd(_DIOFR, 2), 2*8), - 1: (_format_cmd(_FAST_READ, 1), 1*8) - } - read_cmd, cmd_width = read_cmd_params[spi_width] - addr_width = 24 - - dq = TSTriple(spi_width) - self.specials.dq = dq.get_tristate(pads.dq) - - sr = Signal(max(cmd_width, addr_width, wbone_width)) - self.comb += bus.dat_r.eq(sr) - - self.comb += [ - pads.clk.eq(clk), - pads.cs_n.eq(cs_n), - dq.o.eq(sr[-spi_width:]), - dq.oe.eq(dq_oe) - ] - - if div < 2: - raise ValueError("Unsupported value \'{}\' for div parameter for SpiFlash core".format(div)) - else: - i = Signal(max=div) - dqi = Signal(spi_width) - self.sync += [ - If(i == div//2 - 1, - clk.eq(1), - dqi.eq(dq.i), - ), - If(i == div - 1, - i.eq(0), - clk.eq(0), - sr.eq(Cat(dqi, sr[:-spi_width])) - ).Else( - i.eq(i + 1), - ), - ] - - # spi is byte-addressed, prefix by zeros - z = Replicate(0, log2_int(wbone_width//8)) - - seq = [ - (cmd_width//spi_width*div, - [dq_oe.eq(1), cs_n.eq(0), sr[-cmd_width:].eq(read_cmd)]), - (addr_width//spi_width*div, - [sr[-addr_width:].eq(Cat(z, bus.adr))]), - ((dummy + wbone_width//spi_width)*div, - [dq_oe.eq(0)]), - (1, - [bus.ack.eq(1), cs_n.eq(1)]), - (div, # tSHSL! - [bus.ack.eq(0)]), - (0, - []), - ] - - # accumulate timeline deltas - t, tseq = 0, [] - for dt, a in seq: - tseq.append((t, a)) - t += dt - - self.sync += timeline(bus.cyc & bus.stb & (i == div - 1), tseq) - - -class SpiFlashSingle(Module, AutoCSR): - def __init__(self, pads, dummy=15, div=2): - """ - Simple SPI flash. - Supports 1-bit reads. Only supports mode0 (cpol=0, cpha=0). - """ - self.bus = bus = wishbone.Interface() - - # # # - - if hasattr(pads, "wp"): - self.comb += pads.wp.eq(1) - - if hasattr(pads, "hold"): - self.comb += pads.hold.eq(1) - - cs_n = Signal(reset=1) - clk = Signal() - wbone_width = len(bus.dat_r) - - read_cmd = _FAST_READ - cmd_width = 8 - addr_width = 24 - - sr = Signal(max(cmd_width, addr_width, wbone_width)) - self.comb += bus.dat_r.eq(sr) - - self.comb += [ - pads.clk.eq(clk), - pads.cs_n.eq(cs_n), - pads.mosi.eq(sr[-1:]) - ] - - if div < 2: - raise ValueError("Unsupported value \'{}\' for div parameter for SpiFlash core".format(div)) - else: - i = Signal(max=div) - miso = Signal() - self.sync += [ - If(i == div//2 - 1, - clk.eq(1), - miso.eq(pads.miso), - ), - If(i == div - 1, - i.eq(0), - clk.eq(0), - sr.eq(Cat(miso, sr[:-1])) - ).Else( - i.eq(i + 1), - ), - ] - - # spi is byte-addressed, prefix by zeros - z = Replicate(0, log2_int(wbone_width//8)) - - seq = [ - (cmd_width*div, - [cs_n.eq(0), sr[-cmd_width:].eq(read_cmd)]), - (addr_width*div, - [sr[-addr_width:].eq(Cat(z, bus.adr))]), - ((dummy + wbone_width)*div, - []), - (1, - [bus.ack.eq(1), cs_n.eq(1)]), - (div, # tSHSL! - [bus.ack.eq(0)]), - (0, - []), - ] - - # accumulate timeline deltas - t, tseq = 0, [] - for dt, a in seq: - tseq.append((t, a)) - t += dt - - self.sync += timeline(bus.cyc & bus.stb & (i == div - 1), tseq) - - -def SpiFlash(pads, *args, **kw): - if hasattr(pads, "mosi"): - return SpiFlashSingle(pads, *args, **kw) - else: - return SpiFlashDualQuad(pads, *args, **kw) diff --git a/litex/soc/cores/nor_flash_16.py b/litex/soc/cores/nor_flash_16.py new file mode 100644 index 00000000..3027882a --- /dev/null +++ b/litex/soc/cores/nor_flash_16.py @@ -0,0 +1,104 @@ +from litex.gen import * +from litex.gen.genlib.fsm import FSM, NextState + +from litex.soc.interconnect import wishbone + + +class NorFlash16(Module): + def __init__(self, pads, rd_timing, wr_timing): + self.bus = wishbone.Interface() + + ### + + data = TSTriple(16) + lsb = Signal() + + self.specials += data.get_tristate(pads.d) + self.comb += [ + data.oe.eq(pads.oe_n), + pads.ce_n.eq(0) + ] + + load_lo = Signal() + load_hi = Signal() + store = Signal() + + pads.oe_n.reset, pads.we_n.reset = 1, 1 + self.sync += [ + pads.oe_n.eq(1), + pads.we_n.eq(1), + + # Register data/address to avoid off-chip glitches + If(self.bus.cyc & self.bus.stb, + pads.adr.eq(Cat(lsb, self.bus.adr)), + If(self.bus.we, + # Only 16-bit writes are supported. Assume sel=0011 or 1100. + If(self.bus.sel[0], + data.o.eq(self.bus.dat_w[:16]) + ).Else( + data.o.eq(self.bus.dat_w[16:]) + ) + ).Else( + pads.oe_n.eq(0) + ) + ), + + If(load_lo, self.bus.dat_r[:16].eq(data.i)), + If(load_hi, self.bus.dat_r[16:].eq(data.i)), + If(store, pads.we_n.eq(0)) + ] + + # Typical timing of the flash chips: + # - 110ns address to output + # - 50ns write pulse width + counter = Signal(max=max(rd_timing, wr_timing)+1) + counter_en = Signal() + counter_wr_mode = Signal() + counter_done = Signal() + self.comb += counter_done.eq(counter == Mux(counter_wr_mode, wr_timing, rd_timing)) + self.sync += If(counter_en & ~counter_done, + counter.eq(counter + 1) + ).Else( + counter.eq(0) + ) + + fsm = FSM() + self.submodules += fsm + + fsm.act("IDLE", + If(self.bus.cyc & self.bus.stb, + If(self.bus.we, + NextState("WR") + ).Else( + NextState("RD_HI") + ) + ) + ) + fsm.act("RD_HI", + lsb.eq(0), + counter_en.eq(1), + If(counter_done, + load_hi.eq(1), + NextState("RD_LO") + ) + ) + fsm.act("RD_LO", + lsb.eq(1), + counter_en.eq(1), + If(counter_done, + load_lo.eq(1), + NextState("ACK") + ) + ) + fsm.act("WR", + # supported cases: sel=0011 [lsb=1] and sel=1100 [lsb=0] + lsb.eq(self.bus.sel[0]), + counter_wr_mode.eq(1), + counter_en.eq(1), + store.eq(1), + If(counter_done, NextState("ACK")) + ) + fsm.act("ACK", + self.bus.ack.eq(1), + NextState("IDLE") + ) diff --git a/litex/soc/cores/spi_flash.py b/litex/soc/cores/spi_flash.py new file mode 100644 index 00000000..14df3a4d --- /dev/null +++ b/litex/soc/cores/spi_flash.py @@ -0,0 +1,197 @@ +from litex.gen import * +from litex.gen.genlib.misc import timeline + +from litex.soc.interconnect import wishbone +from litex.soc.interconnect.csr import AutoCSR, CSRStorage, CSRStatus + + +_FAST_READ = 0x0b +_DIOFR = 0xbb +_QIOFR = 0xeb + + +def _format_cmd(cmd, spi_width): + """ + `cmd` is the read instruction. Since everything is transmitted on all + dq lines (cmd, adr and data), extend/interleave cmd to full pads.dq + width even if dq1-dq3 are don't care during the command phase: + For example, for N25Q128, 0xeb is the quad i/o fast read, and + extended to 4 bits (dq1,dq2,dq3 high) is: 0xfffefeff + """ + c = 2**(8*spi_width)-1 + for b in range(8): + if not (cmd>>b)%2: + c &= ~(1<<(b*spi_width)) + return c + + +class SpiFlashDualQuad(Module, AutoCSR): + def __init__(self, pads, dummy=15, div=2): + """ + Simple SPI flash. + Supports multi-bit pseudo-parallel reads (aka Dual or Quad I/O Fast + Read). Only supports mode0 (cpol=0, cpha=0). + """ + self.bus = bus = wishbone.Interface() + spi_width = len(pads.dq) + assert spi_width >= 2 + + # # # + + cs_n = Signal(reset=1) + clk = Signal() + dq_oe = Signal() + wbone_width = len(bus.dat_r) + + + read_cmd_params = { + 4: (_format_cmd(_QIOFR, 4), 4*8), + 2: (_format_cmd(_DIOFR, 2), 2*8), + 1: (_format_cmd(_FAST_READ, 1), 1*8) + } + read_cmd, cmd_width = read_cmd_params[spi_width] + addr_width = 24 + + dq = TSTriple(spi_width) + self.specials.dq = dq.get_tristate(pads.dq) + + sr = Signal(max(cmd_width, addr_width, wbone_width)) + self.comb += bus.dat_r.eq(sr) + + self.comb += [ + pads.clk.eq(clk), + pads.cs_n.eq(cs_n), + dq.o.eq(sr[-spi_width:]), + dq.oe.eq(dq_oe) + ] + + if div < 2: + raise ValueError("Unsupported value \'{}\' for div parameter for SpiFlash core".format(div)) + else: + i = Signal(max=div) + dqi = Signal(spi_width) + self.sync += [ + If(i == div//2 - 1, + clk.eq(1), + dqi.eq(dq.i), + ), + If(i == div - 1, + i.eq(0), + clk.eq(0), + sr.eq(Cat(dqi, sr[:-spi_width])) + ).Else( + i.eq(i + 1), + ), + ] + + # spi is byte-addressed, prefix by zeros + z = Replicate(0, log2_int(wbone_width//8)) + + seq = [ + (cmd_width//spi_width*div, + [dq_oe.eq(1), cs_n.eq(0), sr[-cmd_width:].eq(read_cmd)]), + (addr_width//spi_width*div, + [sr[-addr_width:].eq(Cat(z, bus.adr))]), + ((dummy + wbone_width//spi_width)*div, + [dq_oe.eq(0)]), + (1, + [bus.ack.eq(1), cs_n.eq(1)]), + (div, # tSHSL! + [bus.ack.eq(0)]), + (0, + []), + ] + + # accumulate timeline deltas + t, tseq = 0, [] + for dt, a in seq: + tseq.append((t, a)) + t += dt + + self.sync += timeline(bus.cyc & bus.stb & (i == div - 1), tseq) + + +class SpiFlashSingle(Module, AutoCSR): + def __init__(self, pads, dummy=15, div=2): + """ + Simple SPI flash. + Supports 1-bit reads. Only supports mode0 (cpol=0, cpha=0). + """ + self.bus = bus = wishbone.Interface() + + # # # + + if hasattr(pads, "wp"): + self.comb += pads.wp.eq(1) + + if hasattr(pads, "hold"): + self.comb += pads.hold.eq(1) + + cs_n = Signal(reset=1) + clk = Signal() + wbone_width = len(bus.dat_r) + + read_cmd = _FAST_READ + cmd_width = 8 + addr_width = 24 + + sr = Signal(max(cmd_width, addr_width, wbone_width)) + self.comb += bus.dat_r.eq(sr) + + self.comb += [ + pads.clk.eq(clk), + pads.cs_n.eq(cs_n), + pads.mosi.eq(sr[-1:]) + ] + + if div < 2: + raise ValueError("Unsupported value \'{}\' for div parameter for SpiFlash core".format(div)) + else: + i = Signal(max=div) + miso = Signal() + self.sync += [ + If(i == div//2 - 1, + clk.eq(1), + miso.eq(pads.miso), + ), + If(i == div - 1, + i.eq(0), + clk.eq(0), + sr.eq(Cat(miso, sr[:-1])) + ).Else( + i.eq(i + 1), + ), + ] + + # spi is byte-addressed, prefix by zeros + z = Replicate(0, log2_int(wbone_width//8)) + + seq = [ + (cmd_width*div, + [cs_n.eq(0), sr[-cmd_width:].eq(read_cmd)]), + (addr_width*div, + [sr[-addr_width:].eq(Cat(z, bus.adr))]), + ((dummy + wbone_width)*div, + []), + (1, + [bus.ack.eq(1), cs_n.eq(1)]), + (div, # tSHSL! + [bus.ack.eq(0)]), + (0, + []), + ] + + # accumulate timeline deltas + t, tseq = 0, [] + for dt, a in seq: + tseq.append((t, a)) + t += dt + + self.sync += timeline(bus.cyc & bus.stb & (i == div - 1), tseq) + + +def SpiFlash(pads, *args, **kw): + if hasattr(pads, "mosi"): + return SpiFlashSingle(pads, *args, **kw) + else: + return SpiFlashDualQuad(pads, *args, **kw)