Compare commits

...

31 Commits
master ... sw

Author SHA1 Message Date
Markus Koch 30e18b4357 sw: Add 16-bit counter demo 2019-09-27 15:23:03 +02:00
Markus Koch 6fbdcf9016 sw: Fix coding style 2019-09-23 21:29:36 +02:00
Markus Koch 7bb7049eea sw: Fix logic to determine when to enable the output drivers
Before, it was always enabling all outputs,
even when they should have been tristated.
2019-09-23 21:28:54 +02:00
Markus Koch 98a7a5d170 sw: Create function to determine whether an output is driven 2019-09-23 21:27:45 +02:00
Markus Koch 953818f43c sw: Report if bit is unset in final bitstream result 2019-09-23 21:26:50 +02:00
Markus Koch 72dabd64db sw: Swap the order of the two LUTs in the bitstream 2019-09-23 21:25:27 +02:00
Markus Koch f27c728472 sw: Implement bodgefix for schematic rev 03L 2019-09-22 19:11:43 +02:00
Markus Koch 30c83a658f sw: Fix fpga_cell_lut34_lut_get_out_mux
Was accessing wrong data when generating info for set 2.
2019-09-22 19:11:21 +02:00
Markus Koch 0a493bdd2a Remove unnecessary debug output 2019-09-13 13:02:05 +09:00
Markus Koch a072dbfe8a Fix unnecessary semicolon warnings in bit set / unset macros 2019-09-13 12:59:24 +09:00
Markus Koch a2abccfc5d Fix output MUX selection logic
Fixes #15.
2019-09-13 12:55:32 +09:00
Markus Koch 7abcead6a9 des: Fix data type of drive_sel 2019-09-13 12:48:28 +09:00
Markus Koch f60d76f831 Fix sync polarity
Fixes #11.
2019-06-29 12:48:26 +02:00
Markus Koch 9a06c054e8 Fix bitstream generator collision check 2019-06-29 12:37:59 +02:00
Markus Koch 29efb7446b Add spreadsheet to help generate LUT configs 2019-06-22 17:50:42 +02:00
Markus Koch 0de1c093cd Add program.sh script 2019-06-22 17:47:20 +02:00
Markus Koch 15fe4e4ca3 Add test configuration for 2-bit counter 2019-06-22 17:24:44 +02:00
Markus Koch 6846aff71d Add debug print for bitstream bits 2019-06-22 17:24:26 +02:00
Markus Koch 01df956317 Fix a variety of bugs found during integration 2019-06-22 17:24:09 +02:00
Markus Koch 28adf2340b Add FDEF for single-cell FPGA 2019-06-21 21:17:32 +02:00
Markus Koch ae2e6552ce Add option to generate binary or ASCII hex bitstreams 2019-06-21 21:16:46 +02:00
Markus Koch 7df813fc71 Add argument parsing 2019-06-21 20:57:56 +02:00
Markus Koch 0834cf0c0d Finish basic bitstream generator 2019-06-21 20:31:34 +02:00
Markus Koch 5d86f8c7cf Start bitstream generator 2019-06-20 13:45:04 +02:00
Markus Koch a1d635889c Clean up 2019-06-19 18:32:59 +02:00
Markus Koch 925e17372a Implement fpga_isp_chain_new 2019-06-19 18:25:21 +02:00
Markus Koch d0fed3cce4 Implement ISP chain walker 2019-06-18 20:15:35 +02:00
Markus Koch cf80ff7b6b Reverse order of log levels 2019-06-17 22:08:24 +02:00
Markus Koch 0309934d82 Add comments for later cleanups 2019-06-17 22:08:11 +02:00
Markus Koch e12120fade Start implementing Kousaten 2019-06-16 21:27:42 +02:00
Markus Koch 0072ed418b Initialize CMakeProject for Kousaten 2019-06-16 17:11:20 +02:00
22 changed files with 1205 additions and 0 deletions

BIN
doc/lut-helper.ods 100644

Binary file not shown.

5
sw/kousaten/.gitignore vendored 100644
View File

@ -0,0 +1,5 @@
*.user
*~
Makefile
*.autosave
build-*

View File

@ -0,0 +1,8 @@
cmake_minimum_required(VERSION 2.8)
project(kousaten)
#set(CMAKE_BUILD_TYPE Release)
set(CMAKE_C_FLAGS "-Wall")
aux_source_directory(./src SRC_LIST)
add_executable(${PROJECT_NAME} ${SRC_LIST})

View File

@ -0,0 +1,2 @@
# TTL-FPGA Compiler *Kousaten*
Tool to generate bitstreams for the TTL-FPGA after manual synthesis and PNR.

View File

@ -0,0 +1,4 @@
PLLLL]
[LLLL]
[LLLL]
[LLLL

View File

@ -0,0 +1 @@
PL

View File

@ -0,0 +1,9 @@
#!/bin/bash
if [ $# -lt 2 ]; then
echo "Usage: $0 </dev/ttyX> <progfile>"
exit 1
fi
stty -F "$1" raw
cat "$2" > "$1"

View File

@ -0,0 +1,56 @@
#include "fpga.h"
#include "fpga_global.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int fpga_generate_bitstream(struct fpga_chain *chain,
char *filename, int ascii)
{
int i;
char *buf = NULL;
FILE *bitstream = stdout;
if (strcmp(filename, "-")) {
bitstream = fopen(filename, "wb");
}
if (!bitstream) {
report(LL_ERROR,
"Could not open output file '%s'.",
filename);
errno = EIO;
goto fail;
}
report(LL_INFO, "Generating bitstream...");
for (i = chain->length - 1; i >= 0; --i) {
report(LL_DEBUG,
"Generating bitstream for cell %p (%c)...",
chain->head[i], chain->head[i]->type->identifier);
buf = chain->head[i]->type->isp_generate_bitstream(chain->head[i]);
if (!buf) {
report(LL_ERROR,
"Error during bitstream generation for cell %p.",
chain->head[i]);
errno = ETYPE;
goto fail;
}
for (int j = 0; j < chain->head[i]->type->isp_length; ++j) {
if (ascii)
fprintf(bitstream, "%02X ", buf[j] & 0xFF);
else
fputc(buf[j] & 0xFF, bitstream);
}
if (ascii)
fprintf(bitstream, "\n");
free(buf);
}
return 0;
fail:
if (bitstream && (strcmp(filename, "-")))
fclose(bitstream);
return 1;
}

View File

@ -0,0 +1,8 @@
#ifndef FPGA_H
#define FPGA_H
#include "fpga_cell.h"
int fpga_generate_bitstream(struct fpga_chain *chain,
char *filename, int ascii);
#endif // FPGA_H

View File

@ -0,0 +1,329 @@
#include "fpga_cell.h"
#include "fpga_global.h"
#include "fpga_cell_lut34.h"
#include "fpga_cell_none.h"
#include "fpga_cell_wire.h"
#include <stdlib.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,
.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 <fpga_cell> to the <position> of <target_cell>
* @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 <position> of <cell>
* @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 <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;
}
/**
* @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,
&current_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));
}

View File

@ -0,0 +1,67 @@
#ifndef FPGA_CELL_H
#define FPGA_CELL_H
#include <stddef.h>
enum fpga_cell_position {
LEFT = 0,
TOP,
RIGHT,
BOTTOM,
FPGA_CELL_CONNECTION_COUNT
};
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);
unsigned long isp_length;
char *(*isp_generate_bitstream)(struct fpga_cell *cell);
};
/* FPGA Logic cell base parameters */
struct fpga_cell
{
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. */
};
struct fpga_chain {
struct fpga_cell **head;
int length;
};
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);
char *fpga_cell_isp_generate_bitstream_dummy(struct fpga_cell *cell);
struct fpga_cell *fpga_cell_new(char identifier);
#define FPGA_TO_CELL(a) ((struct fpga_cell*) a)
struct fpga_chain *fpga_isp_chain_new(struct fpga_cell *entry);
int fpga_cell_bitstream_set_bit(char *buffer, char *sbuffer,
int bit, int value);
int fpga_cell_bitstream_set_bits(char *buffer, char *sbuffer,
int value, int nbits, int *mapping);
int fpga_cell_bitstream_is_set(char *buffer, int bit);
#endif // FPGA_CELL_H

View File

@ -0,0 +1,300 @@
#include "fpga_cell_lut34.h"
#include "fpga_global.h"
#include <stdlib.h>
#include <string.h>
#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] = {
24, 25, 26, 27, 28, 29, 30, 31,
16, 17, 18, 19, 20, 21, 22, 23
};
static int LUT3_BITMAP[2][8] = {
{24, 25, 26, 27, 28, 29, 30, 31},
{16, 17, 18, 19, 20, 21, 22, 23}
};
/* LUT Config Definitions */
static int BIT_LUT_SYNC_N = 20;
static int BIT_LUT_SPLIT_N = 21;
/* 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}
};
/* LUT OUT MUX Definitions */
static int LUT_OUT_MUX[4][4] = {
{LUT_OUT_C, LUT_OUT_A, LUT_OUT_B, LUT_OUT_B_ASYNC},
{LUT_OUT_C, LUT_OUT_B_ASYNC, LUT_OUT_A, LUT_OUT_A},
{LUT_OUT_C, LUT_OUT_A, LUT_OUT_B, LUT_OUT_B_ASYNC},
{LUT_OUT_C, LUT_OUT_B_ASYNC, LUT_OUT_B, LUT_OUT_A}
};
static int LUT_OUT_BITMAP[2][2] = {
{27, 23},
{25, 30}
};
static int LUT_OUT_EN_N_BITMAP[4] = {
22, 26, 31, 24
};
/* Routing Definitions */
static int ROUTE_BITMAP[8] = {
3, 6, 4, 0, /* Left */
5, 1, 2, 7, /* Top */
};
/* LED Definitions */
static int BIT_LED_LUT_IN = 28;
static int BIT_LED_LUT_OUT_N = 29; /* Low-active */
static inline int fpga_cell_lut34_is_driven(char drive_sel)
{
return (drive_sel != LUT_OUT_DC && drive_sel != LUT_OUT_Z);
}
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;
}
static int fpga_cell_lut34_lut_get_out_mux(int lut_group, char *ports)
{
int i;
int lut;
if (lut_group < 0 || lut_group > 2) {
report(LL_ERROR,
"Invalid LUT group requested.");
return -1;
}
lut = lut_group * 2;
ports = ports + lut;
for (i = 0; i < 4; ++i) {
if (!fpga_cell_lut34_is_driven(ports[0]) ||
ports[0] == LUT_OUT_MUX[lut][i]) {
if (!fpga_cell_lut34_is_driven(ports[1]) ||
ports[1] == LUT_OUT_MUX[lut + 1][i])
return i;
}
}
return -1;
}
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));
fpga_cell_lut_34->LUT3[0] = -1;
fpga_cell_lut_34->LUT3[1] = -1;
fpga_cell_lut_34->LUT4 = -1;
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;
}
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;\
}} (void)0
#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;\
}} (void)0
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));
if (!buf || !sbuf) {
report(LL_CRITICAL,
"Out of memory during bitstream generation.");
errno = ENOMEM;
goto fail;
}
/* 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);
}
for (i = 0; i < 2; ++i) {
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);
fix_bitfields(&BIT_LUT_SYNC_N, 1);
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 */
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;
}
BS_SET_BITS(temp, 3, LUT_IN_BITMAP[i], "Couldn't set LUT input sel for input %d.", i);
}
/* LUT output sel + enable */
for (i = 0; i < 2; ++i) {
temp = fpga_cell_lut34_lut_get_out_mux(i, lut34->drive_sel);
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;
}
BS_SET_BITS(temp, 2, LUT_OUT_BITMAP[i],
"Couldn't set LUT output sel %d for output %d.", temp, i);
}
for (i = 0; i < 4; ++i) {
temp = fpga_cell_lut34_is_driven(lut34->drive_sel[i]);
BS_SET_BIT(LUT_OUT_EN_N_BITMAP[i], !temp,
"Couldn't %s output for output %d.",
(!temp ? "enable" : "disabled"), 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) {
BS_SET_BITS(lut34->LUT3[i], 8, LUT3_BITMAP[i],
"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?");
}
}
BS_SET_BIT(BIT_LUT_SYNC_N, !lut34->sync, "Couldn't %s synchronous mode.",
(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;
}
}
report(LL_DEBUG, "Bitstream result for %p:", cell);
for (i = 0; i < 48; ++i) {
report(LL_DEBUG,
" %d: %d%s",
i,
fpga_cell_bitstream_is_set(buf, i),
(fpga_cell_bitstream_is_set(sbuf, i) ? "" : " (Z)"));
}
free(sbuf);
return buf;
fail:
if (buf)
free(buf);
if (sbuf)
free(sbuf);
return NULL;
}

View File

@ -0,0 +1,61 @@
#ifndef FPGA_CELL_LUT34_H
#define FPGA_CELL_LUT34_H
#include "fpga_cell.h"
enum LUT_NET_NAMES {
LUT_NET_DC = '\0', /* Dont' care */
LUT_NET_T0 = '0',
LUT_NET_T1 = '1',
LUT_NET_T2 = '2',
LUT_NET_T3 = '3',
LUT_NET_L0 = 'A',
LUT_NET_L1 = 'B',
LUT_NET_L2 = 'C',
LUT_NET_L3 = 'D',
LUT_NET_F0 = 'W',
LUT_NET_F1 = 'X',
LUT_NET_F2 = 'Y',
LUT_NET_F3 = 'Z'
};
enum LUT_OUT_NAMES {
LUT_OUT_DC = '\0', /* Don't care, treated like Z */
LUT_OUT_Z = 'Z',
LUT_OUT_C = 'C',
LUT_OUT_A = 'A',
LUT_OUT_B = 'B',
LUT_OUT_B_ASYNC = 'b'
};
enum ROUTE_NAMES {
ROUTE_L0 = 0,
ROUTE_L1,
ROUTE_L2,
ROUTE_L3,
ROUTE_T0,
ROUTE_T1,
ROUTE_T2,
ROUTE_T3
};
struct fpga_cell_lut34 {
struct fpga_cell base_cell;
int led_lut_in_enable;
int led_lut_out_enable;
char lut_in_sel[4]; /* Input select */
char drive_sel[4]; /* Which signal to drive onto each fabric line */
int sync; /* Register output on rising edge of clk */
int route_en; /* Bitfield, Enable routing between {left, top} and main fabric */
int LUT4; /* Look-up table for LUT-4 configuration */
int LUT3[2]; /* Look-up tables for LUT-3 configuration */
};
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);
char *fpga_cell_lut34_isp_generate_bitstream(struct fpga_cell *cell);
#endif // FPGA_CELL_LUT34_H

View File

@ -0,0 +1,20 @@
#include "fpga_cell_none.h"
#include <stdlib.h>
#include "fpga_global.h"
struct fpga_cell *fpga_cell_none_new()
{
struct fpga_cell_none *fpga_cell_none;
fpga_cell_none = malloc(sizeof(struct 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;
}

View File

@ -0,0 +1,14 @@
#ifndef FPGA_CELL_NONE_H
#define FPGA_CELL_NONE_H
#include "fpga_cell.h"
struct fpga_cell_none {
struct fpga_cell base_cell;
};
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

View File

@ -0,0 +1,48 @@
#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];
}
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;
}

View 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

View File

@ -0,0 +1,60 @@
#include "fpga_fdef_loader.h"
#include <stdio.h>
struct fpga_cell *fpga_fdef_loader_load(char *filename)
{
FILE *fdef;
int c;
int line = 1;
int col = 1;
struct fpga_cell *cell_left = NULL;
struct fpga_cell *cell_top = NULL;
struct fpga_cell *cell = NULL;
report(LL_INFO, "Loading FDEF from %s...", filename);
fdef = fopen(filename, "r");
if (!fdef)
return NULL;
while ((c = fgetc(fdef)) != EOF) {
switch (c) {
case '\n':
col = 0;
line++;
break;
default:
cell = fpga_cell_new((char) c);
if (!cell) {
/* TODO: clean up existing cells */
return NULL;
}
break;
}
if (c == '\n') {
cell_left = NULL;
cell_top = fpga_cell_get_far(cell, LEFT);
report(LL_DEBUG, "");
} else {
if (cell_left)
fpga_cell_connect(cell, cell_left, RIGHT);
if (cell_top)
fpga_cell_connect(cell, cell_top, BOTTOM);
cell_left = cell;
if (cell_top)
cell_top = cell_top->cell_connections[RIGHT];
}
col++;
}
fclose(fdef);
return fpga_cell_get_far(fpga_cell_get_far(cell, LEFT), TOP);
}

View File

@ -0,0 +1,11 @@
#ifndef FPGA_FDEF_LOADER_H
#define FPGA_FDEF_LOADER_H
#include "fpga_global.h"
#include "fpga_cell.h"
#include "fpga_cell_lut34.h"
#include "fpga_cell_none.h"
struct fpga_cell *fpga_fdef_loader_load(char *filename);
#endif // FPGA_FDEF_LOADER_H

View File

@ -0,0 +1,38 @@
#include "fpga_global.h"
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
static int current_log_level = 100;
static const char *ll_string[] = {
"\x1B[31m\x1B[1m[X] ",
"\x1B[31m[E] ",
"\x1B[33m[W] ",
"\x1B[32m[I] ",
"\x1B[34m[D] ",
"[?] "
};
enum log_level report(enum log_level log_level, const char *format, ...)
{
va_list vargs;
if (log_level > LL_COUNT)
log_level = LL_COUNT;
if (log_level <= current_log_level) {
va_start(vargs, format);
fprintf(stderr, "%s", ll_string[log_level]);
vfprintf(stderr, format, vargs);
fprintf(stderr, "\x1B[0m\n");
va_end(vargs);
}
return log_level;
}
void set_log_level(enum log_level log_level)
{
current_log_level = log_level;
}

View File

@ -0,0 +1,20 @@
#ifndef FPGA_GLOBAL_H
#define FPGA_GLOBAL_H
#include <errno.h>
enum log_level {LL_CRITICAL = 0,
LL_ERROR,
LL_WARNING,
LL_INFO,
LL_DEBUG,
LL_COUNT};
enum log_level report(enum log_level log_level, const char *format, ...);
void set_log_level(enum log_level log_level);
/* Error codes */
#define ECONN 1000 /* Tried to connect to already connected port */
#define ETYPE 1001 /* Tried an operation on a cell that does not support it */
#define ERECONF 1100 /* Tried to set a configuration bit to multiple values */
#endif // FPGA_GLOBAL_H

View File

@ -0,0 +1,130 @@
#include <stdio.h>
#include "fpga_cell.h"
#include "fpga_fdef_loader.h"
#include "fpga_global.h"
#include "fpga.h"
#include "unistd.h"
#include "string.h"
#include "fpga_cell_lut34.h" /* For testing purposes only */
#define E_FDEF 1
#define E_BITSTREAM 2
static void test_design_cell_ripple(struct fpga_cell_lut34 *cell, int first, int last)
{
cell->lut_in_sel[0] = LUT_NET_F0; // Own state
cell->lut_in_sel[1] = LUT_NET_F2; // Feedback &-net -- just for fun
cell->lut_in_sel[2] = (first ? LUT_NET_T2 : LUT_NET_L1); // &-state of previous stages
cell->lut_in_sel[3] = LUT_NET_L0; // Previous state -- just for fun
cell->sync = 1;
cell->drive_sel[0] = 'A';
cell->drive_sel[1] = 'b';
cell->drive_sel[2] = (last ? 'b' : 'Z');
cell->drive_sel[3] = 'Z';
cell->route_en = (1 << ROUTE_L2);
cell->LUT3[0] = 0b01011010;
cell->LUT3[1] = 0b10100000;
}
// WARNING: Requires a >=4x4 FPGA FDEF!
static void test_design_counter(struct fpga_cell *entry_cell)
{
struct fpga_cell_lut34 *cell;
int i, j;
for (i = 0; i < 4; ++i) {
cell = ((struct fpga_cell_lut34 *)(entry_cell->cell_connections[RIGHT]));
for (j = 4 - i; j < 4; ++j) {
cell = (struct fpga_cell_lut34 *)cell->base_cell.cell_connections[BOTTOM];
}
test_design_cell_ripple(cell, 1, 0);
cell = (struct fpga_cell_lut34 *)cell->base_cell.cell_connections[RIGHT];
test_design_cell_ripple(cell, 0, 0);
cell = (struct fpga_cell_lut34 *)cell->base_cell.cell_connections[RIGHT];
test_design_cell_ripple(cell, 0, 0);
cell = (struct fpga_cell_lut34 *)cell->base_cell.cell_connections[RIGHT];
test_design_cell_ripple(cell, 0, 1);
}
}
int development_test_main(int argc, char *argv[])
{
struct fpga_cell *entry_cell;
struct fpga_chain *chain;
int opt;
char *fdef_filename = "fdef/4x4.fdef";
char *kst_filename = "-";
char *bitstream_filename = "-";
int bitstream_ascii = 0;
set_log_level(LL_DEBUG);
while((opt = getopt(argc, argv, "f:i:o:h")) != -1)
{
switch(opt)
{
case 'f':
fdef_filename = optarg;
break;
case 'i':
kst_filename = optarg;
report(LL_WARNING, "Input not yet implemented.");
break;
case 'o':
bitstream_filename = optarg;
break;
case 'h':
bitstream_ascii = 1;
break;
case ':':
case '?':
printf("Usage: %s [-f fdef] [-i input.kst] [-o output.bin] [-h]\n"
"Generate bitstreams for the TTL-FPGA.\n\n"
"When INPUT or OUTPUT is -, read/write standard input.\n\n"
" -f\tFDEF FPGA description file, default fdef/4x4.fdef\n"
" -i\tKousaten input file, default stdin\n"
" -o\tOutput file, default stdout\n"
" -h\tGenerate output as ASCII HEX\n",
argv[0]);
return 0;
default:
break;
}
}
entry_cell = fpga_fdef_loader_load(fdef_filename);
if (!entry_cell) {
report(LL_CRITICAL, "Error loading FDEF.");
return E_FDEF;
}
report(LL_INFO, "FDEF loaded.");
chain = fpga_isp_chain_new(entry_cell);
if (!chain) {
report(LL_CRITICAL, "Critical error during bitstream generation.");
return E_BITSTREAM;
}
report(LL_INFO, "Chain loaded.");
test_design_counter(entry_cell);
if (fpga_generate_bitstream(chain, bitstream_filename, bitstream_ascii)) {
report(LL_ERROR, "Bitstream generation failed.");
return E_BITSTREAM;
}
report(LL_INFO, "Generated bitstream.");
return 0;
}
int main(int argc, char *argv[])
{
return development_test_main(argc, argv);
}