From d0fed3cce4374cd30ece6325773b338e156ade47 Mon Sep 17 00:00:00 2001 From: Markus Koch Date: Tue, 18 Jun 2019 20:15:35 +0200 Subject: [PATCH] Implement ISP chain walker --- sw/kousaten/fdef/{16x16.fdef => 4x4.fdef} | 0 sw/kousaten/src/fpga.c | 23 ++++++ sw/kousaten/src/fpga.h | 7 ++ sw/kousaten/src/fpga_cell.c | 97 +++++++++++++++++++++-- sw/kousaten/src/fpga_cell.h | 30 +++++-- sw/kousaten/src/fpga_cell_lut34.c | 29 +++++-- sw/kousaten/src/fpga_cell_lut34.h | 4 +- sw/kousaten/src/fpga_cell_none.c | 17 ++-- sw/kousaten/src/fpga_cell_none.h | 4 +- sw/kousaten/src/fpga_cell_wire.c | 61 ++++++++++++++ sw/kousaten/src/fpga_cell_wire.h | 14 ++++ sw/kousaten/src/fpga_fdef_loader.c | 19 +---- sw/kousaten/src/main.c | 20 ++++- 13 files changed, 276 insertions(+), 49 deletions(-) rename sw/kousaten/fdef/{16x16.fdef => 4x4.fdef} (100%) create mode 100644 sw/kousaten/src/fpga.c create mode 100644 sw/kousaten/src/fpga.h create mode 100644 sw/kousaten/src/fpga_cell_wire.c create mode 100644 sw/kousaten/src/fpga_cell_wire.h diff --git a/sw/kousaten/fdef/16x16.fdef b/sw/kousaten/fdef/4x4.fdef similarity index 100% rename from sw/kousaten/fdef/16x16.fdef rename to sw/kousaten/fdef/4x4.fdef diff --git a/sw/kousaten/src/fpga.c b/sw/kousaten/src/fpga.c new file mode 100644 index 0000000..2336497 --- /dev/null +++ b/sw/kousaten/src/fpga.c @@ -0,0 +1,23 @@ +#include "fpga.h" +#include "fpga_global.h" + +int fpga_generate_bitstream(struct fpga_cell *cell) +{ + struct fpga_cell *current_cell = cell; + enum fpga_isp_channel current_channel = FPGA_ISP_CHANNEL_NORMAL; + + while (current_cell) { + report(LL_DEBUG, + "Adding %p (%c) to ISP chain.", + current_cell, current_cell->type->identifier); + current_cell = current_cell->type->get_next_isp(current_cell, + ¤t_channel); + if (current_channel == FPGA_ISP_CHANNEL_ERROR) + return 1; + } + + report(LL_INFO, + "Bitstream generation finished."); + + return 0; +} diff --git a/sw/kousaten/src/fpga.h b/sw/kousaten/src/fpga.h new file mode 100644 index 0000000..266be57 --- /dev/null +++ b/sw/kousaten/src/fpga.h @@ -0,0 +1,7 @@ +#ifndef FPGA_H +#define FPGA_H +#include "fpga_cell.h" + +int fpga_generate_bitstream(struct fpga_cell *cell); + +#endif // FPGA_H diff --git a/sw/kousaten/src/fpga_cell.c b/sw/kousaten/src/fpga_cell.c index e578c90..5b24c71 100644 --- a/sw/kousaten/src/fpga_cell.c +++ b/sw/kousaten/src/fpga_cell.c @@ -1,21 +1,57 @@ #include "fpga_cell.h" #include "fpga_global.h" -#include +#include "fpga_cell_lut34.h" +#include "fpga_cell_none.h" +#include "fpga_cell_wire.h" -void fpga_cell_init(struct fpga_cell *fpga_cell, - enum fpga_cell_type fpga_cell_type) +static struct fpga_cell_type fpga_cell_list[] = { +{ + .identifier = ' ', + .cell_new = fpga_cell_none_new, + .get_next_isp = fpga_cell_none_get_next_isp +}, +{ + .identifier = '[', + .cell_new = fpga_cell_wire_new, + .get_next_isp = fpga_cell_wire_get_next_isp +}, +{ + .identifier = ']', + .cell_new = fpga_cell_wire_new, + .get_next_isp = fpga_cell_wire_get_next_isp +}, +{ + .identifier = 'P', + .cell_new = fpga_cell_wire_new, + .get_next_isp = fpga_cell_wire_get_next_isp +}, +{ + .identifier = 'L', + .cell_new = fpga_cell_lut34_new, + .get_next_isp = fpga_cell_lut34_get_next_isp +}, +{ + .identifier = '\0', + .cell_new = NULL, + .get_next_isp = NULL +} +}; + +void fpga_cell_init(struct fpga_cell *cell, + struct fpga_cell_type *cell_type) { int i; for (i = 0; i < FPGA_CELL_CONNECTION_COUNT; ++i) { - fpga_cell->cell_connections[i] = NULL; + cell->cell_connections[i] = NULL; } - fpga_cell->type = fpga_cell_type; + cell->type = cell_type; + //fpga_cell->get_next_isp = fpga_cell_get_next_isp_dummy; report(LL_DEBUG, "Initialized cell of type %d at %p.", - fpga_cell_type, fpga_cell); + cell_type, cell); } enum fpga_cell_position fpga_cell_connection_opposing(enum fpga_cell_position position) @@ -84,3 +120,52 @@ struct fpga_cell *fpga_cell_get_far(struct fpga_cell *cell, return next; } + +/** + * @brief fpga_cell_get_next_isp Get the next cell in the ISP chain + * @param fpga_cell the current cell in the ISP chain + * @param isp_channel the current channel. This will be updated when calling this function! + * @return the next ISP cell + */ +struct fpga_cell *fpga_cell_get_next_isp_dummy(struct fpga_cell *cell, + enum fpga_isp_channel *isp_channel) +{ + report(LL_CRITICAL, + "Internal error. Cell type %c does not implement get_next_isp!", + cell->type->identifier); + *isp_channel = FPGA_ISP_CHANNEL_ERROR; + return NULL; +} + +/** + * @brief fpga_cell_new Create a new instance of type + * @param identifier + * @return + */ +struct fpga_cell *fpga_cell_new(char identifier) +{ + struct fpga_cell_type *cell_type = fpga_cell_list; + struct fpga_cell *cell = NULL; + + while (cell_type->identifier) { + if (identifier == cell_type->identifier) { + cell = cell_type->cell_new(); + if (!cell) { + report(LL_CRITICAL, + "Out of memory when creating cell."); + return NULL; + } + cell->type = cell_type; + report(LL_DEBUG, + "Created cell %p of type %c.", + cell, identifier); + return cell; + } + cell_type++; + } + + report(LL_ERROR, + "Invalid cell type %c found in FDEF.", + identifier); + return NULL; +} diff --git a/sw/kousaten/src/fpga_cell.h b/sw/kousaten/src/fpga_cell.h index aa6413b..1c1cfb7 100644 --- a/sw/kousaten/src/fpga_cell.h +++ b/sw/kousaten/src/fpga_cell.h @@ -1,5 +1,6 @@ #ifndef FPGA_CELL_H #define FPGA_CELL_H +#include enum fpga_cell_position { LEFT = 0, @@ -9,30 +10,43 @@ enum fpga_cell_position { FPGA_CELL_CONNECTION_COUNT }; -enum fpga_cell_type { - FPGA_CELL_NONE = 0, - FPGA_CELL_WIRE, - FPGA_CELL_LUT34 +enum fpga_isp_channel { + FPGA_ISP_CHANNEL_NORMAL = 0, + FPGA_ISP_CHANNEL_BACK, + FPGA_ISP_CHANNEL_LFDN, + FPGA_ISP_CHANNEL_DNUP, + FPGA_ISP_CHANNEL_ERROR +}; + +struct fpga_cell_type +{ + char identifier; + + struct fpga_cell *(*cell_new)(); + struct fpga_cell *(*get_next_isp)(struct fpga_cell *cell, + enum fpga_isp_channel *isp_channel); }; /* FPGA Logic cell base parameters */ struct fpga_cell { - enum fpga_cell_type type; + struct fpga_cell_type *type; struct fpga_cell *cell_connections[FPGA_CELL_CONNECTION_COUNT]; /* Cell-specific data will be appended depending on the cell type. */ }; -void fpga_cell_init(struct fpga_cell *fpga_cell, - enum fpga_cell_type fpga_cell_type); +void fpga_cell_init(struct fpga_cell *cell, + struct fpga_cell_type *cell_type); int fpga_cell_connect(struct fpga_cell *fpga_cell, struct fpga_cell *target_cell, enum fpga_cell_position position); struct fpga_cell *fpga_cell_get_far(struct fpga_cell *cell, enum fpga_cell_position position); - +struct fpga_cell *fpga_cell_get_next_isp_dummy(struct fpga_cell *fpga_cell, + enum fpga_isp_channel *isp_channel); +struct fpga_cell *fpga_cell_new(char identifier); #define FPGA_TO_CELL(a) ((struct fpga_cell*) a) #endif // FPGA_CELL_H diff --git a/sw/kousaten/src/fpga_cell_lut34.c b/sw/kousaten/src/fpga_cell_lut34.c index e7e46ac..89f16c6 100644 --- a/sw/kousaten/src/fpga_cell_lut34.c +++ b/sw/kousaten/src/fpga_cell_lut34.c @@ -1,15 +1,32 @@ #include "fpga_cell_lut34.h" +#include "fpga_global.h" #include -struct fpga_cell_lut34 *fpga_cell_lut_34_new() +struct fpga_cell *fpga_cell_lut34_new() { struct fpga_cell_lut34 *fpga_cell_lut_34; fpga_cell_lut_34 = malloc(sizeof(struct fpga_cell_lut34)); - if (fpga_cell_lut_34) { - fpga_cell_init(FPGA_TO_CELL(fpga_cell_lut_34), - FPGA_CELL_LUT34); - } - return fpga_cell_lut_34; + return FPGA_TO_CELL(fpga_cell_lut_34); +} + +struct fpga_cell *fpga_cell_lut34_get_next_isp(struct fpga_cell *cell, + enum fpga_isp_channel *isp_channel) +{ + switch (*isp_channel) { + case FPGA_ISP_CHANNEL_LFDN: + *isp_channel = FPGA_ISP_CHANNEL_NORMAL; + return cell->cell_connections[BOTTOM]; + case FPGA_ISP_CHANNEL_NORMAL: + return cell->cell_connections[RIGHT]; + case FPGA_ISP_CHANNEL_BACK: + return cell->cell_connections[LEFT]; + default: + report(LL_ERROR, + "Unhandled ISP channel %d for LUT34.", + *isp_channel); + } + return NULL; + } diff --git a/sw/kousaten/src/fpga_cell_lut34.h b/sw/kousaten/src/fpga_cell_lut34.h index 6fcf188..ef7671f 100644 --- a/sw/kousaten/src/fpga_cell_lut34.h +++ b/sw/kousaten/src/fpga_cell_lut34.h @@ -23,6 +23,8 @@ struct fpga_cell_lut34 { enum lut_mode lut_mode; /* Look-up table mode selection */ }; -struct fpga_cell_lut34 *fpga_cell_lut_34_new(); +struct fpga_cell *fpga_cell_lut34_new(); +struct fpga_cell *fpga_cell_lut34_get_next_isp(struct fpga_cell *cell, + enum fpga_isp_channel *isp_channel); #endif // FPGA_CELL_LUT34_H diff --git a/sw/kousaten/src/fpga_cell_none.c b/sw/kousaten/src/fpga_cell_none.c index 0904b22..933cc36 100644 --- a/sw/kousaten/src/fpga_cell_none.c +++ b/sw/kousaten/src/fpga_cell_none.c @@ -1,15 +1,20 @@ #include "fpga_cell_none.h" #include +#include "fpga_global.h" -struct fpga_cell_none *fpga_cell_none_new() +struct fpga_cell *fpga_cell_none_new() { struct fpga_cell_none *fpga_cell_none; fpga_cell_none = malloc(sizeof(struct fpga_cell_none)); - if (fpga_cell_none) { - fpga_cell_init(FPGA_TO_CELL(fpga_cell_none), - FPGA_CELL_NONE); - } - return fpga_cell_none; + return FPGA_TO_CELL(fpga_cell_none); +} + +struct fpga_cell *fpga_cell_none_get_next_isp(struct fpga_cell *fpga_cell, + enum fpga_isp_channel *isp_channel) +{ + report(LL_WARNING, + "ISP signal ran into empty cell. Terminating chain."); + return NULL; } diff --git a/sw/kousaten/src/fpga_cell_none.h b/sw/kousaten/src/fpga_cell_none.h index 7d8c0e1..d4476fa 100644 --- a/sw/kousaten/src/fpga_cell_none.h +++ b/sw/kousaten/src/fpga_cell_none.h @@ -7,6 +7,8 @@ struct fpga_cell_none { struct fpga_cell base_cell; }; -struct fpga_cell_none *fpga_cell_none_new(); +struct fpga_cell *fpga_cell_none_new(); +struct fpga_cell *fpga_cell_none_get_next_isp(struct fpga_cell *fpga_cell, + enum fpga_isp_channel *isp_channel); #endif // FPGA_CELL_NONE_H diff --git a/sw/kousaten/src/fpga_cell_wire.c b/sw/kousaten/src/fpga_cell_wire.c new file mode 100644 index 0000000..d4fefb4 --- /dev/null +++ b/sw/kousaten/src/fpga_cell_wire.c @@ -0,0 +1,61 @@ +#include "fpga_cell_wire.h" +#include +#include "fpga_global.h" + +struct fpga_cell *fpga_cell_wire_new() +{ + struct fpga_cell_wire *fpga_cell_wire; + + fpga_cell_wire = malloc(sizeof(struct fpga_cell_wire)); + + return FPGA_TO_CELL(fpga_cell_wire); +} + +struct fpga_cell *fpga_cell_wire_get_next_isp(struct fpga_cell *cell, + enum fpga_isp_channel *isp_channel) +{ + switch (*isp_channel) { + case FPGA_ISP_CHANNEL_NORMAL: + switch (cell->type->identifier) { + case 'P': + return cell->cell_connections[RIGHT]; + case ']': + *isp_channel = FPGA_ISP_CHANNEL_BACK; + return cell->cell_connections[LEFT]; + default: + goto fail; + } + + case FPGA_ISP_CHANNEL_BACK: + switch (cell->type->identifier) { + case 'P': + case '[': + *isp_channel = FPGA_ISP_CHANNEL_LFDN; + return cell->cell_connections[RIGHT]; + } + } + + // switch (cell->type->identifier) { + // case ' ': + // report(LL_WARNING, + // "ISP signal ran into empty cell. Terminating chain."); + // return NULL; + // case ']': + // switch (*isp_channel) { + // case FPGA_ISP_CHANNEL_NORMAL: + // *isp_channel = FPGA_ISP_CHANNEL_BACK; + // return cell->cell_connections[LEFT]; + // default: + // goto fail; + // } + // } + +fail: + report(LL_ERROR, + "Entered wiring cell %c on invalid ISP channel %d.", + cell->type->identifier, *isp_channel); + *isp_channel = FPGA_ISP_CHANNEL_ERROR; + return NULL; + + return NULL; +} diff --git a/sw/kousaten/src/fpga_cell_wire.h b/sw/kousaten/src/fpga_cell_wire.h new file mode 100644 index 0000000..3ac08d5 --- /dev/null +++ b/sw/kousaten/src/fpga_cell_wire.h @@ -0,0 +1,14 @@ +#ifndef FPGA_CELL_WIRE_H +#define FPGA_CELL_WIRE_H + +#include "fpga_cell.h" + +struct fpga_cell_wire { + struct fpga_cell base_cell; +}; + +struct fpga_cell *fpga_cell_wire_new(); +struct fpga_cell *fpga_cell_wire_get_next_isp(struct fpga_cell *cell, + enum fpga_isp_channel *isp_channel); + +#endif // FPGA_CELL_WIRE_H diff --git a/sw/kousaten/src/fpga_fdef_loader.c b/sw/kousaten/src/fpga_fdef_loader.c index 7a6f0d5..e064c5f 100644 --- a/sw/kousaten/src/fpga_fdef_loader.c +++ b/sw/kousaten/src/fpga_fdef_loader.c @@ -21,31 +21,14 @@ struct fpga_cell *fpga_fdef_loader_load(char *filename) while ((c = fgetc(fdef)) != EOF) { switch (c) { - case 'L': - cell = FPGA_TO_CELL(fpga_cell_lut_34_new()); - if (!cell) { - report(LL_CRITICAL, - "Out of memory when creating cell."); - /* TODO: clean up existing cells */ - return NULL; - } - break; - case '\n': col = 0; line++; break; default: - report(LL_ERROR, - "%s:%d:%d: Invalid cell type %c. Replacing with empty cell.", - filename, line, col, c); - /* fall-through */ - case ' ': - cell = FPGA_TO_CELL(fpga_cell_none_new()); + cell = fpga_cell_new((char) c); if (!cell) { - report(LL_CRITICAL, - "Out of memory when creating cell."); /* TODO: clean up existing cells */ return NULL; } diff --git a/sw/kousaten/src/main.c b/sw/kousaten/src/main.c index 2c2288f..73ee8fe 100644 --- a/sw/kousaten/src/main.c +++ b/sw/kousaten/src/main.c @@ -2,20 +2,34 @@ #include "fpga_cell.h" #include "fpga_fdef_loader.h" #include "fpga_global.h" +#include "fpga.h" + +#define E_FDEF 1 +#define E_BITSTREAM 2 int development_test_main(int argc, char *argv[]) { struct fpga_cell *entry_cell; - entry_cell = fpga_fdef_loader_load("fdef/16x16.fdef"); + entry_cell = fpga_fdef_loader_load("fdef/4x4.fdef"); if (!entry_cell) { - report(LL_CRITICAL, "Error loading FDEF.\n"); - return 1; + report(LL_CRITICAL, "Error loading FDEF."); + return E_FDEF; } +// if (entry_cell->type != FPGA_CELL_PROG) { +// report(LL_CRITICAL, "Entry cell must be of type P."); +// return E_FDEF; +// } + report(LL_INFO, "FDEF loaded."); + if (fpga_generate_bitstream(entry_cell)) { + report(LL_CRITICAL, "Critical error during bitstream generation."); + return E_BITSTREAM; + } + return 0; }