-
Notifications
You must be signed in to change notification settings - Fork 50
Modules, Hierarchy, Composability
Any function marked as a pragma 'MAIN', ex. #pragma MAIN my_main_inst
, will have its inputs and output arguments/value exposed as a port on the top level generated VHDL module.
ex.
#pragma MAIN_MHZ my_main 100.0
uint8_t my_main(uint8_t input_port_name)
{
return ...
}
entity top is
port(
clk_100p0 : in std_logic;
-- IO for each main func
my_main_input_port_name : in unsigned(7 downto 0);
my_main_return_output : out unsigned(7 downto 0)
);
end top;
It is also proved useful to use shared global variables and (old-style) clock crossing mechanisms to create globally visible versions of ports (so top level ports are not confined to my_main
instance). For example:
#pragma MAIN_MHZ my_main 100.0
uint8_t my_global_input;
uint8_t my_global_output;
uint8_t my_main(uint8_t input_port_name)
{
// Connect top level port to global port
my_global_input = input_port_name;
// Connect top level port to global port
uint8_t output_wire = my_global_output;
return output_wire;
}
// Later, anywhere in code can connect to the other side of those wires
some_input_val = my_global_input;
my_global_output = some_output_val;
// sub.c
output_t sub(input_t input)
{
// Do work on input to get output
return work(input);
}
// top.c
#include "sub.c"
output_t top(input_t input)
{
return sub(input);
}
// top.c
// Globally visible ports/wires
input_t top_to_sub; // Output from top, input to sub
output_t sub_to_top; // Input into top, output from sub
output_t top(input_t input)
{
top_to_sub = input;
return sub_to_top;
}
// sub.c
#include "top.c"
void sub()
{
// Do work on input to get output
input_t input = top_to_sub;
output_t output = work(input);
sub_to_top = output;
}
As opposed to rewiring the LEDs manually through the ports of top
,sub
, and work
using a globally visible point to point wire makes reading and writing arbitrary signals in the design possible.
// leds.c
uint4_t leds; // Globally visible port/wire name
uint4_t leds_module()
{
// Drive the output port with the global wire
return leds;
}
#include "leds.c"
output_t work(input_t input)
{
// Doing lots of complicated stuff
// ...
// Lets drive status leds
leds = 0xF;
// ...
}
output_t sub(input_t input)
{
return work(input);
}
output_t top(input_t input)
{
return sub(input);
}
The above code snippets are pseudo code. The real C syntax for clock crossings is a bit uglier.
For [shared global wires](https://github.com/JulianKemmerer/PipelineC/wiki/Global-Variables in the same clock domain, clock crossings do not need to be used.