Skip to content

Commit

Permalink
greenpak4/gp4par: Implemented GP_PGEN block. Fixes #33.
Browse files Browse the repository at this point in the history
azonenberg committed Oct 19, 2016
1 parent 67c4441 commit 835caa9
Showing 7 changed files with 220 additions and 32 deletions.
61 changes: 59 additions & 2 deletions doc/gp4-hdl.tex
Original file line number Diff line number Diff line change
@@ -232,7 +232,6 @@ \section{\namestyle{gp4par} Limitations}
\item Comparators: Global buffer bandwidth selection, speed doubler
\item ADC
\item DAC (partially implemented)
\item PGEN mode of LUT4/PGEN block
\item Wake-Sleep
\item DCMP/PWM
\item Slave SPI
@@ -2733,6 +2732,65 @@ \subsubsection{Verilog Usage Example}
\label{gp-pga-example}
\end{figure}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% GP_PGEN

\pagebreak
\clearpage
\subsection{\tokenstyle{GP\_PGEN}: Pattern Generator}
\label{gp-pgen}

\subsubsection{Introduction}
This primitive represents a digital sequence generator. It outputs a repeating sequence of 2...16 user-selected bits
on successive clock edges.

\subsubsection{Port Descriptions}

\begin{tabularx}{\textwidth}{lllX}
\thinhline
\whenstyle{Port} & \whenstyle{Type} & \whenstyle{Width} & \whenstyle{Function} \\
\thickhline
\tokenstyle{nRST} & Input & 1 & Active-low reset. OUT is set to PATTERN\_DATA[0] during reset.\\
\thinhline
\tokenstyle{CLK} & Input & 1 & Pattern clock\\
\thinhline
\tokenstyle{OUT} & Output & 1 & Generated pattern data.\\
\thinhline
\end{tabularx}

\subsubsection{Parameter Descriptions}

\begin{tabularx}{\textwidth}{lllX}
\thinhline
\whenstyle{Parameter} & \whenstyle{Type} & \whenstyle{Width} & \whenstyle{Function} \\
\thickhline
\tokenstyle{PATTERN\_DATA} & Integer & 16 & The pattern to be generated (LSB sent first). \\
\thinhline
\tokenstyle{PATTERN\_LEN} & Integer & 5 & Length of the pattern to send. \\
\thinhline
\end{tabularx}

\subsubsection{Verilog Usage Example}

The example shown in figure \ref{gp-pgen-example} outputs an alternating sequence of 1s and 0s on the signal
\namestyle{data}, shifting phase after 8 bits have been sent.

\begin{figure}[h]
\begin{lstlisting}
wire por_done;
GP_PGEN #(
.PATTERN_DATA(16'h55AA),
.PATTERN_LEN(5'd16)
) pgen (
.nRST(nrst),
.CLK(clk),
.OUT(data)
);
\end{lstlisting}
\caption{Example usage of \tokenstyle{GP\_PGEN}}
\label{gp-pgen-example}
\end{figure}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% GP_POR

@@ -2784,7 +2842,6 @@ \subsubsection{Verilog Usage Example}
\label{gp-por-example}
\end{figure}


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% GP_PWRCTL

7 changes: 7 additions & 0 deletions src/gp4par/make_graphs.cpp
Original file line number Diff line number Diff line change
@@ -443,6 +443,13 @@ void MakeDeviceNodes(
node->AddAlternateLabel(inv_label);
}

//Add the second label for the LUT/pattern generator cell, if present
uint32_t pgen_label = AllocateLabel(ngraph, dgraph, lmap, "GP_PGEN");
auto pgen = device->GetPgen();
LogDebug("pgen = %p\n", pgen);
if(pgen)
pgen->GetPARNode()->AddAlternateLabel(pgen_label);

//Make device nodes for the shift registers
uint32_t shreg_label = AllocateLabel(ngraph, dgraph, lmap, "GP_SHREG");
for(unsigned int i=0; i<device->GetShiftRegisterCount(); i++)
5 changes: 5 additions & 0 deletions src/gp4par/par_reporting.cpp
Original file line number Diff line number Diff line change
@@ -67,6 +67,7 @@ void PrintUtilizationReport(PARGraph* netlist, Greenpak4Device* device, unsigned
unsigned int acmp_used = 0;
unsigned int pga_used = 0;
unsigned int abuf_used = 0;
unsigned int delay_used = 0;
for(uint32_t i=0; i<netlist->GetNumNodes(); i++)
{
auto entity = static_cast<Greenpak4BitstreamEntity*>(netlist->GetNodeByIndex(i)->GetMate()->GetData());
@@ -117,6 +118,8 @@ void PrintUtilizationReport(PARGraph* netlist, Greenpak4Device* device, unsigned
pga_used ++;
else if(dynamic_cast<Greenpak4Abuf*>(entity))
abuf_used ++;
else if(dynamic_cast<Greenpak4Delay*>(entity))
delay_used ++;
}
if(device->GetLFOscillator()->GetPARNode()->GetMate() != NULL)
lfosc_used = 1;
@@ -147,6 +150,8 @@ void PrintUtilizationReport(PARGraph* netlist, Greenpak4Device* device, unsigned
PrintRow(" COUNT8_ADV:", counters_8_adv_used, device->Get8BitCounterCount(true));
PrintRow(" COUNT14:", counters_14_used, device->Get14BitCounterCount(false));
PrintRow(" COUNT14_ADV:", counters_14_adv_used, device->Get14BitCounterCount(true));
PrintRow("DELAY:", delay_used, device->GetDelayCount());
//TODO: print {as DELAY / as EDGEDET}
PrintRow("FF:", total_dff_used, device->GetTotalFFCount());
PrintRow(" DFF:", dff_used, device->GetDFFCount());
PrintRow(" DFFSR:", dffsr_used, device->GetDFFSRCount());
11 changes: 11 additions & 0 deletions src/greenpak4/Greenpak4Device.h
Original file line number Diff line number Diff line change
@@ -248,6 +248,17 @@ class Greenpak4Device
unsigned int GetDelayCount()
{ return m_delays.size(); }

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Pattern generator

//TODO: Make this work for parts other than SLG46620V!!!
Greenpak4LUTPgen* GetPgen()
{
if(m_lut4s.size() < 1)
return NULL;
return dynamic_cast<Greenpak4LUTPgen*>(m_lut4s[0]);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// ALL NODES

109 changes: 100 additions & 9 deletions src/greenpak4/Greenpak4LUTPgen.cpp
Original file line number Diff line number Diff line change
@@ -16,6 +16,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA *
**********************************************************************************************************************/

#include <log.h>
#include <Greenpak4.h>

using namespace std;
@@ -32,6 +33,8 @@ Greenpak4LUTPgen::Greenpak4LUTPgen(
unsigned int cbase,
unsigned int order)
: Greenpak4LUT(device, lutnum, matrix, ibase, oword, cbase, order)
, m_pgenMode(false)
, m_patternLen(2)
{

}
@@ -42,7 +45,88 @@ Greenpak4LUTPgen::~Greenpak4LUTPgen()
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Serialization of the truth table
// Pattern generator specific logic

bool Greenpak4LUTPgen::CommitChanges()
{
//Get our cell, or bail if we're unassigned
auto ncell = dynamic_cast<Greenpak4NetlistCell*>(GetNetlistEntity());
if(ncell == NULL)
return true;

//It's a pattern generator
if(ncell->m_type == "GP_PGEN")
{
m_pgenMode = true;

for(auto x : ncell->m_parameters)
{
if(x.first == "PATTERN_DATA")
{
//convert to bit array format
uint32_t truth_table = atoi(x.second.c_str());
unsigned int nbits = 1 << m_order;
for(unsigned int i=0; i<nbits; i++)
{
bool a3 = (i & 8) ? true : false;
bool a2 = (i & 4) ? true : false;
bool a1 = (i & 2) ? true : false;
bool a0 = (i & 1) ? true : false;
m_truthtable[a3*8 | a2*4 | a1*2 | a0] = (truth_table & (1 << i)) ? true : false;
}
}

else if(x.first == "PATTERN_LEN")
{
m_patternLen = atoi(x.second.c_str());
if( (m_patternLen < 2) || (m_patternLen > 16) )
{
LogError("GP_PGEN PATTERN_LEN must be between 2 and 16 (requested %d)\n", m_patternLen);
return false;
}
}

else
{
LogWarning("Cell \"%s\" has unrecognized parameter %s, ignoring\n",
ncell->m_name.c_str(), x.first.c_str());
}
}

return true;
}

//Nope, it's a LUT (or remapped INV etc)
else
{
m_pgenMode = false;
return Greenpak4LUT::CommitChanges();
}
}

vector<string> Greenpak4LUTPgen::GetInputPorts() const
{
vector<string> ret = Greenpak4LUT::GetInputPorts();
ret.push_back("nRST");
ret.push_back("CLK");
return ret;
}

void Greenpak4LUTPgen::SetInput(string port, Greenpak4EntityOutput src)
{
//Pattern gen specific stuff
if(port == "CLK")
m_inputs[2] = src;

else if(port == "nRST")
m_inputs[3] = src;

else
Greenpak4LUT::SetInput(port, src);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Serialization

bool Greenpak4LUTPgen::Load(bool* bitstream)
{
@@ -52,15 +136,22 @@ bool Greenpak4LUTPgen::Load(bool* bitstream)

bool Greenpak4LUTPgen::Save(bool* bitstream)
{
//4-bit counter data in (TODO)
bitstream[m_configBase + 16] = false;
bitstream[m_configBase + 17] = false;
bitstream[m_configBase + 18] = false;
bitstream[m_configBase + 19] = false;
//Save the mode regardless
bitstream[m_configBase + 20] = m_pgenMode;

//Save pattern gen stuff
if(m_pgenMode)
{
//Pattern data is stored in LUT truth table

//Mode (for now, always LUT4)
bitstream[m_configBase + 20] = false;
//4-bit counter data
int len = m_patternLen - 1;
bitstream[m_configBase + 16] = (len & 1) ? true : false;
bitstream[m_configBase + 17] = (len & 2) ? true : false;
bitstream[m_configBase + 18] = (len & 4) ? true : false;
bitstream[m_configBase + 19] = (len & 8) ? true : false;
}

//Save LUT stuff
//Save LUT stuff (input bus etc) regardless
return Greenpak4LUT::Save(bitstream);
}
8 changes: 8 additions & 0 deletions src/greenpak4/Greenpak4LUTPgen.h
Original file line number Diff line number Diff line change
@@ -41,7 +41,15 @@ class Greenpak4LUTPgen : public Greenpak4LUT
virtual bool Load(bool* bitstream);
virtual bool Save(bool* bitstream);

virtual bool CommitChanges();

virtual std::vector<std::string> GetInputPorts() const;

virtual void SetInput(std::string port, Greenpak4EntityOutput src);

protected:
bool m_pgenMode;
int m_patternLen;
};

#endif
51 changes: 30 additions & 21 deletions tests/greenpak4/Ethernet.v
Original file line number Diff line number Diff line change
@@ -19,9 +19,9 @@
`default_nettype none

/**
@brief Minimal 10baseT autonegotiation
@brief Minimal 10baseT autonegotiation implementation
*/
module Ethernet(rst_done, clk_debug, txd);
module Ethernet(rst_done, clk_debug, txd, lcw);

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// I/O declarations
@@ -35,17 +35,17 @@ module Ethernet(rst_done, clk_debug, txd);
(* LOC = "P18" *)
output wire txd;

(* LOC = "P17" *)
output wire lcw;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// System reset stuff
// Power-on-reset configuration

//Power-on reset flag
wire por_done;
GP_POR #(.POR_TIME(500)) por (.RST_DONE(por_done));

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Clock source - 2 MHz RC oscillator

//500 ns per cycle
// Clock source - 2 MHz RC oscillator (500 ns per cycle)

wire clk_hardip;
wire clk_fabric;
@@ -60,37 +60,46 @@ module Ethernet(rst_done, clk_debug, txd);
.CLKOUT_HARDIP(clk_hardip),
.CLKOUT_FABRIC(clk_fabric)
);

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// The actual logic

reg pulse_en = 0;

always @(posedge clk_fabric) begin
pulse_en <= ~pulse_en;
end

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Edge detector for producing ~150 ns FLPs
// Edge detector for producing ~150 ns FLP/NLPs

wire pulse_out;
reg pulse_en = 0;
GP_EDGEDET #(
.DELAY_STEPS(1),
.EDGE_DIRECTION("RISING"),
.GLITCH_FILTER(0)
) delay(
.IN(pulse_en),
.OUT(pulse_out)
.OUT(txd)
);

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Link codeword generation

GP_PGEN #(
.PATTERN_DATA(16'h55aa),
.PATTERN_LEN(5'd16)
) pgen (
.nRST(1'b1),
.CLK(clk_fabric),
.OUT(lcw)
);

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// The actual logic

always @(posedge clk_fabric) begin
pulse_en <= ~pulse_en;
end

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Debug outputs

//Detect when the system reset has completed
always @(posedge clk_fabric)
rst_done <= 1;
rst_done <= 1;

assign clk_debug = clk_fabric;
assign txd = pulse_out;

endmodule

0 comments on commit 835caa9

Please sign in to comment.