diff --git a/himbaechel/uarch/gowin/constids.inc b/himbaechel/uarch/gowin/constids.inc index 5307eaee..b781f37c 100644 --- a/himbaechel/uarch/gowin/constids.inc +++ b/himbaechel/uarch/gowin/constids.inc @@ -997,6 +997,7 @@ X(IBUF) X(OBUF) X(IOBUF) X(TBUF) +X(TLVDS_IBUF_ADC) X(TLVDS_OBUF) X(TLVDS_TBUF) X(TLVDS_IBUF) @@ -1040,6 +1041,7 @@ X(PLLA) // ADC X(ADC) +X(ADC_IO) // primitive attributes X(INIT) @@ -1067,6 +1069,7 @@ X(I0) X(I1) X(I2) X(I3) +X(ADCEN) X(OEN) X(S0) X(SEL) diff --git a/himbaechel/uarch/gowin/cst.cc b/himbaechel/uarch/gowin/cst.cc index e502750f..c9097850 100644 --- a/himbaechel/uarch/gowin/cst.cc +++ b/himbaechel/uarch/gowin/cst.cc @@ -160,7 +160,7 @@ struct GowinCstReader row = col; col = 1; } - adc_ios.insert(ctx->idf("%d/X%dY%d", std::stoi(match[1]), row - 1, col - 1)); + adc_ios.insert(ctx->idf("%d/X%dY%d", std::stoi(match[1]), col - 1, row - 1)); } break; case clock: { // CLOCK name BUFG|S=# std::string which_clock = match[2]; diff --git a/himbaechel/uarch/gowin/gowin.h b/himbaechel/uarch/gowin/gowin.h index 22b62dec..3aff35b6 100644 --- a/himbaechel/uarch/gowin/gowin.h +++ b/himbaechel/uarch/gowin/gowin.h @@ -28,7 +28,7 @@ inline bool is_io(const CellInfo *cell) { return type_is_io(cell->type); } inline bool type_is_diffio(IdString cell_type) { return cell_type.in(id_ELVDS_IOBUF, id_ELVDS_IBUF, id_ELVDS_TBUF, id_ELVDS_OBUF, id_TLVDS_IOBUF, id_TLVDS_IBUF, - id_TLVDS_TBUF, id_TLVDS_OBUF); + id_TLVDS_TBUF, id_TLVDS_OBUF, id_TLVDS_IBUF_ADC); } inline bool is_diffio(const CellInfo *cell) { return type_is_diffio(cell->type); } diff --git a/himbaechel/uarch/gowin/gowin_arch_gen.py b/himbaechel/uarch/gowin/gowin_arch_gen.py index 8e211829..6a9668af 100644 --- a/himbaechel/uarch/gowin/gowin_arch_gen.py +++ b/himbaechel/uarch/gowin/gowin_arch_gen.py @@ -925,6 +925,10 @@ def create_io_tiletype(chip: Chip, db: chipdb, x: int, y: int, ttyp: int, tdesc: tt.add_bel_pin(io, "I", portmap['I'], PinType.INPUT) tt.add_bel_pin(io, "OEN", portmap['OE'], PinType.INPUT) tt.add_bel_pin(io, "O", portmap['O'], PinType.OUTPUT) + if 'ADCEN' in portmap: + tt.create_wire(portmap['ADCEN'], "IO_ADCEN") + tt.add_bel_pin(io, "ADCEN", portmap['ADCEN'], PinType.INPUT) + # bottom io if 'BOTTOM_IO_PORT_A' in portmap and portmap['BOTTOM_IO_PORT_A']: if not tt.has_wire(portmap['BOTTOM_IO_PORT_A']): diff --git a/himbaechel/uarch/gowin/pack.cc b/himbaechel/uarch/gowin/pack.cc index 5c09f7a5..44e519b0 100644 --- a/himbaechel/uarch/gowin/pack.cc +++ b/himbaechel/uarch/gowin/pack.cc @@ -232,7 +232,8 @@ struct GowinPacker p = net_only_drives(ctx, ci.ports.at(id_O).net, is_iob, id_I, true); n = net_only_drives(ctx, ci.ports.at(id_OB).net, is_iob, id_I, true); break; - case ID_ELVDS_IBUF: /* fall-through */ + case ID_TLVDS_IBUF_ADC: /* fall-through */ + case ID_ELVDS_IBUF: /* fall-through */ case ID_TLVDS_IBUF: p = net_driven_by(ctx, ci.ports.at(id_I).net, is_iob, id_O); n = net_driven_by(ctx, ci.ports.at(id_IB).net, is_iob, id_O); @@ -254,6 +255,10 @@ struct GowinPacker pn_cells.first->setParam(id_DIFF_TYPE, ci.type.str(ctx)); pn_cells.second->setParam(id_DIFF, std::string("N")); pn_cells.second->setParam(id_DIFF_TYPE, ci.type.str(ctx)); + if (ci.params.count(id_ADC_IO)) { + pn_cells.first->setParam(id_ADC_IO, ci.params.at(id_ADC_IO)); + pn_cells.second->setParam(id_ADC_IO, ci.params.at(id_ADC_IO)); + } } void switch_diff_ports(CellInfo &ci, std::pair &pn_cells, @@ -318,6 +323,17 @@ struct GowinPacker ci.movePortTo(id_O, iob_p, id_O); return; } + if (ci.type.in(id_TLVDS_IBUF_ADC)) { + nets_to_remove.push_back(ci.getPort(id_I)->name); + ci.disconnectPort(id_I); + nets_to_remove.push_back(ci.getPort(id_IB)->name); + ci.disconnectPort(id_IB); + iob_p->disconnectPort(id_O); + iob_n->disconnectPort(id_O); + + ci.movePortTo(id_ADCEN, iob_p, id_ADCEN); + return; + } } // ===================================