Skip to content

Commit 39f583b

Browse files
committedMay 23, 2017
Finished initial DAC support. Fixes #32. DRC could probably be better?
1 parent ab976c9 commit 39f583b

File tree

7 files changed

+156
-51
lines changed

7 files changed

+156
-51
lines changed
 

‎doc/gp4-hdl.tex

-1
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,6 @@ \subsection{\namestyle{gp4par} Device Limitations}
221221
\item Counters: Delay, edge detector, PWM, wake-sleep mode, counter cascading.
222222
All clock sources other than on-chip oscillators.
223223
\item ADC
224-
\item DAC: Inputs from DCMP.
225224
\item Wake-Sleep
226225
\item DCMP/PWM: PWM mode. Inputs from ADC.
227226
\item SPI: ADC buffer mode, parallel output to fabric, clock synchronization.

‎src/gp4par/make_graphs.cpp

+102-5
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ PARGraphNode* MakeNode(
4646
Greenpak4BitstreamEntity* entity,
4747
PARGraph* dgraph);
4848

49-
void InferExtraNodes(
49+
bool InferExtraNodes(
5050
Greenpak4Netlist* netlist,
5151
Greenpak4Device* device,
5252
PARGraph*& ngraph,
@@ -94,7 +94,8 @@ bool BuildGraphs(
9494
return false;
9595

9696
//Infer extra support nodes for things that use hidden functions of others
97-
InferExtraNodes(netlist, device, ngraph, ilmap);
97+
if(!InferExtraNodes(netlist, device, ngraph, ilmap))
98+
return false;
9899

99100
return true;
100101
}
@@ -178,7 +179,7 @@ void ReplicateVREF(
178179
/**
179180
@brief Add extra nodes to handle dependencies between nodes that share hard IP under the hood
180181
*/
181-
void InferExtraNodes(
182+
bool InferExtraNodes(
182183
Greenpak4Netlist* netlist,
183184
Greenpak4Device* device,
184185
PARGraph*& ngraph,
@@ -214,8 +215,102 @@ void InferExtraNodes(
214215
continue;
215216
Greenpak4NetlistCell* netsrc = driver.m_cell;
216217

217-
//We found the source of the net!
218-
LogVerbose("Found a DAC not driven by a power rail\n");
218+
LogDebug("DAC \"%s\" is driven by %s \"%s\"\n",
219+
cell->m_name.c_str(),
220+
netsrc->m_type.substr(3).c_str(),
221+
netsrc->m_name.c_str());
222+
LogIndenter li;
223+
224+
//See if there's already a DCMP driven by the same signal.
225+
vector<Greenpak4NetlistCell*> dcmps;
226+
for(auto jt : net->m_nodeports)
227+
{
228+
if(jt.IsNull())
229+
continue;
230+
if(jt.m_cell->m_type == "GP_DCMP")
231+
dcmps.push_back(jt.m_cell);
232+
}
233+
234+
//If not, create one
235+
if(dcmps.empty())
236+
{
237+
LogDebug("No DCMP driven by this cell, creating a dummy\n");
238+
madeChanges = true;
239+
240+
//Monotonically increasing counter used to ensure unique node IDs
241+
static unsigned int dcmp_id = 1;
242+
243+
//Create the cell
244+
Greenpak4NetlistCell* dcmp = new Greenpak4NetlistCell(module);
245+
dcmp->m_type = "GP_DCMP";
246+
247+
//Tie its negative input to our input
248+
char tmp[128];
249+
for(int i=0; i<8; i++)
250+
{
251+
snprintf(tmp, sizeof(tmp), "INN[%d]", i);
252+
dcmp->m_connections[tmp].push_back(net);
253+
}
254+
255+
//Power down the comparator so it stays out of our way and doesn't waste power
256+
dcmp->m_connections["PWRDN"].push_back(vdd);
257+
258+
//Give it a name
259+
snprintf(tmp, sizeof(tmp), "$auto$make_graphs.cpp:%d:dcmp$%u",
260+
__LINE__,
261+
dcmp_id ++);
262+
dcmp->m_name = tmp;
263+
264+
//Set a special attribute on the cell so that we don't give a "has no loads" warning
265+
dcmp->m_attributes["__IGNORE__NOLOAD__"] = "1";
266+
267+
//LOC it to DCMP1 to ensure correct routing
268+
dcmp->m_attributes["LOC"] = "DCMP_1";
269+
270+
//Add the cell to the module
271+
module->AddCell(dcmp);
272+
273+
//Create the PAR node for it
274+
PARGraphNode* nnode = new PARGraphNode(ilmap[dcmp->m_type], dcmp);
275+
dcmp->m_parnode = nnode;
276+
ngraph->AddNode(nnode);
277+
278+
//Copy the netlist edges to the PAR graph
279+
//TODO: automate this somehow? Seems error-prone to do it twice
280+
for(int i=0; i<8; i++)
281+
{
282+
snprintf(tmp, sizeof(tmp), "INN[%d]", i);
283+
netsrc->m_parnode->AddEdge(driver.m_portname, nnode, tmp);
284+
}
285+
vddn->AddEdge("OUT", nnode, "PWRDN");
286+
287+
dcmps.push_back(dcmp);
288+
continue;
289+
}
290+
291+
//If exactly one, LOC it to DCMP1
292+
else if(dcmps.size() == 1)
293+
{
294+
//TODO: is it possible for IN+ to not be routable? If so, need to make a new DCMP to handle this
295+
auto dcmp = *dcmps.begin();
296+
dcmp->m_attributes["LOC"] = "DCMP_1";
297+
}
298+
299+
//TODO: If there's MORE than one DCMP driven by this signal, need to ensure one of them is placed at DCMP1
300+
else
301+
{
302+
LogError("Can't handle multiple DCMPs and a DAC all sharing the same input yet");
303+
return false;
304+
}
305+
}
306+
307+
//Re-index the graph if we changed it
308+
if(madeChanges)
309+
{
310+
LogNotice("Re-indexing graph because we inferred additional nodes..\n");
311+
netlist->Reindex();
312+
ngraph->IndexNodesByLabel();
313+
madeChanges = false;
219314
}
220315

221316
//Look for IOBs driven by GP_VREF cells
@@ -362,6 +457,8 @@ void InferExtraNodes(
362457
ngraph->IndexNodesByLabel();
363458
//madeChanges = false;
364459
}
460+
461+
return true;
365462
}
366463

367464
/**

‎src/gp4par/par_main.cpp

+1-2
Original file line numberDiff line numberDiff line change
@@ -220,8 +220,7 @@ bool PostPARDRC(PARGraph* netlist, Greenpak4Device* device)
220220
//so nothing to do here
221221
}
222222

223-
//Check for DACs not sharing input with DCMP1 negative, but also not a constant
224-
//TODO: check for DACs with wrong input bit ordering or not same source for all bits
223+
//TODO: Check for DACs not sharing input with DCMP1 negative, but also not a constant
225224

226225
//TODO: check for DCMPs with wrong input bit ordering or not same source for all bits
227226

‎src/greenpak4/Greenpak4DAC.cpp

+10-13
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/***********************************************************************************************************************
2-
* Copyright (C) 2016 Andrew Zonenberg and contributors *
2+
* Copyright (C) 2017 Andrew Zonenberg and contributors *
33
* *
44
* This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General *
55
* Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) *
@@ -152,19 +152,15 @@ bool Greenpak4DAC::Save(bool* bitstream)
152152
return false;
153153
}
154154

155-
//DIN must be either ALL power rails, or NO power rails
156-
int dinPower = 0;
157-
for(unsigned int i=0; i<8; i++)
158-
{
159-
if(m_din[i].IsPowerRail())
160-
dinPower ++;
161-
}
162-
if( (dinPower != 0) && (dinPower != 8) )
155+
//Verify that all 8 bits of each input came from the same entity
156+
//TODO: verify bit ordering?
157+
for(int i=1; i<8; i++)
163158
{
164-
LogError(
165-
"DRC: DAC input data must be driven by either a constant, the SPI bus, or a counter.\n"
166-
"Mixing constant and variable bits is not allowed.\n");
167-
return false;
159+
if(m_din[i].GetRealEntity() != m_din[0].GetRealEntity())
160+
{
161+
LogError("All bits of GP_DAC DIN must come from the same source node\n");
162+
return false;
163+
}
168164
}
169165

170166
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -188,6 +184,7 @@ bool Greenpak4DAC::Save(bool* bitstream)
188184
//Input selector
189185
//WTF, the config is flipped from DAC0 to DAC1??? (see SLG46620V table 40)
190186
//This also applies to the SLG46140 (see SLG46140 table 28).
187+
bool dinPower = (m_din[0].IsPowerRail());
191188
if(m_dacnum == 0)
192189
bitstream[m_cbaseInsel] = !dinPower;
193190
else

‎src/greenpak4/Greenpak4DigitalComparator.cpp

+38-24
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/***********************************************************************************************************************
2-
* Copyright (C) 2016 Andrew Zonenberg and contributors *
2+
* Copyright (C) 2017 Andrew Zonenberg and contributors *
33
* *
44
* This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General *
55
* Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) *
@@ -208,26 +208,33 @@ bool Greenpak4DigitalComparator::Save(bool* bitstream)
208208
bitstream[m_configBase + 4] = m_dcmpMode;
209209

210210
//Verify that all 8 bits of each input came from the same entity
211+
//TODO: verify bit ordering?
211212
for(int i=1; i<8; i++)
212213
{
213-
if(m_inp[i].GetRealEntity() != m_inp[i].GetRealEntity())
214+
if(m_inp[i].GetRealEntity() != m_inp[0].GetRealEntity())
214215
{
215216
LogError("All bits of GP_DCMP INP must come from the same source node\n");
216217
return false;
217218
}
218219

219-
if(m_inn[i].GetRealEntity() != m_inn[i].GetRealEntity())
220+
if(m_inn[i].GetRealEntity() != m_inn[0].GetRealEntity())
220221
{
221222
LogError("All bits of GP_DCMP INN must come from the same source node\n");
222223
return false;
223224
}
224225
}
225226

226-
//If null inputs, but not unused, complain
227+
//Enable bit
228+
//Set this true if our power-down input is anything but Vdd
229+
bool enabled = (m_powerDown != m_device->GetPower());
230+
231+
//If null inputs, but not unused, complain.
232+
//It's OK to be partially connected if we're powered down.
233+
//This can happen if, for example, DCMP1 is being inferred to drive a DAC
227234
bool noClock = (m_clock.IsPowerRail() && !m_clock.GetPowerRailValue());
228235
bool noInP = (m_inp[0].IsPowerRail() && !m_inp[0].GetPowerRailValue());
229236
bool noInN = (m_inn[0].IsPowerRail() && !m_inn[0].GetPowerRailValue());
230-
if(noClock || noInP || noInN)
237+
if( (noClock || noInP || noInN) && enabled )
231238
{
232239
LogError("Missing clock or input to DCMP_%d (%s clock, %s inP, %s inN)\n",
233240
m_cmpNum,
@@ -238,6 +245,31 @@ bool Greenpak4DigitalComparator::Save(bool* bitstream)
238245
return false;
239246
}
240247

248+
//If the negative input is used, hook it up
249+
unsigned int cbase = m_configBase + 7;
250+
if(!noInN)
251+
{
252+
//Invalid input
253+
if(m_innsels.find(m_inn[0]) == m_innsels.end())
254+
{
255+
LogError("Invalid DCMP input (tried to feed %s to %s INN)\n",
256+
m_inn[0].GetDescription().c_str(), GetDescription().c_str());
257+
return false;
258+
}
259+
260+
//Valid input, hook it up
261+
else
262+
{
263+
unsigned int sel = m_innsels[m_inn[0]];
264+
bitstream[cbase + 3] = (sel & 1) ? true : false;
265+
bitstream[cbase + 4] = (sel & 2) ? true : false;
266+
}
267+
}
268+
269+
//If disabled, skip remaining config
270+
if(!enabled)
271+
return true;
272+
241273
//configBase + 5 is input clock source (clkbuf5 = 0, clkbuf2 = 1, anything else = illegal)
242274
auto entity = m_clock.GetRealEntity();
243275
auto ck = dynamic_cast<Greenpak4ClockBuffer*>(entity);
@@ -260,16 +292,14 @@ bool Greenpak4DigitalComparator::Save(bool* bitstream)
260292
bitstream[m_configBase + 6] = m_clockInvert;
261293

262294
//insert powerdown sync bit here for DCMP0, others don't have it
263-
unsigned int cbase = m_configBase + 7;
264295
if(m_cmpNum == 0)
265296
{
266297
bitstream[m_configBase + 7] = m_pdSync;
267298
cbase ++;
268299
}
269300

270301
//Enable bit
271-
//Set this true if our power-down input is anything but Vdd
272-
bitstream[cbase + 0] = (m_powerDown != m_device->GetPower());
302+
bitstream[cbase + 0] = enabled;
273303

274304
//Invalid input
275305
if(m_inpsels.find(m_inp[0]) == m_inpsels.end())
@@ -287,21 +317,5 @@ bool Greenpak4DigitalComparator::Save(bool* bitstream)
287317
bitstream[cbase + 2] = (sel & 2) ? true : false;
288318
}
289319

290-
//Invalid input
291-
if(m_innsels.find(m_inn[0]) == m_innsels.end())
292-
{
293-
LogError("Invalid DCMP input (tried to feed %s to %s INN)\n",
294-
m_inn[0].GetDescription().c_str(), GetDescription().c_str());
295-
return false;
296-
}
297-
298-
//Valid input, hook it up
299-
else
300-
{
301-
unsigned int sel = m_innsels[m_inn[0]];
302-
bitstream[cbase + 3] = (sel & 1) ? true : false;
303-
bitstream[cbase + 4] = (sel & 2) ? true : false;
304-
}
305-
306320
return true;
307321
}

‎tests/greenpak4/CMakeLists.txt

-1
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,6 @@ function(add_greenpak4_bitstream name part)
7878
COMMAND gp4par "--stdout-only"
7979
--usercode 41
8080
--quiet
81-
--debug
8281
--part ${part}
8382
${pcfargs1}
8483
${pcfargs2}

‎tests/greenpak4/slg46620v/Dac.v

+5-5
Original file line numberDiff line numberDiff line change
@@ -61,14 +61,14 @@ module Dac(bg_ok, vout, vout2, wave_sync);
6161
// Oscillators
6262

6363
//The 1730 Hz oscillator
64-
wire clk_108hz;
64+
wire clk_1730hz;
6565
GP_LFOSC #(
6666
.PWRDN_EN(0),
6767
.AUTO_PWRDN(0),
68-
.OUT_DIV(16)
68+
.OUT_DIV(1)
6969
) lfosc (
7070
.PWRDN(1'b0),
71-
.CLKOUT(clk_108hz)
71+
.CLKOUT(clk_1730hz)
7272
);
7373

7474
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -103,7 +103,7 @@ module Dac(bg_ok, vout, vout2, wave_sync);
103103
(* LOC = "COUNT8_6" *)
104104
(* COUNT_EXTRACT = "FORCE" *)
105105
reg[7:0] count = COUNT_MAX;
106-
always @(posedge clk_108hz) begin
106+
always @(posedge clk_1730hz) begin
107107
if(count == 0)
108108
count <= COUNT_MAX;
109109
else
@@ -121,7 +121,7 @@ module Dac(bg_ok, vout, vout2, wave_sync);
121121
.COUNT_TO(COUNT_MAX),
122122
.RESET_MODE("RISING")
123123
) cnt (
124-
.CLK(clk_108hz),
124+
.CLK(clk_1730hz),
125125
.RST(1'b0),
126126
.OUT(wave_sync),
127127
.POUT(count_pout)

0 commit comments

Comments
 (0)
Please sign in to comment.