aboutsummaryrefslogtreecommitdiffstats
path: root/ice40
diff options
context:
space:
mode:
Diffstat (limited to 'ice40')
-rw-r--r--ice40/bitstream.cc166
-rw-r--r--ice40/bitstream.h1
-rw-r--r--ice40/main.cc8
3 files changed, 142 insertions, 33 deletions
diff --git a/ice40/bitstream.cc b/ice40/bitstream.cc
index c12fa90e..b0f6260d 100644
--- a/ice40/bitstream.cc
+++ b/ice40/bitstream.cc
@@ -157,6 +157,42 @@ void configure_extra_cell(chipconfig_t &config, const Context *ctx, CellInfo *ce
}
}
+std::string tagTileType(TileType &tile)
+{
+ if (tile == TILE_NONE)
+ return "";
+ switch (tile) {
+ case TILE_LOGIC:
+ return ".logic_tile";
+ break;
+ case TILE_IO:
+ return ".io_tile";
+ break;
+ case TILE_RAMB:
+ return ".ramb_tile";
+ break;
+ case TILE_RAMT:
+ return ".ramt_tile";
+ break;
+ case TILE_DSP0:
+ return ".dsp0_tile";
+ break;
+ case TILE_DSP1:
+ return ".dsp1_tile";
+ break;
+ case TILE_DSP2:
+ return ".dsp2_tile";
+ break;
+ case TILE_DSP3:
+ return ".dsp3_tile";
+ break;
+ case TILE_IPCON:
+ return ".ipcon_tile";
+ break;
+ default:
+ NPNR_ASSERT(false);
+ }
+}
void write_asc(const Context *ctx, std::ostream &out)
{
// [y][x][row][col]
@@ -443,39 +479,7 @@ void write_asc(const Context *ctx, std::ostream &out)
for (int y = 0; y < ci.height; y++) {
for (int x = 0; x < ci.width; x++) {
TileType tile = tile_at(ctx, x, y);
- if (tile == TILE_NONE)
- continue;
- switch (tile) {
- case TILE_LOGIC:
- out << ".logic_tile";
- break;
- case TILE_IO:
- out << ".io_tile";
- break;
- case TILE_RAMB:
- out << ".ramb_tile";
- break;
- case TILE_RAMT:
- out << ".ramt_tile";
- break;
- case TILE_DSP0:
- out << ".dsp0_tile";
- break;
- case TILE_DSP1:
- out << ".dsp1_tile";
- break;
- case TILE_DSP2:
- out << ".dsp2_tile";
- break;
- case TILE_DSP3:
- out << ".dsp3_tile";
- break;
- case TILE_IPCON:
- out << ".ipcon_tile";
- break;
- default:
- NPNR_ASSERT(false);
- }
+ out << tagTileType(tile);
out << " " << x << " " << y << std::endl;
for (auto row : config.at(y).at(x)) {
for (auto col : row) {
@@ -526,4 +530,100 @@ void write_asc(const Context *ctx, std::ostream &out)
}
}
+void read_config(Context *ctx, std::istream &in, chipconfig_t &config)
+{
+ constexpr size_t line_buf_size = 65536;
+ char buffer[line_buf_size];
+ int tile_x = -1, tile_y = -1, line_nr = -1;
+
+ while (1) {
+ in.getline(buffer, line_buf_size);
+ if (buffer[0] == '.') {
+ line_nr = -1;
+ const char *tok = strtok(buffer, " \t\r\n");
+
+ if (!strcmp(tok, ".device")) {
+ std::string config_device = strtok(nullptr, " \t\r\n");
+ std::string expected;
+ switch (ctx->args.type) {
+ case ArchArgs::LP384:
+ expected = "384";
+ break;
+ case ArchArgs::HX1K:
+ case ArchArgs::LP1K:
+ expected = "1k";
+ break;
+ case ArchArgs::HX8K:
+ case ArchArgs::LP8K:
+ expected = "8k";
+ break;
+ case ArchArgs::UP5K:
+ expected = "5k";
+ break;
+ default:
+ log_error("unsupported device type");
+ }
+ if (expected != config_device)
+ log_error("device type does not match");
+ } else if (!strcmp(tok, ".io_tile") || !strcmp(tok, ".logic_tile") || !strcmp(tok, ".ramb_tile") ||
+ !strcmp(tok, ".ramt_tile") || !strcmp(tok, ".ipcon_tile") || !strcmp(tok, ".dsp0_tile") ||
+ !strcmp(tok, ".dsp1_tile") || !strcmp(tok, ".dsp2_tile") || !strcmp(tok, ".dsp3_tile")) {
+ line_nr = 0;
+ tile_x = atoi(strtok(nullptr, " \t\r\n"));
+ tile_y = atoi(strtok(nullptr, " \t\r\n"));
+
+ TileType tile = tile_at(ctx, tile_x, tile_y);
+ if (tok != tagTileType(tile))
+ log_error("Wrong tile type for specified position");
+
+ } else if (!strcmp(tok, ".extra_bit")) {
+ /*
+ int b = atoi(strtok(nullptr, " \t\r\n"));
+ int x = atoi(strtok(nullptr, " \t\r\n"));
+ int y = atoi(strtok(nullptr, " \t\r\n"));
+ std::tuple<int, int, int> key(b, x, y);
+ extra_bits.insert(key);
+ */
+ } else if (!strcmp(tok, ".sym")) {
+ int net = atoi(strtok(nullptr, " \t\r\n")); (void)net;
+ const char *name = strtok(nullptr, " \t\r\n");
+ std::unique_ptr<NetInfo> created_net = std::unique_ptr<NetInfo>(new NetInfo);
+ created_net->name = ctx->id(name);
+ ctx->nets[created_net->name] = std::move(created_net);
+ }
+ } else if (line_nr >= 0 && strlen(buffer) > 0) {
+ if (line_nr > int(config.at(tile_y).at(tile_x).size() - 1))
+ log_error("Invalid data in input asc file");
+ for (int i = 0; buffer[i] == '0' || buffer[i] == '1'; i++)
+ config.at(tile_y).at(tile_x).at(line_nr).at(i) = (buffer[i] == '1') ? 1 : 0;
+ line_nr++;
+ }
+ if (in.eof())
+ break;
+ }
+}
+
+bool read_asc(Context *ctx, std::istream &in)
+{
+ try {
+ // [y][x][row][col]
+ const ChipInfoPOD &ci = *ctx->chip_info;
+ const BitstreamInfoPOD &bi = *ci.bits_info;
+ chipconfig_t config;
+ config.resize(ci.height);
+ for (int y = 0; y < ci.height; y++) {
+ config.at(y).resize(ci.width);
+ for (int x = 0; x < ci.width; x++) {
+ TileType tile = tile_at(ctx, x, y);
+ int rows = bi.tiles_nonrouting[tile].rows;
+ int cols = bi.tiles_nonrouting[tile].cols;
+ config.at(y).at(x).resize(rows, std::vector<int8_t>(cols));
+ }
+ }
+ read_config(ctx, in, config);
+ return true;
+ } catch (log_execution_error_exception) {
+ return false;
+ }
+}
NEXTPNR_NAMESPACE_END
diff --git a/ice40/bitstream.h b/ice40/bitstream.h
index 2b6cda1d..41a2ae68 100644
--- a/ice40/bitstream.h
+++ b/ice40/bitstream.h
@@ -27,6 +27,7 @@
NEXTPNR_NAMESPACE_BEGIN
void write_asc(const Context *ctx, std::ostream &out);
+bool read_asc(Context *ctx, std::istream &in);
NEXTPNR_NAMESPACE_END
diff --git a/ice40/main.cc b/ice40/main.cc
index e77bdd34..c14b6086 100644
--- a/ice40/main.cc
+++ b/ice40/main.cc
@@ -95,6 +95,7 @@ int main(int argc, char *argv[])
options.add_options()("json", po::value<std::string>(), "JSON design file to ingest");
options.add_options()("pcf", po::value<std::string>(), "PCF constraints file to ingest");
options.add_options()("asc", po::value<std::string>(), "asc bitstream file to write");
+ options.add_options()("read", po::value<std::string>(), "asc bitstream file to read");
options.add_options()("seed", po::value<int>(), "seed value for random number generator");
options.add_options()("version,V", "show version");
options.add_options()("tmfuzz", "run path delay estimate fuzzer");
@@ -353,6 +354,13 @@ int main(int argc, char *argv[])
if (vm.count("no-tmdriv"))
ctx->timing_driven = false;
+ if (vm.count("read")) {
+ std::string filename = vm["read"].as<std::string>();
+ std::ifstream f(filename);
+ if (!read_asc(ctx.get(), f))
+ log_error("Loading ASC failed.\n");
+ }
+
#ifndef NO_GUI
if (vm.count("gui")) {
Application a(argc, argv);