In embedded systems you have read only and write only registers. How are the two type distinguished in the produced netlist? How one builds a flop which you can only write to and not read from?
asked Feb 22, 2013 at 11:10 725 3 3 gold badges 11 11 silver badges 25 25 bronze badgesIt's all about how the registers are connected to the bus:
if wb_cyc = '1' and wb_stb = '1' then -- accessing the register if wb_we = '1' then -- writing to the register? my_reg
If you leave out the part of the hardware that can read the register then your register is write-only. Similarly if you leave out the part of the hardware that can write to the register then it's read-only.
Sometimes it makes sense to have only one "direction" of data flow. Think of a DAC or an ADC data path.
Also, sometimes it makes sense to have the same address return something other than the data you've written to it. Think of most common microcontrollers; their peripherals tend to have a single address that is a "command" for writes and a "status" for reads.
Another example would be interrupt flags: you read the interrupt register to see which peripheral interrupted the program, then write a '1' to the same bit to clear the interrupt flag. One way to realize that is as follows:
wb_dat_o '0'); if wb_cyc = '1' and wb_stb = '1' then -- register access if wb_we = '1' then -- writing to the register? clear_int
Here you can see that I'm setting a flag to whatever is in bit position 0 in the write case (and I don't care about whatever else they may have written), while in the read case I'm building up a status word made up of individual bits that the peripheral is driving.
aside: I am also explicitly maintaining clear_int at zero in the read case. It's just good coding practice to make sure that all signals are assigned in all code paths in HDL. At best not doing so makes for sloppy code. At worst you can infer latches. Note that I do something similar with wb_dat_o before I even enter the register access case.
Keep in mind that these are only examples to illustrate the point, and that a well-written program will be described more carefully and thoroughly. Also keep in mind that it's 8am here and I haven't had my coffee yet. :-)
answered Feb 22, 2013 at 13:23 akohlsmith akohlsmith 11.4k 1 1 gold badge 37 37 silver badges 63 63 bronze badges \$\begingroup\$I guess you are talking about register in some peripheral part, either part of the processor chip or connected to it in some way.
In a Read Only register the data originates from some external (from the processor's point of view) process and associated hardware, like the receiving of serial data by a UART. Hence that hardware connects to te FF's input, and its outputs connect (for instance) to the processor's bus.
For a Write Only register the situation is the reverse, the processor connects (directly or indirectly) to the FF's inputs, and the FF's outputs connect to some external circuitry. An example is a digital-to-analog converter.
answered Feb 22, 2013 at 11:22 Wouter van Ooijen Wouter van Ooijen 48.8k 1 1 gold badge 65 65 silver badges 140 140 bronze badges \$\begingroup\$ Thanks, what about WR registers? \$\endgroup\$ Commented Feb 22, 2013 at 12:50\$\begingroup\$ A simple WO register (where the non-CPU hardware will not change the contents) can of course be extended to be readable, as a service to the software (so it does not have to remember what was put there when it wants to apply an incremental change). Another type of RW register is one that can be changed by both the software and the hardware, think of a running counter/timer. \$\endgroup\$
Commented Feb 22, 2013 at 13:41 \$\begingroup\$One thing I would suggest you try to do, though alas many designs don't do this consistently, is to divide writable registers into "latching" and "action" categories, with the expectation that a read of a latching register will always return the value written, while a read of an action register's address should be regarded as reading an independent read-only register.
For example, suppose your system has eight latches that detect external events. If those latches sit in one 8-bit register which can be directly read or written by the CPU, or which can be asynchronously set externally, then if user code observes that bit 0 and 2 are set (meaning the register reads 0x05) and wants to clear bit 0 while leaving bit 2 set, trying to write 0x04 to the register just as some event would cause some other bit to become set would have the unfortunate effect of clearing the latch associated with that other event, thus causing it to be missed. If one instead had a "read" address that reports the state of the latches, a "write zeroes" address which allows selected bits to be cleared, and possibly a "write ones" address which allows selected bits to be set, then these problems would not occur.
For things that the CPU is actually supposed to control (as opposed to merely making note of--as was the case with interrupt flags), but where the CPU's ability to control them may be limited by external factors, one should separate out what the CPU is requesting from what it's able to do. For example, if a motor-control output is supposed to be asynchronously switched off by a an external "motor-shutdown" input, that input shouldn't simply clear the "motor-control" output latch which the CPU set. Instead, the CPU should have a latch which says whether it wants the motor to be on, and that latch should not be changed by external factors. A second externally-triggered latch should indicate whether a motor-shutdown signal has arrived; the motor output should then be driven only when the CPU request says "go" and the "shutdown" latch is not tripped, thus allowing the CPU to have separate "commands" for "start this device which it had previously requested to be off, assuming no fault exists", and "acknowledge/clear the fault condition".
Designing hardware to separate out what the computer is asking for versus what the external hardware is currently allowed to do shouldn't be hard, and keeping such things separate as a matter of principle will help avoid bugs that can occur when the CPU--in the process of trying to write one thing--accidentally writes something else.