diff --git a/himbaechel/uarch/gowin/constids.inc b/himbaechel/uarch/gowin/constids.inc index 53ca6a23..5307eaee 100644 --- a/himbaechel/uarch/gowin/constids.inc +++ b/himbaechel/uarch/gowin/constids.inc @@ -1038,6 +1038,9 @@ X(RPLLA) X(PLLVR) X(PLLA) +// ADC +X(ADC) + // primitive attributes X(INIT) X(FF_USED) diff --git a/himbaechel/uarch/gowin/cst.cc b/himbaechel/uarch/gowin/cst.cc index b02fab9f..e502750f 100644 --- a/himbaechel/uarch/gowin/cst.cc +++ b/himbaechel/uarch/gowin/cst.cc @@ -80,6 +80,7 @@ struct GowinCstReader constrained_cells.insert(std::make_pair(cellId, belId)); } }; + pool 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 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) { diff --git a/himbaechel/uarch/gowin/gowin.h b/himbaechel/uarch/gowin/gowin.h index aaeb8d42..22b62dec 100644 --- a/himbaechel/uarch/gowin/gowin.h +++ b/himbaechel/uarch/gowin/gowin.h @@ -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. diff --git a/himbaechel/uarch/gowin/gowin_arch_gen.py b/himbaechel/uarch/gowin/gowin_arch_gen.py index 5058005c..8e211829 100644 --- a/himbaechel/uarch/gowin/gowin_arch_gen.py +++ b/himbaechel/uarch/gowin/gowin_arch_gen.py @@ -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') diff --git a/himbaechel/uarch/gowin/pack.cc b/himbaechel/uarch/gowin/pack.cc index ed3433ec..5c09f7a5 100644 --- a/himbaechel/uarch/gowin/pack.cc +++ b/himbaechel/uarch/gowin/pack.cc @@ -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();