#include "fpga_cell.h" #include "fpga_global.h" #include "fpga_cell_lut34.h" #include "fpga_cell_none.h" #include "fpga_cell_wire.h" #include static struct fpga_cell_type fpga_cell_list[] = { { .identifier = ' ', .cell_new = fpga_cell_none_new, .get_next_isp = fpga_cell_none_get_next_isp, .isp_length = 0, .isp_generate_bitstream = fpga_cell_isp_generate_bitstream_dummy }, { .identifier = '[', .cell_new = fpga_cell_wire_new, .get_next_isp = fpga_cell_wire_get_next_isp, .isp_length = 0, .isp_generate_bitstream = fpga_cell_isp_generate_bitstream_dummy }, { .identifier = ']', .cell_new = fpga_cell_wire_new, .get_next_isp = fpga_cell_wire_get_next_isp, .isp_length = 0, .isp_generate_bitstream = fpga_cell_isp_generate_bitstream_dummy }, { .identifier = 'P', .cell_new = fpga_cell_wire_new, .get_next_isp = fpga_cell_wire_get_next_isp, .isp_length = 0, .isp_generate_bitstream = fpga_cell_isp_generate_bitstream_dummy }, { .identifier = 'L', .cell_new = fpga_cell_lut34_new, .get_next_isp = fpga_cell_lut34_get_next_isp, .isp_length = 6, .isp_generate_bitstream = fpga_cell_lut34_isp_generate_bitstream }, { .identifier = '\0', .cell_new = NULL, .get_next_isp = NULL, .isp_length = 0, .isp_generate_bitstream = fpga_cell_isp_generate_bitstream_dummy } }; 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 isp_generate_bitstream_dummy * @param cell * @param buf * @return */ char *fpga_cell_isp_generate_bitstream_dummy(struct fpga_cell *cell) { report(LL_CRITICAL, "Internal error. Cell type %c does not implement isp_generate_bitstream!", cell->type->identifier); 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; } /** * @brief fpga_isp_chain_new * @param entry * @return */ struct fpga_chain *fpga_isp_chain_new(struct fpga_cell *entry) { struct fpga_cell *current_cell = entry; enum fpga_isp_channel current_channel = FPGA_ISP_CHANNEL_NORMAL; struct fpga_chain *chain; report(LL_INFO, "Generating ISP chain..."); if (entry->type->identifier != 'P') { report(LL_CRITICAL, "Entry cell must be of type P, was '%c'", entry->type->identifier); errno = EINVAL; return NULL; } chain = calloc(sizeof (struct fpga_chain), 1); if (!chain) { report (LL_CRITICAL, "Out of memory during ISP chain generation."); errno = ENOMEM; return NULL; } while (current_cell) { if (current_channel == FPGA_ISP_CHANNEL_NORMAL && current_cell->type->isp_length > 0) { report(LL_DEBUG, "Adding %p (%c) to ISP chain.", current_cell, current_cell->type->identifier); if (!chain->head) { chain->head = malloc(sizeof(chain->head)); *(chain->head) = current_cell; chain->length = 1; } else { chain->length++; chain->head = realloc(chain->head, sizeof(chain->head) * chain->length); *(chain->head + chain->length - 1) = current_cell; } } else { report(LL_DEBUG, "Using %p (%c) for ISP routing.", 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) { /* TODO: Clean up memory */ errno = ETYPE; return NULL; } } report(LL_INFO, "Added %d cells to ISP chain.", chain->length); for (int i = 0; i < chain->length; ++i) { report(LL_DEBUG, " %4d = %p", i, chain->head[i]); } report(LL_INFO, "ISP chain generation finished."); return chain; } int fpga_cell_bitstream_set_bit(char *buffer, char *sbuffer, int bit, int value) { int byteno; int bitno; bit = 47 - bit; bitno = 7 - (bit % 8); byteno = bit / 8; value = !!value; /* Make sure it's a proper boolean value */ if ((sbuffer[byteno] & (1 << bitno))) { /* Already set */ return value == !((buffer[byteno] & (1 << bitno))); } else { sbuffer[byteno] |= (1 << bitno); if (value) buffer[byteno] |= (1 << bitno); else buffer[byteno] &= ~(1 << bitno); } return 0; } int fpga_cell_bitstream_set_bits(char *buffer, char *sbuffer, int value, int nbits, int *mapping) { int i; int ret = 0; for (i = 0; i < nbits; ++i) { ret = ret || fpga_cell_bitstream_set_bit(buffer, sbuffer, mapping[i], value & (1 << i)); } return ret; } int fpga_cell_bitstream_is_set(char *buffer, int bit) { int byteno; int bitno; bit = 47 - bit; bitno = 7 - (bit % 8); byteno = bit / 8; return !!(buffer[byteno] & (1 << bitno)); }