Implement ISP chain walker
This commit is contained in:
parent
cf80ff7b6b
commit
d0fed3cce4
23
sw/kousaten/src/fpga.c
Normal file
23
sw/kousaten/src/fpga.c
Normal file
@ -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;
|
||||||
|
}
|
7
sw/kousaten/src/fpga.h
Normal file
7
sw/kousaten/src/fpga.h
Normal file
@ -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
|
@ -1,21 +1,57 @@
|
|||||||
#include "fpga_cell.h"
|
#include "fpga_cell.h"
|
||||||
#include "fpga_global.h"
|
#include "fpga_global.h"
|
||||||
#include <stddef.h>
|
#include "fpga_cell_lut34.h"
|
||||||
|
#include "fpga_cell_none.h"
|
||||||
|
#include "fpga_cell_wire.h"
|
||||||
|
|
||||||
void fpga_cell_init(struct fpga_cell *fpga_cell,
|
static struct fpga_cell_type fpga_cell_list[] = {
|
||||||
enum fpga_cell_type fpga_cell_type)
|
{
|
||||||
|
.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;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < FPGA_CELL_CONNECTION_COUNT; ++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,
|
report(LL_DEBUG,
|
||||||
"Initialized cell of type %d at %p.",
|
"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)
|
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;
|
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 <identifier>
|
||||||
|
* @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;
|
||||||
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#ifndef FPGA_CELL_H
|
#ifndef FPGA_CELL_H
|
||||||
#define FPGA_CELL_H
|
#define FPGA_CELL_H
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
enum fpga_cell_position {
|
enum fpga_cell_position {
|
||||||
LEFT = 0,
|
LEFT = 0,
|
||||||
@ -9,30 +10,43 @@ enum fpga_cell_position {
|
|||||||
FPGA_CELL_CONNECTION_COUNT
|
FPGA_CELL_CONNECTION_COUNT
|
||||||
};
|
};
|
||||||
|
|
||||||
enum fpga_cell_type {
|
enum fpga_isp_channel {
|
||||||
FPGA_CELL_NONE = 0,
|
FPGA_ISP_CHANNEL_NORMAL = 0,
|
||||||
FPGA_CELL_WIRE,
|
FPGA_ISP_CHANNEL_BACK,
|
||||||
FPGA_CELL_LUT34
|
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 */
|
/* FPGA Logic cell base parameters */
|
||||||
struct fpga_cell
|
struct fpga_cell
|
||||||
{
|
{
|
||||||
enum fpga_cell_type type;
|
struct fpga_cell_type *type;
|
||||||
|
|
||||||
struct fpga_cell *cell_connections[FPGA_CELL_CONNECTION_COUNT];
|
struct fpga_cell *cell_connections[FPGA_CELL_CONNECTION_COUNT];
|
||||||
|
|
||||||
/* Cell-specific data will be appended depending on the cell type. */
|
/* Cell-specific data will be appended depending on the cell type. */
|
||||||
};
|
};
|
||||||
|
|
||||||
void fpga_cell_init(struct fpga_cell *fpga_cell,
|
void fpga_cell_init(struct fpga_cell *cell,
|
||||||
enum fpga_cell_type fpga_cell_type);
|
struct fpga_cell_type *cell_type);
|
||||||
int fpga_cell_connect(struct fpga_cell *fpga_cell,
|
int fpga_cell_connect(struct fpga_cell *fpga_cell,
|
||||||
struct fpga_cell *target_cell,
|
struct fpga_cell *target_cell,
|
||||||
enum fpga_cell_position position);
|
enum fpga_cell_position position);
|
||||||
struct fpga_cell *fpga_cell_get_far(struct fpga_cell *cell,
|
struct fpga_cell *fpga_cell_get_far(struct fpga_cell *cell,
|
||||||
enum fpga_cell_position position);
|
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)
|
#define FPGA_TO_CELL(a) ((struct fpga_cell*) a)
|
||||||
|
|
||||||
#endif // FPGA_CELL_H
|
#endif // FPGA_CELL_H
|
||||||
|
@ -1,15 +1,32 @@
|
|||||||
#include "fpga_cell_lut34.h"
|
#include "fpga_cell_lut34.h"
|
||||||
|
#include "fpga_global.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
struct fpga_cell_lut34 *fpga_cell_lut_34_new()
|
struct fpga_cell *fpga_cell_lut34_new()
|
||||||
{
|
{
|
||||||
struct fpga_cell_lut34 *fpga_cell_lut_34;
|
struct fpga_cell_lut34 *fpga_cell_lut_34;
|
||||||
|
|
||||||
fpga_cell_lut_34 = malloc(sizeof(struct fpga_cell_lut34));
|
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),
|
return FPGA_TO_CELL(fpga_cell_lut_34);
|
||||||
FPGA_CELL_LUT34);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 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;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,8 @@ struct fpga_cell_lut34 {
|
|||||||
enum lut_mode lut_mode; /* Look-up table mode selection */
|
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
|
#endif // FPGA_CELL_LUT34_H
|
||||||
|
@ -1,15 +1,20 @@
|
|||||||
#include "fpga_cell_none.h"
|
#include "fpga_cell_none.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#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;
|
struct fpga_cell_none *fpga_cell_none;
|
||||||
|
|
||||||
fpga_cell_none = malloc(sizeof(struct 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),
|
return FPGA_TO_CELL(fpga_cell_none);
|
||||||
FPGA_CELL_NONE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 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;
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,8 @@ struct fpga_cell_none {
|
|||||||
struct fpga_cell base_cell;
|
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
|
#endif // FPGA_CELL_NONE_H
|
||||||
|
61
sw/kousaten/src/fpga_cell_wire.c
Normal file
61
sw/kousaten/src/fpga_cell_wire.c
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
#include "fpga_cell_wire.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#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;
|
||||||
|
}
|
14
sw/kousaten/src/fpga_cell_wire.h
Normal file
14
sw/kousaten/src/fpga_cell_wire.h
Normal file
@ -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
|
@ -21,31 +21,14 @@ struct fpga_cell *fpga_fdef_loader_load(char *filename)
|
|||||||
|
|
||||||
while ((c = fgetc(fdef)) != EOF) {
|
while ((c = fgetc(fdef)) != EOF) {
|
||||||
switch (c) {
|
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':
|
case '\n':
|
||||||
col = 0;
|
col = 0;
|
||||||
line++;
|
line++;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
report(LL_ERROR,
|
cell = fpga_cell_new((char) c);
|
||||||
"%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());
|
|
||||||
if (!cell) {
|
if (!cell) {
|
||||||
report(LL_CRITICAL,
|
|
||||||
"Out of memory when creating cell.");
|
|
||||||
/* TODO: clean up existing cells */
|
/* TODO: clean up existing cells */
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -2,20 +2,34 @@
|
|||||||
#include "fpga_cell.h"
|
#include "fpga_cell.h"
|
||||||
#include "fpga_fdef_loader.h"
|
#include "fpga_fdef_loader.h"
|
||||||
#include "fpga_global.h"
|
#include "fpga_global.h"
|
||||||
|
#include "fpga.h"
|
||||||
|
|
||||||
|
#define E_FDEF 1
|
||||||
|
#define E_BITSTREAM 2
|
||||||
|
|
||||||
int development_test_main(int argc, char *argv[])
|
int development_test_main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
struct fpga_cell *entry_cell;
|
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) {
|
if (!entry_cell) {
|
||||||
report(LL_CRITICAL, "Error loading FDEF.\n");
|
report(LL_CRITICAL, "Error loading FDEF.");
|
||||||
return 1;
|
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.");
|
report(LL_INFO, "FDEF loaded.");
|
||||||
|
|
||||||
|
if (fpga_generate_bitstream(entry_cell)) {
|
||||||
|
report(LL_CRITICAL, "Critical error during bitstream generation.");
|
||||||
|
return E_BITSTREAM;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user