Coming from a microcontroller background, it is common to interface to a peripheral (such as a UART) and one can set a register from outside the peripheral, and internally the peripheral can clear it.
I started a new design and sometimes as you do when hacking code quickly I had everything in the same file, everything works great. Then I started trying to clean things up and I wanted to put my UART into it’s own file/module (sorry I don’t know what that is called in myhdl).
But, now the code doesn’t compile, since two separate sequential blocks (again, not sure of the terminology) try to write to the same signal (external to the UART I try to set the transmitting bit, internal I try to clear it).
It might be complex for the myhdl conversion code but it seems possible that IDENTICAL sequential blocks (eg always_seq) with the same clock edge, same reset signal, same other attributes) could be converted into HDL in the same sequential block.
So, as far as code organisation I can have my modules all nicely separated into separate files and I can instantiate them hierarchically, but in terms of the HDL it is as though I was lazy and it was all in the same sequence block.
This could be an option to enable when doing conversion, in case it would have adverse effects on existing code? I don’t see how it would, but I am very inexperienced with HDL etc.
Even in your micro-controller peripheral example the register is both set and cleared by the peripheral itself. The code executed by the processor merely instructs the peripheral to set the register.
HW design is different from software design and more strict. A register can only be set/reset inside a single process (VHDL) or always block(Verilog).
IMO there is no merit in what you are describing; merging two sequential MyHDL blocks into a single V* process. It may perhaps be not that difficult to do but certainly very contrived. And, perhaps most of all, very ugly code (again IMHO).
This sort of design pattern is done in a few Xilinx IP blocks, and IMO is an anti-pattern. Registers should be defined from the perspective of a single side to be read-write, read-only or write-only. Most importantly, in the case of RW, if you write to a register, it should never change without the same side writing to it (the scope should be as tight as possible). This is exactly the same as one of the strongest argument against global variables, which this design pattern amounts to.
That said, it seems that the microcontroller world play fast and loose with variable scope as well (AFAICT because of the misguided notion that it’s not a problem if the module is a singleton module).
Thanks, I will take your advice to heart. To fix up the issue I had to change eg transmitting signal into two signals, start_transmit (external r/w) and transmitting (external r/o). It just hurts to have to duplicate a bunch of signals and also duplicate them in associated if statements etc. no doubt there might be a better way to do it that I don’t know about
@WayneUroda Conceptually, we have actions registers, which are when the software wants to control the FPGA. Those are write-only registers, which present on the HDL side as a single cycle pulse. The checking of status is then done through read-only status registers. Read-write registers are typically used for settings.
No. Uart is actually irrelevant, I’m just using it as an example.
More generic example - I have two modules. One module starts the second module doing something, and the second module finishes doing that all on its own.
When both of these modules are in the same sequential process (as it was when I was hurriedly hacking code together), then a single signal can be used to start the activity/behaviour and also to monitor if it is still doing said activity (because both the “control” code and the “activity” code can write to the same signal in the same sequential process). But when I cleaned up my code it resulted in splitting the control code and activity code into two sequential processes - even though both have exactly the same clock and reset signals it is a conversion error for one signal to be driven from two processes. Therefore I have to split that one signal into a “start” and “active” signal, and any associated if statements where previously were ‘if doBehaviour’ now need to be something like ‘if startBehaviour or doingBehaviour’.
As it was already pointed out to me, my idea to coalecse the two sequential processes into one process, thus allowing code in different .py files/modules/sequential blocks to write to the same signal, is a bad one. Actually just thinking about it now it would not be easily defined or visible at design time what order the writes would occur (which .py file would go first? Would it be deterministic?) so that right there is a damn good reason to abandon my crazy thought bubble!
I’m slightly confused. Is the point you have an asynchronous activity happening? A good way to solve this is with a go/running action/status signals. There are loads of architectures to do what you want to do, but I strongly suspect you want some kind of control block.
Hmm. I’m not sure if I can explain it. I suspect because I am not using the right language, as I am still really fresh to HDL (~18mo) and having started with myhdl maybe I will never really grasp the same concepts.
I’m not sure what a control block is. Yes I split my one signal (previous called “transmit”) into two signals - one is called start_transmit, it is written and cleared by module A, only high for one clock cycle, and the other “transmitting” which is written and cleared by the UART module (and monitored by module A), it is high for many clock cycles. Module A is higher up in the hierarchy than UART module (module A instantiates the UART module). At this point, my explaining and your understanding is just academic since I’ve abandoned the notion of the opening post