[video member=pervognsen stream_platform=twitch project=bitwise title="Sequential Logic, Part 2" vod_platform=youtube id=kU9QIqdy5i0 annotator=Miblo]
[0:08][Recap and set the stage for the day continuing with :"sequential logic"][:speech]
[0:46][Review the off-by-one issue from yesterday, in which simulate_test() failed to update the module output values after a tick and before calling in to the tester][:"sequential logic" :research]
[2:18][On splitting the update logic into two parts][:"sequential logic" :research]
[3:39][Consult the emitted code of our entire circuit, on the update logic split between update() - computing outputs - and tick() - computing register values][:"sequential logic" :run]
[7:52][Note the fewer yields in example39_test()][:"sequential logic" :research]
[8:50][:Run simulate_test() successfully on example39_test][:emulation :"sequential logic"]
[9:03][Combinational pipelining][:"sequential logic" :speech]
[9:46][Introduce delay() to construct feed-forward register chains][:"sequential logic"]
[13:52][Define Example40 module as a delay][:"sequential logic"]
[15:18][Check the graph of Example40, the delay][:"debug visualisation" :"sequential logic" :run]
[15:54][Create simulation test for Example40][:emulation :"sequential logic"]
[16:46][:Run simulate_test() successfully on example40_test][:emulation :"sequential logic"]
[17:50][A few words on the utility of delay like an operator][:"sequential logic" :speech]
[21:49][Augmenting delay analysis to compute critical paths between internal registers][:profiling :"sequential logic" :speech]
[23:18][Change the DelayAnalyzer use nodes rather than node names][:profiling :"sequential logic"]
[29:45][:Run it to see our delay analysis][:profiling :"sequential logic"]
[30:49][Introduce combinational_multiplier() as a dumb multiplier][:"sequential logic"]
[34:19][:Run simulate_test() on the combinational_multiplier() successfully][:emulation :"sequential logic"]
[34:26][Introduce pipelined_multiplier() interspersing delay() in the combinational_multiplier(), also adding an "enable" control signal in Example42][:"sequential logic"]
[41:56][:Run it and hit runtime error "dictionary changed size during iteration"][:emulation :"sequential logic"]
[42:10][Enable linearize() to handle register discovery][:"code generation"]
[44:08][:Run it successfully][:emulation :"sequential logic"]
[44:13][Create a test of Example42 without pipelining][:"code generation" :emulation :"sequential logic"]
[45:00][:Run it, hit an AttributeError, and investigate the problem in register discovery][:"code generation" :emulation :"sequential logic"]
[50:45][Investigate the project in the combinational_multiplier()][:emulation :"sequential logic"]
[51:39][Pass through the __iter__() of SimulatorInstance while debugging][:"sequential logic"]
[52:06][Step through example42_test() inspecting the values][:emulation :"sequential logic" :run]
[53:28][Fix the "enable" control signal in Example42 to be a single bit][:"sequential logic"]
[53:43][:Run simulate_test() on example42_test to completion][:emulation :"sequential logic"]
[54:22][Change pipelined_multiplier() to use the current values of x and y before reassigning them][:"sequential logic"]
[56:00][:Run simulate_test() on example42_test, hit our test assertion and step in to pipelined_multiplier() to investigate][:emulation :"sequential logic"]
[58:05][Check out our generated code to see self.r8 being set incorrectly][:"sequential logic" :run]
[59:47][Change Example42 to set p and p_valid to their output() separately from the pipelined_multiplier() call][:"sequential logic"]
[1:00:06][:Run it to see the same p_valid value as before, and check the code][:"sequential logic" :run]
[1:01:51][Scrutinise linearize() to discover the issue][:"code generation" :research]
[1:02:42][Prevent name collision during register discovery in linearize()][:"code generation"]
[1:06:43][Realise that both update() and tick() need to use the same register names, and consider how to resolve our failure][:"code generation" :speech]
[1:07:28][Make linearize() use a shared dictionary for registers][:"code generation"]
[1:08:27][:Run it still unsuccessfully, with the same p_valid() value as before][:"code generation"]
[1:08:41][Make linearize() clone the counter as well][:"code generation"]
[1:09:01][:Run it successfully][:emulation :"code generation"]
[1:09:17][Try to clean up the update_instructions and tick_instructions split in linearize()][:"code generation"]
[1:10:55][:Run it and hit an AttributeError][:"code generation"]
[1:12:20][Revert linearize() to the working version][:"code generation"]
[1:12:56][:Run simulate_test() on the real example42_test unsuccessfully, and inspect the computed values][:emulation :"sequential logic"]
[1:16:56][Reformulate combinational_multiplier() as a parallel assignment][:"sequential logic"]
[1:17:51][:Run it to see that that works][:emulation :"sequential logic"]
[1:17:55][Change pipelined_multiplier() to use this new parallel formulation of combinational_multiplier()][:"sequential logic"]
[1:18:54][Enable delay() to handle tuples][:"sequential logic"]
[1:19:25][:Run it to see it still doesn't work][:"sequential logic"]
[1:19:28][Fix pipelined_multiplier() to iterate over all the bits][:"sequential logic"]
[1:19:33][:Run the pipelined multiplier successfully][:"sequential logic"]
[1:20:21][Introduce example42_test_producer() and example42_test_consumer() to give us two different agents to feed and consume from the multiplier][:"sequential logic"]
[1:22:04][Enable simulate_test() to handle multiple testers][:emulation]
[1:24:37][:Run it to ensure that the existing tests do run][:emulation]
[1:24:55][Write a simulation test of our multiplier producer and consumer running in parallel][:emulation :"sequential logic"]
[1:25:23][:Run simulate_test() on our multiplier producer and consumer, fail the test and investigate why][:emulation :"sequential logic"]
[1:28:43][Fix example42_test_consumer() to correctly yield][:"sequential logic"]
[1:29:17][:Run simulate_test() on our multiplier with parallel producer and consumer successfully][:emulation :"sequential logic"]
[1:29:25][@spriithy][New place?]
[1:29:45][Reflect on the utility of running more than one test co-routine at once][:emulation :"sequential logic" :speech]
[1:30:10][Further decouple the producer and consumer using a separate "expected" queue[ref
    site="Python 3.7.0 documentation"
    page="17.7. queue — A synchronized queue class"
    url=https://docs.python.org/3/library/queue.html]][:"sequential logic"]
[1:33:23][:Run it to see that example42_test_consumer() never gets to run, and investigate why][:emulation :"sequential logic"]
[1:35:30][:Run it again to see that example42_test_consumer() now gets to run][:emulation :"sequential logic"]
[1:36:32][Revert the decoupling][:"sequential logic"]
[1:36:57][:Run it successfully][:"sequential logic"]
[1:37:17][Reflect on our pipelined system, impressing the need to keep thing in phase when mixing, and the utility of pipelining to improve the throughput of any combinational circuit][:"sequential logic" :speech]
[1:43:36][Pipelining a 1024-bit carry-propagate adder][:"sequential logic" :speech]
[1:51:37][That's it for the main stream][:speech]
[/video]
