-
Notifications
You must be signed in to change notification settings - Fork 50
Global Variables
Global variables maintain state between function execution... like you would expect in C.
static
local variables are identical to 'global variables' discussed here, prefer static locals to avoid polluting global namespace.
Functions that use global variables are referred to as "global functions". Global variables are hardware registers. Global variables belong to a single function and cannot be used to move data between functions. (yet?) See clock crossings for wires + message passing like interfaces for moving data around in global scope.
The most straight forward example of global variables is something like blinking LEDs.
Below describes a slightly more advanced combining of feed-forward global state and pipelined logic:
Here is PipelineC code that toggles between multiplying or dividing two floating point numbers depending on a global select variable. First set of numbers is multiplied, the next divided, the next multiplied, etc. This global toggling variable is a single hardware register in addition to the pipeline registers for the main function.
// uint1_t select; // Prefer static locals instead
uint1_t toggle_select()
{
static uint1_t select;
if(select)
{
select = 0;
}
else
{
select = 1;
}
return select;
}
float main(float x, float y)
{
float rv;
if(toggle_select())
{
rv = x * y;
}
else
{
rv = x / y;
}
return rv;
}
But whats the deal with putting the toggle in a separate function? Take a look at these rules for globals:
- Global functions cannot be pipelined. That is, these functions fundamentally limit the operating frequency of your design and should be made as simple as possible.
- Each call to a global function or function containing global function calls creates separate copies of the global variables. Ex. Calling 'toggle_select()' again would not be toggling the same 'select' as the previous function call. Two instances of 'select' would exist.
- Global functions or functions containing global function when called conditionally (ex. inside an IF) infer clock enable logic for all registers in the funciton. Not all global functions support clock enabling / conditionally calling...todo on detecting/enforcing this...
Wait, wait, wait, what hardware does this actually implement?
The above example implements two separate floating point modules - one for the divide, one for the multiply. The two operations are performed in parallel and their results muxed to get the return value.
Aw, wow, no resource sharing? Well ok, advanced user, the floating point operators are implemented as PipelineC functions that you can modify. Combine the code for the divide and multiply into one function, add in the muxing logic, and begin finding places where you can share variables/operators/etc to construct this shared multiplier/divider unit of yours - and probably shoot me an email.
What if I need global state but don't want to limit the operating frequency of my design? Well, you can use volatile global variables but they are pretty weird...