From 31b4e9fe1185325e12d30e22398c0f603f71ea77 Mon Sep 17 00:00:00 2001 From: Wolfgang Spraul Date: Thu, 13 Dec 2012 05:30:34 -0500 Subject: [PATCH] more clock routing --- autotest.c | 7 +- libs/bit_frames.c | 205 +++++++++++++++++++++++++++++++++++++++--- libs/control.c | 42 +++++++-- libs/control.h | 6 +- libs/model.h | 7 +- libs/model_helper.c | 50 +++++------ libs/model_switches.c | 2 +- libs/parts.h | 4 + 8 files changed, 264 insertions(+), 59 deletions(-) diff --git a/autotest.c b/autotest.c index 0e2e98c..1e3ec85 100644 --- a/autotest.c +++ b/autotest.c @@ -734,7 +734,8 @@ static int test_iologic_switches2(struct test_state* tstate, int iob_y, int iob_ if (construct_sw_chain(&chain, tstate->model, switch_to.dest_y, switch_to.dest_x, switch_to.dest_connpt, from_to, - /*max_depth*/ -1, /*block_list*/ 0, /*block_list_len*/ 0)) + /*max_depth*/ -1, SWCHAIN_DEFAULT, + /*block_list*/ 0, /*block_list_len*/ 0)) FAIL(EINVAL); while (fpga_switch_chain(&chain) != NO_CONN) { @@ -1765,7 +1766,7 @@ static int test_clock_routing(struct test_state* tstate) fdev_iob_input(tstate->model, iob_clk_y, iob_clk_x, iob_clk_type_idx, IO_LVCMOS33); - logic_y = 58; + logic_y = 65; // down from hclk at 62 logic_x = 13; logic_type_idx = DEV_LOG_M_OR_L; @@ -1818,7 +1819,7 @@ static int test_clock_routing(struct test_state* tstate) if (!is_aty(Y_ROW_HORIZ_AXSYMM, tstate->model, y)) continue; logic_type_idx = DEV_LOG_M_OR_L; - logic_y = y-3; + logic_y = y-3; // up from hclk for (logic_x = 13; logic_x <= 26; logic_x += 13) { fdev_logic_a2d_lut(tstate->model, logic_y, logic_x, logic_type_idx, LUT_A, 6, "A1", ZTERM); diff --git a/libs/bit_frames.c b/libs/bit_frames.c index de12484..f612f00 100644 --- a/libs/bit_frames.c +++ b/libs/bit_frames.c @@ -13,6 +13,7 @@ static uint8_t* get_first_minor(struct fpga_bits* bits, int row, int major) { int i, num_frames; + if (row < 0) { HERE(); return 0; } num_frames = 0; for (i = 0; i < major; i++) num_frames += get_major_minors(XC6SLX9, i); @@ -593,6 +594,7 @@ static int extract_type2(struct extract_state* es) // // find and enable reg-switch for gclk_pin[i] + // the writing equivalent is in write_inner_term_sw() // fpga_find_iob(es->model, es->model->pkg->gclk_pin[i], @@ -1907,12 +1909,14 @@ static int extract_center_switches(struct extract_state *es) RC_RETURN(es->model); } -static int extract_hclk_switches(struct extract_state *es) +static int extract_gclk_center_vert_sw(struct extract_state *es) { int word, cur_row, cur_minor, cur_pin, i, hclk_y; uint8_t *ma0_bits; RC_CHECK(es->model); + // Switches in the vertical center column that are routing gclk + // signals to the left and right side of the chip. for (cur_row = 0; cur_row < es->model->die->num_rows; cur_row++) { hclk_y = row_to_hclk(cur_row, es->model); RC_ASSERT(es->model, hclk_y != -1); @@ -1946,13 +1950,95 @@ static int extract_hclk_switches(struct extract_state *es) word &= ~(1<model); } +static int extract_gclk_hclk_updown_sw(struct extract_state *es) +{ + int word, cur_row, x, gclk_pin, hclk_y; + uint8_t *mi0_bits; + + RC_CHECK(es->model); + // Switches in each horizontal hclk row that are routing + // gclk signals and and down to the clocked devices. + + // todo: clk access in left and right IO devs, center devs, + // bram and macc devs as well as special devs not tested + // yet (only XM logic devs tested). + for (cur_row = 0; cur_row < es->model->die->num_rows; cur_row++) { + hclk_y = row_to_hclk(cur_row, es->model); + RC_ASSERT(es->model, hclk_y != -1); + for (x = LEFT_IO_ROUTING; x <= es->model->x_width-RIGHT_IO_ROUTING_O; x++) { + if (!is_atx(X_ROUTING_COL, es->model, x)) + continue; + mi0_bits = get_first_minor(es->bits, cur_row, es->model->x_major[x]); + // each minor (0:15) stores the configuration bits for one gclk + // pin (in the hclk bytes of the minor) + for (gclk_pin = 0; gclk_pin <= 15; gclk_pin++) { + word = frame_get_pinword(mi0_bits + gclk_pin*FRAME_SIZE + XC6_HCLK_POS); + if (word & (1<model); +} + +static int write_hclk_sw(struct fpga_bits *bits, struct fpga_model *model, + int y, int x) +{ + uint8_t *mi0_bits; + struct fpga_tile *tile; + const char *from_str, *to_str; + int i, j, gclk_pin_from, gclk_pin_to, up, word; + + RC_CHECK(model); + + mi0_bits = get_first_minor(bits, which_row(y, model), model->x_major[x]); + RC_ASSERT(model, mi0_bits); + + tile = YX_TILE(model, y, x); + for (i = 0; i < tile->num_switches; i++) { + if (!(tile->switches[i] & SWITCH_USED)) + continue; + from_str = fpga_switch_str(model, y, x, i, SW_FROM); + to_str = fpga_switch_str(model, y, x, i, SW_TO); + + j = sscanf(from_str, "HCLK_GCLK%i_INT", &gclk_pin_from); + RC_ASSERT(model, j == 1); + j = sscanf(to_str, "HCLK_GCLK%i", &gclk_pin_to); + if (j == 1) + up = 0; // down + else { + j = sscanf(to_str, "HCLK_GCLK_UP%i", &gclk_pin_to); + RC_ASSERT(model, j == 1); + up = 1; + } + RC_ASSERT(model, gclk_pin_from == gclk_pin_to); + + word = frame_get_pinword(mi0_bits + gclk_pin_from*FRAME_SIZE + XC6_HCLK_POS); + word |= 1 << (up ? XC6_HCLK_GCLK_UP_PIN : XC6_HCLK_GCLK_DOWN_PIN); + frame_set_pinword(mi0_bits + gclk_pin_from*FRAME_SIZE + XC6_HCLK_POS, word); + } + RC_RETURN(model); +} + static int extract_switches(struct extract_state *es) { int x, y; @@ -1979,7 +2065,8 @@ static int extract_switches(struct extract_state *es) } } extract_center_switches(es); - extract_hclk_switches(es); + extract_gclk_center_vert_sw(es); + extract_gclk_hclk_updown_sw(es); RC_RETURN(es->model); } @@ -2245,12 +2332,99 @@ fail: return rc; } +static int write_inner_term_sw(struct fpga_bits *bits, + struct fpga_model *model, int y, int x) +{ + struct fpga_tile *tile; + const char *from_str, *from_found, *to_str, *to_found; + int i, j, from_idx, to_idx; + + RC_CHECK(model); + + tile = YX_TILE(model, y, x); + for (i = 0; i < tile->num_switches; i++) { + if (!(tile->switches[i] & SWITCH_USED)) + continue; + + from_str = fpga_switch_str(model, y, x, i, SW_FROM); + to_str = fpga_switch_str(model, y, x, i, SW_TO); + RC_ASSERT(model, from_str && to_str); + + if (strstr(from_str, "IBUF") + && strstr(to_str, "CLKPIN")) + continue; + if ((from_found = strstr(from_str, "CLKPIN")) + && (to_found = strstr(to_str, "CKPIN"))) { + struct switch_to_yx_l2 switch_to_yx_l2; + int iob_y, iob_x, iob_idx; + struct fpga_device *iob_dev; + + from_idx = atoi(&from_found[6]); + to_idx = atoi(&to_found[5]); + RC_ASSERT(model, from_idx == to_idx); + + // follow switches backwards to IOB + switch_to_yx_l2.l1.yx_req = YX_DEV_IOB; + switch_to_yx_l2.l1.flags = SWTO_YX_DEF; + switch_to_yx_l2.l1.model = model; + switch_to_yx_l2.l1.y = y; + switch_to_yx_l2.l1.x = x; + switch_to_yx_l2.l1.start_switch = fpga_switch_str_i(model, y, x, i, SW_TO); + switch_to_yx_l2.l1.from_to = SW_TO; + fpga_switch_to_yx_l2(&switch_to_yx_l2); + RC_ASSERT(model, switch_to_yx_l2.l1.set.len); + + // find matching gclk pin + for (j = 0; j < model->pkg->num_gclk_pins; j++) { + if (!model->pkg->gclk_pin[j]) + continue; + + fpga_find_iob(model, model->pkg->gclk_pin[j], + &iob_y, &iob_x, &iob_idx); + RC_CHECK(model); + if (iob_y != switch_to_yx_l2.l1.dest_y + || iob_x != switch_to_yx_l2.l1.dest_x) + continue; + iob_dev = fdev_p(model, iob_y, iob_x, DEV_IOB, iob_idx); + RC_ASSERT(model, iob_dev); + + if (fpga_switch_lookup(model, iob_y, iob_x, + iob_dev->pinw[IOB_OUT_I], + switch_to_yx_l2.l1.dest_connpt) != NO_SWITCH) + break; + } + // set bit + if (j < model->pkg->num_gclk_pins) { + uint16_t u16; + int bits_off; + + bits_off = IOB_DATA_START + + model->pkg->gclk_type2_o[j]*XC6_WORD_BYTES + + XC6_TYPE2_GCLK_REG_SW/XC6_WORD_BITS; + u16 = frame_get_u16(&bits->d[bits_off]); + u16 |= 1<<(XC6_TYPE2_GCLK_REG_SW%XC6_WORD_BITS); + frame_set_u16(&bits->d[bits_off], u16); + continue; + } + // fall-through to unsupported + } + fprintf(stderr, "#E %s:%i unsupported switch " + "y%i x%i %s -> %s\n", __FILE__, __LINE__, + y, x, from_str, to_str); + } + RC_RETURN(model); +} + static int write_switches(struct fpga_bits* bits, struct fpga_model* model) { struct fpga_tile* tile; - int x, y, i, rc; + int x, y, i; RC_CHECK(model); + // We need to identify and take out each enabled switch, whether it + // leads to enabled bits or not. That way we can print unsupported + // switches at the end and keep our model alive and maintainable + // over time. for (x = 0; x < model->x_width; x++) { for (y = 0; y < model->y_height; y++) { if (is_atx(X_ROUTING_COL, model, x) @@ -2258,20 +2432,25 @@ static int write_switches(struct fpga_bits* bits, struct fpga_model* model) && y < model->y_height-BOT_IO_TILES && !is_aty(Y_ROW_HORIZ_AXSYMM|Y_CHIP_HORIZ_REGS, model, y)) { - rc = write_routing_sw(bits, model, y, x); - if (rc) FAIL(rc); + write_routing_sw(bits, model, y, x); continue; } if (is_atyx(YX_DEV_ILOGIC, model, y, x)) { - rc = write_iologic_sw(bits, model, y, x); - if (rc) FAIL(rc); + write_iologic_sw(bits, model, y, x); continue; } - // todo: there are probably switches in logic and - // iob that need bits, and switches in other - // tiles that need no bits... if (is_atyx(YX_DEV_LOGIC|YX_DEV_IOB, model, y, x)) continue; + if (is_atx(X_ROUTING_COL, model, x) + && is_aty(Y_ROW_HORIZ_AXSYMM, model, y)) { + write_hclk_sw(bits, model, y, x); + continue; + } + if (is_atyx(YX_INNER_TERM, model, y, x)) { + write_inner_term_sw(bits, model, y, x); + continue; + } + // print unsupported switches tile = YX_TILE(model, y, x); for (i = 0; i < tile->num_switches; i++) { if (!(tile->switches[i] & SWITCH_USED)) @@ -2283,9 +2462,7 @@ static int write_switches(struct fpga_bits* bits, struct fpga_model* model) } } } - return 0; -fail: - return rc; + RC_RETURN(model); } static int write_logic(struct fpga_bits* bits, struct fpga_model* model) diff --git a/libs/control.c b/libs/control.c index 59d3b56..1dc8fd1 100644 --- a/libs/control.c +++ b/libs/control.c @@ -9,6 +9,7 @@ #include "control.h" #undef DBG_ENUM_SWITCH +#undef DBG_SWITCH_CONNS #undef DBG_SWITCH_TO_YX #undef DBG_SWITCH_TO_REL @@ -1580,13 +1581,14 @@ const char* fmt_swset(struct fpga_model* model, int y, int x, int construct_sw_chain(struct sw_chain* chain, struct fpga_model* model, int y, int x, str16_t start_switch, int from_to, int max_depth, - swidx_t* block_list, int block_list_len) + int flags, swidx_t* block_list, int block_list_len) { RC_CHECK(model); #ifdef DBG_ENUM_SWITCH - printf("construct_sw_chain() %s (%s)\n", + printf("construct_sw_chain() %s (%s) flags %Xh\n", strarray_lookup(&model->str, start_switch), - (from_to == SW_FROM) ? "SW_FROM" : "SW_TO"); + (from_to == SW_FROM) ? "SW_FROM" : "SW_TO", + flags); #endif memset(chain, 0, sizeof(*chain)); chain->model = model; @@ -1594,6 +1596,7 @@ int construct_sw_chain(struct sw_chain* chain, struct fpga_model* model, chain->x = x; chain->from_to = from_to; chain->max_depth = (max_depth < 0) ? SW_SET_SIZE : max_depth; + chain->flags = flags; if (block_list) { chain->block_list = block_list; chain->block_list_len = block_list_len; @@ -1665,7 +1668,8 @@ int fpga_switch_chain(struct sw_chain* ch) if (idx == NO_SWITCH) break; ch->set.sw[ch->set.len-1] = idx; - if (!fpga_switch_is_used(ch->model, ch->y, ch->x, idx) + if ((!(ch->flags & SWCHAIN_EXCLUDING_USED) + || !fpga_switch_is_used(ch->model, ch->y, ch->x, idx)) && switch_list_contains(ch->model, ch->y, ch->x, ch->block_list, ch->block_list_len, idx) == NO_SWITCH) @@ -1718,7 +1722,8 @@ int fpga_switch_chain(struct sw_chain* ch) ch->model, ch->y, ch->x, child_from_to)); #endif - if (fpga_switch_is_used(ch->model, ch->y, ch->x, idx)) + if (ch->flags & SWCHAIN_EXCLUDING_USED + && fpga_switch_is_used(ch->model, ch->y, ch->x, idx)) level_down = 0; if (level_down) { @@ -1784,7 +1789,8 @@ int fpga_switch_chain(struct sw_chain* ch) ch->model, ch->y, ch->x, ch->set.sw[ch->set.len-1], ch->from_to); if (ch->set.sw[ch->set.len-1] != NO_SWITCH) { - if (fpga_switch_is_used(ch->model, ch->y, + if (ch->flags & SWCHAIN_EXCLUDING_USED + && fpga_switch_is_used(ch->model, ch->y, ch->x, ch->set.sw[ch->set.len-1])) { #ifdef DBG_ENUM_SWITCH printf(" skipping used %s\n", @@ -1822,7 +1828,8 @@ int construct_sw_conns(struct sw_conns* conns, struct fpga_model* model, RC_CHECK(model); memset(conns, 0, sizeof(*conns)); construct_sw_chain(&conns->chain, model, y, x, start_switch, - from_to, max_depth, /*block_list*/ 0, /*block_list_len*/ 0); + from_to, max_depth, SWCHAIN_DEFAULT, + /*block_list*/ 0, /*block_list_len*/ 0); RC_RETURN(model); } @@ -1838,11 +1845,18 @@ int fpga_switch_conns(struct sw_conns* conns) if (!conns->chain.set.len) { HERE(); goto internal_error; } +#ifdef DBG_SWITCH_TO_YX + printf("fpga_switch_conns() dest_i %i num_dests %i\n", conns->dest_i, conns->num_dests); +#endif // on the first call, both dest_i and num_dests are 0 while (conns->dest_i >= conns->num_dests) { fpga_switch_chain(&conns->chain); - if (conns->chain.set.len == 0) + if (conns->chain.set.len == 0) { +#ifdef DBG_SWITCH_TO_YX + printf(" no more switches\n"); +#endif return NO_CONN; + } end_of_chain_str = fpga_switch_str_i(conns->chain.model, conns->chain.y, conns->chain.x, conns->chain.set.sw[conns->chain.set.len-1], @@ -1853,8 +1867,17 @@ int fpga_switch_conns(struct sw_conns* conns) fpga_connpt_find(conns->chain.model, conns->chain.y, conns->chain.x, end_of_chain_str, &conns->connpt_dest_start, &conns->num_dests); - if (conns->num_dests) + if (conns->num_dests) { +#ifdef DBG_SWITCH_TO_YX + printf(" %s: %i conns\n", strarray_lookup(&conns->chain.model->str, + end_of_chain_str), conns->num_dests); +#endif break; + } +#ifdef DBG_SWITCH_TO_YX + printf(" %s: no conns\n", strarray_lookup( + &conns->chain.model->str, end_of_chain_str)); +#endif } fpga_conn_dest(conns->chain.model, conns->chain.y, conns->chain.x, conns->connpt_dest_start + conns->dest_i, @@ -1880,6 +1903,7 @@ void printf_swchain(struct fpga_model* model, int y, int x, y, x, strarray_lookup(&model->str, sw), block_list_len ? *block_list_len : 0); if (construct_sw_chain(&chain, model, y, x, sw, from_to, max_depth, + SWCHAIN_DEFAULT, block_list, block_list_len ? *block_list_len : 0)) { HERE(); return; } while (fpga_switch_chain(&chain) != NO_CONN) { diff --git a/libs/control.h b/libs/control.h index b2f675a..7a45d5b 100644 --- a/libs/control.h +++ b/libs/control.h @@ -203,6 +203,9 @@ const char* fmt_swset(struct fpga_model* model, int y, int x, // of switches in a tile, currently 3459 in a slx9 routing tile. #define MAX_SWITCHBOX_SIZE 4000 +#define SWCHAIN_DEFAULT 0 +#define SWCHAIN_EXCLUDING_USED 0x0001 + struct sw_chain { // start and recurring values: @@ -211,6 +214,7 @@ struct sw_chain int x; int from_to; int max_depth; + int flags; // // block_list works as if all switches from or to the ones // on the block list are blocked, that is the recursion will @@ -233,7 +237,7 @@ struct sw_chain int construct_sw_chain(struct sw_chain* chain, struct fpga_model* model, int y, int x, str16_t start_switch, int from_to, int max_depth, - swidx_t* block_list, int block_list_len); + int flags, swidx_t* block_list, int block_list_len); void destruct_sw_chain(struct sw_chain* chain); // Returns 0 if another switchset is returned in chain, or diff --git a/libs/model.h b/libs/model.h index f1f7f57..f6744cd 100644 --- a/libs/model.h +++ b/libs/model.h @@ -292,10 +292,9 @@ int is_atx(int check, struct fpga_model* model, int x); // outside_of_routing is true for anything outside of the outer // boundary of the regular routing area. #define YX_OUTSIDE_OF_ROUTING 0x0400 -#define YX_ROUTING_BOUNDARY 0x0800 -#define YX_X_CENTER_CMTPLL 0x1000 -#define YX_Y_CENTER 0x2000 -#define YX_CENTER 0x4000 +#define YX_X_CENTER_CMTPLL 0x0800 +#define YX_Y_CENTER 0x1000 +#define YX_CENTER 0x2000 int is_atyx(int check, struct fpga_model* model, int y, int x); diff --git a/libs/model_helper.c b/libs/model_helper.c index d724d0a..c9cc5bf 100644 --- a/libs/model_helper.c +++ b/libs/model_helper.c @@ -732,10 +732,6 @@ int is_atyx(int check, struct fpga_model* model, int y, int x) || x > model->x_width-RIGHT_IO_ROUTING_O || y <= TOP_INNER_ROW || y >= model->y_height-BOT_INNER_ROW )) return 1; - if (check & YX_ROUTING_BOUNDARY - && is_atyx(YX_ROUTING_TILE, model, y, x) - && (x == LEFT_IO_ROUTING || x == model->x_width-RIGHT_IO_ROUTING_O - || y == TOP_FIRST_REGULAR || y == model->y_height-BOT_LAST_REGULAR_O)) return 1; if (check & YX_X_CENTER_CMTPLL && is_atx(X_CENTER_CMTPLL_COL, model, x)) return 1; if (check & YX_Y_CENTER @@ -1905,6 +1901,29 @@ enum extra_wires fpga_str2wire(const char* str) } } } + if (!strcmp(_str, "GFAN0")) return GFAN0; + if (!strcmp(_str, "GFAN1")) return GFAN1; + if (!strcmp(_str, "CLK0")) return CLK0; + if (!strcmp(_str, "CLK1")) return CLK1; + if (!strcmp(_str, "SR0")) return SR0; + if (!strcmp(_str, "SR1")) return SR1; + if (!strcmp(_str, "GND_WIRE")) return GND_WIRE; + if (!strcmp(_str, "VCC_WIRE")) return VCC_WIRE; + if (!strcmp(_str, "FAN_B")) return FAN_B; + if (!strncmp(_str, "LOGICIN", 7)) { + if (!strcmp(&_str[7], "20")) return LOGICIN20; + if (!strcmp(&_str[7], "21")) return LOGICIN21; + if (!strcmp(&_str[7], "44")) return LOGICIN44; + if (!strcmp(&_str[7], "52")) return LOGICIN52; + if (!strcmp(&_str[7], "_N21")) return LOGICIN_N21; + if (!strcmp(&_str[7], "_N28")) return LOGICIN_N28; + if (!strcmp(&_str[7], "_N52")) return LOGICIN_N52; + if (!strcmp(&_str[7], "_N60")) return LOGICIN_N60; + if (!strcmp(&_str[7], "_S20")) return LOGICIN_S20; + if (!strcmp(&_str[7], "_S36")) return LOGICIN_S36; + if (!strcmp(&_str[7], "_S44")) return LOGICIN_S44; + if (!strcmp(&_str[7], "_S62")) return LOGICIN_S62; + } if ((wtype = base2wire(_str))) { flags = 0; if (_str[3] == 'B') @@ -1932,29 +1951,6 @@ enum extra_wires fpga_str2wire(const char* str) return DW + ((wtype*4 + num)|flags); } } - if (!strcmp(_str, "GFAN0")) return GFAN0; - if (!strcmp(_str, "GFAN1")) return GFAN1; - if (!strcmp(_str, "CLK0")) return CLK0; - if (!strcmp(_str, "CLK1")) return CLK1; - if (!strcmp(_str, "SR0")) return SR0; - if (!strcmp(_str, "SR1")) return SR1; - if (!strcmp(_str, "GND_WIRE")) return GND_WIRE; - if (!strcmp(_str, "VCC_WIRE")) return VCC_WIRE; - if (!strcmp(_str, "FAN_B")) return FAN_B; - if (!strncmp(_str, "LOGICIN", 7)) { - if (!strcmp(&_str[7], "20")) return LOGICIN20; - if (!strcmp(&_str[7], "21")) return LOGICIN21; - if (!strcmp(&_str[7], "44")) return LOGICIN44; - if (!strcmp(&_str[7], "52")) return LOGICIN52; - if (!strcmp(&_str[7], "_N21")) return LOGICIN_N21; - if (!strcmp(&_str[7], "_N28")) return LOGICIN_N28; - if (!strcmp(&_str[7], "_N52")) return LOGICIN_N52; - if (!strcmp(&_str[7], "_N60")) return LOGICIN_N60; - if (!strcmp(&_str[7], "_S20")) return LOGICIN_S20; - if (!strcmp(&_str[7], "_S36")) return LOGICIN_S36; - if (!strcmp(&_str[7], "_S44")) return LOGICIN_S44; - if (!strcmp(&_str[7], "_S62")) return LOGICIN_S62; - } HERE(); return NO_WIRE; } diff --git a/libs/model_switches.c b/libs/model_switches.c index 395c845..4ee14ef 100644 --- a/libs/model_switches.c +++ b/libs/model_switches.c @@ -1308,7 +1308,7 @@ enum wire_type base2wire(const char* str) if (!strncmp(str, "WW4", 3)) return W_WW4; if (!strncmp(str, "NW4", 3)) return W_NW4; - HERE(); + fprintf(stderr, "#E %s:%i base2wire() %s unknown\n", __FILE__, __LINE__, str); return 0; } diff --git a/libs/parts.h b/libs/parts.h index e99827e..0909fb7 100644 --- a/libs/parts.h +++ b/libs/parts.h @@ -130,9 +130,13 @@ const struct xc6_pkg_info *xc6_pkg_info(enum xc6_pkg pkg); #define XC6_WORD_BYTES 2 #define XC6_WORD_BITS (XC6_WORD_BYTES*8) +#define XC6_HCLK_POS 64 #define XC6_HCLK_BYTES 2 #define XC6_HCLK_BITS (XC6_HCLK_BYTES*8) +#define XC6_HCLK_GCLK_UP_PIN 0 +#define XC6_HCLK_GCLK_DOWN_PIN 1 + #define XC6_NULL_MAJOR 0 #define XC6_IOB_MASK_IO 0x00FF00FFFF000000