more clock routing

This commit is contained in:
Wolfgang Spraul 2012-12-10 22:17:01 -05:00
parent b7b2f594a3
commit a3f42ee998
10 changed files with 492 additions and 102 deletions

View File

@ -22,6 +22,7 @@ time_t g_start_time;
struct test_state struct test_state
{ {
int cmdline_skip; int cmdline_skip;
int cmdline_count;
char cmdline_diff_exec[1024]; char cmdline_diff_exec[1024];
int dry_run; int dry_run;
int diff_to_null; int diff_to_null;
@ -78,6 +79,11 @@ static int diff_printf(struct test_state* tstate)
printf("O Skipping diff %i.\n", tstate->next_diff_counter++); printf("O Skipping diff %i.\n", tstate->next_diff_counter++);
return 0; return 0;
} }
if (tstate->cmdline_count != -1
&& tstate->next_diff_counter >= tstate->cmdline_skip + tstate->cmdline_count + 1) {
printf("\nO Finished %i tests.\n", tstate->cmdline_count);
exit(0);
}
snprintf(path, sizeof(path), "%s/autotest_%s_%06i", tstate->tmp_dir, snprintf(path, sizeof(path), "%s/autotest_%s_%06i", tstate->tmp_dir,
tstate->base_name, tstate->next_diff_counter); tstate->base_name, tstate->next_diff_counter);
@ -561,6 +567,7 @@ static int test_routing_sw_from_logic(struct test_state* tstate,
swto.start_switch = fdev_logic_pinstr_i(tstate->model, swto.start_switch = fdev_logic_pinstr_i(tstate->model,
dev->pinw_req_for_cfg[0]|LD1, LOGIC_M); dev->pinw_req_for_cfg[0]|LD1, LOGIC_M);
swto.from_to = SW_TO; swto.from_to = SW_TO;
swto.flags = SWTO_REL_DEFAULT;
swto.rel_y = 0; swto.rel_y = 0;
swto.rel_x = -1; swto.rel_x = -1;
swto.target_connpt = STRIDX_NO_ENTRY; swto.target_connpt = STRIDX_NO_ENTRY;
@ -1061,7 +1068,8 @@ static int test_logic(struct test_state* tstate, int y, int x, int type_idx,
|| (latch_logic || (latch_logic
&& (dev->pinw_req_for_cfg[i] == LI_CLK && (dev->pinw_req_for_cfg[i] == LI_CLK
|| dev->pinw_req_for_cfg[i] == LI_CE))) { || dev->pinw_req_for_cfg[i] == LI_CE))) {
rc = fnet_route_to_inpins(tstate->model, pinw_nets[i], "VCC_WIRE"); rc = fnet_route_to_inpins_s(tstate->model,
pinw_nets[i], "VCC_WIRE");
if (rc) FAIL(rc); if (rc) FAIL(rc);
} }
} }
@ -1745,6 +1753,9 @@ static int test_clock_routing(struct test_state* tstate)
rc = fpga_find_iob(tstate->model, tstate->model->pkg->gclk_pin[i], rc = fpga_find_iob(tstate->model, tstate->model->pkg->gclk_pin[i],
&iob_clk_y, &iob_clk_x, &iob_clk_type_idx); &iob_clk_y, &iob_clk_x, &iob_clk_type_idx);
if (rc) FAIL(rc); if (rc) FAIL(rc);
printf("\nO test %i: gclk pin %s (y%02i x%02i IOB %i)\n",
tstate->next_diff_counter, tstate->model->pkg->gclk_pin[i],
iob_clk_y, iob_clk_x, iob_clk_type_idx);
rc = fdev_iob_input(tstate->model, iob_clk_y, iob_clk_x, rc = fdev_iob_input(tstate->model, iob_clk_y, iob_clk_x,
iob_clk_type_idx, IO_LVCMOS33); iob_clk_type_idx, IO_LVCMOS33);
if (rc) FAIL(rc); if (rc) FAIL(rc);
@ -1782,7 +1793,6 @@ static int test_clock_routing(struct test_state* tstate)
logic_type_idx); logic_type_idx);
fdev_delete(tstate->model, iob_clk_y, iob_clk_x, DEV_IOB, fdev_delete(tstate->model, iob_clk_y, iob_clk_x, DEV_IOB,
iob_clk_type_idx); iob_clk_type_idx);
break;
} }
return 0; return 0;
fail: fail:
@ -1796,8 +1806,8 @@ static void printf_help(const char* argv_0, const char** available_tests)
printf( "\n" printf( "\n"
"fpgatools automatic test suite\n" "fpgatools automatic test suite\n"
"\n" "\n"
"Usage: %s [--test=<name>] [--skip=<num>] [--dry-run]\n" "Usage: %s [--test=<name>] [--skip=<num>] [--count=<num>]\n"
" %*s [--diff=<diff executable>]\n" " %*s [--dry-run] [--diff=<diff executable>]\n"
"Default diff executable: " DEFAULT_DIFF_EXEC "\n" "Default diff executable: " DEFAULT_DIFF_EXEC "\n"
"Output dir: " AUTOTEST_TMP_DIR "\n", argv_0, (int) strlen(argv_0), ""); "Output dir: " AUTOTEST_TMP_DIR "\n", argv_0, (int) strlen(argv_0), "");
@ -1818,7 +1828,7 @@ int main(int argc, char** argv)
struct fpga_model model; struct fpga_model model;
struct test_state tstate; struct test_state tstate;
char param[1024], cmdline_test[1024]; char param[1024], cmdline_test[1024];
int i, param_skip, rc; int i, param_skip, param_count, rc;
const char* available_tests[] = const char* available_tests[] =
{ "logic_cfg", "routing_sw", "io_sw", "iob_cfg", { "logic_cfg", "routing_sw", "io_sw", "iob_cfg",
"lut_encoding", "bufg_cfg", "bufio_cfg", "pll_cfg", "lut_encoding", "bufg_cfg", "bufio_cfg", "pll_cfg",
@ -1840,6 +1850,7 @@ int main(int argc, char** argv)
memset(&tstate, 0, sizeof(tstate)); memset(&tstate, 0, sizeof(tstate));
tstate.cmdline_skip = -1; tstate.cmdline_skip = -1;
tstate.cmdline_count = -1;
tstate.cmdline_diff_exec[0] = 0; tstate.cmdline_diff_exec[0] = 0;
cmdline_test[0] = 0; cmdline_test[0] = 0;
tstate.dry_run = -1; tstate.dry_run = -1;
@ -1871,6 +1882,14 @@ int main(int argc, char** argv)
tstate.cmdline_skip = param_skip; tstate.cmdline_skip = param_skip;
continue; continue;
} }
if (sscanf(argv[i], "--count=%i", &param_count) == 1) {
if (tstate.cmdline_count != -1) {
printf_help(argv[0], available_tests);
return EINVAL;
}
tstate.cmdline_count = param_count;
continue;
}
if (!strcmp(argv[i], "--dry-run")) { if (!strcmp(argv[i], "--dry-run")) {
tstate.dry_run = 1; tstate.dry_run = 1;
continue; continue;
@ -1910,6 +1929,7 @@ int main(int argc, char** argv)
printf("O Test: %s\n", cmdline_test); printf("O Test: %s\n", cmdline_test);
printf("O Diff: %s\n", tstate.cmdline_diff_exec); printf("O Diff: %s\n", tstate.cmdline_diff_exec);
printf("O Skip: %i\n", tstate.cmdline_skip); printf("O Skip: %i\n", tstate.cmdline_skip);
printf("O Count: %i\n", tstate.cmdline_count);
printf("O Dry run: %i\n", tstate.dry_run); printf("O Dry run: %i\n", tstate.dry_run);
printf("\n"); printf("\n");
printf("O Time measured in seconds from 0.\n"); printf("O Time measured in seconds from 0.\n");

View File

@ -106,7 +106,7 @@ static int find_es_switch(struct extract_state* es, int y, int x, swidx_t sw)
return 0; return 0;
} }
static int write_iobs(struct fpga_bits* bits, struct fpga_model* model) static int write_type2(struct fpga_bits* bits, struct fpga_model* model)
{ {
int i, y, x, type_idx, part_idx, dev_idx, first_iob, rc; int i, y, x, type_idx, part_idx, dev_idx, first_iob, rc;
struct fpga_device* dev; struct fpga_device* dev;
@ -571,6 +571,79 @@ fail:
return rc; return rc;
} }
static int extract_type2(struct extract_state* es)
{
int i, bits_off;
uint16_t u16;
RC_CHECK(es->model);
extract_iobs(es);
for (i = 0; i < es->model->pkg->num_gclk_pins; i++) {
if (!es->model->pkg->gclk_pin[i])
continue;
bits_off = IOB_DATA_START
+ es->model->pkg->gclk_type2_o[i]*XC6_WORD_BYTES
+ XC6_TYPE2_GCLK_REG_SW/XC6_WORD_BITS;
u16 = frame_get_u16(&es->bits->d[bits_off]);
if (!u16)
continue;
if (u16 & (1<<(XC6_TYPE2_GCLK_REG_SW%XC6_WORD_BITS))) {
int iob_y, iob_x, iob_idx;
struct fpga_device *iob_dev;
struct switch_to_yx_l2 switch_to_yx_l2;
struct switch_to_rel switch_to_rel;
//
// find and enable reg-switch for gclk_pin[i]
//
fpga_find_iob(es->model, es->model->pkg->gclk_pin[i],
&iob_y, &iob_x, &iob_idx);
RC_CHECK(es->model);
iob_dev = fdev_p(es->model, iob_y, iob_x, DEV_IOB, iob_idx);
RC_ASSERT(es->model, iob_dev);
switch_to_yx_l2.l1.yx_req = YX_X_CENTER_CMTPLL | YX_Y_CENTER;
switch_to_yx_l2.l1.flags = SWTO_YX_CLOSEST;
switch_to_yx_l2.l1.model = es->model;
switch_to_yx_l2.l1.y = iob_y;
switch_to_yx_l2.l1.x = iob_x;
switch_to_yx_l2.l1.start_switch = iob_dev->pinw[IOB_OUT_I];
switch_to_yx_l2.l1.from_to = SW_FROM;
fpga_switch_to_yx_l2(&switch_to_yx_l2);
RC_CHECK(es->model);
if (!switch_to_yx_l2.l1.set.len)
{ HERE(); continue; }
switch_to_rel.model = es->model;
switch_to_rel.start_y = switch_to_yx_l2.l1.dest_y;
switch_to_rel.start_x = switch_to_yx_l2.l1.dest_x;
switch_to_rel.start_switch = switch_to_yx_l2.l1.dest_connpt;
switch_to_rel.from_to = SW_FROM;
switch_to_rel.flags = SWTO_REL_WEAK_TARGET;
switch_to_rel.rel_y = es->model->center_y - switch_to_rel.start_y;
switch_to_rel.rel_x = es->model->center_x - switch_to_rel.start_x;
switch_to_rel.target_connpt = STRIDX_NO_ENTRY;
fpga_switch_to_rel(&switch_to_rel);
RC_CHECK(es->model);
if (!switch_to_rel.set.len)
{ HERE(); continue; }
if (switch_to_rel.set.len != 1) HERE();
RC_ASSERT(es->model, es->num_yx_pos < MAX_YX_SWITCHES);
es->yx_pos[es->num_yx_pos].y = switch_to_rel.start_y;
es->yx_pos[es->num_yx_pos].x = switch_to_rel.start_x;
es->yx_pos[es->num_yx_pos].idx = switch_to_rel.set.sw[0];
es->num_yx_pos++;
u16 &= ~(1<<(XC6_TYPE2_GCLK_REG_SW%XC6_WORD_BITS));
}
if (u16) HERE();
frame_set_u16(&es->bits->d[bits_off], u16);
}
RC_RETURN(es->model);
}
static int lut2str(uint64_t lut, int lut_pos, int lut5_used, static int lut2str(uint64_t lut, int lut_pos, int lut5_used,
char *lut6_buf, char** lut6_p, char *lut5_buf, char** lut5_p) char *lut6_buf, char** lut6_p, char *lut5_buf, char** lut5_p)
{ {
@ -1854,7 +1927,7 @@ int extract_model(struct fpga_model* model, struct fpga_bits* bits)
rc = extract_switches(&es); rc = extract_switches(&es);
if (rc) RC_FAIL(model, rc); if (rc) RC_FAIL(model, rc);
rc = extract_iobs(&es); rc = extract_type2(&es);
if (rc) RC_FAIL(model, rc); if (rc) RC_FAIL(model, rc);
rc = extract_logic(&es); rc = extract_logic(&es);
if (rc) RC_FAIL(model, rc); if (rc) RC_FAIL(model, rc);
@ -2230,7 +2303,7 @@ int write_model(struct fpga_bits* bits, struct fpga_model* model)
for (i = 0; i < sizeof(s_default_bits)/sizeof(s_default_bits[0]); i++) for (i = 0; i < sizeof(s_default_bits)/sizeof(s_default_bits[0]); i++)
set_bitp(bits, &s_default_bits[i]); set_bitp(bits, &s_default_bits[i]);
write_switches(bits, model); write_switches(bits, model);
write_iobs(bits, model); write_type2(bits, model);
write_logic(bits, model); write_logic(bits, model);
RC_RETURN(model); RC_RETURN(model);

View File

@ -8,6 +8,10 @@
#include "model.h" #include "model.h"
#include "control.h" #include "control.h"
#undef DBG_ENUM_SWITCH
#undef DBG_SWITCH_TO_YX
#undef DBG_SWITCH_TO_REL
struct iob_site struct iob_site
{ {
int xy; int xy;
@ -1574,14 +1578,11 @@ const char* fmt_swset(struct fpga_model* model, int y, int x,
return buf[last_buf]; return buf[last_buf];
} }
#undef DBG_ENUM_SWITCH
int construct_sw_chain(struct sw_chain* chain, struct fpga_model* model, 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, int y, int x, str16_t start_switch, int from_to, int max_depth,
swidx_t* block_list, int block_list_len) swidx_t* block_list, int block_list_len)
{ {
int rc; RC_CHECK(model);
#ifdef DBG_ENUM_SWITCH #ifdef DBG_ENUM_SWITCH
printf("construct_sw_chain() %s (%s)\n", printf("construct_sw_chain() %s (%s)\n",
strarray_lookup(&model->str, start_switch), strarray_lookup(&model->str, start_switch),
@ -1601,7 +1602,7 @@ int construct_sw_chain(struct sw_chain* chain, struct fpga_model* model,
chain->internal_block_list = malloc( chain->internal_block_list = malloc(
MAX_SWITCHBOX_SIZE * sizeof(*chain->block_list)); MAX_SWITCHBOX_SIZE * sizeof(*chain->block_list));
if (!chain->internal_block_list) if (!chain->internal_block_list)
FAIL(ENOMEM); RC_FAIL(model, ENOMEM);
chain->block_list = chain->internal_block_list; chain->block_list = chain->internal_block_list;
chain->block_list_len = 0; chain->block_list_len = 0;
} }
@ -1612,9 +1613,7 @@ int construct_sw_chain(struct sw_chain* chain, struct fpga_model* model,
chain->first_round = 1; chain->first_round = 1;
chain->set.len = 1; chain->set.len = 1;
chain->set.sw[0] = FIRST_SW | start_switch; chain->set.sw[0] = FIRST_SW | start_switch;
return 0; RC_RETURN(model);
fail:
return rc;
} }
void destruct_sw_chain(struct sw_chain* chain) void destruct_sw_chain(struct sw_chain* chain)
@ -1824,7 +1823,7 @@ int construct_sw_conns(struct sw_conns* conns, struct fpga_model* model,
memset(conns, 0, sizeof(*conns)); memset(conns, 0, sizeof(*conns));
construct_sw_chain(&conns->chain, model, y, x, start_switch, 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, /*block_list*/ 0, /*block_list_len*/ 0);
return 0; RC_RETURN(model);
} }
void destruct_sw_conns(struct sw_conns* conns) void destruct_sw_conns(struct sw_conns* conns)
@ -1915,18 +1914,32 @@ int fpga_switch_to_yx(struct switch_to_yx* p)
struct sw_conns conns; struct sw_conns conns;
struct sw_set best_set; struct sw_set best_set;
int best_y, best_x, best_distance, distance; int best_y, best_x, best_distance, distance;
int best_num_dests, rc; int best_num_dests;
str16_t best_connpt; str16_t best_connpt;
RC_CHECK(p->model); RC_CHECK(p->model);
rc = construct_sw_conns(&conns, p->model, p->y, p->x, p->start_switch, #ifdef DBG_SWITCH_TO_YX
printf("fpga_switch_to_yx() %s y%02i-x%02i-%s yx_req %Xh flags %Xh\n",
p->from_to == SW_FROM ? "SW_FROM" : "SW_TO",
p->y, p->x, strarray_lookup(&p->model->str, p->start_switch),
p->yx_req, p->flags);
#endif
construct_sw_conns(&conns, p->model, p->y, p->x, p->start_switch,
p->from_to, (p->flags & SWTO_YX_MAX_SWITCH_DEPTH) p->from_to, (p->flags & SWTO_YX_MAX_SWITCH_DEPTH)
? p->max_switch_depth : SW_SET_SIZE); ? p->max_switch_depth : SW_SET_SIZE);
if (rc) FAIL(rc); RC_CHECK(p->model);
best_y = -1; best_y = -1;
while (fpga_switch_conns(&conns) != NO_CONN) { while (fpga_switch_conns(&conns) != NO_CONN) {
if (is_atyx(p->yx_req, p->model, conns.dest_y, conns.dest_x)) { if (!is_atyx(p->yx_req, p->model, conns.dest_y, conns.dest_x))
continue;
#ifdef DBG_SWITCH_TO_YX
printf(" sw %s conn y%02i x%02i %s\n",
fmt_swset(p->model, p->y, p->x,
&conns.chain.set, p->from_to),
conns.dest_y, conns.dest_x,
strarray_lookup(&p->model->str, conns.dest_str_i));
#endif
if (p->flags & SWTO_YX_TARGET_CONNPT if (p->flags & SWTO_YX_TARGET_CONNPT
&& conns.dest_str_i != p->target_connpt) && conns.dest_str_i != p->target_connpt)
continue; continue;
@ -1950,7 +1963,6 @@ int fpga_switch_to_yx(struct switch_to_yx* p)
if (!p->flags & SWTO_YX_CLOSEST) if (!p->flags & SWTO_YX_CLOSEST)
break; break;
} }
}
if (best_y == -1) if (best_y == -1)
p->set.len = 0; p->set.len = 0;
else { else {
@ -1960,9 +1972,7 @@ int fpga_switch_to_yx(struct switch_to_yx* p)
p->dest_connpt = best_connpt; p->dest_connpt = best_connpt;
} }
destruct_sw_conns(&conns); destruct_sw_conns(&conns);
return 0; RC_RETURN(p->model);
fail:
return rc;
} }
void printf_switch_to_yx_result(struct switch_to_yx* p) void printf_switch_to_yx_result(struct switch_to_yx* p)
@ -1977,33 +1987,114 @@ void printf_switch_to_yx_result(struct switch_to_yx* p)
fmt_swset(p->model, p->y, p->x, &p->set, p->from_to)); fmt_swset(p->model, p->y, p->x, &p->set, p->from_to));
} }
int fpga_switch_to_yx_l2(struct switch_to_yx_l2 *p)
{
RC_CHECK(p->l1.model);
fpga_switch_to_yx(&p->l1);
RC_CHECK(p->l1.model);
p->l2_set.len = 0;
if (!p->l1.set.len) {
struct sw_conns conns;
struct switch_to_yx l2 = p->l1;
construct_sw_conns(&conns, p->l1.model, p->l1.y, p->l1.x, p->l1.start_switch,
p->l1.from_to, (p->l1.flags & SWTO_YX_MAX_SWITCH_DEPTH)
? p->l1.max_switch_depth : SW_SET_SIZE);
RC_CHECK(p->l1.model);
while (fpga_switch_conns(&conns) != NO_CONN) {
l2.y = conns.dest_y;
l2.x = conns.dest_x;
l2.start_switch = conns.dest_str_i;
fpga_switch_to_yx(&l2);
RC_CHECK(l2.model);
if (l2.set.len) {
p->l1.set = conns.chain.set;
p->l1.dest_y = l2.dest_y;
p->l1.dest_x = l2.dest_x;
p->l1.dest_connpt = l2.dest_connpt;
p->l2_set = l2.set;
p->l2_y = l2.y;
p->l2_x = l2.x;
break;
}
}
destruct_sw_conns(&conns);
}
RC_RETURN(p->l1.model);
}
int fpga_switch_to_rel(struct switch_to_rel *p) int fpga_switch_to_rel(struct switch_to_rel *p)
{ {
struct sw_conns conns; struct sw_conns conns;
int rc; struct sw_set best_set;
int best_y, best_x, best_distance;
str16_t best_connpt;
RC_CHECK(p->model); RC_CHECK(p->model);
rc = construct_sw_conns(&conns, p->model, p->start_y, p->start_x, #ifdef DBG_SWITCH_TO_REL
printf("fpga_switch_to_rel() %s y%02i-x%02i-%s flags %Xh rel_y %i rel_x %i target_connpt %s\n",
p->from_to == SW_FROM ? "SW_FROM" : "SW_TO",
p->start_y, p->start_x, strarray_lookup(&p->model->str, p->start_switch),
p->flags, p->rel_y, p->rel_x,
p->target_connpt == STRIDX_NO_ENTRY ? "-" :
strarray_lookup(&p->model->str, p->target_connpt));
#endif
construct_sw_conns(&conns, p->model, p->start_y, p->start_x,
p->start_switch, p->from_to, SW_SET_SIZE); p->start_switch, p->from_to, SW_SET_SIZE);
if (rc) FAIL(rc); RC_CHECK(p->model);
p->set.len = 0;
best_y = -1;
while (fpga_switch_conns(&conns) != NO_CONN) { while (fpga_switch_conns(&conns) != NO_CONN) {
#ifdef DBG_SWITCH_TO_REL
printf(" sw %s conn y%02i x%02i %s\n",
fmt_swset(p->model, p->start_y, p->start_x,
&conns.chain.set, p->from_to),
conns.dest_y, conns.dest_x,
strarray_lookup(&p->model->str, conns.dest_str_i));
#endif
if (conns.dest_y != p->start_y + p->rel_y if (conns.dest_y != p->start_y + p->rel_y
|| conns.dest_x != p->start_x + p->rel_x) || conns.dest_x != p->start_x + p->rel_x) {
if (!(p->flags & SWTO_REL_WEAK_TARGET))
continue; continue;
if (best_y != -1) {
int distance = abs(conns.dest_y - (p->start_y+p->rel_y))
+ abs(conns.dest_x - (p->start_x+p->rel_x));
if (distance > best_distance)
continue;
}
best_set = conns.chain.set;
best_y = conns.dest_y;
best_x = conns.dest_x;
best_connpt = conns.dest_str_i;
best_distance = abs(conns.dest_y - (p->start_y+p->rel_y))
+ abs(conns.dest_x - (p->start_x+p->rel_x));
continue;
}
if (p->target_connpt != STRIDX_NO_ENTRY if (p->target_connpt != STRIDX_NO_ENTRY
&& conns.dest_str_i != p->target_connpt) && conns.dest_str_i != p->target_connpt)
continue; continue;
p->set = conns.chain.set; best_set = conns.chain.set;
p->dest_y = conns.dest_y; best_y = conns.dest_y;
p->dest_x = conns.dest_x; best_x = conns.dest_x;
p->dest_connpt = conns.dest_str_i; best_connpt = conns.dest_str_i;
break; break;
} }
if (best_y == -1)
p->set.len = 0;
else {
#ifdef DBG_SWITCH_TO_REL
printf(" sw %s\n", fmt_swset(p->model, p->start_y, p->start_x,
&best_set, p->from_to));
printf(" dest y%02i-x%02i-%s\n", best_y, best_x,
strarray_lookup(&p->model->str, best_connpt));
#endif
p->set = best_set;
p->dest_y = best_y;
p->dest_x = best_x;
p->dest_connpt = best_connpt;
}
destruct_sw_conns(&conns); destruct_sw_conns(&conns);
return 0; RC_RETURN(p->model);
fail:
return rc;
} }
void printf_switch_to_rel_result(struct switch_to_rel* p) void printf_switch_to_rel_result(struct switch_to_rel* p)
@ -2260,9 +2351,153 @@ void fnet_printf(FILE* f, struct fpga_model* model, net_idx_t net_i)
} }
} }
static int fnet_pinw(struct fpga_model *model, net_idx_t net_i,
int out_pinw, int idx)
{
struct fpga_net *net_p;
struct fpga_device *dev_p;
int i, next_idx;
if (model->rc) { HERE(); return -1; };
net_p = fnet_get(model, net_i);
if (!net_p) { HERE(); return -1; };
next_idx = 0;
for (i = 0; i < net_p->len; i++) {
if (!(net_p->el[i].idx & NET_IDX_IS_PINW))
continue;
dev_p = FPGA_DEV(model, net_p->el[i].y,
net_p->el[i].x, net_p->el[i].dev_idx);
if ((out_pinw && (net_p->el[i].idx & NET_IDX_MASK) < dev_p->num_pinw_in)
|| (!out_pinw && (net_p->el[i].idx & NET_IDX_MASK) >= dev_p->num_pinw_in))
continue;
if (next_idx == idx)
return i;
next_idx++;
}
return -1;
}
static int fnet_autoroute_clock(struct fpga_model* model, net_idx_t net_i) static int fnet_autoroute_clock(struct fpga_model* model, net_idx_t net_i)
{ {
return 0; struct fpga_net *net_p;
int out_i, in_i, hclk_y;
struct fpga_device *out_dev, *in_dev;
struct switch_to_yx_l2 switch_to_yx_l2;
struct switch_to_rel switch_to_rel;
RC_CHECK(model);
net_p = fnet_get(model, net_i);
if (!net_p) RC_FAIL(model, EINVAL);
out_i = fnet_pinw(model, net_i, /*out*/ 1, 0);
in_i = fnet_pinw(model, net_i, /*out*/ 0, 0);
if (out_i == -1 || in_i == -1)
RC_FAIL(model, EINVAL);
out_dev = FPGA_DEV(model, net_p->el[out_i].y,
net_p->el[out_i].x, net_p->el[out_i].dev_idx);
in_dev = FPGA_DEV(model, net_p->el[in_i].y,
net_p->el[in_i].x, net_p->el[in_i].dev_idx);
if (out_dev->type != DEV_IOB || in_dev->type != DEV_LOGIC)
RC_FAIL(model, ENOTSUP);
// to regs (l2 allows one intermediate hop)
switch_to_yx_l2.l1.yx_req = YX_X_CENTER_CMTPLL | YX_Y_CENTER;
switch_to_yx_l2.l1.flags = SWTO_YX_CLOSEST;
switch_to_yx_l2.l1.model = model;
switch_to_yx_l2.l1.y = net_p->el[out_i].y;
switch_to_yx_l2.l1.x = net_p->el[out_i].x;
switch_to_yx_l2.l1.start_switch = out_dev->pinw[net_p->el[out_i].idx
& NET_IDX_MASK];
switch_to_yx_l2.l1.from_to = SW_FROM;
fpga_switch_to_yx_l2(&switch_to_yx_l2);
RC_ASSERT(model, switch_to_yx_l2.l1.set.len);
fnet_add_sw(model, net_i, switch_to_yx_l2.l1.y, switch_to_yx_l2.l1.x,
switch_to_yx_l2.l1.set.sw, switch_to_yx_l2.l1.set.len);
if (switch_to_yx_l2.l2_set.len)
fnet_add_sw(model, net_i, switch_to_yx_l2.l2_y, switch_to_yx_l2.l2_x,
switch_to_yx_l2.l2_set.sw, switch_to_yx_l2.l2_set.len);
// to center (possibly over intermediate)
switch_to_rel.dest_y = switch_to_yx_l2.l1.dest_y;
switch_to_rel.dest_x = switch_to_yx_l2.l1.dest_x;
switch_to_rel.dest_connpt = switch_to_yx_l2.l1.dest_connpt;
do {
switch_to_rel.model = model;
switch_to_rel.start_y = switch_to_rel.dest_y;
switch_to_rel.start_x = switch_to_rel.dest_x;
switch_to_rel.start_switch = switch_to_rel.dest_connpt;
switch_to_rel.from_to = SW_FROM;
switch_to_rel.flags = SWTO_REL_WEAK_TARGET;
switch_to_rel.rel_y = model->center_y - switch_to_rel.start_y;
switch_to_rel.rel_x = model->center_x - switch_to_rel.start_x;
switch_to_rel.target_connpt = STRIDX_NO_ENTRY;
fpga_switch_to_rel(&switch_to_rel);
RC_ASSERT(model, switch_to_rel.set.len);
fnet_add_sw(model, net_i, switch_to_rel.start_y, switch_to_rel.start_x,
switch_to_rel.set.sw, switch_to_rel.set.len);
} while (switch_to_rel.dest_y != model->center_y
|| switch_to_rel.dest_x != model->center_x);
// to hclk
RC_ASSERT(model, switch_to_rel.dest_y == model->center_y
&& switch_to_rel.dest_x == model->center_x);
hclk_y = y_to_hclk(net_p->el[in_i].y, model);
RC_ASSERT(model, hclk_y != -1);
do {
switch_to_rel.model = model;
switch_to_rel.start_y = switch_to_rel.dest_y;
switch_to_rel.start_x = switch_to_rel.dest_x;
switch_to_rel.start_switch = switch_to_rel.dest_connpt;
switch_to_rel.from_to = SW_FROM;
switch_to_rel.flags = SWTO_REL_WEAK_TARGET;
switch_to_rel.rel_y = hclk_y - switch_to_rel.start_y;
switch_to_rel.rel_x = 0;
switch_to_rel.target_connpt = STRIDX_NO_ENTRY;
fpga_switch_to_rel(&switch_to_rel);
RC_ASSERT(model, switch_to_rel.set.len);
fnet_add_sw(model, net_i, switch_to_rel.start_y, switch_to_rel.start_x,
switch_to_rel.set.sw, switch_to_rel.set.len);
} while (switch_to_rel.dest_y != hclk_y);
// to routing col
do {
switch_to_rel.model = model;
switch_to_rel.start_y = switch_to_rel.dest_y;
switch_to_rel.start_x = switch_to_rel.dest_x;
switch_to_rel.start_switch = switch_to_rel.dest_connpt;
switch_to_rel.from_to = SW_FROM;
switch_to_rel.flags = SWTO_REL_WEAK_TARGET;
switch_to_rel.rel_y = 0;
switch_to_rel.rel_x = net_p->el[in_i].x-1 - switch_to_rel.start_x;
switch_to_rel.target_connpt = STRIDX_NO_ENTRY;
fpga_switch_to_rel(&switch_to_rel);
RC_ASSERT(model, switch_to_rel.set.len);
fnet_add_sw(model, net_i, switch_to_rel.start_y, switch_to_rel.start_x,
switch_to_rel.set.sw, switch_to_rel.set.len);
} while (switch_to_rel.dest_x != net_p->el[in_i].x-1);
// to logic device routing
switch_to_rel.model = model;
switch_to_rel.start_y = switch_to_rel.dest_y;
switch_to_rel.start_x = switch_to_rel.dest_x;
switch_to_rel.start_switch = switch_to_rel.dest_connpt;
switch_to_rel.from_to = SW_FROM;
switch_to_rel.flags = SWTO_REL_DEFAULT;
switch_to_rel.rel_y = net_p->el[in_i].y - switch_to_rel.start_y;
switch_to_rel.rel_x = net_p->el[in_i].x-1 - switch_to_rel.start_x;
switch_to_rel.target_connpt = STRIDX_NO_ENTRY;
fpga_switch_to_rel(&switch_to_rel);
RC_ASSERT(model, switch_to_rel.set.len);
fnet_add_sw(model, net_i, switch_to_rel.start_y, switch_to_rel.start_x,
switch_to_rel.set.sw, switch_to_rel.set.len);
// connect with pinw
fnet_route_to_inpins(model, net_i, switch_to_rel.dest_connpt);
RC_RETURN(model);
} }
int fnet_autoroute(struct fpga_model* model, net_idx_t net_i) int fnet_autoroute(struct fpga_model* model, net_idx_t net_i)
@ -2294,22 +2529,9 @@ int fnet_autoroute(struct fpga_model* model, net_idx_t net_i)
} }
// todo: gnd and vcc nets are special and have no outpin // todo: gnd and vcc nets are special and have no outpin
// but lots of inpins // but can have multiple inpins
out_i = -1; out_i = fnet_pinw(model, net_i, /*out*/ 1, 0);
in_i = -1; in_i = fnet_pinw(model, net_i, /*out*/ 0, 0);
for (i = 0; i < net_p->len; i++) {
dev_p = FPGA_DEV(model, net_p->el[i].y,
net_p->el[i].x, net_p->el[i].dev_idx);
if ((net_p->el[i].idx & NET_IDX_MASK) < dev_p->num_pinw_in) {
// todo: right now we only support 1 inpin
if (in_i != -1) RC_FAIL(model, ENOTSUP);
in_i = i;
continue;
}
if (out_i != -1) RC_FAIL(model, EINVAL); // at most 1 outpin
out_i = i;
}
// todo: vcc and gnd have no outpin?
if (out_i == -1 || in_i == -1) if (out_i == -1 || in_i == -1)
RC_FAIL(model, EINVAL); RC_FAIL(model, EINVAL);
@ -2353,6 +2575,7 @@ int fnet_autoroute(struct fpga_model* model, net_idx_t net_i)
switch_to_rel.start_switch = switch_to_rel.start_switch =
in_dev->pinw[net_p->el[in_i].idx & NET_IDX_MASK]; in_dev->pinw[net_p->el[in_i].idx & NET_IDX_MASK];
switch_to_rel.from_to = SW_TO; switch_to_rel.from_to = SW_TO;
switch_to_rel.flags = SWTO_REL_DEFAULT;
switch_to_rel.rel_y = 0; switch_to_rel.rel_y = 0;
switch_to_rel.rel_x = -1; switch_to_rel.rel_x = -1;
switch_to_rel.target_connpt = STRIDX_NO_ENTRY; switch_to_rel.target_connpt = STRIDX_NO_ENTRY;
@ -2410,6 +2633,7 @@ int fnet_autoroute(struct fpga_model* model, net_idx_t net_i)
switch_to_rel.start_switch = switch_to_rel.start_switch =
out_dev->pinw[net_p->el[out_i].idx & NET_IDX_MASK]; out_dev->pinw[net_p->el[out_i].idx & NET_IDX_MASK];
switch_to_rel.from_to = SW_FROM; switch_to_rel.from_to = SW_FROM;
switch_to_rel.flags = SWTO_REL_DEFAULT;
switch_to_rel.rel_y = 0; switch_to_rel.rel_y = 0;
switch_to_rel.rel_x = -1; switch_to_rel.rel_x = -1;
switch_to_rel.target_connpt = STRIDX_NO_ENTRY; switch_to_rel.target_connpt = STRIDX_NO_ENTRY;
@ -2435,19 +2659,16 @@ int fnet_autoroute(struct fpga_model* model, net_idx_t net_i)
} }
int fnet_route_to_inpins(struct fpga_model* model, net_idx_t net_i, int fnet_route_to_inpins(struct fpga_model* model, net_idx_t net_i,
const char* from) str16_t from)
{ {
struct fpga_net* net_p; struct fpga_net* net_p;
struct fpga_device* dev_p; struct fpga_device* dev_p;
str16_t from_i;
struct sw_set start_set, end_set; struct sw_set start_set, end_set;
int i, rc; int i;
RC_CHECK(model); RC_CHECK(model);
net_p = fnet_get(model, net_i); net_p = fnet_get(model, net_i);
if (!net_p) FAIL(EINVAL); RC_ASSERT(model, net_p);
from_i = strarray_find(&model->str, from);
if (from_i == STRIDX_NO_ENTRY) FAIL(EINVAL);
for (i = 0; i < net_p->len; i++) { for (i = 0; i < net_p->len; i++) {
if (!(net_p->el[i].idx & NET_IDX_IS_PINW)) if (!(net_p->el[i].idx & NET_IDX_IS_PINW))
@ -2459,23 +2680,30 @@ int fnet_route_to_inpins(struct fpga_model* model, net_idx_t net_i,
// skip outpin // skip outpin
continue; continue;
rc = froute_direct(model, net_p->el[i].y, net_p->el[i].x-1, froute_direct(model, net_p->el[i].y, net_p->el[i].x-1,
from_i, net_p->el[i].y, net_p->el[i].x, from, net_p->el[i].y, net_p->el[i].x,
dev_p->pinw[net_p->el[i].idx & NET_IDX_MASK], dev_p->pinw[net_p->el[i].idx & NET_IDX_MASK],
&start_set, &end_set); &start_set, &end_set);
if (rc) FAIL(rc); RC_CHECK(model);
if (!start_set.len || !end_set.len) if (!start_set.len || !end_set.len)
HERE(); HERE();
rc = fnet_add_sw(model, net_i, net_p->el[i].y, fnet_add_sw(model, net_i, net_p->el[i].y,
net_p->el[i].x-1, start_set.sw, start_set.len); net_p->el[i].x-1, start_set.sw, start_set.len);
if (rc) FAIL(rc); fnet_add_sw(model, net_i, net_p->el[i].y,
rc = fnet_add_sw(model, net_i, net_p->el[i].y,
net_p->el[i].x, end_set.sw, end_set.len); net_p->el[i].x, end_set.sw, end_set.len);
if (rc) FAIL(rc);
} }
return 0; RC_RETURN(model);
fail: }
return rc;
int fnet_route_to_inpins_s(struct fpga_model *model, net_idx_t net_i,
const char *from)
{
str16_t from_i;
RC_CHECK(model);
from_i = strarray_find(&model->str, from);
RC_ASSERT(model, from_i != STRIDX_NO_ENTRY);
return fnet_route_to_inpins(model, net_i, from_i);
} }
int froute_direct(struct fpga_model* model, int start_y, int start_x, int froute_direct(struct fpga_model* model, int start_y, int start_x,

View File

@ -268,6 +268,8 @@ void printf_swconns(struct fpga_model* model, int y, int x,
str16_t sw, int from_to, int max_depth); str16_t sw, int from_to, int max_depth);
#define SWTO_YX_DEF 0 #define SWTO_YX_DEF 0
// SWTO_YX_CLOSEST finds the closest tile that satisfies
// the YX requirement.
#define SWTO_YX_CLOSEST 0x0001 #define SWTO_YX_CLOSEST 0x0001
#define SWTO_YX_TARGET_CONNPT 0x0002 #define SWTO_YX_TARGET_CONNPT 0x0002
#define SWTO_YX_MAX_SWITCH_DEPTH 0x0004 #define SWTO_YX_MAX_SWITCH_DEPTH 0x0004
@ -295,6 +297,26 @@ struct switch_to_yx
int fpga_switch_to_yx(struct switch_to_yx *p); int fpga_switch_to_yx(struct switch_to_yx *p);
void printf_switch_to_yx_result(struct switch_to_yx *p); void printf_switch_to_yx_result(struct switch_to_yx *p);
struct switch_to_yx_l2
{
struct switch_to_yx l1;
// l2 y/x/set is inserted between l1.y/x/start_switch
// and l1.dest_y/dest_x/dest_connpt
struct sw_set l2_set;
int l2_y, l2_x;
};
// fpga_switch_to_yx_l2() allows for an optional intermediate tile
// to come before the yx_req. If a direct link was found, l2_set.len
// will be 0 and l2_y and l2_x are undefined.
int fpga_switch_to_yx_l2(struct switch_to_yx_l2 *p);
#define SWTO_REL_DEFAULT 0
// If a connection to the actal target is not found,
// WEAK_TARGET will allow to return the connection that
// reaches as close as possible to the x/y target.
#define SWTO_REL_WEAK_TARGET 0x0001
struct switch_to_rel struct switch_to_rel
{ {
// input: // input:
@ -303,6 +325,7 @@ struct switch_to_rel
int start_x; int start_x;
str16_t start_switch; str16_t start_switch;
int from_to; int from_to;
int flags; // SWTO_REL-value
int rel_y; int rel_y;
int rel_x; int rel_x;
str16_t target_connpt; // can be STRIDX_NO_ENTRY str16_t target_connpt; // can be STRIDX_NO_ENTRY
@ -370,6 +393,8 @@ void fnet_printf(FILE* f, struct fpga_model* model, net_idx_t net_i);
int fnet_autoroute(struct fpga_model* model, net_idx_t net_i); int fnet_autoroute(struct fpga_model* model, net_idx_t net_i);
int fnet_route_to_inpins(struct fpga_model* model, net_idx_t net_i, int fnet_route_to_inpins(struct fpga_model* model, net_idx_t net_i,
str16_t from);
int fnet_route_to_inpins_s(struct fpga_model* model, net_idx_t net_i,
const char* from); const char* from);
// //

View File

@ -355,20 +355,22 @@ int parse_boolexpr(const char *expr, uint64_t *lut)
return 0; return 0;
} }
int printf_type2(uint8_t *d, int len, int inpos, int num_entries) void printf_type2(uint8_t *d, int len, int inpos, int num_entries)
{ {
int i, num_printed;
uint64_t u64; uint64_t u64;
uint16_t u16;
int i, j;
num_printed = 0;
for (i = 0; i < num_entries; i++) { for (i = 0; i < num_entries; i++) {
u64 = frame_get_u64(&d[inpos+i*8]); u64 = frame_get_u64(&d[inpos+i*8]);
if (u64) { if (!u64) continue;
printf("type2 i%i 0x%016lX\n", i, u64); printf("type2 8*%i 0x%016lX\n", i, u64);
num_printed++; for (j = 0; j < 4; j++) {
u16 = frame_get_u16(&d[inpos+i*8+j*2]);
if (u16)
printf("type2 2*%i 8*%i+%i 0x%04X\n", i*4+j, i, j, u16);
} }
} }
return num_printed;
} }
void printf_ramb16_data(uint8_t *bits, int inpos) void printf_ramb16_data(uint8_t *bits, int inpos)

View File

@ -69,7 +69,7 @@ const char* bool_bits2str(uint64_t u64, int num_bits);
int parse_boolexpr(const char* expr, uint64_t* lut); int parse_boolexpr(const char* expr, uint64_t* lut);
int printf_type2(uint8_t* d, int len, int inpos, int num_entries); void printf_type2(uint8_t* d, int len, int inpos, int num_entries);
void printf_ramb16_data(uint8_t* bits, int inpos); void printf_ramb16_data(uint8_t* bits, int inpos);
int is_empty(const uint8_t* d, int l); int is_empty(const uint8_t* d, int l);

View File

@ -293,6 +293,9 @@ int is_atx(int check, struct fpga_model* model, int x);
// boundary of the regular routing area. // boundary of the regular routing area.
#define YX_OUTSIDE_OF_ROUTING 0x0400 #define YX_OUTSIDE_OF_ROUTING 0x0400
#define YX_ROUTING_BOUNDARY 0x0800 #define YX_ROUTING_BOUNDARY 0x0800
#define YX_X_CENTER_CMTPLL 0x1000
#define YX_Y_CENTER 0x2000
#define YX_CENTER 0x4000
int is_atyx(int check, struct fpga_model* model, int y, int x); int is_atyx(int check, struct fpga_model* model, int y, int x);
@ -307,6 +310,7 @@ int which_row(int y, struct fpga_model* model);
int pos_in_row(int y, struct fpga_model* model); int pos_in_row(int y, struct fpga_model* model);
// regular_row_pos() returns the index (0..15) without hclk, or -1 if y is a hclk. // regular_row_pos() returns the index (0..15) without hclk, or -1 if y is a hclk.
int regular_row_pos(int y, struct fpga_model* model); int regular_row_pos(int y, struct fpga_model* model);
int y_to_hclk(int y, struct fpga_model *model);
const char* logicin_s(int wire, int routing_io); const char* logicin_s(int wire, int routing_io);

View File

@ -736,6 +736,13 @@ int is_atyx(int check, struct fpga_model* model, int y, int x)
&& is_atyx(YX_ROUTING_TILE, model, y, x) && is_atyx(YX_ROUTING_TILE, model, y, x)
&& (x == LEFT_IO_ROUTING || x == model->x_width-RIGHT_IO_ROUTING_O && (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; || 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
&& is_aty(Y_CHIP_HORIZ_REGS, model, y)) return 1;
if (check & YX_CENTER
&& is_atx(X_CENTER_REGS_COL, model, x)
&& is_aty(Y_CHIP_HORIZ_REGS, model, y)) return 1;
return 0; return 0;
} }
@ -785,6 +792,22 @@ int regular_row_pos(int y, struct fpga_model* model)
return row_pos; return row_pos;
} }
int y_to_hclk(int y, struct fpga_model *model)
{
int row_num, row_pos, hclk_pos;
is_in_row(model, y, &row_num, &row_pos);
if (row_num == -1
|| row_pos == -1 || row_pos == HCLK_POS)
{ HERE(); return -1; }
hclk_pos = model->y_height - BOT_LAST_REGULAR_O - row_num*ROW_SIZE - HCLK_POS;
if (hclk_pos < model->center_y)
hclk_pos--; // center regs
if (hclk_pos < TOP_FIRST_REGULAR)
{ HERE(); return -1; }
return hclk_pos;
}
const char* logicin_s(int wire, int routing_io) const char* logicin_s(int wire, int routing_io)
{ {
if (routing_io && ((wire & LWF_WIRE_MASK) == X_A5 || (wire & LWF_WIRE_MASK) == X_B4)) if (routing_io && ((wire & LWF_WIRE_MASK) == X_A5 || (wire & LWF_WIRE_MASK) == X_B4))

View File

@ -389,7 +389,16 @@ const struct xc6_pkg_info *xc6_pkg_info(enum xc6_pkg pkg)
/* 16 */ "P131", "P132", "P133", "P134", /* 16 */ "P131", "P132", "P133", "P134",
/* 20 */ "P14", "P15", "P16", "P17", /* 20 */ "P14", "P15", "P16", "P17",
/* 24 */ "P21", "P22", "P23", "P24", /* 24 */ "P21", "P22", "P23", "P24",
/* 28 */ 0, 0, "P50", "P51" }}; /* 28 */ 0, 0, "P50", "P51" },
.gclk_type2_o = {
/* 0 */ 20*4+ 6, 20*4+ 9, -1, -1,
/* 4 */ 190*4+18, 190*4+21, 190*4+12, 190*4+15,
/* 8 */ 190*4+ 6, 190*4+ 9, 190*4+ 0, 190*4+ 3,
/* 12 */ 136*4+18, 136*4+21, 136*4+12, 136*4+15,
/* 16 */ 136*4+ 6, 136*4+ 9, 136*4+ 0, 136*4+ 3,
/* 20 */ 78*4+21, 78*4+18, 78*4+15, 78*4+12,
/* 24 */ 78*4+ 9, 78*4+ 6, 78*4+ 3, 78*4+ 0,
/* 28 */ -1, -1, 20*4+12, 20*4+15 }};
switch (pkg) { switch (pkg) {
case TQG144: return &pkg_tqg144; case TQG144: return &pkg_tqg144;
default: ; default: ;

View File

@ -105,6 +105,7 @@ struct xc6_pkg_info
// negative side of differential pairs: even numbers // negative side of differential pairs: even numbers
// positive side of differential pairs: odd numbers // positive side of differential pairs: odd numbers
const char* gclk_pin[XC6_NUM_GCLK_PINS]; const char* gclk_pin[XC6_NUM_GCLK_PINS];
int gclk_type2_o[XC6_NUM_GCLK_PINS]; // in words
}; };
const struct xc6_pkg_info *xc6_pkg_info(enum xc6_pkg pkg); const struct xc6_pkg_info *xc6_pkg_info(enum xc6_pkg pkg);
@ -124,6 +125,9 @@ const struct xc6_pkg_info *xc6_pkg_info(enum xc6_pkg pkg);
#define IOB_ENTRY_LEN 8 #define IOB_ENTRY_LEN 8
#define BITS_LEN (IOB_DATA_START+IOB_DATA_LEN) #define BITS_LEN (IOB_DATA_START+IOB_DATA_LEN)
#define XC6_WORD_BYTES 2
#define XC6_WORD_BITS (XC6_WORD_BYTES*8)
#define XC6_HCLK_BYTES 2 #define XC6_HCLK_BYTES 2
#define XC6_HCLK_BITS (XC6_HCLK_BYTES*8) #define XC6_HCLK_BITS (XC6_HCLK_BYTES*8)
@ -421,3 +425,5 @@ void xc6_lut_bitmap(int lut_pos, int (*map)[64], int num_bits);
#define XC6_ML_A_CY0_O5 62 // implies lut5 on ML-A #define XC6_ML_A_CY0_O5 62 // implies lut5 on ML-A
#define XC6_L_A_FFSRINIT_1 63 // L-device only #define XC6_L_A_FFSRINIT_1 63 // L-device only
#define XC6_TYPE2_GCLK_REG_SW 2 // bit 2 in 1st word