autotester

This commit is contained in:
Wolfgang Spraul 2012-08-16 10:57:51 +02:00
parent b1d665e84b
commit 3487a8ad7b
15 changed files with 463 additions and 30 deletions

View File

@ -21,13 +21,17 @@ all: autotest bit2txt draw_svg_tiles new_fp fp2bit hstrrep sort_seq merge_seq
autotest: autotest.o $(MODEL_OBJ) floorplan.o control.o helper.o model.h
autotest.c: model.h floorplan.h control.h
new_fp: new_fp.o $(MODEL_OBJ) floorplan.o helper.o
new_fp.o: new_fp.c floorplan.h model.h helper.h
fp2bit: fp2bit.c $(MODEL_OBJ) bits.o helper.o
fp2bit: fp2bit.o $(MODEL_OBJ) floorplan.o control.o bits.o helper.o
floorplan.o: floorplan.c floorplan.h model.h
fp2bit.o: fp2bit.c model.h floorplan.h bits.h helper.h
floorplan.o: floorplan.c floorplan.h model.h control.h
bits.o: bits.c bits.h model.h

2
README
View File

@ -4,7 +4,7 @@ Design Principles
- plain C, no C++
- simple Makefiles
- text-based file formats
- no documentation - read the sources
- no documentation - please read the sources
- automatic test suite
Libraries

View File

@ -85,7 +85,13 @@ int main(int argc, char** argv)
dev->iob.slew = SLEW_SLOW;
dev->iob.suspend = SUSP_3STATE;
// todo: configure logic
// configure logic
dev = fpga_dev(&model, /*y*/ 68, /*x*/ 13, DEV_LOGIC, /*LOGIC_X*/ 1);
EXIT(!dev);
dev->instantiated = 1;
dev->logic.D_used = 1;
rc = fpga_set_lut(&model, dev, D6_LUT, "A3", ZTERM);
EXIT(rc);
mkdir(AUTOTEST_TMP_DIR, S_IRWXU|S_IRWXG|S_IROTH|S_IXOTH);
dest_f = fopen(AUTOTEST_TMP_DIR "/test_0001.fp", "w");

5
bits.c
View File

@ -7,3 +7,8 @@
#include "model.h"
#include "bits.h"
int write_bits(FILE* f, struct fpga_model* model)
{
return 0;
}

2
bits.h
View File

@ -4,3 +4,5 @@
// This is free and unencumbered software released into the public domain.
// For details see the UNLICENSE file at the root of the source tree.
//
int write_bits(FILE* f, struct fpga_model* model);

View File

@ -156,6 +156,50 @@ int fpga_find_iob(struct fpga_model* model, const char* sitename,
return -1;
}
const char* fpga_iob_sitename(struct fpga_model* model, int y, int x,
int idx)
{
int i;
if (y == TOP_OUTER_ROW) {
for (i = 0; i < sizeof(xc6slx9_iob_top)/sizeof(xc6slx9_iob_top[0]); i++) {
if (xc6slx9_iob_right[i].xy == x) {
if (idx < 0 || idx > 3) return 0;
return xc6slx9_iob_top[i].name[idx];
}
}
return 0;
}
if (y == model->y_height-BOT_OUTER_ROW) {
for (i = 0; i < sizeof(xc6slx9_iob_bottom)/sizeof(xc6slx9_iob_bottom[0]); i++) {
if (xc6slx9_iob_bottom[i].xy == x) {
if (idx < 0 || idx > 3) return 0;
return xc6slx9_iob_bottom[i].name[idx];
}
}
return 0;
}
if (x == LEFT_OUTER_COL) {
for (i = 0; i < sizeof(xc6slx9_iob_left)/sizeof(xc6slx9_iob_left[0]); i++) {
if (xc6slx9_iob_left[i].xy == y) {
if (idx < 0 || idx > 1) return 0;
return xc6slx9_iob_left[i].name[idx];
}
}
return 0;
}
if (x == model->x_width-RIGHT_OUTER_O) {
for (i = 0; i < sizeof(xc6slx9_iob_right)/sizeof(xc6slx9_iob_right[0]); i++) {
if (xc6slx9_iob_right[i].xy == y) {
if (idx < 0 || idx > 1) return 0;
return xc6slx9_iob_right[i].name[idx];
}
}
return 0;
}
return 0;
}
struct fpga_device* fpga_dev(struct fpga_model* model,
int y, int x, enum fpgadev_type type, int idx)
{
@ -173,3 +217,32 @@ struct fpga_device* fpga_dev(struct fpga_model* model,
}
return 0;
}
#define MAX_LUT_LEN 512
int fpga_set_lut(struct fpga_model* model, struct fpga_device* dev,
int which_lut, const char* lut_str, int lut_len)
{
char** ptr;
if (dev->type != DEV_LOGIC)
return -1;
switch (which_lut) {
case A6_LUT: ptr = &dev->logic.A6_lut; break;
case B6_LUT: ptr = &dev->logic.B6_lut; break;
case C6_LUT: ptr = &dev->logic.C6_lut; break;
case D6_LUT: ptr = &dev->logic.D6_lut; break;
default: return -1;
}
if (!(*ptr)) {
*ptr = malloc(MAX_LUT_LEN);
if (!(*ptr)) {
OUT_OF_MEM();
return -1;
}
}
if (lut_len == ZTERM) lut_len = strlen(lut_str);
memcpy(*ptr, lut_str, lut_len);
(*ptr)[lut_len] = 0;
return 0;
}

View File

@ -8,5 +8,13 @@
int fpga_find_iob(struct fpga_model* model, const char* sitename,
int* y, int* x, int* idx);
const char* fpga_iob_sitename(struct fpga_model* model, int y, int x,
int idx);
struct fpga_device* fpga_dev(struct fpga_model* model,
int y, int x, enum fpgadev_type type, int idx);
enum { A6_LUT, B6_LUT, C6_LUT, D6_LUT };
// lut_len can be -1 (ZTERM)
int fpga_set_lut(struct fpga_model* model, struct fpga_device* dev,
int which_lut, const char* lut_str, int lut_len);

View File

@ -8,6 +8,7 @@
#include <stdarg.h>
#include "model.h"
#include "control.h"
#include "floorplan.h"
void printf_version(FILE* f)
@ -146,7 +147,7 @@ static int printf_IOB(FILE* f, struct fpga_model* model,
case 0: break; default: EXIT(1);
}
if (tile->devs[i].iob.O_used)
printf_wrap(f, line, plen, "o_used");
printf_wrap(f, line, plen, "O_used");
switch (tile->devs[i].iob.suspend) {
case SUSP_LAST_VAL:
printf_wrap(f, line, plen, "suspend DRIVE_LAST_VALUE");
@ -204,6 +205,109 @@ static int printf_IOB(FILE* f, struct fpga_model* model,
return 0;
}
static int read_IOB_attr(struct fpga_model* model, struct fpga_device* dev,
const char* w1, int w1_len, const char* w2, int w2_len)
{
// First the one-word attributes.
if (!str_cmp(w1, w1_len, "O_used", ZTERM)) {
dev->iob.O_used = 1;
goto inst_1;
}
// The remaining attributes all require 2 words.
if (w2_len < 1) return 0;
if (!str_cmp(w1, w1_len, "type", ZTERM))
return 2; // no reason for instantiation
if (!str_cmp(w1, w1_len, "istd", ZTERM)) {
memcpy(dev->iob.istandard, w2, w2_len);
dev->iob.istandard[w2_len] = 0;
goto inst_2;
}
if (!str_cmp(w1, w1_len, "ostd", ZTERM)) {
memcpy(dev->iob.ostandard, w2, w2_len);
dev->iob.ostandard[w2_len] = 0;
goto inst_2;
}
if (!str_cmp(w1, w1_len, "bypass_mux", ZTERM)) {
if (!str_cmp(w2, w2_len, "I", ZTERM))
dev->iob.bypass_mux = BYPASS_MUX_I;
else if (!str_cmp(w2, w2_len, "O", ZTERM))
dev->iob.bypass_mux = BYPASS_MUX_O;
else if (!str_cmp(w2, w2_len, "T", ZTERM))
dev->iob.bypass_mux = BYPASS_MUX_T;
else return 0;
goto inst_2;
}
if (!str_cmp(w1, w1_len, "imux", ZTERM)) {
if (!str_cmp(w2, w2_len, "I_B", ZTERM))
dev->iob.I_mux = IMUX_I_B;
else if (!str_cmp(w2, w2_len, "I", ZTERM))
dev->iob.I_mux = IMUX_I;
else return 0;
goto inst_2;
}
if (!str_cmp(w1, w1_len, "strength", ZTERM)) {
dev->iob.drive_strength = to_i(w2, w2_len);
goto inst_2;
}
if (!str_cmp(w1, w1_len, "slew", ZTERM)) {
if (!str_cmp(w2, w2_len, "SLOW", ZTERM))
dev->iob.slew = SLEW_SLOW;
else if (!str_cmp(w2, w2_len, "FAST", ZTERM))
dev->iob.slew = SLEW_FAST;
else if (!str_cmp(w2, w2_len, "QUIETIO", ZTERM))
dev->iob.slew = SLEW_QUIETIO;
else return 0;
goto inst_2;
}
if (!str_cmp(w1, w1_len, "suspend", 7)) {
if (!str_cmp(w2, w2_len, "DRIVE_LAST_VALUE", ZTERM))
dev->iob.suspend = SUSP_LAST_VAL;
else if (!str_cmp(w2, w2_len, "3STATE", ZTERM))
dev->iob.suspend = SUSP_3STATE;
else if (!str_cmp(w2, w2_len, "3STATE_PULLUP", ZTERM))
dev->iob.suspend = SUSP_3STATE_PULLUP;
else if (!str_cmp(w2, w2_len, "3STATE_PULLDOWN", ZTERM))
dev->iob.suspend = SUSP_3STATE_PULLDOWN;
else if (!str_cmp(w2, w2_len, "3STATE_KEEPER", ZTERM))
dev->iob.suspend = SUSP_3STATE_KEEPER;
else if (!str_cmp(w2, w2_len, "3STATE_OCT_ON", ZTERM))
dev->iob.suspend = SUSP_3STATE_OCT_ON;
else return 0;
goto inst_2;
}
if (!str_cmp(w1, w1_len, "in_term", ZTERM)) {
if (!str_cmp(w2, w2_len, "NONE", ZTERM))
dev->iob.in_term = ITERM_NONE;
else if (!str_cmp(w2, w2_len, "UNTUNED_SPLIT_25", ZTERM))
dev->iob.in_term = ITERM_UNTUNED_25;
else if (!str_cmp(w2, w2_len, "UNTUNED_SPLIT_50", ZTERM))
dev->iob.in_term = ITERM_UNTUNED_50;
else if (!str_cmp(w2, w2_len, "UNTUNED_SPLIT_75", ZTERM))
dev->iob.in_term = ITERM_UNTUNED_75;
else return 0;
goto inst_2;
}
if (!str_cmp(w1, w1_len, "out_term", ZTERM)) {
if (!str_cmp(w2, w2_len, "NONE", ZTERM))
dev->iob.out_term = OTERM_NONE;
else if (!str_cmp(w2, w2_len, "UNTUNED_25", ZTERM))
dev->iob.out_term = OTERM_UNTUNED_25;
else if (!str_cmp(w2, w2_len, "UNTUNED_50", ZTERM))
dev->iob.out_term = OTERM_UNTUNED_50;
else if (!str_cmp(w2, w2_len, "UNTUNED_75", ZTERM))
dev->iob.out_term = OTERM_UNTUNED_75;
else return 0;
goto inst_2;
}
return 0;
inst_1:
dev->instantiated = 1;
return 1;
inst_2:
dev->instantiated = 2;
return 2;
}
static int printf_LOGIC(FILE* f, struct fpga_model* model,
int y, int x, int config_only)
{
@ -237,12 +341,85 @@ static int printf_LOGIC(FILE* f, struct fpga_model* model,
break;
default: EXIT(1);
}
if (tile->devs[i].logic.A_used)
printf_wrap(f, line, plen, "A_used");
if (tile->devs[i].logic.B_used)
printf_wrap(f, line, plen, "B_used");
if (tile->devs[i].logic.C_used)
printf_wrap(f, line, plen, "C_used");
if (tile->devs[i].logic.D_used)
printf_wrap(f, line, plen, "D_used");
if (tile->devs[i].logic.A6_lut && tile->devs[i].logic.A6_lut[0])
printf_wrap(f, line, plen, "A6_lut %s",
tile->devs[i].logic.A6_lut);
if (tile->devs[i].logic.B6_lut && tile->devs[i].logic.B6_lut[0])
printf_wrap(f, line, plen, "B6_lut %s",
tile->devs[i].logic.B6_lut);
if (tile->devs[i].logic.C6_lut && tile->devs[i].logic.C6_lut[0])
printf_wrap(f, line, plen, "C6_lut %s",
tile->devs[i].logic.C6_lut);
if (tile->devs[i].logic.D6_lut && tile->devs[i].logic.D6_lut[0])
printf_wrap(f, line, plen, "D6_lut %s",
tile->devs[i].logic.D6_lut);
strcat(line, "\n");
fprintf(f, line);
}
return 0;
}
static int read_LOGIC_attr(struct fpga_model* model, struct fpga_device* dev,
const char* w1, int w1_len, const char* w2, int w2_len)
{
// First the one-word attributes.
if (!str_cmp(w1, w1_len, "A_used", ZTERM)) {
dev->logic.A_used = 1;
goto inst_1;
}
if (!str_cmp(w1, w1_len, "B_used", ZTERM)) {
dev->logic.B_used = 1;
goto inst_1;
}
if (!str_cmp(w1, w1_len, "C_used", ZTERM)) {
dev->logic.C_used = 1;
goto inst_1;
}
if (!str_cmp(w1, w1_len, "D_used", ZTERM)) {
dev->logic.D_used = 1;
goto inst_1;
}
// The remaining attributes all require 2 words.
if (w2_len < 1) return 0;
if (!str_cmp(w1, w1_len, "type", ZTERM))
return 2; // no reason for instantiation
if (!str_cmp(w1, w1_len, "A6_lut", ZTERM)) {
if (fpga_set_lut(model, dev, A6_LUT, w2, w2_len))
return 0;
goto inst_2;
}
if (!str_cmp(w1, w1_len, "B6_lut", ZTERM)) {
if (fpga_set_lut(model, dev, B6_LUT, w2, w2_len))
return 0;
goto inst_2;
}
if (!str_cmp(w1, w1_len, "C6_lut", ZTERM)) {
if (fpga_set_lut(model, dev, C6_LUT, w2, w2_len))
return 0;
goto inst_2;
}
if (!str_cmp(w1, w1_len, "D6_lut", ZTERM)) {
if (fpga_set_lut(model, dev, D6_LUT, w2, w2_len))
return 0;
goto inst_2;
}
return 0;
inst_1:
dev->instantiated = 1;
return 1;
inst_2:
dev->instantiated = 2;
return 2;
}
int printf_devices(FILE* f, struct fpga_model* model, int config_only)
{
int x, y, i, rc;
@ -332,6 +509,7 @@ int printf_devices(FILE* f, struct fpga_model* model, int config_only)
break;
case DEV_IOB:
case DEV_LOGIC:
case DEV_NONE:
// to suppress compiler warning
break;
}
@ -483,3 +661,99 @@ int printf_switches(FILE* f, struct fpga_model* model, int enabled_only)
}
return 0;
}
static enum fpgadev_type to_type(const char* s, int len)
{
if (!str_cmp(s, len, "IOB", 3)) return DEV_IOB;
if (!str_cmp(s, len, "LOGIC", 5)) return DEV_LOGIC;
return DEV_NONE;
}
int read_floorplan(struct fpga_model* model, FILE* f)
{
char line[1024];
int beg, end;
while (fgets(line, sizeof(line), f)) {
next_word(line, 0, &beg, &end);
if (end == beg) continue;
if (!str_cmp(&line[beg], end-beg, "dev", 3)) {
int y_beg, y_end, x_beg, x_end;
int y_coord, x_coord;
int type_beg, type_end, idx_beg, idx_end;
enum fpgadev_type dev_type;
int dev_idx, words_consumed;
struct fpga_device* dev_ptr;
int next_beg, next_end, second_beg, second_end;
next_word(line, end, &y_beg, &y_end);
next_word(line, y_end, &x_beg, &x_end);
if (y_end < y_beg+2 || x_end < x_beg+2
|| line[y_beg] != 'y' || line[x_beg] != 'x'
|| !all_digits(&line[y_beg+1], y_end-y_beg-1)
|| !all_digits(&line[x_beg+1], x_end-x_beg-1)) {
fprintf(stderr, "error %i: %s", __LINE__, line);
continue;
}
y_coord = to_i(&line[y_beg+1], y_end-y_beg-1);
x_coord = to_i(&line[x_beg+1], x_end-x_beg-1);
next_word(line, x_end, &type_beg, &type_end);
next_word(line, type_end, &idx_beg, &idx_end);
if (type_end == type_beg || idx_end == idx_beg
|| !all_digits(&line[idx_beg], idx_end-idx_beg)) {
fprintf(stderr, "error %i: %s", __LINE__, line);
continue;
}
dev_type = to_type(&line[type_beg], type_end-type_beg);
dev_idx = to_i(&line[idx_beg], idx_end-idx_beg);
dev_ptr = fpga_dev(model, y_coord, x_coord, dev_type, dev_idx);
if (!dev_ptr) {
fprintf(stderr, "error %i: %s", __LINE__, line);
continue;
}
next_end = idx_end;
while (next_word(line, next_end, &next_beg, &next_end),
next_end > next_beg) {
next_word(line, next_end, &second_beg, &second_end);
switch (dev_type) {
case DEV_IOB:
words_consumed = read_IOB_attr(
model, dev_ptr,
&line[next_beg],
next_end-next_beg,
&line[second_beg],
second_end-second_beg);
break;
case DEV_LOGIC:
words_consumed = read_LOGIC_attr(
model, dev_ptr,
&line[next_beg],
next_end-next_beg,
&line[second_beg],
second_end-second_beg);
break;
default:
fprintf(stderr, "error %i: %s",
__LINE__, line);
goto next_line;
}
if (!words_consumed)
fprintf(stderr,
"error %i w1 %.*s w2 %.*s: %s",
__LINE__, next_end-next_beg,
&line[next_beg],
second_end-second_beg,
&line[second_beg],
line);
else if (words_consumed == 2)
next_end = second_end;
}
next_line: ;
}
}
return 0;
}

View File

@ -24,6 +24,8 @@
// - lines should typically not exceed 80 characters
//
int read_floorplan(struct fpga_model* model, FILE* f);
void printf_version(FILE* f);
int printf_tiles(FILE* f, struct fpga_model* model);
int printf_devices(FILE* f, struct fpga_model* model, int config_only);

View File

@ -6,17 +6,45 @@
//
#include "model.h"
#include "floorplan.h"
#include "bits.h"
int main(int argc, char** argv)
{
struct fpga_model model;
int rc;
FILE* fp, *fbits;
int rc = -1;
if (argc != 3) {
fprintf(stderr,
"\n"
"%s - floorplan to bitstream\n"
"Usage: %s <floorplan_file|- for stdin> <bits_file>\n"
"\n", argv[0], argv[0]);
goto fail;
}
if (!strcmp(argv[1], "-"))
fp = stdin;
else {
fp = fopen(argv[1], "r");
if (!fp) {
fprintf(stderr, "Error opening %s.\n", argv[1]);
goto fail;
}
}
fbits = fopen(argv[2], "w");
if (!fbits) {
fprintf(stderr, "Error opening %s.\n", argv[2]);
goto fail;
}
if ((rc = fpga_build_model(&model, XC6SLX9_ROWS, XC6SLX9_COLUMNS,
XC6SLX9_LEFT_WIRING, XC6SLX9_RIGHT_WIRING)))
goto fail;
if ((rc = read_floorplan(&model, fp))) goto fail;
if ((rc = write_bits(fbits, &model))) goto fail;
return EXIT_SUCCESS;
fail:
return rc;

View File

@ -702,6 +702,47 @@ void next_word(const char*s, int start, int* beg, int* end)
*end = i;
}
int str_cmp(const char* a, int a_len, const char* b, int b_len)
{
int i = 0;
if (a_len == -1) {
a_len = 0;
while (a[a_len]) a_len++;
}
if (b_len == -1) {
b_len = 0;
while (b[b_len]) b_len++;
}
while (1) {
if (i >= a_len) {
if (i >= b_len)
return 0;
return -1;
}
if (i >= b_len) {
if (i >= a_len)
return 0;
return 1;
}
if (a[i] != b[i])
return a[i] - b[i];
i++;
}
}
int all_digits(const char* a, int len)
{
int i;
if (!len) return 0;
for (i = 0; i < len; i++) {
if (a[i] < '0' || a[i] > '9')
return 0;
}
return 1;
}
int to_i(const char* s, int len)
{
int num, base;

View File

@ -16,6 +16,8 @@
#define PROGRAM_REVISION "2012-06-27"
#define MACRO_STR(arg) #arg
#define OUT_OF_MEM() { fprintf(stderr, \
"Out of memory in %s:%i\n", __FILE__, __LINE__); }
#define EXIT(expr) if (expr) { fprintf(stderr, \
"Internal error in %s:%i\n", __FILE__, __LINE__); exit(1); }
@ -77,7 +79,13 @@ uint64_t read_lut64(uint8_t* two_minors, int off_in_frame);
int get_vm_mb(void);
int get_random(void);
int compare_with_number(const char* a, const char* b);
// If no next word is found, *end == *beg
void next_word(const char* s, int start, int* beg, int* end);
// if a_len or b_len are -1, the length is until 0-termination
#define ZTERM -1
int str_cmp(const char* a, int a_len, const char* b, int b_len);
// all_digits() returns 0 if len == 0
int all_digits(const char* a, int len);
int to_i(const char* s, int len);
uint32_t hash_djb2(const unsigned char* str);

View File

@ -168,7 +168,7 @@ enum fpga_tile_type
#define CENTER_LOGIC_O 2
#define CENTER_ROUTING_O 3
#define YX_TILE(model, y, x) (&(model)->tiles[(y)*model->x_width+(x)])
#define YX_TILE(model, y, x) (&(model)->tiles[(y)*(model)->x_width+(x)])
// tile flags
@ -271,6 +271,8 @@ const char* logicin_s(int wire, int routing_io);
enum fpgadev_type
{
DEV_NONE = 0,
DEV_LOGIC,
DEV_TIEOFF,
DEV_MACC,

View File

@ -325,13 +325,14 @@ int init_devices(struct fpga_model* model)
if (!is_atx(X_LOGIC_COL, model, x))
continue;
for (y = TOP_IO_TILES; y < model->y_height - BOT_IO_TILES; y++) {
// M and L are at index 0, X is at index 1.
if (YX_TILE(model, y, x)->flags & TF_LOGIC_XM_DEV) {
if ((rc = add_dev(model, y, x, DEV_LOGIC, LOGIC_X))) goto fail;
if ((rc = add_dev(model, y, x, DEV_LOGIC, LOGIC_M))) goto fail;
if ((rc = add_dev(model, y, x, DEV_LOGIC, LOGIC_X))) goto fail;
}
if (YX_TILE(model, y, x)->flags & TF_LOGIC_XL_DEV) {
if ((rc = add_dev(model, y, x, DEV_LOGIC, LOGIC_X))) goto fail;
if ((rc = add_dev(model, y, x, DEV_LOGIC, LOGIC_L))) goto fail;
if ((rc = add_dev(model, y, x, DEV_LOGIC, LOGIC_X))) goto fail;
}
}
}

View File

@ -106,27 +106,6 @@ static void find_number(const char* s, int s_len, int* num_start, int* num_end)
}
}
static int str_cmp(const char* a, int a_len, const char* b, int b_len)
{
int i = 0;
while (1) {
if (i >= a_len) {
if (i >= b_len)
return 0;
return -1;
}
if (i >= b_len) {
if (i >= a_len)
return 0;
return 1;
}
if (a[i] != b[i])
return a[i] - b[i];
i++;
}
}
static int is_known_suffix(const char* str, int str_len)
{
int i;