diff --git a/gateware/extio.py b/gateware/extio.py index b07475a..0e16efa 100644 --- a/gateware/extio.py +++ b/gateware/extio.py @@ -93,41 +93,40 @@ class Waveform(LiteXModule): force_stop = Signal() self.sync += If(b.cyc & b.stb & ~b.ack, - Case(b.adr, { + Case(b.adr[0:5], { 0x0: If(b.we, run.eq(b.dat_w[0]), ).Else( - b.dat_r[0].eq(run) + b.dat_r.eq(run) ), 0x4: [ - b.dat_r[0:counter_max_wid].eq(cntr), + b.dat_r.eq(cntr), ], 0x8: [ If(b.we, do_loop.eq(b.dat_w[0]), ).Else( - b.dat_r[0].eq(do_loop), + b.dat_r.eq(do_loop), ) ], 0xC: [ - b.dat_r[0].eq(ready), - b.dat_r[1].eq(finished), + b.dat_r.eq(finished << 1 | ready), ], 0x10: If(b.we, wform_size.eq(b.dat_w[0:counter_max_wid]), ).Else( - b.dat_r[0:counter_max_wid].eq(wform_size) + b.dat_r.eq(wform_size) ), - 0x14: b.dat_r[0:timer_wid].eq(timer), + 0x14: b.dat_r.eq(timer), 0x18: If(b.we, timer_spacing.eq(b.dat_w[0:timer_wid]), ).Else( - b.dat_r[0:timer_wid].eq(timer_spacing), + b.dat_r.eq(timer_spacing), ), 0x1C: If(b.we, force_stop.eq(b.dat_w[0]), ).Else( - b.dat_r[0].eq(force_stop), + b.dat_r.eq(force_stop), ), # (W)A(V)EFO(RM) "default": b.dat_r.eq(0xAEF0AEF0), diff --git a/gateware/rtl/waveform/waveform.v b/gateware/rtl/waveform/waveform.v index 26a1149..a784e1f 100644 --- a/gateware/rtl/waveform/waveform.v +++ b/gateware/rtl/waveform/waveform.v @@ -67,6 +67,7 @@ CHECK_START: if (run) begin state <= CHECK_LEN; end else begin ready <= 1; + finished <= 0; end CHECK_LEN: if (cntr >= wform_size) begin if (do_loop) begin @@ -79,11 +80,9 @@ CHECK_LEN: if (cntr >= wform_size) begin state <= READ_RAM; end WAIT_FINISHED: if (!run) begin - finished <= 0; state <= CHECK_START; end else if (do_loop) begin state <= READ_RAM; - finished <= 0; cntr <= 0; end else begin finished <= 1; @@ -174,7 +173,6 @@ end * master switch for the DAC to the main CPU. */ WAIT_PERIOD: if (!run) begin - finished <= 0; state <= CHECK_START; end else if (timer < timer_spacing) begin timer <= timer + 1; diff --git a/gateware/soc.py b/gateware/soc.py index 922e86a..02debdf 100644 --- a/gateware/soc.py +++ b/gateware/soc.py @@ -305,6 +305,9 @@ class UpsilonSoC(SoCCore): return self.add_spi_master(name, **args) def add_waveform(self, name, ram_len, **kwargs): + # TODO: Either set the SPI interface at instantiation time, + # or allow waveform to read more than one SPI bus (either by + # master switching or addressing by Waveform). kwargs['counter_max_wid'] = minbits(ram_len) wf = Waveform(**kwargs) @@ -316,8 +319,8 @@ class UpsilonSoC(SoCCore): wf.add_ram(bram_pi.add_master(name), ram_len) def f(csrs): - origin = csrs["memories"][name.lower() + "_pi"]["base"] - return f'{name} = RegisterRegion({origin}, {wf.mmio(origin)})' + param_origin = csrs["memories"][name.lower() + "_pi"]["base"] + return f'{name} = Waveform({name}_ram, {name}_PI, {name}_ram_PI, RegisterRegion({param_origin}, {wf.mmio(param_origin)}))' self.mmio_closures.append(f) return wf, pi diff --git a/linux/Makefile b/linux/Makefile index 44eecd2..622237f 100644 --- a/linux/Makefile +++ b/linux/Makefile @@ -2,7 +2,7 @@ .SUFFIXES: .mpy .py -MPY=picorv32.mpy registers.mpy spi.mpy waveform.mpy mmio.mpy +MPY=picorv32.mpy registers.mpy spi.mpy waveform.mpy mmio.mpy random.mpy all: $(MPY) .py.mpy: diff --git a/linux/random.py b/linux/random.py new file mode 100644 index 0000000..3818b2a --- /dev/null +++ b/linux/random.py @@ -0,0 +1,10 @@ +class RandomGenerator: + # XorShift + def __init__(self, seed=2463534242): + self.seed = seed + + def __call__(self): + self.seed = self.seed ^ ((self.seed << 13) & 0xFFFFFFFF) + self.seed = self.seed ^ ((self.seed >> 17) & 0xFFFFFFFF) + self.seed = self.seed ^ ((self.seed << 5) & 0xFFFFFFFF) + return self.seed diff --git a/linux/spi.py b/linux/spi.py index 0bac286..c8ee7d8 100644 --- a/linux/spi.py +++ b/linux/spi.py @@ -3,14 +3,14 @@ from registers import * class SPI(RegisterRegion): def __init__(self, spiwid, spi_PI, origin, **regs): self.spiwid = spiwid - self.spi_PI = spi_PI + self.PI = spi_PI super().__init__(origin, **regs) def send(self, val, force=False): - if self.spi_PI.v != 0 and not force: + if self.PI.v != 0 and not force: raise Exception("SPI is controlled by another master") - self.spi_PI.v = 0 + self.PI.v = 0 self.arm.v = 0 while self.finished_or_ready.v == 0: diff --git a/linux/waveform.py b/linux/waveform.py index 12ff653..101dae5 100644 --- a/linux/waveform.py +++ b/linux/waveform.py @@ -1,23 +1,34 @@ from registers import * class Waveform(Immutable): - def __init__(self, ram, ram_pi, regs): + def __init__(self, ram, wf_pi, ram_pi, regs): super().__init__() + + self.wf_pi = wf_pi self.ram = ram self.ram_pi = ram_pi self.regs = regs self.make_immutable() - def run(self, wf, timer_spacing, do_loop = False): + def start(self, wf, timer_spacing, do_loop = False, force_control=False): """ Start waveform with signal. + Note that a transfer of control of the SPI bus to the Waveform + must be done manually. :param wf: Array of integers that describe the waveform. These are twos-complement 20-bit integers. :param timer_spacing: The amount of time to wait between points on the waveform. :param do_loop: If True, the waveform will repeat. + :param force_control: If True, will take control of the Waveform + even if it is being controlled by another Wishbone bus. """ + if self.wf_pi.v != 0: + if not force_control: + raise Exception("Waveform is not controlled by master") + self.wf_pi.v = 0 + self.stop() self.ram_pi.v = 0 @@ -32,15 +43,15 @@ class Waveform(Immutable): def stop(self): """ Stop the waveform and wait until it is ready. """ - self.regs.run = 0 - self.regs.do_loop = 0 + self.regs.run.v = 0 + self.regs.do_loop.v = 0 - while self.regs.finished_or_ready == 0: + while self.regs.finished_or_ready.v == 0: pass def force_stop(self): - self.regs.force_stop = 1 - selff.regs.force_stop = 0 + self.regs.force_stop.v = 1 + selff.regs.force_stop.v = 0 def dump(self): """ Dump contents of control registers. """