#include "fpga_cell.h" #include "fpga_global.h" #include "fpga_cell_lut34.h" #include "fpga_cell_none.h" #include "fpga_cell_wire.h" 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) { cell->cell_connections[i] = NULL; } 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.", cell_type, cell); } enum fpga_cell_position fpga_cell_connection_opposing(enum fpga_cell_position position) { switch (position) { case LEFT: return RIGHT; case RIGHT: return LEFT; case TOP: return BOTTOM; case BOTTOM: return TOP; default: report(LL_ERROR, "Internal error: Requested opposite of invalid position %d.", position); return LEFT; } } /** * @brief fpga_cell_connect Connect to the of * @param fpga_cell * @param target_cell * @param position * @return 0 on success, -1 on failure */ int fpga_cell_connect(struct fpga_cell *fpga_cell, struct fpga_cell *target_cell, enum fpga_cell_position position) { if (target_cell->cell_connections[position] || fpga_cell->cell_connections[fpga_cell_connection_opposing(position)]) { report(LL_WARNING, "Tried to connect cell %p to pos %d of %p, even though a connection already exists for a least one of them.", fpga_cell, target_cell, position); errno = -ECONN; return -1; } target_cell->cell_connections[position] = fpga_cell; fpga_cell->cell_connections[fpga_cell_connection_opposing(position)] = target_cell; report(LL_DEBUG, "Connected cell %p to port %d of %p.", fpga_cell, position, target_cell); return 0; } /** * @brief fpga_cell_get_far Get cell on the far of * @param cell * @param position * @return */ struct fpga_cell *fpga_cell_get_far(struct fpga_cell *cell, enum fpga_cell_position position) { struct fpga_cell *next = cell; while (next->cell_connections[position]) { next = next->cell_connections[position]; } 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; }