modeled first line - NN2
This commit is contained in:
parent
b4ad7801b0
commit
a17588fac5
9
Makefile
9
Makefile
|
@ -10,11 +10,14 @@
|
||||||
CFLAGS = -Wall -g
|
CFLAGS = -Wall -g
|
||||||
LDLIBS = -lxml2
|
LDLIBS = -lxml2
|
||||||
|
|
||||||
all: bit2txt draw_svg_tiles new_floorplan xc6slx9.svg
|
all: bit2txt draw_svg_tiles new_floorplan xc6slx9.svg xc6slx9.fp
|
||||||
|
|
||||||
xc6slx9.svg: draw_svg_tiles
|
xc6slx9.svg: draw_svg_tiles
|
||||||
./draw_svg_tiles | xmllint --pretty 1 - > $@
|
./draw_svg_tiles | xmllint --pretty 1 - > $@
|
||||||
|
|
||||||
|
xc6slx9.fp: new_floorplan
|
||||||
|
./new_floorplan > $@
|
||||||
|
|
||||||
bit2txt: bit2txt.o helper.o
|
bit2txt: bit2txt.o helper.o
|
||||||
|
|
||||||
bit2txt.o: bit2txt.c helper.h
|
bit2txt.o: bit2txt.c helper.h
|
||||||
|
@ -23,6 +26,10 @@ helper.o: helper.c helper.h
|
||||||
|
|
||||||
model.o: model.c model.h
|
model.o: model.c model.h
|
||||||
|
|
||||||
|
new_floorplan.o: new_floorplan.c model.h
|
||||||
|
|
||||||
|
draw_svg_tiles.o: draw_svg_tiles.c model.h
|
||||||
|
|
||||||
draw_svg_tiles: draw_svg_tiles.o model.o
|
draw_svg_tiles: draw_svg_tiles.o model.o
|
||||||
|
|
||||||
new_floorplan: new_floorplan.o model.o
|
new_floorplan: new_floorplan.o model.o
|
||||||
|
|
|
@ -19,6 +19,9 @@
|
||||||
|
|
||||||
#include "model.h"
|
#include "model.h"
|
||||||
|
|
||||||
|
#define VERT_TILE_SPACING 45
|
||||||
|
#define HORIZ_TILE_SPACING 160
|
||||||
|
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
static const xmlChar* empty_svg = (const xmlChar*)
|
static const xmlChar* empty_svg = (const xmlChar*)
|
||||||
|
@ -28,7 +31,7 @@ int main(int argc, char** argv)
|
||||||
" xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n"
|
" xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n"
|
||||||
" xmlns:fpga=\"http://qi-hw.com/fpga\"\n"
|
" xmlns:fpga=\"http://qi-hw.com/fpga\"\n"
|
||||||
" id=\"root\">\n"
|
" id=\"root\">\n"
|
||||||
"<style type=\"text/css\"><![CDATA[text{font-size:6pt;text-anchor:end;}]]></style>\n"
|
"<style type=\"text/css\"><![CDATA[text{font-size:8pt;font-family:sans-serif;text-anchor:end;}]]></style>\n"
|
||||||
"</svg>\n";
|
"</svg>\n";
|
||||||
|
|
||||||
xmlDocPtr doc = 0;
|
xmlDocPtr doc = 0;
|
||||||
|
@ -74,16 +77,32 @@ int main(int argc, char** argv)
|
||||||
|
|
||||||
for (i = 0; i < model.tile_y_range; i++) {
|
for (i = 0; i < model.tile_y_range; i++) {
|
||||||
for (j = 0; j < model.tile_x_range; j++) {
|
for (j = 0; j < model.tile_x_range; j++) {
|
||||||
strcpy(str, fpga_tiletype_str(model.tiles[i*model.tile_x_range+j].type));
|
sprintf(str, "y%i x%i:", i, j);
|
||||||
new_node = xmlNewChild(xpathObj->nodesetval->nodeTab[0], 0 /* xmlNsPtr */, BAD_CAST "text", BAD_CAST str);
|
new_node = xmlNewChild(xpathObj->nodesetval->nodeTab[0],
|
||||||
xmlSetProp(new_node, BAD_CAST "x", xmlXPathCastNumberToString(130 + j*130));
|
0 /* xmlNsPtr */, BAD_CAST "text", BAD_CAST str);
|
||||||
xmlSetProp(new_node, BAD_CAST "y", xmlXPathCastNumberToString(40 + i*14));
|
xmlSetProp(new_node, BAD_CAST "x",
|
||||||
|
xmlXPathCastNumberToString(HORIZ_TILE_SPACING + j*HORIZ_TILE_SPACING));
|
||||||
|
xmlSetProp(new_node, BAD_CAST "y",
|
||||||
|
xmlXPathCastNumberToString(20
|
||||||
|
+ VERT_TILE_SPACING + i*VERT_TILE_SPACING));
|
||||||
|
|
||||||
|
strcpy(str, fpga_tiletype_str(
|
||||||
|
model.tiles[i*model.tile_x_range+j].type));
|
||||||
|
new_node = xmlNewChild(xpathObj->nodesetval->nodeTab[0],
|
||||||
|
0 /* xmlNsPtr */, BAD_CAST "text", BAD_CAST str);
|
||||||
|
xmlSetProp(new_node, BAD_CAST "x",
|
||||||
|
xmlXPathCastNumberToString(HORIZ_TILE_SPACING + j*HORIZ_TILE_SPACING));
|
||||||
|
xmlSetProp(new_node, BAD_CAST "y",
|
||||||
|
xmlXPathCastNumberToString(20 + VERT_TILE_SPACING + i*VERT_TILE_SPACING + 14));
|
||||||
xmlSetProp(new_node, BAD_CAST "fpga:tile_y", BAD_CAST xmlXPathCastNumberToString(i));
|
xmlSetProp(new_node, BAD_CAST "fpga:tile_y", BAD_CAST xmlXPathCastNumberToString(i));
|
||||||
xmlSetProp(new_node, BAD_CAST "fpga:tile_x", BAD_CAST xmlXPathCastNumberToString(j));
|
xmlSetProp(new_node, BAD_CAST "fpga:tile_x", BAD_CAST xmlXPathCastNumberToString(j));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
xmlSetProp(xpathObj->nodesetval->nodeTab[0], BAD_CAST "width", BAD_CAST xmlXPathCastNumberToString(model.tile_x_range * 130 + 65));
|
xmlSetProp(xpathObj->nodesetval->nodeTab[0], BAD_CAST "width",
|
||||||
xmlSetProp(xpathObj->nodesetval->nodeTab[0], BAD_CAST "height", BAD_CAST xmlXPathCastNumberToString(model.tile_y_range * 14 + 60));
|
BAD_CAST xmlXPathCastNumberToString(model.tile_x_range * HORIZ_TILE_SPACING + HORIZ_TILE_SPACING/2));
|
||||||
|
xmlSetProp(xpathObj->nodesetval->nodeTab[0], BAD_CAST "height",
|
||||||
|
BAD_CAST xmlXPathCastNumberToString(20 + VERT_TILE_SPACING
|
||||||
|
+ model.tile_y_range * VERT_TILE_SPACING + 20));
|
||||||
|
|
||||||
xmlDocFormatDump(stdout, doc, 1 /* format */);
|
xmlDocFormatDump(stdout, doc, 1 /* format */);
|
||||||
xmlXPathFreeObject(xpathObj);
|
xmlXPathFreeObject(xpathObj);
|
||||||
|
|
523
model.c
523
model.c
|
@ -5,6 +5,7 @@
|
||||||
// For details see the UNLICENSE file at the root of the source tree.
|
// For details see the UNLICENSE file at the root of the source tree.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
#include "model.h"
|
#include "model.h"
|
||||||
|
|
||||||
static const char* fpga_ttstr[] = // tile type strings
|
static const char* fpga_ttstr[] = // tile type strings
|
||||||
|
@ -162,19 +163,219 @@ static const char* fpga_ttstr[] = // tile type strings
|
||||||
[HCLK_IO_BOT_DN_R] = "HCLK_IO_BOT_DN_R",
|
[HCLK_IO_BOT_DN_R] = "HCLK_IO_BOT_DN_R",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
int init_tiles(struct fpga_model* model);
|
||||||
|
int run_wires(struct fpga_model* model);
|
||||||
|
|
||||||
int fpga_build_model(struct fpga_model* model, int fpga_rows, const char* columns,
|
int fpga_build_model(struct fpga_model* model, int fpga_rows, const char* columns,
|
||||||
const char* left_wiring, const char* right_wiring)
|
const char* left_wiring, const char* right_wiring)
|
||||||
{
|
{
|
||||||
int tile_rows, tile_columns, i, j, k, l, row_top_y, center_row, left_side;
|
int rc;
|
||||||
int start, end;
|
|
||||||
|
|
||||||
tile_rows = 1 /* middle */ + (8+1+8)*fpga_rows + 2+2 /* two extra tiles at top and bottom */;
|
memset(model, 0, sizeof(*model));
|
||||||
|
model->cfg_rows = fpga_rows;
|
||||||
|
strncpy(model->cfg_columns, columns, sizeof(model->cfg_columns)-1);
|
||||||
|
strncpy(model->cfg_left_wiring, left_wiring, sizeof(model->cfg_left_wiring)-1);
|
||||||
|
strncpy(model->cfg_right_wiring, right_wiring, sizeof(model->cfg_right_wiring)-1);
|
||||||
|
strarray_init(&model->str);
|
||||||
|
|
||||||
|
rc = init_tiles(model);
|
||||||
|
if (rc) return rc;
|
||||||
|
|
||||||
|
rc = run_wires(model);
|
||||||
|
if (rc) return rc;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define CONN_NAMES_INCREMENT 128
|
||||||
|
#define CONNS_INCREMENT 128
|
||||||
|
|
||||||
|
int add_conn_uni(struct fpga_model* model, int y1, int x1, const char* name1, int y2, int x2, const char* name2)
|
||||||
|
{
|
||||||
|
struct fpga_tile* tile1;
|
||||||
|
uint16_t name1_i, name2_i;
|
||||||
|
uint16_t* new_ptr;
|
||||||
|
int conn_start, num_conns_for_this_wire, rc, i, j;
|
||||||
|
|
||||||
|
tile1 = &model->tiles[y1 * model->tile_x_range + x1];
|
||||||
|
rc = strarray_find_or_add(&model->str, name1, &name1_i);
|
||||||
|
if (!rc) return -1;
|
||||||
|
rc = strarray_find_or_add(&model->str, name2, &name2_i);
|
||||||
|
if (!rc) return -1;
|
||||||
|
|
||||||
|
// Search for a connection set under name1.
|
||||||
|
for (i = 0; i < tile1->num_conn_names; i++) {
|
||||||
|
if (tile1->conn_names[i*2+1] == name1_i)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// If this is the first connection under name1, add name1.
|
||||||
|
if (i >= tile1->num_conn_names) {
|
||||||
|
if (!(tile1->num_conn_names % CONN_NAMES_INCREMENT)) {
|
||||||
|
new_ptr = realloc(tile1->conn_names, (tile1->num_conn_names+CONN_NAMES_INCREMENT)*2*sizeof(uint16_t));
|
||||||
|
if (!new_ptr) {
|
||||||
|
fprintf(stderr, "Out of memory %s:%i\n", __FILE__, __LINE__);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
tile1->conn_names = new_ptr;
|
||||||
|
}
|
||||||
|
tile1->conn_names[tile1->num_conn_names*2] = tile1->num_conns;
|
||||||
|
tile1->conn_names[tile1->num_conn_names*2+1] = name1_i;
|
||||||
|
tile1->num_conn_names++;
|
||||||
|
}
|
||||||
|
conn_start = tile1->conn_names[i*2];
|
||||||
|
if (i+1 >= tile1->num_conn_names)
|
||||||
|
num_conns_for_this_wire = tile1->num_conns - conn_start;
|
||||||
|
else
|
||||||
|
num_conns_for_this_wire = tile1->conn_names[(i+1)*2] - conn_start;
|
||||||
|
|
||||||
|
// Is the connection made a second time?
|
||||||
|
for (j = conn_start; j < conn_start + num_conns_for_this_wire; j++) {
|
||||||
|
if (tile1->conns[j*3] == x2
|
||||||
|
&& tile1->conns[j*3+1] == y2
|
||||||
|
&& tile1->conns[j*3+2] == name2_i) {
|
||||||
|
fprintf(stderr, "Internal error, connection made twice.\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(tile1->num_conns % CONNS_INCREMENT)) {
|
||||||
|
new_ptr = realloc(tile1->conns, (tile1->num_conns+CONNS_INCREMENT)*3*sizeof(uint16_t));
|
||||||
|
if (!new_ptr) {
|
||||||
|
fprintf(stderr, "Out of memory %s:%i\n", __FILE__, __LINE__);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
tile1->conns = new_ptr;
|
||||||
|
}
|
||||||
|
if (tile1->num_conns > j)
|
||||||
|
memmove(&tile1->conns[(j+1)*3], &tile1->conns[j*3], (tile1->num_conns-j)*3);
|
||||||
|
tile1->conns[j*3] = x2;
|
||||||
|
tile1->conns[j*3+1] = y2;
|
||||||
|
tile1->conns[j*3+2] = name2_i;
|
||||||
|
tile1->num_conns++;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int add_conn_bi(struct fpga_model* model, int y1, int x1, const char* name1, int y2, int x2, const char* name2)
|
||||||
|
{
|
||||||
|
int rc = add_conn_uni(model, y1, x1, name1, y2, x2, name2);
|
||||||
|
if (rc) return rc;
|
||||||
|
return add_conn_uni(model, y2, x2, name2, y1, x1, name1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* pf(const char* fmt, ...)
|
||||||
|
{
|
||||||
|
static char pf_buf[128];
|
||||||
|
va_list list;
|
||||||
|
pf_buf[0] = 0;
|
||||||
|
va_start(list, fmt);
|
||||||
|
vsnprintf(pf_buf, sizeof(pf_buf), fmt, list);
|
||||||
|
va_end(list);
|
||||||
|
return pf_buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
int run_wires(struct fpga_model* model)
|
||||||
|
{
|
||||||
|
struct fpga_tile* tile, *tile_up1, *tile_up2;
|
||||||
|
char b_wire[16], m_wire[16], e_wire[16];
|
||||||
|
char* wire_fmt;
|
||||||
|
int x, y, i, rc;
|
||||||
|
|
||||||
|
rc = -1;
|
||||||
|
for (y = 0; y < model->tile_y_range; y++) {
|
||||||
|
for (x = 0; x < model->tile_x_range; x++) {
|
||||||
|
tile = &model->tiles[y * model->tile_x_range + x];
|
||||||
|
if (!(tile->flags & TF_DIRWIRE_START))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
tile_up1 = &model->tiles[(y-1) * model->tile_x_range + x];
|
||||||
|
tile_up2 = &model->tiles[(y-2) * model->tile_x_range + x];
|
||||||
|
for (i = 0; i <= 3; i++) {
|
||||||
|
sprintf(b_wire, "NN2B%i", i);
|
||||||
|
sprintf(m_wire, "NN2M%i", i);
|
||||||
|
sprintf(e_wire, "NN2E%i", i);
|
||||||
|
if (tile_up1->flags & TF_SECOND_ROW) {
|
||||||
|
rc = add_conn_bi(model, y, x, b_wire, y-1, x, pf("IOI_TTERM_%s", b_wire));
|
||||||
|
if (rc) goto xout;
|
||||||
|
} else if (tile_up2->flags & TF_SECOND_ROW) {
|
||||||
|
rc = add_conn_bi(model, y, x, b_wire, y-1, x, m_wire);
|
||||||
|
if (rc) goto xout;
|
||||||
|
rc = add_conn_bi(model, y, x, b_wire, y-2, x, pf("IOI_TTERM_%s", m_wire));
|
||||||
|
if (rc) goto xout;
|
||||||
|
rc = add_conn_bi(model, y-1, x, m_wire, y-2, x, pf("IOI_TTERM_%s", m_wire));
|
||||||
|
if (rc) goto xout;
|
||||||
|
} else if (tile_up1->flags & (TF_ROW_HORIZ_AXSYMM|TF_CHIP_HORIZ_AXSYMM)) {
|
||||||
|
|
||||||
|
if (tile_up1->flags & TF_ROW_HORIZ_AXSYMM)
|
||||||
|
wire_fmt = "HCLK_%s";
|
||||||
|
else if (tile[3].flags & TF_CHIP_VERT_AXSYMM)
|
||||||
|
wire_fmt = "REGC_INT_%s";
|
||||||
|
else
|
||||||
|
wire_fmt = "REGH_%s";
|
||||||
|
|
||||||
|
rc = add_conn_bi(model, y, x, b_wire, y-1, x, pf(wire_fmt, m_wire));
|
||||||
|
if (rc) goto xout;
|
||||||
|
rc = add_conn_bi(model, y, x, b_wire, y-2, x, m_wire);
|
||||||
|
if (rc) goto xout;
|
||||||
|
rc = add_conn_bi(model, y, x, b_wire, y-3, x, e_wire);
|
||||||
|
if (rc) goto xout;
|
||||||
|
rc = add_conn_bi(model, y-1, x, pf(wire_fmt, m_wire), y-2, x, m_wire);
|
||||||
|
if (rc) goto xout;
|
||||||
|
rc = add_conn_bi(model, y-1, x, pf(wire_fmt, m_wire), y-3, x, e_wire);
|
||||||
|
if (rc) goto xout;
|
||||||
|
rc = add_conn_bi(model, y-2, x, m_wire, y-3, x, e_wire);
|
||||||
|
if (rc) goto xout;
|
||||||
|
|
||||||
|
} else if (tile_up2->flags & (TF_ROW_HORIZ_AXSYMM|TF_CHIP_HORIZ_AXSYMM)) {
|
||||||
|
|
||||||
|
if (tile_up2->flags & TF_ROW_HORIZ_AXSYMM)
|
||||||
|
wire_fmt = "HCLK_%s";
|
||||||
|
else if (tile[3].flags & TF_CHIP_VERT_AXSYMM)
|
||||||
|
wire_fmt = "REGC_INT_%s";
|
||||||
|
else
|
||||||
|
wire_fmt = "REGH_%s";
|
||||||
|
|
||||||
|
rc = add_conn_bi(model, y, x, b_wire, y-1, x, m_wire);
|
||||||
|
if (rc) goto xout;
|
||||||
|
rc = add_conn_bi(model, y, x, b_wire, y-2, x, pf(wire_fmt, e_wire));
|
||||||
|
if (rc) goto xout;
|
||||||
|
rc = add_conn_bi(model, y, x, b_wire, y-3, x, e_wire);
|
||||||
|
if (rc) goto xout;
|
||||||
|
rc = add_conn_bi(model, y-1, x, m_wire, y-2, x, pf(wire_fmt, e_wire));
|
||||||
|
if (rc) goto xout;
|
||||||
|
rc = add_conn_bi(model, y-1, x, m_wire, y-3, x, e_wire);
|
||||||
|
if (rc) goto xout;
|
||||||
|
rc = add_conn_bi(model, y-2, x, pf(wire_fmt, e_wire), y-3, x, e_wire);
|
||||||
|
if (rc) goto xout;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
rc = add_conn_bi(model, y, x, b_wire, y-1, x, m_wire);
|
||||||
|
if (rc) goto xout;
|
||||||
|
rc = add_conn_bi(model, y, x, b_wire, y-2, x, e_wire);
|
||||||
|
if (rc) goto xout;
|
||||||
|
rc = add_conn_bi(model, y-1, x, m_wire, y-2, x, e_wire);
|
||||||
|
if (rc) goto xout;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
xout:
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
int init_tiles(struct fpga_model* model)
|
||||||
|
{
|
||||||
|
int tile_rows, tile_columns, i, j, k, l, x, y, row_top_y, center_row, left_side;
|
||||||
|
int start, end;
|
||||||
|
struct fpga_tile* tile_i0;
|
||||||
|
|
||||||
|
tile_rows = 1 /* middle */ + (8+1+8)*model->cfg_rows + 2+2 /* two extra tiles at top and bottom */;
|
||||||
tile_columns = 5 /* left */ + 5 /* right */;
|
tile_columns = 5 /* left */ + 5 /* right */;
|
||||||
for (i = 0; columns[i] != 0; i++) {
|
for (i = 0; model->cfg_columns[i] != 0; i++) {
|
||||||
tile_columns += 2; // 2 for logic blocks L/M and minimum for others
|
tile_columns += 2; // 2 for logic blocks L/M and minimum for others
|
||||||
if (columns[i] == 'B' || columns[i] == 'D')
|
if (model->cfg_columns[i] == 'B' || model->cfg_columns[i] == 'D')
|
||||||
tile_columns++; // 3 for bram or macc
|
tile_columns++; // 3 for bram or macc
|
||||||
else if (columns[i] == 'R')
|
else if (model->cfg_columns[i] == 'R')
|
||||||
tile_columns+=2; // 2+2 for middle IO+logic+PLL/DCM
|
tile_columns+=2; // 2+2 for middle IO+logic+PLL/DCM
|
||||||
}
|
}
|
||||||
model->tile_x_range = tile_columns;
|
model->tile_x_range = tile_columns;
|
||||||
|
@ -188,7 +389,21 @@ int fpga_build_model(struct fpga_model* model, int fpga_rows, const char* column
|
||||||
model->tiles[i].type = NA;
|
model->tiles[i].type = NA;
|
||||||
if (!(tile_rows % 2))
|
if (!(tile_rows % 2))
|
||||||
fprintf(stderr, "Unexpected even number of tile rows (%i).\n", tile_rows);
|
fprintf(stderr, "Unexpected even number of tile rows (%i).\n", tile_rows);
|
||||||
center_row = 2 /* top IO files */ + (fpga_rows/2)*(8+1/*middle of row clock*/+8);
|
center_row = 2 /* top IO files */ + (model->cfg_rows/2)*(8+1/*middle of row clock*/+8);
|
||||||
|
|
||||||
|
// flag horizontal rows
|
||||||
|
for (x = 0; x < model->tile_x_range; x++) {
|
||||||
|
model->tiles[x].flags |= TF_FIRST_ROW;
|
||||||
|
model->tiles[model->tile_x_range + x].flags |= TF_SECOND_ROW;
|
||||||
|
for (i = model->cfg_rows-1; i >= 0; i--) {
|
||||||
|
row_top_y = 2 /* top IO tiles */ + (model->cfg_rows-1-i)*(8+1/*middle of row clock*/+8);
|
||||||
|
if (i<(model->cfg_rows/2)) row_top_y++; // middle system tiles
|
||||||
|
model->tiles[(row_top_y+8)*model->tile_x_range + x].flags |= TF_ROW_HORIZ_AXSYMM;
|
||||||
|
}
|
||||||
|
model->tiles[center_row * model->tile_x_range + x].flags |= TF_CHIP_HORIZ_AXSYMM;
|
||||||
|
model->tiles[(model->tile_y_range-2)*model->tile_x_range + x].flags |= TF_SECOND_TO_LAST_ROW;
|
||||||
|
model->tiles[(model->tile_y_range-1)*model->tile_x_range + x].flags |= TF_LAST_ROW;
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// top, bottom, center:
|
// top, bottom, center:
|
||||||
|
@ -197,24 +412,28 @@ int fpga_build_model(struct fpga_model* model, int fpga_rows, const char* column
|
||||||
|
|
||||||
left_side = 1; // turn off (=right side) when reaching the 'R' middle column
|
left_side = 1; // turn off (=right side) when reaching the 'R' middle column
|
||||||
i = 5; // skip left IO columns
|
i = 5; // skip left IO columns
|
||||||
for (j = 0; columns[j]; j++) {
|
for (j = 0; model->cfg_columns[j]; j++) {
|
||||||
switch (columns[j]) {
|
switch (model->cfg_columns[j]) {
|
||||||
case 'L':
|
case 'L':
|
||||||
case 'l':
|
case 'l':
|
||||||
case 'M':
|
case 'M':
|
||||||
case 'm':
|
case 'm':
|
||||||
for (k = fpga_rows-1; k >= 0; k--) {
|
for (k = model->cfg_rows-1; k >= 0; k--) {
|
||||||
row_top_y = 2 /* top IO tiles */ + (fpga_rows-1-k)*(8+1/*middle of row clock*/+8);
|
row_top_y = 2 /* top IO tiles */ + (model->cfg_rows-1-k)*(8+1/*middle of row clock*/+8);
|
||||||
if (k<(fpga_rows/2)) row_top_y++; // middle system tiles (center row)
|
if (k<(model->cfg_rows/2)) row_top_y++; // middle system tiles (center row)
|
||||||
start = ((k == fpga_rows-1 && (columns[j] == 'L' || columns[j] == 'M')) ? 2 : 0);
|
start = ((k == model->cfg_rows-1 && (model->cfg_columns[j] == 'L' || model->cfg_columns[j] == 'M')) ? 2 : 0);
|
||||||
end = ((k == 0 && (columns[j] == 'L' || columns[j] == 'M')) ? 14 : 16);
|
end = ((k == 0 && (model->cfg_columns[j] == 'L' || model->cfg_columns[j] == 'M')) ? 14 : 16);
|
||||||
for (l = start; l < end; l++) {
|
for (l = start; l < end; l++) {
|
||||||
model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + i].type =
|
tile_i0 = &model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + i];
|
||||||
(l < 15 || (!k && (columns[j] == 'l' || columns[j] == 'm'))) ? ROUTING : ROUTING_BRK;
|
if (l < 15 || (!k && (model->cfg_columns[j] == 'l' || model->cfg_columns[j] == 'm'))) {
|
||||||
model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + i + 1].type
|
tile_i0->type = ROUTING;
|
||||||
= (columns[j] == 'L' || columns[j] == 'l') ? LOGIC_XL : LOGIC_XM;
|
tile_i0->flags |= TF_DIRWIRE_START;
|
||||||
|
} else
|
||||||
|
tile_i0->type = ROUTING_BRK;
|
||||||
|
tile_i0[1].type
|
||||||
|
= (model->cfg_columns[j] == 'L' || model->cfg_columns[j] == 'l') ? LOGIC_XL : LOGIC_XM;
|
||||||
}
|
}
|
||||||
if (columns[j] == 'L' || columns[j] == 'l') {
|
if (model->cfg_columns[j] == 'L' || model->cfg_columns[j] == 'l') {
|
||||||
model->tiles[(row_top_y+8)*tile_columns + i].type = HCLK_ROUTING_XL;
|
model->tiles[(row_top_y+8)*tile_columns + i].type = HCLK_ROUTING_XL;
|
||||||
model->tiles[(row_top_y+8)*tile_columns + i + 1].type = HCLK_LOGIC_XL;
|
model->tiles[(row_top_y+8)*tile_columns + i + 1].type = HCLK_LOGIC_XL;
|
||||||
} else {
|
} else {
|
||||||
|
@ -223,43 +442,47 @@ int fpga_build_model(struct fpga_model* model, int fpga_rows, const char* column
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (j && columns[j-1] == 'R') {
|
if (j && model->cfg_columns[j-1] == 'R') {
|
||||||
model->tiles[tile_columns + i].type = IO_BUFPLL_TERM_T;
|
model->tiles[tile_columns + i].type = IO_BUFPLL_TERM_T;
|
||||||
model->tiles[(tile_rows-2)*tile_columns + i].type = IO_BUFPLL_TERM_B;
|
model->tiles[(tile_rows-2)*tile_columns + i].type = IO_BUFPLL_TERM_B;
|
||||||
} else {
|
} else {
|
||||||
model->tiles[tile_columns + i].type = IO_TERM_T;
|
model->tiles[tile_columns + i].type = IO_TERM_T;
|
||||||
if (columns[j] == 'L' || columns[j] == 'M')
|
if (model->cfg_columns[j] == 'L' || model->cfg_columns[j] == 'M')
|
||||||
model->tiles[(tile_rows-2)*tile_columns + i].type = IO_TERM_B;
|
model->tiles[(tile_rows-2)*tile_columns + i].type = IO_TERM_B;
|
||||||
else
|
else
|
||||||
model->tiles[(tile_rows-2)*tile_columns + i].type = LOGIC_ROUTING_TERM_B;
|
model->tiles[(tile_rows-2)*tile_columns + i].type = LOGIC_ROUTING_TERM_B;
|
||||||
}
|
}
|
||||||
if (columns[j] == 'L' || columns[j] == 'M') {
|
if (model->cfg_columns[j] == 'L' || model->cfg_columns[j] == 'M') {
|
||||||
model->tiles[i].type = IO_T;
|
model->tiles[i].type = IO_T;
|
||||||
model->tiles[(tile_rows-1)*tile_columns + i].type = IO_B;
|
model->tiles[(tile_rows-1)*tile_columns + i].type = IO_B;
|
||||||
model->tiles[2*tile_columns + i].type = IO_ROUTING;
|
model->tiles[2*tile_columns + i].type = IO_ROUTING;
|
||||||
|
model->tiles[2*tile_columns + i].flags |= TF_DIRWIRE_START;
|
||||||
model->tiles[3*tile_columns + i].type = IO_ROUTING;
|
model->tiles[3*tile_columns + i].type = IO_ROUTING;
|
||||||
|
model->tiles[3*tile_columns + i].flags |= TF_DIRWIRE_START;
|
||||||
model->tiles[(tile_rows-4)*tile_columns + i].type = IO_ROUTING;
|
model->tiles[(tile_rows-4)*tile_columns + i].type = IO_ROUTING;
|
||||||
|
model->tiles[(tile_rows-4)*tile_columns + i].flags |= TF_DIRWIRE_START;
|
||||||
model->tiles[(tile_rows-3)*tile_columns + i].type = IO_ROUTING;
|
model->tiles[(tile_rows-3)*tile_columns + i].type = IO_ROUTING;
|
||||||
|
model->tiles[(tile_rows-3)*tile_columns + i].flags |= TF_DIRWIRE_START;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (j && columns[j-1] == 'R') {
|
if (j && model->cfg_columns[j-1] == 'R') {
|
||||||
model->tiles[tile_columns + i + 1].type = IO_LOGIC_REG_TERM_T;
|
model->tiles[tile_columns + i + 1].type = IO_LOGIC_REG_TERM_T;
|
||||||
model->tiles[(tile_rows-2)*tile_columns + i + 1].type = IO_LOGIC_REG_TERM_B;
|
model->tiles[(tile_rows-2)*tile_columns + i + 1].type = IO_LOGIC_REG_TERM_B;
|
||||||
} else {
|
} else {
|
||||||
model->tiles[tile_columns + i + 1].type = IO_LOGIC_TERM_T;
|
model->tiles[tile_columns + i + 1].type = IO_LOGIC_TERM_T;
|
||||||
if (columns[j] == 'L' || columns[j] == 'M')
|
if (model->cfg_columns[j] == 'L' || model->cfg_columns[j] == 'M')
|
||||||
model->tiles[(tile_rows-2)*tile_columns + i + 1].type = IO_LOGIC_TERM_B;
|
model->tiles[(tile_rows-2)*tile_columns + i + 1].type = IO_LOGIC_TERM_B;
|
||||||
else
|
else
|
||||||
model->tiles[(tile_rows-2)*tile_columns + i + 1].type = LOGIC_NOIO_TERM_B;
|
model->tiles[(tile_rows-2)*tile_columns + i + 1].type = LOGIC_NOIO_TERM_B;
|
||||||
}
|
}
|
||||||
if (columns[j] == 'L' || columns[j] == 'M') {
|
if (model->cfg_columns[j] == 'L' || model->cfg_columns[j] == 'M') {
|
||||||
model->tiles[2*tile_columns + i + 1].type = IO_OUTER_T;
|
model->tiles[2*tile_columns + i + 1].type = IO_OUTER_T;
|
||||||
model->tiles[3*tile_columns + i + 1].type = IO_INNER_T;
|
model->tiles[3*tile_columns + i + 1].type = IO_INNER_T;
|
||||||
model->tiles[(tile_rows-4)*tile_columns + i + 1].type = IO_INNER_B;
|
model->tiles[(tile_rows-4)*tile_columns + i + 1].type = IO_INNER_B;
|
||||||
model->tiles[(tile_rows-3)*tile_columns + i + 1].type = IO_OUTER_B;
|
model->tiles[(tile_rows-3)*tile_columns + i + 1].type = IO_OUTER_B;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (columns[j] == 'L' || columns[j] == 'l') {
|
if (model->cfg_columns[j] == 'L' || model->cfg_columns[j] == 'l') {
|
||||||
model->tiles[center_row*tile_columns + i].type = REGH_ROUTING_XL;
|
model->tiles[center_row*tile_columns + i].type = REGH_ROUTING_XL;
|
||||||
model->tiles[center_row*tile_columns + i + 1].type = REGH_LOGIC_XL;
|
model->tiles[center_row*tile_columns + i + 1].type = REGH_LOGIC_XL;
|
||||||
} else {
|
} else {
|
||||||
|
@ -269,11 +492,16 @@ int fpga_build_model(struct fpga_model* model, int fpga_rows, const char* column
|
||||||
i += 2;
|
i += 2;
|
||||||
break;
|
break;
|
||||||
case 'B':
|
case 'B':
|
||||||
for (k = fpga_rows-1; k >= 0; k--) {
|
for (k = model->cfg_rows-1; k >= 0; k--) {
|
||||||
row_top_y = 2 /* top IO tiles */ + (fpga_rows-1-k)*(8+1/*middle of row clock*/+8);
|
row_top_y = 2 /* top IO tiles */ + (model->cfg_rows-1-k)*(8+1/*middle of row clock*/+8);
|
||||||
if (k<(fpga_rows/2)) row_top_y++; // middle system tiles
|
if (k<(model->cfg_rows/2)) row_top_y++; // middle system tiles
|
||||||
for (l = 0; l < 16; l++) {
|
for (l = 0; l < 16; l++) {
|
||||||
model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + i].type = (l < 15) ? BRAM_ROUTING : BRAM_ROUTING_BRK;
|
tile_i0 = &model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + i];
|
||||||
|
if (l < 15) {
|
||||||
|
tile_i0->type = BRAM_ROUTING;
|
||||||
|
tile_i0->flags |= TF_DIRWIRE_START;
|
||||||
|
} else
|
||||||
|
tile_i0->type = BRAM_ROUTING_BRK;
|
||||||
model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + i + 1].type = ROUTING_VIA;
|
model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + i + 1].type = ROUTING_VIA;
|
||||||
if (!(l%4))
|
if (!(l%4))
|
||||||
model->tiles[(row_top_y+3+(l<8?l:l+1))*tile_columns + i + 2].type = BRAM;
|
model->tiles[(row_top_y+3+(l<8?l:l+1))*tile_columns + i + 2].type = BRAM;
|
||||||
|
@ -296,12 +524,17 @@ int fpga_build_model(struct fpga_model* model, int fpga_rows, const char* column
|
||||||
i += 3;
|
i += 3;
|
||||||
break;
|
break;
|
||||||
case 'D':
|
case 'D':
|
||||||
for (k = fpga_rows-1; k >= 0; k--) {
|
for (k = model->cfg_rows-1; k >= 0; k--) {
|
||||||
row_top_y = 2 /* top IO tiles */ + (fpga_rows-1-k)*(8+1/*middle of row clock*/+8);
|
row_top_y = 2 /* top IO tiles */ + (model->cfg_rows-1-k)*(8+1/*middle of row clock*/+8);
|
||||||
if (k<(fpga_rows/2)) row_top_y++; // middle system tiles
|
if (k<(model->cfg_rows/2)) row_top_y++; // middle system tiles
|
||||||
for (l = 0; l < 16; l++) {
|
for (l = 0; l < 16; l++) {
|
||||||
model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + i].type = (l < 15) ? ROUTING : ROUTING_BRK;
|
tile_i0 = &model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + i];
|
||||||
model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + i + 1].type = ROUTING_VIA;
|
if (l < 15) {
|
||||||
|
tile_i0->type = ROUTING;
|
||||||
|
tile_i0->flags |= TF_DIRWIRE_START;
|
||||||
|
} else
|
||||||
|
tile_i0->type = ROUTING_BRK;
|
||||||
|
tile_i0[1].type = ROUTING_VIA;
|
||||||
if (!(l%4))
|
if (!(l%4))
|
||||||
model->tiles[(row_top_y+3+(l<8?l:l+1))*tile_columns + i + 2].type = MACC;
|
model->tiles[(row_top_y+3+(l<8?l:l+1))*tile_columns + i + 2].type = MACC;
|
||||||
}
|
}
|
||||||
|
@ -323,56 +556,61 @@ int fpga_build_model(struct fpga_model* model, int fpga_rows, const char* column
|
||||||
i += 3;
|
i += 3;
|
||||||
break;
|
break;
|
||||||
case 'R':
|
case 'R':
|
||||||
if (columns[j+1] != 'M') {
|
if (model->cfg_columns[j+1] != 'M') {
|
||||||
// We expect a LOGIC_XM column to follow the center for
|
// We expect a LOGIC_XM column to follow the center for
|
||||||
// the top and bottom bufpll and reg routing.
|
// the top and bottom bufpll and reg routing.
|
||||||
fprintf(stderr, "Expecting LOGIC_XM after center but found '%c'\n", columns[j+1]);
|
fprintf(stderr, "Expecting LOGIC_XM after center but found '%c'\n", model->cfg_columns[j+1]);
|
||||||
}
|
}
|
||||||
left_side = 0;
|
left_side = 0;
|
||||||
for (k = fpga_rows-1; k >= 0; k--) {
|
for (k = model->cfg_rows-1; k >= 0; k--) {
|
||||||
row_top_y = 2 /* top IO tiles */ + (fpga_rows-1-k)*(8+1/*middle of row clock*/+8);
|
row_top_y = 2 /* top IO tiles */ + (model->cfg_rows-1-k)*(8+1/*middle of row clock*/+8);
|
||||||
if (k<(fpga_rows/2)) row_top_y++; // middle system tiles
|
if (k<(model->cfg_rows/2)) row_top_y++; // middle system tiles
|
||||||
|
|
||||||
for (l = 0; l < 16; l++) {
|
for (l = 0; l < 16; l++) {
|
||||||
|
|
||||||
if ((k < fpga_rows-1 || l >= 2) && (k || l<14)) {
|
if ((k < model->cfg_rows-1 || l >= 2) && (k || l<14)) {
|
||||||
model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + i].type =
|
tile_i0 = &model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + i];
|
||||||
(l < 15) ? ROUTING : ROUTING_BRK;
|
if (l < 15) {
|
||||||
if (l == 7) {
|
tile_i0->type = ROUTING;
|
||||||
model->tiles[(row_top_y+l)*tile_columns + i + 1].type = ROUTING_VIA_IO;
|
tile_i0->flags |= TF_DIRWIRE_START;
|
||||||
} else if (l == 8) {
|
|
||||||
model->tiles[(row_top_y+l+1)*tile_columns + i + 1].type =
|
|
||||||
(k%2) ? ROUTING_VIA_CARRY : ROUTING_VIA_IO_DCM;
|
|
||||||
} else if (l == 15 && k==fpga_rows/2) {
|
|
||||||
model->tiles[(row_top_y+l+1)*tile_columns + i + 1].type = ROUTING_VIA_REGC;
|
|
||||||
} else
|
} else
|
||||||
model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + i + 1].type = LOGIC_XL;
|
tile_i0->type = ROUTING_BRK;
|
||||||
|
if (l == 7)
|
||||||
|
tile_i0[1].type = ROUTING_VIA_IO;
|
||||||
|
else if (l == 8)
|
||||||
|
tile_i0[1].type = (k%2) ? ROUTING_VIA_CARRY : ROUTING_VIA_IO_DCM;
|
||||||
|
else if (l == 15 && k==model->cfg_rows/2)
|
||||||
|
tile_i0[1].type = ROUTING_VIA_REGC;
|
||||||
|
else
|
||||||
|
tile_i0[1].type = LOGIC_XL;
|
||||||
|
}
|
||||||
|
if (l == 7
|
||||||
|
|| (l == 8 && !(k%2))) { // even row, together with DCM
|
||||||
|
tile_i0 = &model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + i];
|
||||||
|
tile_i0->type = IO_ROUTING;
|
||||||
|
tile_i0->flags |= TF_DIRWIRE_START;
|
||||||
}
|
}
|
||||||
if (l == 7)
|
|
||||||
model->tiles[(row_top_y+l)*tile_columns + i].type = IO_ROUTING;
|
|
||||||
if (l == 8 && !(k%2)) // even row, together with DCM
|
|
||||||
model->tiles[(row_top_y+l+1)*tile_columns + i].type = IO_ROUTING;
|
|
||||||
|
|
||||||
if (l == 7) {
|
if (l == 7) {
|
||||||
if (k%2) // odd
|
if (k%2) // odd
|
||||||
model->tiles[(row_top_y+l)*tile_columns + i + 2].type = (k<(fpga_rows/2)) ? PLL_B : PLL_T;
|
model->tiles[(row_top_y+l)*tile_columns + i + 2].type = (k<(model->cfg_rows/2)) ? PLL_B : PLL_T;
|
||||||
else // even
|
else // even
|
||||||
model->tiles[(row_top_y+l)*tile_columns + i + 2].type = (k<(fpga_rows/2)) ? DCM_B : DCM_T;
|
model->tiles[(row_top_y+l)*tile_columns + i + 2].type = (k<(model->cfg_rows/2)) ? DCM_B : DCM_T;
|
||||||
}
|
}
|
||||||
// four midbuf tiles, in the middle of the top and bottom halves
|
// four midbuf tiles, in the middle of the top and bottom halves
|
||||||
if (l == 15) {
|
if (l == 15) {
|
||||||
if (k == fpga_rows*3/4)
|
if (k == model->cfg_rows*3/4)
|
||||||
model->tiles[(row_top_y+l+1)*tile_columns + i + 3].type = REGV_MIDBUF_T;
|
model->tiles[(row_top_y+l+1)*tile_columns + i + 3].type = REGV_MIDBUF_T;
|
||||||
else if (k == fpga_rows/4)
|
else if (k == model->cfg_rows/4)
|
||||||
model->tiles[(row_top_y+l+1)*tile_columns + i + 3].type = REGV_HCLKBUF_B;
|
model->tiles[(row_top_y+l+1)*tile_columns + i + 3].type = REGV_HCLKBUF_B;
|
||||||
else
|
else
|
||||||
model->tiles[(row_top_y+l+1)*tile_columns + i + 3].type = REGV_BRK;
|
model->tiles[(row_top_y+l+1)*tile_columns + i + 3].type = REGV_BRK;
|
||||||
} else if (l == 0 && k == fpga_rows*3/4-1) {
|
} else if (l == 0 && k == model->cfg_rows*3/4-1) {
|
||||||
model->tiles[(row_top_y+l)*tile_columns + i + 3].type = REGV_HCLKBUF_T;
|
model->tiles[(row_top_y+l)*tile_columns + i + 3].type = REGV_HCLKBUF_T;
|
||||||
} else if (l == 0 && k == fpga_rows/4-1) {
|
} else if (l == 0 && k == model->cfg_rows/4-1) {
|
||||||
model->tiles[(row_top_y+l)*tile_columns + i + 3].type = REGV_MIDBUF_B;
|
model->tiles[(row_top_y+l)*tile_columns + i + 3].type = REGV_MIDBUF_B;
|
||||||
} else if (l == 8) {
|
} else if (l == 8) {
|
||||||
model->tiles[(row_top_y+l+1)*tile_columns + i + 3].type = (k<fpga_rows/2) ? REGV_B : REGV_T;
|
model->tiles[(row_top_y+l+1)*tile_columns + i + 3].type = (k<model->cfg_rows/2) ? REGV_B : REGV_T;
|
||||||
} else
|
} else
|
||||||
model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + i + 3].type = REGV;
|
model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + i + 3].type = REGV;
|
||||||
}
|
}
|
||||||
|
@ -385,9 +623,13 @@ int fpga_build_model(struct fpga_model* model, int fpga_rows, const char* column
|
||||||
model->tiles[tile_columns + i].type = IO_TERM_T;
|
model->tiles[tile_columns + i].type = IO_TERM_T;
|
||||||
model->tiles[(tile_rows-2)*tile_columns + i].type = IO_TERM_B;
|
model->tiles[(tile_rows-2)*tile_columns + i].type = IO_TERM_B;
|
||||||
model->tiles[2*tile_columns + i].type = IO_ROUTING;
|
model->tiles[2*tile_columns + i].type = IO_ROUTING;
|
||||||
|
model->tiles[2*tile_columns + i].flags |= TF_DIRWIRE_START;
|
||||||
model->tiles[3*tile_columns + i].type = IO_ROUTING;
|
model->tiles[3*tile_columns + i].type = IO_ROUTING;
|
||||||
|
model->tiles[3*tile_columns + i].flags |= TF_DIRWIRE_START;
|
||||||
model->tiles[(tile_rows-4)*tile_columns + i].type = IO_ROUTING;
|
model->tiles[(tile_rows-4)*tile_columns + i].type = IO_ROUTING;
|
||||||
|
model->tiles[(tile_rows-4)*tile_columns + i].flags |= TF_DIRWIRE_START;
|
||||||
model->tiles[(tile_rows-3)*tile_columns + i].type = IO_ROUTING;
|
model->tiles[(tile_rows-3)*tile_columns + i].type = IO_ROUTING;
|
||||||
|
model->tiles[(tile_rows-3)*tile_columns + i].flags |= TF_DIRWIRE_START;
|
||||||
|
|
||||||
model->tiles[tile_columns + i + 1].type = IO_LOGIC_REG_TERM_T;
|
model->tiles[tile_columns + i + 1].type = IO_LOGIC_REG_TERM_T;
|
||||||
model->tiles[(tile_rows-2)*tile_columns + i + 1].type = IO_LOGIC_REG_TERM_B;
|
model->tiles[(tile_rows-2)*tile_columns + i + 1].type = IO_LOGIC_REG_TERM_B;
|
||||||
|
@ -407,10 +649,15 @@ int fpga_build_model(struct fpga_model* model, int fpga_rows, const char* column
|
||||||
model->tiles[center_row*tile_columns + i + 1].type = REGC_LOGIC;
|
model->tiles[center_row*tile_columns + i + 1].type = REGC_LOGIC;
|
||||||
model->tiles[center_row*tile_columns + i + 2].type = REGC_CMT;
|
model->tiles[center_row*tile_columns + i + 2].type = REGC_CMT;
|
||||||
model->tiles[center_row*tile_columns + i + 3].type = CENTER;
|
model->tiles[center_row*tile_columns + i + 3].type = CENTER;
|
||||||
|
|
||||||
|
// flag vertical axis of symmetry
|
||||||
|
for (y = 0; y < model->tile_y_range; y++)
|
||||||
|
model->tiles[y*model->tile_x_range + i + 3].flags |= TF_CHIP_VERT_AXSYMM;
|
||||||
|
|
||||||
i += 4;
|
i += 4;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
fprintf(stderr, "Unexpected column identifier '%c'\n", columns[j]);
|
fprintf(stderr, "Unexpected column identifier '%c'\n", model->cfg_columns[j]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -419,59 +666,61 @@ int fpga_build_model(struct fpga_model* model, int fpga_rows, const char* column
|
||||||
// left IO
|
// left IO
|
||||||
//
|
//
|
||||||
|
|
||||||
for (k = fpga_rows-1; k >= 0; k--) {
|
for (k = model->cfg_rows-1; k >= 0; k--) {
|
||||||
row_top_y = 2 /* top IO tiles */ + (fpga_rows-1-k)*(8+1/*middle of row clock*/+8);
|
row_top_y = 2 /* top IO tiles */ + (model->cfg_rows-1-k)*(8+1/*middle of row clock*/+8);
|
||||||
if (k<(fpga_rows/2)) row_top_y++; // middle system tiles
|
if (k<(model->cfg_rows/2)) row_top_y++; // middle system tiles
|
||||||
|
|
||||||
for (l = 0; l < 16; l++) {
|
for (l = 0; l < 16; l++) {
|
||||||
//
|
//
|
||||||
// +0
|
// +0
|
||||||
//
|
//
|
||||||
if (left_wiring[(fpga_rows-1-k)*16+l] == 'W')
|
if (model->cfg_left_wiring[(model->cfg_rows-1-k)*16+l] == 'W')
|
||||||
model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns].type = IO_L;
|
model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns].type = IO_L;
|
||||||
//
|
//
|
||||||
// +1
|
// +1
|
||||||
//
|
//
|
||||||
if ((k == fpga_rows-1 && !l) || (!k && l==15))
|
if ((k == model->cfg_rows-1 && !l) || (!k && l==15))
|
||||||
model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + 1].type = CORNER_TERM_L;
|
model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + 1].type = CORNER_TERM_L;
|
||||||
else if (k == fpga_rows/2 && l == 12)
|
else if (k == model->cfg_rows/2 && l == 12)
|
||||||
model->tiles[(row_top_y+l+1)*tile_columns + 1].type = IO_TERM_L_UPPER_TOP;
|
model->tiles[(row_top_y+l+1)*tile_columns + 1].type = IO_TERM_L_UPPER_TOP;
|
||||||
else if (k == fpga_rows/2 && l == 13)
|
else if (k == model->cfg_rows/2 && l == 13)
|
||||||
model->tiles[(row_top_y+l+1)*tile_columns + 1].type = IO_TERM_L_UPPER_BOT;
|
model->tiles[(row_top_y+l+1)*tile_columns + 1].type = IO_TERM_L_UPPER_BOT;
|
||||||
else if (k == (fpga_rows/2)-1 && !l)
|
else if (k == (model->cfg_rows/2)-1 && !l)
|
||||||
model->tiles[(row_top_y+l)*tile_columns + 1].type = IO_TERM_L_LOWER_TOP;
|
model->tiles[(row_top_y+l)*tile_columns + 1].type = IO_TERM_L_LOWER_TOP;
|
||||||
else if (k == (fpga_rows/2)-1 && l == 1)
|
else if (k == (model->cfg_rows/2)-1 && l == 1)
|
||||||
model->tiles[(row_top_y+l)*tile_columns + 1].type = IO_TERM_L_LOWER_BOT;
|
model->tiles[(row_top_y+l)*tile_columns + 1].type = IO_TERM_L_LOWER_BOT;
|
||||||
else
|
else
|
||||||
model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + 1].type = IO_TERM_L;
|
model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + 1].type = IO_TERM_L;
|
||||||
//
|
//
|
||||||
// +2
|
// +2
|
||||||
//
|
//
|
||||||
if (left_wiring[(fpga_rows-1-k)*16+l] == 'W') {
|
if (model->cfg_left_wiring[(model->cfg_rows-1-k)*16+l] == 'W') {
|
||||||
if (l == 15 && k && k != fpga_rows/2)
|
if (l == 15 && k && k != model->cfg_rows/2)
|
||||||
model->tiles[(row_top_y+l+1)*tile_columns + 2].type = ROUTING_IO_L_BRK;
|
model->tiles[(row_top_y+l+1)*tile_columns + 2].type = ROUTING_IO_L_BRK;
|
||||||
else
|
else
|
||||||
model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + 2].type = ROUTING_IO_L;
|
model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + 2].type = ROUTING_IO_L;
|
||||||
} else { // unwired
|
} else { // unwired
|
||||||
if (k && k != fpga_rows/2 && l == 15)
|
if (k && k != model->cfg_rows/2 && l == 15)
|
||||||
model->tiles[(row_top_y+l+1)*tile_columns + 2].type = ROUTING_BRK;
|
model->tiles[(row_top_y+l+1)*tile_columns + 2].type = ROUTING_BRK;
|
||||||
else if (k == fpga_rows/2 && l == 14)
|
else if (k == model->cfg_rows/2 && l == 14)
|
||||||
model->tiles[(row_top_y+l+1)*tile_columns + 2].type = ROUTING_GCLK;
|
model->tiles[(row_top_y+l+1)*tile_columns + 2].type = ROUTING_GCLK;
|
||||||
else
|
else {
|
||||||
model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + 2].type = ROUTING;
|
model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + 2].type = ROUTING;
|
||||||
|
model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + 2].flags |= TF_DIRWIRE_START;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
// +3
|
// +3
|
||||||
//
|
//
|
||||||
if (left_wiring[(fpga_rows-1-k)*16+l] == 'W') {
|
if (model->cfg_left_wiring[(model->cfg_rows-1-k)*16+l] == 'W') {
|
||||||
model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + 3].type = ROUTING_IO_VIA_L;
|
model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + 3].type = ROUTING_IO_VIA_L;
|
||||||
} else { // unwired
|
} else { // unwired
|
||||||
if (k == fpga_rows-1 && !l) {
|
if (k == model->cfg_rows-1 && !l) {
|
||||||
model->tiles[(row_top_y+l)*tile_columns + 3].type = CORNER_TL;
|
model->tiles[(row_top_y+l)*tile_columns + 3].type = CORNER_TL;
|
||||||
} else if (!k && l == 15) {
|
} else if (!k && l == 15) {
|
||||||
model->tiles[(row_top_y+l+1)*tile_columns + 3].type = CORNER_BL;
|
model->tiles[(row_top_y+l+1)*tile_columns + 3].type = CORNER_BL;
|
||||||
} else {
|
} else {
|
||||||
if (k && k != fpga_rows/2 && l == 15)
|
if (k && k != model->cfg_rows/2 && l == 15)
|
||||||
model->tiles[(row_top_y+l+1)*tile_columns + 3].type = ROUTING_VIA_CARRY;
|
model->tiles[(row_top_y+l+1)*tile_columns + 3].type = ROUTING_VIA_CARRY;
|
||||||
else
|
else
|
||||||
model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + 3].type = ROUTING_VIA;
|
model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + 3].type = ROUTING_VIA;
|
||||||
|
@ -480,17 +729,17 @@ int fpga_build_model(struct fpga_model* model, int fpga_rows, const char* column
|
||||||
}
|
}
|
||||||
model->tiles[(row_top_y+8)*tile_columns + 1].type = HCLK_TERM_L;
|
model->tiles[(row_top_y+8)*tile_columns + 1].type = HCLK_TERM_L;
|
||||||
model->tiles[(row_top_y+8)*tile_columns + 2].type = HCLK_ROUTING_IO_L;
|
model->tiles[(row_top_y+8)*tile_columns + 2].type = HCLK_ROUTING_IO_L;
|
||||||
if (k >= fpga_rows/2) { // top half
|
if (k >= model->cfg_rows/2) { // top half
|
||||||
if (k > (fpga_rows*3)/4)
|
if (k > (model->cfg_rows*3)/4)
|
||||||
model->tiles[(row_top_y+8)*tile_columns + 3].type = HCLK_IO_TOP_UP_L;
|
model->tiles[(row_top_y+8)*tile_columns + 3].type = HCLK_IO_TOP_UP_L;
|
||||||
else if (k == (fpga_rows*3)/4)
|
else if (k == (model->cfg_rows*3)/4)
|
||||||
model->tiles[(row_top_y+8)*tile_columns + 3].type = HCLK_IO_TOP_SPLIT_L;
|
model->tiles[(row_top_y+8)*tile_columns + 3].type = HCLK_IO_TOP_SPLIT_L;
|
||||||
else
|
else
|
||||||
model->tiles[(row_top_y+8)*tile_columns + 3].type = HCLK_IO_TOP_DN_L;
|
model->tiles[(row_top_y+8)*tile_columns + 3].type = HCLK_IO_TOP_DN_L;
|
||||||
} else { // bottom half
|
} else { // bottom half
|
||||||
if (k < fpga_rows/4 - 1)
|
if (k < model->cfg_rows/4 - 1)
|
||||||
model->tiles[(row_top_y+8)*tile_columns + 3].type = HCLK_IO_BOT_DN_L;
|
model->tiles[(row_top_y+8)*tile_columns + 3].type = HCLK_IO_BOT_DN_L;
|
||||||
else if (k == fpga_rows/4 - 1)
|
else if (k == model->cfg_rows/4 - 1)
|
||||||
model->tiles[(row_top_y+8)*tile_columns + 3].type = HCLK_IO_BOT_SPLIT_L;
|
model->tiles[(row_top_y+8)*tile_columns + 3].type = HCLK_IO_BOT_SPLIT_L;
|
||||||
else
|
else
|
||||||
model->tiles[(row_top_y+8)*tile_columns + 3].type = HCLK_IO_BOT_UP_L;
|
model->tiles[(row_top_y+8)*tile_columns + 3].type = HCLK_IO_BOT_UP_L;
|
||||||
|
@ -519,38 +768,38 @@ int fpga_build_model(struct fpga_model* model, int fpga_rows, const char* column
|
||||||
// right IO
|
// right IO
|
||||||
//
|
//
|
||||||
|
|
||||||
for (k = fpga_rows-1; k >= 0; k--) {
|
for (k = model->cfg_rows-1; k >= 0; k--) {
|
||||||
row_top_y = 2 /* top IO tiles */ + (fpga_rows-1-k)*(8+1/*middle of row clock*/+8);
|
row_top_y = 2 /* top IO tiles */ + (model->cfg_rows-1-k)*(8+1/*middle of row clock*/+8);
|
||||||
if (k<(fpga_rows/2)) row_top_y++; // middle system tiles
|
if (k<(model->cfg_rows/2)) row_top_y++; // middle system tiles
|
||||||
|
|
||||||
for (l = 0; l < 16; l++) {
|
for (l = 0; l < 16; l++) {
|
||||||
//
|
//
|
||||||
// -1
|
// -1
|
||||||
//
|
//
|
||||||
if (k == fpga_rows/2 && l == 13)
|
if (k == model->cfg_rows/2 && l == 13)
|
||||||
model->tiles[(row_top_y+l+1)*tile_columns + tile_columns - 1].type = IO_RDY_R;
|
model->tiles[(row_top_y+l+1)*tile_columns + tile_columns - 1].type = IO_RDY_R;
|
||||||
else if (k == fpga_rows/2 && l == 14)
|
else if (k == model->cfg_rows/2 && l == 14)
|
||||||
model->tiles[(row_top_y+l+1)*tile_columns + tile_columns - 1].type = IO_PCI_CONN_R;
|
model->tiles[(row_top_y+l+1)*tile_columns + tile_columns - 1].type = IO_PCI_CONN_R;
|
||||||
else if (k == fpga_rows/2 && l == 15)
|
else if (k == model->cfg_rows/2 && l == 15)
|
||||||
model->tiles[(row_top_y+l+1)*tile_columns + tile_columns - 1].type = IO_PCI_CONN_R;
|
model->tiles[(row_top_y+l+1)*tile_columns + tile_columns - 1].type = IO_PCI_CONN_R;
|
||||||
else if (k == fpga_rows/2-1 && !l)
|
else if (k == model->cfg_rows/2-1 && !l)
|
||||||
model->tiles[(row_top_y+l)*tile_columns + tile_columns - 1].type = IO_PCI_R;
|
model->tiles[(row_top_y+l)*tile_columns + tile_columns - 1].type = IO_PCI_R;
|
||||||
else {
|
else {
|
||||||
if (right_wiring[(fpga_rows-1-k)*16+l] == 'W')
|
if (model->cfg_right_wiring[(model->cfg_rows-1-k)*16+l] == 'W')
|
||||||
model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + tile_columns - 1].type = IO_R;
|
model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + tile_columns - 1].type = IO_R;
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
// -2
|
// -2
|
||||||
//
|
//
|
||||||
if ((k == fpga_rows-1 && (!l || l == 1)) || (!k && (l==15 || l==14)))
|
if ((k == model->cfg_rows-1 && (!l || l == 1)) || (!k && (l==15 || l==14)))
|
||||||
model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + tile_columns - 2].type = CORNER_TERM_R;
|
model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + tile_columns - 2].type = CORNER_TERM_R;
|
||||||
else if (k == fpga_rows/2 && l == 12)
|
else if (k == model->cfg_rows/2 && l == 12)
|
||||||
model->tiles[(row_top_y+l+1)*tile_columns + tile_columns - 2].type = IO_TERM_R_UPPER_TOP;
|
model->tiles[(row_top_y+l+1)*tile_columns + tile_columns - 2].type = IO_TERM_R_UPPER_TOP;
|
||||||
else if (k == fpga_rows/2 && l == 13)
|
else if (k == model->cfg_rows/2 && l == 13)
|
||||||
model->tiles[(row_top_y+l+1)*tile_columns + tile_columns - 2].type = IO_TERM_R_UPPER_BOT;
|
model->tiles[(row_top_y+l+1)*tile_columns + tile_columns - 2].type = IO_TERM_R_UPPER_BOT;
|
||||||
else if (k == (fpga_rows/2)-1 && !l)
|
else if (k == (model->cfg_rows/2)-1 && !l)
|
||||||
model->tiles[(row_top_y+l)*tile_columns + tile_columns - 2].type = IO_TERM_R_LOWER_TOP;
|
model->tiles[(row_top_y+l)*tile_columns + tile_columns - 2].type = IO_TERM_R_LOWER_TOP;
|
||||||
else if (k == (fpga_rows/2)-1 && l == 1)
|
else if (k == (model->cfg_rows/2)-1 && l == 1)
|
||||||
model->tiles[(row_top_y+l)*tile_columns + tile_columns - 2].type = IO_TERM_R_LOWER_BOT;
|
model->tiles[(row_top_y+l)*tile_columns + tile_columns - 2].type = IO_TERM_R_LOWER_BOT;
|
||||||
else
|
else
|
||||||
model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + tile_columns - 2].type = IO_TERM_R;
|
model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + tile_columns - 2].type = IO_TERM_R;
|
||||||
|
@ -560,14 +809,14 @@ int fpga_build_model(struct fpga_model* model, int fpga_rows, const char* column
|
||||||
//
|
//
|
||||||
// -4
|
// -4
|
||||||
//
|
//
|
||||||
if (right_wiring[(fpga_rows-1-k)*16+l] == 'W')
|
if (model->cfg_right_wiring[(model->cfg_rows-1-k)*16+l] == 'W')
|
||||||
model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + tile_columns - 4].type = ROUTING_IO_VIA_R;
|
model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + tile_columns - 4].type = ROUTING_IO_VIA_R;
|
||||||
else {
|
else {
|
||||||
if (k == fpga_rows-1 && l == 0)
|
if (k == model->cfg_rows-1 && l == 0)
|
||||||
model->tiles[(row_top_y+l)*tile_columns + tile_columns - 4].type = CORNER_TR_UPPER;
|
model->tiles[(row_top_y+l)*tile_columns + tile_columns - 4].type = CORNER_TR_UPPER;
|
||||||
else if (k == fpga_rows-1 && l == 1)
|
else if (k == model->cfg_rows-1 && l == 1)
|
||||||
model->tiles[(row_top_y+l)*tile_columns + tile_columns - 4].type = CORNER_TR_LOWER;
|
model->tiles[(row_top_y+l)*tile_columns + tile_columns - 4].type = CORNER_TR_LOWER;
|
||||||
else if (k && k != fpga_rows/2 && l == 15)
|
else if (k && k != model->cfg_rows/2 && l == 15)
|
||||||
model->tiles[(row_top_y+l+1)*tile_columns + tile_columns - 4].type = ROUTING_VIA_CARRY;
|
model->tiles[(row_top_y+l+1)*tile_columns + tile_columns - 4].type = ROUTING_VIA_CARRY;
|
||||||
else if (!k && l == 14)
|
else if (!k && l == 14)
|
||||||
model->tiles[(row_top_y+l+1)*tile_columns + tile_columns - 4].type = CORNER_BR_UPPER;
|
model->tiles[(row_top_y+l+1)*tile_columns + tile_columns - 4].type = CORNER_BR_UPPER;
|
||||||
|
@ -579,32 +828,35 @@ int fpga_build_model(struct fpga_model* model, int fpga_rows, const char* column
|
||||||
//
|
//
|
||||||
// -5
|
// -5
|
||||||
//
|
//
|
||||||
if (right_wiring[(fpga_rows-1-k)*16+l] == 'W')
|
if (model->cfg_right_wiring[(model->cfg_rows-1-k)*16+l] == 'W') {
|
||||||
model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + tile_columns - 5].type = IO_ROUTING;
|
model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + tile_columns - 5].type = IO_ROUTING;
|
||||||
else {
|
model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + tile_columns - 5].flags |= TF_DIRWIRE_START;
|
||||||
if (k && k != fpga_rows/2 && l == 15)
|
} else {
|
||||||
|
if (k && k != model->cfg_rows/2 && l == 15)
|
||||||
model->tiles[(row_top_y+l+1)*tile_columns + tile_columns - 5].type = ROUTING_BRK;
|
model->tiles[(row_top_y+l+1)*tile_columns + tile_columns - 5].type = ROUTING_BRK;
|
||||||
else if (k == fpga_rows/2 && l == 14)
|
else if (k == model->cfg_rows/2 && l == 14)
|
||||||
model->tiles[(row_top_y+l+1)*tile_columns + tile_columns - 5].type = ROUTING_GCLK;
|
model->tiles[(row_top_y+l+1)*tile_columns + tile_columns - 5].type = ROUTING_GCLK;
|
||||||
else
|
else {
|
||||||
model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + tile_columns - 5].type = ROUTING;
|
model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + tile_columns - 5].type = ROUTING;
|
||||||
|
model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + tile_columns - 5].flags |= TF_DIRWIRE_START;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
model->tiles[(row_top_y+8)*tile_columns + tile_columns - 2].type = HCLK_TERM_R;
|
model->tiles[(row_top_y+8)*tile_columns + tile_columns - 2].type = HCLK_TERM_R;
|
||||||
model->tiles[(row_top_y+8)*tile_columns + tile_columns - 3].type = HCLK_MCB;
|
model->tiles[(row_top_y+8)*tile_columns + tile_columns - 3].type = HCLK_MCB;
|
||||||
|
|
||||||
model->tiles[(row_top_y+8)*tile_columns + tile_columns - 5].type = HCLK_ROUTING_IO_R;
|
model->tiles[(row_top_y+8)*tile_columns + tile_columns - 5].type = HCLK_ROUTING_IO_R;
|
||||||
if (k >= fpga_rows/2) { // top half
|
if (k >= model->cfg_rows/2) { // top half
|
||||||
if (k > (fpga_rows*3)/4)
|
if (k > (model->cfg_rows*3)/4)
|
||||||
model->tiles[(row_top_y+8)*tile_columns + tile_columns - 4].type = HCLK_IO_TOP_UP_R;
|
model->tiles[(row_top_y+8)*tile_columns + tile_columns - 4].type = HCLK_IO_TOP_UP_R;
|
||||||
else if (k == (fpga_rows*3)/4)
|
else if (k == (model->cfg_rows*3)/4)
|
||||||
model->tiles[(row_top_y+8)*tile_columns + tile_columns - 4].type = HCLK_IO_TOP_SPLIT_R;
|
model->tiles[(row_top_y+8)*tile_columns + tile_columns - 4].type = HCLK_IO_TOP_SPLIT_R;
|
||||||
else
|
else
|
||||||
model->tiles[(row_top_y+8)*tile_columns + tile_columns - 4].type = HCLK_IO_TOP_DN_R;
|
model->tiles[(row_top_y+8)*tile_columns + tile_columns - 4].type = HCLK_IO_TOP_DN_R;
|
||||||
} else { // bottom half
|
} else { // bottom half
|
||||||
if (k < fpga_rows/4 - 1)
|
if (k < model->cfg_rows/4 - 1)
|
||||||
model->tiles[(row_top_y+8)*tile_columns + tile_columns - 4].type = HCLK_IO_BOT_DN_R;
|
model->tiles[(row_top_y+8)*tile_columns + tile_columns - 4].type = HCLK_IO_BOT_DN_R;
|
||||||
else if (k == fpga_rows/4 - 1)
|
else if (k == model->cfg_rows/4 - 1)
|
||||||
model->tiles[(row_top_y+8)*tile_columns + tile_columns - 4].type = HCLK_IO_BOT_SPLIT_R;
|
model->tiles[(row_top_y+8)*tile_columns + tile_columns - 4].type = HCLK_IO_BOT_SPLIT_R;
|
||||||
else
|
else
|
||||||
model->tiles[(row_top_y+8)*tile_columns + tile_columns - 4].type = HCLK_IO_BOT_UP_R;
|
model->tiles[(row_top_y+8)*tile_columns + tile_columns - 4].type = HCLK_IO_BOT_UP_R;
|
||||||
|
@ -619,13 +871,13 @@ int fpga_build_model(struct fpga_model* model, int fpga_rows, const char* column
|
||||||
model->tiles[center_row*tile_columns + tile_columns - 3].type = REGH_MCB;
|
model->tiles[center_row*tile_columns + tile_columns - 3].type = REGH_MCB;
|
||||||
model->tiles[center_row*tile_columns + tile_columns - 4].type = REGH_IO_R;
|
model->tiles[center_row*tile_columns + tile_columns - 4].type = REGH_IO_R;
|
||||||
model->tiles[center_row*tile_columns + tile_columns - 5].type = REGH_ROUTING_IO_R;
|
model->tiles[center_row*tile_columns + tile_columns - 5].type = REGH_ROUTING_IO_R;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void fpga_free_model(struct fpga_model* model)
|
void fpga_free_model(struct fpga_model* model)
|
||||||
{
|
{
|
||||||
if (!model) return;
|
if (!model) return;
|
||||||
|
strarray_free(&model->str);
|
||||||
free(model->tiles);
|
free(model->tiles);
|
||||||
memset(model, 0, sizeof(*model));
|
memset(model, 0, sizeof(*model));
|
||||||
}
|
}
|
||||||
|
@ -638,9 +890,9 @@ const char* fpga_tiletype_str(enum fpga_tile_type type)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dan Bernstein's hash function
|
// Dan Bernstein's hash function
|
||||||
unsigned long hash_djb2(const unsigned char* str)
|
uint32_t hash_djb2(const unsigned char* str)
|
||||||
{
|
{
|
||||||
unsigned long hash = 5381;
|
uint32_t hash = 5381;
|
||||||
int c;
|
int c;
|
||||||
|
|
||||||
while ((c = *str++) != 0)
|
while ((c = *str++) != 0)
|
||||||
|
@ -661,8 +913,13 @@ unsigned long hash_djb2(const unsigned char* str)
|
||||||
|
|
||||||
const char* strarray_lookup(struct hashed_strarray* array, uint16_t idx)
|
const char* strarray_lookup(struct hashed_strarray* array, uint16_t idx)
|
||||||
{
|
{
|
||||||
int bin = array->index_to_bin[idx];
|
int bin, offset;
|
||||||
int offset = array->bin_offsets[idx];
|
|
||||||
|
if (!array->index_to_bin || !array->bin_offsets || !idx)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
bin = array->index_to_bin[idx];
|
||||||
|
offset = array->bin_offsets[idx];
|
||||||
|
|
||||||
// bin 0 offset 0 is a special value that signals 'no
|
// bin 0 offset 0 is a special value that signals 'no
|
||||||
// entry'. Normal offsets cannot be less than 4.
|
// entry'. Normal offsets cannot be less than 4.
|
||||||
|
@ -683,7 +940,7 @@ const char* strarray_lookup(struct hashed_strarray* array, uint16_t idx)
|
||||||
int strarray_find_or_add(struct hashed_strarray* array, const char* str,
|
int strarray_find_or_add(struct hashed_strarray* array, const char* str,
|
||||||
uint16_t* idx)
|
uint16_t* idx)
|
||||||
{
|
{
|
||||||
int bin, search_off, str_len, i, num_indices, free_index;
|
int bin, search_off, str_len, i, free_index;
|
||||||
int new_alloclen, start_index;
|
int new_alloclen, start_index;
|
||||||
unsigned long hash;
|
unsigned long hash;
|
||||||
void* new_ptr;
|
void* new_ptr;
|
||||||
|
@ -699,6 +956,10 @@ int strarray_find_or_add(struct hashed_strarray* array, const char* str,
|
||||||
str)) {
|
str)) {
|
||||||
*idx = *(uint16_t*)&array->bin_strings
|
*idx = *(uint16_t*)&array->bin_strings
|
||||||
[bin][search_off-4];
|
[bin][search_off-4];
|
||||||
|
if (!(*idx)) {
|
||||||
|
fprintf(stderr, "Internal error - index 0.\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
search_off += *(uint16_t*)&array->bin_strings
|
search_off += *(uint16_t*)&array->bin_strings
|
||||||
|
@ -706,17 +967,19 @@ int strarray_find_or_add(struct hashed_strarray* array, const char* str,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// search free index
|
// search free index
|
||||||
num_indices = sizeof(array->bin_offsets)/sizeof(array->bin_offsets[0]);
|
start_index = (uint16_t) ((hash >> 16) ^ (hash & 0xFFFF));
|
||||||
start_index = hash % num_indices;
|
for (i = 0; i < HASHARRAY_NUM_INDICES; i++) {
|
||||||
for (i = 0; i < num_indices; i++) {
|
int cur_i = (start_index+i)%HASHARRAY_NUM_INDICES;
|
||||||
if (!array->bin_offsets[(start_index+i)%num_indices])
|
if (!cur_i) // never issue index 0
|
||||||
|
continue;
|
||||||
|
if (!array->bin_offsets[cur_i])
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (i >= num_indices) {
|
if (i >= HASHARRAY_NUM_INDICES) {
|
||||||
fprintf(stderr, "All array indices full.\n");
|
fprintf(stderr, "All array indices full.\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
free_index = (start_index+i)%num_indices;
|
free_index = (start_index+i)%HASHARRAY_NUM_INDICES;
|
||||||
// check whether bin needs expansion
|
// check whether bin needs expansion
|
||||||
if (!(array->bin_len[bin]%BIN_INCREMENT)
|
if (!(array->bin_len[bin]%BIN_INCREMENT)
|
||||||
|| array->bin_len[bin]%BIN_INCREMENT + 4+str_len+1 > BIN_INCREMENT)
|
|| array->bin_len[bin]%BIN_INCREMENT + 4+str_len+1 > BIN_INCREMENT)
|
||||||
|
@ -743,6 +1006,18 @@ int strarray_find_or_add(struct hashed_strarray* array, const char* str,
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int strarray_used_slots(struct hashed_strarray* array)
|
||||||
|
{
|
||||||
|
int i, num_used_slots;
|
||||||
|
num_used_slots = 0;
|
||||||
|
if (!array->bin_offsets) return 0;
|
||||||
|
for (i = 0; i < sizeof(array->bin_offsets)/sizeof(*array->bin_offsets); i++) {
|
||||||
|
if (array->bin_offsets[i])
|
||||||
|
num_used_slots++;
|
||||||
|
}
|
||||||
|
return num_used_slots;
|
||||||
|
}
|
||||||
|
|
||||||
void strarray_init(struct hashed_strarray* array)
|
void strarray_init(struct hashed_strarray* array)
|
||||||
{
|
{
|
||||||
memset(array, 0, sizeof(*array));
|
memset(array, 0, sizeof(*array));
|
||||||
|
|
76
model.h
76
model.h
|
@ -12,6 +12,20 @@
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#define HASHARRAY_NUM_INDICES (256*256)
|
||||||
|
|
||||||
|
// Strings are distributed among 1024 bins. Each bin
|
||||||
|
// is one continuous stream of zero-terminated strings
|
||||||
|
// prefixed with a 2*16-bit header. The allocation
|
||||||
|
// increment for each bin is 32k.
|
||||||
|
struct hashed_strarray
|
||||||
|
{
|
||||||
|
uint32_t bin_offsets[HASHARRAY_NUM_INDICES]; // min offset is 4, 0 means no entry
|
||||||
|
uint16_t index_to_bin[HASHARRAY_NUM_INDICES];
|
||||||
|
char* bin_strings[1024];
|
||||||
|
int bin_len[1024]; // points behind the last zero-termination
|
||||||
|
};
|
||||||
|
|
||||||
// columns
|
// columns
|
||||||
// 'L' = X+L logic block
|
// 'L' = X+L logic block
|
||||||
// 'l' = X+L logic block without IO at top and bottom
|
// 'l' = X+L logic block without IO at top and bottom
|
||||||
|
@ -40,8 +54,13 @@
|
||||||
|
|
||||||
struct fpga_model
|
struct fpga_model
|
||||||
{
|
{
|
||||||
|
int cfg_rows;
|
||||||
|
char cfg_columns[512];
|
||||||
|
char cfg_left_wiring[1024], cfg_right_wiring[1024];
|
||||||
|
|
||||||
int tile_x_range, tile_y_range;
|
int tile_x_range, tile_y_range;
|
||||||
struct fpga_tile* tiles;
|
struct fpga_tile* tiles;
|
||||||
|
struct hashed_strarray str;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum fpga_tile_type
|
enum fpga_tile_type
|
||||||
|
@ -100,40 +119,46 @@ enum fpga_tile_type
|
||||||
HCLK_IO_BOT_DN_L, HCLK_IO_BOT_DN_R,
|
HCLK_IO_BOT_DN_L, HCLK_IO_BOT_DN_R,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// tile flags
|
||||||
|
|
||||||
|
#define TF_DIRWIRE_START 0x0001
|
||||||
|
#define TF_FIRST_ROW 0x0002
|
||||||
|
#define TF_SECOND_ROW 0x0004
|
||||||
|
#define TF_SECOND_TO_LAST_ROW 0x0008
|
||||||
|
#define TF_LAST_ROW 0x0010
|
||||||
|
#define TF_ROW_HORIZ_AXSYMM 0x0020
|
||||||
|
#define TF_CHIP_HORIZ_AXSYMM 0x0040
|
||||||
|
#define TF_CHIP_VERT_AXSYMM 0x0080
|
||||||
|
|
||||||
struct fpga_tile
|
struct fpga_tile
|
||||||
{
|
{
|
||||||
enum fpga_tile_type type;
|
enum fpga_tile_type type;
|
||||||
|
int flags;
|
||||||
|
|
||||||
// expect up to 64 devices per tile
|
// expect up to 64 devices per tile
|
||||||
int num_devices;
|
int num_devices;
|
||||||
struct fpga_device* devices;
|
struct fpga_device* devices;
|
||||||
|
|
||||||
|
// expect up to 5k connection names per tile
|
||||||
|
// 2*16 bit per entry
|
||||||
|
// - index into conns (not multiplied by 3) (16bit)
|
||||||
|
// - hashed string array index (16 bit)
|
||||||
|
int num_conn_names; // conn_names is 2*num_conn_names 16-bit words
|
||||||
|
uint16_t* conn_names; // num_conn_names*2 16-bit-words: 16(conn)-16(str)
|
||||||
|
|
||||||
// expect up to 28k connections to other tiles per tile
|
// expect up to 28k connections to other tiles per tile
|
||||||
// 3*16 bit per connection:
|
// 3*16 bit per connection:
|
||||||
// - x coordinate of other tile (16bit)
|
// - x coordinate of other tile (16bit)
|
||||||
// - y coordinate of other tile (16bit)
|
// - y coordinate of other tile (16bit)
|
||||||
// - endpoint index in other tile (16bit)
|
// - hashed string array index for conn_names name in other tile (16bit)
|
||||||
int num_conns; // conns array is 3*num_conns 16-bit words
|
int num_conns; // conns array is 3*num_conns 16-bit words
|
||||||
uint16_t* conns; // num_conns*3 16-bit words: 16(x)-16(y)-16(endpoint)
|
uint16_t* conns; // num_conns*3 16-bit words: 16(x)-16(y)-16(conn_name)
|
||||||
|
|
||||||
// expect up to 5k endpoints per tile
|
|
||||||
// 16-bit index into conns (not yet multiplied by 3)
|
|
||||||
int num_endpoints;
|
|
||||||
uint16_t* endpoints;
|
|
||||||
// endpoints0 are conceptual endpoints without outgoing wires.
|
|
||||||
// Imagine their indices added to the end of num_endpoints, so
|
|
||||||
// the first endpoint0 is at index num_endpoints, the second one
|
|
||||||
// at num_endpoints+1, and so on.
|
|
||||||
int num_endpoints0;
|
|
||||||
// If != 0, endpoint_names will have
|
|
||||||
// num_endpoints + num_endpoints0 entries.
|
|
||||||
uint16_t* endpoint_names;
|
|
||||||
|
|
||||||
// expect up to 4k connection pairs per tile
|
// expect up to 4k connection pairs per tile
|
||||||
// 32bit: 31 off: not in use on: used
|
// 32bit: 31 off: not in use on: used
|
||||||
// 30 off: unidirectional on: bidirectional
|
// 30 off: unidirectional on: bidirectional
|
||||||
// 29:15 from, index into endpoints
|
// 29:15 from, index into conn_names
|
||||||
// 14:0 to, index into endpoints
|
// 14:0 to, index into conn_names
|
||||||
int num_connect_pairs;
|
int num_connect_pairs;
|
||||||
uint32_t* connect_pairs;
|
uint32_t* connect_pairs;
|
||||||
};
|
};
|
||||||
|
@ -145,22 +170,13 @@ void fpga_free_model(struct fpga_model* model);
|
||||||
|
|
||||||
const char* fpga_tiletype_str(enum fpga_tile_type type);
|
const char* fpga_tiletype_str(enum fpga_tile_type type);
|
||||||
|
|
||||||
unsigned long hash_djb2(const unsigned char* str);
|
uint32_t hash_djb2(const unsigned char* str);
|
||||||
|
|
||||||
// Strings are distributed among 1024 bins. Each bin
|
|
||||||
// is one continuous stream of zero-terminated strings
|
|
||||||
// prefixed with a 2*16-bit header. The allocation
|
|
||||||
// increment for each bin is 32k.
|
|
||||||
struct hashed_strarray
|
|
||||||
{
|
|
||||||
uint32_t bin_offsets[256*256]; // min offset is 4, 0 means no entry
|
|
||||||
uint16_t index_to_bin[256*256];
|
|
||||||
char* bin_strings[1024];
|
|
||||||
int bin_len[1024]; // points behind the last zero-termination
|
|
||||||
};
|
|
||||||
|
|
||||||
const char* strarray_lookup(struct hashed_strarray* array, uint16_t idx);
|
const char* strarray_lookup(struct hashed_strarray* array, uint16_t idx);
|
||||||
|
// The found or created index will never be 0, so the caller
|
||||||
|
// can use 0 as a special value to indicate 'no string'.
|
||||||
int strarray_find_or_add(struct hashed_strarray* array, const char* str,
|
int strarray_find_or_add(struct hashed_strarray* array, const char* str,
|
||||||
uint16_t* idx);
|
uint16_t* idx);
|
||||||
|
int strarray_used_slots(struct hashed_strarray* array);
|
||||||
void strarray_init(struct hashed_strarray* array);
|
void strarray_init(struct hashed_strarray* array);
|
||||||
void strarray_free(struct hashed_strarray* array);
|
void strarray_free(struct hashed_strarray* array);
|
||||||
|
|
|
@ -16,18 +16,34 @@
|
||||||
|
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
struct fpga_model* model = 0;
|
struct fpga_model model;
|
||||||
int x, y;
|
int x, y;
|
||||||
|
|
||||||
model = fpga_build_model(XC6SLX9_ROWS, XC6SLX9_COLUMNS,
|
if (fpga_build_model(&model, XC6SLX9_ROWS, XC6SLX9_COLUMNS,
|
||||||
XC6SLX9_LEFT_WIRING, XC6SLX9_RIGHT_WIRING);
|
XC6SLX9_LEFT_WIRING, XC6SLX9_RIGHT_WIRING))
|
||||||
if (!model) goto fail;
|
goto fail;
|
||||||
|
|
||||||
printf("fpga_floorplan_format 1\n");
|
printf("fpga_floorplan_format 1\n");
|
||||||
for (y = 0; y < model->tile_y_range; y++) {
|
//
|
||||||
for (x = 0; x < model->tile_x_range; x++) {
|
// What needs to be in the file:
|
||||||
printf("x%i y%i %s\n", x, y,
|
// - all devices, configuration for each device
|
||||||
fpga_tiletype_str(model->tiles[y*model->tile_x_range + x].type));
|
// probably multiple lines that are adding config strings
|
||||||
|
// - wires maybe separately, and/or as named connection points
|
||||||
|
// in tiles?
|
||||||
|
// - connection pairs that can be enabled/disabled
|
||||||
|
// - global flags and configuration registers
|
||||||
|
// - the static data should be optional (unused conn pairs,
|
||||||
|
// unused devices, wires)
|
||||||
|
//
|
||||||
|
// - each line should be in the global namespace, line order
|
||||||
|
// should not matter
|
||||||
|
// - file should be easily parsable with bison
|
||||||
|
// - lines should typically not exceed 80 characters
|
||||||
|
//
|
||||||
|
for (y = 0; y < model.tile_y_range; y++) {
|
||||||
|
for (x = 0; x < model.tile_x_range; x++) {
|
||||||
|
printf("y%i x%i %s\n", y, x,
|
||||||
|
fpga_tiletype_str(model.tiles[y*model.tile_x_range + x].type));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user