fromtypingimportListfromnmigen.assertsimportAssert,Cover,AssumefromnmigenimportElaboratable,Module,Signal,Muxfromnmigen.back.pysimimportSimulator,Delayfromnmigen.buildimportPlatformfromnmigen.cliimportmain_parser,main_runnerclassClocky(Elaboratable):def__init__(self):self.x=Signal(7)self.load=Signal()self.value=Signal(7)defelaborate(self,platform:Platform)->Module:m=Module()withm.If(self.load):m.d.sync+=self.x.eq(Mux(self.value<=100,self.value,100))withm.Elif(self.x==100):m.d.sync+=self.x.eq(0)withm.Else():m.d.sync+=self.x.eq(self.x+1)returnmdefports(self)->List[Signal]:return[self.x,self.load,self.value]if__name__=="__main__":parser=main_parser()args=parser.parse_args()m=Module()m.submodules.clocky=clocky=Clocky()#main_runner(parser, args, m, ports=[] + clocky.ports())load=Signal()value=Signal(7)m.d.comb+=clocky.load.eq(load)m.d.comb+=clocky.value.eq(value)sim=Simulator(m)sim.add_clock(1e-6)defprocess():yieldyieldload.eq(1)yieldvalue.eq(95)yieldyieldload.eq(0)yieldyieldyieldyieldyieldyieldyieldyieldyieldsim.add_sync_process(process)withsim.write_vcd("test.vcd","test.gtkw",traces=[]+clocky.ports()):sim.run()
After simulation, here is the waveform.
As you can see, x will be loaded when load is high and after the pulse, x will keep increasing each cycle until it reaches 100. Then x will be clear.
You might want to ask, why would x is not loaded at rising edge of load? That is becuase load is changing not simutanously with clock edge but infinitesimally close after clock rising edge. Which also applys to clock falling edge.
Formal verification
We remove simulator part and add main_runner into our clocky.py.