Gowin. Implement ADC. (#1597)

ADC support for GW5A-25 chips has been added.

The inputs of this primitive are fixed and do not require routing,
although they can be switched dynamically.

The .CST file also specifies the pins used as signal sources for the
bus0 and bus1 ADC buses.

Signed-off-by: YRabbit <rabbit@yrabbit.cyou>
This commit is contained in:
YRabbit 2025-11-06 18:17:05 +10:00 committed by GitHub
parent 30669eca60
commit d8117e3cad
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 100 additions and 7 deletions

View File

@ -1038,6 +1038,9 @@ X(RPLLA)
X(PLLVR)
X(PLLA)
// ADC
X(ADC)
// primitive attributes
X(INIT)
X(FF_USED)

View File

@ -80,6 +80,7 @@ struct GowinCstReader
constrained_cells.insert(std::make_pair(cellId, belId));
}
};
pool<IdString> adc_ios; // bus#/X#Y#
log_info("Reading constraints...\n");
try {
@ -95,6 +96,7 @@ struct GowinCstReader
std::regex hclkre =
std::regex("INS_LOC +\"([^\"]+)\" +(TOP|RIGHT|BOTTOM|LEFT)SIDE\\[([0,1])\\] *;*[\\s\\S]*");
std::regex clockre = std::regex("CLOCK_LOC +\"([^\"]+)\" +BUF([GS])(\\[([0-7])\\])?[^;]*;.*[\\s\\S]*");
std::regex adcre = std::regex("USE_ADC_SRC +bus([0-9]) +IO([TRBL])([0-9]+) *;.*[\\s\\S]*");
std::smatch match, match_attr, match_pinloc;
std::string line, pinlines[2];
std::vector<IdStringList> constrained_clkdivs;
@ -104,7 +106,8 @@ struct GowinCstReader
ioport,
insloc,
clock,
hclk
hclk,
adc
} cst_type;
while (!in.eof()) {
@ -123,10 +126,14 @@ struct GowinCstReader
if (std::regex_match(line, match, hclkre)) {
cst_type = hclk;
} else {
if ((!line.empty()) && (line.rfind("//", 0) == std::string::npos)) {
log_warning("Invalid constraint: %s\n", line.c_str());
if (std::regex_match(line, match, adcre)) {
cst_type = adc;
} else {
if ((!line.empty()) && (line.rfind("//", 0) == std::string::npos)) {
log_warning("Invalid constraint: %s\n", line.c_str());
}
continue;
}
continue;
}
}
}
@ -135,11 +142,26 @@ struct GowinCstReader
IdString net = ctx->id(match[1]);
auto it = ctx->cells.find(net);
if (cst_type != clock && it == ctx->cells.end()) {
if (cst_type != clock && cst_type != adc && it == ctx->cells.end()) {
log_info("Cell %s not found\n", net.c_str(ctx));
continue;
}
switch (cst_type) {
case adc: { // USE_ADC_SRC bus# IOLOC
int col = std::stoi(match[3]);
int row = 1; // Top
std::string side = match[2].str();
if (side == "R") {
row = col;
col = ctx->getGridDimX();
} else if (side == "B") {
row = ctx->getGridDimY();
} else if (side == "L") {
row = col;
col = 1;
}
adc_ios.insert(ctx->idf("%d/X%dY%d", std::stoi(match[1]), row - 1, col - 1));
} break;
case clock: { // CLOCK name BUFG|S=#
std::string which_clock = match[2];
std::string lw = match[4];
@ -258,6 +280,25 @@ struct GowinCstReader
for (auto &cell : constrained_cells) {
log_info("Cell %s is constrained to %s\n", cell.first.c_str(ctx), cell.second.str(ctx).c_str());
}
if (!adc_ios.empty()) {
log_info("ADC iobufs:\n");
for (auto &bus_io : adc_ios) {
log_info(" bus %s\n", bus_io.c_str(ctx));
}
}
}
if (!adc_ios.empty()) {
for (auto &cell : ctx->cells) {
auto &ci = *cell.second;
if (is_adc(&ci)) {
int idx = 0;
for (auto &bus_io : adc_ios) {
ci.setAttr(ctx->idf("ADC_IO_%d", idx), bus_io.str(ctx));
++idx;
}
}
}
}
return true;
} catch (log_execution_error_exception) {

View File

@ -100,6 +100,10 @@ inline bool is_userflash(const CellInfo *cell) { return type_is_userflash(cell->
inline bool type_is_pll(IdString cell_type) { return cell_type.in(id_rPLL, id_PLLVR); }
inline bool is_pll(const CellInfo *cell) { return type_is_pll(cell->type); }
// Return true if a cell is a ADC
inline bool type_is_adc(IdString cell_type) { return cell_type.in(id_ADC); }
inline bool is_adc(const CellInfo *cell) { return type_is_adc(cell->type); }
// Return true if a cell is a EMCU
inline bool type_is_emcu(IdString cell_type) { return cell_type == id_EMCU; }
inline bool is_emcu(const CellInfo *cell) { return type_is_emcu(cell->type); }
@ -254,6 +258,8 @@ enum
PINCFG_Z = 400,
ADC_Z = 401,
// The two least significant bits encode Z for 9-bit adders and
// multipliers, if they are equal to 0, then we get Z of their common
// 18-bit equivalent.

View File

@ -75,7 +75,8 @@ MIPIIBUF_Z = 302
DLLDLY_Z = 303 # : 305 reserve for 2 DLLDLYs
PINCFG_Z = 400 #
PINCFG_Z = 400
ADC_Z = 401
DSP_Z = 509
@ -463,7 +464,7 @@ def create_nodes(chip: Chip, db: chipdb):
for i in range(5):
nodes.append([NodeWire(x, y, f'COUT{i}'),
NodeWire(x, y, f'CIN{i + 1}')]);
# gobal carry chain
# global carry chain
if x > 1 and chip.tile_type_at(x - 1, y).extra_data.tile_class == chip.strs.id('LOGIC'):
nodes.append([NodeWire(x, y, f'CIN0'),
NodeWire(x - 1, y, f'COUT5')])
@ -788,6 +789,17 @@ def create_extra_funcs(tt: TileType, db: chipdb, x: int, y: int):
for pin, wire in desc['inputs'].items():
tt.create_wire(wire, "PLL_I")
tt.add_bel_pin(pll, pin, wire, PinType.INPUT)
elif func == 'adc':
pll = tt.create_bel("ADC", "ADC", z = ADC_Z)
for pin, wire in desc['outputs'].items():
tt.create_wire(wire, "ADC_O")
tt.add_bel_pin(pll, pin, wire, PinType.OUTPUT)
for pin, wire in desc['inputs'].items():
if pin == 'CLK' or pin == 'MDRP_CLK':
tt.create_wire(wire, "TILE_CLK")
else:
tt.create_wire(wire, "ADC_I")
tt.add_bel_pin(pll, pin, wire, PinType.INPUT)
elif func == 'gnd_source':
# GND is the logic low level generator
tt.create_wire('VSS', 'GND', const_value = 'VSS')

View File

@ -4073,6 +4073,34 @@ struct GowinPacker
}
}
// ===================================
// ADC
// ===================================
void pack_adc(void)
{
log_info("Pack ADC...\n");
for (auto &cell : ctx->cells) {
auto &ci = *cell.second;
if (is_adc(&ci)) {
for (int i = 0; i < 14; ++i) {
if (i < 2) {
ci.renamePort(ctx->idf("MDRP_OPCODE[%d]", i), ctx->idf("MDRP_OPCODE%d", i));
}
if (i < 3) {
ci.renamePort(ctx->idf("VSENCTL[%d]", i), ctx->idf("VSENCTL%d", i));
}
if (i < 8) {
ci.renamePort(ctx->idf("MDRP_WDATA[%d]", i), ctx->idf("MDRP_WDATA%d", i));
ci.renamePort(ctx->idf("MDRP_RDATA[%d]", i), ctx->idf("MDRP_RDATA%d", i));
}
ci.renamePort(ctx->idf("ADCVALUE[%d]", i), ctx->idf("ADCVALUE%d", i));
}
}
}
}
// ===================================
// HCLK -- CLKDIV and CLKDIV2 for now
// ===================================
@ -4557,6 +4585,9 @@ struct GowinPacker
pack_pll();
ctx->check();
pack_adc();
ctx->check();
pack_bsram();
ctx->check();