summaryrefslogtreecommitdiffstats
path: root/verilog.tex
diff options
context:
space:
mode:
authorYann Herklotz <git@yannherklotz.com>2021-04-15 10:38:53 +0100
committerYann Herklotz <git@yannherklotz.com>2021-04-15 10:38:53 +0100
commit2bf1ff846a792ef3007fa1e97928697509f318f7 (patch)
treede842907b30c337f3c20a35f36fc17ede8147fd7 /verilog.tex
parent6363b3998d65dc7a4e45cec0db9b41f69f45fb31 (diff)
downloadoopsla21_fvhls-2bf1ff846a792ef3007fa1e97928697509f318f7.tar.gz
oopsla21_fvhls-2bf1ff846a792ef3007fa1e97928697509f318f7.zip
Update the table
Diffstat (limited to 'verilog.tex')
-rw-r--r--verilog.tex20
1 files changed, 13 insertions, 7 deletions
diff --git a/verilog.tex b/verilog.tex
index cb0d243..e95889c 100644
--- a/verilog.tex
+++ b/verilog.tex
@@ -32,28 +32,34 @@ Nonblocking assignment can therefore be expressed as follows:
Finally, the following rule dictates how the whole module runs in one clock cycle:
\begin{equation*}
- \inferrule[Module]{(\Gamma, \epsilon, \vec{m})\ \downarrow_{\text{module}^{+}} (\Gamma', \Delta') \\ (\Gamma'\ //\ \Delta', \epsilon, \vec{m}) \downarrow_{\text{module}^{-}} (\Gamma'', \Delta'')}{(\Gamma, \yhkeyword{module } \yhconstant{main} \yhkeyword{(...);}\ \vec{m}\ \yhkeyword{endmodule}) \downarrow_{\text{program}} (\Gamma''\ //\ \Delta'')}
+ \inferrule[Module]{(\Gamma, \epsilon, \vec{m})\ \downarrow_{\text{module}} (\Gamma', \Delta')}{(\Gamma, \yhkeyword{module } \yhconstant{main} \yhkeyword{(...);}\ \vec{m}\ \yhkeyword{endmodule}) \downarrow_{\text{program}} (\Gamma'\ //\ \Delta')}
\end{equation*}
where $\Gamma$ is the initial state of all the variables, and $\vec{m}$ is a list of variable declarations and \alwaysblock{}s that $\downarrow_{\text{module}}$ evaluates sequentially to obtain $(\Gamma', \Delta')$. The final state is obtained by merging these maps using the $//$ operator, which gives priority to the right-hand operand in a conflict. This rule ensures that the nonblocking assignments overwrite at the end of the clock cycle any blocking assignments made during the cycle.
\subsection{Changes to the Semantics}
-Four changes were made to the semantics proposed by \citet{loow19_proof_trans_veril_devel_hol} to make it suitable as a HLS target.
+Five changes were made to the semantics proposed by \citet{loow19_proof_trans_veril_devel_hol} to make it suitable as a HLS target.
\paragraph{Adding array support}
The main change is the addition of support for arrays, which are needed to model RAM in Verilog. RAM is needed to model the stack in C efficiently, without having to declare a variable for each possible stack location. % In the original semantics, RAMs (as well as inputs and outputs to the module) could be modelled using a function from variable names (strings) to values, which could be modified accordingly to model inputs to the module. This is quite an abstract description of memory and can also be expressed as an array of bitvectors instead, which is the path we took. This requires the addition of array operators to the semantics and correct reasoning of loads and stores to the array in different \alwaysblock{}s simultaneously.
Consider the following Verilog code:
\begin{center}
-\begin{minted}{verilog}
+\begin{minted}[xleftmargin=40pt,linenos]{verilog}
reg [31:0] x[1:0];
-always @(posedge clk) begin
- x[0] = 1;
- x[1] <= 1;
-end
+always @(posedge clk) begin x[0] = 1; x[1] <= 1; end
\end{minted}
\end{center}
which modifies one array element using blocking assignment and then a second using nonblocking assignment. If the existing semantics were used to update the array, then during the merge, the entire array \texttt{x} from the nonblocking association map would replace the entire array from the blocking association map. This would replace \texttt{x[0]} with its original value and therefore behave incorrectly. Accordingly, we modified the maps so they record updates on a per-el\-em\-ent basis. Our state $\Gamma$ is therefore split up into $\Gamma_{r}$ for instantaneous updates to variables, and $\Gamma_{a}$ for instantaneous updates to arrays; $\Delta$ is split similarly. The merge function then ensures that only the modified indices get updated when $\Gamma_{a}$ is merged with the nonblocking map equivalent $\Delta_{a}$.
+\paragraph{Adding negative edge support}
+To support memory inferrence efficiently and create and reason about a circuit that executes at the negative edge of the clock, support for the negative edge triggered \alwaysblock{}s was added to the semantics. This is shown in the modifications of the \textsc{Module} rule shown below:
+
+\begin{equation*}
+ \inferrule[Module]{(\Gamma, \epsilon, \vec{m})\ \downarrow_{\text{module}^{+}} (\Gamma', \Delta') \\ (\Gamma'\ //\ \Delta', \epsilon, \vec{m}) \downarrow_{\text{module}^{-}} (\Gamma'', \Delta'')}{(\Gamma, \yhkeyword{module } \yhconstant{main} \yhkeyword{(...);}\ \vec{m}\ \yhkeyword{endmodule}) \downarrow_{\text{program}} (\Gamma''\ //\ \Delta'')}
+\end{equation*}
+
+The main execution of the module $\downarrow_{\text{module}}$ is split into $\downarrow_{\text{module}^{+}}$ and $\downarrow_{\text{module}^{-}}$, which are rules that only execute always blocks triggered at the positive and at the negative edge respectively. As in the initial \textsc{Module} rule, the positive edge triggered \alwaysblock{}s are processed in the same way. The output maps $\Gamma'$ and $\Delta'$ are then merged and passed as the blocking assignments map into the negative edge execution, so that all the blocking and nonblocking assignments are present. Finally, all the negative edge triggered \alwaysblock{}s are processed and merged to give the final state.
+
\paragraph{Adding declarations} Explicit support for declaring inputs, outputs and internal variables was added to the semantics to make sure that the generated Verilog also contains the correct declarations. This adds some guarantees to the generated Verilog and ensures that it synthesises and simulates correctly.
\paragraph{Removing support for external inputs to modules} Support for receiving external inputs was removed from the semantics for simplicity, as these are not needed for an HLS target. The main module in Verilog models the main function in C, and since the inputs to a C function shouldn't change during its execution, there is no need for external inputs for Verilog modules.