2019-06-16 21:27:42 +02:00
|
|
|
#include "fpga_cell_lut34.h"
|
2019-06-18 20:15:35 +02:00
|
|
|
#include "fpga_global.h"
|
2019-06-16 21:27:42 +02:00
|
|
|
#include <stdlib.h>
|
2019-06-20 13:45:04 +02:00
|
|
|
#include <string.h>
|
|
|
|
|
2019-06-21 20:31:34 +02:00
|
|
|
#define LUTD_POSITION 16 /* First bit of LUTD cfg bits */
|
|
|
|
#define LUTD_BIT_COUNT 16 /* To be applied for any cfg no > 15 */
|
|
|
|
|
|
|
|
static int need_fix = 1;
|
|
|
|
|
|
|
|
/* LUT Definitions (correct offset, no fix must be applied) */
|
|
|
|
static int LUT4_BITMAP[16] = {
|
|
|
|
16, 17, 18, 19, 20, 21, 22, 23,
|
|
|
|
24, 25, 26, 27, 28, 29, 30, 31
|
|
|
|
};
|
|
|
|
static int LUT3_BITMAP[2][8] = {
|
|
|
|
{16, 17, 18, 19, 20, 21, 22, 23},
|
|
|
|
{24, 25, 26, 27, 28, 29, 30, 31}
|
|
|
|
};
|
|
|
|
|
|
|
|
/* LUT Config Definitions */
|
2019-06-29 12:48:26 +02:00
|
|
|
static int BIT_LUT_SYNC_N = 20;
|
2019-06-21 20:31:34 +02:00
|
|
|
static int BIT_LUT_SPLIT_N = 21;
|
|
|
|
|
2019-06-20 13:45:04 +02:00
|
|
|
/* LUT IN MUX Definitions */
|
|
|
|
static char LUT_IN_MUX[4][8] = {
|
|
|
|
{LUT_NET_F2, LUT_NET_L0, LUT_NET_L3, LUT_NET_L2, LUT_NET_L1, LUT_NET_F1, LUT_NET_F0, LUT_NET_T0},
|
|
|
|
{LUT_NET_F0, LUT_NET_F1, LUT_NET_L1, LUT_NET_L2, LUT_NET_L3, LUT_NET_L0, LUT_NET_F2, LUT_NET_T1},
|
|
|
|
{LUT_NET_F3, LUT_NET_L0, LUT_NET_L3, LUT_NET_L2, LUT_NET_L1, LUT_NET_F1, LUT_NET_F0, LUT_NET_T2},
|
|
|
|
{LUT_NET_F0, LUT_NET_F1, LUT_NET_L1, LUT_NET_L2, LUT_NET_L3, LUT_NET_L0, LUT_NET_F3, LUT_NET_T3}
|
|
|
|
};
|
|
|
|
static int LUT_IN_BITMAP[4][3] = {
|
|
|
|
{12, 11, 19},
|
|
|
|
{ 8, 9, 10},
|
|
|
|
{15, 14, 13},
|
|
|
|
{16, 17, 18}
|
|
|
|
};
|
|
|
|
|
2019-06-21 20:31:34 +02:00
|
|
|
/* LUT OUT MUX Definitions */
|
|
|
|
static int LUT_OUT_MUX[4][4] = {
|
2019-06-22 17:24:09 +02:00
|
|
|
{LUT_OUT_C, LUT_OUT_A, LUT_OUT_B, LUT_OUT_B_ASYNC},
|
2019-06-21 20:31:34 +02:00
|
|
|
{LUT_OUT_C, LUT_OUT_B_ASYNC, LUT_OUT_B, LUT_OUT_A},
|
2019-06-22 17:24:09 +02:00
|
|
|
{LUT_OUT_C, LUT_OUT_A, LUT_OUT_B, LUT_OUT_B_ASYNC},
|
2019-06-21 20:31:34 +02:00
|
|
|
{LUT_OUT_C, LUT_OUT_B_ASYNC, LUT_OUT_B, LUT_OUT_A}
|
|
|
|
};
|
2019-09-13 05:55:32 +02:00
|
|
|
static int LUT_OUT_BITMAP[2][2] = {
|
2019-06-21 20:31:34 +02:00
|
|
|
{27, 23},
|
2019-09-13 05:55:32 +02:00
|
|
|
{25, 30}
|
2019-06-21 20:31:34 +02:00
|
|
|
};
|
|
|
|
static int LUT_OUT_EN_N_BITMAP[4] = {
|
|
|
|
22, 26, 31, 24
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Routing Definitions */
|
|
|
|
static int ROUTE_BITMAP[8] = {
|
2019-06-22 17:24:09 +02:00
|
|
|
3, 6, 4, 0, /* Left */
|
|
|
|
5, 1, 2, 7, /* Top */
|
2019-06-21 20:31:34 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
/* LED Definitions */
|
|
|
|
static int BIT_LED_LUT_IN = 28;
|
|
|
|
static int BIT_LED_LUT_OUT_N = 29; /* Low-active */
|
2019-06-20 13:45:04 +02:00
|
|
|
|
|
|
|
static int fpga_cell_lut34_lut_get_mux(int lut, char port) {
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (port == LUT_NET_DC)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
for (i = 0; i < 8; ++i) {
|
|
|
|
if (LUT_IN_MUX[lut][i] == port)
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
2019-06-16 21:27:42 +02:00
|
|
|
|
2019-09-13 05:55:32 +02:00
|
|
|
static int fpga_cell_lut34_lut_get_out_mux(int lut_group, char *ports) {
|
2019-06-21 20:31:34 +02:00
|
|
|
int i;
|
2019-09-13 05:55:32 +02:00
|
|
|
int lut;
|
2019-06-21 20:31:34 +02:00
|
|
|
|
2019-09-13 05:55:32 +02:00
|
|
|
ports = ports + lut_group;
|
|
|
|
|
|
|
|
if (lut_group < 0 || lut_group > 2) {
|
|
|
|
report(LL_ERROR,
|
|
|
|
"Invalid LUT group requested.");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
lut = lut_group * 2;
|
|
|
|
|
2019-06-21 20:31:34 +02:00
|
|
|
for (i = 0; i < 4; ++i) {
|
2019-09-13 05:55:32 +02:00
|
|
|
if (ports[0] == LUT_OUT_DC ||
|
|
|
|
ports[0] == LUT_OUT_Z ||
|
|
|
|
ports[0] == LUT_OUT_MUX[lut][i]) {
|
|
|
|
if (ports[1] == LUT_OUT_DC ||
|
|
|
|
ports[1] == LUT_OUT_Z ||
|
|
|
|
ports[1] == LUT_OUT_MUX[lut + 1][i])
|
|
|
|
return i;
|
|
|
|
}
|
2019-06-21 20:31:34 +02:00
|
|
|
}
|
2019-09-13 05:55:32 +02:00
|
|
|
|
2019-06-21 20:31:34 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2019-06-18 20:15:35 +02:00
|
|
|
struct fpga_cell *fpga_cell_lut34_new()
|
2019-06-16 21:27:42 +02:00
|
|
|
{
|
|
|
|
struct fpga_cell_lut34 *fpga_cell_lut_34;
|
|
|
|
|
|
|
|
fpga_cell_lut_34 = malloc(sizeof(struct fpga_cell_lut34));
|
2019-06-18 20:15:35 +02:00
|
|
|
|
2019-06-21 20:31:34 +02:00
|
|
|
fpga_cell_lut_34->LUT3[0] = -1;
|
|
|
|
fpga_cell_lut_34->LUT3[1] = -1;
|
|
|
|
fpga_cell_lut_34->LUT4 = -1;
|
|
|
|
|
2019-06-18 20:15:35 +02:00
|
|
|
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);
|
2019-06-16 21:27:42 +02:00
|
|
|
}
|
2019-06-18 20:15:35 +02:00
|
|
|
return NULL;
|
2019-06-16 21:27:42 +02:00
|
|
|
|
|
|
|
}
|
2019-06-20 13:45:04 +02:00
|
|
|
|
2019-06-21 20:31:34 +02:00
|
|
|
static void fix_bitfields(int *bitmap, int count)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < count; ++i) {
|
|
|
|
if (bitmap[i] >= LUTD_POSITION) {
|
|
|
|
bitmap[i] += LUTD_BIT_COUNT;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#define BS_SET_BIT(bitno, value, errmsg, ...)\
|
|
|
|
{if (fpga_cell_bitstream_set_bit(buf, sbuf, bitno, value)) {\
|
|
|
|
report(LL_ERROR, errmsg, ##__VA_ARGS__);\
|
|
|
|
errno = ERECONF;\
|
|
|
|
goto fail;\
|
2019-09-13 05:59:24 +02:00
|
|
|
}} (void)0
|
2019-06-21 20:31:34 +02:00
|
|
|
#define BS_SET_BITS(value, nbits, mapping, errmsg, ...) \
|
|
|
|
{if (fpga_cell_bitstream_set_bits(buf, sbuf, value, nbits, mapping)) {\
|
|
|
|
report(LL_ERROR, errmsg, ##__VA_ARGS__);\
|
|
|
|
errno = ERECONF;\
|
|
|
|
goto fail;\
|
2019-09-13 05:59:24 +02:00
|
|
|
}} (void)0
|
2019-06-21 20:31:34 +02:00
|
|
|
|
2019-06-20 13:45:04 +02:00
|
|
|
char *fpga_cell_lut34_isp_generate_bitstream(struct fpga_cell *cell)
|
|
|
|
{
|
|
|
|
struct fpga_cell_lut34 *lut34 = (struct fpga_cell_lut34 *) cell;
|
|
|
|
char *buf = NULL;
|
|
|
|
char *sbuf = NULL;
|
|
|
|
int i;
|
|
|
|
int temp;
|
|
|
|
|
|
|
|
buf = calloc(cell->type->isp_length, sizeof(char));
|
|
|
|
sbuf = calloc(cell->type->isp_length, sizeof(char));
|
|
|
|
|
2019-06-21 20:31:34 +02:00
|
|
|
if (!buf || !sbuf) {
|
2019-06-20 13:45:04 +02:00
|
|
|
report(LL_CRITICAL,
|
|
|
|
"Out of memory during bitstream generation.");
|
|
|
|
errno = ENOMEM;
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
2019-06-21 20:31:34 +02:00
|
|
|
/* Reposition cfg bits after LUTD cfg, cheap workaround to use the same
|
|
|
|
cfg names as the schematic does. */
|
|
|
|
if (need_fix) {
|
|
|
|
need_fix = 0;
|
|
|
|
for (i = 0; i < 4; ++i) {
|
|
|
|
fix_bitfields(LUT_IN_BITMAP[i], 3);
|
|
|
|
}
|
2019-09-13 05:55:32 +02:00
|
|
|
for (i = 0; i < 2; ++i) {
|
2019-06-21 20:31:34 +02:00
|
|
|
fix_bitfields(LUT_OUT_BITMAP[i], 2);
|
|
|
|
}
|
|
|
|
fix_bitfields(LUT_OUT_EN_N_BITMAP, 4);
|
|
|
|
fix_bitfields(ROUTE_BITMAP, 8);
|
|
|
|
fix_bitfields(&BIT_LED_LUT_IN, 1);
|
|
|
|
fix_bitfields(&BIT_LED_LUT_OUT_N, 1);
|
2019-06-29 12:48:26 +02:00
|
|
|
fix_bitfields(&BIT_LUT_SYNC_N, 1);
|
2019-06-21 20:31:34 +02:00
|
|
|
fix_bitfields(&BIT_LUT_SPLIT_N, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* LEDs */
|
|
|
|
BS_SET_BIT(BIT_LED_LUT_IN, 1,
|
|
|
|
"Couldn't set LUT in LED to %d.", 1);
|
|
|
|
BS_SET_BIT(BIT_LED_LUT_OUT_N, 0,
|
|
|
|
"Couldn't set LUT out LED to %d.", 0);
|
|
|
|
|
|
|
|
/* LUT input sel */
|
2019-06-20 13:45:04 +02:00
|
|
|
for (i = 0; i < 4; ++i) {
|
|
|
|
temp = fpga_cell_lut34_lut_get_mux(i, lut34->lut_in_sel[i]);
|
|
|
|
|
|
|
|
if (temp < 0) {
|
|
|
|
report(LL_ERROR,
|
|
|
|
"Invalid input mux '%c' selected for mux %d on cell %p.",
|
|
|
|
lut34->lut_in_sel[i], i, cell);
|
|
|
|
errno = EINVAL;
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
2019-06-21 20:31:34 +02:00
|
|
|
BS_SET_BITS(temp, 3, LUT_IN_BITMAP[i], "Couldn't set LUT input sel for input %d.", i);
|
2019-06-20 13:45:04 +02:00
|
|
|
}
|
|
|
|
|
2019-06-21 20:31:34 +02:00
|
|
|
/* LUT output sel + enable */
|
2019-09-13 05:55:32 +02:00
|
|
|
for (i = 0; i < 2; ++i) {
|
|
|
|
temp = fpga_cell_lut34_lut_get_out_mux(i, lut34->drive_sel);
|
2019-06-21 20:31:34 +02:00
|
|
|
|
|
|
|
if (temp < 0) {
|
|
|
|
report(LL_ERROR,
|
|
|
|
"Invalid output mux sel '%c' selected for net %d on cell %p.",
|
|
|
|
lut34->drive_sel[i], i, cell);
|
|
|
|
errno = EINVAL;
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
2019-09-13 05:55:32 +02:00
|
|
|
BS_SET_BITS(temp, 2, LUT_OUT_BITMAP[i],
|
|
|
|
"Couldn't set LUT output sel %d for output %d.", temp, i);
|
2019-06-21 20:31:34 +02:00
|
|
|
|
|
|
|
}
|
2019-09-13 05:55:32 +02:00
|
|
|
for (i = 0; i < 2; ++i) {
|
2019-06-21 20:31:34 +02:00
|
|
|
temp = fpga_cell_bitstream_is_set(sbuf, LUT_OUT_BITMAP[i][0]); /* At some point, we set a specific output on this MUX */
|
2019-06-22 17:24:09 +02:00
|
|
|
BS_SET_BIT(LUT_OUT_EN_N_BITMAP[i], !temp,
|
2019-06-21 20:31:34 +02:00
|
|
|
"Couldn't %s output for output %d.",
|
2019-06-22 17:24:09 +02:00
|
|
|
(!temp ? "enable" : "disabled"), i);
|
2019-06-21 20:31:34 +02:00
|
|
|
if (!temp) {
|
|
|
|
BS_SET_BITS(0, 2 , LUT_OUT_BITMAP[i],
|
|
|
|
"Couldn't set LUT output sel 0 for output %d (undriven by user logic).", i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Routing */
|
|
|
|
for (i = 0; i < 8; ++i) {
|
|
|
|
BS_SET_BITS(lut34->route_en, 8, ROUTE_BITMAP,
|
|
|
|
"Couldn't set routing bitmap to 0x%X for cell %p.",
|
|
|
|
lut34->route_en, cell);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* LUTD */
|
|
|
|
if (lut34->LUT4 > -1) {
|
|
|
|
BS_SET_BITS(lut34->LUT4, 16, LUT4_BITMAP,
|
|
|
|
"Error setting LUT4 data.");
|
|
|
|
BS_SET_BIT(BIT_LUT_SPLIT_N, 1, "Couldn't set LUT4 mode.");
|
|
|
|
}
|
|
|
|
for (i = 0; i < 2; ++i) {
|
|
|
|
if (lut34->LUT3[i] > -1) {
|
2019-06-22 17:24:09 +02:00
|
|
|
BS_SET_BITS(lut34->LUT3[i], 8, LUT3_BITMAP[i],
|
2019-06-21 20:31:34 +02:00
|
|
|
"Error setting LUT3[%d] data. Did you configure a LUT4 before?",
|
|
|
|
i);
|
|
|
|
BS_SET_BIT(BIT_LUT_SPLIT_N, 0, "Couldn't set LUT3-2 mode. Did you configure a LUT4 before?");
|
|
|
|
}
|
|
|
|
}
|
2019-06-29 12:48:26 +02:00
|
|
|
BS_SET_BIT(BIT_LUT_SYNC_N, !lut34->sync, "Couldn't %s synchronous mode.",
|
2019-06-21 20:31:34 +02:00
|
|
|
(lut34->sync ? "enabling" : "disabling"));
|
|
|
|
|
|
|
|
/* Basic check whether each bit has been configured */
|
|
|
|
for (i = 0; i < cell->type->isp_length; ++i) {
|
|
|
|
if ((sbuf[i] & 0xFF) != 255) {
|
|
|
|
report(LL_WARNING,
|
|
|
|
"Incomplete configuration for cell %p (byte %d: 0x%X).",
|
|
|
|
cell, i, sbuf[i] & 0xFF);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-22 17:24:26 +02:00
|
|
|
report(LL_DEBUG, "Bitstream result for %p:", cell);
|
|
|
|
for (i = 0; i < 48; ++i) {
|
|
|
|
report(LL_DEBUG,
|
|
|
|
" %d: %d",
|
|
|
|
i, fpga_cell_bitstream_is_set(buf, i));
|
|
|
|
}
|
|
|
|
|
2019-06-21 20:31:34 +02:00
|
|
|
free(sbuf);
|
|
|
|
|
2019-06-20 13:45:04 +02:00
|
|
|
return buf;
|
|
|
|
|
2019-06-21 20:31:34 +02:00
|
|
|
fail:
|
|
|
|
if (buf)
|
|
|
|
free(buf);
|
|
|
|
if (sbuf)
|
|
|
|
free(sbuf);
|
|
|
|
return NULL;
|
2019-06-20 13:45:04 +02:00
|
|
|
}
|