def set_horizontal_sync(self, m): "Calculate Horizontal sync." h = self.params.horizontal with m.If(watch_lfsr(m, self.x, h.sync_start - 1, name='hsync_start')): m.d.sync += self.horizontal_sync.eq(~self.horizontal_sync) with m.If(watch_lfsr(m, self.x, h.sync_end - 1, name='hsync_end')): m.d.sync += self.horizontal_sync.eq(~self.horizontal_sync)
def set_vertical_sync(self, m): "Calculate Vertical sync" v = self.params.vertical with m.If(self.at_line_m1): with m.If( watch_lfsr(m, self.y, v.sync_start - 1, name='vsync_start')): m.d.sync += self.vertical_sync.eq(~self.vertical_sync) with m.If(watch_lfsr(m, self.y, v.sync_end - 1, name='vsync_end')): m.d.sync += self.vertical_sync.eq(~self.vertical_sync)
def set_at_active_line_m2(self, m): "Calculate at_active_line_m2" h = self.params.horizontal def setval(val): m.d.sync += self.at_active_line_m2.eq(val) with m.If(watch_lfsr(m, self.x, h.total - 3)): with m.If(self.last_frame_line): setval(True) with m.If(~self.vertical_blanking): setval(True) with m.If(watch_lfsr(m, self.x, h.total - 2)): setval(False)
def watch_coord(self, m, xp, yp, name): """Adds logic to module to generate a one cycle pulse on a synced signal when timing reaches x, y """ # TODO: Speed up by calculating over several cycles # Calculate when to trigger tx, ty = self.params.add_clocks(xp, yp, -1) result = Signal(1, name=name) x_at = Signal() y_at = Signal() m.d.sync += [ x_at.eq(watch_lfsr(m, self.x, tx, name=f"{name}_x")), y_at.eq(watch_lfsr(m, self.y, ty, name=f"{name}_y")), ] m.d.comb += result.eq(x_at & y_at) return result
def elaborate(self, plat): lfsr = Lfsr.num_steps(1100) led = plat.request('led_r') m = Module() m.d.sync += led.eq(lfsr.value[0]) m.d.comb += lfsr.restart.eq(watch_lfsr(m, lfsr, 999)) m.submodules += [lfsr] return m
def elaborate(self, plat): # 89.77 90.62 94.95 95.31 95.31 95.31 95.31 95.31 101.58 107.52 lfsr = Lfsr.num_steps(1100, default_enabled=False) button = plat.request('button') led = plat.request('led_r') m = Module() m.d.sync += led.eq(lfsr.value[0]) m.d.comb += lfsr.restart.eq(watch_lfsr(m, lfsr, 999)) m.d.comb += lfsr.enable.eq(button) m.submodules += [lfsr] return m
def set_starts(self, m, last_y): """Calculate line start and frame start signals. Because at_line_m1 and at_frame_m1 are synchronous, they need to be calculated one clock before their values are used.""" h = self.params.horizontal v = self.params.vertical last_x2 = Signal() m.d.comb += last_x2.eq(watch_lfsr(m, self.x, h.total - 2, name="h_m2")) m.d.sync += self.at_line_m1.eq( last_x2) # high on next clock, which is last for line with m.If(self.at_line_m1): m.d.sync += self.last_frame_line.eq( watch_lfsr(m, self.y, v.total - 2, name="v_m2")) at_frame_m3 = Signal() m.d.comb += at_frame_m3.eq( self.watch_coord(m, *self.params.add_clocks(0, 0, -3), name="f_m3")) m.d.sync += self.at_frame_m2.eq(at_frame_m3) m.d.sync += self.at_frame_m1.eq(self.at_frame_m2)
def elaborate(self, plat): lfsr1 = Lfsr.num_steps(1200) lfsr2 = Lfsr.num_steps(1000, default_enabled=False) led1 = plat.request('led_r') led2 = plat.request('led_g') m = Module() # Use both LFSRs m.d.sync += [ led1.eq(lfsr1.value[0]), led2.eq(lfsr2.value[0]), ] # step lfsr2 when lfsr 1 is about to restart m.d.sync += [lfsr2.enable.eq(watch_lfsr(m, lfsr1, 1199))] m.submodules += [lfsr1, lfsr2] return m
def elaborate_read(self, m): """Make logic to build read_addr signal.""" m.submodules.r_lfsr = r_lfsr = rename_sync(self.read_domain, self.make_lfsr()) on_last = watch_lfsr(m, r_lfsr, self.num_words - 1, domain=self.read_domain, name='last') m.d.comb += [ # Address is whatever LFSR says. Last is on last word self.read.addr.eq(r_lfsr.value), self.read.last.eq(on_last), # restart LFSR on toggle, step LFSR on r_next r_lfsr.restart.eq(self.read.toggle), r_lfsr.enable.eq(self.read.next), ]
def set_active(self, m): "Calculate active signal" # NOTE: Previously, was using < operation, which is effetively a subtraction and # subtractions are slow. Changed to use == with stateful operation - is going better h = self.params.horizontal v = self.params.vertical at_active_end = watch_lfsr(m, self.x, h.active - 1, name='hactive_end') with m.If(self.at_frame_m1): # next pixel is top of screen m.d.sync += self.active.eq(True) with m.Elif(self.at_line_m1 & ~self.vertical_blanking): # For all except last line, set active when next line is about to begin m.d.sync += self.active.eq(True) with m.Elif(at_active_end): # Turn off at end of horizontal display area m.d.sync += self.active.eq(False)
def elaborate(self, platform): m = Module() m.submodules += [self.x, self.y] # Step y at end of every line m.d.comb += self.y.enable.eq(self.at_line_m1) last_y = Signal() m.d.comb += last_y.eq( watch_lfsr(m, self.y, self.params.vertical.value_at_last)) self.set_starts(m, last_y) self.set_at_active_line_m1(m) self.set_at_active_line_m2(m) self.set_horizontal_sync(m) self.set_vertical_sync(m) self.set_vertical_blanking(m) self.set_active(m) return m
def elaborate(self, platform): m = Module() self.connect_line_shifter(m) # Tag is the current db read item after line is shifted out tag = self.db.data if self.debug else self.db.data[0] first_line = Signal() m.d.comb += first_line.eq(watch_lfsr(m, self.vt.y, 0)) # Runs once per line, after line shifter done # DB should be pointing to first word (aka "tag") with m.If(self.line_shifter.done): # Always toggle after showing first line. Also toggle if tag is zero. # By happy coincidence, at reset will also toggle for first line # because first item from DB reads as zero with m.If((tag == 0) | first_line): m.d.comb += self.db.toggle.eq(1) with m.Else(): # If didn't toggle, loop back to start m.d.comb += self.db.next.eq(1) return m