Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions gateware/src/rs/hal/src/persist.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
pub trait Persist {
fn set_persist(&mut self, value: u16);
fn set_decay(&mut self, value: u8);
fn set_skip(&mut self, value: u8);
}

#[macro_export]
Expand Down Expand Up @@ -29,6 +30,10 @@ macro_rules! impl_persist {
self.registers.decay().write(|w| unsafe { w.decay().bits(value) } );
}

fn set_skip(&mut self, value: u8) {
self.registers.skip().write(|w| unsafe { w.skip().bits(value) } );
}

}
)+
};
Expand Down
30 changes: 27 additions & 3 deletions gateware/src/tiliqua/raster/persist.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ def __init__(self, *, bus_signature,
# Tweakables
"holdoff": In(16, init=holdoff_default),
"decay": In(4, init=1),
"skip": In(8, init=0),
# DMA bus / fb
"bus": Out(bus_signature),
"fbp": In(DMAFramebuffer.Properties()),
Expand Down Expand Up @@ -70,11 +71,21 @@ def elaborate(self, platform) -> Module:

# Latched version of decay speed control input
decay_latch = Signal.like(self.decay)
# Latched version of skip probability control input
skip_latch = Signal.like(self.skip)
# Track delay between read/write bursts
holdoff_count = Signal(32)
# Incoming pixel array (read from FIFO)
pixels_r = Signal(data.ArrayLayout(Pixel, 4))

# Free-running LFSR for probabilistic pixel skipping.
lfsr0 = Signal(unsigned(32), init=0x67452301)
lfsr1 = Signal(unsigned(32), init=0xefcdab89)
lfsr1_next = Signal(unsigned(32))
m.d.comb += lfsr1_next.eq(lfsr1 + lfsr0)
m.d.sync += lfsr1.eq(lfsr1_next)
m.d.sync += lfsr0.eq(lfsr0 ^ lfsr1_next)

m.d.comb += self.fifo.w_data.eq(bus.dat_r)

# Used for fastpath when all pixels are zero
Expand All @@ -101,6 +112,7 @@ def elaborate(self, platform) -> Module:

with m.State('BURST-IN'):
m.d.sync += decay_latch.eq(self.decay)
m.d.sync += skip_latch.eq(self.skip)
m.d.comb += [
bus.stb.eq(1),
bus.cyc.eq(1),
Expand Down Expand Up @@ -135,12 +147,17 @@ def elaborate(self, platform) -> Module:

with m.State('BURST-OUT'):
# The actual persistance calculation. 4 pixels at a time.
#
# Per-pixel LFSR comparison decides whether to decay or
# write back unchanged (probabilistic skip).
pixels_w = Signal(data.ArrayLayout(Pixel, 4))
for n in range(4):
# color
skip_this = Signal(name=f"skip_{n}")
m.d.comb += skip_this.eq(lfsr1[n*8:(n*8)+8] < skip_latch)
m.d.comb += pixels_w[n].color.eq(pixels_r[n].color)
# intensity
with m.If(pixels_r[n].intensity >= decay_latch):
with m.If(skip_this):
m.d.comb += pixels_w[n].intensity.eq(pixels_r[n].intensity)
with m.Elif(pixels_r[n].intensity >= decay_latch):
m.d.comb += pixels_w[n].intensity.eq(pixels_r[n].intensity - decay_latch)
with m.Else():
m.d.comb += pixels_w[n].intensity.eq(0)
Expand Down Expand Up @@ -184,6 +201,9 @@ class PersistReg(csr.Register, access="w"):
class DecayReg(csr.Register, access="w"):
decay: csr.Field(csr.action.W, unsigned(8))

class SkipReg(csr.Register, access="w"):
skip: csr.Field(csr.action.W, unsigned(8))

def __init__(self, bus_dma):
self.en = Signal()
self.persist = Persistance(bus_signature=bus_dma.bus.signature.flip())
Expand All @@ -193,6 +213,7 @@ def __init__(self, bus_dma):

self._persist = regs.add("persist", self.PersistReg(), offset=0x0)
self._decay = regs.add("decay", self.DecayReg(), offset=0x4)
self._skip = regs.add("skip", self.SkipReg(), offset=0x8)

self._bridge = csr.Bridge(regs.as_memory_map())

Expand All @@ -216,4 +237,7 @@ def elaborate(self, platform):
with m.If(self._decay.f.decay.w_stb):
m.d.sync += self.persist.decay.eq(self._decay.f.decay.w_data)

with m.If(self._skip.f.skip.w_stb):
m.d.sync += self.persist.skip.eq(self._skip.f.skip.w_data)

return m
13 changes: 8 additions & 5 deletions gateware/src/top/xbeam/fw/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,14 @@ fn build_cc_mapper(opts: &Opts) -> MidiCcMapper {
m.add(31, global_index(opts, &opts.delay.delay_y), CcMapMode::Absolute);
m.add(32, global_index(opts, &opts.delay.delay_i), CcMapMode::Absolute);
m.add(33, global_index(opts, &opts.delay.delay_c), CcMapMode::Absolute);
// Beam page (CC 40-45)
// Beam page (CC 40-46)
m.add(40, global_index(opts, &opts.beam.persist), CcMapMode::Absolute);
m.add(41, global_index(opts, &opts.beam.decay), CcMapMode::Absolute);
m.add(42, global_index(opts, &opts.beam.ui_hue), CcMapMode::Absolute);
m.add(43, global_index(opts, &opts.beam.palette), CcMapMode::Absolute);
m.add(44, global_index(opts, &opts.beam.grid), CcMapMode::Absolute);
m.add(45, global_index(opts, &opts.beam.grid_i), CcMapMode::Absolute);
m.add(42, global_index(opts, &opts.beam.rnd_skip), CcMapMode::Absolute);
m.add(43, global_index(opts, &opts.beam.ui_hue), CcMapMode::Absolute);
m.add(44, global_index(opts, &opts.beam.palette), CcMapMode::Absolute);
m.add(45, global_index(opts, &opts.beam.grid), CcMapMode::Absolute);
m.add(46, global_index(opts, &opts.beam.grid_i), CcMapMode::Absolute);
// Misc page (CC 50-52)
m.add(50, global_index(opts, &opts.misc.plot_type), CcMapMode::Absolute);
m.add(51, global_index(opts, &opts.misc.plot_src), CcMapMode::Absolute);
Expand Down Expand Up @@ -283,9 +284,11 @@ fn main() -> ! {
opts.beam.ui_hue.value).ok();
persist.set_persist(128);
persist.set_decay(1);
persist.set_skip(0);
} else {
persist.set_persist(opts.beam.persist.value);
persist.set_decay(opts.beam.decay.value);
persist.set_skip(opts.beam.rnd_skip.value);
}


Expand Down
3 changes: 3 additions & 0 deletions gateware/src/top/xbeam/fw/src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ int_params!(DelayParams<u16> { step: 8, min: 0, max: 512, format: IntFormat
int_params!(PCScaleParams<u8> { step: 1, min: 0, max: 15 });
int_params!(PersistParams<u16> { step: 32, min: 32, max: 4096 });
int_params!(DecayParams<u8> { step: 1, min: 0, max: 15 });
int_params!(SkipParams<u8> { step: 16, min: 0, max: 240 });
int_params!(IntensityParams<u8> { step: 1, min: 0, max: 15 });
int_params!(HueParams<u8> { step: 1, min: 0, max: 15 });
int_params!(TriggerLvlParams<i16> { step: 500, min: -16000, max: 16000, format: IntFormat::Scaled { divisor: 4000, precision: 2, suffix: "V" } });
Expand Down Expand Up @@ -145,6 +146,8 @@ pub struct BeamOpts {
pub persist: IntOption<PersistParams>,
#[option(1)]
pub decay: IntOption<DecayParams>,
#[option(0)]
pub rnd_skip: IntOption<SkipParams>,
#[option(10)]
pub ui_hue: IntOption<HueParams>,
#[option]
Expand Down
9 changes: 5 additions & 4 deletions gateware/src/top/xbeam/top.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,10 +106,11 @@

BEAM persist 40 phosphor decay speed (high = slow)
BEAM decay 41 phosphor decay amount (low = slow)
BEAM ui-hue 42 menu and grid overlay hue
BEAM palette 43 color palette
BEAM grid 44 grid overlay style
BEAM grid-i 45 grid overlay intensity
BEAM rnd-skip 42 probabilistic decay skip (high = more)
BEAM ui-hue 43 menu and grid overlay hue
BEAM palette 44 color palette
BEAM grid 45 grid overlay style
BEAM grid-i 46 grid overlay intensity

MISC plot-type 50 vectorscope or oscilloscope
MISC plot-src 51 plot inputs or outputs
Expand Down
Loading