pax_global_header 0000666 0000000 0000000 00000000064 12065743015 0014515 g ustar 00root root 0000000 0000000 52 comment=f4b5b89b87292145247d43d53eb9fab2ff746fb3
fpgatools-201212/ 0000775 0000000 0000000 00000000000 12065743015 0013604 5 ustar 00root root 0000000 0000000 fpgatools-201212/.gitignore 0000664 0000000 0000000 00000000503 12065743015 0015572 0 ustar 00root root 0000000 0000000 #
# common ignore files
#
.*
*.d
*.o
*.o.*
*.so
*.so.*
/tags
/TAGS
#
# git files that we don't want to ignore even it they are dot-files
#
!.gitignore
#
# binaries
#
draw_svg_tiles
new_fp
hstrrep
sort_seq
merge_seq
pair2net
autotest
fp2bit
bit2fp
hello_world
blinking_led
#
# folders
#
test.gold/
test.out/
build-libs/
fpgatools-201212/LINKS 0000664 0000000 0000000 00000004435 12065743015 0014415 0 ustar 00root root 0000000 0000000 panta rhei
knowledge
http://www.hottconsultants.com/techtips/pcb-stack-up-3.html
http://smithsonianchips.si.edu/ice/s4.htm
http://www.texample.net/tikz/examples/timing-diagram/
http://www.siliconpr0n.org/
software
http://en.wikipedia.org/wiki/Wikipedia:WikiProject_Electronics/Programs
http://qfsm.sourceforge.net/about.html
http://code.google.com/p/red-tin-logic-analyzer
Andrew's redtin logic analyzer
http://gtkwave.sourceforge.net
gtkwave wave viewer
https://github.com/openrisc/mor1kx
https://github.com/milkymist
http://spins.fedoraproject.org/fel/#portfolio
http://chitlesh.fedorapeople.org/FEL/list.html
Fedora Electronic Lab tool overview
with links to magic, toped, qucs, iverilog, alliance, etc.
standards
IEEE 1149.1 Boundary Scan/JTAG
IEEE 1532 Configuration and Programming
http://www.xilinx.com/products/design_resources/config_sol/isp_standards_specs.htm
physical goods
- chips
* fpga
www.xilinx.com
www.altera.com
* other
Murata
Peregrine
TriQuint
Maxim
Avago
Skyworks
Analog Devices
- wafers
www.oci.co.kr/eng/ OCI (South Korea)
www.gcl-poly.com GCL-Poly (China)
www.hscpoly.com Hemlock (USA)
www.wacker.com/cms/de/wacker_group/divisions/polysilicon/polysilicon.jsp
Wacker (EU)
- foundry equipment
www.asml.com lithography systems
www.kns.com assembly equipment
- materials
www.sciencecompany.com ACS grade solvents
www.injectorall.com photoresist
www.dudadiesel.com NaOH, KOH
www.mtixtl.com individual 6'' wafers
www.unitednuclear.com
www.tedpella.com/gold_html/Nanotubes.htm
Carbon Nanotubes
www.tubedevices.com/alek/pwl/pwl_e.htm
Private Tube Manufacture-PWL vacuum tubes
services
- foundry
http://cmp.imag.fr/products/ic/?p=prices
CMP
www.lfoundry.com analog and mixed signal
- pcb
http://www.pcbcart.com Chinese corp in Hangzhou
- ref Andrew Zonenberg:
http://www.oshpark.com used for 2 and 4-layers
http://www.4pcb.com Advanced Circuits
http://www.sunstone.com Sunstone Circuits
http://www.saecircuits.com SAE Circuits
http://www.rjrinc.com RJR Circuits
fpgatools-201212/Makefile 0000664 0000000 0000000 00000020130 12065743015 0015240 0 ustar 00root root 0000000 0000000 #
# Makefile - fpgatools
# Author: Wolfgang Spraul
#
# This is free and unencumbered software released into the public domain.
# For details see the UNLICENSE file at the root of the source tree.
#
CFLAGS += -I$(CURDIR)/libs
LDFLAGS += -Wl,-rpath,$(CURDIR)/libs
OBJS = autotest.o bit2fp.o draw_svg_tiles.o fp2bit.o hstrrep.o \
merge_seq.o new_fp.o pair2net.o sort_seq.o hello_world.o \
blinking_led.o
DYNAMIC_LIBS = libs/libfpga-model.so libs/libfpga-bit.so \
libs/libfpga-floorplan.so libs/libfpga-control.so \
libs/libfpga-cores.so
.PHONY: all test clean install uninstall FAKE
.SECONDARY:
.SECONDEXPANSION:
all: new_fp fp2bit bit2fp draw_svg_tiles autotest hstrrep \
sort_seq merge_seq pair2net hello_world blinking_led
include Makefile.common
%.o: %.c
$(CC) $(CPPFLAGS) $(CFLAGS) -o $@ -c $<
$(MKDEP)
libs/%.so: FAKE
@make -C libs $(notdir $@)
#
# Testing section - there are three types of tests:
#
# 1. design
#
# design tests run a design binary to produce floorplan stdout, which is
# converted to binary configuration and back to floorplan. The resulting
# floorplan after conversion through binary must match the original
# floorplan. Additionally, the original floorplan is compared to a gold
# standard if one exists.
#
# ./binary -> .fp -> .bit -> .fp -> compare first .fp to second and gold .fp
#
# 2. autotest
#
# autotest runs an automated test of some fpga logic and produces a log output
# which is compared against a gold standard.
#
# ./autotest -> stdout -> compare with gold standard
#
# 3. compare
#
# tool output is parsed to extract different types of model data and compare
# against a gold standard.
#
# tool output -> awk/processing -> compare to gold standard
#
# - extensions
#
# .ftest = fpgatools run test (design, autotest, compare)
#
# .f2gd = fpgatools to-gold diff
# .ffbd = diff between first fp and after roundtrip through binary config
# .fb2f = fpgatools binary config back to floorplan
# .ff2b = fpgatools floorplan to binary config
# .fco = fpgatools compare output for missing/extra
# .fcr = fpgatools compare missing/extra result
# .fcm = fpgatools compare match
# .fcd = fpgatools compare diff
# .fce = fpgatools compare extra
# .fao = fpgatools autotest output
# .far = fpgatools autotest result (diff to gold output)
#
test_dirs := $(shell mkdir -p test.gold test.out)
DESIGN_TESTS := hello_world blinking_led
AUTO_TESTS := logic_cfg routing_sw io_sw iob_cfg lut_encoding
COMPARE_TESTS := xc6slx9_tiles xc6slx9_devs xc6slx9_ports xc6slx9_conns xc6slx9_sw xc6slx9_swbits
DESIGN_GOLD := $(foreach target, $(DESIGN_TESTS), test.gold/design_$(target).fp)
AUTOTEST_GOLD := $(foreach target, $(AUTO_TESTS), test.gold/autotest_$(target).fao)
COMPARE_GOLD := $(foreach target, $(COMPARE_TESTS), test.gold/compare_$(target).fco)
test_gold: design_gold autotest_gold compare_gold
design_gold: $(DESIGN_GOLD)
autotest_gold: $(AUTOTEST_GOLD)
compare_gold: $(COMPARE_GOLD)
test: test_design test_auto test_compare
test_design: $(foreach target, $(DESIGN_TESTS), test.out/design_$(target).ftest)
test_auto: $(foreach target, $(AUTO_TESTS), test.out/autotest_$(target).ftest)
test_compare: $(foreach target, $(COMPARE_TESTS), test.out/compare_$(target).ftest)
# design testing targets
design_%.ftest: design_%.ffbd
@if test -s $<; then echo "Design test: $(*F) - failed, diff follows"; cat $<; else echo "Design test: $(*F) - succeeded"; fi;
@if test -s test.gold/$(basename $(@F)).fp; then diff -U 0 test.gold/$(basename $(@F)).fp $(basename $@).fp > $(basename $@).f2gd || (echo Diff to gold: && cat $(basename $@).f2gd); fi;
%.ffbd: %.fp %.fb2f
@diff -u $(basename $@).fp $(basename $@).fb2f >$@ || true
%.fb2f: %.ff2b bit2fp
@./bit2fp $< >$@ 2>&1
%.ff2b: %.fp fp2bit
@./fp2bit $< $@
design_%.fp: $$*
@./$(*F) >$@ 2>&1
# autotest targets
autotest_%.ftest: autotest_%.far
@if test -s $<; then echo "Test failed: $(*F) (autotest), diff follows"; cat $<; else echo "Test succeeded: $(*F) (autotest)"; fi;
%.far: %.fao
@if test ! -e test.gold/$(*F).fao; then echo Gold test.gold/$(*F).fao does not exist, aborting.; false; fi;
@diff -U 0 -I "^O #NODIFF" test.gold/$(*F).fao $< >$@ || true
autotest_%.fao: autotest fp2bit bit2fp
./autotest --test=$(*F) >$@ 2>&1
# compare testing targets
compare_%.ftest: compare_%.fcr
@echo Test: $(*F) \(compare\)
@cat $<|awk '{print " "$$0}'
%.fcr: %.fcm %.fcd %.fce
@echo Matching lines - $*.fcm >$@
@cat $*.fcm | wc -l >>$@
@echo Missing lines - $*.fcd >>$@
@cat $*.fcd | grep ^-[^-] | wc -l >>$@
@if test -s $*.fce; then echo Extra lines - $*.fce: >>$@; cat $*.fce >>$@; fi;
%.fcm: %.fco
@if test ! -e test.gold/$(*F).fco; then echo Gold test.gold/$(*F).fco does not exist, aborting.; false; fi;
@comm -1 -2 $< test.gold/$(*F).fco >$@
%.fcd: %.fco
@if test ! -e test.gold/$(*F).fco; then echo Gold test.gold/$(*F).fco does not exist, aborting.; false; fi;
@diff -u test.gold/$(*F).fco $< >$@ || true
%.fce: %.fcd
@cat $< | grep ^+[^+] >$@ || true
compare_%_tiles.fco: compare_%.fp
@cat $<|awk '{if ($$1=="tile" && $$4=="name") printf "%s %s %s\n",$$2,$$3,$$5}'|sort >$@
compare_%_devs.fco: compare_%.fp
@cat $<|awk '{if ($$1=="dev") {if ($$6=="type") printf "%s %s %s %s\n",$$2,$$3,$$4,$$7; else printf "%s %s %s\n",$$2,$$3,$$4; }}'|sort >$@
compare_%_ports.fco: compare_%.fp
@cat $<|awk '{if ($$1=="port") printf "%s %s %s\n",$$2,$$3,$$4}'|sort >$@
compare_%_conns.fco: compare_%.fp sort_seq merge_seq
@cat $<|awk '{if ($$1=="conn") printf "%s %s %s %s %s %s\n",$$2,$$3,$$5,$$6,$$4,$$7}'|sort|./sort_seq -|./merge_seq -|awk '{printf "%s %s %s %s %s %s\n",$$1,$$2,$$5,$$3,$$4,$$6}'|sort >$@
compare_%_sw.fco: compare_%.fp
@cat $<|awk '{if ($$1=="sw") printf "%s %s %s %s %s\n",$$2,$$3,$$4,$$5,$$6}'|sort >$@
compare_%_swbits.fco: bit2fp
@./bit2fp --printf-swbits | sort > $@
compare_%.fp: new_fp
@./new_fp >$@
# todo: .cnets not integrated yet
%.cnets: %.fp pair2net
cat $<|awk '{if ($$1=="conn") printf "%s-%s-%s %s-%s-%s\n",$$2,$$3,$$4,$$5,$$6,$$7}' |./pair2net -|sort >$@
@echo Number of conn nets:
@cat $@|wc -l
@echo Number of connection points:
@cat $@|wc -w
@echo Largest net:
@cat $@|awk '{if (NF>max) max=NF} END {print max}'
#
# end of testing section
#
autotest: autotest.o $(DYNAMIC_LIBS)
hello_world: hello_world.o $(DYNAMIC_LIBS)
blinking_led: blinking_led.o $(DYNAMIC_LIBS)
fp2bit: fp2bit.o $(DYNAMIC_LIBS)
bit2fp: bit2fp.o $(DYNAMIC_LIBS)
new_fp: new_fp.o $(DYNAMIC_LIBS)
draw_svg_tiles: CFLAGS += `pkg-config libxml-2.0 --cflags`
draw_svg_tiles: LDLIBS += `pkg-config libxml-2.0 --libs`
draw_svg_tiles: draw_svg_tiles.o $(DYNAMIC_LIBS)
pair2net: pair2net.o $(DYNAMIC_LIBS)
sort_seq: sort_seq.o $(DYNAMIC_LIBS)
merge_seq: merge_seq.o $(DYNAMIC_LIBS)
hstrrep: hstrrep.o $(DYNAMIC_LIBS)
xc6slx9.fp: new_fp
./new_fp > $@
xc6slx9.svg: draw_svg_tiles
./draw_svg_tiles | xmllint --pretty 1 - > $@
clean:
@make -C libs clean
rm -f $(OBJS) *.d
rm -f draw_svg_tiles new_fp hstrrep sort_seq merge_seq autotest
rm -f fp2bit bit2fp pair2net hello_world blinking_led
rm -f xc6slx9.fp xc6slx9.svg
rm -f $(DESIGN_GOLD) $(AUTOTEST_GOLD) $(COMPARE_GOLD)
rm -f test.gold/compare_xc6slx9.fp
rm -f $(foreach f, $(DESIGN_TESTS), test.out/design_$(f).ffbd)
rm -f $(foreach f, $(DESIGN_TESTS), test.out/design_$(f).ff2b)
rm -f $(foreach f, $(DESIGN_TESTS), test.out/design_$(f).fb2f)
rm -f $(foreach f, $(DESIGN_TESTS), test.out/design_$(f).f2gd)
rm -f $(foreach f, $(DESIGN_TESTS), test.out/design_$(f).fp)
rm -f test.out/autotest_*
rm -f $(foreach f, $(COMPARE_TESTS), test.out/compare_$(f).fco)
rm -f $(foreach f, $(COMPARE_TESTS), test.out/compare_$(f).fcr)
rm -f $(foreach f, $(COMPARE_TESTS), test.out/compare_$(f).fcm)
rm -f $(foreach f, $(COMPARE_TESTS), test.out/compare_$(f).fcd)
rm -f $(foreach f, $(COMPARE_TESTS), test.out/compare_$(f).fce)
rm -f test.out/compare_xc6slx9.fp
rmdir --ignore-fail-on-non-empty test.out test.gold
install: fp2bit bit2fp
@make -C libs install
mkdir -p $(DESTDIR)/$(PREFIX)/bin/
install -m 755 fp2bit $(DESTDIR)/$(PREFIX)/bin/
install -m 755 bit2fp $(DESTDIR)/$(PREFIX)/bin/
chrpath -d $(DESTDIR)/$(PREFIX)/bin/fp2bit
chrpath -d $(DESTDIR)/$(PREFIX)/bin/bit2fp
uninstall:
@make -C libs uninstall
rm -f $(DESTDIR)/$(PREFIX)/bin/{fp2bit,bit2fp}
fpgatools-201212/Makefile.common 0000664 0000000 0000000 00000003432 12065743015 0016535 0 ustar 00root root 0000000 0000000 #
# Makefile - fpgatools
# Author: Wolfgang Spraul
#
# This is free and unencumbered software released into the public domain.
# For details see the UNLICENSE file at the root of the source tree.
#
PREFIX ?= /usr/local
SHELL = /bin/bash
# -fno-omit-frame-pointer and -ggdb add almost nothing to execution
# time right now, so we can leave them in all the time.
CFLAGS_DBG = -fno-omit-frame-pointer -ggdb
CFLAGS += $(CFLAGS_DBG)
CFLAGS += -Wall -Wshadow -Wmissing-prototypes -Wmissing-declarations \
-Wno-format-zero-length -O2
# ----- Verbosity control -----------------------------------------------------
CPP := $(CPP) # make sure changing CC won't affect CPP
CC_normal := $(CC)
AR_normal := $(AR) rsc
DEPEND_normal := $(CPP) $(CFLAGS) -D__OPTIMIZE__ -MM -MG
RANLIB_normal := ranlib
CC_quiet = @echo " CC " $@ && $(CC_normal)
AR_quiet = @echo " AR " $@ && $(AR_normal)
DEPEND_quiet = @$(DEPEND_normal)
RANLIB_quiet = @$(RANLIB_normal)
ifeq ($(V),1)
CC = $(CC_normal)
AR = $(AR_normal)
DEPEND = $(DEPEND_normal)
RANLIB = $(RANLIB_normal)
else
CC = $(CC_quiet)
AR = $(AR_quiet)
DEPEND = $(DEPEND_quiet)
RANLIB = $(RANLIB_quiet)
endif
# because all sub Makefiles also include this file, no need to pass down
# these variables. or we risk producing "@echo ... && @echo ... && cc .."
# which is not correct.
unexport CC AR DEPEND RANLIB
# ----- Dependencies ----------------------------------------------------------
MKDEP = \
$(DEPEND) $< | \
sed \
-e 's|^$(basename $(notdir $<)).o:|$@:|' \
-e '/^\(.*:\)\? */{p;s///;s/ *\\\?$$/ /;s/ */:\n/g;H;}' \
-e '$${g;p;}' \
-e d >$(basename $@).d; \
[ "$${PIPESTATUS[*]}" = "0 0" ] || \
{ rm -f $(basename $@).d; exit 1; }
-include $(OBJS:.o=.d)
fpgatools-201212/README 0000664 0000000 0000000 00000007604 12065743015 0014473 0 ustar 00root root 0000000 0000000 Introduction
fpgatools is a toolchain to program field-programmable gate arrays
(FPGAs). The only supported chip at this time is the xc6slx9, a
7 USD 45nm-generation fpga with 5720 6-input LUTs, block ram and
multiply-accumulate devices.
*) maximize chip performance
*) fast development cycles
*) independent toolchain that only depends on other free software
*) reconfigure on-chip
*) include get-started tools such as jtag, debugging, parts data
and designs for prototyping hardware
*) design flow that includes asic manufacturing
*) lightweight C implementation without GUI
*) supported platform: Linux
*) license: public domain
FAQ
todo
Libraries
- libfpga-cores reusable cores
- libfpga-stdlib standard design elements on top of libfpga-control
- libfpga-control programmatic access to libfpga-model
- libfpga-model memory-only representation of an FPGA
- libfpga-floorplan reads and writes .fp floorplan files
- libfpga-bit reads and writes .bit bitstream files
Design Utilities
- hello_world outputs an AND gate floorplan to stdout
- blinking_led outputs blinking led design to stdout
- new_fp creates empty .fp floorplan file
- fp2bit converts .fp floorplan into .bit bitstream
- bit2fp converts .bit bitstream into .fp floorplan
- draw_svg_tiles draws a simple .svg showing tile types
fpgatools Development Utilities
- autotest test suite
- sort_seq sorts line-based text file by sequence numbers in strings
- merge_seq merges a pre-sorted text file into wire sequences
- pair2net reads the first two words per line and builds nets
- hstrrep high-speed hashed array based search and replace util
Profiling
~# time ./hello_world
~# perf record ./hello_world
~# perf annotate
~# perf report
Design Principles
- small independent command line utilities, no GUI
- plain C, no C++
- simple Makefiles
- text-based file formats
- automatic test suite
- public domain software
TODO (as of January, 2013)
short-term (1 month):
* example: counter (including clock, jtag)
* support xc6slx9-ftg256
mid-term (6 months):
* example: j1 soc
* llvm backend
* maybe fp2bit should natively write ieee1532 and separate tools convert
from ieee1532 to .bit and other formats
* configuration of bram and macc blocks, bram initialization data
* more cases in logic block configuration
* autotest: fix bugs in lut_encoding, logic_cfg, routing_sw, io_sw tests
* autotest: protect stderr of diff executable in autotest log
* 3 Debian packages: libfpga, libfpga-doc, fpgatools
* support chips other than xc6slx9, maybe an ftg256 or fgg484-packaged
xc6 or the xc7a100
* write standard design elements for libfpga-stdlib library
* several places might benefit from a bison parser:
- switchbox description into bit parser/generator (bit_frames.c)
- inter-tile wire connections (model_conns.c)
- configure devices and route wires
cleanup (whenever convenient):
* use tile flags instead of tile names
* model connections and switches together rather than separately
* describe more wire names/meanings with integers instead of strings
* move all part-specific static data into xc_info()
long-term (>6 months):
* auto-crc calculation in .bit file
* MCB switches and connections
* support lm32 or openrisc core, either via libfpga or iverilog backend
* ipv6 or vnc in hardware?
* iverilog fpga backend
* design fpga core that uses high-speed icap/reconfig to process data
ChangeLog
2012-12-20
* Second design verified: blinking_led is a clocked design where the clock
increments a counter and the highest bit of the counter drives a LED.
2012-09-24
* First design verified: hello_world is an unclocked AND gate design
which was verified in a xc6slx9.
2012-08-20
* Beginning of full fidelity circle with model, floorplan, conversion
between floorplan and binary configuration formats.
2012-06-03
* Project started.
fpgatools-201212/UNLICENSE 0000664 0000000 0000000 00000002273 12065743015 0015060 0 ustar 00root root 0000000 0000000 This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to
fpgatools-201212/autotest.c 0000664 0000000 0000000 00000167325 12065743015 0015636 0 ustar 00root root 0000000 0000000 //
// Author: Wolfgang Spraul
//
// This is free and unencumbered software released into the public domain.
// For details see the UNLICENSE file at the root of the source tree.
//
#include
#include "model.h"
#include "floorplan.h"
#include "control.h"
time_t g_start_time;
#define TIME() (time(0)-g_start_time)
#define TIMESTAMP() printf("O #NODIFF timestamp %lld\n", (long long) TIME())
#define MEMUSAGE() printf("O #NODIFF memusage %i\n", get_vm_mb());
#define TIME_AND_MEM() TIMESTAMP(); MEMUSAGE()
#define AUTOTEST_TMP_DIR "test.out"
struct test_state
{
int cmdline_skip;
int cmdline_count;
char cmdline_diff_exec[1024];
int dry_run;
int diff_to_null;
struct fpga_model* model;
// test filenames are: tmp_dir/autotest__.???
char tmp_dir[256];
char base_name[256];
int next_diff_counter;
};
static int dump_file(const char* path)
{
char line[1024];
FILE* f;
printf("\n");
printf("O begin dump %s\n", path);
if (!(f = fopen(path, "r")))
printf("#E error opening %s\n", path);
else {
while (fgets(line, sizeof(line), f)) {
if (!strncmp(line, "--- ", 4)
|| !strncmp(line, "+++ ", 4)
|| !strncmp(line, "@@ ", 3))
continue;
printf(line);
}
fclose(f);
}
printf("O end dump %s\n", path);
return 0;
}
static int diff_start(struct test_state* tstate, const char* base_name)
{
strcpy(tstate->base_name, base_name);
tstate->next_diff_counter = 1;
return 0;
}
static int diff_printf(struct test_state* tstate)
{
char path[1024], tmp[1024], prior_fp[1024];
int path_base;
FILE* dest_f = 0;
int rc;
if (tstate->cmdline_count != -1
&& tstate->next_diff_counter >= tstate->cmdline_skip + tstate->cmdline_count + 1) {
printf("\nO Finished %i tests.\n", tstate->cmdline_count);
exit(0);
}
if (tstate->dry_run) {
printf("O Dry run, skipping diff %i.\n", tstate->next_diff_counter++);
return 0;
}
if (tstate->cmdline_skip >= tstate->next_diff_counter) {
printf("O Skipping diff %i.\n", tstate->next_diff_counter++);
return 0;
}
snprintf(path, sizeof(path), "%s/autotest_%s_%06i", tstate->tmp_dir,
tstate->base_name, tstate->next_diff_counter);
path_base = strlen(path);
if (tstate->diff_to_null
|| tstate->next_diff_counter == tstate->cmdline_skip + 1)
strcpy(prior_fp, "/dev/null");
else {
snprintf(prior_fp, sizeof(prior_fp), "%s/autotest_%s_%06i.fp",
tstate->tmp_dir, tstate->base_name,
tstate->next_diff_counter-1);
}
strcpy(&path[path_base], ".fp");
dest_f = fopen(path, "w");
if (!dest_f) FAIL(errno);
rc = printf_devices(dest_f, tstate->model, /*config_only*/ 1);
if (rc) FAIL(rc);
rc = printf_nets(dest_f, tstate->model);
if (rc) FAIL(rc);
fclose(dest_f);
dest_f = 0;
path[path_base] = 0;
snprintf(tmp, sizeof(tmp), "%s %s %s.fp >%s.log 2>&1",
tstate->cmdline_diff_exec, prior_fp, path, path);
rc = system(tmp);
if (rc) {
printf("#E %s:%i system call '%s' failed with code %i, "
"check %s.log\n", __FILE__, __LINE__, tmp, rc, path);
// ENOENT comes back when pressing ctrl-c
if (rc == ENOENT) EXIT(rc);
// todo: report the error up so we can avoid adding a switch to the block list etc.
}
strcpy(&path[path_base], ".diff");
rc = dump_file(path);
if (rc) FAIL(rc);
tstate->next_diff_counter++;
return 0;
fail:
if (dest_f) fclose(dest_f);
return rc;
}
static int test_logic_net(struct test_state* tstate, int logic_y, int logic_x,
int type_idx, pinw_idx_t port, const struct sw_set* logic_switch_set,
int routing_y, int routing_x, swidx_t routing_sw1, swidx_t routing_sw2)
{
net_idx_t net_idx;
struct sw_set routing_switches;
int dbg, rc;
dbg = 0;
rc = fnet_new(tstate->model, &net_idx);
if (rc) FAIL(rc);
// add port
rc = fnet_add_port(tstate->model, net_idx, logic_y, logic_x,
DEV_LOGIC, type_idx, port);
if (rc) FAIL(rc);
// add (one) switch in logic tile
rc = fnet_add_sw(tstate->model, net_idx,
logic_y, logic_x, logic_switch_set->sw, logic_switch_set->len);
if (rc) FAIL(rc);
// add switches in routing tile
routing_switches.len = 0;
if (routing_sw1 == NO_SWITCH) FAIL(EINVAL);
routing_switches.sw[routing_switches.len++] = routing_sw1;
if (routing_sw2 != NO_SWITCH)
routing_switches.sw[routing_switches.len++] = routing_sw2;
rc = fnet_add_sw(tstate->model, net_idx,
routing_y, routing_x, routing_switches.sw, routing_switches.len);
if (rc) FAIL(rc);
if (dbg)
printf("lnet %s %s\n",
routing_sw2 == NO_SWITCH ? "" : fpga_switch_print(
tstate->model, routing_y, routing_x,
routing_sw2),
fpga_switch_print(tstate->model,
routing_y, routing_x, routing_sw1));
rc = diff_printf(tstate);
if (rc) FAIL(rc);
fnet_delete(tstate->model, net_idx);
return 0;
fail:
return rc;
}
static int test_logic_net_l2(struct test_state* tstate, int y, int x,
int type, int type_idx, str16_t* done_pinw_list, int* done_pinw_len,
swidx_t* l2_done_list, int* l2_done_len)
{
struct fpga_device* dev;
struct switch_to_yx switch_to;
int i, j, k, l, m, from_to, rc;
struct sw_set set_l1, set_l2;
struct fpga_tile* switch_tile;
int dbg = 0;
rc = fdev_set_required_pins(tstate->model, y, x, type, type_idx);
if (rc) FAIL(rc);
if (dbg)
fdev_print_required_pins(tstate->model, y, x, type, type_idx);
dev = fdev_p(tstate->model, y, x, type, type_idx);
if (!dev) FAIL(EINVAL);
for (i = 0; i < dev->pinw_req_total; i++) {
// do every pinw only once across all configs
for (j = 0; j < *done_pinw_len; j++) {
if (done_pinw_list[j] == dev->pinw[dev->pinw_req_for_cfg[i]])
break;
}
if (j < *done_pinw_len)
continue;
done_pinw_list[(*done_pinw_len)++] = dev->pinw[dev->pinw_req_for_cfg[i]];
from_to = (i < dev->pinw_req_in) ? SW_TO : SW_FROM;
switch_to.yx_req = YX_ROUTING_TILE;
switch_to.flags = SWTO_YX_DEF;
switch_to.model = tstate->model;
switch_to.y = y;
switch_to.x = x;
switch_to.start_switch = dev->pinw[dev->pinw_req_for_cfg[i]];
switch_to.from_to = from_to;
switch_to.exclusive_net = NO_NET;
rc = fpga_switch_to_yx(&switch_to);
if (rc) FAIL(rc);
if (dbg)
printf_switch_to_yx_result(&switch_to);
switch_tile = YX_TILE(tstate->model, switch_to.dest_y, switch_to.dest_x);
rc = fpga_swset_fromto(tstate->model, switch_to.dest_y,
switch_to.dest_x, switch_to.dest_connpt, from_to, &set_l1);
if (rc) FAIL(rc);
if (dbg)
fpga_swset_print(tstate->model, switch_to.dest_y,
switch_to.dest_x, &set_l1, from_to);
for (j = 0; j < set_l1.len; j++) {
for (k = 0; k < 2; k++) {
// k == 0 is the SW_FROM round, k == 1 is the SW_TO round.
// For out-pins, we don't need the SW_TO round because they
// would create multiple sources driving one pin which is
// illegal.
if (k && i >= dev->pinw_req_in)
break;
rc = fpga_swset_fromto(tstate->model, switch_to.dest_y,
switch_to.dest_x, CONNPT_STR16(switch_tile,
SW_I(switch_tile->switches[set_l1.sw[j]], !from_to)),
k ? SW_TO : SW_FROM, &set_l2);
if (rc) FAIL(rc);
for (l = 0; l < set_l2.len; l++) {
// duplicate check
for (m = 0; m < *l2_done_len; m++) {
if (l2_done_list[m] == set_l2.sw[l])
break;
}
if (m < *l2_done_len)
continue;
l2_done_list[(*l2_done_len)++] = set_l2.sw[l];
if (tstate->dry_run)
printf("l2_done_list %s at %i\n", fpga_switch_print(tstate->model,
switch_to.dest_y, switch_to.dest_x, l2_done_list[(*l2_done_len)-1]),
(*l2_done_len)-1);
// we did the l1 switches in an earlier round, but have to
// redo them before every l2 switch to make a clean diff
// on top of l1. The l2 can be in the same mip as the l1
// so it has to be repeated for every l2 switch, not just
// once for the set.
rc = test_logic_net(tstate, y, x, type_idx, dev->pinw_req_for_cfg[i],
&switch_to.set, switch_to.dest_y, switch_to.dest_x,
set_l1.sw[j], NO_SWITCH);
if (rc) FAIL(rc);
rc = test_logic_net(tstate, y, x, type_idx, dev->pinw_req_for_cfg[i],
&switch_to.set, switch_to.dest_y, switch_to.dest_x,
set_l1.sw[j], set_l2.sw[l]);
if (rc) FAIL(rc);
}
}
}
}
return 0;
fail:
return rc;
}
static int test_logic_net_l1(struct test_state* tstate, int y, int x,
int type, int type_idx, str16_t* done_pinw_list, int* done_pinw_len,
swidx_t* done_sw_list, int* done_sw_len)
{
struct fpga_device* dev;
struct switch_to_yx switch_to;
int i, j, k, from_to, rc;
struct sw_set set_l1;
int dbg = 0;
rc = fdev_set_required_pins(tstate->model, y, x, type, type_idx);
if (rc) FAIL(rc);
if (tstate->dry_run)
fdev_print_required_pins(tstate->model, y, x, type, type_idx);
dev = fdev_p(tstate->model, y, x, type, type_idx);
if (!dev) FAIL(EINVAL);
for (i = 0; i < dev->pinw_req_total; i++) {
// do every pinw only once across all configs
for (j = 0; j < *done_pinw_len; j++) {
if (done_pinw_list[j] == dev->pinw[dev->pinw_req_for_cfg[i]])
break;
}
if (j < *done_pinw_len)
continue;
done_pinw_list[(*done_pinw_len)++] = dev->pinw[dev->pinw_req_for_cfg[i]];
from_to = (i < dev->pinw_req_in) ? SW_TO : SW_FROM;
switch_to.yx_req = YX_ROUTING_TILE;
switch_to.flags = SWTO_YX_DEF;
switch_to.model = tstate->model;
switch_to.y = y;
switch_to.x = x;
switch_to.start_switch = dev->pinw[dev->pinw_req_for_cfg[i]];
switch_to.from_to = from_to;
switch_to.exclusive_net = NO_NET;
rc = fpga_switch_to_yx(&switch_to);
if (rc) FAIL(rc);
if (tstate->dry_run)
printf_switch_to_yx_result(&switch_to);
rc = fpga_swset_fromto(tstate->model, switch_to.dest_y,
switch_to.dest_x, switch_to.dest_connpt, from_to, &set_l1);
if (rc) FAIL(rc);
if (dbg)
fpga_swset_print(tstate->model, switch_to.dest_y,
switch_to.dest_x, &set_l1, from_to);
for (j = 0; j < set_l1.len; j++) {
// an out-pin can go directly to an in-pin and
// we don't need that pin twice
for (k = 0; k < *done_sw_len; k++) {
if (done_sw_list[k] == set_l1.sw[j])
break;
}
if (k < *done_sw_len)
continue;
rc = test_logic_net(tstate, y, x, type_idx, dev->pinw_req_for_cfg[i],
&switch_to.set, switch_to.dest_y, switch_to.dest_x,
set_l1.sw[j], NO_SWITCH);
if (rc) FAIL(rc);
done_sw_list[(*done_sw_len)++] = set_l1.sw[j];
if (tstate->dry_run)
printf("done_list %s at %i\n", fpga_switch_print(tstate->model,
switch_to.dest_y, switch_to.dest_x, set_l1.sw[j]),
(*done_sw_len)-1);
}
}
return 0;
fail:
return rc;
}
static int test_switches(struct test_state* tstate, int y, int x,
str16_t start_switch, net_idx_t net, swidx_t* done_list, int* done_list_len)
{
struct sw_set sw_set, w4_set;
const char* switch_str;
str16_t switch_str_i;
int i, j, k, rc;
rc = fpga_swset_fromto(tstate->model, y, x, start_switch, SW_TO, &sw_set);
if (rc) FAIL(rc);
if (tstate->dry_run)
fpga_swset_print(tstate->model, y, x, &sw_set, SW_TO);
for (i = 0; i < sw_set.len; i++) {
switch_str_i = fpga_switch_str_i(tstate->model, y, x,
sw_set.sw[i], SW_FROM);
switch_str = strarray_lookup(&tstate->model->str, switch_str_i);
if (!switch_str) FAIL(EINVAL);
if (switch_str[2] == '4') {
// base for len-4 wire
if (tstate->dry_run)
fnet_printf(stdout, tstate->model, net);
rc = diff_printf(tstate);
if (rc) FAIL(rc);
// add len-4 wire
rc = fnet_add_sw(tstate->model, net, y, x,
&sw_set.sw[i], 1);
if (rc) FAIL(rc);
// enum dests of len-4 wire
rc = fpga_swset_fromto(tstate->model, y, x,
switch_str_i, SW_FROM, &w4_set);
if (rc) FAIL(rc);
if (tstate->dry_run)
fpga_swset_print(tstate->model, y, x,
&w4_set, SW_FROM);
for (j = 0; j < w4_set.len; j++) {
// do not point to our base twice
if (w4_set.sw[j] == sw_set.sw[i])
continue;
// duplicate check and done_list
for (k = 0; k < *done_list_len; k++) {
if (done_list[k] == w4_set.sw[j])
break;
}
if (k < *done_list_len)
continue;
done_list[(*done_list_len)++] = w4_set.sw[j];
if (tstate->dry_run)
printf("done_list %s at %i\n",
fpga_switch_print(tstate->model,
y, x, done_list[(*done_list_len)-1]),
(*done_list_len)-1);
// base for len-4 target
if (tstate->dry_run)
fnet_printf(stdout, tstate->model, net);
rc = diff_printf(tstate);
if (rc) FAIL(rc);
// add len-4 target
rc = fnet_add_sw(tstate->model, net, y, x,
&w4_set.sw[j], 1);
if (rc) FAIL(rc);
if (tstate->dry_run)
fnet_printf(stdout, tstate->model, net);
rc = diff_printf(tstate);
if (rc) FAIL(rc);
rc = fnet_remove_sw(tstate->model, net, y, x,
&w4_set.sw[j], 1);
if (rc) FAIL(rc);
}
rc = fnet_remove_sw(tstate->model, net, y, x,
&sw_set.sw[i], 1);
if (rc) FAIL(rc);
}
}
return 0;
fail:
return rc;
}
int test_routing_sw_from_iob(struct test_state* tstate,
swidx_t* done_list, int* done_list_len);
int test_routing_sw_from_iob(struct test_state* tstate,
swidx_t* done_list, int* done_list_len)
{
struct switch_to_yx switch_to;
int iob_y, iob_x, iob_type_idx, rc;
struct fpga_device* iob_dev;
net_idx_t net;
rc = fpga_find_iob(tstate->model, "P48", &iob_y, &iob_x, &iob_type_idx);
if (rc) FAIL(rc);
rc = fdev_iob_output(tstate->model, iob_y, iob_x, iob_type_idx, IO_LVCMOS33);
if (rc) FAIL(rc);
iob_dev = fdev_p(tstate->model, iob_y, iob_x, DEV_IOB, iob_type_idx);
if (!iob_dev) FAIL(EINVAL);
rc = fnet_new(tstate->model, &net);
if (rc) FAIL(rc);
rc = fnet_add_port(tstate->model, net, iob_y, iob_x,
DEV_IOB, iob_type_idx, IOB_IN_O);
if (rc) FAIL(rc);
switch_to.yx_req = YX_DEV_OLOGIC;
switch_to.flags = SWTO_YX_DEF;
switch_to.model = tstate->model;
switch_to.y = iob_y;
switch_to.x = iob_x;
switch_to.start_switch = iob_dev->pinw[IOB_IN_O];
switch_to.from_to = SW_TO;
switch_to.exclusive_net = NO_NET;
rc = fpga_switch_to_yx(&switch_to);
if (rc) FAIL(rc);
if (tstate->dry_run)
printf_switch_to_yx_result(&switch_to);
rc = fnet_add_sw(tstate->model, net, switch_to.y,
switch_to.x, switch_to.set.sw, switch_to.set.len);
if (rc) FAIL(rc);
switch_to.yx_req = YX_ROUTING_TILE;
switch_to.flags = SWTO_YX_DEF;
switch_to.model = tstate->model;
switch_to.y = switch_to.dest_y;
switch_to.x = switch_to.dest_x;
switch_to.start_switch = switch_to.dest_connpt;
switch_to.from_to = SW_TO;
switch_to.exclusive_net = NO_NET;
rc = fpga_switch_to_yx(&switch_to);
if (rc) FAIL(rc);
rc = fnet_add_sw(tstate->model, net, switch_to.y,
switch_to.x, switch_to.set.sw, switch_to.set.len);
if (rc) FAIL(rc);
if (tstate->dry_run)
printf_switch_to_yx_result(&switch_to);
switch_to.yx_req = YX_ROUTING_TO_FABLOGIC;
switch_to.flags = SWTO_YX_CLOSEST;
switch_to.model = tstate->model;
switch_to.y = switch_to.dest_y;
switch_to.x = switch_to.dest_x;
switch_to.start_switch = switch_to.dest_connpt;
switch_to.from_to = SW_TO;
switch_to.exclusive_net = NO_NET;
rc = fpga_switch_to_yx(&switch_to);
if (rc) FAIL(rc);
if (tstate->dry_run)
printf_switch_to_yx_result(&switch_to);
rc = fnet_add_sw(tstate->model, net, switch_to.y,
switch_to.x, switch_to.set.sw, switch_to.set.len);
if (rc) FAIL(rc);
rc = test_switches(tstate, switch_to.dest_y, switch_to.dest_x,
switch_to.dest_connpt, net, done_list, done_list_len);
if (rc) FAIL(rc);
fdev_delete(tstate->model, iob_y, iob_x, DEV_IOB, iob_type_idx);
fnet_delete(tstate->model, net);
return 0;
fail:
return rc;
}
static int test_routing_sw_from_logic(struct test_state* tstate,
swidx_t* done_list, int* done_list_len)
{
struct fpga_device* dev;
struct switch_to_rel swto;
struct sw_conns conns;
const char* str;
net_idx_t net;
int y, x, rel_y, i, rc;
y = 67;
x = 13;
// We loop over this twice, once with rel_y==-1 and then with rel_y==+1
// That way we come into the routing switchbox over the nr1/nl1 wires
// from below, or sr1/sl1 wires from above.
for (rel_y = -1; rel_y <= 1; rel_y += 2) {
for (i = '1'; i <= '6'; i++) {
rc = fdev_logic_a2d_lut(tstate->model, y, x,
DEV_LOG_M_OR_L, LUT_A, 6, pf("A%c", i), ZTERM);
if (rc) FAIL(rc);
rc = fdev_set_required_pins(tstate->model, y, x,
DEV_LOGIC, DEV_LOG_M_OR_L);
if (rc) FAIL(rc);
if (tstate->dry_run)
fdev_print_required_pins(tstate->model,
y, x, DEV_LOGIC, DEV_LOG_M_OR_L);
dev = fdev_p(tstate->model, y, x, DEV_LOGIC, DEV_LOG_M_OR_L);
if (!dev) FAIL(EINVAL);
if (!dev->pinw_req_in) FAIL(EINVAL);
rc = fnet_new(tstate->model, &net);
if (rc) FAIL(rc);
rc = fnet_add_port(tstate->model, net, y, x,
DEV_LOGIC, DEV_LOG_M_OR_L, dev->pinw_req_for_cfg[0]);
if (rc) FAIL(rc);
swto.model = tstate->model;
swto.start_y = y;
swto.start_x = x;
swto.start_switch = fdev_logic_pinstr_i(tstate->model,
dev->pinw_req_for_cfg[0]|LD1, LOGIC_M);
swto.from_to = SW_TO;
swto.flags = SWTO_REL_DEFAULT;
swto.rel_y = 0;
swto.rel_x = -1;
swto.target_connpt = STRIDX_NO_ENTRY;
rc = fpga_switch_to_rel(&swto);
if (rc) FAIL(rc);
if (!swto.set.len) FAIL(EINVAL);
if (tstate->dry_run)
printf_switch_to_rel_result(&swto);
rc = fnet_add_sw(tstate->model, net, swto.start_y,
swto.start_x, swto.set.sw, swto.set.len);
if (rc) FAIL(rc);
rc = construct_sw_conns(&conns, tstate->model, swto.dest_y, swto.dest_x,
swto.dest_connpt, SW_TO, /*max_depth*/ 1, NO_NET);
if (rc) FAIL(rc);
while (fpga_switch_conns(&conns) != NO_CONN) {
if (conns.dest_x != swto.dest_x
|| conns.dest_y != swto.dest_y+rel_y)
continue;
str = strarray_lookup(&tstate->model->str, conns.dest_str_i);
if (!str) { HERE(); continue; }
if (strlen(str) < 5
|| str[2] != '1' || str[3] != 'B')
continue;
rc = fnet_add_sw(tstate->model, net, swto.dest_y,
swto.dest_x, conns.chain.set.sw, conns.chain.set.len);
if (rc) FAIL(rc);
if (tstate->dry_run)
fnet_printf(stdout, tstate->model, net);
rc = test_switches(tstate, conns.dest_y, conns.dest_x,
conns.dest_str_i, net, done_list, done_list_len);
if (rc) FAIL(rc);
rc = fnet_remove_sw(tstate->model, net, swto.dest_y,
swto.dest_x, conns.chain.set.sw, conns.chain.set.len);
if (rc) FAIL(rc);
}
destruct_sw_conns(&conns);
fdev_delete(tstate->model, y, x, DEV_LOGIC, DEV_LOG_M_OR_L);
fnet_delete(tstate->model, net);
}
}
return 0;
fail:
return rc;
}
// goal: use all switches in a routing switchbox
static int test_routing_switches(struct test_state* tstate)
{
int idx_enum[] = { DEV_LOG_M_OR_L, DEV_LOG_X };
int y, x, i, j, k, r, rc;
swidx_t done_sw_list[MAX_SWITCHBOX_SIZE];
int done_sw_len;
str16_t done_pinw_list[2000];
int done_pinw_len;
y = 68;
x = 13;
done_sw_len = 0;
for (r = 0; r <= 1; r++) {
// two rounds:
// r == 0: round over all configs with single-level nets only
// r == 1: second round with two-level nets
done_pinw_len = 0; // reset done pinwires for each round
for (i = 0; i < sizeof(idx_enum)/sizeof(*idx_enum); i++) {
for (j = LUT_A; j <= LUT_D; j++) {
// A1-A6 to A (same for lut B-D)
for (k = '1'; k <= '6'; k++) {
rc = fdev_logic_a2d_lut(tstate->model, y, x,
idx_enum[i], j, 6, pf("A%c", k), ZTERM);
if (rc) FAIL(rc);
if (!r)
rc = test_logic_net_l1(tstate, y, x, DEV_LOGIC,
idx_enum[i], done_pinw_list, &done_pinw_len,
done_sw_list, &done_sw_len);
else
rc = test_logic_net_l2(tstate, y, x, DEV_LOGIC,
idx_enum[i], done_pinw_list, &done_pinw_len,
done_sw_list, &done_sw_len);
if (rc) FAIL(rc);
fdev_delete(tstate->model, y, x, DEV_LOGIC, idx_enum[i]);
}
// A1->O6->FF->AQ (same for lut B-D)
rc = fdev_logic_a2d_lut(tstate->model, y, x,
idx_enum[i], j, 6, "A1", ZTERM);
if (rc) FAIL(rc);
rc = fdev_logic_a2d_ff(tstate->model, y, x, idx_enum[i],
j, MUX_O6, FF_SRINIT0);
if (rc) FAIL(rc);
rc = fdev_logic_sync(tstate->model, y, x, idx_enum[i],
SYNCATTR_ASYNC);
if (rc) FAIL(rc);
rc = fdev_logic_clk(tstate->model, y, x, idx_enum[i],
CLKINV_B);
if (rc) FAIL(rc);
rc = fdev_logic_ce_used(tstate->model, y, x, idx_enum[i]);
if (rc) FAIL(rc);
rc = fdev_logic_sr_used(tstate->model, y, x, idx_enum[i]);
if (rc) FAIL(rc);
rc = fdev_set_required_pins(tstate->model, y, x,
DEV_LOGIC, idx_enum[i]);
if (rc) FAIL(rc);
if (!r)
rc = test_logic_net_l1(tstate, y, x, DEV_LOGIC,
idx_enum[i], done_pinw_list, &done_pinw_len,
done_sw_list, &done_sw_len);
else
rc = test_logic_net_l2(tstate, y, x, DEV_LOGIC,
idx_enum[i], done_pinw_list, &done_pinw_len,
done_sw_list, &done_sw_len);
if (rc) FAIL(rc);
fdev_delete(tstate->model, y, x, DEV_LOGIC, idx_enum[i]);
}
}
}
done_sw_len = 0;
rc = test_routing_sw_from_logic(tstate, done_sw_list, &done_sw_len);
if (rc) FAIL(rc);
return 0;
fail:
return rc;
}
static int test_iologic_switches2(struct test_state* tstate, int iob_y, int iob_x, int iob_type_idx)
{
struct fpga_device* iob_dev;
struct switch_to_yx switch_to;
struct sw_chain chain;
net_idx_t net_idx;
int i, from_to, rc;
rc = fdev_set_required_pins(tstate->model, iob_y, iob_x, DEV_IOB, iob_type_idx);
if (rc) FAIL(rc);
if (tstate->dry_run)
fdev_print_required_pins(tstate->model, iob_y, iob_x, DEV_IOB, iob_type_idx);
iob_dev = fdev_p(tstate->model, iob_y, iob_x, DEV_IOB, iob_type_idx);
if (!iob_dev) FAIL(EINVAL);
for (i = 0; i < iob_dev->pinw_req_total; i++) {
from_to = i >= iob_dev->pinw_req_in ? SW_FROM : SW_TO;
// determine switch in iob to reach iologic tile
switch_to.yx_req = YX_DEV_ILOGIC;
switch_to.flags = SWTO_YX_DEF;
switch_to.model = tstate->model;
switch_to.y = iob_y;
switch_to.x = iob_x;
switch_to.start_switch = iob_dev->pinw[iob_dev->pinw_req_for_cfg[i]];
switch_to.from_to = from_to;
switch_to.exclusive_net = NO_NET;
rc = fpga_switch_to_yx(&switch_to);
if (rc) FAIL(rc);
if (tstate->dry_run)
printf_switch_to_yx_result(&switch_to);
if (construct_sw_chain(&chain, tstate->model, switch_to.dest_y,
switch_to.dest_x, switch_to.dest_connpt, from_to,
/*max_depth*/ -1, NO_NET, /*block_list*/ 0, /*block_list_len*/ 0))
FAIL(EINVAL);
while (fpga_switch_chain(&chain) != NO_CONN) {
if (tstate->dry_run)
printf("sw %s\n", fmt_swset(tstate->model,
switch_to.dest_y, switch_to.dest_x,
&chain.set, from_to));
// new net
rc = fnet_new(tstate->model, &net_idx);
if (rc) FAIL(rc);
// add iob port
rc = fnet_add_port(tstate->model, net_idx, iob_y, iob_x,
DEV_IOB, iob_type_idx, IOB_IN_O);
if (rc) FAIL(rc);
// add switch in iob tile
rc = fnet_add_sw(tstate->model, net_idx, switch_to.y,
switch_to.x, switch_to.set.sw, switch_to.set.len);
if (rc) FAIL(rc);
// add all but last switch in set
if (chain.set.len > 1) {
rc = fnet_add_sw(tstate->model, net_idx, switch_to.dest_y,
switch_to.dest_x, chain.set.sw, chain.set.len-1);
if (rc) FAIL(rc);
}
rc = diff_printf(tstate);
if (rc) FAIL(rc);
// add last switch
rc = fnet_add_sw(tstate->model, net_idx, switch_to.dest_y,
switch_to.dest_x, &chain.set.sw[chain.set.len-1], 1);
if (rc) FAIL(rc);
rc = diff_printf(tstate);
if (rc) FAIL(rc);
fnet_delete(tstate->model, net_idx);
}
destruct_sw_chain(&chain);
}
return 0;
fail:
return rc;
}
static int test_iologic_switches(struct test_state* tstate)
{
char iob_name[32];
int iob_y, iob_x, iob_type_idx, i, rc;
for (i = 45; i <= 48; i++) {
snprintf(iob_name, sizeof(iob_name), "P%i", i);
// input IOB
rc = fpga_find_iob(tstate->model, iob_name, &iob_y, &iob_x, &iob_type_idx);
if (rc) FAIL(rc);
rc = fdev_iob_input(tstate->model, iob_y, iob_x, iob_type_idx, IO_LVCMOS33);
if (rc) FAIL(rc);
rc = test_iologic_switches2(tstate, iob_y, iob_x, iob_type_idx);
if (rc) FAIL(rc);
fdev_delete(tstate->model, iob_y, iob_x, DEV_IOB, iob_type_idx);
// output IOB
rc = fpga_find_iob(tstate->model, iob_name, &iob_y, &iob_x, &iob_type_idx);
if (rc) FAIL(rc);
rc = fdev_iob_output(tstate->model, iob_y, iob_x, iob_type_idx, IO_LVCMOS33);
if (rc) FAIL(rc);
rc = test_iologic_switches2(tstate, iob_y, iob_x, iob_type_idx);
if (rc) FAIL(rc);
fdev_delete(tstate->model, iob_y, iob_x, DEV_IOB, iob_type_idx);
}
return 0;
fail:
return rc;
}
static int test_iob_config(struct test_state* tstate)
{
int iob_y, iob_x, iob_type_idx, i, j, rc;
net_idx_t net_idx;
struct fpga_device* dev;
int drive_strengths[] = {2, 4, 6, 8, 12, 16, 24};
tstate->diff_to_null = 1;
// P45 is an IOBS
rc = fpga_find_iob(tstate->model, "P45", &iob_y, &iob_x, &iob_type_idx);
if (rc) FAIL(rc);
rc = fdev_iob_input(tstate->model, iob_y, iob_x, iob_type_idx, IO_LVCMOS33);
if (rc) FAIL(rc);
dev = fdev_p(tstate->model, iob_y, iob_x, DEV_IOB, iob_type_idx);
if (!dev) FAIL(EINVAL);
if ((rc = diff_printf(tstate))) FAIL(rc);
dev->u.iob.I_mux = IMUX_I_B;
if ((rc = diff_printf(tstate))) FAIL(rc);
fdev_delete(tstate->model, iob_y, iob_x, DEV_IOB, iob_type_idx);
// P46 is an IOBM
rc = fpga_find_iob(tstate->model, "P46", &iob_y, &iob_x, &iob_type_idx);
if (rc) FAIL(rc);
rc = fdev_iob_input(tstate->model, iob_y, iob_x, iob_type_idx, IO_LVCMOS33);
if (rc) FAIL(rc);
if ((rc = diff_printf(tstate))) FAIL(rc);
fdev_delete(tstate->model, iob_y, iob_x, DEV_IOB, iob_type_idx);
// P47 is an IOBS
rc = fpga_find_iob(tstate->model, "P47", &iob_y, &iob_x, &iob_type_idx);
if (rc) FAIL(rc);
rc = fdev_iob_output(tstate->model, iob_y, iob_x, iob_type_idx, IO_LVCMOS33);
if (rc) FAIL(rc);
dev = fdev_p(tstate->model, iob_y, iob_x, DEV_IOB, iob_type_idx);
if (!dev) FAIL(EINVAL);
// least amount of bits:
dev->u.iob.slew = SLEW_SLOW;
dev->u.iob.drive_strength = 8;
dev->u.iob.suspend = SUSP_3STATE;
dev->u.iob.suspend = SUSP_3STATE;
rc = diff_printf(tstate); if (rc) FAIL(rc);
dev->u.iob.suspend = SUSP_3STATE_OCT_ON;
rc = diff_printf(tstate); if (rc) FAIL(rc);
dev->u.iob.suspend = SUSP_3STATE_KEEPER;
rc = diff_printf(tstate); if (rc) FAIL(rc);
dev->u.iob.suspend = SUSP_3STATE_PULLUP;
rc = diff_printf(tstate); if (rc) FAIL(rc);
dev->u.iob.suspend = SUSP_3STATE_PULLDOWN;
rc = diff_printf(tstate); if (rc) FAIL(rc);
dev->u.iob.suspend = SUSP_LAST_VAL;
rc = diff_printf(tstate); if (rc) FAIL(rc);
dev->u.iob.suspend = SUSP_3STATE;
for (i = 0; i < sizeof(drive_strengths)/sizeof(*drive_strengths); i++) {
dev->u.iob.drive_strength = drive_strengths[i];
rc = diff_printf(tstate); if (rc) FAIL(rc);
}
dev->u.iob.drive_strength = 8;
dev->u.iob.slew = SLEW_SLOW;
rc = diff_printf(tstate); if (rc) FAIL(rc);
dev->u.iob.slew = SLEW_FAST;
rc = diff_printf(tstate); if (rc) FAIL(rc);
dev->u.iob.slew = SLEW_QUIETIO;
rc = diff_printf(tstate); if (rc) FAIL(rc);
dev->u.iob.slew = SLEW_SLOW;
fdev_delete(tstate->model, iob_y, iob_x, DEV_IOB, iob_type_idx);
// P48 is an IOBM
rc = fpga_find_iob(tstate->model, "P48", &iob_y, &iob_x, &iob_type_idx);
if (rc) FAIL(rc);
rc = fdev_iob_output(tstate->model, iob_y, iob_x, iob_type_idx, IO_LVCMOS33);
if (rc) FAIL(rc);
dev = fdev_p(tstate->model, iob_y, iob_x, DEV_IOB, iob_type_idx);
if (!dev) FAIL(EINVAL);
// least bits
dev->u.iob.slew = SLEW_SLOW;
dev->u.iob.drive_strength = 8;
dev->u.iob.suspend = SUSP_3STATE;
// new net
rc = fnet_new(tstate->model, &net_idx);
if (rc) FAIL(rc);
// add iob port
rc = fnet_add_port(tstate->model, net_idx, iob_y, iob_x,
DEV_IOB, iob_type_idx, IOB_IN_O);
if (rc) FAIL(rc);
if ((rc = diff_printf(tstate))) FAIL(rc);
fnet_delete(tstate->model, net_idx);
fdev_delete(tstate->model, iob_y, iob_x, DEV_IOB, iob_type_idx);
// different IO standards
// The left (3) and right (1) banks have higher voltage ranges
// than the top (0) and bottom (2) banks, so we test this on
// the left side (ug381 page 13).
// todo: IO_SSTL2_I is not implemented right
{ const char* io_std[] = { IO_LVCMOS33, IO_LVCMOS25, IO_LVCMOS18,
IO_LVCMOS18_JEDEC, IO_LVCMOS15, IO_LVCMOS15_JEDEC,
IO_LVCMOS12, IO_LVCMOS12_JEDEC, IO_LVTTL, IO_SSTL2_I, 0 };
i = 0;
while (io_std[i]) {
// input
rc = fpga_find_iob(tstate->model, "P22", &iob_y, &iob_x, &iob_type_idx);
if (rc) FAIL(rc);
rc = fdev_iob_input(tstate->model, iob_y, iob_x, iob_type_idx, io_std[i]);
if (rc) FAIL(rc);
if ((rc = diff_printf(tstate))) FAIL(rc);
fdev_delete(tstate->model, iob_y, iob_x, DEV_IOB, iob_type_idx);
i++;
}
i = 0;
while (io_std[i]) {
// output
rc = fpga_find_iob(tstate->model, "P22", &iob_y, &iob_x, &iob_type_idx);
if (rc) FAIL(rc);
rc = fdev_iob_output(tstate->model, iob_y, iob_x, iob_type_idx, io_std[i]);
if (rc) FAIL(rc);
if (!strcmp(io_std[i], IO_SSTL2_I)) {
rc = diff_printf(tstate); if (rc) FAIL(rc);
} else {
dev = fdev_p(tstate->model, iob_y, iob_x, DEV_IOB, iob_type_idx);
if (!dev) FAIL(EINVAL);
for (j = 0; j < sizeof(drive_strengths)/sizeof(*drive_strengths); j++) {
if ((!strcmp(io_std[i], IO_LVCMOS15)
|| !strcmp(io_std[i], IO_LVCMOS15_JEDEC))
&& drive_strengths[j] == 24)
continue;
if ((!strcmp(io_std[i], IO_LVCMOS12)
|| !strcmp(io_std[i], IO_LVCMOS12_JEDEC))
&& (drive_strengths[j] == 16 || drive_strengths[j] == 24))
continue;
dev->u.iob.drive_strength = drive_strengths[j];
rc = diff_printf(tstate); if (rc) FAIL(rc);
}
}
fdev_delete(tstate->model, iob_y, iob_x, DEV_IOB, iob_type_idx);
i++;
}}
// enum all iobs
{
const char* name;
for (i = 0; (name = fpga_enum_iob(tstate->model, i, &iob_y,
&iob_x, &iob_type_idx)); i++) {
if (tstate->dry_run)
printf("IOB %s y%i x%i i%i\n", name,
iob_y, iob_x, iob_type_idx);
rc = fdev_iob_IMUX(tstate->model, iob_y, iob_x,
iob_type_idx, IMUX_I);
if (rc) FAIL(rc);
if ((rc = diff_printf(tstate))) FAIL(rc);
fdev_delete(tstate->model, iob_y, iob_x,
DEV_IOB, iob_type_idx);
}
}
return 0;
fail:
return rc;
}
static int test_logic(struct test_state* tstate, int y, int x, int type_idx,
const struct fpgadev_logic* logic_cfg)
{
struct fpga_device* dev;
net_idx_t pinw_nets[MAX_NUM_PINW];
int i, lut, latch_logic, rc;
if (tstate->dry_run) {
for (lut = LUT_A; lut <= LUT_D; lut++) {
if (!logic_cfg->a2d[lut].lut6
&& !logic_cfg->a2d[lut].lut5)
continue;
printf("O %c6_lut '%s' %c5_lut '%s'\n",
'A'+lut, logic_cfg->a2d[lut].lut6
? logic_cfg->a2d[lut].lut6 : "-",
'A'+lut, logic_cfg->a2d[lut].lut5
? logic_cfg->a2d[lut].lut5 : "-");
}
}
rc = fdev_logic_setconf(tstate->model, y, x, type_idx, logic_cfg);
if (rc) FAIL(rc);
if (tstate->dry_run) {
fdev_print_required_pins(tstate->model, y, x,
DEV_LOGIC, type_idx);
}
latch_logic = 0;
for (lut = LUT_A; lut <= LUT_D; lut++) {
if (logic_cfg->a2d[lut].ff == FF_AND2L
|| logic_cfg->a2d[lut].ff == FF_OR2L) {
latch_logic = 1;
break;
}
}
// add one stub net per required pin
dev = fdev_p(tstate->model, y, x, DEV_LOGIC, type_idx);
if (!dev) FAIL(EINVAL);
for (i = 0; i < dev->pinw_req_total; i++) {
// i < dev->pinw_req_in -> input
rc = fnet_new(tstate->model, &pinw_nets[i]);
if (rc) FAIL(rc);
rc = fnet_add_port(tstate->model, pinw_nets[i], y, x,
DEV_LOGIC, type_idx, dev->pinw_req_for_cfg[i]);
if (rc) FAIL(rc);
if (dev->pinw_req_for_cfg[i] == LI_CIN) {
int connpt_dests_o, num_dests, cout_y, cout_x;
str16_t cout_str;
swidx_t cout_sw;
if ((fpga_connpt_find(tstate->model, y, x,
dev->pinw[LI_CIN], &connpt_dests_o,
&num_dests) == NO_CONN)
|| num_dests != 1) {
HERE();
} else {
fpga_conn_dest(tstate->model, y, x,
connpt_dests_o, &cout_y, &cout_x, &cout_str);
cout_sw = fpga_switch_first(tstate->model,
cout_y, cout_x, cout_str, SW_TO);
if (cout_sw == NO_SWITCH) HERE();
else {
rc = fnet_add_sw(tstate->model,
pinw_nets[i], cout_y, cout_x,
&cout_sw, /*num_sw*/ 1);
if (rc) FAIL(rc);
}
}
}
if ((dev->pinw_req_for_cfg[i] == LI_A6
&& dev->u.logic.a2d[LUT_A].lut5
&& *dev->u.logic.a2d[LUT_A].lut5)
|| (dev->pinw_req_for_cfg[i] == LI_B6
&& dev->u.logic.a2d[LUT_B].lut5
&& *dev->u.logic.a2d[LUT_B].lut5)
|| (dev->pinw_req_for_cfg[i] == LI_C6
&& dev->u.logic.a2d[LUT_C].lut5
&& *dev->u.logic.a2d[LUT_C].lut5)
|| (dev->pinw_req_for_cfg[i] == LI_D6
&& dev->u.logic.a2d[LUT_D].lut5
&& *dev->u.logic.a2d[LUT_D].lut5)
|| (latch_logic
&& (dev->pinw_req_for_cfg[i] == LI_CLK
|| dev->pinw_req_for_cfg[i] == LI_CE))) {
rc = fnet_vcc_gnd(tstate->model, pinw_nets[i],
/*is_vcc*/ 1);
if (rc) FAIL(rc);
}
}
if ((rc = diff_printf(tstate))) FAIL(rc);
for (i = 0; i < dev->pinw_req_total; i++)
fnet_delete(tstate->model, pinw_nets[i]);
fdev_delete(tstate->model, y, x, DEV_LOGIC, type_idx);
return 0;
fail:
return rc;
}
static int test_logic_enum_precyinit(struct test_state* tstate, int y, int x,
int type_idx, const struct fpgadev_logic* logic_cfg)
{
struct fpgadev_logic local_cfg = *logic_cfg;
int rc;
rc = test_logic(tstate, y, x, type_idx, &local_cfg);
if (rc) FAIL(rc);
local_cfg.precyinit = PRECYINIT_0;
rc = test_logic(tstate, y, x, type_idx, &local_cfg);
if (rc) FAIL(rc);
local_cfg.precyinit = PRECYINIT_1;
rc = test_logic(tstate, y, x, type_idx, &local_cfg);
if (rc) FAIL(rc);
local_cfg.precyinit = PRECYINIT_AX;
rc = test_logic(tstate, y, x, type_idx, &local_cfg);
if (rc) FAIL(rc);
return 0;
fail:
return rc;
}
static int test_logic_enum_srinit_clk_sync_ce_sr(struct test_state* tstate, int y,
int x, int type_idx, const struct fpgadev_logic* logic_cfg)
{
struct fpgadev_logic local_cfg = *logic_cfg;
int lut, rc;
for (lut = LUT_A; lut <= LUT_D; lut++) {
if (!local_cfg.a2d[lut].ff_mux
&& !local_cfg.a2d[lut].out_mux)
continue;
if (local_cfg.a2d[lut].ff_mux)
local_cfg.a2d[lut].ff_srinit = FF_SRINIT0;
if (local_cfg.a2d[lut].out_mux == MUX_5Q)
local_cfg.a2d[lut].ff5_srinit = FF_SRINIT0;
local_cfg.clk_inv = CLKINV_CLK;
local_cfg.sync_attr = SYNCATTR_ASYNC;
local_cfg.ce_used = 0;
local_cfg.sr_used = 0;
rc = test_logic(tstate, y, x, type_idx, &local_cfg);
if (rc) FAIL(rc);
if (local_cfg.a2d[lut].ff_mux) {
local_cfg.a2d[lut].ff_srinit = FF_SRINIT1;
rc = test_logic(tstate, y, x, type_idx, &local_cfg);
if (rc) FAIL(rc);
local_cfg.a2d[lut].ff_srinit = FF_SRINIT0;
}
if (local_cfg.a2d[lut].out_mux == MUX_5Q) {
local_cfg.a2d[lut].ff5_srinit = FF_SRINIT1;
rc = test_logic(tstate, y, x, type_idx, &local_cfg);
if (rc) FAIL(rc);
local_cfg.a2d[lut].ff5_srinit = FF_SRINIT0;
}
local_cfg.clk_inv = CLKINV_B;
rc = test_logic(tstate, y, x, type_idx, &local_cfg);
if (rc) FAIL(rc);
local_cfg.clk_inv = CLKINV_CLK;
local_cfg.sync_attr = SYNCATTR_SYNC;
rc = test_logic(tstate, y, x, type_idx, &local_cfg);
if (rc) FAIL(rc);
local_cfg.sync_attr = SYNCATTR_ASYNC;
local_cfg.ce_used = 1;
rc = test_logic(tstate, y, x, type_idx, &local_cfg);
if (rc) FAIL(rc);
local_cfg.ce_used = 0;
local_cfg.sr_used = 1;
rc = test_logic(tstate, y, x, type_idx, &local_cfg);
if (rc) FAIL(rc);
local_cfg.sr_used = 0;
}
return 0;
fail:
return rc;
}
static int test_lut_encoding(struct test_state* tstate)
{
int idx_enum[] = { DEV_LOG_M_OR_L, DEV_LOG_X };
// The center column (x==22 on a xc6slx9) is a regular XL column
// for the lut encoding, so it doesn't need separate testing.
int x_enum[] = { /*xm*/ 13, /*xl*/ 39 };
int y, x_i, i, j, lut_str_len, rc;
struct fpgadev_logic logic_cfg;
int type_i, lut;
char lut6_str[128], lut5_str[128];
tstate->diff_to_null = 1;
y = 68;
for (x_i = 0; x_i < sizeof(x_enum)/sizeof(*x_enum); x_i++) {
for (type_i = 0; type_i < sizeof(idx_enum)/sizeof(*idx_enum); type_i++) {
for (lut = LUT_A; lut <= LUT_D; lut++) {
memset(&logic_cfg, 0, sizeof(logic_cfg));
logic_cfg.a2d[lut].lut6 = lut6_str;
logic_cfg.a2d[lut].out_used = 1;
// lut6 only
sprintf(lut6_str, "0");
rc = test_logic(tstate, y, x_enum[x_i], idx_enum[type_i],
&logic_cfg);
if (rc) FAIL(rc);
sprintf(lut6_str, "1");
rc = test_logic(tstate, y, x_enum[x_i], idx_enum[type_i],
&logic_cfg);
if (rc) FAIL(rc);
for (i = '1'; i <= '6'; i++) {
sprintf(lut6_str, "A%c", i);
rc = test_logic(tstate, y, x_enum[x_i], idx_enum[type_i],
&logic_cfg);
if (rc) FAIL(rc);
}
for (i = 0; i < 64; i++) {
lut_str_len = 0;
for (j = 0; j < 6; j++) {
if (lut_str_len)
lut6_str[lut_str_len++] = '*';
if (!(i & (1<diff_to_null = 1;
// For cin/cout testing, pick a y that is not at the bottom.
y = 67;
for (x_i = 0; x_i < sizeof(x_enum)/sizeof(*x_enum); x_i++) {
for (type_i = 0; type_i < sizeof(idx_enum)/sizeof(*idx_enum); type_i++) {
for (lut = LUT_A; lut <= LUT_D; lut++) {
// lut6, direct-out
memset(&logic_cfg, 0, sizeof(logic_cfg));
logic_cfg.a2d[lut].lut6 = "A1";
logic_cfg.a2d[lut].out_used = 1;
rc = test_logic(tstate, y, x_enum[x_i],
idx_enum[type_i], &logic_cfg);
if (rc) FAIL(rc);
if (idx_enum[type_i] == DEV_LOG_M_OR_L) {
// lut6, mux-out
// O6 over mux-out seems not supported
// on an X device.
memset(&logic_cfg, 0, sizeof(logic_cfg));
logic_cfg.a2d[lut].lut6 = "A1";
logic_cfg.a2d[lut].out_mux = MUX_O6;
rc = test_logic(tstate, y, x_enum[x_i],
idx_enum[type_i], &logic_cfg);
if (rc) FAIL(rc);
// . out_mux=xor
logic_cfg.a2d[lut].out_mux = MUX_XOR;
if (lut == LUT_A) {
// . precyinit=0/1/ax
rc = test_logic_enum_precyinit(tstate,
y, x_enum[x_i], idx_enum[type_i], &logic_cfg);
if (rc) FAIL(rc);
} else {
rc = test_logic(tstate, y, x_enum[x_i],
idx_enum[type_i], &logic_cfg);
if (rc) FAIL(rc);
}
// . out_mux=cy cy0=x
logic_cfg.a2d[lut].out_mux = MUX_CY;
logic_cfg.a2d[lut].cy0 = CY0_X;
if (lut == LUT_A) {
// . precyinit=0/1/ax
// tbd: the X enum will have X drive
// both cy0 and precyinit at the same time.
rc = test_logic_enum_precyinit(tstate,
y, x_enum[x_i], idx_enum[type_i], &logic_cfg);
if (rc) FAIL(rc);
} else {
rc = test_logic(tstate, y, x_enum[x_i],
idx_enum[type_i], &logic_cfg);
if (rc) FAIL(rc);
}
}
// lut6, ff-out
memset(&logic_cfg, 0, sizeof(logic_cfg));
logic_cfg.a2d[lut].lut6 = "A1";
logic_cfg.a2d[lut].ff = FF_FF;
logic_cfg.a2d[lut].ff_mux = MUX_O6;
logic_cfg.a2d[lut].ff_srinit = FF_SRINIT0;
logic_cfg.clk_inv = CLKINV_CLK;
logic_cfg.sync_attr = SYNCATTR_ASYNC;
rc = test_logic_enum_srinit_clk_sync_ce_sr(tstate, y,
x_enum[x_i], idx_enum[type_i], &logic_cfg);
if (rc) FAIL(rc);
if (idx_enum[type_i] == DEV_LOG_M_OR_L) {
// . ff_mux=xor
logic_cfg.a2d[lut].ff_mux = MUX_XOR;
if (lut == LUT_A) {
// . precyinit=0/1/ax
rc = test_logic_enum_precyinit(tstate,
y, x_enum[x_i], idx_enum[type_i], &logic_cfg);
if (rc) FAIL(rc);
} else {
rc = test_logic(tstate, y, x_enum[x_i],
idx_enum[type_i], &logic_cfg);
if (rc) FAIL(rc);
}
// . ff_mux=cy cy0=x
logic_cfg.a2d[lut].ff_mux = MUX_CY;
logic_cfg.a2d[lut].cy0 = CY0_X;
if (lut == LUT_A) {
// . precyinit=0/1/ax
rc = test_logic_enum_precyinit(tstate,
y, x_enum[x_i], idx_enum[type_i], &logic_cfg);
if (rc) FAIL(rc);
} else {
rc = test_logic(tstate, y, x_enum[x_i],
idx_enum[type_i], &logic_cfg);
if (rc) FAIL(rc);
}
}
// lut6, latch-out
memset(&logic_cfg, 0, sizeof(logic_cfg));
logic_cfg.a2d[lut].lut6 = "A1";
logic_cfg.a2d[lut].ff = FF_LATCH;
logic_cfg.a2d[lut].ff_mux = MUX_O6;
logic_cfg.a2d[lut].ff_srinit = FF_SRINIT0;
logic_cfg.clk_inv = CLKINV_CLK;
logic_cfg.sync_attr = SYNCATTR_ASYNC;
rc = test_logic(tstate, y, x_enum[x_i],
idx_enum[type_i], &logic_cfg);
if (rc) FAIL(rc);
//
// AND and OR latches are physically a normal
// latch, but with additional configuration
// constraints:
//
// 1. ce and clk must be driven high/vcc
// 2. the clk must be inverted before the latch (clk_b)
// 3. srinit must be 0 for AND, 1 for OR
//
// lut6, and-latch
memset(&logic_cfg, 0, sizeof(logic_cfg));
logic_cfg.a2d[lut].lut6 = "A1";
logic_cfg.a2d[lut].ff = FF_AND2L;
logic_cfg.a2d[lut].ff_mux = MUX_O6;
// AND2L requires SRINIT=0
logic_cfg.a2d[lut].ff_srinit = FF_SRINIT0;
logic_cfg.clk_inv = CLKINV_B;
logic_cfg.sync_attr = SYNCATTR_ASYNC;
logic_cfg.ce_used = 1;
logic_cfg.sr_used = 1;
rc = test_logic(tstate, y, x_enum[x_i],
idx_enum[type_i], &logic_cfg);
if (rc) FAIL(rc);
// lut6, or-latch
memset(&logic_cfg, 0, sizeof(logic_cfg));
logic_cfg.a2d[lut].lut6 = "A1";
logic_cfg.a2d[lut].ff = FF_OR2L;
logic_cfg.a2d[lut].ff_mux = MUX_O6;
// OR2L requires SRINIT=1
logic_cfg.a2d[lut].ff_srinit = FF_SRINIT1;
logic_cfg.clk_inv = CLKINV_B;
logic_cfg.sync_attr = SYNCATTR_ASYNC;
logic_cfg.ce_used = 1;
logic_cfg.sr_used = 1;
rc = test_logic(tstate, y, x_enum[x_i],
idx_enum[type_i], &logic_cfg);
if (rc) FAIL(rc);
// x, ff-out
memset(&logic_cfg, 0, sizeof(logic_cfg));
logic_cfg.a2d[lut].ff = FF_FF;
logic_cfg.a2d[lut].ff_mux = MUX_X;
logic_cfg.a2d[lut].ff_srinit = FF_SRINIT0;
logic_cfg.clk_inv = CLKINV_CLK;
logic_cfg.sync_attr = SYNCATTR_ASYNC;
rc = test_logic(tstate, y, x_enum[x_i],
idx_enum[type_i], &logic_cfg);
if (rc) FAIL(rc);
// . o6-direct
logic_cfg.a2d[lut].lut6 = "A1";
logic_cfg.a2d[lut].out_used = 1;
rc = test_logic(tstate, y, x_enum[x_i],
idx_enum[type_i], &logic_cfg);
if (rc) FAIL(rc);
logic_cfg.a2d[lut].out_used = 0;
if (idx_enum[type_i] == DEV_LOG_M_OR_L) {
// . o6-outmux
logic_cfg.a2d[lut].out_mux = MUX_O6;
rc = test_logic(tstate, y, x_enum[x_i],
idx_enum[type_i], &logic_cfg);
if (rc) FAIL(rc);
logic_cfg.a2d[lut].out_mux = 0;
}
//
// lut5/6 pairs
//
// lut6 direct-out, lut5 mux-out
memset(&logic_cfg, 0, sizeof(logic_cfg));
logic_cfg.a2d[lut].lut6 = "(A6+~A6)*A1";
logic_cfg.a2d[lut].out_used = 1;
logic_cfg.a2d[lut].lut5 = "A1*A2";
logic_cfg.a2d[lut].out_mux = MUX_O5;
rc = test_logic(tstate, y, x_enum[x_i],
idx_enum[type_i], &logic_cfg);
if (rc) FAIL(rc);
if (idx_enum[type_i] == DEV_LOG_M_OR_L) {
// . out_mux=cy cy0=o5
logic_cfg.a2d[lut].out_mux = MUX_CY;
logic_cfg.a2d[lut].cy0 = CY0_O5;
if (lut == LUT_A) {
// . precyinit=0/1/ax
rc = test_logic_enum_precyinit(tstate,
y, x_enum[x_i], idx_enum[type_i], &logic_cfg);
if (rc) FAIL(rc);
} else {
rc = test_logic(tstate, y, x_enum[x_i],
idx_enum[type_i], &logic_cfg);
if (rc) FAIL(rc);
}
}
// lut6 direct-out, lut5 a5q-out, ff5_srinit=0
logic_cfg.a2d[lut].cy0 = 0;
logic_cfg.a2d[lut].out_mux = MUX_5Q;
logic_cfg.a2d[lut].ff5_srinit = FF_SRINIT0;
logic_cfg.clk_inv = CLKINV_CLK;
logic_cfg.sync_attr = SYNCATTR_ASYNC;
// We go through the global ff configs again for
// the second ff.
rc = test_logic_enum_srinit_clk_sync_ce_sr(tstate, y,
x_enum[x_i], idx_enum[type_i], &logic_cfg);
if (rc) FAIL(rc);
if (idx_enum[type_i] == DEV_LOG_M_OR_L) {
// . change from out_mux/5q to ff_mux
logic_cfg.a2d[lut].out_mux = 0;
logic_cfg.a2d[lut].ff5_srinit = 0;
logic_cfg.a2d[lut].ff = FF_FF;
logic_cfg.a2d[lut].ff_mux = MUX_O5;
logic_cfg.a2d[lut].ff_srinit = FF_SRINIT0;
rc = test_logic(tstate, y, x_enum[x_i],
idx_enum[type_i], &logic_cfg);
if (rc) FAIL(rc);
// . add out_mux=cy cy0=x
logic_cfg.a2d[lut].out_mux = MUX_CY;
logic_cfg.a2d[lut].cy0 = CY0_X;
rc = test_logic(tstate, y, x_enum[x_i],
idx_enum[type_i], &logic_cfg);
if (rc) FAIL(rc);
logic_cfg.a2d[lut].out_mux = 0;
logic_cfg.a2d[lut].cy0 = 0;
// . ff_mux=cy cy0=o5
logic_cfg.a2d[lut].ff_mux = MUX_CY;
logic_cfg.a2d[lut].cy0 = CY0_O5;
if (lut == LUT_A) {
// . precyinit=0/1/ax
rc = test_logic_enum_precyinit(tstate,
y, x_enum[x_i], idx_enum[type_i], &logic_cfg);
if (rc) FAIL(rc);
} else {
rc = test_logic(tstate, y, x_enum[x_i],
idx_enum[type_i], &logic_cfg);
if (rc) FAIL(rc);
}
}
}
if (idx_enum[type_i] == DEV_LOG_X) {
// minimum-config X device
memset(&logic_cfg, 0, sizeof(logic_cfg));
logic_cfg.a2d[LUT_A].lut6 = "(A6+~A6)*A1";
logic_cfg.a2d[LUT_A].lut5 = "A2";
logic_cfg.a2d[LUT_A].out_mux = MUX_5Q;
logic_cfg.a2d[LUT_A].ff5_srinit = FF_SRINIT0;
logic_cfg.a2d[LUT_A].ff = FF_FF;
logic_cfg.a2d[LUT_A].ff_mux = MUX_O6;
logic_cfg.a2d[LUT_A].ff_srinit = FF_SRINIT0;
logic_cfg.a2d[LUT_B].lut6 = "(A6+~A6)*A4";
logic_cfg.a2d[LUT_B].lut5 = "A3";
logic_cfg.a2d[LUT_B].out_mux = MUX_5Q;
logic_cfg.a2d[LUT_B].ff5_srinit = FF_SRINIT0;
logic_cfg.a2d[LUT_B].ff = FF_FF;
logic_cfg.a2d[LUT_B].ff_mux = MUX_O6;
logic_cfg.a2d[LUT_B].ff_srinit = FF_SRINIT0;
logic_cfg.a2d[LUT_C].lut6 = "(A6+~A6)*(A2+A5)";
logic_cfg.a2d[LUT_C].lut5 = "A3+A4";
logic_cfg.a2d[LUT_C].out_mux = MUX_5Q;
logic_cfg.a2d[LUT_C].ff5_srinit = FF_SRINIT0;
logic_cfg.a2d[LUT_C].ff = FF_FF;
logic_cfg.a2d[LUT_C].ff_mux = MUX_O6;
logic_cfg.a2d[LUT_C].ff_srinit = FF_SRINIT0;
logic_cfg.a2d[LUT_D].lut6 = "(A6+~A6)*A3";
logic_cfg.a2d[LUT_D].lut5 = "A3+A5";
logic_cfg.a2d[LUT_D].out_mux = MUX_5Q;
logic_cfg.a2d[LUT_D].ff5_srinit = FF_SRINIT0;
logic_cfg.a2d[LUT_D].ff = FF_FF;
logic_cfg.a2d[LUT_D].ff_mux = MUX_O6;
logic_cfg.a2d[LUT_D].ff_srinit = FF_SRINIT0;
logic_cfg.clk_inv = CLKINV_CLK;
logic_cfg.sync_attr = SYNCATTR_ASYNC;
rc = test_logic(tstate, y, x_enum[x_i],
idx_enum[type_i], &logic_cfg);
if (rc) FAIL(rc);
continue;
}
// cout
memset(&logic_cfg, 0, sizeof(logic_cfg));
logic_cfg.a2d[LUT_A].lut6 = "(A6+~A6)*(~A5)";
logic_cfg.a2d[LUT_A].lut5 = "1";
logic_cfg.a2d[LUT_A].cy0 = CY0_O5;
logic_cfg.a2d[LUT_A].ff = FF_FF;
logic_cfg.a2d[LUT_A].ff_mux = MUX_XOR;
logic_cfg.a2d[LUT_A].ff_srinit = FF_SRINIT0;
logic_cfg.a2d[LUT_B].lut6 = "(A6+~A6)*(A5)";
logic_cfg.a2d[LUT_B].lut5 = "1";
logic_cfg.a2d[LUT_B].cy0 = CY0_O5;
logic_cfg.a2d[LUT_B].ff = FF_FF;
logic_cfg.a2d[LUT_B].ff_mux = MUX_XOR;
logic_cfg.a2d[LUT_B].ff_srinit = FF_SRINIT0;
logic_cfg.a2d[LUT_C].lut6 = "(A6+~A6)*(A5)";
logic_cfg.a2d[LUT_C].lut5 = "1";
logic_cfg.a2d[LUT_C].cy0 = CY0_O5;
logic_cfg.a2d[LUT_C].ff = FF_FF;
logic_cfg.a2d[LUT_C].ff_mux = MUX_XOR;
logic_cfg.a2d[LUT_C].ff_srinit = FF_SRINIT0;
logic_cfg.a2d[LUT_D].lut6 = "(A6+~A6)*(A5)";
logic_cfg.a2d[LUT_D].lut5 = "1";
logic_cfg.a2d[LUT_D].cy0 = CY0_O5;
logic_cfg.a2d[LUT_D].ff = FF_FF;
logic_cfg.a2d[LUT_D].ff_mux = MUX_XOR;
logic_cfg.a2d[LUT_D].ff_srinit = FF_SRINIT0;
logic_cfg.clk_inv = CLKINV_CLK;
logic_cfg.sync_attr = SYNCATTR_ASYNC;
logic_cfg.precyinit = PRECYINIT_0;
logic_cfg.cout_used = 1;
rc = test_logic(tstate, y, x_enum[x_i],
idx_enum[type_i], &logic_cfg);
if (rc) FAIL(rc);
// f8 out-mux
memset(&logic_cfg, 0, sizeof(logic_cfg));
logic_cfg.a2d[LUT_A].lut6 = "~A5";
logic_cfg.a2d[LUT_B].lut6 = "(A5)";
logic_cfg.a2d[LUT_C].lut6 = "A5";
logic_cfg.a2d[LUT_D].lut6 = "((A5))";
logic_cfg.a2d[LUT_B].out_mux = MUX_F8;
rc = test_logic(tstate, y, x_enum[x_i],
idx_enum[type_i], &logic_cfg);
if (rc) FAIL(rc);
// . over ff
logic_cfg.a2d[LUT_B].out_mux = 0;
logic_cfg.a2d[LUT_B].ff_mux = MUX_F8;
logic_cfg.a2d[LUT_B].ff = FF_FF;
logic_cfg.a2d[LUT_B].ff_srinit = FF_SRINIT0;
logic_cfg.clk_inv = CLKINV_CLK;
logic_cfg.sync_attr = SYNCATTR_ASYNC;
rc = test_logic(tstate, y, x_enum[x_i],
idx_enum[type_i], &logic_cfg);
if (rc) FAIL(rc);
// f7amux
memset(&logic_cfg, 0, sizeof(logic_cfg));
logic_cfg.a2d[LUT_A].lut6 = "~A5";
logic_cfg.a2d[LUT_B].lut6 = "(A5)";
logic_cfg.a2d[LUT_A].out_mux = MUX_F7;
rc = test_logic(tstate, y, x_enum[x_i],
idx_enum[type_i], &logic_cfg);
if (rc) FAIL(rc);
// . over ff
logic_cfg.a2d[LUT_A].out_mux = 0;
logic_cfg.a2d[LUT_A].ff_mux = MUX_F7;
logic_cfg.a2d[LUT_A].ff = FF_FF;
logic_cfg.a2d[LUT_A].ff_srinit = FF_SRINIT0;
logic_cfg.clk_inv = CLKINV_CLK;
logic_cfg.sync_attr = SYNCATTR_ASYNC;
rc = test_logic(tstate, y, x_enum[x_i],
idx_enum[type_i], &logic_cfg);
if (rc) FAIL(rc);
// f7bmux
memset(&logic_cfg, 0, sizeof(logic_cfg));
logic_cfg.a2d[LUT_C].lut6 = "~A5";
logic_cfg.a2d[LUT_D].lut6 = "(A5)";
logic_cfg.a2d[LUT_C].out_mux = MUX_F7;
rc = test_logic(tstate, y, x_enum[x_i],
idx_enum[type_i], &logic_cfg);
if (rc) FAIL(rc);
// . over ff
logic_cfg.a2d[LUT_C].out_mux = 0;
logic_cfg.a2d[LUT_C].ff_mux = MUX_F7;
logic_cfg.a2d[LUT_C].ff = FF_FF;
logic_cfg.a2d[LUT_C].ff_srinit = FF_SRINIT0;
logic_cfg.clk_inv = CLKINV_CLK;
logic_cfg.sync_attr = SYNCATTR_ASYNC;
rc = test_logic(tstate, y, x_enum[x_i],
idx_enum[type_i], &logic_cfg);
if (rc) FAIL(rc);
}
}
return 0;
fail:
return rc;
}
static int test_bufg_config(struct test_state* tstate)
{
int dev_y, dev_x, dev_tidx, i, rc;
tstate->diff_to_null = 1;
// todo: not implemented
return 0;
i = 0;
while (1) {
rc = fdev_enum(tstate->model, DEV_BUFGMUX, i++,
&dev_y, &dev_x, &dev_tidx);
if (rc) FAIL(EINVAL);
if (dev_y == -1) break;
rc = fdev_bufgmux(tstate->model, dev_y, dev_x, dev_tidx,
BUFG_CLK_ASYNC, BUFG_DISATTR_LOW, BUFG_SINV_Y);
if (rc) FAIL(rc);
// stub nets for required pins? s-pin?
if ((rc = diff_printf(tstate))) FAIL(rc);
fdev_delete(tstate->model, dev_y, dev_x, DEV_BUFGMUX, dev_tidx);
}
return 0;
fail:
return rc;
}
static int test_bufio_config(struct test_state* tstate)
{
// todo: not implemented
return 0;
}
static int test_pll_config(struct test_state* tstate)
{
// todo: not implemented
return 0;
}
static int test_dcm_config(struct test_state* tstate)
{
// todo: not implemented
return 0;
}
static int test_bscan_config(struct test_state* tstate)
{
// todo: not implemented
return 0;
}
static int test_clock_routing(struct test_state* tstate)
{
int rc, i, iob_clk_y, iob_clk_x, iob_clk_type_idx;
int logic_y, logic_x, logic_type_idx;
int y;
net_idx_t clock_net;
tstate->diff_to_null = 1;
//
// first round over all gclk pins to the same logic dev
//
for (i = 0; i < tstate->model->pkg->num_gclk_pins; i++) {
if (!tstate->model->pkg->gclk_pin[i])
continue;
fpga_find_iob(tstate->model, tstate->model->pkg->gclk_pin[i],
&iob_clk_y, &iob_clk_x, &iob_clk_type_idx);
RC_CHECK(tstate->model);
printf("\nO test %i: gclk pin %s (y%i x%i IOB %i)\n",
tstate->next_diff_counter, tstate->model->pkg->gclk_pin[i],
iob_clk_y, iob_clk_x, iob_clk_type_idx);
fdev_iob_input(tstate->model, iob_clk_y, iob_clk_x,
iob_clk_type_idx, IO_LVCMOS33);
logic_y = 65; // down from hclk at 62
logic_x = 13;
logic_type_idx = DEV_LOG_M_OR_L;
fdev_logic_a2d_lut(tstate->model, logic_y, logic_x,
logic_type_idx, LUT_A, 6, "A1", ZTERM);
fdev_set_required_pins(tstate->model, logic_y, logic_x,
DEV_LOGIC, logic_type_idx);
if (tstate->dry_run)
fdev_print_required_pins(tstate->model,
logic_y, logic_x, DEV_LOGIC, logic_type_idx);
fnet_new(tstate->model, &clock_net);
RC_CHECK(tstate->model);
fnet_add_port(tstate->model, clock_net, iob_clk_y,
iob_clk_x, DEV_IOB, iob_clk_type_idx, IOB_OUT_I);
fnet_add_port(tstate->model, clock_net, logic_y, logic_x,
DEV_LOGIC, logic_type_idx, LI_CLK);
fnet_route(tstate->model, clock_net);
if ((rc = diff_printf(tstate))) FAIL(rc);
fnet_delete(tstate->model, clock_net);
fdev_delete(tstate->model, logic_y, logic_x, DEV_LOGIC,
logic_type_idx);
fdev_delete(tstate->model, iob_clk_y, iob_clk_x, DEV_IOB,
iob_clk_type_idx);
}
//
// Second round over left and right gclk pins only (that's enough
// to reach all 16 gclk wires in the center). Then going to the
// left and right side of all hclk rows top-down.
//
for (i = 0; i < tstate->model->pkg->num_gclk_pins; i++) {
if (!tstate->model->pkg->gclk_pin[i])
continue;
fpga_find_iob(tstate->model, tstate->model->pkg->gclk_pin[i],
&iob_clk_y, &iob_clk_x, &iob_clk_type_idx);
RC_CHECK(tstate->model);
// skip top and bottom iobs
if (iob_clk_x != LEFT_OUTER_COL
&& iob_clk_x != tstate->model->x_width-RIGHT_OUTER_O)
continue;
fdev_iob_input(tstate->model, iob_clk_y, iob_clk_x,
iob_clk_type_idx, IO_LVCMOS33);
for (y = TOP_FIRST_REGULAR; y < tstate->model->y_height - BOT_LAST_REGULAR_O; y++) {
if (!is_aty(Y_ROW_HORIZ_AXSYMM, tstate->model, y))
continue;
logic_type_idx = DEV_LOG_M_OR_L;
logic_y = y-3; // up from hclk
for (logic_x = 13; logic_x <= 26; logic_x += 13) {
fdev_logic_a2d_lut(tstate->model, logic_y, logic_x,
logic_type_idx, LUT_A, 6, "A1", ZTERM);
fdev_set_required_pins(tstate->model, logic_y, logic_x,
DEV_LOGIC, logic_type_idx);
if (tstate->dry_run)
fdev_print_required_pins(tstate->model,
logic_y, logic_x, DEV_LOGIC, logic_type_idx);
fnet_new(tstate->model, &clock_net);
RC_CHECK(tstate->model);
fnet_add_port(tstate->model, clock_net, iob_clk_y,
iob_clk_x, DEV_IOB, iob_clk_type_idx, IOB_OUT_I);
fnet_add_port(tstate->model, clock_net, logic_y, logic_x,
DEV_LOGIC, logic_type_idx, LI_CLK);
fnet_route(tstate->model, clock_net);
if ((rc = diff_printf(tstate))) FAIL(rc);
fnet_delete(tstate->model, clock_net);
fdev_delete(tstate->model, logic_y, logic_x, DEV_LOGIC,
logic_type_idx);
}
}
fdev_delete(tstate->model, iob_clk_y, iob_clk_x, DEV_IOB,
iob_clk_type_idx);
}
return 0;
fail:
return rc;
}
#define DEFAULT_DIFF_EXEC "./autotest_diff.sh"
static void printf_help(const char* argv_0, const char** available_tests)
{
printf( "\n"
"fpgatools automatic test suite\n"
"\n"
"Usage: %s [--test=] [--skip=] [--count=]\n"
" %*s [--dry-run] [--diff=]\n"
"Default diff executable: " DEFAULT_DIFF_EXEC "\n"
"Output dir: " AUTOTEST_TMP_DIR "\n", argv_0, (int) strlen(argv_0), "");
if (available_tests) {
int i = 0;
printf("\n");
while (available_tests[i] && available_tests[i][0]) {
printf("%s %s\n", !i ? "Available tests:"
: " ", available_tests[i]);
i++;
}
}
printf("\n");
}
int main(int argc, char** argv)
{
struct fpga_model model;
struct test_state tstate;
char param[1024], cmdline_test[1024];
int i, param_skip, param_count, rc;
const char* available_tests[] =
{ "logic_cfg", "routing_sw", "io_sw", "iob_cfg",
"lut_encoding", "bufg_cfg", "bufio_cfg", "pll_cfg",
"dcm_cfg", "bscan_cfg", "clock_routing", 0 };
// flush after every line is better for the autotest
// output, tee, etc.
// for example: ./autotest 2>&1 | tee autotest.log
setvbuf(stdout, /*buf*/ 0, _IOLBF, /*size*/ 0);
if (argc < 2) {
printf_help(argv[0], available_tests);
return 0;
}
//
// command line
//
memset(&tstate, 0, sizeof(tstate));
tstate.cmdline_skip = -1;
tstate.cmdline_count = -1;
tstate.cmdline_diff_exec[0] = 0;
cmdline_test[0] = 0;
tstate.dry_run = -1;
tstate.diff_to_null = 0;
for (i = 1; i < argc; i++) {
memset(param, 0, sizeof(param));
if (sscanf(argv[i], "--test=%1023c", param) == 1) {
if (cmdline_test[0]) {
printf_help(argv[0], available_tests);
return EINVAL;
}
strcpy(cmdline_test, param);
continue;
}
memset(param, 0, sizeof(param));
if (sscanf(argv[i], "--diff=%1023c", param) == 1) {
if (tstate.cmdline_diff_exec[0]) {
printf_help(argv[0], available_tests);
return EINVAL;
}
strcpy(tstate.cmdline_diff_exec, param);
continue;
}
if (sscanf(argv[i], "--skip=%i", ¶m_skip) == 1) {
if (tstate.cmdline_skip != -1) {
printf_help(argv[0], available_tests);
return EINVAL;
}
tstate.cmdline_skip = param_skip;
continue;
}
if (sscanf(argv[i], "--count=%i", ¶m_count) == 1) {
if (tstate.cmdline_count != -1) {
printf_help(argv[0], available_tests);
return EINVAL;
}
tstate.cmdline_count = param_count;
continue;
}
if (!strcmp(argv[i], "--dry-run")) {
tstate.dry_run = 1;
continue;
}
printf_help(argv[0], available_tests);
return EINVAL;
}
if (!cmdline_test[0]) {
printf_help(argv[0], available_tests);
return EINVAL;
}
i = 0;
while (available_tests[i] && available_tests[i][0]) {
if (!strcmp(available_tests[i], cmdline_test))
break;
i++;
}
if (!available_tests[i] || !available_tests[i][0]) {
printf_help(argv[0], available_tests);
return EINVAL;
}
if (!tstate.cmdline_diff_exec[0])
strcpy(tstate.cmdline_diff_exec, DEFAULT_DIFF_EXEC);
if (tstate.cmdline_skip == -1)
tstate.cmdline_skip = 0;
if (tstate.dry_run == -1)
tstate.dry_run = 0;
//
// test
//
printf("\n");
printf("O fpgatools automatic test suite. Be welcome and be "
"our guest. namo namaha.\n");
printf("\n");
printf("O Test: %s\n", cmdline_test);
printf("O Diff: %s\n", tstate.cmdline_diff_exec);
printf("O Skip: %i\n", tstate.cmdline_skip);
printf("O Count: %i\n", tstate.cmdline_count);
printf("O Dry run: %i\n", tstate.dry_run);
printf("\n");
printf("O Time measured in seconds from 0.\n");
g_start_time = time(0);
TIMESTAMP();
printf("O Memory usage reported in megabytes.\n");
MEMUSAGE();
printf("O Building memory model...\n");
if ((rc = fpga_build_model(&model, XC6SLX9, TQG144)))
goto fail;
printf("O Done\n");
TIME_AND_MEM();
tstate.model = &model;
strcpy(tstate.tmp_dir, AUTOTEST_TMP_DIR);
mkdir(tstate.tmp_dir, S_IRWXU|S_IRWXG|S_IROTH|S_IXOTH);
rc = diff_start(&tstate, cmdline_test);
if (rc) FAIL(rc);
if (!strcmp(cmdline_test, "logic_cfg")) {
rc = test_logic_config(&tstate);
if (rc) FAIL(rc);
}
if (!strcmp(cmdline_test, "routing_sw")) {
rc = test_routing_switches(&tstate);
if (rc) FAIL(rc);
}
if (!strcmp(cmdline_test, "io_sw")) {
rc = test_iologic_switches(&tstate);
if (rc) FAIL(rc);
}
if (!strcmp(cmdline_test, "iob_cfg")) {
rc = test_iob_config(&tstate);
if (rc) FAIL(rc);
}
if (!strcmp(cmdline_test, "lut_encoding")) {
rc = test_lut_encoding(&tstate);
if (rc) FAIL(rc);
}
if (!strcmp(cmdline_test, "bufg_cfg")) {
rc = test_bufg_config(&tstate);
if (rc) FAIL(rc);
}
if (!strcmp(cmdline_test, "bufio_cfg")) {
rc = test_bufio_config(&tstate);
if (rc) FAIL(rc);
}
if (!strcmp(cmdline_test, "pll_cfg")) {
rc = test_pll_config(&tstate);
if (rc) FAIL(rc);
}
if (!strcmp(cmdline_test, "dcm_cfg")) {
rc = test_dcm_config(&tstate);
if (rc) FAIL(rc);
}
if (!strcmp(cmdline_test, "bscan_cfg")) {
rc = test_bscan_config(&tstate);
if (rc) FAIL(rc);
}
if (!strcmp(cmdline_test, "clock_routing")) {
rc = test_clock_routing(&tstate);
if (rc) FAIL(rc);
}
printf("\n");
printf("O Test completed.\n");
TIME_AND_MEM();
printf("\n");
return EXIT_SUCCESS;
fail:
return rc;
}
fpgatools-201212/autotest_diff.sh 0000775 0000000 0000000 00000000763 12065743015 0017011 0 ustar 00root root 0000000 0000000 #!/usr/bin/env bash
diff -U 0 $1 $2 > ${2%.*}.fp_diff
./fp2bit $2 ${2%.*}.f2b || exit $?
./bit2fp --no-fp-header ${2%.*}.f2b > ${2%.*}.b2f || exit $?
if [ "$1" == "/dev/null" ]
then
diff -U 0 /dev/null ${2%.*}.b2f > ${2%.*}.b2f_diff
else
diff -U 0 ${1%.*}.b2f ${2%.*}.b2f > ${2%.*}.b2f_diff
fi
echo "fp:" > ${2%.*}.diff
cat ${2%.*}.fp_diff | sed -e '/^--- /d;/^+++ /d;/^@@ /d' >> ${2%.*}.diff
echo "bit:" >> ${2%.*}.diff
cat ${2%.*}.b2f_diff | sed -e '/^--- /d;/^+++ /d;/^@@ /d' >> ${2%.*}.diff
fpgatools-201212/bit2fp.c 0000664 0000000 0000000 00000004424 12065743015 0015142 0 ustar 00root root 0000000 0000000 //
// Author: Wolfgang Spraul
//
// This is free and unencumbered software released into the public domain.
// For details see the UNLICENSE file at the root of the source tree.
//
#include "model.h"
#include "floorplan.h"
#include "bit.h"
int main(int argc, char** argv)
{
struct fpga_model model;
int bit_header, bit_regs, bit_crc, fp_header, pull_model, file_arg, flags;
int print_swbits, rc = -1;
struct fpga_config config;
// parameters
if (argc < 2) {
fprintf(stderr,
"\n"
"%s - bitstream to floorplan\n"
"Usage: %s [--bit-header] [--bit-regs] [--bit-crc] [--no-model]\n"
" %*s [--no-fp-header] [--printf-swbits] \n"
"\n", argv[0], argv[0], (int) strlen(argv[0]), "");
goto fail;
}
bit_header = 0;
bit_regs = 0;
bit_crc = 0;
pull_model = 1;
fp_header = 1;
file_arg = 1;
print_swbits = 0;
while (file_arg < argc
&& !strncmp(argv[file_arg], "--", 2)) {
if (!strcmp(argv[file_arg], "--bit-header"))
bit_header = 1;
else if (!strcmp(argv[file_arg], "--bit-regs"))
bit_regs = 1;
else if (!strcmp(argv[file_arg], "--bit-crc"))
bit_crc = 1;
else if (!strcmp(argv[file_arg], "--no-model"))
pull_model = 0;
else if (!strcmp(argv[file_arg], "--no-fp-header"))
fp_header = 0;
else if (!strcmp(argv[file_arg], "--printf-swbits"))
print_swbits = 1;
else break;
file_arg++;
}
// build model
if ((rc = fpga_build_model(&model, XC6SLX9, TQG144)))
FAIL(rc);
if (print_swbits) {
rc = printf_swbits(&model);
if (rc) FAIL(rc);
return 0;
}
// read binary configuration file
{
FILE* fbits = fopen(argv[file_arg], "r");
if (!fbits) {
fprintf(stderr, "Error opening %s.\n", argv[file_arg]);
goto fail;
}
rc = read_bitfile(&config, fbits);
fclose(fbits);
if (rc) FAIL(rc);
}
// fill model from binary configuration
if (pull_model)
if ((rc = extract_model(&model, &config.bits))) FAIL(rc);
// dump model
flags = FP_DEFAULT;
if (!fp_header) flags |= FP_NO_HEADER;
if ((rc = write_floorplan(stdout, &model, flags))) FAIL(rc);
// dump what doesn't fit into the model
flags = DUMP_BITS;
if (bit_header) flags |= DUMP_HEADER_STR;
if (bit_regs) flags |= DUMP_REGS;
if (bit_crc) flags |= DUMP_CRC;
if ((rc = dump_config(&config, flags))) FAIL(rc);
return EXIT_SUCCESS;
fail:
return rc;
}
fpgatools-201212/blinking_led.c 0000664 0000000 0000000 00000015641 12065743015 0016400 0 ustar 00root root 0000000 0000000 //
// Author: Wolfgang Spraul
//
// This is free and unencumbered software released into the public domain.
// For details see the UNLICENSE file at the root of the source tree.
//
#include "model.h"
#include "floorplan.h"
#include "control.h"
/*
This C design corresponds to the following Verilog:
module blinking(input clk, output led);
// synthesis attribute LOC clk "P55 | IOSTANDARD = LVCMOS33"
// synthesis attribute LOC led "P48 | SLEW = QUIETIO | DRIVE = 8"
reg [14:0] counter;
always @(posedge clk) counter <= counter + 1;
assign led = counter[14];
endmodule
*/
int main(int argc, char** argv)
{
struct fpga_model model;
int param_bits;
const char *param_clock_pin, *param_led_pin;
int iob_clk_y, iob_clk_x, iob_clk_type_idx;
int iob_led_y, iob_led_x, iob_led_type_idx;
int logic_y, logic_x, logic_type_idx;
struct fpgadev_logic logic_cfg;
net_idx_t net;
if (cmdline_help(argc, argv)) {
printf( " %*s [-Dbits=14|23]\n"
" %*s [-Dclock_pin=P55|...]\n"
" %*s [-Dled_pin=P48|...]\n"
"\n", (int) strlen(*argv), "",
(int) strlen(*argv), "", (int) strlen(*argv), "");
return 0;
}
if (!(param_bits = cmdline_intvar(argc, argv, "bits")))
param_bits = 14;
if (!(param_clock_pin = cmdline_strvar(argc, argv, "clock_pin")))
param_clock_pin = "P55";
if (!(param_led_pin = cmdline_strvar(argc, argv, "led_pin")))
param_led_pin = "P48";
fpga_build_model(&model, cmdline_part(argc, argv),
cmdline_package(argc, argv));
fpga_find_iob(&model, param_clock_pin, &iob_clk_y, &iob_clk_x, &iob_clk_type_idx);
fdev_iob_input(&model, iob_clk_y, iob_clk_x, iob_clk_type_idx,
IO_LVCMOS33);
fpga_find_iob(&model, param_led_pin, &iob_led_y, &iob_led_x, &iob_led_type_idx);
fdev_iob_output(&model, iob_led_y, iob_led_x, iob_led_type_idx,
IO_LVCMOS25);
fdev_iob_slew(&model, iob_led_y, iob_led_x, iob_led_type_idx,
SLEW_QUIETIO);
fdev_iob_drive(&model, iob_led_y, iob_led_x, iob_led_type_idx,
8);
logic_y = 58;
logic_x = 13;
logic_type_idx = DEV_LOG_M_OR_L;
CLEAR(logic_cfg);
logic_cfg.a2d[LUT_A].lut6 = "(A6+~A6)*(~A5)";
logic_cfg.a2d[LUT_A].lut5 = "1";
logic_cfg.a2d[LUT_A].cy0 = CY0_O5;
logic_cfg.a2d[LUT_A].ff = FF_FF;
logic_cfg.a2d[LUT_A].ff_mux = MUX_XOR;
logic_cfg.a2d[LUT_A].ff_srinit = FF_SRINIT0;
logic_cfg.a2d[LUT_B].lut6 = "(A6+~A6)*(A5)";
logic_cfg.a2d[LUT_B].lut5 = "0";
logic_cfg.a2d[LUT_B].cy0 = CY0_O5;
logic_cfg.a2d[LUT_B].ff = FF_FF;
logic_cfg.a2d[LUT_B].ff_mux = MUX_XOR;
logic_cfg.a2d[LUT_B].ff_srinit = FF_SRINIT0;
logic_cfg.a2d[LUT_C].lut6 = "(A6+~A6)*(A5)";
logic_cfg.a2d[LUT_C].lut5 = "0";
logic_cfg.a2d[LUT_C].cy0 = CY0_O5;
logic_cfg.a2d[LUT_C].ff = FF_FF;
logic_cfg.a2d[LUT_C].ff_mux = MUX_XOR;
logic_cfg.a2d[LUT_C].ff_srinit = FF_SRINIT0;
logic_cfg.a2d[LUT_D].lut6 = "(A6+~A6)*(A5)";
logic_cfg.a2d[LUT_D].lut5 = "0";
logic_cfg.a2d[LUT_D].cy0 = CY0_O5;
logic_cfg.a2d[LUT_D].ff = FF_FF;
logic_cfg.a2d[LUT_D].ff_mux = MUX_XOR;
logic_cfg.a2d[LUT_D].ff_srinit = FF_SRINIT0;
logic_cfg.clk_inv = CLKINV_CLK;
logic_cfg.sync_attr = SYNCATTR_ASYNC;
logic_cfg.precyinit = PRECYINIT_0;
logic_cfg.cout_used = 1;
fdev_logic_setconf(&model, logic_y, logic_x, logic_type_idx, &logic_cfg);
logic_y = 57;
logic_cfg.precyinit = 0;
logic_cfg.a2d[LUT_A].lut6 = "(A6+~A6)*(A5)";
logic_cfg.a2d[LUT_A].lut5 = "0";
fdev_logic_setconf(&model, logic_y, logic_x, logic_type_idx, &logic_cfg);
logic_y = 56;
fdev_logic_setconf(&model, logic_y, logic_x, logic_type_idx, &logic_cfg);
logic_y = 55;
logic_cfg.cout_used = 0;
logic_cfg.a2d[LUT_C].lut6 = "A5";
logic_cfg.a2d[LUT_C].lut5 = 0;
logic_cfg.a2d[LUT_C].cy0 = 0;
logic_cfg.a2d[LUT_C].ff = FF_FF;
logic_cfg.a2d[LUT_C].ff_mux = MUX_XOR;
logic_cfg.a2d[LUT_C].ff_srinit = FF_SRINIT0;
CLEAR(logic_cfg.a2d[LUT_D]);
fdev_logic_setconf(&model, logic_y, logic_x, logic_type_idx, &logic_cfg);
// clock to logic devs
fnet_new(&model, &net);
fnet_add_port(&model, net, iob_clk_y, iob_clk_x, DEV_IOB,
iob_clk_type_idx, IOB_OUT_I);
fnet_add_port(&model, net, 55, 13, DEV_LOGIC, DEV_LOG_M_OR_L, LI_CLK);
fnet_add_port(&model, net, 56, 13, DEV_LOGIC, DEV_LOG_M_OR_L, LI_CLK);
fnet_add_port(&model, net, 57, 13, DEV_LOGIC, DEV_LOG_M_OR_L, LI_CLK);
fnet_add_port(&model, net, 58, 13, DEV_LOGIC, DEV_LOG_M_OR_L, LI_CLK);
fnet_route(&model, net);
// vcc to logic devs
fnet_new(&model, &net);
fnet_add_port(&model, net, 55, 13, DEV_LOGIC, DEV_LOG_M_OR_L, LI_A6);
fnet_add_port(&model, net, 55, 13, DEV_LOGIC, DEV_LOG_M_OR_L, LI_B6);
fnet_vcc_gnd(&model, net, /*is_vcc*/ 1);
fnet_new(&model, &net);
fnet_add_port(&model, net, 56, 13, DEV_LOGIC, DEV_LOG_M_OR_L, LI_A6);
fnet_add_port(&model, net, 56, 13, DEV_LOGIC, DEV_LOG_M_OR_L, LI_B6);
fnet_add_port(&model, net, 56, 13, DEV_LOGIC, DEV_LOG_M_OR_L, LI_C6);
fnet_add_port(&model, net, 56, 13, DEV_LOGIC, DEV_LOG_M_OR_L, LI_D6);
fnet_vcc_gnd(&model, net, /*is_vcc*/ 1);
fnet_new(&model, &net);
fnet_add_port(&model, net, 57, 13, DEV_LOGIC, DEV_LOG_M_OR_L, LI_A6);
fnet_add_port(&model, net, 57, 13, DEV_LOGIC, DEV_LOG_M_OR_L, LI_B6);
fnet_add_port(&model, net, 57, 13, DEV_LOGIC, DEV_LOG_M_OR_L, LI_C6);
fnet_add_port(&model, net, 57, 13, DEV_LOGIC, DEV_LOG_M_OR_L, LI_D6);
fnet_vcc_gnd(&model, net, /*is_vcc*/ 1);
fnet_new(&model, &net);
fnet_add_port(&model, net, 58, 13, DEV_LOGIC, DEV_LOG_M_OR_L, LI_A6);
fnet_add_port(&model, net, 58, 13, DEV_LOGIC, DEV_LOG_M_OR_L, LI_B6);
fnet_add_port(&model, net, 58, 13, DEV_LOGIC, DEV_LOG_M_OR_L, LI_C6);
fnet_add_port(&model, net, 58, 13, DEV_LOGIC, DEV_LOG_M_OR_L, LI_D6);
fnet_vcc_gnd(&model, net, /*is_vcc*/ 1);
// carry chain
fnet_new(&model, &net);
fnet_add_port(&model, net, 55, 13, DEV_LOGIC, DEV_LOG_M_OR_L, LI_CIN);
fnet_add_port(&model, net, 56, 13, DEV_LOGIC, DEV_LOG_M_OR_L, LO_COUT);
fnet_route(&model, net);
fnet_new(&model, &net);
fnet_add_port(&model, net, 56, 13, DEV_LOGIC, DEV_LOG_M_OR_L, LI_CIN);
fnet_add_port(&model, net, 57, 13, DEV_LOGIC, DEV_LOG_M_OR_L, LO_COUT);
fnet_route(&model, net);
fnet_new(&model, &net);
fnet_add_port(&model, net, 57, 13, DEV_LOGIC, DEV_LOG_M_OR_L, LI_CIN);
fnet_add_port(&model, net, 58, 13, DEV_LOGIC, DEV_LOG_M_OR_L, LO_COUT);
fnet_route(&model, net);
// bit chain
{
int out_pin[] = {LO_AQ, LO_BQ, LO_CQ, LO_DQ};
int in_pin[] = {LI_A5, LI_B5, LI_C5, LI_D5};
int cur_y, i;
for (cur_y = 58; cur_y >= 55; cur_y--) {
for (i = 0; i < 4; i++) {
if (cur_y == 55 && i >= 2)
break;
fnet_new(&model, &net);
fnet_add_port(&model, net, cur_y, 13, DEV_LOGIC, DEV_LOG_M_OR_L, out_pin[i]);
fnet_add_port(&model, net, cur_y, 13, DEV_LOGIC, DEV_LOG_M_OR_L, in_pin[i]);
fnet_route(&model, net);
}
}
}
fnet_new(&model, &net);
fnet_add_port(&model, net, 55, 13, DEV_LOGIC, DEV_LOG_M_OR_L, LO_CQ);
fnet_add_port(&model, net, 55, 13, DEV_LOGIC, DEV_LOG_M_OR_L, LI_C5);
fnet_add_port(&model, net, iob_led_y, iob_led_x, DEV_IOB,
iob_led_type_idx, IOB_IN_O);
fnet_route(&model, net);
write_floorplan(stdout, &model, FP_DEFAULT);
return fpga_free_model(&model);
}
fpgatools-201212/doc/ 0000775 0000000 0000000 00000000000 12065743015 0014351 5 ustar 00root root 0000000 0000000 fpgatools-201212/doc/bit2fp.1 0000664 0000000 0000000 00000000711 12065743015 0015620 0 ustar 00root root 0000000 0000000 .\" Process this file with
.\" groff -man -Tascii bit2fp.1
.TH FPGATOOLS: "1" "September 2012"
.SH NAME
bit2fp \- bitstream to floorplan
.SH SYNOPSIS
.B bit2fp
.RB [--bit-header]
.RB [--bit-regs]
.RB [--no-model]
.RB [--no-fp-header]
.RB [--dump-routing-mips]
.RB
.SH AUTHORS
Wolfgang Spraul
.PP
This is free and unencumbered software released into the public domain.
for details see the UNLICENSE file at the root of the source tree.
fpgatools-201212/doc/fp2bit.1 0000664 0000000 0000000 00000000601 12065743015 0015616 0 ustar 00root root 0000000 0000000 .\" Process this file with
.\" groff -man -Tascii bit2fp.1
.TH FPGATOOLS: "1" "September 2012"
.SH NAME
fp2bit \- floorplan to bitstream
.SH SYNOPSIS
.B fp2bit
.RB
.RB
.SH AUTHORS
Wolfgang Spraul
.PP
This is free and unencumbered software released into the public domain.
for details see the UNLICENSE file at the root of the source tree.
fpgatools-201212/draw_svg_tiles.c 0000664 0000000 0000000 00000007375 12065743015 0017000 0 ustar 00root root 0000000 0000000 //
// Author: Wolfgang Spraul
//
// This is free and unencumbered software released into the public domain.
// For details see the UNLICENSE file at the root of the source tree.
//
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "model.h"
#define VERT_TILE_SPACING 45
#define HORIZ_TILE_SPACING 160
int main(int argc, char** argv)
{
static const xmlChar* empty_svg = (const xmlChar*)
"\n"
"\n";
xmlDocPtr doc = 0;
xmlXPathContextPtr xpathCtx = 0;
xmlXPathObjectPtr xpathObj = 0;
xmlNodePtr new_node;
struct fpga_model model = {0};
char str[128];
int i, j;
// can't get indent formatting to work - use 'xmllint --pretty 1 -'
// on the output for now
xmlInitParser();
if (fpga_build_model(&model, XC6SLX9, TQG144))
goto fail;
doc = xmlParseDoc(empty_svg);
if (!doc) {
fprintf(stderr, "Internal error %i.\n", __LINE__);
goto fail;
}
xpathCtx = xmlXPathNewContext(doc);
if (!xpathCtx) {
fprintf(stderr, "Cannot create XPath context.\n");
goto fail;
}
xmlXPathRegisterNs(xpathCtx, BAD_CAST "svg", BAD_CAST "http://www.w3.org/2000/svg");
xpathObj = xmlXPathEvalExpression(BAD_CAST "//svg:*[@id='root']", xpathCtx);
if (!xpathObj) {
fprintf(stderr, "Cannot evaluate root expression.\n");
goto fail;
}
if (!xpathObj->nodesetval) {
fprintf(stderr, "Cannot find root node.\n");
goto fail;
}
if (xpathObj->nodesetval->nodeNr != 1) {
fprintf(stderr, "Found %i root nodes.\n", xpathObj->nodesetval->nodeNr);
goto fail;
}
for (i = 0; i < model.y_height; i++) {
for (j = 0; j < model.x_width; j++) {
sprintf(str, "y%i x%i:", i, j);
new_node = xmlNewChild(xpathObj->nodesetval->nodeTab[0],
0 /* xmlNsPtr */, BAD_CAST "text", BAD_CAST str);
xmlSetProp(new_node, BAD_CAST "x",
xmlXPathCastNumberToString(HORIZ_TILE_SPACING + j*HORIZ_TILE_SPACING));
xmlSetProp(new_node, BAD_CAST "y",
xmlXPathCastNumberToString(20
+ VERT_TILE_SPACING + i*VERT_TILE_SPACING));
strcpy(str, fpga_tiletype_str(
model.tiles[i*model.x_width+j].type));
new_node = xmlNewChild(xpathObj->nodesetval->nodeTab[0],
0 /* xmlNsPtr */, BAD_CAST "text", BAD_CAST str);
xmlSetProp(new_node, BAD_CAST "x",
xmlXPathCastNumberToString(HORIZ_TILE_SPACING + j*HORIZ_TILE_SPACING));
xmlSetProp(new_node, BAD_CAST "y",
xmlXPathCastNumberToString(20 + VERT_TILE_SPACING + i*VERT_TILE_SPACING + 14));
xmlSetProp(new_node, BAD_CAST "fpga:tile_y", BAD_CAST xmlXPathCastNumberToString(i));
xmlSetProp(new_node, BAD_CAST "fpga:tile_x", BAD_CAST xmlXPathCastNumberToString(j));
}
}
xmlSetProp(xpathObj->nodesetval->nodeTab[0], BAD_CAST "width",
BAD_CAST xmlXPathCastNumberToString(model.x_width * HORIZ_TILE_SPACING + HORIZ_TILE_SPACING/2));
xmlSetProp(xpathObj->nodesetval->nodeTab[0], BAD_CAST "height",
BAD_CAST xmlXPathCastNumberToString(20 + VERT_TILE_SPACING
+ model.y_height * VERT_TILE_SPACING + 20));
xmlDocFormatDump(stdout, doc, 1 /* format */);
xmlXPathFreeObject(xpathObj);
xmlXPathFreeContext(xpathCtx);
xmlFreeDoc(doc);
xmlCleanupParser();
fpga_free_model(&model);
return EXIT_SUCCESS;
fail:
if (xpathObj) xmlXPathFreeObject(xpathObj);
if (xpathCtx) xmlXPathFreeContext(xpathCtx);
if (doc) xmlFreeDoc(doc);
xmlCleanupParser();
fpga_free_model(&model);
return EXIT_FAILURE;
}
fpgatools-201212/fp2bit.c 0000664 0000000 0000000 00000002051 12065743015 0015134 0 ustar 00root root 0000000 0000000 //
// Author: Wolfgang Spraul
//
// This is free and unencumbered software released into the public domain.
// For details see the UNLICENSE file at the root of the source tree.
//
#include "model.h"
#include "floorplan.h"
#include "bit.h"
int main(int argc, char** argv)
{
struct fpga_model model;
FILE* fp, *fbits;
int rc = -1;
fbits = 0;
if (argc != 3) {
fprintf(stderr,
"\n"
"%s - floorplan to bitstream\n"
"Usage: %s \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, TQG144)))
goto fail;
if ((rc = read_floorplan(&model, fp))) goto fail;
if ((rc = write_bitfile(fbits, &model))) goto fail;
fclose(fbits);
return EXIT_SUCCESS;
fail:
if (fbits) fclose(fbits);
return rc;
}
fpgatools-201212/fpgastyle.css 0000664 0000000 0000000 00000000307 12065743015 0016314 0 ustar 00root root 0000000 0000000 rect.background
{
fill: black;
}
text
{
stroke: yellow;
font-family: sans-serif;
}
text.small
{
font-size: 10pt;
text-anchor: end;
}
path
{
stroke: yellow;
}
circle
{
stroke: yellow;
}
fpgatools-201212/hello_world.c 0000664 0000000 0000000 00000004375 12065743015 0016273 0 ustar 00root root 0000000 0000000 //
// Author: Wolfgang Spraul
//
// This is free and unencumbered software released into the public domain.
// For details see the UNLICENSE file at the root of the source tree.
//
#include "model.h"
#include "floorplan.h"
#include "control.h"
/*
This C design corresponds to the following Verilog:
module ver_and(input a, b, output y);
// synthesis attribute LOC a "P45"
// synthesis attribute LOC b "P46"
// synthesis attribute LOC y "P48 | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 12"
assign y = a & b;
endmodule
*/
int main(int argc, char** argv)
{
struct fpga_model model;
int iob_inA_y, iob_inA_x, iob_inA_type_idx;
int iob_inB_y, iob_inB_x, iob_inB_type_idx;
int iob_out_y, iob_out_x, iob_out_type_idx;
int logic_y, logic_x, logic_type_idx;
net_idx_t inA_net, inB_net, out_net;
fpga_build_model(&model, XC6SLX9, TQG144);
fpga_find_iob(&model, "P45", &iob_inA_y, &iob_inA_x,
&iob_inA_type_idx);
fdev_iob_input(&model, iob_inA_y, iob_inA_x,
iob_inA_type_idx, IO_LVCMOS33);
fpga_find_iob(&model, "P46", &iob_inB_y, &iob_inB_x,
&iob_inB_type_idx);
fdev_iob_input(&model, iob_inB_y, iob_inB_x,
iob_inB_type_idx, IO_LVCMOS33);
fpga_find_iob(&model, "P48", &iob_out_y, &iob_out_x,
&iob_out_type_idx);
fdev_iob_output(&model, iob_out_y, iob_out_x,
iob_out_type_idx, IO_LVCMOS33);
logic_y = 68;
logic_x = 13;
logic_type_idx = DEV_LOG_X;
fdev_logic_a2d_lut(&model, logic_y, logic_x, logic_type_idx,
LUT_D, 6, "A3*A5", ZTERM);
fnet_new(&model, &inA_net);
fnet_add_port(&model, inA_net, iob_inA_y, iob_inA_x,
DEV_IOB, iob_inA_type_idx, IOB_OUT_I);
fnet_add_port(&model, inA_net, logic_y, logic_x, DEV_LOGIC,
logic_type_idx, LI_D3);
fnet_route(&model, inA_net);
fnet_new(&model, &inB_net);
fnet_add_port(&model, inB_net, iob_inB_y, iob_inB_x,
DEV_IOB, iob_inB_type_idx, IOB_OUT_I);
fnet_add_port(&model, inB_net, logic_y, logic_x, DEV_LOGIC,
logic_type_idx, LI_D5);
fnet_route(&model, inB_net);
fnet_new(&model, &out_net);
fnet_add_port(&model, out_net, logic_y, logic_x, DEV_LOGIC,
logic_type_idx, LO_D);
fnet_add_port(&model, out_net, iob_out_y, iob_out_x,
DEV_IOB, iob_out_type_idx, IOB_IN_O);
fnet_route(&model, out_net);
write_floorplan(stdout, &model, FP_DEFAULT);
return fpga_free_model(&model);
}
fpgatools-201212/hstrrep.c 0000664 0000000 0000000 00000005217 12065743015 0015444 0 ustar 00root root 0000000 0000000 //
// Author: Wolfgang Spraul
//
// This is free and unencumbered software released into the public domain.
// For details see the UNLICENSE file at the root of the source tree.
//
#include
#include
#include
#include
#include
#include
#include "helper.h"
int main(int argc, char** argv)
{
char line[1024], search_str[1024], replace_str[1024];
char* next_wrd, *lasts;
const char* replace_ptr;
struct hashed_strarray search_arr, replace_arr;
FILE* fp = 0;
int i, rc, search_idx;
if (argc < 3) {
fprintf(stderr,
"\n"
"hstrrep - hashed string replace\n"
"Usage: %s \n"
" token_file is parsed into two parts: first word is the string\n"
" that is to be replaced, rest of line the replacement.\n", argv[0]);
goto xout;
}
if (strarray_init(&search_arr, STRIDX_1M)) {
fprintf(stderr, "Out of memory in %s:%i\n", __FILE__, __LINE__);
goto xout;
}
if (strarray_init(&replace_arr, STRIDX_1M)) {
fprintf(stderr, "Out of memory in %s:%i\n", __FILE__, __LINE__);
goto xout;
}
//
// Read search and replace tokens into hashed strarray
//
fp = fopen(argv[2], "r");
if (!fp) {
fprintf(stderr, "Error opening %s.\n", argv[2]);
goto xout;
}
while (fgets(line, sizeof(line), fp)) {
memset(replace_str, 0, sizeof(replace_str));
i = sscanf(line, " %[^ ] %1023c", search_str, replace_str);
if (i == 2) {
i = strlen(replace_str);
if (i && replace_str[i-1] == '\n')
replace_str[i-1] = 0;
rc = strarray_add(&search_arr, search_str, &search_idx);
if (rc) {
fprintf(stderr, "Out of memory in %s:%i\n", __FILE__, __LINE__);
goto xout;
}
rc = strarray_stash(&replace_arr, replace_str, search_idx);
if (rc) {
fprintf(stderr, "Out of memory in %s:%i\n", __FILE__, __LINE__);
goto xout;
}
}
}
fclose(fp);
//
// Go through data file and search and replace
//
fp = fopen(argv[1], "r");
if (!fp) {
fprintf(stderr, "Error opening %s.\n", argv[1]);
goto xout;
}
while (fgets(line, sizeof(line), fp)) {
next_wrd = strtok_r(line, " \n", &lasts);
if (next_wrd) {
do {
search_idx = strarray_find(&search_arr, next_wrd);
if (search_idx == STRIDX_NO_ENTRY)
fputs(next_wrd, stdout);
else {
replace_ptr = strarray_lookup(&replace_arr, search_idx);
if (!replace_ptr) {
fprintf(stderr, "Internal error in %s:%i\n", __FILE__, __LINE__);
goto xout;
}
fputs(replace_ptr, stdout);
}
next_wrd = strtok_r(0, " \n", &lasts);
if (next_wrd)
putchar(' ');
} while ( next_wrd );
putchar('\n');
}
}
fclose(fp);
return EXIT_SUCCESS;
xout:
return EXIT_FAILURE;
}
fpgatools-201212/lib.svg 0000664 0000000 0000000 00000000421 12065743015 0015070 0 ustar 00root root 0000000 0000000
fpgatools-201212/libs/ 0000775 0000000 0000000 00000000000 12065743015 0014535 5 ustar 00root root 0000000 0000000 fpgatools-201212/libs/Makefile 0000664 0000000 0000000 00000005350 12065743015 0016200 0 ustar 00root root 0000000 0000000 #
# Makefile - fpgatools
# Author: Wolfgang Spraul
#
# This is free and unencumbered software released into the public domain.
# For details see the UNLICENSE file at the root of the source tree.
#
LIBS_VERSION_MAJOR = 0
LIBS_VERSION = $(LIBS_VERSION_MAJOR).0.0
LIBFPGA_BIT_OBJS = bit_frames.o bit_regs.o
LIBFPGA_MODEL_OBJS = model_main.o model_tiles.o model_devices.o \
model_ports.o model_conns.o model_switches.o model_helper.o
LIBFPGA_FLOORPLAN_OBJS = floorplan.o
LIBFPGA_CONTROL_OBJS = control.o
LIBFPGA_CORES_OBJS = parts.o helper.o
OBJS := $(LIBFPGA_CORES_OBJS) $(LIBFPGA_BIT_OBJS) $(LIBFPGA_MODEL_OBJS) \
$(LIBFPGA_FLOORPLAN_OBJS) $(LIBFPGA_CONTROL_OBJS)
DYNAMIC_LIBS = libfpga-model.so libfpga-bit.so libfpga-floorplan.so \
libfpga-control.so libfpga-cores.so
DYNAMIC_HEADS = bit.h control.h floorplan.h helper.h model.h parts.h
SHARED_FLAGS = -shared -Wl,-soname,$@.$(LIBS_VERSION_MAJOR)
.PHONY: all clean install uninstall FAKE
all: $(DYNAMIC_LIBS) $(DYNAMIC_LIBS:.so=.a)
include ../Makefile.common
libfpga-cores.a: $(LIBFPGA_CORES_OBJS)
libfpga-bit.a: $(LIBFPGA_BIT_OBJS)
libfpga-model.a: $(LIBFPGA_MODEL_OBJS)
libfpga-floorplan.a: $(LIBFPGA_FLOORPLAN_OBJS)
libfpga-control.a: $(LIBFPGA_CONTROL_OBJS)
%.a:
$(AR) $@ $^
$(RANLIB) $@
libfpga-cores.so: $(LIBFPGA_CORES_OBJS)
libfpga-bit.so: $(LIBFPGA_BIT_OBJS)
libfpga-model.so: $(LIBFPGA_MODEL_OBJS)
libfpga-floorplan.so: $(LIBFPGA_FLOORPLAN_OBJS)
libfpga-control.so: $(LIBFPGA_CONTROL_OBJS)
%.so:
$(CC) $(LDFLAGS) $(SHARED_FLAGS) -o $@.$(LIBS_VERSION) $^
@ln -sf $@.$(LIBS_VERSION_MAJOR) $@
@ln -sf $@.$(LIBS_VERSION) $@.$(LIBS_VERSION_MAJOR)
%.o: %.c
$(CC) $(CPPFLAGS) $(CFLAGS) -fPIC -o $@ -c $<
$(MKDEP)
clean:
rm -f $(OBJS) $(OBJS:.o=.d) $(DYNAMIC_LIBS)
rm -f $(DYNAMIC_LIBS:.so=.a)
rm -f $(DYNAMIC_LIBS:.so=.so.$(LIBS_VERSION_MAJOR))
rm -f $(DYNAMIC_LIBS:.so=.so.$(LIBS_VERSION))
install: all
mkdir -p $(DESTDIR)/$(PREFIX)/include/
mkdir -p $(DESTDIR)/$(PREFIX)/lib/
install -m 644 $(DYNAMIC_HEADS) $(DESTDIR)/$(PREFIX)/include/
for f in $(DYNAMIC_LIBS); do \
chrpath -d $$f.$(LIBS_VERSION_MAJOR) && \
install -m 644 $$f.$(LIBS_VERSION) $(DESTDIR)/$(PREFIX)/lib/$$f.$(LIBS_VERSION) && \
(cd $(DESTDIR)/$(PREFIX)/lib/ && \
ln -sf $$f.$(LIBS_VERSION) $$f.$(LIBS_VERSION_MAJOR) && \
ln -sf $$f.$(LIBS_VERSION_MAJOR) $$f) \
|| exit 1; done
for f in $(DYNAMIC_LIBS:.so=.a); do \
install -m 644 $$f $(DESTDIR)/$(PREFIX)/lib/$$f \
|| exit 1; done
uninstall:
for f in $(DYNAMIC_HEADS); do rm -f $(DESTDIR)/$(PREFIX)/include/$$f || exit 1; done
for f in $(DYNAMIC_LIBS) $(DYNAMIC_LIBS:.so=.a) \
$(DYNAMIC_LIBS:.so=.so.$(LIBS_VERSION_MAJOR)) \
$(DYNAMIC_LIBS:.so=.so.$(LIBS_VERSION)); do \
rm -f $(DESTDIR)/$(PREFIX)/lib/$$f || exit 1; done
fpgatools-201212/libs/bit.h 0000664 0000000 0000000 00000004772 12065743015 0015476 0 ustar 00root root 0000000 0000000 //
// Author: Wolfgang Spraul
//
// This is free and unencumbered software released into the public domain.
// For details see the UNLICENSE file at the root of the source tree.
//
// xc6 configuration registers, documentation in ug380, page90
enum fpga_config_reg {
CRC = 0, FAR_MAJ, FAR_MIN, FDRI, FDRO, CMD, CTL, MASK, STAT, LOUT, COR1,
COR2, PWRDN_REG, FLR, IDCODE, CWDT, HC_OPT_REG, CSBO = 18,
GENERAL1, GENERAL2, GENERAL3, GENERAL4, GENERAL5, MODE_REG, PU_GWE,
PU_GTS, MFWR, CCLK_FREQ, SEU_OPT, EXP_SIGN, RDBK_SIGN, BOOTSTS,
EYE_MASK, CBC_REG
};
#define REG_NOOP -1 // pseudo register for noops
#define COR1_DEF 0x3D00
#define COR1_CRC_BYPASS 0x0010
#define COR2_DEF 0x09EE
#define MASK_DEF 0xCF
#define MASK_SECURITY 0x0030
#define CTL_DEF 0x81
#define CCLK_FREQ_DEF 0x3CC8
#define PWRDN_REG_DEF 0x0881
#define EYE_MASK_DEF 0x0000
#define HC_OPT_REG_DEF 0x1F
#define CWDT_DEF 0xFFFF
#define PU_GWE_DEF 0x005
#define PU_GTS_DEF 0x004
#define MODE_REG_DEF 0x100
#define GENERAL1_DEF 0x0000
#define GENERAL2_DEF 0x0000
#define GENERAL3_DEF 0x0000
#define GENERAL4_DEF 0x0000
#define GENERAL5_DEF 0x0000
#define SEU_OPT_DEF 0x1BE2
#define EXP_SIGN_DEF 0
#define FAR_MAJ_O 0
#define FAR_MIN_O 1
struct fpga_config_reg_rw
{
enum fpga_config_reg reg;
union {
int int_v;
int far[2]; // 0 (FAR_MAJ_O) = major, 1 (FAR_MIN_O) = minor
} u;
};
#define int_v u.int_v
#define far u.far
enum {
CMD_NULL = 0, CMD_WCFG, CMD_MFW, CMD_LFRM, CMD_RCFG, CMD_START,
CMD_RCRC = 7, CMD_AGHIGH, CMD_GRESTORE = 10, CMD_SHUTDOWN,
CMD_DESYNC = 13, CMD_IPROG
};
#define MAX_HEADER_STR_LEN 128
#define MAX_REG_ACTIONS 256
struct fpga_bits
{
uint8_t* d;
int len;
};
// Use the default value together with COR1 CRC_BYPASS
#define DEFAULT_AUTO_CRC 0x9876DEFC
struct fpga_config
{
char header_str[4][MAX_HEADER_STR_LEN];
int num_regs;
struct fpga_config_reg_rw reg[MAX_REG_ACTIONS];
// indices into reg (initialized to -1)
int num_regs_before_bits;
int idcode_reg;
int FLR_reg;
struct fpga_bits bits;
uint32_t auto_crc;
};
int read_bitfile(struct fpga_config* cfg, FILE* f);
#define DUMP_HEADER_STR 0x0001
#define DUMP_REGS 0x0002
#define DUMP_BITS 0x0004
#define DUMP_CRC 0x0008
int dump_config(struct fpga_config* cfg, int flags);
void free_config(struct fpga_config* cfg);
int write_bitfile(FILE* f, struct fpga_model* model);
int extract_model(struct fpga_model* model, struct fpga_bits* bits);
int printf_swbits(struct fpga_model* model);
int write_model(struct fpga_bits* bits, struct fpga_model* model);
fpgatools-201212/libs/bit_frames.c 0000664 0000000 0000000 00000271617 12065743015 0017032 0 ustar 00root root 0000000 0000000 //
// Author: Wolfgang Spraul
//
// This is free and unencumbered software released into the public domain.
// For details see the UNLICENSE file at the root of the source tree.
//
#include "model.h"
#include "bit.h"
#include "control.h"
static uint8_t* get_first_minor(struct fpga_bits* bits, int row, int major)
{
int i, num_frames;
if (row < 0) { HERE(); return 0; }
num_frames = 0;
for (i = 0; i < major; i++)
num_frames += get_major_minors(XC6SLX9, i);
return &bits->d[(row*FRAMES_PER_ROW + num_frames)*FRAME_SIZE];
}
static int get_bit(struct fpga_bits* bits,
int row, int major, int minor, int bit_i)
{
return frame_get_bit(get_first_minor(bits, row, major)
+ minor*FRAME_SIZE, bit_i);
}
static void set_bit(struct fpga_bits* bits,
int row, int major, int minor, int bit_i)
{
return frame_set_bit(get_first_minor(bits, row, major)
+ minor*FRAME_SIZE, bit_i);
}
static void clear_bit(struct fpga_bits* bits,
int row, int major, int minor, int bit_i)
{
return frame_clear_bit(get_first_minor(bits, row, major)
+ minor*FRAME_SIZE, bit_i);
}
struct bit_pos
{
int row;
int major;
int minor;
int bit_i;
};
static int get_bitp(struct fpga_bits* bits, struct bit_pos* pos)
{
return get_bit(bits, pos->row, pos->major, pos->minor, pos->bit_i);
}
static void set_bitp(struct fpga_bits* bits, struct bit_pos* pos)
{
set_bit(bits, pos->row, pos->major, pos->minor, pos->bit_i);
}
static void clear_bitp(struct fpga_bits* bits, struct bit_pos* pos)
{
clear_bit(bits, pos->row, pos->major, pos->minor, pos->bit_i);
}
static struct bit_pos s_default_bits[] = {
{ 0, 0, 3, 66 },
{ 0, 1, 23, 1034 },
{ 0, 1, 23, 1035 },
{ 0, 1, 23, 1039 },
{ 2, 0, 3, 66 }};
struct sw_yxpos
{
int y;
int x;
swidx_t idx;
};
#define MAX_YX_SWITCHES 1024
struct extract_state
{
struct fpga_model* model;
struct fpga_bits* bits;
// yx switches are fully extracted ones pointing into the
// model, stored here for later processing into nets.
int num_yx_pos;
struct sw_yxpos yx_pos[MAX_YX_SWITCHES]; // needs to be dynamically alloced...
};
static int find_es_switch(struct extract_state* es, int y, int x, swidx_t sw)
{
int i;
RC_CHECK(es->model);
if (sw == NO_SWITCH) { HERE(); return 0; }
for (i = 0; i < es->num_yx_pos; i++) {
if (es->yx_pos[i].y == y
&& es->yx_pos[i].x == x
&& es->yx_pos[i].idx == sw)
return 1;
}
return 0;
}
static int write_type2(struct fpga_bits* bits, struct fpga_model* model)
{
int i, y, x, type_idx, part_idx, dev_idx, first_iob, rc;
struct fpga_device* dev;
uint64_t u64;
const char* name;
RC_CHECK(model);
first_iob = 0;
for (i = 0; (name = fpga_enum_iob(model, i, &y, &x, &type_idx)); i++) {
dev_idx = fpga_dev_idx(model, y, x, DEV_IOB, type_idx);
if (dev_idx == NO_DEV) FAIL(EINVAL);
dev = FPGA_DEV(model, y, x, dev_idx);
if (!dev->instantiated)
continue;
part_idx = find_iob_sitename(XC6SLX9, name);
if (part_idx == -1) {
HERE();
continue;
}
if (!first_iob) {
first_iob = 1;
// todo: is this right on the other sides?
set_bit(bits, /*row*/ 0, get_rightside_major(XC6SLX9),
/*minor*/ 22, 64*15+XC6_HCLK_BITS+4);
}
if (dev->u.iob.istandard[0]) {
if (!dev->u.iob.I_mux
|| !dev->u.iob.bypass_mux
|| dev->u.iob.ostandard[0])
HERE();
u64 = XC6_IOB_INPUT | XC6_IOB_INSTANTIATED;
if (dev->u.iob.I_mux == IMUX_I_B)
u64 |= XC6_IOB_IMUX_I_B;
if (!strcmp(dev->u.iob.istandard, IO_LVCMOS33)
|| !strcmp(dev->u.iob.istandard, IO_LVCMOS25)
|| !strcmp(dev->u.iob.istandard, IO_LVTTL))
u64 |= XC6_IOB_INPUT_LVCMOS33_25_LVTTL;
else if (!strcmp(dev->u.iob.istandard, IO_LVCMOS18)
|| !strcmp(dev->u.iob.istandard, IO_LVCMOS15)
|| !strcmp(dev->u.iob.istandard, IO_LVCMOS12))
u64 |= XC6_IOB_INPUT_LVCMOS18_15_12;
else if (!strcmp(dev->u.iob.istandard, IO_LVCMOS18_JEDEC)
|| !strcmp(dev->u.iob.istandard, IO_LVCMOS15_JEDEC)
|| !strcmp(dev->u.iob.istandard, IO_LVCMOS12_JEDEC))
u64 |= XC6_IOB_INPUT_LVCMOS18_15_12_JEDEC;
else if (!strcmp(dev->u.iob.istandard, IO_SSTL2_I))
u64 |= XC6_IOB_INPUT_SSTL2_I;
else
HERE();
frame_set_u64(&bits->d[IOB_DATA_START
+ part_idx*IOB_ENTRY_LEN], u64);
} else if (dev->u.iob.ostandard[0]) {
if (!dev->u.iob.drive_strength
|| !dev->u.iob.slew
|| !dev->u.iob.suspend
|| dev->u.iob.istandard[0])
HERE();
u64 = XC6_IOB_INSTANTIATED;
// for now we always turn on O_PINW even if no net
// is connected to the pinw
u64 |= XC6_IOB_O_PINW;
if (!strcmp(dev->u.iob.ostandard, IO_LVTTL)) {
switch (dev->u.iob.drive_strength) {
case 2: u64 |= XC6_IOB_OUTPUT_LVTTL_DRIVE_2; break;
case 4: u64 |= XC6_IOB_OUTPUT_LVTTL_DRIVE_4; break;
case 6: u64 |= XC6_IOB_OUTPUT_LVTTL_DRIVE_6; break;
case 8: u64 |= XC6_IOB_OUTPUT_LVTTL_DRIVE_8; break;
case 12: u64 |= XC6_IOB_OUTPUT_LVTTL_DRIVE_12; break;
case 16: u64 |= XC6_IOB_OUTPUT_LVTTL_DRIVE_16; break;
case 24: u64 |= XC6_IOB_OUTPUT_LVTTL_DRIVE_24; break;
default: FAIL(EINVAL);
}
} else if (!strcmp(dev->u.iob.ostandard, IO_LVCMOS33)) {
switch (dev->u.iob.drive_strength) {
case 2: u64 |= XC6_IOB_OUTPUT_LVCMOS33_25_DRIVE_2; break;
case 4: u64 |= XC6_IOB_OUTPUT_LVCMOS33_DRIVE_4; break;
case 6: u64 |= XC6_IOB_OUTPUT_LVCMOS33_DRIVE_6; break;
case 8: u64 |= XC6_IOB_OUTPUT_LVCMOS33_DRIVE_8; break;
case 12: u64 |= XC6_IOB_OUTPUT_LVCMOS33_DRIVE_12; break;
case 16: u64 |= XC6_IOB_OUTPUT_LVCMOS33_DRIVE_16; break;
case 24: u64 |= XC6_IOB_OUTPUT_LVCMOS33_DRIVE_24; break;
default: FAIL(EINVAL);
}
} else if (!strcmp(dev->u.iob.ostandard, IO_LVCMOS25)) {
switch (dev->u.iob.drive_strength) {
case 2: u64 |= XC6_IOB_OUTPUT_LVCMOS33_25_DRIVE_2; break;
case 4: u64 |= XC6_IOB_OUTPUT_LVCMOS25_DRIVE_4; break;
case 6: u64 |= XC6_IOB_OUTPUT_LVCMOS25_DRIVE_6; break;
case 8: u64 |= XC6_IOB_OUTPUT_LVCMOS25_DRIVE_8; break;
case 12: u64 |= XC6_IOB_OUTPUT_LVCMOS25_DRIVE_12; break;
case 16: u64 |= XC6_IOB_OUTPUT_LVCMOS25_DRIVE_16; break;
case 24: u64 |= XC6_IOB_OUTPUT_LVCMOS25_DRIVE_24; break;
default: FAIL(EINVAL);
}
} else if (!strcmp(dev->u.iob.ostandard, IO_LVCMOS18)
|| !strcmp(dev->u.iob.ostandard, IO_LVCMOS18_JEDEC)) {
switch (dev->u.iob.drive_strength) {
case 2: u64 |= XC6_IOB_OUTPUT_LVCMOS18_DRIVE_2; break;
case 4: u64 |= XC6_IOB_OUTPUT_LVCMOS18_DRIVE_4; break;
case 6: u64 |= XC6_IOB_OUTPUT_LVCMOS18_DRIVE_6; break;
case 8: u64 |= XC6_IOB_OUTPUT_LVCMOS18_DRIVE_8; break;
case 12: u64 |= XC6_IOB_OUTPUT_LVCMOS18_DRIVE_12; break;
case 16: u64 |= XC6_IOB_OUTPUT_LVCMOS18_DRIVE_16; break;
case 24: u64 |= XC6_IOB_OUTPUT_LVCMOS18_DRIVE_24; break;
default: FAIL(EINVAL);
}
} else if (!strcmp(dev->u.iob.ostandard, IO_LVCMOS15)
|| !strcmp(dev->u.iob.ostandard, IO_LVCMOS15_JEDEC)) {
switch (dev->u.iob.drive_strength) {
case 2: u64 |= XC6_IOB_OUTPUT_LVCMOS15_DRIVE_2; break;
case 4: u64 |= XC6_IOB_OUTPUT_LVCMOS15_DRIVE_4; break;
case 6: u64 |= XC6_IOB_OUTPUT_LVCMOS15_DRIVE_6; break;
case 8: u64 |= XC6_IOB_OUTPUT_LVCMOS15_DRIVE_8; break;
case 12: u64 |= XC6_IOB_OUTPUT_LVCMOS15_DRIVE_12; break;
case 16: u64 |= XC6_IOB_OUTPUT_LVCMOS15_DRIVE_16; break;
default: FAIL(EINVAL);
}
} else if (!strcmp(dev->u.iob.ostandard, IO_LVCMOS12)
|| !strcmp(dev->u.iob.ostandard, IO_LVCMOS12_JEDEC)) {
switch (dev->u.iob.drive_strength) {
case 2: u64 |= XC6_IOB_OUTPUT_LVCMOS12_DRIVE_2; break;
case 4: u64 |= XC6_IOB_OUTPUT_LVCMOS12_DRIVE_4; break;
case 6: u64 |= XC6_IOB_OUTPUT_LVCMOS12_DRIVE_6; break;
case 8: u64 |= XC6_IOB_OUTPUT_LVCMOS12_DRIVE_8; break;
case 12: u64 |= XC6_IOB_OUTPUT_LVCMOS12_DRIVE_12; break;
default: FAIL(EINVAL);
}
} else FAIL(EINVAL);
switch (dev->u.iob.slew) {
case SLEW_SLOW: u64 |= XC6_IOB_SLEW_SLOW; break;
case SLEW_FAST: u64 |= XC6_IOB_SLEW_FAST; break;
case SLEW_QUIETIO: u64 |= XC6_IOB_SLEW_QUIETIO; break;
default: FAIL(EINVAL);
}
switch (dev->u.iob.suspend) {
case SUSP_LAST_VAL: u64 |= XC6_IOB_SUSP_LAST_VAL; break;
case SUSP_3STATE: u64 |= XC6_IOB_SUSP_3STATE; break;
case SUSP_3STATE_PULLUP: u64 |= XC6_IOB_SUSP_3STATE_PULLUP; break;
case SUSP_3STATE_PULLDOWN: u64 |= XC6_IOB_SUSP_3STATE_PULLDOWN; break;
case SUSP_3STATE_KEEPER: u64 |= XC6_IOB_SUSP_3STATE_KEEPER; break;
case SUSP_3STATE_OCT_ON: u64 |= XC6_IOB_SUSP_3STATE_OCT_ON; break;
default: FAIL(EINVAL);
}
frame_set_u64(&bits->d[IOB_DATA_START
+ part_idx*IOB_ENTRY_LEN], u64);
} else HERE();
}
return 0;
fail:
return rc;
}
static int extract_iobs(struct extract_state* es)
{
int i, num_iobs, iob_y, iob_x, iob_idx, dev_idx, first_iob, rc;
uint64_t u64;
const char* iob_sitename;
struct fpga_device* dev;
struct fpgadev_iob cfg;
RC_CHECK(es->model);
num_iobs = get_num_iobs(XC6SLX9);
first_iob = 0;
for (i = 0; i < num_iobs; i++) {
u64 = frame_get_u64(&es->bits->d[
IOB_DATA_START + i*IOB_ENTRY_LEN]);
if (!u64) continue;
iob_sitename = get_iob_sitename(XC6SLX9, i);
if (!iob_sitename) {
// The space for 6 IOBs on all four sides
// (6*8 = 48 bytes, *4=192 bytes) is used
// for clocks etc, so we ignore them here.
continue;
}
rc = fpga_find_iob(es->model, iob_sitename, &iob_y, &iob_x, &iob_idx);
if (rc) FAIL(rc);
dev_idx = fpga_dev_idx(es->model, iob_y, iob_x, DEV_IOB, iob_idx);
if (dev_idx == NO_DEV) FAIL(EINVAL);
dev = FPGA_DEV(es->model, iob_y, iob_x, dev_idx);
memset(&cfg, 0, sizeof(cfg));
if (!first_iob) {
first_iob = 1;
// todo: is this right on the other sides?
if (!get_bit(es->bits, /*row*/ 0, get_rightside_major(XC6SLX9),
/*minor*/ 22, 64*15+XC6_HCLK_BITS+4))
HERE();
clear_bit(es->bits, /*row*/ 0, get_rightside_major(XC6SLX9),
/*minor*/ 22, 64*15+XC6_HCLK_BITS+4);
}
if (u64 & XC6_IOB_INSTANTIATED)
u64 &= ~XC6_IOB_INSTANTIATED;
else
HERE();
switch (u64 & XC6_IOB_MASK_IO) {
case XC6_IOB_INPUT:
cfg.bypass_mux = BYPASS_MUX_I;
if (u64 & XC6_IOB_IMUX_I_B) {
cfg.I_mux = IMUX_I_B;
u64 &= ~XC6_IOB_IMUX_I_B;
} else
cfg.I_mux = IMUX_I;
switch (u64 & XC6_IOB_MASK_IN_TYPE) {
case XC6_IOB_INPUT_LVCMOS33_25_LVTTL:
u64 &= ~XC6_IOB_MASK_IN_TYPE;
strcpy(cfg.istandard, IO_LVCMOS25);
break;
case XC6_IOB_INPUT_LVCMOS18_15_12:
u64 &= ~XC6_IOB_MASK_IN_TYPE;
strcpy(cfg.istandard, IO_LVCMOS12);
break;
case XC6_IOB_INPUT_LVCMOS18_15_12_JEDEC:
u64 &= ~XC6_IOB_MASK_IN_TYPE;
strcpy(cfg.istandard, IO_LVCMOS12_JEDEC);
break;
case XC6_IOB_INPUT_SSTL2_I:
u64 &= ~XC6_IOB_MASK_IN_TYPE;
strcpy(cfg.istandard, IO_SSTL2_I);
break;
default: HERE(); break;
}
break;
case XC6_IOB_OUTPUT_LVCMOS33_25_DRIVE_2:
cfg.drive_strength = 2;
strcpy(cfg.ostandard, IO_LVCMOS25);
break;
case XC6_IOB_OUTPUT_LVCMOS33_DRIVE_4:
cfg.drive_strength = 4;
strcpy(cfg.ostandard, IO_LVCMOS33);
break;
case XC6_IOB_OUTPUT_LVCMOS33_DRIVE_6:
cfg.drive_strength = 6;
strcpy(cfg.ostandard, IO_LVCMOS33);
break;
case XC6_IOB_OUTPUT_LVCMOS33_DRIVE_8:
cfg.drive_strength = 8;
strcpy(cfg.ostandard, IO_LVCMOS33);
break;
case XC6_IOB_OUTPUT_LVCMOS33_DRIVE_12:
cfg.drive_strength = 12;
strcpy(cfg.ostandard, IO_LVCMOS33);
break;
case XC6_IOB_OUTPUT_LVCMOS33_DRIVE_16:
cfg.drive_strength = 16;
strcpy(cfg.ostandard, IO_LVCMOS33);
break;
case XC6_IOB_OUTPUT_LVCMOS33_DRIVE_24:
cfg.drive_strength = 24;
strcpy(cfg.ostandard, IO_LVCMOS33);
break;
case XC6_IOB_OUTPUT_LVCMOS25_DRIVE_4:
cfg.drive_strength = 4;
strcpy(cfg.ostandard, IO_LVCMOS25);
break;
case XC6_IOB_OUTPUT_LVCMOS25_DRIVE_6:
cfg.drive_strength = 6;
strcpy(cfg.ostandard, IO_LVCMOS25);
break;
case XC6_IOB_OUTPUT_LVCMOS25_DRIVE_8:
cfg.drive_strength = 8;
strcpy(cfg.ostandard, IO_LVCMOS25);
break;
case XC6_IOB_OUTPUT_LVCMOS25_DRIVE_12:
cfg.drive_strength = 12;
strcpy(cfg.ostandard, IO_LVCMOS25);
break;
case XC6_IOB_OUTPUT_LVCMOS25_DRIVE_16:
cfg.drive_strength = 16;
strcpy(cfg.ostandard, IO_LVCMOS25);
break;
case XC6_IOB_OUTPUT_LVCMOS25_DRIVE_24:
cfg.drive_strength = 24;
strcpy(cfg.ostandard, IO_LVCMOS25);
break;
case XC6_IOB_OUTPUT_LVTTL_DRIVE_2:
cfg.drive_strength = 2;
strcpy(cfg.ostandard, IO_LVTTL);
break;
case XC6_IOB_OUTPUT_LVTTL_DRIVE_4:
cfg.drive_strength = 4;
strcpy(cfg.ostandard, IO_LVTTL);
break;
case XC6_IOB_OUTPUT_LVTTL_DRIVE_6:
cfg.drive_strength = 6;
strcpy(cfg.ostandard, IO_LVTTL);
break;
case XC6_IOB_OUTPUT_LVTTL_DRIVE_8:
cfg.drive_strength = 8;
strcpy(cfg.ostandard, IO_LVTTL);
break;
case XC6_IOB_OUTPUT_LVTTL_DRIVE_12:
cfg.drive_strength = 12;
strcpy(cfg.ostandard, IO_LVTTL);
break;
case XC6_IOB_OUTPUT_LVTTL_DRIVE_16:
cfg.drive_strength = 16;
strcpy(cfg.ostandard, IO_LVTTL);
break;
case XC6_IOB_OUTPUT_LVTTL_DRIVE_24:
cfg.drive_strength = 24;
strcpy(cfg.ostandard, IO_LVTTL);
break;
case XC6_IOB_OUTPUT_LVCMOS18_DRIVE_2:
cfg.drive_strength = 2;
strcpy(cfg.ostandard, IO_LVCMOS18);
break;
case XC6_IOB_OUTPUT_LVCMOS18_DRIVE_4:
cfg.drive_strength = 4;
strcpy(cfg.ostandard, IO_LVCMOS18);
break;
case XC6_IOB_OUTPUT_LVCMOS18_DRIVE_6:
cfg.drive_strength = 6;
strcpy(cfg.ostandard, IO_LVCMOS18);
break;
case XC6_IOB_OUTPUT_LVCMOS18_DRIVE_8:
cfg.drive_strength = 8;
strcpy(cfg.ostandard, IO_LVCMOS18);
break;
case XC6_IOB_OUTPUT_LVCMOS18_DRIVE_12:
cfg.drive_strength = 12;
strcpy(cfg.ostandard, IO_LVCMOS18);
break;
case XC6_IOB_OUTPUT_LVCMOS18_DRIVE_16:
cfg.drive_strength = 16;
strcpy(cfg.ostandard, IO_LVCMOS18);
break;
case XC6_IOB_OUTPUT_LVCMOS18_DRIVE_24:
cfg.drive_strength = 24;
strcpy(cfg.ostandard, IO_LVCMOS18);
break;
case XC6_IOB_OUTPUT_LVCMOS15_DRIVE_2:
cfg.drive_strength = 2;
strcpy(cfg.ostandard, IO_LVCMOS15);
break;
case XC6_IOB_OUTPUT_LVCMOS15_DRIVE_4:
cfg.drive_strength = 4;
strcpy(cfg.ostandard, IO_LVCMOS15);
break;
case XC6_IOB_OUTPUT_LVCMOS15_DRIVE_6:
cfg.drive_strength = 6;
strcpy(cfg.ostandard, IO_LVCMOS15);
break;
case XC6_IOB_OUTPUT_LVCMOS15_DRIVE_8:
cfg.drive_strength = 8;
strcpy(cfg.ostandard, IO_LVCMOS15);
break;
case XC6_IOB_OUTPUT_LVCMOS15_DRIVE_12:
cfg.drive_strength = 12;
strcpy(cfg.ostandard, IO_LVCMOS15);
break;
case XC6_IOB_OUTPUT_LVCMOS15_DRIVE_16:
cfg.drive_strength = 16;
strcpy(cfg.ostandard, IO_LVCMOS15);
break;
case XC6_IOB_OUTPUT_LVCMOS12_DRIVE_2:
cfg.drive_strength = 2;
strcpy(cfg.ostandard, IO_LVCMOS12);
break;
case XC6_IOB_OUTPUT_LVCMOS12_DRIVE_4:
cfg.drive_strength = 4;
strcpy(cfg.ostandard, IO_LVCMOS12);
break;
case XC6_IOB_OUTPUT_LVCMOS12_DRIVE_6:
cfg.drive_strength = 6;
strcpy(cfg.ostandard, IO_LVCMOS12);
break;
case XC6_IOB_OUTPUT_LVCMOS12_DRIVE_8:
cfg.drive_strength = 8;
strcpy(cfg.ostandard, IO_LVCMOS12);
break;
case XC6_IOB_OUTPUT_LVCMOS12_DRIVE_12:
cfg.drive_strength = 12;
strcpy(cfg.ostandard, IO_LVCMOS12);
break;
default: HERE(); break;
}
if (cfg.istandard[0] || cfg.ostandard[0])
u64 &= ~XC6_IOB_MASK_IO;
if (cfg.ostandard[0]) {
cfg.O_used = 1;
u64 &= ~XC6_IOB_O_PINW;
if (!strcmp(cfg.ostandard, IO_LVCMOS12)
|| !strcmp(cfg.ostandard, IO_LVCMOS15)
|| !strcmp(cfg.ostandard, IO_LVCMOS18)
|| !strcmp(cfg.ostandard, IO_LVCMOS25)
|| !strcmp(cfg.ostandard, IO_LVCMOS33)
|| !strcmp(cfg.ostandard, IO_LVTTL)) {
switch (u64 & XC6_IOB_MASK_SLEW) {
case XC6_IOB_SLEW_SLOW:
u64 &= ~XC6_IOB_MASK_SLEW;
cfg.slew = SLEW_SLOW;
break;
case XC6_IOB_SLEW_FAST:
u64 &= ~XC6_IOB_MASK_SLEW;
cfg.slew = SLEW_FAST;
break;
case XC6_IOB_SLEW_QUIETIO:
u64 &= ~XC6_IOB_MASK_SLEW;
cfg.slew = SLEW_QUIETIO;
break;
default: HERE();
}
}
switch (u64 & XC6_IOB_MASK_SUSPEND) {
case XC6_IOB_SUSP_3STATE:
u64 &= ~XC6_IOB_MASK_SUSPEND;
cfg.suspend = SUSP_3STATE;
break;
case XC6_IOB_SUSP_3STATE_OCT_ON:
u64 &= ~XC6_IOB_MASK_SUSPEND;
cfg.suspend = SUSP_3STATE_OCT_ON;
break;
case XC6_IOB_SUSP_3STATE_KEEPER:
u64 &= ~XC6_IOB_MASK_SUSPEND;
cfg.suspend = SUSP_3STATE_KEEPER;
break;
case XC6_IOB_SUSP_3STATE_PULLUP:
u64 &= ~XC6_IOB_MASK_SUSPEND;
cfg.suspend = SUSP_3STATE_PULLUP;
break;
case XC6_IOB_SUSP_3STATE_PULLDOWN:
u64 &= ~XC6_IOB_MASK_SUSPEND;
cfg.suspend = SUSP_3STATE_PULLDOWN;
break;
case XC6_IOB_SUSP_LAST_VAL:
u64 &= ~XC6_IOB_MASK_SUSPEND;
cfg.suspend = SUSP_LAST_VAL;
break;
default: HERE();
}
}
if (!u64) {
frame_set_u64(&es->bits->d[IOB_DATA_START
+ i*IOB_ENTRY_LEN], 0);
dev->instantiated = 1;
dev->u.iob = cfg;
} else HERE();
}
return 0;
fail:
return rc;
}
static int extract_type2(struct extract_state* es)
{
int i, bits_off;
uint16_t u16;
RC_CHECK(es->model);
extract_iobs(es);
for (i = 0; i < es->model->pkg->num_gclk_pins; i++) {
if (!es->model->pkg->gclk_pin[i])
continue;
bits_off = IOB_DATA_START
+ es->model->pkg->gclk_type2_o[i]*XC6_WORD_BYTES
+ XC6_TYPE2_GCLK_REG_SW/XC6_WORD_BITS;
u16 = frame_get_u16(&es->bits->d[bits_off]);
if (!u16)
continue;
if (u16 & (1<<(XC6_TYPE2_GCLK_REG_SW%XC6_WORD_BITS))) {
int iob_y, iob_x, iob_idx;
struct fpga_device *iob_dev;
struct switch_to_yx_l2 switch_to_yx_l2;
struct switch_to_rel switch_to_rel;
//
// find and enable reg-switch for gclk_pin[i]
// the writing equivalent is in write_inner_term_sw()
//
fpga_find_iob(es->model, es->model->pkg->gclk_pin[i],
&iob_y, &iob_x, &iob_idx);
RC_CHECK(es->model);
iob_dev = fdev_p(es->model, iob_y, iob_x, DEV_IOB, iob_idx);
RC_ASSERT(es->model, iob_dev);
switch_to_yx_l2.l1.yx_req = YX_X_CENTER_CMTPLL | YX_Y_CENTER;
switch_to_yx_l2.l1.flags = SWTO_YX_CLOSEST;
switch_to_yx_l2.l1.model = es->model;
switch_to_yx_l2.l1.y = iob_y;
switch_to_yx_l2.l1.x = iob_x;
switch_to_yx_l2.l1.start_switch = iob_dev->pinw[IOB_OUT_I];
switch_to_yx_l2.l1.from_to = SW_FROM;
fpga_switch_to_yx_l2(&switch_to_yx_l2);
RC_CHECK(es->model);
if (!switch_to_yx_l2.l1.set.len)
{ HERE(); continue; }
switch_to_rel.model = es->model;
switch_to_rel.start_y = switch_to_yx_l2.l1.dest_y;
switch_to_rel.start_x = switch_to_yx_l2.l1.dest_x;
switch_to_rel.start_switch = switch_to_yx_l2.l1.dest_connpt;
switch_to_rel.from_to = SW_FROM;
switch_to_rel.flags = SWTO_REL_WEAK_TARGET;
switch_to_rel.rel_y = es->model->center_y - switch_to_rel.start_y;
switch_to_rel.rel_x = es->model->center_x - switch_to_rel.start_x;
switch_to_rel.target_connpt = STRIDX_NO_ENTRY;
fpga_switch_to_rel(&switch_to_rel);
RC_CHECK(es->model);
if (!switch_to_rel.set.len)
{ HERE(); continue; }
if (switch_to_rel.set.len != 1) HERE();
RC_ASSERT(es->model, es->num_yx_pos < MAX_YX_SWITCHES);
es->yx_pos[es->num_yx_pos].y = switch_to_rel.start_y;
es->yx_pos[es->num_yx_pos].x = switch_to_rel.start_x;
es->yx_pos[es->num_yx_pos].idx = switch_to_rel.set.sw[0];
es->num_yx_pos++;
u16 &= ~(1<<(XC6_TYPE2_GCLK_REG_SW%XC6_WORD_BITS));
}
if (u16) HERE();
frame_set_u16(&es->bits->d[bits_off], u16);
}
RC_RETURN(es->model);
}
static int lut2str(uint64_t lut, int lut_pos, int lut5_used,
char *lut6_buf, char** lut6_p, char *lut5_buf, char** lut5_p)
{
int lut_map[64], rc;
uint64_t lut_mapped;
const char* str;
if (lut5_used) {
xc6_lut_bitmap(lut_pos, &lut_map, 32);
lut_mapped = map_bits(lut, 64, lut_map);
// lut6
str = bool_bits2str(ULL_HIGH32(lut_mapped), 32);
if (!str) FAIL(EINVAL);
snprintf(lut6_buf, MAX_LUT_LEN, "(A6+~A6)*(%s)", str);
*lut6_p = lut6_buf;
// lut5
str = bool_bits2str(ULL_LOW32(lut_mapped), 32);
if (!str) FAIL(EINVAL);
strcpy(lut5_buf, str);
*lut5_p = lut5_buf;
} else {
xc6_lut_bitmap(lut_pos, &lut_map, 64);
lut_mapped = map_bits(lut, 64, lut_map);
str = bool_bits2str(lut_mapped, 64);
if (!str) FAIL(EINVAL);
strcpy(lut6_buf, str);
*lut6_p = lut6_buf;
}
return 0;
fail:
return rc;
}
static int extract_logic(struct extract_state* es)
{
int row, row_pos, x, y, i, byte_off, last_minor, lut5_used, rc;
int latch_ml, latch_x, l_col, lut;
struct fpgadev_logic cfg_ml, cfg_x;
uint64_t lut_X[4], lut_ML[4]; // LUT_A-LUT_D
uint64_t mi20, mi23_M, mi2526;
uint8_t* u8_p;
char lut6_ml[NUM_LUTS][MAX_LUT_LEN];
char lut5_ml[NUM_LUTS][MAX_LUT_LEN];
char lut6_x[NUM_LUTS][MAX_LUT_LEN];
char lut5_x[NUM_LUTS][MAX_LUT_LEN];
struct fpga_device* dev_ml;
RC_CHECK(es->model);
for (x = LEFT_SIDE_WIDTH; x < es->model->x_width-RIGHT_SIDE_WIDTH; x++) {
if (!is_atx(X_FABRIC_LOGIC_COL|X_CENTER_LOGIC_COL, es->model, x))
continue;
for (y = TOP_IO_TILES; y < es->model->y_height - BOT_IO_TILES; y++) {
if (!has_device(es->model, y, x, DEV_LOGIC))
continue;
row = which_row(y, es->model);
row_pos = pos_in_row(y, es->model);
if (row == -1 || row_pos == -1 || row_pos == 8) {
HERE();
continue;
}
if (row_pos > 8) row_pos--;
u8_p = get_first_minor(es->bits, row, es->model->x_major[x]);
byte_off = row_pos * 8;
if (row_pos >= 8) byte_off += XC6_HCLK_BYTES;
//
// Step 1:
//
// read all configuration bits for the 2 logic devices
// into local variables
//
mi20 = frame_get_u64(u8_p + 20*FRAME_SIZE + byte_off) & XC6_MI20_LOGIC_MASK;
if (has_device_type(es->model, y, x, DEV_LOGIC, LOGIC_M)) {
mi23_M = frame_get_u64(u8_p + 23*FRAME_SIZE + byte_off);
mi2526 = frame_get_u64(u8_p + 26*FRAME_SIZE + byte_off);
lut_ML[LUT_A] = frame_get_lut64(u8_p + 24*FRAME_SIZE, row_pos*2+1);
lut_ML[LUT_B] = frame_get_lut64(u8_p + 21*FRAME_SIZE, row_pos*2+1);
lut_ML[LUT_C] = frame_get_lut64(u8_p + 24*FRAME_SIZE, row_pos*2);
lut_ML[LUT_D] = frame_get_lut64(u8_p + 21*FRAME_SIZE, row_pos*2);
lut_X[LUT_A] = frame_get_lut64(u8_p + 27*FRAME_SIZE, row_pos*2+1);
lut_X[LUT_B] = frame_get_lut64(u8_p + 29*FRAME_SIZE, row_pos*2+1);
lut_X[LUT_C] = frame_get_lut64(u8_p + 27*FRAME_SIZE, row_pos*2);
lut_X[LUT_D] = frame_get_lut64(u8_p + 29*FRAME_SIZE, row_pos*2);
l_col = 0;
} else if (has_device_type(es->model, y, x, DEV_LOGIC, LOGIC_L)) {
mi23_M = 0;
mi2526 = frame_get_u64(u8_p + 25*FRAME_SIZE + byte_off);
lut_ML[LUT_A] = frame_get_lut64(u8_p + 23*FRAME_SIZE, row_pos*2+1);
lut_ML[LUT_B] = frame_get_lut64(u8_p + 21*FRAME_SIZE, row_pos*2+1);
lut_ML[LUT_C] = frame_get_lut64(u8_p + 23*FRAME_SIZE, row_pos*2);
lut_ML[LUT_D] = frame_get_lut64(u8_p + 21*FRAME_SIZE, row_pos*2);
lut_X[LUT_A] = frame_get_lut64(u8_p + 26*FRAME_SIZE, row_pos*2+1);
lut_X[LUT_B] = frame_get_lut64(u8_p + 28*FRAME_SIZE, row_pos*2+1);
lut_X[LUT_C] = frame_get_lut64(u8_p + 26*FRAME_SIZE, row_pos*2);
lut_X[LUT_D] = frame_get_lut64(u8_p + 28*FRAME_SIZE, row_pos*2);
l_col = 1;
} else {
HERE();
continue;
}
//
// Step 2:
//
// If all is zero, assume the devices are not instantiated.
// todo: we could check pin connectivity and infer 0-bit
// configured devices
//
if (!mi20 && !mi23_M && !mi2526
&& !lut_X[0] && !lut_X[1] && !lut_X[2] && !lut_X[3]
&& !lut_ML[0] && !lut_ML[1] && !lut_ML[2] && !lut_ML[3])
continue;
//
// Step 3:
//
// Parse all bits from minors 20 and 25/26 into more
// easily usable cfg_ml and cfg_x structures.
//
memset(&cfg_ml, 0, sizeof(cfg_ml));
memset(&cfg_x, 0, sizeof(cfg_x));
latch_ml = 0;
latch_x = 0;
// minor20
if (mi20 & (1ULL<> XC6_ML_D_OUTMUX_O) {
case XC6_ML_D_OUTMUX_O6:
cfg_ml.a2d[LUT_D].out_mux = MUX_O6;
break;
case XC6_ML_D_OUTMUX_XOR:
cfg_ml.a2d[LUT_D].out_mux = MUX_XOR;
break;
case XC6_ML_D_OUTMUX_O5:
cfg_ml.a2d[LUT_D].out_mux = MUX_O5;
break;
case XC6_ML_D_OUTMUX_CY:
cfg_ml.a2d[LUT_D].out_mux = MUX_CY;
break;
case XC6_ML_D_OUTMUX_5Q:
cfg_ml.a2d[LUT_D].out_mux = MUX_5Q;
break;
default: HERE(); continue;
}
mi2526 &= ~XC6_ML_D_OUTMUX_MASK;
}
if (mi2526 & XC6_ML_D_FFMUX_MASK) {
switch ((mi2526 & XC6_ML_D_FFMUX_MASK) >> XC6_ML_D_FFMUX_O) {
case XC6_ML_D_FFMUX_O5:
cfg_ml.a2d[LUT_D].ff_mux = MUX_O5;
break;
case XC6_ML_D_FFMUX_X:
cfg_ml.a2d[LUT_D].ff_mux = MUX_X;
break;
case XC6_ML_D_FFMUX_XOR:
cfg_ml.a2d[LUT_D].ff_mux = MUX_XOR;
break;
case XC6_ML_D_FFMUX_CY:
cfg_ml.a2d[LUT_D].ff_mux = MUX_CY;
break;
default: HERE(); continue;
}
mi2526 &= ~XC6_ML_D_FFMUX_MASK;
}
if (mi2526 & (1ULL<> XC6_ML_C_OUTMUX_O) {
case XC6_ML_C_OUTMUX_XOR:
cfg_ml.a2d[LUT_C].out_mux = MUX_XOR;
break;
case XC6_ML_C_OUTMUX_O6:
cfg_ml.a2d[LUT_C].out_mux = MUX_O6;
break;
case XC6_ML_C_OUTMUX_5Q:
cfg_ml.a2d[LUT_C].out_mux = MUX_5Q;
break;
case XC6_ML_C_OUTMUX_CY:
cfg_ml.a2d[LUT_C].out_mux = MUX_CY;
break;
case XC6_ML_C_OUTMUX_O5:
cfg_ml.a2d[LUT_C].out_mux = MUX_O5;
break;
case XC6_ML_C_OUTMUX_F7:
cfg_ml.a2d[LUT_C].out_mux = MUX_F7;
break;
default: HERE(); continue;
}
mi2526 &= ~XC6_ML_C_OUTMUX_MASK;
}
if (mi2526 & XC6_ML_C_FFMUX_MASK) {
switch ((mi2526 & XC6_ML_C_FFMUX_MASK) >> XC6_ML_C_FFMUX_O) {
case XC6_ML_C_FFMUX_O5:
cfg_ml.a2d[LUT_C].ff_mux = MUX_O5;
break;
case XC6_ML_C_FFMUX_X:
cfg_ml.a2d[LUT_C].ff_mux = MUX_X;
break;
case XC6_ML_C_FFMUX_F7:
cfg_ml.a2d[LUT_C].ff_mux = MUX_F7;
break;
case XC6_ML_C_FFMUX_XOR:
cfg_ml.a2d[LUT_C].ff_mux = MUX_XOR;
break;
case XC6_ML_C_FFMUX_CY:
cfg_ml.a2d[LUT_C].ff_mux = MUX_CY;
break;
default: HERE(); continue;
}
mi2526 &= ~XC6_ML_C_FFMUX_MASK;
}
if (mi2526 & XC6_ML_B_OUTMUX_MASK) {
switch ((mi2526 & XC6_ML_B_OUTMUX_MASK) >> XC6_ML_B_OUTMUX_O) {
case XC6_ML_B_OUTMUX_5Q:
cfg_ml.a2d[LUT_B].out_mux = MUX_5Q;
break;
case XC6_ML_B_OUTMUX_F8:
cfg_ml.a2d[LUT_B].out_mux = MUX_F8;
break;
case XC6_ML_B_OUTMUX_XOR:
cfg_ml.a2d[LUT_B].out_mux = MUX_XOR;
break;
case XC6_ML_B_OUTMUX_CY:
cfg_ml.a2d[LUT_B].out_mux = MUX_CY;
break;
case XC6_ML_B_OUTMUX_O6:
cfg_ml.a2d[LUT_B].out_mux = MUX_O6;
break;
case XC6_ML_B_OUTMUX_O5:
cfg_ml.a2d[LUT_B].out_mux = MUX_O5;
break;
default: HERE(); continue;
}
mi2526 &= ~XC6_ML_B_OUTMUX_MASK;
}
if (mi2526 & (1ULL<> XC6_ML_B_FFMUX_O) {
case XC6_ML_B_FFMUX_XOR:
cfg_ml.a2d[LUT_B].ff_mux = MUX_XOR;
break;
case XC6_ML_B_FFMUX_O5:
cfg_ml.a2d[LUT_B].ff_mux = MUX_O5;
break;
case XC6_ML_B_FFMUX_CY:
cfg_ml.a2d[LUT_B].ff_mux = MUX_CY;
break;
case XC6_ML_B_FFMUX_X:
cfg_ml.a2d[LUT_B].ff_mux = MUX_X;
break;
case XC6_ML_B_FFMUX_F8:
cfg_ml.a2d[LUT_B].ff_mux = MUX_F8;
break;
default: HERE(); continue;
}
mi2526 &= ~XC6_ML_B_FFMUX_MASK;
}
if (mi2526 & XC6_ML_A_FFMUX_MASK) {
switch ((mi2526 & XC6_ML_A_FFMUX_MASK) >> XC6_ML_A_FFMUX_O) {
case XC6_ML_A_FFMUX_XOR:
cfg_ml.a2d[LUT_A].ff_mux = MUX_XOR;
break;
case XC6_ML_A_FFMUX_X:
cfg_ml.a2d[LUT_A].ff_mux = MUX_X;
break;
case XC6_ML_A_FFMUX_O5:
cfg_ml.a2d[LUT_A].ff_mux = MUX_O5;
break;
case XC6_ML_A_FFMUX_CY:
cfg_ml.a2d[LUT_A].ff_mux = MUX_CY;
break;
case XC6_ML_A_FFMUX_F7:
cfg_ml.a2d[LUT_A].ff_mux = MUX_F7;
break;
default: HERE(); continue;
}
mi2526 &= ~XC6_ML_A_FFMUX_MASK;
}
if (mi2526 & XC6_ML_A_OUTMUX_MASK) {
switch ((mi2526 & XC6_ML_A_OUTMUX_MASK) >> XC6_ML_A_OUTMUX_O) {
case XC6_ML_A_OUTMUX_5Q:
cfg_ml.a2d[LUT_A].out_mux = MUX_5Q;
break;
case XC6_ML_A_OUTMUX_F7:
cfg_ml.a2d[LUT_A].out_mux = MUX_F7;
break;
case XC6_ML_A_OUTMUX_XOR:
cfg_ml.a2d[LUT_A].out_mux = MUX_XOR;
break;
case XC6_ML_A_OUTMUX_CY:
cfg_ml.a2d[LUT_A].out_mux = MUX_CY;
break;
case XC6_ML_A_OUTMUX_O6:
cfg_ml.a2d[LUT_A].out_mux = MUX_O6;
break;
case XC6_ML_A_OUTMUX_O5:
cfg_ml.a2d[LUT_A].out_mux = MUX_O5;
break;
default: HERE(); continue;
}
mi2526 &= ~XC6_ML_A_OUTMUX_MASK;
}
if (mi2526 & (1ULL<model, y, x, DEV_LOGIC, DEV_LOG_M_OR_L);
if (!dev_ml) FAIL(EINVAL);
if (find_es_switch(es, y, x, fpga_switch_first(
es->model, y, x, dev_ml->pinw[LO_COUT], SW_FROM)))
cfg_ml.cout_used = 1;
// todo: if srinit=1, the matching ff/latch must be on
// todo: handle all_latch
// todo: precyinit=0 has no bits
// todo: cy0=X has no bits, check connectivity
// todo: the x-device ffmux must not be left as MUX_X unless the ff is really in use
//
// Step 6:
//
// Determine lut5_usage and read the luts.
//
// todo: in ML, if srinit=0 cannot decide between ff_mux=O6 or
// direct-out, need to check pin connectivity, is_pin_connected()
// todo: in ML devs, ffmux=O6 has no bits set
// todo: 5Q-ff in X devices
// ML-A
if (lut_ML[LUT_A]
|| !all_zero(&cfg_ml.a2d[LUT_A], sizeof(cfg_ml.a2d[LUT_A]))) {
if (lut_ML[LUT_A]
&& cfg_ml.a2d[LUT_A].out_mux != MUX_O6
&& cfg_ml.a2d[LUT_A].out_mux != MUX_XOR
&& cfg_ml.a2d[LUT_A].out_mux != MUX_CY
&& cfg_ml.a2d[LUT_A].out_mux != MUX_F7
&& cfg_ml.a2d[LUT_A].ff_mux != MUX_O6
&& cfg_ml.a2d[LUT_A].ff_mux != MUX_XOR
&& cfg_ml.a2d[LUT_A].ff_mux != MUX_CY
&& cfg_ml.a2d[LUT_A].ff_mux != MUX_F7)
cfg_ml.a2d[LUT_A].out_used = 1;
lut5_used = (cfg_ml.a2d[LUT_A].ff_mux == MUX_O5
|| cfg_ml.a2d[LUT_A].out_mux == MUX_5Q
|| cfg_ml.a2d[LUT_A].out_mux == MUX_O5
|| cfg_ml.a2d[LUT_A].cy0 == CY0_O5);
rc = lut2str(lut_ML[LUT_A], l_col
? XC6_LMAP_XL_L_A : XC6_LMAP_XM_M_A,
lut5_used,
lut6_ml[LUT_A], &cfg_ml.a2d[LUT_A].lut6,
lut5_ml[LUT_A], &cfg_ml.a2d[LUT_A].lut5);
if (rc) FAIL(rc);
}
// ML-B
if (lut_ML[LUT_B]
|| !all_zero(&cfg_ml.a2d[LUT_B], sizeof(cfg_ml.a2d[LUT_B]))) {
if (lut_ML[LUT_B]
&& cfg_ml.a2d[LUT_B].out_mux != MUX_O6
&& cfg_ml.a2d[LUT_B].out_mux != MUX_XOR
&& cfg_ml.a2d[LUT_B].out_mux != MUX_CY
&& cfg_ml.a2d[LUT_B].out_mux != MUX_F7
&& cfg_ml.a2d[LUT_B].ff_mux != MUX_O6
&& cfg_ml.a2d[LUT_B].ff_mux != MUX_XOR
&& cfg_ml.a2d[LUT_B].ff_mux != MUX_CY
&& cfg_ml.a2d[LUT_B].ff_mux != MUX_F7)
cfg_ml.a2d[LUT_B].out_used = 1;
lut5_used = (cfg_ml.a2d[LUT_B].ff_mux == MUX_O5
|| cfg_ml.a2d[LUT_B].out_mux == MUX_5Q
|| cfg_ml.a2d[LUT_B].out_mux == MUX_O5
|| cfg_ml.a2d[LUT_B].cy0 == CY0_O5);
rc = lut2str(lut_ML[LUT_B], l_col
? XC6_LMAP_XL_L_B : XC6_LMAP_XM_M_B,
lut5_used,
lut6_ml[LUT_B], &cfg_ml.a2d[LUT_B].lut6,
lut5_ml[LUT_B], &cfg_ml.a2d[LUT_B].lut5);
if (rc) FAIL(rc);
}
// ML-C
if (lut_ML[LUT_C]
|| !all_zero(&cfg_ml.a2d[LUT_C], sizeof(cfg_ml.a2d[LUT_C]))) {
if (lut_ML[LUT_C]
&& cfg_ml.a2d[LUT_C].out_mux != MUX_O6
&& cfg_ml.a2d[LUT_C].out_mux != MUX_XOR
&& cfg_ml.a2d[LUT_C].out_mux != MUX_CY
&& cfg_ml.a2d[LUT_C].out_mux != MUX_F7
&& cfg_ml.a2d[LUT_C].ff_mux != MUX_O6
&& cfg_ml.a2d[LUT_C].ff_mux != MUX_XOR
&& cfg_ml.a2d[LUT_C].ff_mux != MUX_CY
&& cfg_ml.a2d[LUT_C].ff_mux != MUX_F7)
cfg_ml.a2d[LUT_C].out_used = 1;
lut5_used = (cfg_ml.a2d[LUT_C].ff_mux == MUX_O5
|| cfg_ml.a2d[LUT_C].out_mux == MUX_5Q
|| cfg_ml.a2d[LUT_C].out_mux == MUX_O5
|| cfg_ml.a2d[LUT_C].cy0 == CY0_O5);
rc = lut2str(lut_ML[LUT_C], l_col
? XC6_LMAP_XL_L_C : XC6_LMAP_XM_M_C,
lut5_used,
lut6_ml[LUT_C], &cfg_ml.a2d[LUT_C].lut6,
lut5_ml[LUT_C], &cfg_ml.a2d[LUT_C].lut5);
if (rc) FAIL(rc);
}
// ML-D
if (lut_ML[LUT_D]
|| !all_zero(&cfg_ml.a2d[LUT_D], sizeof(cfg_ml.a2d[LUT_D]))) {
if (lut_ML[LUT_D]
&& cfg_ml.a2d[LUT_D].out_mux != MUX_O6
&& cfg_ml.a2d[LUT_D].out_mux != MUX_XOR
&& cfg_ml.a2d[LUT_D].out_mux != MUX_CY
&& cfg_ml.a2d[LUT_D].out_mux != MUX_F7
&& cfg_ml.a2d[LUT_D].ff_mux != MUX_O6
&& cfg_ml.a2d[LUT_D].ff_mux != MUX_XOR
&& cfg_ml.a2d[LUT_D].ff_mux != MUX_CY
&& cfg_ml.a2d[LUT_D].ff_mux != MUX_F7)
cfg_ml.a2d[LUT_D].out_used = 1;
lut5_used = (cfg_ml.a2d[LUT_D].ff_mux == MUX_O5
|| cfg_ml.a2d[LUT_D].out_mux == MUX_5Q
|| cfg_ml.a2d[LUT_D].out_mux == MUX_O5
|| cfg_ml.a2d[LUT_D].cy0 == CY0_O5);
rc = lut2str(lut_ML[LUT_D], l_col
? XC6_LMAP_XL_L_D : XC6_LMAP_XM_M_D,
lut5_used,
lut6_ml[LUT_D], &cfg_ml.a2d[LUT_D].lut6,
lut5_ml[LUT_D], &cfg_ml.a2d[LUT_D].lut5);
if (rc) FAIL(rc);
}
// X-A
if (lut_X[LUT_A]
|| !all_zero(&cfg_x.a2d[LUT_A], sizeof(cfg_x.a2d[LUT_A]))) {
if (lut_X[LUT_A]
&& cfg_x.a2d[LUT_A].ff_mux != MUX_O6)
cfg_x.a2d[LUT_A].out_used = 1;
lut5_used = cfg_x.a2d[LUT_A].out_mux != 0;
rc = lut2str(lut_X[LUT_A], l_col
? XC6_LMAP_XL_X_A : XC6_LMAP_XM_X_A,
lut5_used,
lut6_x[LUT_A], &cfg_x.a2d[LUT_A].lut6,
lut5_x[LUT_A], &cfg_x.a2d[LUT_A].lut5);
if (rc) FAIL(rc);
}
// X-B
if (lut_X[LUT_B]
|| !all_zero(&cfg_x.a2d[LUT_B], sizeof(cfg_x.a2d[LUT_B]))) {
if (lut_X[LUT_B]
&& cfg_x.a2d[LUT_B].ff_mux != MUX_O6)
cfg_x.a2d[LUT_B].out_used = 1;
lut5_used = cfg_x.a2d[LUT_B].out_mux != 0;
rc = lut2str(lut_X[LUT_B], l_col
? XC6_LMAP_XL_X_B : XC6_LMAP_XM_X_B,
lut5_used,
lut6_x[LUT_B], &cfg_x.a2d[LUT_B].lut6,
lut5_x[LUT_B], &cfg_x.a2d[LUT_B].lut5);
if (rc) FAIL(rc);
}
// X-C
if (lut_X[LUT_C]
|| !all_zero(&cfg_x.a2d[LUT_C], sizeof(cfg_x.a2d[LUT_C]))) {
if (lut_X[LUT_C]
&& cfg_x.a2d[LUT_C].ff_mux != MUX_O6)
cfg_x.a2d[LUT_C].out_used = 1;
lut5_used = cfg_x.a2d[LUT_C].out_mux != 0;
rc = lut2str(lut_X[LUT_C], l_col
? XC6_LMAP_XL_X_C : XC6_LMAP_XM_X_C,
lut5_used,
lut6_x[LUT_C], &cfg_x.a2d[LUT_C].lut6,
lut5_x[LUT_C], &cfg_x.a2d[LUT_C].lut5);
if (rc) FAIL(rc);
}
// X-D
if (lut_X[LUT_D]
|| !all_zero(&cfg_x.a2d[LUT_D], sizeof(cfg_x.a2d[LUT_D]))) {
if (lut_X[LUT_D]
&& cfg_x.a2d[LUT_D].ff_mux != MUX_O6)
cfg_x.a2d[LUT_D].out_used = 1;
lut5_used = cfg_x.a2d[LUT_D].out_mux != 0;
rc = lut2str(lut_X[LUT_D], l_col
? XC6_LMAP_XL_X_D : XC6_LMAP_XM_X_D,
lut5_used,
lut6_x[LUT_D], &cfg_x.a2d[LUT_D].lut6,
lut5_x[LUT_D], &cfg_x.a2d[LUT_D].lut5);
if (rc) FAIL(rc);
}
//
// Step 7:
//
// Do more and final sanity checks before instantiation.
//
// todo: latch cannot be combined with out_mux=5Q or ff5_srinit
if (latch_ml
&& !cfg_ml.a2d[LUT_A].ff_mux
&& !cfg_ml.a2d[LUT_B].ff_mux
&& !cfg_ml.a2d[LUT_C].ff_mux
&& !cfg_ml.a2d[LUT_D].ff_mux) {
HERE();
continue;
}
if (latch_x
&& !cfg_x.a2d[LUT_A].ff_mux
&& !cfg_x.a2d[LUT_B].ff_mux
&& !cfg_x.a2d[LUT_C].ff_mux
&& !cfg_x.a2d[LUT_D].ff_mux) {
HERE();
continue;
}
// todo: latch and2l and or2l need to be determined
// from vcc connectivity, srinit etc.
for (lut = LUT_A; lut <= LUT_D; lut++) {
if (cfg_ml.a2d[lut].ff_mux) {
cfg_ml.a2d[lut].ff = latch_ml ? FF_LATCH : FF_FF;
if (!cfg_ml.a2d[lut].ff_srinit)
cfg_ml.a2d[lut].ff_srinit = FF_SRINIT0;
if (!cfg_ml.clk_inv)
cfg_ml.clk_inv = CLKINV_CLK;
if (!cfg_ml.sync_attr)
cfg_ml.sync_attr = SYNCATTR_ASYNC;
}
if (cfg_x.a2d[lut].ff_mux) {
cfg_x.a2d[lut].ff = latch_x ? FF_LATCH : FF_FF;
if (!cfg_x.a2d[lut].ff_srinit)
cfg_x.a2d[lut].ff_srinit = FF_SRINIT0;
if (!cfg_x.clk_inv)
cfg_x.clk_inv = CLKINV_CLK;
if (!cfg_x.sync_attr)
cfg_x.sync_attr = SYNCATTR_ASYNC;
}
// todo: ff5_srinit
// todo: 5Q ff also needs clock/sync check
}
// Check whether we should default to PRECYINIT_0
if (!cfg_ml.precyinit
&& (cfg_ml.a2d[LUT_A].out_mux == MUX_XOR
|| cfg_ml.a2d[LUT_A].ff_mux == MUX_XOR
|| cfg_ml.a2d[LUT_A].cy0)) {
int connpt_dests_o, num_dests, cout_y, cout_x;
str16_t cout_str;
if ((fpga_connpt_find(es->model, y, x,
dev_ml->pinw[LI_CIN], &connpt_dests_o,
&num_dests) == NO_CONN)
|| num_dests != 1) {
HERE();
} else {
fpga_conn_dest(es->model, y, x, connpt_dests_o,
&cout_y, &cout_x, &cout_str);
if (find_es_switch(es, cout_y, cout_x,fpga_switch_first(
es->model, cout_y, cout_x, cout_str, SW_TO)))
cfg_ml.precyinit = PRECYINIT_0;
}
}
//
// Step 8:
//
// Remove all bits.
//
frame_set_u64(u8_p + 20*FRAME_SIZE + byte_off,
frame_get_u64(u8_p + 20*FRAME_SIZE + byte_off)
& ~XC6_MI20_LOGIC_MASK);
last_minor = l_col ? 29 : 30;
for (i = 21; i <= last_minor; i++)
frame_set_u64(u8_p + i*FRAME_SIZE + byte_off, 0);
//
// Step 9:
//
// Instantiate configuration.
//
if (!all_zero(&cfg_ml, sizeof(cfg_ml))) {
rc = fdev_logic_setconf(es->model, y, x, DEV_LOG_M_OR_L, &cfg_ml);
if (rc) FAIL(rc);
}
if (!all_zero(&cfg_x, sizeof(cfg_x))) {
rc = fdev_logic_setconf(es->model, y, x, DEV_LOG_X, &cfg_x);
if (rc) FAIL(rc);
}
}
}
return 0;
fail:
return rc;
}
static int bitpos_is_set(struct extract_state *es, int y, int x,
struct xc6_routing_bitpos *swpos, int *is_set)
{
int row_num, row_pos, start_in_frame, two_bits_val, rc;
RC_CHECK(es->model);
*is_set = 0;
is_in_row(es->model, y, &row_num, &row_pos);
if (row_num == -1 || row_pos == -1
|| row_pos == HCLK_POS) FAIL(EINVAL);
if (row_pos > HCLK_POS)
start_in_frame = (row_pos-1)*64 + 16;
else
start_in_frame = row_pos*64;
if (swpos->minor == 20) {
two_bits_val = ((get_bit(es->bits, row_num, es->model->x_major[x],
20, start_in_frame + swpos->two_bits_o) != 0) << 1)
| ((get_bit(es->bits, row_num, es->model->x_major[x],
20, start_in_frame + swpos->two_bits_o+1) != 0) << 0);
if (two_bits_val != swpos->two_bits_val)
return 0;
if (!get_bit(es->bits, row_num, es->model->x_major[x], 20,
start_in_frame + swpos->one_bit_o))
return 0;
} else {
two_bits_val =
((get_bit(es->bits, row_num, es->model->x_major[x], swpos->minor,
start_in_frame + swpos->two_bits_o/2) != 0) << 1)
| ((get_bit(es->bits, row_num, es->model->x_major[x], swpos->minor+1,
start_in_frame + swpos->two_bits_o/2) != 0) << 0);
if (two_bits_val != swpos->two_bits_val)
return 0;
if (!get_bit(es->bits, row_num, es->model->x_major[x],
swpos->minor + (swpos->one_bit_o&1),
start_in_frame + swpos->one_bit_o/2))
return 0;
}
*is_set = 1;
return 0;
fail:
return rc;
}
static int bitpos_clear_bits(struct extract_state* es, int y, int x,
struct xc6_routing_bitpos* swpos)
{
int row_num, row_pos, start_in_frame, rc;
RC_CHECK(es->model);
is_in_row(es->model, y, &row_num, &row_pos);
if (row_num == -1 || row_pos == -1
|| row_pos == HCLK_POS) FAIL(EINVAL);
if (row_pos > HCLK_POS)
start_in_frame = (row_pos-1)*64 + 16;
else
start_in_frame = row_pos*64;
if (swpos->minor == 20) {
clear_bit(es->bits, row_num, es->model->x_major[x], swpos->minor,
start_in_frame + swpos->two_bits_o);
clear_bit(es->bits, row_num, es->model->x_major[x], swpos->minor,
start_in_frame + swpos->two_bits_o+1);
clear_bit(es->bits, row_num, es->model->x_major[x], swpos->minor,
start_in_frame + swpos->one_bit_o);
} else {
clear_bit(es->bits, row_num, es->model->x_major[x], swpos->minor,
start_in_frame + swpos->two_bits_o/2);
clear_bit(es->bits, row_num, es->model->x_major[x], swpos->minor + 1,
start_in_frame + swpos->two_bits_o/2);
clear_bit(es->bits, row_num, es->model->x_major[x], swpos->minor + (swpos->one_bit_o&1),
start_in_frame + swpos->one_bit_o/2);
}
return 0;
fail:
return rc;
}
static int bitpos_set_bits(struct fpga_bits* bits, struct fpga_model* model,
int y, int x, struct xc6_routing_bitpos* swpos)
{
int row_num, row_pos, start_in_frame, rc;
RC_CHECK(model);
is_in_row(model, y, &row_num, &row_pos);
if (row_num == -1 || row_pos == -1
|| row_pos == HCLK_POS) FAIL(EINVAL);
if (row_pos > HCLK_POS)
start_in_frame = (row_pos-1)*64 + 16;
else
start_in_frame = row_pos*64;
if (swpos->minor == 20) {
if (swpos->two_bits_val & 0x02)
set_bit(bits, row_num, model->x_major[x], swpos->minor,
start_in_frame + swpos->two_bits_o);
if (swpos->two_bits_val & 0x01)
set_bit(bits, row_num, model->x_major[x], swpos->minor,
start_in_frame + swpos->two_bits_o+1);
set_bit(bits, row_num, model->x_major[x], swpos->minor,
start_in_frame + swpos->one_bit_o);
} else {
if (swpos->two_bits_val & 0x02)
set_bit(bits, row_num, model->x_major[x], swpos->minor,
start_in_frame + swpos->two_bits_o/2);
if (swpos->two_bits_val & 0x01)
set_bit(bits, row_num, model->x_major[x], swpos->minor + 1,
start_in_frame + swpos->two_bits_o/2);
set_bit(bits, row_num, model->x_major[x], swpos->minor + (swpos->one_bit_o&1),
start_in_frame + swpos->one_bit_o/2);
}
return 0;
fail:
return rc;
}
static int extract_routing_switches(struct extract_state* es, int y, int x)
{
struct fpga_tile* tile;
swidx_t sw_idx;
int i, is_set, rc;
RC_CHECK(es->model);
tile = YX_TILE(es->model, y, x);
for (i = 0; i < es->model->num_bitpos; i++) {
rc = bitpos_is_set(es, y, x, &es->model->sw_bitpos[i], &is_set);
if (rc) RC_FAIL(es->model, rc);
if (!is_set) continue;
sw_idx = fpga_switch_lookup(es->model, y, x,
fpga_wire2str_i(es->model, es->model->sw_bitpos[i].from),
fpga_wire2str_i(es->model, es->model->sw_bitpos[i].to));
if (sw_idx == NO_SWITCH) RC_FAIL(es->model, EINVAL);
// todo: es->model->sw_bitpos[i].bidir handling
if (tile->switches[sw_idx] & SWITCH_BIDIRECTIONAL)
HERE();
if (tile->switches[sw_idx] & SWITCH_USED)
HERE();
if (es->num_yx_pos >= MAX_YX_SWITCHES)
{ RC_FAIL(es->model, ENOTSUP); }
es->yx_pos[es->num_yx_pos].y = y;
es->yx_pos[es->num_yx_pos].x = x;
es->yx_pos[es->num_yx_pos].idx = sw_idx;
es->num_yx_pos++;
rc = bitpos_clear_bits(es, y, x, &es->model->sw_bitpos[i]);
if (rc) RC_FAIL(es->model, rc);
}
RC_RETURN(es->model);
}
static int extract_logic_switches(struct extract_state* es, int y, int x)
{
int row, row_pos, byte_off, minor, rc;
uint8_t* u8_p;
RC_CHECK(es->model);
row = which_row(y, es->model);
row_pos = pos_in_row(y, es->model);
if (row == -1 || row_pos == -1 || row_pos == 8) FAIL(EINVAL);
if (row_pos > 8) row_pos--;
u8_p = get_first_minor(es->bits, row, es->model->x_major[x]);
byte_off = row_pos * 8;
if (row_pos >= 8) byte_off += XC6_HCLK_BYTES;
if (has_device_type(es->model, y, x, DEV_LOGIC, LOGIC_M))
minor = 26;
else if (has_device_type(es->model, y, x, DEV_LOGIC, LOGIC_L))
minor = 25;
else
FAIL(EINVAL);
if (frame_get_bit(u8_p + minor*FRAME_SIZE, byte_off*8 + XC6_ML_CIN_USED)) {
struct fpga_device* dev;
int connpt_dests_o, num_dests, cout_y, cout_x;
str16_t cout_str;
swidx_t cout_sw;
dev = fdev_p(es->model, y, x, DEV_LOGIC, DEV_LOG_M_OR_L);
if (!dev) FAIL(EINVAL);
if ((fpga_connpt_find(es->model, y, x,
dev->pinw[LI_CIN], &connpt_dests_o,
&num_dests) == NO_CONN)
|| num_dests != 1) {
HERE();
} else {
fpga_conn_dest(es->model, y, x, connpt_dests_o,
&cout_y, &cout_x, &cout_str);
cout_sw = fpga_switch_first(es->model, cout_y,
cout_x, cout_str, SW_TO);
if (cout_sw == NO_SWITCH) HERE();
else {
if (es->num_yx_pos >= MAX_YX_SWITCHES)
{ FAIL(ENOTSUP); }
es->yx_pos[es->num_yx_pos].y = cout_y;
es->yx_pos[es->num_yx_pos].x = cout_x;
es->yx_pos[es->num_yx_pos].idx = cout_sw;
es->num_yx_pos++;
frame_clear_bit(u8_p + minor*FRAME_SIZE,
byte_off*8 + XC6_ML_CIN_USED);
}
}
}
return 0;
fail:
return rc;
}
#define MAX_IOLOGIC_SWBLOCK 4
#define MAX_IOLOGIC_BITS 4
struct iologic_sw_pos
{
const char* to[MAX_IOLOGIC_SWBLOCK];
const char* from[MAX_IOLOGIC_SWBLOCK];
int minor[MAX_IOLOGIC_BITS];
int b64[MAX_IOLOGIC_BITS];
};
// todo: can we assume the maximum range for iologic
// minors to be 21..29? that would be a total of
// 9*64=675 bits for ilogic/ologic/iodelay?
struct iologic_sw_pos s_left_io_swpos[] = { {{0}} };
struct iologic_sw_pos s_right_io_swpos[] = { {{0}} };
struct iologic_sw_pos s_top_outer_io_swpos[] = { {{0}} };
struct iologic_sw_pos s_top_inner_io_swpos[] = { {{0}} };
struct iologic_sw_pos s_bot_inner_io_swpos[] =
{
// input
{{"D_ILOGIC_IDATAIN_IODELAY_S"},
{"BIOI_INNER_IBUF0"},
{23, 23, -1},
{28, 29}},
{{"D_ILOGIC_SITE"},
{"D_ILOGIC_IDATAIN_IODELAY"},
{26, -1},
{20}},
{{"D_ILOGIC_SITE_S"},
{"D_ILOGIC_IDATAIN_IODELAY_S"},
{26, -1},
{23}},
{{"DFB_ILOGIC_SITE"},
{"D_ILOGIC_SITE"},
{28, -1},
{63}},
{{"DFB_ILOGIC_SITE_S"},
{"D_ILOGIC_SITE_S"},
{28, -1},
{0}},
{{"FABRICOUT_ILOGIC_SITE"},
{"D_ILOGIC_SITE"},
{29, -1},
{49}},
{{"FABRICOUT_ILOGIC_SITE_S"},
{"D_ILOGIC_SITE_S"},
{29, -1},
{14}},
// output
{{"OQ_OLOGIC_SITE", "BIOI_INNER_O0"},
{"D1_OLOGIC_SITE", "OQ_OLOGIC_SITE"},
{26, 27, 28, -1},
{40, 21, 57}},
{{"OQ_OLOGIC_SITE_S", "BIOI_INNER_O1"},
{"D1_OLOGIC_SITE_S", "OQ_OLOGIC_SITE_S"},
{26, 27, 28, -1},
{43, 56, 6}},
{{"IOI_LOGICOUT0"}, {"IOI_INTER_LOGICOUT0"}, {-1}},
{{"IOI_LOGICOUT7"}, {"IOI_INTER_LOGICOUT7"}, {-1}},
{{"IOI_INTER_LOGICOUT0"}, {"FABRICOUT_ILOGIC_SITE"}, {-1}},
{{"IOI_INTER_LOGICOUT7"}, {"FABRICOUT_ILOGIC_SITE_S"}, {-1}},
{{"D_ILOGIC_IDATAIN_IODELAY"}, {"BIOI_INNER_IBUF0"}, {-1}},
{{"D_ILOGIC_IDATAIN_IODELAY_S"}, {"BIOI_INNER_IBUF1"}, {-1}},
{{"D1_OLOGIC_SITE"}, {"IOI_LOGICINB31"}, {-1}},
{{0}}
};
struct iologic_sw_pos s_bot_outer_io_swpos[] =
{
// input
{{"D_ILOGIC_IDATAIN_IODELAY_S"},
{"BIOI_OUTER_IBUF0"},
{23, 23, -1},
{28, 29}},
{{"D_ILOGIC_SITE"},
{"D_ILOGIC_IDATAIN_IODELAY"},
{26, -1},
{20}},
{{"D_ILOGIC_SITE_S"},
{"D_ILOGIC_IDATAIN_IODELAY_S"},
{26, -1},
{23}},
{{"DFB_ILOGIC_SITE"},
{"D_ILOGIC_SITE"},
{28, -1},
{63}},
{{"DFB_ILOGIC_SITE_S"},
{"D_ILOGIC_SITE_S"},
{28, -1},
{0}},
{{"FABRICOUT_ILOGIC_SITE"},
{"D_ILOGIC_SITE"},
{29, -1},
{49}},
{{"FABRICOUT_ILOGIC_SITE_S"},
{"D_ILOGIC_SITE_S"},
{29, -1},
{14}},
// output
{{"OQ_OLOGIC_SITE", "BIOI_OUTER_O0"},
{"D1_OLOGIC_SITE", "OQ_OLOGIC_SITE"},
{26, 27, 28, -1},
{40, 21, 57}},
{{"OQ_OLOGIC_SITE_S", "BIOI_OUTER_O1"},
{"D1_OLOGIC_SITE_S", "OQ_OLOGIC_SITE_S"},
{26, 27, 28, -1},
{43, 56, 6}},
{{"IOI_LOGICOUT0"}, {"IOI_INTER_LOGICOUT0"}, {-1}},
{{"IOI_LOGICOUT7"}, {"IOI_INTER_LOGICOUT7"}, {-1}},
{{"IOI_INTER_LOGICOUT0"}, {"FABRICOUT_ILOGIC_SITE"}, {-1}},
{{"IOI_INTER_LOGICOUT7"}, {"FABRICOUT_ILOGIC_SITE_S"}, {-1}},
{{"D_ILOGIC_IDATAIN_IODELAY"}, {"BIOI_INNER_IBUF0"}, {-1}},
{{"D_ILOGIC_IDATAIN_IODELAY_S"}, {"BIOI_INNER_IBUF1"}, {-1}},
{{"D1_OLOGIC_SITE"}, {"IOI_LOGICINB31"}, {-1}},
{{0}}
};
static int add_yx_switch(struct extract_state *es,
int y, int x, const char *from, const char *to)
{
str16_t from_str_i, to_str_i;
swidx_t sw_idx;
RC_CHECK(es->model);
from_str_i = strarray_find(&es->model->str, from);
to_str_i = strarray_find(&es->model->str, to);
RC_ASSERT(es->model, from_str_i != STRIDX_NO_ENTRY
&& to_str_i != STRIDX_NO_ENTRY);
sw_idx = fpga_switch_lookup(es->model, y, x,
from_str_i, to_str_i);
RC_ASSERT(es->model, sw_idx != NO_SWITCH);
RC_ASSERT(es->model, es->num_yx_pos < MAX_YX_SWITCHES);
es->yx_pos[es->num_yx_pos].y = y;
es->yx_pos[es->num_yx_pos].x = x;
es->yx_pos[es->num_yx_pos].idx = sw_idx;
es->num_yx_pos++;
RC_RETURN(es->model);
}
static int extract_iologic_switches(struct extract_state* es, int y, int x)
{
int row_num, row_pos, bit_in_frame, i, j, rc;
uint8_t* minor0_p;
struct iologic_sw_pos* sw_pos;
RC_CHECK(es->model);
// From y/x coordinate, determine major, row, bit offset
// in frame (v64_i) and pointer to first minor.
is_in_row(es->model, y, &row_num, &row_pos);
if (row_num == -1 || row_pos == -1
|| row_pos == HCLK_POS) FAIL(EINVAL);
if (row_pos > HCLK_POS)
bit_in_frame = (row_pos-1)*64 + XC6_HCLK_BITS;
else
bit_in_frame = row_pos*64;
minor0_p = get_first_minor(es->bits, row_num, es->model->x_major[x]);
if (x < LEFT_SIDE_WIDTH) {
if (x != LEFT_IO_DEVS) FAIL(EINVAL);
sw_pos = s_left_io_swpos;
} else if (x >= es->model->x_width-RIGHT_SIDE_WIDTH) {
if (x != es->model->x_width - RIGHT_IO_DEVS_O) FAIL(EINVAL);
sw_pos = s_right_io_swpos;
} else if (y == TOP_OUTER_IO)
sw_pos = s_top_outer_io_swpos;
else if (y == TOP_INNER_IO)
sw_pos = s_top_inner_io_swpos;
else if (y == es->model->y_height-BOT_INNER_IO)
sw_pos = s_bot_inner_io_swpos;
else if (y == es->model->y_height-BOT_OUTER_IO)
sw_pos = s_bot_outer_io_swpos;
else FAIL(EINVAL);
// Go through switches
for (i = 0; sw_pos[i].to[0]; i++) {
for (j = 0; sw_pos[i].minor[j] != -1; j++) {
if (!frame_get_bit(&minor0_p[sw_pos[i].minor[j]
*FRAME_SIZE], bit_in_frame+sw_pos[i].b64[j]))
break;
}
if (!j || sw_pos[i].minor[j] != -1)
continue;
for (j = 0; j < MAX_IOLOGIC_SWBLOCK && sw_pos[i].to[j]; j++)
add_yx_switch(es, y, x, sw_pos[i].from[j], sw_pos[i].to[j]);
for (j = 0; sw_pos[i].minor[j] != -1; j++)
frame_clear_bit(&minor0_p[sw_pos[i].minor[j]
*FRAME_SIZE], bit_in_frame+sw_pos[i].b64[j]);
}
// todo: we could implement an all-or-nothing system where
// the device bits are first copied into an u64 array,
// and switches rewound by resetting num_yx_pos - unless
// all bits have been processed...
return 0;
fail:
return rc;
}
static int extract_center_switches(struct extract_state *es)
{
int center_row, center_major, word, i;
uint8_t *minor_p;
RC_CHECK(es->model);
center_row = es->model->die->num_rows/2;
center_major = xc_die_center_major(es->model->die);
minor_p = get_first_minor(es->bits, center_row,
center_major) + XC6_CENTER_GCLK_MINOR*FRAME_SIZE;
word = frame_get_pinword(minor_p + 15*8+XC6_HCLK_BYTES);
if (word) {
for (i = 0; i < 16; i++) {
if (!(word & (1<model->center_y, es->model->center_x,
pf("CLKC_CKLR%i", i), pf("CLKC_GCLK%i", i));
}
frame_set_pinword(minor_p + 15*8+XC6_HCLK_BYTES, 0);
}
word = frame_get_pinword(minor_p + 15*8+XC6_HCLK_BYTES + XC6_WORD_BYTES);
if (word) {
for (i = 0; i < 16; i++) {
if (!(word & (1<model->center_y, es->model->center_x,
pf("CLKC_CKTB%i", i), pf("CLKC_GCLK%i", i));
}
frame_set_pinword(minor_p + 15*8+XC6_HCLK_BYTES + XC6_WORD_BYTES, 0);
}
RC_RETURN(es->model);
}
static int write_center_sw(struct fpga_bits *bits,
struct fpga_model *model, int y, int x)
{
struct fpga_tile *tile;
const char *from_str, *to_str;
int center_row, center_major, word;
int i, j, gclk_pin_from, gclk_pin_to;
uint8_t *minor_p;
RC_CHECK(model);
center_row = model->die->num_rows/2;
center_major = xc_die_center_major(model->die);
minor_p = get_first_minor(bits, center_row,
center_major) + XC6_CENTER_GCLK_MINOR*FRAME_SIZE;
tile = YX_TILE(model, y, x);
for (i = 0; i < tile->num_switches; i++) {
if (!(tile->switches[i] & SWITCH_USED))
continue;
from_str = fpga_switch_str(model, y, x, i, SW_FROM);
to_str = fpga_switch_str(model, y, x, i, SW_TO);
RC_ASSERT(model, from_str && to_str);
j = sscanf(from_str, "CLKC_CKLR%i", &gclk_pin_from);
if (j == 1) {
j = sscanf(to_str, "CLKC_GCLK%i", &gclk_pin_to);
RC_ASSERT(model, j == 1 && gclk_pin_to == gclk_pin_from);
word = frame_get_pinword(minor_p + 15*8+XC6_HCLK_BYTES);
word |= 1 << gclk_pin_from;
frame_set_pinword(minor_p + 15*8+XC6_HCLK_BYTES, word);
continue;
}
j = sscanf(from_str, "CLKC_CKTB%i", &gclk_pin_from);
if (j == 1) {
j = sscanf(to_str, "CLKC_GCLK%i", &gclk_pin_to);
RC_ASSERT(model, j == 1 && gclk_pin_to == gclk_pin_from);
word = frame_get_pinword(minor_p + 15*8+XC6_HCLK_BYTES + XC6_WORD_BYTES);
word |= 1 << gclk_pin_from;
frame_set_pinword(minor_p + 15*8+XC6_HCLK_BYTES + XC6_WORD_BYTES, word);
continue;
}
// todo: it's possible that other switches need bits
// todo: we can manually detect used switches that do not
// need bits, such as
// I0_GCLK_SITE0:15 -> O_GCLK_SITE0:15
// O_GCLK_SITE0:15 -> CLKC_GCLK_MAIN0:15
// CLKC_GCLK%i -> I0_GCLK_SITE%i
}
RC_RETURN(model);
}
static int extract_gclk_center_vert_sw(struct extract_state *es)
{
int word, cur_row, cur_minor, cur_pin, i, hclk_y;
uint8_t *ma0_bits;
RC_CHECK(es->model);
// Switches in the vertical center column that are routing gclk
// signals to the left and right side of the chip.
for (cur_row = 0; cur_row < es->model->die->num_rows; cur_row++) {
hclk_y = row_to_hclk(cur_row, es->model);
RC_ASSERT(es->model, hclk_y != -1);
ma0_bits = get_first_minor(es->bits, cur_row, XC6_NULL_MAJOR);
for (cur_minor = 0; cur_minor <= 2; cur_minor++) {
// left
word = frame_get_pinword(ma0_bits + cur_minor*FRAME_SIZE + 8*8+XC6_HCLK_BYTES);
if (word) {
for (i = 0; i <= 16/3; i++) { // 0-5
cur_pin = cur_minor + i*3;
if (cur_pin > 15) break;
if (!(word & (1<model->center_x,
pf("CLKV_GCLKH_MAIN%i_FOLD", cur_pin),
pf("CLKV_GCLKH_L%i", cur_pin));
word &= ~(1< 15) break;
if (!(word & (1<model->center_x,
pf("CLKV_GCLKH_MAIN%i_FOLD", cur_pin),
pf("CLKV_GCLKH_R%i", cur_pin));
word &= ~(1<model);
}
static int write_gclk_center_vert_sw(struct fpga_bits *bits,
struct fpga_model *model, int y, int x)
{
struct fpga_tile *tile;
const char *from_str, *to_str;
int i, j, gclk_pin_from, gclk_pin_to, cur_pin, cur_minor, minor_found, word;
uint8_t *ma0_bits;
RC_CHECK(model);
ma0_bits = get_first_minor(bits, which_row(y, model), XC6_NULL_MAJOR);
RC_ASSERT(model, ma0_bits);
tile = YX_TILE(model, y, x);
for (i = 0; i < tile->num_switches; i++) {
if (!(tile->switches[i] & SWITCH_USED))
continue;
from_str = fpga_switch_str(model, y, x, i, SW_FROM);
to_str = fpga_switch_str(model, y, x, i, SW_TO);
RC_ASSERT(model, from_str && to_str);
// left
j = sscanf(from_str, "CLKV_GCLKH_MAIN%i_FOLD", &gclk_pin_from);
if (j == 1) {
j = sscanf(to_str, "CLKV_GCLKH_L%i", &gclk_pin_to);
RC_ASSERT(model, j == 1 && gclk_pin_to == gclk_pin_from);
minor_found = -1;
for (cur_minor = 0; minor_found == -1 && cur_minor <= 2; cur_minor++) {
for (j = 0; j <= 16/3; j++) { // 0-5
cur_pin = cur_minor + j*3;
if (cur_pin > 15) break;
if (cur_pin == gclk_pin_from) {
minor_found = cur_minor;
break;
}
}
}
if (minor_found != -1) {
word = frame_get_pinword(ma0_bits + minor_found*FRAME_SIZE + 8*8+XC6_HCLK_BYTES);
word |= 1 << gclk_pin_from;
frame_set_pinword(ma0_bits + minor_found*FRAME_SIZE + 8*8+XC6_HCLK_BYTES, word);
continue;
}
HERE(); // fall-through to unsupported
}
// right
j = sscanf(from_str, "CLKV_GCLKH_MAIN%i_FOLD", &gclk_pin_from);
if (j == 1) {
j = sscanf(to_str, "CLKV_GCLKH_R%i", &gclk_pin_to);
RC_ASSERT(model, j == 1 && gclk_pin_to == gclk_pin_from);
minor_found = -1;
for (cur_minor = 0; minor_found == -1 && cur_minor <= 2; cur_minor++) {
for (j = 0; j <= 16/3; j++) { // 0-5
cur_pin = cur_minor + j*3;
if (cur_pin > 15) break;
if (cur_pin == gclk_pin_from) {
minor_found = cur_minor;
break;
}
}
}
if (minor_found != -1) {
word = frame_get_pinword(ma0_bits + minor_found*FRAME_SIZE + 8*8+XC6_HCLK_BYTES + 4);
word |= 1 << gclk_pin_from;
frame_set_pinword(ma0_bits + minor_found*FRAME_SIZE + 8*8+XC6_HCLK_BYTES + 4, word);
continue;
}
HERE(); // fall-through to unsupported
}
// todo: we can manually detect used switches that do not
// need bits, such as
// CLKV_GCLKH_L0:15 -> I_BUFH_LEFT_SITE0:15
// I_BUFH_LEFT_SITE0:15 -> O_BUFH_LEFT_SITE0:15
// O_BUFH_LEFT_SITE0:15 -> CLKV_BUFH_LEFT_L0:15
}
RC_RETURN(model);
}
static int extract_gclk_hclk_updown_sw(struct extract_state *es)
{
int word, cur_row, x, gclk_pin, hclk_y;
uint8_t *mi0_bits;
RC_CHECK(es->model);
// Switches in each horizontal hclk row that are routing
// gclk signals and and down to the clocked devices.
// todo: clk access in left and right IO devs, center devs,
// bram and macc devs as well as special devs not tested
// yet (only XM logic devs tested).
for (cur_row = 0; cur_row < es->model->die->num_rows; cur_row++) {
hclk_y = row_to_hclk(cur_row, es->model);
RC_ASSERT(es->model, hclk_y != -1);
for (x = LEFT_IO_ROUTING; x <= es->model->x_width-RIGHT_IO_ROUTING_O; x++) {
if (!is_atx(X_ROUTING_COL, es->model, x))
continue;
mi0_bits = get_first_minor(es->bits, cur_row, es->model->x_major[x]);
// each minor (0:15) stores the configuration bits for one gclk
// pin (in the hclk bytes of the minor)
for (gclk_pin = 0; gclk_pin <= 15; gclk_pin++) {
word = frame_get_pinword(mi0_bits + gclk_pin*FRAME_SIZE + XC6_HCLK_POS);
if (word & (1<model);
}
static int write_hclk_sw(struct fpga_bits *bits, struct fpga_model *model,
int y, int x)
{
uint8_t *mi0_bits;
struct fpga_tile *tile;
const char *from_str, *to_str;
int i, j, gclk_pin_from, gclk_pin_to, up, word;
RC_CHECK(model);
mi0_bits = get_first_minor(bits, which_row(y, model), model->x_major[x]);
RC_ASSERT(model, mi0_bits);
tile = YX_TILE(model, y, x);
for (i = 0; i < tile->num_switches; i++) {
if (!(tile->switches[i] & SWITCH_USED))
continue;
from_str = fpga_switch_str(model, y, x, i, SW_FROM);
to_str = fpga_switch_str(model, y, x, i, SW_TO);
j = sscanf(from_str, "HCLK_GCLK%i_INT", &gclk_pin_from);
RC_ASSERT(model, j == 1);
j = sscanf(to_str, "HCLK_GCLK%i", &gclk_pin_to);
if (j == 1)
up = 0; // down
else {
j = sscanf(to_str, "HCLK_GCLK_UP%i", &gclk_pin_to);
RC_ASSERT(model, j == 1);
up = 1;
}
RC_ASSERT(model, gclk_pin_from == gclk_pin_to);
word = frame_get_pinword(mi0_bits + gclk_pin_from*FRAME_SIZE + XC6_HCLK_POS);
word |= 1 << (up ? XC6_HCLK_GCLK_UP_PIN : XC6_HCLK_GCLK_DOWN_PIN);
frame_set_pinword(mi0_bits + gclk_pin_from*FRAME_SIZE + XC6_HCLK_POS, word);
}
RC_RETURN(model);
}
static int extract_switches(struct extract_state *es)
{
int x, y;
RC_CHECK(es->model);
for (x = 0; x < es->model->x_width; x++) {
for (y = 0; y < es->model->y_height; y++) {
// routing switches
if (is_atx(X_ROUTING_COL, es->model, x)
&& y >= TOP_IO_TILES
&& y < es->model->y_height-BOT_IO_TILES
&& !is_aty(Y_ROW_HORIZ_AXSYMM|Y_CHIP_HORIZ_REGS,
es->model, y)) {
extract_routing_switches(es, y, x);
}
// logic switches
if (has_device(es->model, y, x, DEV_LOGIC)) {
extract_logic_switches(es, y, x);
}
// iologic switches
if (has_device(es->model, y, x, DEV_ILOGIC)) {
extract_iologic_switches(es, y, x);
}
}
}
extract_center_switches(es);
extract_gclk_center_vert_sw(es);
extract_gclk_hclk_updown_sw(es);
RC_RETURN(es->model);
}
static int construct_extract_state(struct extract_state* es,
struct fpga_model* model)
{
RC_CHECK(model);
memset(es, 0, sizeof(*es));
es->model = model;
return 0;
}
int extract_model(struct fpga_model* model, struct fpga_bits* bits)
{
struct extract_state es;
net_idx_t net_idx;
int i, rc;
RC_CHECK(model);
rc = construct_extract_state(&es, model);
if (rc) RC_FAIL(model, rc);
es.bits = bits;
for (i = 0; i < sizeof(s_default_bits)/sizeof(s_default_bits[0]); i++) {
if (!get_bitp(bits, &s_default_bits[i]))
RC_FAIL(model, EINVAL);
clear_bitp(bits, &s_default_bits[i]);
}
rc = extract_switches(&es);
if (rc) RC_FAIL(model, rc);
rc = extract_type2(&es);
if (rc) RC_FAIL(model, rc);
rc = extract_logic(&es);
if (rc) RC_FAIL(model, rc);
// turn switches into nets
if (model->nets)
HERE(); // should be empty here
for (i = 0; i < es.num_yx_pos; i++) {
rc = fnet_new(model, &net_idx);
if (rc) RC_FAIL(model, rc);
rc = fnet_add_sw(model, net_idx, es.yx_pos[i].y,
es.yx_pos[i].x, &es.yx_pos[i].idx, 1);
if (rc) RC_FAIL(model, rc);
}
RC_RETURN(model);
}
int printf_swbits(struct fpga_model* model)
{
char bit_str[129];
int i, j, width;
RC_CHECK(model);
for (i = 0; i < model->num_bitpos; i++) {
width = (model->sw_bitpos[i].minor == 20) ? 64 : 128;
for (j = 0; j < width; j++)
bit_str[j] = '0';
bit_str[j] = 0;
if (model->sw_bitpos[i].two_bits_val & 2)
bit_str[model->sw_bitpos[i].two_bits_o] = '1';
if (model->sw_bitpos[i].two_bits_val & 1)
bit_str[model->sw_bitpos[i].two_bits_o+1] = '1';
bit_str[model->sw_bitpos[i].one_bit_o] = '1';
printf("mi%02i %s %s %s %s\n", model->sw_bitpos[i].minor,
fpga_wire2str(model->sw_bitpos[i].to),
bit_str,
fpga_wire2str(model->sw_bitpos[i].from),
model->sw_bitpos[i].bidir ? "<->" : "->");
}
RC_RETURN(model);
}
static int find_bitpos(struct fpga_model* model, int y, int x, swidx_t sw)
{
enum extra_wires from_w, to_w;
const char* from_str, *to_str;
int i;
RC_CHECK(model);
from_str = fpga_switch_str(model, y, x, sw, SW_FROM);
to_str = fpga_switch_str(model, y, x, sw, SW_TO);
from_w = fpga_str2wire(from_str);
to_w = fpga_str2wire(to_str);
if (from_w == NO_WIRE || to_w == NO_WIRE) {
HERE();
return -1;
}
for (i = 0; i < model->num_bitpos; i++) {
if (model->sw_bitpos[i].from == from_w
&& model->sw_bitpos[i].to == to_w)
return i;
if (model->sw_bitpos[i].bidir
&& model->sw_bitpos[i].to == from_w
&& model->sw_bitpos[i].from == to_w) {
if (!fpga_switch_is_bidir(model, y, x, sw))
HERE();
return i;
}
}
fprintf(stderr, "#E switch %s (%i) to %s (%i) not in model\n",
from_str, from_w, to_str, to_w);
return -1;
}
static int write_routing_sw(struct fpga_bits* bits, struct fpga_model* model, int y, int x)
{
struct fpga_tile* tile;
int i, bit_pos, rc;
RC_CHECK(model);
// go through enabled switches, lookup in sw_bitpos
// and set bits
tile = YX_TILE(model, y, x);
for (i = 0; i < tile->num_switches; i++) {
if (!(tile->switches[i] & SWITCH_USED))
continue;
bit_pos = find_bitpos(model, y, x, i);
if (bit_pos == -1) {
HERE();
continue;
}
rc = bitpos_set_bits(bits, model, y, x,
&model->sw_bitpos[bit_pos]);
if (rc) FAIL(rc);
}
return 0;
fail:
return rc;
}
struct str_sw
{
const char* from_str;
const char* to_str;
};
static int get_used_switches(struct fpga_model* model, int y, int x,
struct str_sw** str_sw, int* num_sw)
{
int i, num_used, rc;
struct fpga_tile* tile;
RC_CHECK(model);
tile = YX_TILE(model, y, x);
num_used = 0;
for (i = 0; i < tile->num_switches; i++) {
if (tile->switches[i] & SWITCH_USED)
num_used++;
}
if (!num_used) {
*num_sw = 0;
*str_sw = 0;
return 0;
}
*str_sw = malloc(num_used * sizeof(**str_sw));
if (!(*str_sw)) FAIL(ENOMEM);
*num_sw = 0;
for (i = 0; i < tile->num_switches; i++) {
if (!(tile->switches[i] & SWITCH_USED))
continue;
(*str_sw)[*num_sw].from_str =
fpga_switch_str(model, y, x, i, SW_FROM);
(*str_sw)[*num_sw].to_str =
fpga_switch_str(model, y, x, i, SW_TO);
(*num_sw)++;
}
return 0;
fail:
return rc;
}
// returns the number of found to-from pairs from search_sw that
// were found in the str_sw array, but only if all of the to-from
// pairs in search_sw were found. The found array then contains
// the indices into str_sw were the matches were made.
// If not all to-from pairs were found (or none), returns 0.
static int find_switches(struct iologic_sw_pos* search_sw,
struct str_sw* str_sw, int num_str_sw, int (*found)[MAX_IOLOGIC_SWBLOCK])
{
int i, j;
for (i = 0; i < MAX_IOLOGIC_SWBLOCK && search_sw->to[i]; i++) {
for (j = 0; j < num_str_sw; j++) {
if (!str_sw[j].to_str)
continue;
if (strcmp(str_sw[j].to_str, search_sw->to[i])
|| strcmp(str_sw[j].from_str, search_sw->from[i]))
continue;
(*found)[i] = j;
break;
}
if (j >= num_str_sw)
return 0;
}
return i;
}
static int write_iologic_sw(struct fpga_bits* bits, struct fpga_model* model,
int y, int x)
{
int i, j, row_num, row_pos, start_in_frame, rc;
struct iologic_sw_pos* sw_pos;
struct str_sw* str_sw;
int found_i[MAX_IOLOGIC_SWBLOCK];
int num_sw, num_found;
RC_CHECK(model);
if (x < LEFT_SIDE_WIDTH) {
if (x != LEFT_IO_DEVS) FAIL(EINVAL);
sw_pos = s_left_io_swpos;
} else if (x >= model->x_width-RIGHT_SIDE_WIDTH) {
if (x != model->x_width - RIGHT_IO_DEVS_O) FAIL(EINVAL);
sw_pos = s_right_io_swpos;
} else if (y == TOP_OUTER_IO)
sw_pos = s_top_outer_io_swpos;
else if (y == TOP_INNER_IO)
sw_pos = s_top_inner_io_swpos;
else if (y == model->y_height-BOT_INNER_IO)
sw_pos = s_bot_inner_io_swpos;
else if (y == model->y_height-BOT_OUTER_IO)
sw_pos = s_bot_outer_io_swpos;
else FAIL(EINVAL);
is_in_row(model, y, &row_num, &row_pos);
if (row_num == -1 || row_pos == -1
|| row_pos == HCLK_POS) FAIL(EINVAL);
if (row_pos > HCLK_POS)
start_in_frame = (row_pos-1)*64 + 16;
else
start_in_frame = row_pos*64;
rc = get_used_switches(model, y, x, &str_sw, &num_sw);
if (rc) FAIL(rc);
for (i = 0; sw_pos[i].to[0]; i++) {
if (!(num_found = find_switches(&sw_pos[i], str_sw,
num_sw, &found_i))) continue;
for (j = 0; sw_pos[i].minor[j] != -1; j++) {
set_bit(bits, row_num, model->x_major[x],
sw_pos[i].minor[j], start_in_frame
+ sw_pos[i].b64[j]);
}
// remove switches from 'used' array
for (j = 0; j < num_found; j++)
str_sw[found_i[j]].to_str = 0;
}
// check whether all switches were found
for (i = 0; i < num_sw; i++) {
if (!str_sw[i].to_str)
continue;
fprintf(stderr, "#E %s:%i unsupported switch "
"y%i x%i %s -> %s\n", __FILE__, __LINE__,
y, x, str_sw[i].from_str, str_sw[i].to_str);
}
free(str_sw);
return 0;
fail:
return rc;
}
static int write_inner_term_sw(struct fpga_bits *bits,
struct fpga_model *model, int y, int x)
{
struct fpga_tile *tile;
const char *from_str, *from_found, *to_str, *to_found;
int i, j, from_idx, to_idx;
RC_CHECK(model);
tile = YX_TILE(model, y, x);
for (i = 0; i < tile->num_switches; i++) {
if (!(tile->switches[i] & SWITCH_USED))
continue;
from_str = fpga_switch_str(model, y, x, i, SW_FROM);
to_str = fpga_switch_str(model, y, x, i, SW_TO);
RC_ASSERT(model, from_str && to_str);
if (strstr(from_str, "IBUF")
&& strstr(to_str, "CLKPIN"))
continue;
if ((from_found = strstr(from_str, "CLKPIN"))
&& (to_found = strstr(to_str, "CKPIN"))) {
struct switch_to_yx_l2 switch_to_yx_l2;
int iob_y, iob_x, iob_idx;
struct fpga_device *iob_dev;
from_idx = atoi(&from_found[6]);
to_idx = atoi(&to_found[5]);
RC_ASSERT(model, from_idx == to_idx);
// follow switches backwards to IOB
switch_to_yx_l2.l1.yx_req = YX_DEV_IOB;
switch_to_yx_l2.l1.flags = SWTO_YX_DEF;
switch_to_yx_l2.l1.model = model;
switch_to_yx_l2.l1.y = y;
switch_to_yx_l2.l1.x = x;
switch_to_yx_l2.l1.start_switch = fpga_switch_str_i(model, y, x, i, SW_TO);
switch_to_yx_l2.l1.from_to = SW_TO;
fpga_switch_to_yx_l2(&switch_to_yx_l2);
RC_ASSERT(model, switch_to_yx_l2.l1.set.len);
// find matching gclk pin
for (j = 0; j < model->pkg->num_gclk_pins; j++) {
if (!model->pkg->gclk_pin[j])
continue;
fpga_find_iob(model, model->pkg->gclk_pin[j],
&iob_y, &iob_x, &iob_idx);
RC_CHECK(model);
if (iob_y != switch_to_yx_l2.l1.dest_y
|| iob_x != switch_to_yx_l2.l1.dest_x)
continue;
iob_dev = fdev_p(model, iob_y, iob_x, DEV_IOB, iob_idx);
RC_ASSERT(model, iob_dev);
if (fpga_switch_lookup(model, iob_y, iob_x,
iob_dev->pinw[IOB_OUT_I],
switch_to_yx_l2.l1.dest_connpt) != NO_SWITCH)
break;
}
// set bit
if (j < model->pkg->num_gclk_pins) {
uint16_t u16;
int bits_off;
bits_off = IOB_DATA_START
+ model->pkg->gclk_type2_o[j]*XC6_WORD_BYTES
+ XC6_TYPE2_GCLK_REG_SW/XC6_WORD_BITS;
u16 = frame_get_u16(&bits->d[bits_off]);
u16 |= 1<<(XC6_TYPE2_GCLK_REG_SW%XC6_WORD_BITS);
frame_set_u16(&bits->d[bits_off], u16);
continue;
}
// fall-through to unsupported
}
fprintf(stderr, "#E %s:%i unsupported switch "
"y%i x%i %s -> %s\n", __FILE__, __LINE__,
y, x, from_str, to_str);
}
RC_RETURN(model);
}
static int write_logic_sw(struct fpga_bits *bits,
struct fpga_model *model, int y, int x)
{
struct fpga_tile *tile;
const char *from_str, *to_str;
int i, row, row_pos, xm_col, byte_off, frame_off;
uint64_t mi2526;
uint8_t* u8_p;
RC_CHECK(model);
tile = YX_TILE(model, y, x);
for (i = 0; i < tile->num_switches; i++) {
if (!(tile->switches[i] & SWITCH_USED))
continue;
from_str = fpga_switch_str(model, y, x, i, SW_FROM);
to_str = fpga_switch_str(model, y, x, i, SW_TO);
RC_ASSERT(model, from_str && to_str);
xm_col = has_device_type(model, y, x, DEV_LOGIC, LOGIC_M);
if ((xm_col
&& !strcmp(from_str, "M_COUT")
&& !strcmp(to_str, "M_COUT_N"))
|| (!xm_col
&& !strcmp(from_str, "XL_COUT")
&& !strcmp(to_str, "XL_COUT_N"))) {
is_in_row(model, regular_row_up(y, model), &row, &row_pos);
RC_ASSERT(model, row != -1 && row_pos != -1 && row_pos != HCLK_POS);
if (row_pos > HCLK_POS) row_pos--;
u8_p = get_first_minor(bits, row, model->x_major[x]);
byte_off = row_pos * 8;
if (row_pos >= 8) byte_off += XC6_HCLK_BYTES;
frame_off = (xm_col?26:25)*FRAME_SIZE + byte_off;
mi2526 = frame_get_u64(u8_p + frame_off);
RC_ASSERT(model, !(mi2526 & (1ULL << XC6_ML_CIN_USED)));
mi2526 |= 1ULL << XC6_ML_CIN_USED;
frame_set_u64(u8_p + frame_off, mi2526);
}
}
RC_RETURN(model);
}
static int write_switches(struct fpga_bits* bits, struct fpga_model* model)
{
struct fpga_tile* tile;
int x, y, i;
RC_CHECK(model);
// We need to identify and take out each enabled switch, whether it
// leads to enabled bits or not. That way we can print unsupported
// switches at the end and keep our model alive and maintainable
// over time.
for (x = 0; x < model->x_width; x++) {
for (y = 0; y < model->y_height; y++) {
tile = YX_TILE(model, y, x);
if (is_atx(X_ROUTING_COL, model, x)
&& y >= TOP_IO_TILES
&& y < model->y_height-BOT_IO_TILES
&& !is_aty(Y_ROW_HORIZ_AXSYMM|Y_CHIP_HORIZ_REGS,
model, y)) {
write_routing_sw(bits, model, y, x);
continue;
}
if (is_atyx(YX_DEV_ILOGIC, model, y, x)) {
write_iologic_sw(bits, model, y, x);
continue;
}
if (is_atyx(YX_DEV_LOGIC, model, y, x)) {
write_logic_sw(bits, model, y, x);
continue;
}
if (is_atyx(YX_DEV_IOB, model, y, x))
continue;
if (is_atx(X_ROUTING_COL, model, x)
&& is_aty(Y_ROW_HORIZ_AXSYMM, model, y)) {
write_hclk_sw(bits, model, y, x);
continue;
}
if (is_atyx(YX_INNER_TERM, model, y, x)) {
write_inner_term_sw(bits, model, y, x);
continue;
}
if (is_atyx(YX_CENTER, model, y, x)) {
write_center_sw(bits, model, y, x);
continue;
}
if (is_atx(X_CENTER_REGS_COL, model, x)) {
if (is_aty(Y_ROW_HORIZ_AXSYMM, model, y)) {
write_gclk_center_vert_sw(bits, model, y, x);
continue;
}
if (tile->flags & TF_CENTER_MIDBUF
|| (y < model->center_y
&& YX_TILE(model, y+1, x)->flags & TF_CENTER_MIDBUF)
|| (y > model->center_y
&& YX_TILE(model, y-1, x)->flags & TF_CENTER_MIDBUF))
continue;
}
// print unsupported switches
for (i = 0; i < tile->num_switches; i++) {
if (!(tile->switches[i] & SWITCH_USED))
continue;
fprintf(stderr, "#E %s:%i unsupported switch "
"y%i x%i %s\n", __FILE__, __LINE__,
y, x,
fpga_switch_print(model, y, x, i));
}
}
}
RC_RETURN(model);
}
static int is_latch(struct fpga_device *dev)
{
int i;
// todo: there are a lot more checks we can do to determine whether
// the entire device is properly configured as a latch or not...
for (i = LUT_A; i <= LUT_D; i++) {
if (dev->u.logic.a2d[i].ff == FF_LATCH
|| dev->u.logic.a2d[i].ff == FF_OR2L
|| dev->u.logic.a2d[i].ff == FF_AND2L)
return 1;
}
return 0;
}
static int str2lut(uint64_t *lut, int lut_pos, const struct fpgadev_logic_a2d *a2d)
{
int lut6_used, lut5_used, lut_map[64], rc;
uint64_t u64;
lut6_used = a2d->lut6 && a2d->lut6[0];
lut5_used = a2d->lut5 && a2d->lut5[0];
if (!lut6_used && !lut5_used)
return 0;
if (lut5_used) {
if (!lut6_used) u64 = 0;
else {
rc = bool_str2bits(a2d->lut6, &u64, 32);
if (rc) FAIL(rc);
u64 <<= 32;
}
rc = bool_str2bits(a2d->lut5, &u64, 32);
if (rc) FAIL(rc);
xc6_lut_bitmap(lut_pos, &lut_map, 32);
} else {
// lut6_used only
rc = bool_str2bits(a2d->lut6, &u64, 64);
if (rc) FAIL(rc);
xc6_lut_bitmap(lut_pos, &lut_map, 64);
}
*lut = map_bits(u64, 64, lut_map);
return 0;
fail:
return rc;
}
static int write_logic(struct fpga_bits* bits, struct fpga_model* model)
{
int dev_idx, row, row_pos, xm_col;
int x, y, byte_off, rc;
uint64_t lut_X[4], lut_ML[4]; // LUT_A-LUT_D
uint64_t mi20, mi23_M, mi2526;
uint8_t* u8_p;
struct fpga_device* dev_ml, *dev_x;
RC_CHECK(model);
for (x = LEFT_SIDE_WIDTH; x < model->x_width-RIGHT_SIDE_WIDTH; x++) {
xm_col = is_atx(X_FABRIC_LOGIC_XM_COL, model, x);
if (!xm_col && !is_atx(X_FABRIC_LOGIC_XL_COL, model, x))
continue;
for (y = TOP_IO_TILES; y < model->y_height - BOT_IO_TILES; y++) {
if (!has_device(model, y, x, DEV_LOGIC))
continue;
is_in_row(model, y, &row, &row_pos);
RC_ASSERT(model, row != -1 && row_pos != -1 && row_pos != HCLK_POS);
if (row_pos > HCLK_POS) row_pos--;
u8_p = get_first_minor(bits, row, model->x_major[x]);
byte_off = row_pos * 8;
if (row_pos >= 8) byte_off += XC6_HCLK_BYTES;
//
// 1) check current bits
//
mi20 = frame_get_u64(u8_p + 20*FRAME_SIZE + byte_off) & XC6_MI20_LOGIC_MASK;
if (xm_col) {
mi23_M = frame_get_u64(u8_p + 23*FRAME_SIZE + byte_off);
mi2526 = frame_get_u64(u8_p + 26*FRAME_SIZE + byte_off);
lut_ML[LUT_A] = frame_get_lut64(u8_p + 24*FRAME_SIZE, row_pos*2+1);
lut_ML[LUT_B] = frame_get_lut64(u8_p + 21*FRAME_SIZE, row_pos*2+1);
lut_ML[LUT_C] = frame_get_lut64(u8_p + 24*FRAME_SIZE, row_pos*2);
lut_ML[LUT_D] = frame_get_lut64(u8_p + 21*FRAME_SIZE, row_pos*2);
lut_X[LUT_A] = frame_get_lut64(u8_p + 27*FRAME_SIZE, row_pos*2+1);
lut_X[LUT_B] = frame_get_lut64(u8_p + 29*FRAME_SIZE, row_pos*2+1);
lut_X[LUT_C] = frame_get_lut64(u8_p + 27*FRAME_SIZE, row_pos*2);
lut_X[LUT_D] = frame_get_lut64(u8_p + 29*FRAME_SIZE, row_pos*2);
} else { // xl
mi23_M = 0;
mi2526 = frame_get_u64(u8_p + 25*FRAME_SIZE + byte_off);
lut_ML[LUT_A] = frame_get_lut64(u8_p + 23*FRAME_SIZE, row_pos*2+1);
lut_ML[LUT_B] = frame_get_lut64(u8_p + 21*FRAME_SIZE, row_pos*2+1);
lut_ML[LUT_C] = frame_get_lut64(u8_p + 23*FRAME_SIZE, row_pos*2);
lut_ML[LUT_D] = frame_get_lut64(u8_p + 21*FRAME_SIZE, row_pos*2);
lut_X[LUT_A] = frame_get_lut64(u8_p + 26*FRAME_SIZE, row_pos*2+1);
lut_X[LUT_B] = frame_get_lut64(u8_p + 28*FRAME_SIZE, row_pos*2+1);
lut_X[LUT_C] = frame_get_lut64(u8_p + 26*FRAME_SIZE, row_pos*2);
lut_X[LUT_D] = frame_get_lut64(u8_p + 28*FRAME_SIZE, row_pos*2);
}
// Except for XC6_ML_CIN_USED (which is set by a switch elsewhere),
// everything else should be 0.
if (mi20 || mi23_M || (mi2526 & ~(1ULL<instantiated) {
if (dev_x->u.logic.a2d[LUT_A].ff5_srinit == FF_SRINIT1)
mi20 |= 1ULL << XC6_X_A5_FFSRINIT_1;
if (dev_x->u.logic.a2d[LUT_B].ff5_srinit == FF_SRINIT1)
mi20 |= 1ULL << XC6_X_B5_FFSRINIT_1;
if (dev_x->u.logic.a2d[LUT_C].ff5_srinit == FF_SRINIT1)
mi20 |= 1ULL << XC6_X_C5_FFSRINIT_1;
if (dev_x->u.logic.a2d[LUT_D].ff5_srinit == FF_SRINIT1)
mi20 |= 1ULL << XC6_X_D5_FFSRINIT_1;
if (dev_x->u.logic.a2d[LUT_C].ff_srinit == FF_SRINIT1)
mi20 |= 1ULL << XC6_X_C_FFSRINIT_1;
}
// M or L device
if (dev_ml->instantiated) {
if (dev_ml->u.logic.a2d[LUT_A].ff5_srinit == FF_SRINIT1)
mi20 |= 1ULL << XC6_ML_A5_FFSRINIT_1;
if (dev_ml->u.logic.a2d[LUT_B].ff5_srinit == FF_SRINIT1)
mi20 |= 1ULL << XC6_ML_B5_FFSRINIT_1;
if (dev_ml->u.logic.a2d[LUT_C].ff5_srinit == FF_SRINIT1)
mi20 |= 1ULL << XC6_ML_C5_FFSRINIT_1;
if (dev_ml->u.logic.a2d[LUT_D].ff5_srinit == FF_SRINIT1)
mi20 |= 1ULL << XC6_ML_D5_FFSRINIT_1;
if (xm_col // M-device only
&& dev_ml->u.logic.a2d[LUT_A].ff_srinit == FF_SRINIT1)
mi20 |= 1ULL << XC6_M_A_FFSRINIT_1;
}
//
// 2.2) mi2526
//
// X device
if (dev_x->instantiated) {
if (dev_x->u.logic.a2d[LUT_D].out_mux != MUX_5Q)
mi2526 |= 1ULL << XC6_X_D_OUTMUX_O5; // default-set
if (dev_x->u.logic.a2d[LUT_C].out_mux != MUX_5Q)
mi2526 |= 1ULL << XC6_X_C_OUTMUX_O5; // default-set
if (dev_x->u.logic.a2d[LUT_D].ff_srinit == FF_SRINIT1)
mi2526 |= 1ULL << XC6_X_D_FFSRINIT_1;
if (dev_x->u.logic.a2d[LUT_B].out_mux != MUX_5Q)
mi2526 |= 1ULL << XC6_X_B_OUTMUX_O5; // default-set
if (dev_x->u.logic.clk_inv == CLKINV_B)
mi2526 |= 1ULL << XC6_X_CLK_B;
if (dev_x->u.logic.a2d[LUT_D].ff_mux != MUX_O6)
mi2526 |= 1ULL << XC6_X_D_FFMUX_X; // default-set
if (dev_x->u.logic.a2d[LUT_C].ff_mux != MUX_O6)
mi2526 |= 1ULL << XC6_X_C_FFMUX_X; // default-set
if (dev_x->u.logic.ce_used)
mi2526 |= 1ULL << XC6_X_CE_USED;
if (dev_x->u.logic.a2d[LUT_B].ff_mux != MUX_O6)
mi2526 |= 1ULL << XC6_X_B_FFMUX_X; // default-set
if (dev_x->u.logic.a2d[LUT_A].ff_mux != MUX_O6)
mi2526 |= 1ULL << XC6_X_A_FFMUX_X; // default-set
if (dev_x->u.logic.a2d[LUT_B].ff_srinit == FF_SRINIT1)
mi2526 |= 1ULL << XC6_X_B_FFSRINIT_1;
if (dev_x->u.logic.a2d[LUT_A].out_mux != MUX_5Q)
mi2526 |= 1ULL << XC6_X_A_OUTMUX_O5; // default-set
if (dev_x->u.logic.sr_used)
mi2526 |= 1ULL << XC6_X_SR_USED;
if (dev_x->u.logic.sync_attr == SYNCATTR_SYNC)
mi2526 |= 1ULL << XC6_X_SYNC;
if (is_latch(dev_x))
mi2526 |= 1ULL << XC6_X_ALL_LATCH;
if (dev_x->u.logic.a2d[LUT_A].ff_srinit == FF_SRINIT1)
mi2526 |= 1ULL << XC6_X_A_FFSRINIT_1;
}
// M or L device
if (dev_ml->instantiated) {
if (dev_ml->u.logic.a2d[LUT_D].cy0 == CY0_O5)
mi2526 |= 1ULL << XC6_ML_D_CY0_O5;
if (dev_ml->u.logic.a2d[LUT_D].ff_srinit == FF_SRINIT1)
mi2526 |= 1ULL << XC6_ML_D_FFSRINIT_1;
if (dev_ml->u.logic.a2d[LUT_C].ff_srinit == FF_SRINIT1)
mi2526 |= 1ULL << XC6_ML_C_FFSRINIT_1;
if (dev_ml->u.logic.a2d[LUT_C].cy0 == CY0_O5)
mi2526 |= 1ULL << XC6_ML_C_CY0_O5;
switch (dev_ml->u.logic.a2d[LUT_D].out_mux) {
case MUX_O6: mi2526 |= XC6_ML_D_OUTMUX_O6 << XC6_ML_D_OUTMUX_O; break;
case MUX_XOR: mi2526 |= XC6_ML_D_OUTMUX_XOR << XC6_ML_D_OUTMUX_O; break;
case MUX_O5: mi2526 |= XC6_ML_D_OUTMUX_O5 << XC6_ML_D_OUTMUX_O; break;
case MUX_CY: mi2526 |= XC6_ML_D_OUTMUX_CY << XC6_ML_D_OUTMUX_O; break;
case MUX_5Q: mi2526 |= XC6_ML_D_OUTMUX_5Q << XC6_ML_D_OUTMUX_O; break;
}
switch (dev_ml->u.logic.a2d[LUT_D].ff_mux) {
// XC6_ML_D_FFMUX_O6 is 0
case MUX_O5: mi2526 |= XC6_ML_D_FFMUX_O5 << XC6_ML_D_FFMUX_O; break;
case MUX_X: mi2526 |= XC6_ML_D_FFMUX_X << XC6_ML_D_FFMUX_O; break;
case MUX_XOR: mi2526 |= XC6_ML_D_FFMUX_XOR << XC6_ML_D_FFMUX_O; break;
case MUX_CY: mi2526 |= XC6_ML_D_FFMUX_CY << XC6_ML_D_FFMUX_O; break;
}
if (is_latch(dev_ml))
mi2526 |= 1ULL << XC6_ML_ALL_LATCH;
if (dev_ml->u.logic.sr_used)
mi2526 |= 1ULL << XC6_ML_SR_USED;
if (dev_ml->u.logic.sync_attr == SYNCATTR_SYNC)
mi2526 |= 1ULL << XC6_ML_SYNC;
if (dev_ml->u.logic.ce_used)
mi2526 |= 1ULL << XC6_ML_CE_USED;
switch (dev_ml->u.logic.a2d[LUT_C].out_mux) {
case MUX_XOR: mi2526 |= XC6_ML_C_OUTMUX_XOR << XC6_ML_C_OUTMUX_O; break;
case MUX_O6: mi2526 |= XC6_ML_C_OUTMUX_O6 << XC6_ML_C_OUTMUX_O; break;
case MUX_5Q: mi2526 |= XC6_ML_C_OUTMUX_5Q << XC6_ML_C_OUTMUX_O; break;
case MUX_CY: mi2526 |= XC6_ML_C_OUTMUX_CY << XC6_ML_C_OUTMUX_O; break;
case MUX_O5: mi2526 |= XC6_ML_C_OUTMUX_O5 << XC6_ML_C_OUTMUX_O; break;
case MUX_F7: mi2526 |= XC6_ML_C_OUTMUX_F7 << XC6_ML_C_OUTMUX_O; break;
}
switch (dev_ml->u.logic.a2d[LUT_C].ff_mux) {
// XC6_ML_C_FFMUX_O6 is 0
case MUX_O5: mi2526 |= XC6_ML_C_FFMUX_O5 << XC6_ML_C_FFMUX_O; break;
case MUX_X: mi2526 |= XC6_ML_C_FFMUX_X << XC6_ML_C_FFMUX_O; break;
case MUX_F7: mi2526 |= XC6_ML_C_FFMUX_F7 << XC6_ML_C_FFMUX_O; break;
case MUX_XOR: mi2526 |= XC6_ML_C_FFMUX_XOR << XC6_ML_C_FFMUX_O; break;
case MUX_CY: mi2526 |= XC6_ML_C_FFMUX_CY << XC6_ML_C_FFMUX_O; break;
}
switch (dev_ml->u.logic.a2d[LUT_B].out_mux) {
case MUX_5Q: mi2526 |= XC6_ML_B_OUTMUX_5Q << XC6_ML_B_OUTMUX_O; break;
case MUX_F8: mi2526 |= XC6_ML_B_OUTMUX_F8 << XC6_ML_B_OUTMUX_O; break;
case MUX_XOR: mi2526 |= XC6_ML_B_OUTMUX_XOR << XC6_ML_B_OUTMUX_O; break;
case MUX_CY: mi2526 |= XC6_ML_B_OUTMUX_CY << XC6_ML_B_OUTMUX_O; break;
case MUX_O6: mi2526 |= XC6_ML_B_OUTMUX_O6 << XC6_ML_B_OUTMUX_O; break;
case MUX_O5: mi2526 |= XC6_ML_B_OUTMUX_O5 << XC6_ML_B_OUTMUX_O; break;
}
if (dev_ml->u.logic.clk_inv == CLKINV_B)
mi2526 |= 1ULL << XC6_ML_CLK_B;
switch (dev_ml->u.logic.a2d[LUT_B].ff_mux) {
// XC6_ML_B_FFMUX_O6 is 0
case MUX_XOR: mi2526 |= XC6_ML_B_FFMUX_XOR << XC6_ML_B_FFMUX_O; break;
case MUX_O5: mi2526 |= XC6_ML_B_FFMUX_O5 << XC6_ML_B_FFMUX_O; break;
case MUX_CY: mi2526 |= XC6_ML_B_FFMUX_CY << XC6_ML_B_FFMUX_O; break;
case MUX_X: mi2526 |= XC6_ML_B_FFMUX_X << XC6_ML_B_FFMUX_O; break;
case MUX_F8: mi2526 |= XC6_ML_B_FFMUX_F8 << XC6_ML_B_FFMUX_O; break;
}
switch (dev_ml->u.logic.a2d[LUT_A].ff_mux) {
// XC6_ML_A_FFMUX_O6 is 0
case MUX_XOR: mi2526 |= XC6_ML_A_FFMUX_XOR << XC6_ML_A_FFMUX_O; break;
case MUX_X: mi2526 |= XC6_ML_A_FFMUX_X << XC6_ML_A_FFMUX_O; break;
case MUX_O5: mi2526 |= XC6_ML_A_FFMUX_O5 << XC6_ML_A_FFMUX_O; break;
case MUX_CY: mi2526 |= XC6_ML_A_FFMUX_CY << XC6_ML_A_FFMUX_O; break;
case MUX_F7: mi2526 |= XC6_ML_A_FFMUX_F7 << XC6_ML_A_FFMUX_O; break;
}
switch (dev_ml->u.logic.a2d[LUT_A].out_mux) {
case MUX_5Q: mi2526 |= XC6_ML_A_OUTMUX_5Q << XC6_ML_A_OUTMUX_O; break;
case MUX_F7: mi2526 |= XC6_ML_A_OUTMUX_F7 << XC6_ML_A_OUTMUX_O; break;
case MUX_XOR: mi2526 |= XC6_ML_A_OUTMUX_XOR << XC6_ML_A_OUTMUX_O; break;
case MUX_CY: mi2526 |= XC6_ML_A_OUTMUX_CY << XC6_ML_A_OUTMUX_O; break;
case MUX_O6: mi2526 |= XC6_ML_A_OUTMUX_O6 << XC6_ML_A_OUTMUX_O; break;
case MUX_O5: mi2526 |= XC6_ML_A_OUTMUX_O5 << XC6_ML_A_OUTMUX_O; break;
}
if (dev_ml->u.logic.a2d[LUT_B].cy0 == CY0_O5)
mi2526 |= 1ULL << XC6_ML_B_CY0_O5;
if (dev_ml->u.logic.precyinit == PRECYINIT_AX)
mi2526 |= 1ULL << XC6_ML_PRECYINIT_AX;
else if (dev_ml->u.logic.precyinit == PRECYINIT_1)
mi2526 |= 1ULL << XC6_ML_PRECYINIT_1;
if (dev_ml->u.logic.a2d[LUT_B].ff_srinit == FF_SRINIT1)
mi2526 |= 1ULL << XC6_ML_B_FFSRINIT_1;
if (dev_ml->u.logic.a2d[LUT_A].cy0 == CY0_O5)
mi2526 |= 1ULL << XC6_ML_A_CY0_O5;
if (!xm_col && dev_ml->u.logic.a2d[LUT_A].ff_srinit == FF_SRINIT1)
mi2526 |= 1ULL << XC6_L_A_FFSRINIT_1;
}
//
// 2.3) luts
//
// X device
if (dev_x->instantiated) {
rc = str2lut(&lut_X[LUT_A], xm_col
? XC6_LMAP_XM_X_A : XC6_LMAP_XL_X_A,
&dev_x->u.logic.a2d[LUT_A]);
RC_ASSERT(model, !rc);
rc = str2lut(&lut_X[LUT_B], xm_col
? XC6_LMAP_XM_X_B : XC6_LMAP_XL_X_B,
&dev_x->u.logic.a2d[LUT_B]);
RC_ASSERT(model, !rc);
rc = str2lut(&lut_X[LUT_C], xm_col
? XC6_LMAP_XM_X_C : XC6_LMAP_XL_X_C,
&dev_x->u.logic.a2d[LUT_C]);
RC_ASSERT(model, !rc);
rc = str2lut(&lut_X[LUT_D], xm_col
? XC6_LMAP_XM_X_D : XC6_LMAP_XL_X_D,
&dev_x->u.logic.a2d[LUT_D]);
RC_ASSERT(model, !rc);
}
// M or L device
if (dev_ml->instantiated) {
rc = str2lut(&lut_ML[LUT_A], xm_col
? XC6_LMAP_XM_M_A : XC6_LMAP_XL_L_A,
&dev_ml->u.logic.a2d[LUT_A]);
RC_ASSERT(model, !rc);
rc = str2lut(&lut_ML[LUT_B], xm_col
? XC6_LMAP_XM_M_B : XC6_LMAP_XL_L_B,
&dev_ml->u.logic.a2d[LUT_B]);
RC_ASSERT(model, !rc);
rc = str2lut(&lut_ML[LUT_C], xm_col
? XC6_LMAP_XM_M_C : XC6_LMAP_XL_L_C,
&dev_ml->u.logic.a2d[LUT_C]);
RC_ASSERT(model, !rc);
rc = str2lut(&lut_ML[LUT_D], xm_col
? XC6_LMAP_XM_M_D : XC6_LMAP_XL_L_D,
&dev_ml->u.logic.a2d[LUT_D]);
RC_ASSERT(model, !rc);
}
//
// 3) write bits
//
// logic devs occupy only some bits in mi20, so we merge
// with the others (switches).
frame_set_u64(u8_p + 20*FRAME_SIZE + byte_off,
(frame_get_u64(u8_p + 20*FRAME_SIZE + byte_off) & ~XC6_MI20_LOGIC_MASK)
| mi20);
if (xm_col) {
frame_set_u64(u8_p + 23*FRAME_SIZE + byte_off, mi23_M);
frame_set_u64(u8_p + 26*FRAME_SIZE + byte_off, mi2526);
frame_set_lut64(u8_p + 24*FRAME_SIZE, row_pos*2+1, lut_ML[LUT_A]);
frame_set_lut64(u8_p + 21*FRAME_SIZE, row_pos*2+1, lut_ML[LUT_B]);
frame_set_lut64(u8_p + 24*FRAME_SIZE, row_pos*2, lut_ML[LUT_C]);
frame_set_lut64(u8_p + 21*FRAME_SIZE, row_pos*2, lut_ML[LUT_D]);
frame_set_lut64(u8_p + 27*FRAME_SIZE, row_pos*2+1, lut_X[LUT_A]);
frame_set_lut64(u8_p + 29*FRAME_SIZE, row_pos*2+1, lut_X[LUT_B]);
frame_set_lut64(u8_p + 27*FRAME_SIZE, row_pos*2, lut_X[LUT_C]);
frame_set_lut64(u8_p + 29*FRAME_SIZE, row_pos*2, lut_X[LUT_D]);
} else { // xl
// mi23 is unused in xl cols - no need to write it
RC_ASSERT(model, !mi23_M);
frame_set_u64(u8_p + 25*FRAME_SIZE + byte_off, mi2526);
frame_set_lut64(u8_p + 23*FRAME_SIZE, row_pos*2+1, lut_ML[LUT_A]);
frame_set_lut64(u8_p + 21*FRAME_SIZE, row_pos*2+1, lut_ML[LUT_B]);
frame_set_lut64(u8_p + 23*FRAME_SIZE, row_pos*2, lut_ML[LUT_C]);
frame_set_lut64(u8_p + 21*FRAME_SIZE, row_pos*2, lut_ML[LUT_D]);
frame_set_lut64(u8_p + 26*FRAME_SIZE, row_pos*2+1, lut_X[LUT_A]);
frame_set_lut64(u8_p + 28*FRAME_SIZE, row_pos*2+1, lut_X[LUT_B]);
frame_set_lut64(u8_p + 26*FRAME_SIZE, row_pos*2, lut_X[LUT_C]);
frame_set_lut64(u8_p + 28*FRAME_SIZE, row_pos*2, lut_X[LUT_D]);
}
}
}
RC_RETURN(model);
}
int write_model(struct fpga_bits* bits, struct fpga_model* model)
{
int i;
RC_CHECK(model);
for (i = 0; i < sizeof(s_default_bits)/sizeof(s_default_bits[0]); i++)
set_bitp(bits, &s_default_bits[i]);
write_switches(bits, model);
write_type2(bits, model);
write_logic(bits, model);
RC_RETURN(model);
}
fpgatools-201212/libs/bit_regs.c 0000664 0000000 0000000 00000154000 12065743015 0016477 0 ustar 00root root 0000000 0000000 //
// Author: Wolfgang Spraul
//
// This is free and unencumbered software released into the public domain.
// For details see the UNLICENSE file at the root of the source tree.
//
#include "model.h"
#include "bit.h"
static int parse_header(struct fpga_config* config, uint8_t* d,
int len, int inpos, int* outdelta);
static int parse_commands(struct fpga_config* config, uint8_t* d,
int len, int inpos);
#define SYNC_WORD 0xAA995566
#define PACKET_HDR_TYPE_S 13
#define PACKET_HDR_OPCODE_S 11
#define PACKET_HDR_REG_S 5
#define PACKET_TYPE_1 1
#define PACKET_TYPE_2 2
#define PACKET_HDR_OPCODE_NOOP 0
#define PACKET_HDR_OPCODE_READ 1
#define PACKET_HDR_OPCODE_WRITE 2
#define PACKET_HDR_OPCODE_RSRV 3
#define BITSTREAM_READ_PAGESIZE 4096
int read_bitfile(struct fpga_config* cfg, FILE* f)
{
uint8_t* bit_data = 0;
int rc, file_len, bit_len, bit_cur;
memset(cfg, 0, sizeof(*cfg));
cfg->num_regs_before_bits = -1;
cfg->idcode_reg = -1;
cfg->FLR_reg = -1;
// read .bit into memory
if (fseek(f, 0, SEEK_END) == -1)
FAIL(errno);
if ((file_len = ftell(f)) == -1)
FAIL(errno);
if (fseek(f, 0, SEEK_SET) == -1)
FAIL(errno);
if (!file_len)
FAIL(EINVAL);
if (!(bit_data = malloc(file_len)))
FAIL(ENOMEM);
bit_len = 0;
while (bit_len < file_len) {
size_t num_read = fread(&bit_data[bit_len], sizeof(uint8_t),
BITSTREAM_READ_PAGESIZE, f);
bit_len += num_read;
if (num_read != BITSTREAM_READ_PAGESIZE)
break;
}
if (bit_len != file_len)
FAIL(EINVAL);
// parse header and commands
if ((rc = parse_header(cfg, bit_data, bit_len, /*inpos*/ 0, &bit_cur)))
FAIL(rc);
if ((rc = parse_commands(cfg, bit_data, bit_len, bit_cur)))
FAIL(rc);
free(bit_data);
return 0;
fail:
free(bit_data);
return rc;
}
static void dump_header(struct fpga_config* cfg)
{
int i;
for (i = 0; i < sizeof(cfg->header_str)
/sizeof(cfg->header_str[0]); i++) {
printf("header_str_%c %s\n", 'a'+i,
cfg->header_str[i]);
}
}
static int dump_regs(struct fpga_config* cfg, int start, int end, int dump_crc)
{
uint16_t u16;
int i, rc;
for (i = start; i < end; i++) {
if (cfg->reg[i].reg == REG_NOOP) {
int times = 1;
while (i+times < end && cfg->reg[i+times].reg
== REG_NOOP)
times++;
if (times > 1)
printf("noop times %i\n", times);
else
printf("noop\n");
i += times-1;
continue;
}
if (cfg->reg[i].reg == IDCODE) {
switch (cfg->reg[i].int_v & IDCODE_MASK) {
case XC6SLX4: printf("T1 IDCODE XC6SLX4\n"); break;
case XC6SLX9: printf("T1 IDCODE XC6SLX9\n"); break;
case XC6SLX16: printf("T1 IDCODE XC6SLX16\n"); break;
case XC6SLX25: printf("T1 IDCODE XC6SLX25\n"); break;
case XC6SLX25T: printf("T1 IDCODE XC6SLX25T\n"); break;
case XC6SLX45: printf("T1 IDCODE XC6SLX45\n"); break;
case XC6SLX45T: printf("T1 IDCODE XC6SLX45T\n"); break;
case XC6SLX75: printf("T1 IDCODE XC6SLX75\n"); break;
case XC6SLX75T: printf("T1 IDCODE XC6SLX75T\n"); break;
case XC6SLX100: printf("T1 IDCODE XC6SLX100\n"); break;
case XC6SLX100T: printf("T1 IDCODE XC6SLX100T\n"); break;
case XC6SLX150: printf("T1 IDCODE XC6SLX150\n"); break;
default:
printf("#W Unknown IDCODE 0x%X.\n", cfg->reg[i].int_v);
break;
}
continue;
}
if (cfg->reg[i].reg == CMD) {
static const char* cmds[] =
{
[CMD_NULL] = "NULL",
[CMD_WCFG] = "WCFG",
[CMD_MFW] = "MFW",
[CMD_LFRM] = "LFRM",
[CMD_RCFG] = "RCFG",
[CMD_START] = "START",
[CMD_RCRC] = "RCRC",
[CMD_AGHIGH] = "AGHIGH",
[CMD_GRESTORE] = "GRESTORE",
[CMD_SHUTDOWN] = "SHUTDOWN",
[CMD_DESYNC] = "DESYNC",
[CMD_IPROG] = "IPROG"
};
if (cfg->reg[i].int_v >= sizeof(cmds)/sizeof(cmds[0])
|| cmds[cfg->reg[i].int_v] == 0)
printf("#W Unknown CMD 0x%X.\n", cfg->reg[i].int_v);
else
printf("T1 CMD %s\n", cmds[cfg->reg[i].int_v]);
continue;
}
if (cfg->reg[i].reg == FDRI) {
printf("T2 FDRI %i\n", cfg->reg[i].int_v);
continue;
}
if (cfg->reg[i].reg == FLR) {
printf("T1 FLR %i\n", cfg->reg[i].int_v);
continue;
}
if (cfg->reg[i].reg == CRC) {
if (dump_crc)
printf("T1 CRC 0x%X\n", cfg->reg[i].int_v);
else
printf("T1 CRC\n");
continue;
}
if (cfg->reg[i].reg == COR1) {
int unexpected_clk11 = 0;
u16 = cfg->reg[i].int_v;
printf("T1 COR1");
if (u16 & 0x8000) {
printf(" DRIVE_AWAKE");
u16 &= ~0x8000;
}
if (u16 & 0x0010) {
printf(" CRC_BYPASS");
u16 &= ~0x0010;
}
if (u16 & 0x0008) {
printf(" DONE_PIPE");
u16 &= ~0x0008;
}
if (u16 & 0x0004) {
printf(" DRIVE_DONE");
u16 &= ~0x0004;
}
if (u16 & 0x0003) {
if (u16 & 0x0002) {
if (u16 & 0x0001)
unexpected_clk11 = 1;
printf(" SSCLKSRC=TCK");
} else
printf(" SSCLKSRC=UserClk");
u16 &= ~0x0003;
}
if (u16)
printf(" 0x%x", u16);
printf("\n");
if (unexpected_clk11)
printf("#W Unexpected SSCLKSRC 11.\n");
// Reserved bits 14:5 should be 0110111000
// according to documentation.
if (u16 != 0x3700)
printf("#W Expected reserved 0x%x, got 0x%x.\n", 0x3700, u16);
continue;
}
if (cfg->reg[i].reg == COR2) {
int unexpected_done_cycle = 0;
int unexpected_lck_cycle = 0;
unsigned cycle;
u16 = cfg->reg[i].int_v;
printf("T1 COR2");
if (u16 & 0x8000) {
printf(" RESET_ON_ERROR");
u16 &= ~0x8000;
}
// DONE_CYCLE
cycle = (u16 & 0x0E00) >> 9;
printf(" DONE_CYCLE=%s", bitstr(cycle, 3));
if (!cycle || cycle == 7)
unexpected_done_cycle = 1;
u16 &= ~0x0E00;
// LCK_CYCLE
cycle = (u16 & 0x01C0) >> 6;
printf(" LCK_CYCLE=%s", bitstr(cycle, 3));
if (!cycle)
unexpected_lck_cycle = 1;
u16 &= ~0x01C0;
// GTS_CYCLE
cycle = (u16 & 0x0038) >> 3;
printf(" GTS_CYCLE=%s", bitstr(cycle, 3));
u16 &= ~0x0038;
// GWE_CYCLE
cycle = u16 & 0x0007;
printf(" GWE_CYCLE=%s", bitstr(cycle, 3));
u16 &= ~0x0007;
if (u16)
printf(" 0x%x", u16);
printf("\n");
if (unexpected_done_cycle)
printf("#W Unexpected DONE_CYCLE %s.\n",
bitstr((u16 & 0x01C0) >> 6, 3));
if (unexpected_lck_cycle)
printf("#W Unexpected LCK_CYCLE 0b000.\n");
// Reserved bits 14:12 should be 000
// according to documentation.
if (u16)
printf("#W Expected reserved 0, got 0x%x.\n", u16);
continue;
}
if (cfg->reg[i].reg == FAR_MAJ) {
uint16_t maj, min;
int unexpected_blk_bit4 = 0;
maj = cfg->reg[i].far[FAR_MAJ_O];
min = cfg->reg[i].far[FAR_MIN_O];
printf("T1 FAR_MAJ");
// BLK
u16 = (maj & 0xF000) >> 12;
printf(" BLK=%u", u16);
if (u16 > 7)
unexpected_blk_bit4 = 1;
// ROW
u16 = (maj & 0x0F00) >> 8;
printf(" ROW=%u", u16);
// MAJOR
u16 = maj & 0x00FF;
printf(" MAJOR=%u", u16);
// Block RAM
u16 = (min & 0xC000) >> 14;
printf(" BRAM=%u", u16);
// MINOR
u16 = min & 0x03FF;
printf(" MINOR=%u", u16);
if (min & 0x3C00)
printf(" 0x%x", min & 0x3C00);
printf("\n");
if (unexpected_blk_bit4)
printf("#W Unexpected BLK bit 4 set.\n");
// Reserved min bits 13:10 should be 000.
if (min & 0x3C00)
printf("#W Expected reserved 0, got 0x%x.\n", (min & 0x3C00) > 10);
continue;
}
if (cfg->reg[i].reg == MFWR) {
printf("T1 MFWR\n");
continue;
}
if (cfg->reg[i].reg == CTL) {
u16 = cfg->reg[i].int_v;
printf("T1 CTL");
if (u16 & 0x0040) {
printf(" DECRYPT");
u16 &= ~0x0040;
}
if (u16 & 0x0020) {
if (u16 & 0x0010)
printf(" SBITS=NO_RW");
else
printf(" SBITS=NO_READ");
u16 &= ~0x0030;
} else if (u16 & 0x0010) {
printf(" SBITS=ICAP_READ");
u16 &= ~0x0010;
}
if (u16 & 0x0008) {
printf(" PERSIST");
u16 &= ~0x0008;
}
if (u16 & 0x0004) {
printf(" USE_EFUSE_KEY");
u16 &= ~0x0004;
}
if (u16 & 0x0002) {
printf(" CRC_EXTSTAT_DISABLE");
u16 &= ~0x0002;
}
if (u16)
printf(" 0x%x", u16);
printf("\n");
// bit0 is reserved as 1, and we have seen
// bit7 on as well.
if (u16 != 0x81)
printf("#W Expected reserved 0x%x, got 0x%x.\n", 0x0081, u16);
continue;
}
if (cfg->reg[i].reg == MASK) {
u16 = cfg->reg[i].int_v;
printf("T1 MASK");
if (u16 & 0x0040) {
printf(" DECRYPT");
u16 &= ~0x0040;
}
if ((u16 & MASK_SECURITY) == MASK_SECURITY) {
printf(" SECURITY");
u16 &= ~MASK_SECURITY;
}
if (u16 & 0x0008) {
printf(" PERSIST");
u16 &= ~0x0008;
}
if (u16 & 0x0004) {
printf(" USE_EFUSE_KEY");
u16 &= ~0x0004;
}
if (u16 & 0x0002) {
printf(" CRC_EXTSTAT_DISABLE");
u16 &= ~0x0002;
}
if (u16)
printf(" 0x%x", u16);
printf("\n");
// It seems bit7 and bit0 are always masked in.
if (u16 != 0x81)
printf("#W Expected reserved 0x%x, got 0x%x.\n", 0x0081, u16);
continue;
}
if (cfg->reg[i].reg == PWRDN_REG) {
u16 = cfg->reg[i].int_v;
printf("T1 PWRDN_REG");
if (u16 & 0x4000) {
printf(" EN_EYES");
u16 &= ~0x4000;
}
if (u16 & 0x0020) {
printf(" FILTER_B");
u16 &= ~0x0020;
}
if (u16 & 0x0010) {
printf(" EN_PGSR");
u16 &= ~0x0010;
}
if (u16 & 0x0004) {
printf(" EN_PWRDN");
u16 &= ~0x0004;
}
if (u16 & 0x0001) {
printf(" KEEP_SCLK");
u16 &= ~0x0001;
}
if (u16)
printf(" 0x%x", u16);
printf("\n");
// Reserved bits 13:6 should be 00100010
// according to documentation.
if (u16 != 0x0880)
printf("#W Expected reserved 0x%x, got 0x%x.\n", 0x0880, u16);
continue;
}
if (cfg->reg[i].reg == HC_OPT_REG) {
u16 = cfg->reg[i].int_v;
printf("T1 HC_OPT_REG");
if (u16 & 0x0040) {
printf(" INIT_SKIP");
u16 &= ~0x0040;
}
if (u16)
printf(" 0x%x", u16);
printf("\n");
// Reserved bits 5:0 should be 011111
// according to documentation.
if (u16 != 0x001F)
printf("#W Expected reserved 0x%x, got 0x%x.\n", 0x001F, u16);
continue;
}
if (cfg->reg[i].reg == PU_GWE) {
printf("T1 PU_GWE 0x%03X\n", cfg->reg[i].int_v);
continue;
}
if (cfg->reg[i].reg == PU_GTS) {
printf("T1 PU_GTS 0x%03X\n", cfg->reg[i].int_v);
continue;
}
if (cfg->reg[i].reg == CWDT) {
printf("T1 CWDT 0x%X\n", cfg->reg[i].int_v);
if (cfg->reg[i].int_v < 0x0201)
printf("#W Watchdog timer clock below"
" minimum value of 0x0201.\n");
continue;
}
if (cfg->reg[i].reg == MODE_REG) {
int unexpected_buswidth = 0;
u16 = cfg->reg[i].int_v;
printf("T1 MODE_REG");
if (u16 & (1<<13)) {
printf(" NEW_MODE=BITSTREAM");
u16 &= ~(1<<13);
}
if ((u16 & (1<<12))
&& (u16 & (1<<11)))
unexpected_buswidth = 1;
else if (u16 & (1<<12)) {
printf(" BUSWIDTH=4");
u16 &= ~(1<<12);
} else if (u16 & (1<<11)) {
printf(" BUSWIDTH=2");
u16 &= ~(1<<11);
}
// BUSWIDTH=1 is the default and not displayed
if (u16 & (1<<9)) {
printf(" BOOTMODE_1");
u16 &= ~(1<<9);
}
if (u16 & (1<<8)) {
printf(" BOOTMODE_0");
u16 &= ~(1<<8);
}
if (unexpected_buswidth)
printf("#W Unexpected bus width 0b11.\n");
if (u16)
printf(" 0x%x", u16);
printf("\n");
if (u16)
printf("#W Expected reserved 0, got 0x%x.\n", u16);
continue;
}
if (cfg->reg[i].reg == CCLK_FREQ) {
u16 = cfg->reg[i].int_v;
printf("T1 CCLK_FREQ");
if (u16 & (1<<14)) {
printf(" EXT_MCLK");
u16 &= ~(1<<14);
}
printf(" MCLK_FREQ=0x%03X", u16 & 0x03FF);
u16 &= ~(0x03FF);
if (u16)
printf(" 0x%x", u16);
printf("\n");
if (u16)
printf("#W Expected reserved 0, got 0x%x.\n", u16);
continue;
}
if (cfg->reg[i].reg == EYE_MASK) {
printf("T1 EYE_MASK 0x%X\n", cfg->reg[i].int_v);
continue;
}
if (cfg->reg[i].reg == GENERAL1) {
printf("T1 GENERAL1 0x%X\n", cfg->reg[i].int_v);
continue;
}
if (cfg->reg[i].reg == GENERAL2) {
printf("T1 GENERAL2 0x%X\n", cfg->reg[i].int_v);
continue;
}
if (cfg->reg[i].reg == GENERAL3) {
printf("T1 GENERAL3 0x%X\n", cfg->reg[i].int_v);
continue;
}
if (cfg->reg[i].reg == GENERAL4) {
printf("T1 GENERAL4 0x%X\n", cfg->reg[i].int_v);
continue;
}
if (cfg->reg[i].reg == GENERAL5) {
printf("T1 GENERAL5 0x%X\n", cfg->reg[i].int_v);
continue;
}
if (cfg->reg[i].reg == EXP_SIGN) {
printf("T1 EXP_SIGN 0x%X\n", cfg->reg[i].int_v);
continue;
}
if (cfg->reg[i].reg == SEU_OPT) {
int seu_freq;
u16 = cfg->reg[i].int_v;
seu_freq = (u16 & 0x3FF0) >> 4;
printf("T1 SEU_OPT SEU_FREQ=0x%X", seu_freq);
u16 &= ~(0x3FF0);
if (u16 & (1<<3)) {
printf(" SEU_RUN_ON_ERR");
u16 &= ~(1<<3);
}
if (u16 & (1<<1)) {
printf(" GLUT_MASK");
u16 &= ~(1<<1);
}
if (u16 & (1<<0)) {
printf(" SEU_ENABLE");
u16 &= ~(1<<0);
}
if (u16)
printf(" 0x%x", u16);
printf("\n");
if (u16)
printf("#W Expected reserved 0, got 0x%x.\n", u16);
continue;
}
FAIL(EINVAL);
}
return 0;
fail:
return rc;
}
typedef struct ramb16_cfg
{
uint8_t byte[64];
} __attribute((packed)) ramb16_cfg_t;
static const cfg_atom_t ramb16_instance =
{
{-1}, {12,13, 274,275,276,277,316,317,318,319,
420,421,422,423,-1}, "default_bits"
};
static cfg_atom_t ramb16_atoms[] =
{
// data_width_a
{{264,265,260,261,256,257,-1},{ -1},"data_width_a 1"},
{{264,265,260,261, -1},{ 256,257,-1},"data_width_a 2"},
{{264,265, 256,257,-1},{ 260,261, -1},"data_width_a 4"},
{{264,265, -1},{ 260,261,256,257,-1},"data_width_a 9"},
{{ 260,261,256,257,-1},{264,265, -1},"data_width_a 18"},
{{ 260,261, -1},{264,265, 256,257,-1},"data_width_a 36"},
{{ -1},{264,265,260,261,256,257,-1},"data_width_a 0"},
// data_width_b
{{262,263,286,287,258,259,-1},{ -1},"data_width_b 1"},
{{262,263,286,287, -1},{ 258,259,-1},"data_width_b 2"},
{{262,263, 258,259,-1},{ 286,287, -1},"data_width_b 4"},
{{262,263, -1},{ 286,287,258,259,-1},"data_width_b 9"},
{{ 286,287,258,259,-1},{262,263, -1},"data_width_b 18"},
{{ 286,287, -1},{262,263, 258,259,-1},"data_width_b 36"},
{{ -1},{262,263,286,287,258,259,-1},"data_width_b 0"},
// required
{ { -1}, {266, 267, -1}, "RST_PRIORITY_B:CE" },
{ {266, 267, -1}, { -1}, "RST_PRIORITY_B:SR" },
{ { -1}, {268, 269, -1}, "RST_PRIORITY_A:CE" },
{ {268, 269, -1}, { -1}, "RST_PRIORITY_A:SR" },
{ { -1}, {290, 291, -1}, "EN_RSTRAM_A:TRUE" },
{ {290, 291, -1}, { -1}, "EN_RSTRAM_A:FALSE" },
{ { -1}, {444, 445, -1}, "EN_RSTRAM_B:TRUE" },
{ {444, 445, -1}, { -1}, "EN_RSTRAM_B:FALSE" },
// optional
{ { -1}, { 26, 27, -1}, "CLKAINV:CLKA" },
{ { 26, 27, -1}, { -1}, "CLKAINV:CLKA_B" }, // def
{ { -1}, { 30, 31, -1}, "CLKBINV:CLKB" },
{ { 30, 31, -1}, { -1}, "CLKBINV:CLKB_B" }, // def
{ { -1}, {270, 271, -1}, "RSTTYPE:ASYNC" },
{ {270, 271, -1}, { -1}, "RSTTYPE:SYNC" }, // def
{ { -1}, {278, 279, -1}, "WRITE_MODE_B:READ_FIRST" },
{ { -1}, {280, 281, -1}, "WRITE_MODE_A:READ_FIRST" },
{ { -1}, {282, 283, -1}, "WRITE_MODE_B:NO_CHANGE" },
{ { -1}, {284, 285, -1}, "WRITE_MODE_A:NO_CHANGE" },
{ {278, 279, 282, 283, -1}, {-1}, "WRITE_MODE_B:WRITE_FIRST" }, //def
{ {280, 281, 284, 285, -1}, {-1}, "WRITE_MODE_A:WRITE_FIRST" }, //def
{ { -1}, {306, 307, -1}, "DOB_REG:1" },
{ {306, 306, -1}, { -1}, "DOB_REG:0" }, // def
{ { -1}, {308, 309, -1}, "DOA_REG:1" },
{ {308, 309, -1}, { -1}, "DOA_REG:0" }, // def
{ {431, 467, -1}, {430, 466, -1}, "ENAINV:ENA" }, // def
{ {430, 431, 466, 467, -1}, {-1}, "ENAINV:ENA_B" },
{ {465, 469, -1}, {464, 468, -1}, "ENBINV:ENB" }, // def
{ {464, 465, 468, 469, -1}, {-1}, "ENBINV:ENB_B" },
{ { -1}, { 20, 21, -1}, "REGCEAINV:REGCEA" }, // def
{ { 20, 21, -1}, { -1}, "REGCEAINV:REGCEA_B" },
{ { -1}, { 8, 9, -1}, "REGCEBINV:REGCEB" },
{ { 8, 9, -1}, { -1}, "REGCEBINV:REGCEB_B" }, // def
{ { 24, 25, -1}, { -1}, "RSTAINV:RSTA" }, // def
{ { -1}, { 24, 25, -1}, "RSTAINV:RSTA_B" },
{ { -1}, { 4, 5, -1}, "RSTBINV:RSTB" }, // def
{ { 4, 5, -1}, { -1}, "RSTBINV:RSTB_B" },
{ { -1}, { 19, -1}, "WEA0INV:WEA0" }, // def
{ { 19, -1}, { -1}, "WEA0INV:WEA0_B" },
{ { -1}, { 23, -1}, "WEA2INV:WEA1" }, // def
{ { 23, -1}, { -1}, "WEA2INV:WEA1_B" },
{ { -1}, { 18, -1}, "WEA2INV:WEA2" }, // def
{ { 18, -1}, { -1}, "WEA2INV:WEA2_B" },
{ { -1}, { 22, -1}, "WEA2INV:WEA3" }, // def
{ { 22, -1}, { -1}, "WEA2INV:WEA3_B" },
{ { -1}, { 7, -1}, "WEB0INV:WEB0" }, // def
{ { 7, -1}, { -1}, "WEB0INV:WEB0_B" },
{ { -1}, { 3, -1}, "WEB1INV:WEB1" }, // def
{ { 3, -1}, { -1}, "WEB1INV:WEB1_B" },
{ { -1}, { 6, -1}, "WEB2INV:WEB2" }, // def
{ { 6, -1}, { -1}, "WEB2INV:WEB2_B" },
{ { -1}, { 2, -1}, "WEB3INV:WEB3" }, // def
{ { 2, -1}, { -1}, "WEB3INV:WEB3_B" },
};
static void print_ramb16_cfg(ramb16_cfg_t* cfg)
{
char bits[512];
uint8_t u8;
int i, first_extra;
for (i = 0; i < 32; i++) {
u8 = cfg->byte[i*2];
cfg->byte[i*2] = cfg->byte[i*2+1];
cfg->byte[i*2+1] = u8;
}
for (i = 0; i < 64; i++) {
u8 = 0;
if (cfg->byte[i] & 0x01) u8 |= 0x80;
if (cfg->byte[i] & 0x02) u8 |= 0x40;
if (cfg->byte[i] & 0x04) u8 |= 0x20;
if (cfg->byte[i] & 0x08) u8 |= 0x10;
if (cfg->byte[i] & 0x10) u8 |= 0x08;
if (cfg->byte[i] & 0x20) u8 |= 0x04;
if (cfg->byte[i] & 0x40) u8 |= 0x02;
if (cfg->byte[i] & 0x80) u8 |= 0x01;
cfg->byte[i] = u8;
}
//
// Bits 0..255 come from minor 23, Bits 256..511 from minor 24.
// Each set of 256 bits is divided into two halfs of 128 bits
// that are swept forward and backward to form 2-bit pairs,
// pairs 0..127 are formed out of bits 0..127 and 255..128,
// p128..p255 are formed out of b256..b383 and b511..b384.
// Since so much bit twiddling is already happening, we are sorting
// the bits so that pairs are next to each other.
// The notation for a pair is "p8=01".
// minor 23
for (i = 0; i < 128; i++) {
bits[i*2] = (cfg->byte[i/8] & (1<<(i%8))) != 0;
bits[i*2+1] = (cfg->byte[(255-i)/8]
& (1<<(7-(i%8)))) != 0;
}
// minor 24
for (i = 0; i < 128; i++) {
bits[256+i*2] = (cfg->byte[32+i/8] & (1<<(i%8))) != 0;
bits[256+i*2+1] = (cfg->byte[32+(255-i)/8]
& (1<<(7-(i%8)))) != 0;
}
printf("{\n");
// hexdump(1 /* indent */, &cfg->byte[0], 64 /* len */);
for (i = 0; i < sizeof(ramb16_atoms)/sizeof(ramb16_atoms[0]); i++) {
if (atom_found(bits, &ramb16_atoms[i])
&& ramb16_atoms[i].must_1[0] != -1) {
printf(" %s\n", ramb16_atoms[i].str);
ramb16_atoms[i].flag = 1;
} else
ramb16_atoms[i].flag = 0;
}
for (i = 0; i < sizeof(ramb16_atoms)/sizeof(ramb16_atoms[0]); i++) {
if (ramb16_atoms[i].flag)
atom_remove(bits, &ramb16_atoms[i]);
}
// instantiation bits
if (ramb16_instance.must_1[0] != -1) {
if (atom_found(bits, &ramb16_instance)) {
for (i = 0; ramb16_instance.must_1[i] != -1; i++)
printf(" b%i\n", ramb16_instance.must_1[i]);
atom_remove(bits, &ramb16_instance);
} else
printf(" #W Not all instantiation bits set.\n");
}
// extra bits
first_extra = 1;
for (i = 0; i < 512; i++) {
if (bits[i]) {
if (first_extra) {
printf(" #W Extra bits set.\n");
first_extra = 0;
}
printf(" b%i\n", i);
}
}
printf("}\n");
}
static void printf_routing_2minors(const uint8_t* bits, int row, int major,
int even_minor)
{
int y, i, hclk;
uint64_t u64_0, u64_1;
char bit_str[129];
bit_str[128] = 0;
for (y = 0; y < 16; y++) {
hclk = (y < 8) ? 0 : 2;
u64_0 = frame_get_u64(bits + y*8 + hclk);
u64_1 = frame_get_u64(bits + y*8 + hclk + FRAME_SIZE);
if (u64_0 || u64_1) {
for (i = 0; i < 128; i++)
bit_str[i] = '0';
for (i = 0; i < 64; i++) {
if (u64_0 & (1ULL << i))
bit_str[i*2] = '1';
if (u64_1 & (1ULL << i))
bit_str[i*2+1] = '1';
}
printf("r%i ma%i v64_%02i mip%02i %s\n",
row, major, y, even_minor, bit_str);
}
}
}
static void printf_v64_mi20(const uint8_t* bits, int row, int major)
{
int y, i, num_bits_on, hclk;
uint64_t u64;
char bit_str[65];
bit_str[64] = 0;
for (y = 0; y < 16; y++) {
hclk = (y < 8) ? 0 : 2;
u64 = frame_get_u64(bits + y*8 + hclk);
if (u64) {
for (i = 0; i < 64; i++)
bit_str[i] = (u64 & (1ULL << i)) ? '1' : '0';
printf("r%i ma%i v64_%02i mi20 %s\n",
row, major, y, bit_str);
num_bits_on = 0;
for (i = 0; i < 64; i++) {
if (u64 & (1ULL << i))
num_bits_on++;
}
// this is most helpful for bits 24:39 which are
// part of logic device configuration
if (num_bits_on < 5) {
for (i = 0; i < 64; i++) {
if (!(u64 & (1ULL << i)))
continue;
printf("r%i ma%i v64_%02i mi20 b%i\n",
row, major, y, i);
}
}
}
}
}
static void printf_lut(const uint8_t* bits, int row, int major,
int minor, int v32_i)
{
char bit_str[64];
uint64_t u64;
int i, num_bits_on;
u64 = frame_get_lut64(&bits[minor*FRAME_SIZE], v32_i);
if (u64) {
num_bits_on = 0;
for (i = 0; i < 64; i++) {
if (u64 & (1ULL << i))
num_bits_on++;
}
if (num_bits_on < 5) {
printf("r%i ma%02i v32_%02i mip%02i_lut", row,
major, v32_i, minor);
for (i = 0; i < 64; i++) {
if (u64 & (1ULL << i))
printf(" b%i", i);
}
printf("\n");
} else {
for (i = 0; i < 64; i++)
bit_str[i] = (u64 & (1ULL << i)) ? '1' : '0';
printf("r%i ma%02i v32_%02i mip%02i_lut %.64s\n", row,
major, v32_i, minor, bit_str);
}
}
}
static int dump_maj_zero(const uint8_t* bits, int row, int major)
{
int minor;
for (minor = 0; minor < get_major_minors(XC6SLX9, major); minor++)
printf_clock(&bits[minor*FRAME_SIZE], row, major, minor);
for (minor = 0; minor < get_major_minors(XC6SLX9, major); minor++)
printf_frames(&bits[minor*FRAME_SIZE], /*max_frames*/ 1,
row, major, minor, /*print_empty*/ 0, /*no_clock*/ 1);
return 0;
}
static int dump_maj_left(const uint8_t* bits, int row, int major)
{
int minor;
for (minor = 0; minor < get_major_minors(XC6SLX9, major); minor++)
printf_clock(&bits[minor*FRAME_SIZE], row, major, minor);
for (minor = 0; minor < get_major_minors(XC6SLX9, major); minor++)
printf_frames(&bits[minor*FRAME_SIZE], /*max_frames*/ 1,
row, major, minor, /*print_empty*/ 0, /*no_clock*/ 1);
return 0;
}
static int dump_maj_right(const uint8_t* bits, int row, int major)
{
int minor;
for (minor = 0; minor < get_major_minors(XC6SLX9, major); minor++)
printf_clock(&bits[minor*FRAME_SIZE], row, major, minor);
for (minor = 0; minor < get_major_minors(XC6SLX9, major); minor++)
printf_frames(&bits[minor*FRAME_SIZE], /*max_frames*/ 1,
row, major, minor, /*print_empty*/ 0, /*no_clock*/ 1);
return 0;
}
static int dump_maj_logic(const uint8_t* bits, int row, int major)
{
const struct xc_die* xci = xc_die_info(XC6SLX9);
int minor, i, logdev_start, logdev_end;
for (minor = 0; minor < xci->majors[major].minors; minor++)
printf_clock(&bits[minor*FRAME_SIZE], row, major, minor);
// 0:19 routing minor pairs
for (i = 0; i < 10; i++)
printf_routing_2minors(&bits[i*2*FRAME_SIZE], row, major, i*2);
// mi20 as 64-char 0/1 string
printf_v64_mi20(&bits[20*FRAME_SIZE], row, major);
logdev_start = 0;
logdev_end = 15;
if (xci->majors[major].flags & XC_MAJ_TOP_BOT_IO) {
if (row == xc_die_info(XC6SLX9)->num_rows-1)
logdev_start += TOPBOT_IO_ROWS;
else if (!row)
logdev_end -= TOPBOT_IO_ROWS;
}
if (xci->majors[major].flags & XC_MAJ_XM) {
if (xci->majors[major].minors != 31) HERE();
// M devices
if (logdev_start)
printf_extrabits(bits, 21, 2, 0, logdev_start*64, row, major);
for (i = logdev_start; i <= logdev_end; i++) {
printf_lut(bits, row, major, 21, i*2);
printf_lut(bits, row, major, 21, i*2+1);
}
if (logdev_end < 15)
printf_extrabits(bits, 21, 2, i*64 + XC6_HCLK_BITS, (15-logdev_end)*64, row, major);
printf_frames(&bits[23*FRAME_SIZE], /*max_frames*/ 1,
row, major, 23, /*print_empty*/ 0, /*no_clock*/ 1);
if (logdev_start)
printf_extrabits(bits, 24, 2, 0, logdev_start*64, row, major);
for (i = logdev_start; i <= logdev_end; i++) {
printf_lut(bits, row, major, 24, i*2);
printf_lut(bits, row, major, 24, i*2+1);
}
if (logdev_end < 15)
printf_extrabits(bits, 24, 2, i*64 + XC6_HCLK_BITS, (15-logdev_end)*64, row, major);
// X devices
printf_frames(&bits[26*FRAME_SIZE], /*max_frames*/ 1,
row, major, 26, /*print_empty*/ 0, /*no_clock*/ 1);
if (logdev_start)
printf_extrabits(bits, 27, 4, 0, logdev_start*64, row, major);
for (i = logdev_start; i <= logdev_end; i++) {
printf_lut(bits, row, major, 27, i*2);
printf_lut(bits, row, major, 29, i*2);
printf_lut(bits, row, major, 27, i*2+1);
printf_lut(bits, row, major, 29, i*2+1);
}
if (logdev_end < 15)
printf_extrabits(bits, 27, 4, i*64 + XC6_HCLK_BITS, (15-logdev_end)*64, row, major);
} else if (xci->majors[major].flags & (XC_MAJ_XL|XC_MAJ_CENTER)) {
// L devices
if (logdev_start)
printf_extrabits(bits, 21, 4, 0, logdev_start*64, row, major);
for (i = logdev_start; i <= logdev_end; i++) {
printf_lut(bits, row, major, 21, i*2);
printf_lut(bits, row, major, 23, i*2);
printf_lut(bits, row, major, 21, i*2+1);
printf_lut(bits, row, major, 23, i*2+1);
}
if (logdev_end < 15)
printf_extrabits(bits, 21, 4, i*64 + XC6_HCLK_BITS, (15-logdev_end)*64, row, major);
printf_frames(&bits[25*FRAME_SIZE], /*max_frames*/ 1,
row, major, 25, /*print_empty*/ 0, /*no_clock*/ 1);
// X devices
if (logdev_start)
printf_extrabits(bits, 26, 4, 0, logdev_start*64, row, major);
for (i = logdev_start; i <= logdev_end; i++) {
printf_lut(bits, row, major, 26, i*2);
printf_lut(bits, row, major, 28, i*2);
printf_lut(bits, row, major, 26, i*2+1);
printf_lut(bits, row, major, 28, i*2+1);
}
if (logdev_end < 15)
printf_extrabits(bits, 26, 4, i*64 + XC6_HCLK_BITS, (15-logdev_end)*64, row, major);
// one extra minor in the center major
if (xci->majors[major].flags & XC_MAJ_CENTER) {
if (xci->majors[major].minors != 31) HERE();
printf_frames(&bits[30*FRAME_SIZE], /*max_frames*/ 1,
row, major, 30, /*print_empty*/ 0, /*no_clock*/ 1);
} else { // XL
if (xci->majors[major].minors != 30) HERE();
}
} else
HERE();
return 0;
}
static int dump_maj_bram(const uint8_t* bits, int row, int major)
{
ramb16_cfg_t ramb16_cfg[4];
int minor, i, j, offset_in_frame;
for (minor = 0; minor < get_major_minors(XC6SLX9, major); minor++)
printf_clock(&bits[minor*FRAME_SIZE], row, major, minor);
// 0:19 routing minor pairs
for (i = 0; i < 10; i++)
printf_routing_2minors(&bits[i*2*FRAME_SIZE], row, major, i*2);
// mi20 as 64-char 0/1 string
printf_v64_mi20(&bits[20*FRAME_SIZE], row, major);
printf_frames(&bits[21*FRAME_SIZE], /*max_frames*/ 1,
row, major, 21, /*print_empty*/ 0, /*no_clock*/ 1);
printf_frames(&bits[22*FRAME_SIZE], /*max_frames*/ 1,
row, major, 22, /*print_empty*/ 0, /*no_clock*/ 1);
// minors 23&24
for (i = 0; i < 4; i++) {
offset_in_frame = i*32;
if (offset_in_frame >= 64)
offset_in_frame += 2;
for (j = 0; j < 32; j++) {
ramb16_cfg[i].byte[j] = bits[23*130+offset_in_frame+j];
ramb16_cfg[i].byte[j+32] = bits[24*130+offset_in_frame+j];
}
}
for (i = 0; i < 4; i++) {
for (j = 0; j < 64; j++) {
if (ramb16_cfg[i].byte[j])
break;
}
if (j >= 64)
continue;
printf("r%i ma%i ramb16 i%i\n",
row, major, i);
print_ramb16_cfg(&ramb16_cfg[i]);
}
return 0;
}
static int dump_maj_macc(const uint8_t* bits, int row, int major)
{
int minor, i;
for (minor = 0; minor < get_major_minors(XC6SLX9, major); minor++)
printf_clock(&bits[minor*FRAME_SIZE], row, major, minor);
// 0:19 routing minor pairs
for (i = 0; i < 10; i++)
printf_routing_2minors(&bits[i*2*FRAME_SIZE], row, major, i*2);
// mi20 as 64-char 0/1 string
printf_v64_mi20(&bits[20*FRAME_SIZE], row, major);
for (minor = 21; minor < get_major_minors(XC6SLX9, major); minor++)
printf_frames(&bits[minor*FRAME_SIZE], /*max_frames*/ 1,
row, major, minor, /*print_empty*/ 0, /*no_clock*/ 1);
return 0;
}
static int dump_bits(struct fpga_config* cfg)
{
int idcode, num_rows, row, major, off, rc;
if (cfg->idcode_reg == -1) FAIL(EINVAL);
idcode = cfg->reg[cfg->idcode_reg].int_v;
num_rows = xc_num_rows(idcode);
if (num_rows < 1) FAIL(EINVAL);
// type0
for (major = 0; major <= get_rightside_major(idcode); major++) {
for (row = num_rows-1; row >= 0; row--) {
off = (row*get_frames_per_row(idcode) + get_major_framestart(idcode, major)) * FRAME_SIZE;
switch (get_major_type(idcode, major)) {
case MAJ_ZERO:
rc = dump_maj_zero(&cfg->bits.d[off], row, major);
if (rc) FAIL(rc);
break;
case MAJ_LEFT:
rc = dump_maj_left(&cfg->bits.d[off], row, major);
if (rc) FAIL(rc);
break;
case MAJ_RIGHT:
rc = dump_maj_right(&cfg->bits.d[off], row, major);
if (rc) FAIL(rc);
break;
case MAJ_LOGIC_XM:
case MAJ_LOGIC_XL:
case MAJ_CENTER:
rc = dump_maj_logic(&cfg->bits.d[off], row, major);
if (rc) FAIL(rc);
break;
case MAJ_BRAM:
rc = dump_maj_bram(&cfg->bits.d[off], row, major);
if (rc) FAIL(rc);
break;
case MAJ_MACC:
rc = dump_maj_macc(&cfg->bits.d[off], row, major);
if (rc) FAIL(rc);
break;
default: HERE(); break;
}
}
}
return 0;
fail:
return rc;
}
static int dump_bram(struct fpga_config* cfg)
{
int row, i, j, off, newline;
newline = 0;
for (row = 0; row < 4; row++) {
for (i = 0; i < 8; i++) {
for (j = 0; j < 18*130; j++) {
if (cfg->bits.d[BRAM_DATA_START + row*144*130
+ i*18*130 + j])
break;
}
if (j >= 18*130)
continue;
if (!newline) {
newline = 1;
printf("\n");
}
printf("br%i ramb16 i%i\n", row, i);
printf("{\n");
off = BRAM_DATA_START + row*144*130 + i*18*130;
printf_ramb16_data(cfg->bits.d, off);
printf("}\n");
}
}
return 0;
}
int dump_config(struct fpga_config* cfg, int flags)
{
int rc;
if (flags & DUMP_HEADER_STR)
dump_header(cfg);
if (flags & DUMP_REGS) {
rc = dump_regs(cfg, /*start*/ 0, cfg->num_regs_before_bits, flags & DUMP_CRC);
if (rc) FAIL(rc);
}
if (flags & DUMP_BITS) {
rc = dump_bits(cfg);
if (rc) FAIL(rc);
rc = dump_bram(cfg);
if (rc) FAIL(rc);
printf_type2(cfg->bits.d, cfg->bits.len,
BRAM_DATA_START + BRAM_DATA_LEN, 896*2/8);
if (flags & DUMP_CRC)
printf("auto-crc 0x%X\n", cfg->auto_crc);
}
if (flags & DUMP_REGS) {
rc = dump_regs(cfg, cfg->num_regs_before_bits, cfg->num_regs, flags & DUMP_CRC);
if (rc) FAIL(rc);
}
return 0;
fail:
return rc;
}
void free_config(struct fpga_config* cfg)
{
free(cfg->bits.d);
cfg->bits.d = 0;
memset(cfg, 0, sizeof(*cfg));
}
static const uint8_t s_bit_bof[] = {
0x00, 0x09, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0,
0x0F, 0xF0, 0x00, 0x00, 0x01 };
static const uint8_t s_0xFF_words[] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
static int parse_header(struct fpga_config* cfg, uint8_t* d, int len,
int inpos, int* outdelta)
{
int i, str_len;
*outdelta = 0;
if (inpos + 13 > len) {
fprintf(stderr, "#E File size %i below minimum of 13 bytes.\n",
len);
return -1;
}
for (i = 0; i < 13; i++) {
if (d[inpos+*outdelta+i] == s_bit_bof[i])
continue;
fprintf(stderr, "#E Expected 0x%x, got 0x%x at off %i\n",
s_bit_bof[i], d[inpos+*outdelta+i],
inpos+*outdelta+i);
}
*outdelta += 13;
// 4 strings 'a' - 'd', 16-bit length
for (i = 'a'; i <= 'd'; i++) {
if (inpos + *outdelta + 3 > len) {
fprintf(stderr, "#E Unexpected EOF at %i.\n", len);
return -1;
}
if (d[inpos + *outdelta] != i) {
fprintf(stderr, "#E Expected string code '%c', got "
"'%c'.\n", i, d[inpos + *outdelta]);
return -1;
}
str_len = __be16_to_cpu(*(uint16_t*)&d[inpos + *outdelta + 1]);
if (inpos + *outdelta + 3 + str_len > len) {
fprintf(stderr, "#E Unexpected EOF at %i.\n", len);
return -1;
}
if (d[inpos + *outdelta + 3 + str_len - 1]) {
fprintf(stderr, "#E z-terminated string ends with %0xh"
".\n", d[inpos + *outdelta + 3 + str_len - 1]);
return -1;
}
strcpy(cfg->header_str[i-'a'], (char*) &d[inpos + *outdelta + 3]);
*outdelta += 3 + str_len;
}
return 0;
}
static int FAR_pos(int FAR_row, int FAR_major, int FAR_minor)
{
int result, i;
if (FAR_row < 0 || FAR_major < 0 || FAR_minor < 0)
return -1;
if (FAR_row > 3 || FAR_major > 17
|| FAR_minor >= get_major_minors(XC6SLX9, FAR_major))
return -1;
result = FAR_row * 505*130;
for (i = 0; i < FAR_major; i++)
result += get_major_minors(XC6SLX9, i)*130;
return result + FAR_minor*130;
}
static int read_bits(struct fpga_config* cfg, uint8_t* d, int len,
int inpos, int* outdelta)
{
int src_off, packet_hdr_type, packet_hdr_opcode;
int packet_hdr_register, packet_hdr_wordcount;
int FAR_block, FAR_row, FAR_major, FAR_minor, i, j, rc, MFW_src_off;
int offset_in_bits, block0_words, padding_frames, last_FDRI_pos;
uint16_t u16;
uint32_t u32;
last_FDRI_pos = -1;
*outdelta = 0;
if (cfg->idcode_reg == -1 || cfg->FLR_reg == -1
|| (cfg->reg[cfg->idcode_reg].int_v != XC6SLX4
&& cfg->reg[cfg->idcode_reg].int_v != XC6SLX9)
|| cfg->reg[cfg->FLR_reg].int_v != 896)
FAIL(EINVAL);
cfg->bits.len = (4*505 + 4*144) * 130 + 896*2;
cfg->bits.d = calloc(cfg->bits.len, 1 /* elsize */);
if (!cfg->bits.d) FAIL(ENOMEM);
cfg->auto_crc = 0;
FAR_block = -1;
FAR_row = -1;
FAR_major = -1;
FAR_minor = -1;
MFW_src_off = -1;
// Go through bit_file from first_FAR_off (inpos) until last byte
// of IOB was read, plus padding, plus CRC verification.
src_off = inpos;
while (src_off < len) {
if (src_off + 2 > len) FAIL(EINVAL);
u16 = __be16_to_cpu(*(uint16_t*)&d[src_off]);
src_off += 2;
// 3 bits: 001 = Type 1; 010 = Type 2
packet_hdr_type = (u16 & 0xE000) >> 13;
if (packet_hdr_type != 1 && packet_hdr_type != 2)
FAIL(EINVAL);
// 2 bits: 00 = noop; 01 = read; 10 = write; 11 = reserved
packet_hdr_opcode = (u16 & 0x1800) >> 11;
if (packet_hdr_opcode == 3) FAIL(EINVAL);
if (packet_hdr_opcode == 0) { // noop
if (packet_hdr_type != 1 || u16 & 0x07FF) FAIL(EINVAL);
continue;
}
// Now we must look at a Type 1 command
packet_hdr_register = (u16 & 0x07E0) >> 5;
packet_hdr_wordcount = u16 & 0x001F;
if (src_off + packet_hdr_wordcount*2 > len) FAIL(EINVAL);
if (packet_hdr_type == 1) {
if (packet_hdr_register == CMD) {
if (packet_hdr_wordcount != 1) FAIL(EINVAL);
u16 = __be16_to_cpu(
*(uint16_t*)&d[src_off]);
if (u16 == CMD_GRESTORE || u16 == CMD_LFRM) {
if (last_FDRI_pos == -1) FAIL(EINVAL);
src_off = last_FDRI_pos;
goto success;
}
if (u16 != CMD_MFW && u16 != CMD_WCFG)
FAIL(EINVAL);
if (u16 == CMD_MFW) {
if (FAR_block != 0) FAIL(EINVAL);
MFW_src_off = FAR_pos(FAR_row, FAR_major, FAR_minor);
if (MFW_src_off == -1) FAIL(EINVAL);
}
src_off += 2;
continue;
}
if (packet_hdr_register == FAR_MAJ) {
uint16_t maj, min;
if (packet_hdr_wordcount != 2) FAIL(EINVAL);
maj = __be16_to_cpu(*(uint16_t*)
&d[src_off]);
min = __be16_to_cpu(*(uint16_t*)
&d[src_off+2]);
FAR_block = (maj & 0xF000) >> 12;
if (FAR_block > 7) FAIL(EINVAL);
FAR_row = (maj & 0x0F00) >> 8;
FAR_major = maj & 0x00FF;
FAR_minor = min & 0x03FF;
src_off += 4;
continue;
}
if (packet_hdr_register == MFWR) {
uint32_t first_dword, second_dword;
if (packet_hdr_wordcount != 4) FAIL(EINVAL);
first_dword = __be32_to_cpu(
*(uint32_t*)&d[src_off]);
second_dword = __be32_to_cpu(
*(uint32_t*)&d[src_off+4]);
if (first_dword || second_dword) FAIL(EINVAL);
// The first MFWR will overwrite itself, so
// use memmove().
if (FAR_block != 0) FAIL(EINVAL);
offset_in_bits = FAR_pos(FAR_row, FAR_major, FAR_minor);
if (offset_in_bits == -1) FAIL(EINVAL);
memmove(&cfg->bits.d[offset_in_bits], &cfg->bits.d[MFW_src_off], 130);
src_off += 8;
continue;
}
FAIL(EINVAL);
}
// packet type must be 2 here
if (packet_hdr_wordcount != 0) FAIL(EINVAL);
if (packet_hdr_register != FDRI) FAIL(EINVAL);
if (src_off + 4 > len) FAIL(EINVAL);
u32 = __be32_to_cpu(*(uint32_t*)&d[src_off]);
src_off += 4;
if (src_off+2*u32 > len) FAIL(EINVAL);
if (2*u32 < 130) FAIL(EINVAL);
last_FDRI_pos = src_off+u32*2+/*auto-crc*/4;
// fdri words u32
if (FAR_block == -1 || FAR_block > 1 || FAR_row == -1
|| FAR_major == -1 || FAR_minor == -1)
FAIL(EINVAL);
block0_words = 0;
if (!FAR_block) {
offset_in_bits = FAR_pos(FAR_row, FAR_major, FAR_minor);
if (offset_in_bits == -1) FAIL(EINVAL);
if (!FAR_row && !FAR_major && !FAR_minor
&& u32 > 4*(505+2)*65)
block0_words = 4*(505+2)*65;
else {
block0_words = u32;
if (block0_words % 65) FAIL(EINVAL);
}
padding_frames = 0;
for (i = 0; i < block0_words/65; i++) {
if (i && i+1 == block0_words/65) {
for (j = 0; j < 130; j++) {
if (d[src_off+i*130+j]
!= 0xFF) break;
}
// Not sure about the exact logic to
// determine a padding frame. Maybe
// first word all 1? For now we skip
// the frame as a padding frame when
// it's the last frame of a block and
// all-1.
if (j >= 130)
break;
}
if (!FAR_major && !FAR_minor
&& (i%507 == 505)) {
for (j = 0; j < 2*130; j++) {
if (d[src_off+i*130+j]
!= 0xFF) FAIL(EINVAL);
}
i++;
padding_frames += 2;
continue;
}
memcpy(&cfg->bits.d[offset_in_bits
+ (i-padding_frames)*130],
&d[src_off + i*130], 130);
}
}
if (u32 - block0_words > 0) {
int bram_data_words = 4*144*65 + 896;
if (u32 - block0_words != bram_data_words + 1) FAIL(EINVAL);
offset_in_bits = BRAM_DATA_START;
memcpy(&cfg->bits.d[offset_in_bits],
&d[src_off+block0_words*2],
bram_data_words*2);
u16 = __be16_to_cpu(*(uint16_t*)&d[
(src_off+block0_words+bram_data_words)*2]);
if (u16) FAIL(EINVAL);
}
src_off += 2*u32;
cfg->auto_crc = __be32_to_cpu(*(uint32_t*)&d[src_off]);
src_off += 4;
}
rc = EINVAL;
fail:
free(cfg->bits.d);
cfg->bits.d = 0;
return rc;
success:
*outdelta = src_off - inpos;
return 0;
}
static int parse_commands(struct fpga_config* cfg, uint8_t* d,
int len, int inpos)
{
int curpos, cmd_len, first_FAR_off, u16_off, rc;
int packet_hdr_type, packet_hdr_opcode, packet_hdr_register;
int packet_hdr_wordcount, i;
uint32_t u32;
uint16_t u16;
curpos = inpos;
if (curpos + 5 > len
|| d[curpos] != 'e') FAIL(EINVAL);
cmd_len = __be32_to_cpu(*(uint32_t*)&d[curpos + 1]);
curpos += 5;
if (curpos + cmd_len > len) FAIL(EINVAL);
if (curpos + cmd_len < len) {
printf("#W Unexpected continuation after offset "
"%i (len %i).\n", curpos + cmd_len, len);
}
if (curpos >= len) FAIL(EINVAL);
if (d[curpos] != 0xAA) {
while (curpos < len && d[curpos] != 0xAA) {
if (d[curpos] != 0xFF) {
printf("#W Expected 0xFF, but got 0x%X at "
"offset %i\n", d[curpos], curpos);
}
curpos++; if (curpos >= len) FAIL(EINVAL);
}
}
if (curpos + 4 > len) FAIL(EINVAL);
u32 = __be32_to_cpu(*(uint32_t*)&d[curpos]);
curpos += 4;
if (u32 != SYNC_WORD) {
fprintf(stderr, "#E Unexpected sync word 0x%x.\n", u32);
FAIL(EINVAL);
}
first_FAR_off = -1;
while (curpos < len) {
// packet header: ug380, Configuration Packets (p88)
if (curpos + 2 > len) FAIL(EINVAL);
u16 = __be16_to_cpu(*(uint16_t*)&d[curpos]);
u16_off = curpos; curpos += 2;
// 3 bits: 001 = Type 1; 010 = Type 2
packet_hdr_type = (u16 & 0xE000) >> 13;
if (packet_hdr_type != 1 && packet_hdr_type != 2) FAIL(EINVAL);
// 2 bits: 00 = noop; 01 = read; 10 = write; 11 = reserved
packet_hdr_opcode = (u16 & 0x1800) >> 11;
if (packet_hdr_opcode == 3) FAIL(EINVAL);
if (packet_hdr_opcode == 0) { // noop
if (packet_hdr_type != 1 || u16 & 0x07FF) FAIL(EINVAL);
cfg->reg[cfg->num_regs++].reg = REG_NOOP;
continue;
}
packet_hdr_register = (u16 & 0x07E0) >> 5;
packet_hdr_wordcount = u16 & 0x001F;
if (curpos + packet_hdr_wordcount*2 > len) FAIL(EINVAL);
curpos += packet_hdr_wordcount*2;
if (packet_hdr_type == 2) {
int outdelta;
if (packet_hdr_wordcount != 0) {
printf("#W 0x%x=0x%x Unexpected Type 2 "
"wordcount.\n", u16_off, u16);
}
if (packet_hdr_register != FDRI) FAIL(EINVAL);
// first FAR must be before FDRI, and we should only
// execute the FDRI code here once.
if (first_FAR_off == -1) FAIL(EINVAL);
if (cfg->num_regs_before_bits != -1) FAIL(EINVAL);
if (curpos + 4 > len) FAIL(EINVAL);
u32 = __be32_to_cpu(*(uint32_t*)&d[curpos]);
curpos += 4;
if (curpos+2*u32 > len) FAIL(EINVAL);
if (2*u32 < 130) FAIL(EINVAL);
cfg->reg[cfg->num_regs].reg = FDRI;
cfg->reg[cfg->num_regs].int_v = u32;
cfg->num_regs++;
cfg->num_regs_before_bits = cfg->num_regs;
rc = read_bits(cfg, d, len, first_FAR_off, &outdelta);
if (rc) FAIL(rc);
curpos = first_FAR_off + outdelta;
continue;
}
if (packet_hdr_type != 1) FAIL(EINVAL);
if (packet_hdr_register == IDCODE) {
if (packet_hdr_wordcount != 2) FAIL(EINVAL);
if (cfg->idcode_reg != -1) FAIL(EINVAL);
cfg->idcode_reg = cfg->num_regs;
cfg->reg[cfg->num_regs].reg = IDCODE;
cfg->reg[cfg->num_regs].int_v =
__be32_to_cpu(*(uint32_t*)&d[u16_off+2]);
cfg->num_regs++;
if ((cfg->reg[cfg->idcode_reg].int_v == XC6SLX4
|| cfg->reg[cfg->idcode_reg].int_v == XC6SLX9)
&& cfg->reg[cfg->FLR_reg].int_v != 896)
printf("#W Unexpected FLR value %i on "
"idcode 0x%X.\n",
cfg->reg[cfg->FLR_reg].int_v,
cfg->reg[cfg->idcode_reg].int_v);
continue;
}
if (packet_hdr_register == FLR) {
if (packet_hdr_wordcount != 1) FAIL(EINVAL);
if (cfg->FLR_reg != -1) FAIL(EINVAL);
cfg->FLR_reg = cfg->num_regs;
//
// First come the type 0 frames (clb, bram
// cfg, dsp, etc). Then type 1 (bram data),
// then type 2, the IOB cfg data block.
// FLR is counted in 16-bit words, and there is
// 1 extra dummy 0x0000 after that.
//
cfg->reg[cfg->num_regs].reg = FLR;
cfg->reg[cfg->num_regs].int_v =
__be16_to_cpu(*(uint16_t*)&d[u16_off+2]);
cfg->num_regs++;
if ((cfg->reg[cfg->FLR_reg].int_v*2) % 8)
printf("#W FLR*2 should be multiple of "
"8, but modulo 8 is %i\n",
(cfg->reg[cfg->FLR_reg].int_v*2) % 8);
continue;
}
if (packet_hdr_register == FAR_MAJ) {
if (packet_hdr_wordcount != 2) FAIL(EINVAL);
if (first_FAR_off == -1)
first_FAR_off = u16_off;
cfg->reg[cfg->num_regs].reg = FAR_MAJ;
cfg->reg[cfg->num_regs].far[FAR_MAJ_O] =
__be16_to_cpu(*(uint16_t*)&d[u16_off+2]);
cfg->reg[cfg->num_regs].far[FAR_MIN_O] =
__be16_to_cpu(*(uint16_t*)&d[u16_off+4]);
cfg->num_regs++;
continue;
}
if (packet_hdr_register == MFWR) {
uint32_t first_dword, second_dword;
if (packet_hdr_wordcount != 4) FAIL(EINVAL);
first_dword = __be32_to_cpu(*(uint32_t*)&d[u16_off+2]);
second_dword = __be32_to_cpu(*(uint32_t*)&d[u16_off+6]);
if (first_dword || second_dword) FAIL(EINVAL);
cfg->reg[cfg->num_regs++].reg = MFWR;
continue;
}
if (packet_hdr_register == CRC
|| packet_hdr_register == EXP_SIGN) {
if (packet_hdr_wordcount != 2) FAIL(EINVAL);
cfg->reg[cfg->num_regs].reg = packet_hdr_register;
cfg->reg[cfg->num_regs].int_v =
__be32_to_cpu(*(uint32_t*)&d[u16_off+2]);
cfg->num_regs++;
continue;
}
if (packet_hdr_register == CMD
|| packet_hdr_register == COR1
|| packet_hdr_register == COR2
|| packet_hdr_register == CTL
|| packet_hdr_register == MASK
|| packet_hdr_register == PWRDN_REG
|| packet_hdr_register == HC_OPT_REG
|| packet_hdr_register == PU_GWE
|| packet_hdr_register == PU_GTS
|| packet_hdr_register == CWDT
|| packet_hdr_register == MODE_REG
|| packet_hdr_register == CCLK_FREQ
|| packet_hdr_register == EYE_MASK
|| packet_hdr_register == GENERAL1
|| packet_hdr_register == GENERAL2
|| packet_hdr_register == GENERAL3
|| packet_hdr_register == GENERAL4
|| packet_hdr_register == GENERAL5
|| packet_hdr_register == SEU_OPT) {
if (packet_hdr_wordcount != 1) FAIL(EINVAL);
cfg->reg[cfg->num_regs].reg = packet_hdr_register;
cfg->reg[cfg->num_regs].int_v =
__be16_to_cpu(*(uint16_t*)&d[u16_off+2]);
cfg->num_regs++;
continue;
}
printf("#W 0x%x=0x%x T1 %i (%u words)", u16_off, u16,
packet_hdr_register, packet_hdr_wordcount);
for (i = 0; (i < 8) && (i < packet_hdr_wordcount); i++)
printf(" 0x%x", __be16_to_cpu(*(uint16_t*)
&d[u16_off+2+i*2]));
printf("\n");
}
return 0;
fail:
return rc;
}
static int write_header_str(FILE* f, int code, const char* s)
{
uint16_t be16_len;
int s_len, nwritten, rc;
// format: 8-bit code 'a' - 'd'
// 16-bit string len, including '\0'
// z-terminated string
if (fputc(code, f) == EOF) FAIL(errno);
s_len = strlen(s)+1;
be16_len = __cpu_to_be16(s_len);
nwritten = fwrite(&be16_len, /*size*/ 1, sizeof(be16_len), f);
if (nwritten != sizeof(be16_len)) FAIL(errno);
nwritten = fwrite(s, /*size*/ 1, s_len, f);
if (nwritten != s_len) FAIL(errno);
return 0;
fail:
return rc;
}
static int write_header(FILE* f, const char* str_a, const char* str_b, const char* str_c, const char* str_d)
{
int nwritten, rc;
nwritten = fwrite(s_bit_bof, /*size*/ 1, sizeof(s_bit_bof), f);
if (nwritten != sizeof(s_bit_bof)) FAIL(errno);
rc = write_header_str(f, 'a', str_a);
if (rc) FAIL(rc);
rc = write_header_str(f, 'b', str_b);
if (rc) FAIL(rc);
rc = write_header_str(f, 'c', str_c);
if (rc) FAIL(rc);
rc = write_header_str(f, 'd', str_d);
if (rc) FAIL(rc);
return 0;
fail:
return rc;
}
static struct fpga_config_reg_rw s_defregs_before_bits[] =
{{ CMD, .int_v = CMD_RCRC },
{ REG_NOOP },
{ FLR, .int_v = 896 },
{ COR1, .int_v = COR1_DEF | COR1_CRC_BYPASS },
{ COR2, .int_v = COR2_DEF },
{ IDCODE, .int_v = XC6SLX9 },
{ MASK, .int_v = MASK_DEF },
{ CTL, .int_v = CTL_DEF },
{ REG_NOOP }, { REG_NOOP }, { REG_NOOP }, { REG_NOOP },
{ REG_NOOP }, { REG_NOOP }, { REG_NOOP }, { REG_NOOP },
{ REG_NOOP }, { REG_NOOP }, { REG_NOOP }, { REG_NOOP },
{ REG_NOOP }, { REG_NOOP }, { REG_NOOP }, { REG_NOOP },
{ REG_NOOP },
{ CCLK_FREQ, .int_v = CCLK_FREQ_DEF },
{ PWRDN_REG, .int_v = PWRDN_REG_DEF },
{ EYE_MASK, .int_v = EYE_MASK_DEF },
{ HC_OPT_REG, .int_v = HC_OPT_REG_DEF },
{ CWDT, .int_v = CWDT_DEF },
{ PU_GWE, .int_v = PU_GWE_DEF },
{ PU_GTS, .int_v = PU_GTS_DEF },
{ MODE_REG, .int_v = MODE_REG_DEF },
{ GENERAL1, .int_v = GENERAL1_DEF },
{ GENERAL2, .int_v = GENERAL2_DEF },
{ GENERAL3, .int_v = GENERAL3_DEF },
{ GENERAL4, .int_v = GENERAL4_DEF },
{ GENERAL5, .int_v = GENERAL5_DEF },
{ SEU_OPT, .int_v = SEU_OPT_DEF },
{ EXP_SIGN, .int_v = EXP_SIGN_DEF },
{ REG_NOOP }, { REG_NOOP },
{ FAR_MAJ, .far = { 0, 0 }},
{ CMD, .int_v = CMD_WCFG }};
static struct fpga_config_reg_rw s_defregs_after_bits[] =
{{ REG_NOOP }, { REG_NOOP }, { REG_NOOP }, { REG_NOOP },
{ REG_NOOP }, { REG_NOOP }, { REG_NOOP }, { REG_NOOP },
{ REG_NOOP }, { REG_NOOP }, { REG_NOOP }, { REG_NOOP },
{ REG_NOOP }, { REG_NOOP }, { REG_NOOP }, { REG_NOOP },
{ REG_NOOP }, { REG_NOOP }, { REG_NOOP }, { REG_NOOP },
{ REG_NOOP }, { REG_NOOP }, { REG_NOOP }, { REG_NOOP },
{ CMD, .int_v = CMD_GRESTORE },
{ CMD, .int_v = CMD_LFRM },
{ REG_NOOP }, { REG_NOOP }, { REG_NOOP }, { REG_NOOP },
{ CMD, .int_v = CMD_GRESTORE },
{ CMD, .int_v = CMD_START },
{ MASK, .int_v = MASK_DEF | MASK_SECURITY },
{ CTL, .int_v = CTL_DEF },
{ CRC, .int_v = DEFAULT_AUTO_CRC },
{ CMD, .int_v = CMD_DESYNC },
{ REG_NOOP }, { REG_NOOP }, { REG_NOOP }, { REG_NOOP },
{ REG_NOOP }, { REG_NOOP }, { REG_NOOP }, { REG_NOOP },
{ REG_NOOP }, { REG_NOOP }, { REG_NOOP }, { REG_NOOP },
{ REG_NOOP }, { REG_NOOP }};
static int write_reg_action(FILE* f, const struct fpga_config_reg_rw* reg)
{
uint16_t u16;
int nwritten, i, rc;
if (reg->reg == REG_NOOP) {
u16 = __cpu_to_be16(1 << PACKET_HDR_TYPE_S);
nwritten = fwrite(&u16, /*size*/ 1, sizeof(u16), f);
if (nwritten != sizeof(u16)) FAIL(errno);
return 0;
}
if (reg->reg == MFWR) {
u16 = PACKET_TYPE_1 << PACKET_HDR_TYPE_S;
u16 |= PACKET_HDR_OPCODE_WRITE << PACKET_HDR_OPCODE_S;
u16 |= reg->reg << PACKET_HDR_REG_S;
u16 |= 4; // four 16-bit words
u16 = __cpu_to_be16(u16);
nwritten = fwrite(&u16, /*size*/ 1, sizeof(u16), f);
if (nwritten != sizeof(u16)) FAIL(errno);
u16 = 0;
for (i = 0; i < 4; i++) {
nwritten = fwrite(&u16, /*size*/ 1, sizeof(u16), f);
if (nwritten != sizeof(u16)) FAIL(errno);
}
return 0;
}
if (reg->reg == FAR_MAJ) {
u16 = PACKET_TYPE_1 << PACKET_HDR_TYPE_S;
u16 |= PACKET_HDR_OPCODE_WRITE << PACKET_HDR_OPCODE_S;
u16 |= reg->reg << PACKET_HDR_REG_S;
u16 |= 2; // two 16-bit words
u16 = __cpu_to_be16(u16);
nwritten = fwrite(&u16, /*size*/ 1, sizeof(u16), f);
if (nwritten != sizeof(u16)) FAIL(errno);
if (reg->far[FAR_MAJ_O] > 0xFFFF
|| reg->far[FAR_MIN_O] > 0xFFF) FAIL(EINVAL);
u16 = __cpu_to_be16(reg->far[FAR_MAJ_O]);
nwritten = fwrite(&u16, /*size*/ 1, sizeof(u16), f);
if (nwritten != sizeof(u16)) FAIL(errno);
u16 = __cpu_to_be16(reg->far[FAR_MIN_O]);
nwritten = fwrite(&u16, /*size*/ 1, sizeof(u16), f);
if (nwritten != sizeof(u16)) FAIL(errno);
return 0;
}
if (reg->reg == CRC || reg->reg == IDCODE || reg->reg == EXP_SIGN) {
uint32_t u32;
u16 = PACKET_TYPE_1 << PACKET_HDR_TYPE_S;
u16 |= PACKET_HDR_OPCODE_WRITE << PACKET_HDR_OPCODE_S;
u16 |= reg->reg << PACKET_HDR_REG_S;
u16 |= 2; // two 16-bit words
u16 = __cpu_to_be16(u16);
nwritten = fwrite(&u16, /*size*/ 1, sizeof(u16), f);
if (nwritten != sizeof(u16)) FAIL(errno);
u32 = __cpu_to_be32(reg->int_v);
nwritten = fwrite(&u32, /*size*/ 1, sizeof(u32), f);
if (nwritten != sizeof(u32)) FAIL(errno);
return 0;
}
static const int t1_oneword_regs[] =
{ CMD, COR1, COR2, CTL, FLR, MASK, PWRDN_REG, HC_OPT_REG,
PU_GWE, PU_GTS, CWDT, MODE_REG, CCLK_FREQ, EYE_MASK,
GENERAL1, GENERAL2, GENERAL3, GENERAL4, GENERAL5,
SEU_OPT };
for (i = 0; i < sizeof(t1_oneword_regs)/sizeof(t1_oneword_regs[0]); i++) {
if (reg->reg == t1_oneword_regs[i])
break;
}
if (i >= sizeof(t1_oneword_regs)/sizeof(t1_oneword_regs[0]))
FAIL(EINVAL);
u16 = PACKET_TYPE_1 << PACKET_HDR_TYPE_S;
u16 |= PACKET_HDR_OPCODE_WRITE << PACKET_HDR_OPCODE_S;
u16 |= reg->reg << PACKET_HDR_REG_S;
u16 |= 1; // one word
u16 = __cpu_to_be16(u16);
nwritten = fwrite(&u16, /*size*/ 1, sizeof(u16), f);
if (nwritten != sizeof(u16)) FAIL(errno);
if (reg->int_v > 0xFFFF) FAIL(EINVAL);
u16 = __cpu_to_be16(reg->int_v);
nwritten = fwrite(&u16, /*size*/ 1, sizeof(u16), f);
if (nwritten != sizeof(u16)) FAIL(errno);
return 0;
fail:
return rc;
}
static int write_bits(FILE* f, struct fpga_model* model)
{
struct fpga_bits bits;
uint16_t u16;
uint32_t u32;
int nwritten, i, j, rc;
char padding_frame[FRAME_SIZE];
RC_CHECK(model);
bits.len = IOB_DATA_START + IOB_DATA_LEN;
bits.d = calloc(bits.len, /*elsize*/ 1);
if (!bits.d) FAIL(ENOMEM);
rc = write_model(&bits, model);
if (rc) FAIL(rc);
u16 = PACKET_TYPE_2 << PACKET_HDR_TYPE_S;
u16 |= PACKET_HDR_OPCODE_WRITE << PACKET_HDR_OPCODE_S;
u16 |= FDRI << PACKET_HDR_REG_S;
u16 |= 0; // zero 16-bit words
u16 = __cpu_to_be16(u16);
nwritten = fwrite(&u16, /*size*/ 1, sizeof(u16), f);
if (nwritten != sizeof(u16)) FAIL(errno);
u32 = (FRAMES_DATA_LEN + NUM_ROWS*PADDING_FRAMES_PER_ROW*FRAME_SIZE
+ BRAM_DATA_LEN + IOB_DATA_LEN)/2;
u32++; // there is one extra 16-bit 0x0000 padding at the end
u32 = __cpu_to_be32(u32);
nwritten = fwrite(&u32, /*size*/ 1, sizeof(u32), f);
if (nwritten != sizeof(u32)) FAIL(errno);
// initialize padding frame to 0xFF
for (i = 0; i < FRAME_SIZE; i++)
padding_frame[i] = 0xFF;
// write rows with padding frames
for (i = 0; i < NUM_ROWS; i++) {
nwritten = fwrite(&bits.d[i*FRAMES_PER_ROW*FRAME_SIZE],
/*size*/ 1, FRAMES_PER_ROW*FRAME_SIZE, f);
if (nwritten != FRAMES_PER_ROW*FRAME_SIZE) FAIL(errno);
for (j = 0; j < PADDING_FRAMES_PER_ROW; j++) {
nwritten = fwrite(padding_frame,
/*size*/ 1, FRAME_SIZE, f);
if (nwritten != FRAME_SIZE) FAIL(errno);
}
}
// write bram data
nwritten = fwrite(&bits.d[BRAM_DATA_START],
/*size*/ 1, BRAM_DATA_LEN, f);
if (nwritten != BRAM_DATA_LEN) FAIL(errno);
// write IOB data
nwritten = fwrite(&bits.d[IOB_DATA_START],
/*size*/ 1, IOB_DATA_LEN, f);
if (nwritten != IOB_DATA_LEN) FAIL(errno);
// write extra 0x0000 padding at end of FDRI block
u16 = 0;
nwritten = fwrite(&u16, /*size*/ 1, sizeof(u16), f);
if (nwritten != sizeof(u16)) FAIL(errno);
// todo: support real auto-crc calculation
u32 = DEFAULT_AUTO_CRC;
u32 = __cpu_to_be32(u32);
nwritten = fwrite(&u32, /*size*/ 1, sizeof(u32), f);
if (nwritten != sizeof(u32)) FAIL(errno);
free(bits.d);
return 0;
fail:
free(bits.d);
return rc;
}
int write_bitfile(FILE* f, struct fpga_model* model)
{
uint32_t u32;
int len_to_eof_pos, eof_pos, nwritten, i, rc;
RC_CHECK(model);
rc = write_header(f, "fpgatools.fp;UserID=0xFFFFFFFF",
"6slx9tqg144", "2010/05/26", "08:00:00");
if (rc) FAIL(rc);
if (fputc('e', f) == EOF) FAIL(errno);
if ((len_to_eof_pos = ftell(f)) == -1)
FAIL(errno);
u32 = 0;
nwritten = fwrite(&u32, /*size*/ 1, sizeof(u32), f);
if (nwritten != sizeof(u32)) FAIL(errno);
nwritten = fwrite(s_0xFF_words, /*size*/ 1, sizeof(s_0xFF_words), f);
if (nwritten != sizeof(s_0xFF_words)) FAIL(errno);
u32 = __cpu_to_be32(SYNC_WORD);
nwritten = fwrite(&u32, /*size*/ 1, sizeof(u32), f);
if (nwritten != sizeof(u32)) FAIL(errno);
for (i = 0; i < sizeof(s_defregs_before_bits)/sizeof(s_defregs_before_bits[0]); i++) {
rc = write_reg_action(f, &s_defregs_before_bits[i]);
if (rc) FAIL(rc);
}
rc = write_bits(f, model);
if (rc) FAIL(rc);
for (i = 0; i < sizeof(s_defregs_after_bits)/sizeof(s_defregs_after_bits[0]); i++) {
rc = write_reg_action(f, &s_defregs_after_bits[i]);
if (rc) FAIL(rc);
}
// write len to eof at offset len_to_eof_pos
if ((eof_pos = ftell(f)) == -1)
FAIL(errno);
if (fseek(f, len_to_eof_pos, SEEK_SET) == -1)
FAIL(errno);
u32 = __cpu_to_be32(eof_pos - len_to_eof_pos - sizeof(u32));
nwritten = fwrite(&u32, /*size*/ 1, sizeof(u32), f);
if (nwritten != sizeof(u32)) FAIL(errno);
if (fseek(f, eof_pos, SEEK_SET) == -1)
FAIL(errno);
return 0;
fail:
return rc;
}
fpgatools-201212/libs/control.c 0000664 0000000 0000000 00000246250 12065743015 0016372 0 ustar 00root root 0000000 0000000 //
// Author: Wolfgang Spraul
//
// This is free and unencumbered software released into the public domain.
// For details see the UNLICENSE file at the root of the source tree.
//
#include "model.h"
#include "control.h"
#undef DBG_ENUM_SWITCH
#undef DBG_SWITCH_CONNS
#undef DBG_SWITCH_TO_YX
#undef DBG_SWITCH_TO_REL
#undef DBG_SWITCH_2SETS
struct iob_site
{
int xy;
const char* name[4]; // left and right only use 2, top and bottom 4
};
static const struct iob_site xc6slx9_iob_top[] =
{
{ 5, {"P144", "P143", "P142", "P141"}},
{ 7, {"P140", "P139", "P138", "P137"}},
{12, {"UNB9", "UNB10", "UNB11", "UNB12"}},
{14, {"UNB13", "UNB14", "UNB15", "UNB16"}},
{19, {"UNB17", "UNB18", "UNB19", "UNB20"}},
{21, {"P134", "P133", "P132", "P131"}},
{25, {"P127", "P126", "P124", "P123"}},
{29, {"UNB29", "UNB30", "UNB31", "UNB32"}},
{31, {"UNB33", "UNB34", "P121", "P120"}},
{36, {"P119", "P118", "P117", "P116"}},
{38, {"P115", "P114", "P112", "P111"}},
};
static const struct iob_site xc6slx9_iob_bottom[] =
{
{ 5, {"P39", "P38", "P40", "P41"}},
{ 7, {"UNB139", "UNB140", "P43", "P44"}},
{12, {"P46", "P45", "P47", "P48"}},
{14, {"UNB131", "UNB132", "UNB130", "UNB129"}},
{19, {"UNB127", "UNB128", "UNB126", "UNB125"}},
{21, {"UNB123", "UNB124", "P50", "P51"}},
{25, {"P56", "P55", "UNB118", "UNB117"}},
{29, {"UNB115", "UNB116", "UNB114", "UNB113"}},
{31, {"P58", "P57", "P59", "P60"}},
{36, {"P62", "P61", "P64", "P65"}},
{38, {"P67", "P66", "P69", "P70"}},
};
static const struct iob_site xc6slx9_iob_left[] =
{
{ 3, {"P1", "P2"}},
{ 5, {"UNB198", "UNB197"}},
{ 7, {"UNB196", "UNB195"}},
{ 9, {"UNB194", "UNB193"}},
{ 11, {"P5", "P6"}},
{ 12, {"P7", "P8"}},
{ 13, {"P9", "P10"}},
{ 14, {"P11", "P12"}},
{ 28, {"UNB184", "UNB183"}},
{ 29, {"UNB182", "UNB181"}},
{ 30, {"UNB180", "UNB179"}},
{ 31, {"UNB178", "UNB177"}},
{ 32, {"P14", "P15"}},
{ 33, {"P16", "P17"}},
{ 37, {"P21", "P22"}},
{ 38, {"P23", "P24"}},
{ 39, {"UNB168", "UNB167"}},
{ 42, {"UNB166", "UNB165"}},
{ 46, {"UNB164", "UNB163"}},
{ 49, {"P26", "P27"}},
{ 52, {"P29", "P30"}},
{ 55, {"UNB158", "UNB157"}},
{ 58, {"UNB156", "UNB155"}},
{ 61, {"UNB154", "UNB153"}},
{ 65, {"UNB152", "UNB151"}},
{ 66, {"UNB150", "UNB149"}},
{ 67, {"P32", "P33"}},
{ 68, {"P34", "P35"}},
};
static const struct iob_site xc6slx9_iob_right[] =
{
{ 4, {"P105", "P104"}},
{ 5, {"UNB47", "UNB48"}},
{ 7, {"UNB49", "UNB50"}},
{ 9, {"UNB51", "UNB52"}},
{ 11, {"P102", "P101"}},
{ 12, {"P100", "P99"}},
{ 13, {"P98", "P97"}},
{ 14, {"UNB59", "UNB60"}},
{ 28, {"UNB61", "UNB62"}},
{ 29, {"UNB63", "UNB64"}},
{ 30, {"UNB65", "UNB66"}},
{ 31, {"UNB67", "UNB68"}},
{ 32, {"P95", "P94"}},
{ 33, {"P93", "P92"}},
{ 37, {"P88", "P87"}},
{ 38, {"P85", "P84"}},
{ 39, {"UNB77", "UNB78"}},
{ 42, {"P83", "P82"}},
{ 46, {"P81", "P80"}},
{ 49, {"P79", "P78"}},
{ 52, {"UNB85", "UNB86"}},
{ 55, {"UNB87", "UNB88"}},
{ 58, {"UNB89", "UNB90"}},
{ 61, {"UNB91", "UNB92"}},
{ 65, {"UNB93", "UNB94"}},
{ 66, {"UNB95", "UNB96"}},
{ 67, {"UNB97", "UNB98"}},
{ 68, {"P75", "P74"}},
};
const char* fpga_enum_iob(struct fpga_model* model, int enum_idx,
int* y, int* x, dev_type_idx_t* type_idx)
{
if (enum_idx < 0) { HERE(); return 0; }
if (enum_idx < sizeof(xc6slx9_iob_top)/sizeof(xc6slx9_iob_top[0])*4) {
*y = TOP_OUTER_ROW;
*x = xc6slx9_iob_top[enum_idx/4].xy;
*type_idx = enum_idx%4;
return xc6slx9_iob_top[enum_idx/4].name[enum_idx%4];
}
enum_idx -= sizeof(xc6slx9_iob_top)/sizeof(xc6slx9_iob_top[0])*4;
if (enum_idx < sizeof(xc6slx9_iob_bottom)/sizeof(xc6slx9_iob_bottom[0])*4) {
*y = model->y_height - BOT_OUTER_ROW;
*x = xc6slx9_iob_bottom[enum_idx/4].xy;
*type_idx = enum_idx%4;
return xc6slx9_iob_bottom[enum_idx/4].name[enum_idx%4];
}
enum_idx -= sizeof(xc6slx9_iob_bottom)/sizeof(xc6slx9_iob_bottom[0])*4;
if (enum_idx < sizeof(xc6slx9_iob_left)/sizeof(xc6slx9_iob_left[0])*2) {
*y = xc6slx9_iob_left[enum_idx/2].xy;
*x = LEFT_OUTER_COL;
*type_idx = enum_idx%2;
return xc6slx9_iob_left[enum_idx/2].name[enum_idx%2];
}
enum_idx -= sizeof(xc6slx9_iob_left)/sizeof(xc6slx9_iob_left[0])*2;
if (enum_idx < sizeof(xc6slx9_iob_right)/sizeof(xc6slx9_iob_right[0])*2) {
*y = xc6slx9_iob_right[enum_idx/2].xy;
*x = model->x_width-RIGHT_OUTER_O;
*type_idx = enum_idx%2;
return xc6slx9_iob_right[enum_idx/2].name[enum_idx%2];
}
return 0;
}
int fpga_find_iob(struct fpga_model* model, const char* sitename,
int* y, int* x, dev_type_idx_t* idx)
{
const char* name;
int i;
RC_CHECK(model);
for (i = 0; (name = fpga_enum_iob(model, i, y, x, idx)); i++) {
if (!strcmp(name, sitename))
return 0;
}
return -1;
}
const char* fpga_iob_sitename(struct fpga_model* model, int y, int x,
dev_type_idx_t 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_top[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;
}
static void enum_x(struct fpga_model *model, enum fpgadev_type type,
int enum_i, int *y, int x, int *type_idx)
{
int type_count, i, _y;
struct fpga_tile* tile;
type_count = 0;
for (_y = 0; _y < model->y_height; _y++) {
tile = YX_TILE(model, _y, x);
for (i = 0; i < tile->num_devs; i++) {
if (tile->devs[i].type != type)
continue;
if (type_count == enum_i) {
*y = _y;
*type_idx = type_count;
return;
}
type_count++;
}
}
*y = -1;
}
int fdev_enum(struct fpga_model* model, enum fpgadev_type type, int enum_i,
int *y, int *x, int *type_idx)
{
struct fpga_tile* tile;
int i, j, type_count;
RC_CHECK(model);
switch (type) {
case DEV_BUFGMUX:
tile = YX_TILE(model, model->center_y, model->center_x);
if (!tile) RC_FAIL(model, EINVAL);
type_count = 0;
for (i = 0; i < tile->num_devs; i++) {
if (tile->devs[i].type != DEV_BUFGMUX)
continue;
if (type_count == enum_i) {
*y = model->center_y;
*x = model->center_x;
*type_idx = type_count;
RC_RETURN(model);
}
type_count++;
}
*y = -1;
RC_RETURN(model);
case DEV_BUFIO: {
int yx_pairs[] = {
TOP_OUTER_ROW, model->center_x-CENTER_CMTPLL_O,
model->center_y, LEFT_OUTER_COL,
model->center_y, model->x_width-RIGHT_OUTER_O,
model->y_height-BOT_OUTER_ROW, model->center_x-CENTER_CMTPLL_O };
type_count = 0;
for (i = 0; i < sizeof(yx_pairs)/sizeof(*yx_pairs)/2; i++) {
tile = YX_TILE(model, yx_pairs[i*2], yx_pairs[i*2+1]);
for (j = 0; j < tile->num_devs; j++) {
if (tile->devs[j].type != DEV_BUFIO)
continue;
if (type_count == enum_i) {
*y = yx_pairs[i*2];
*x = yx_pairs[i*2+1];
*type_idx = type_count;
RC_RETURN(model);
}
type_count++;
}
}
*y = -1;
RC_RETURN(model);
}
case DEV_PLL:
case DEV_DCM:
enum_x(model, type, enum_i, y, model->center_x
- CENTER_CMTPLL_O, type_idx);
RC_RETURN(model);
case DEV_BSCAN:
enum_x(model, type, enum_i, y, model->x_width
- RIGHT_IO_DEVS_O, type_idx);
RC_RETURN(model);
default: break;
}
HERE();
*y = -1;
RC_RETURN(model);
}
static const char* dev_str[] = FPGA_DEV_STR;
const char* fdev_type2str(enum fpgadev_type type)
{
if (type < 0 || type >= sizeof(dev_str)/sizeof(*dev_str))
{ HERE(); return 0; }
return dev_str[type];
}
enum fpgadev_type fdev_str2type(const char* str, int len)
{
int i;
for (i = 0; i < sizeof(dev_str)/sizeof(*dev_str); i++) {
if (dev_str[i]
&& strlen(dev_str[i]) == len
&& !str_cmp(dev_str[i], len, str, len))
return i;
}
return DEV_NONE;
}
struct fpga_device* fdev_p(struct fpga_model* model,
int y, int x, enum fpgadev_type type, dev_type_idx_t type_idx)
{
dev_idx_t dev_idx = fpga_dev_idx(model, y, x, type, type_idx);
if (dev_idx == NO_DEV) {
fprintf(stderr, "#E %s:%i fdev_p() y%i x%i type %i/%i not"
" found\n", __FILE__, __LINE__, y, x, type, type_idx);
return 0;
}
return FPGA_DEV(model, y, x, dev_idx);
}
dev_idx_t fpga_dev_idx(struct fpga_model* model,
int y, int x, enum fpgadev_type type, dev_type_idx_t type_idx)
{
struct fpga_tile* tile;
dev_type_idx_t type_count;
dev_idx_t i;
// function must work even if model->rc is set
tile = YX_TILE(model, y, x);
type_count = 0;
for (i = 0; i < tile->num_devs; i++) {
if (tile->devs[i].type == type) {
if (type_count == type_idx)
return i;
type_count++;
}
}
return NO_DEV;
}
dev_type_idx_t fdev_typeidx(struct fpga_model* model, int y, int x,
dev_idx_t dev_idx)
{
struct fpga_tile* tile;
dev_type_idx_t type_count, i;
// function must work even if model->rc is set
tile = YX_TILE(model, y, x);
type_count = 0;
for (i = 0; i < dev_idx; i++) {
if (tile->devs[i].type == tile->devs[dev_idx].type)
type_count++;
}
return type_count;
}
static const char* iob_pinw_str[] = IOB_PINW_STR;
static const char* logic_pinw_str[] = LOGIC_PINW_STR;
pinw_idx_t fdev_pinw_str2idx(int devtype, const char* str, int len)
{
int i;
if (devtype == DEV_IOB) {
for (i = 0; i < sizeof(iob_pinw_str)/sizeof(*iob_pinw_str); i++) {
if (strlen(iob_pinw_str[i]) == len
&& !str_cmp(iob_pinw_str[i], len, str, len))
return i;
}
HERE();
return PINW_NO_IDX;
}
if (devtype == DEV_LOGIC) {
for (i = 0; i < sizeof(logic_pinw_str)/sizeof(*logic_pinw_str); i++) {
if (strlen(logic_pinw_str[i]) == len
&& !str_cmp(logic_pinw_str[i], len, str, len))
return i;
}
HERE();
return PINW_NO_IDX;
}
HERE();
return PINW_NO_IDX;
}
const char* fdev_pinw_idx2str(int devtype, pinw_idx_t idx)
{
if (devtype == DEV_IOB) {
if (idx < 0 || idx >= sizeof(iob_pinw_str)/sizeof(*iob_pinw_str)) {
HERE();
return 0;
}
return iob_pinw_str[idx];
}
if (devtype == DEV_LOGIC) {
if (idx < 0 || idx >= sizeof(logic_pinw_str)/sizeof(*logic_pinw_str)) {
HERE();
return 0;
}
return logic_pinw_str[idx];
}
HERE();
return 0;
}
const char* fdev_logic_pinstr(pinw_idx_t idx, int ld1_type)
{
enum { NUM_BUFS = 16, BUF_SIZE = 16 };
static char buf[NUM_BUFS][BUF_SIZE];
static int last_buf = 0;
last_buf = (last_buf+1)%NUM_BUFS;
if (ld1_type == LOGIC_M)
snprintf(buf[last_buf], sizeof(*buf), "%s%s",
(idx & LD1) ? "M_" : "X_",
logic_pinw_str[idx&(~LD1)]);
else if (ld1_type == LOGIC_L)
snprintf(buf[last_buf], sizeof(*buf), "%s%s",
(idx & LD1) ? "L_" : "XX_",
logic_pinw_str[idx&(~LD1)]);
else {
HERE();
buf[last_buf][0] = 0;
}
return buf[last_buf];
}
str16_t fdev_logic_pinstr_i(struct fpga_model* model, pinw_idx_t idx, int ld1_type)
{
int str_i;
RC_CHECK(model);
str_i = strarray_find(&model->str, fdev_logic_pinstr(idx, ld1_type));
if (OUT_OF_U16(str_i))
{ HERE(); return STRIDX_NO_ENTRY; }
return str_i;
}
static int reset_required_pins(struct fpga_device* dev)
{
int rc;
if (!dev->pinw_req_for_cfg) {
dev->pinw_req_for_cfg = malloc(dev->num_pinw_total
* sizeof(*dev->pinw_req_for_cfg));
if (!dev->pinw_req_for_cfg) FAIL(ENOMEM);
}
dev->pinw_req_total = 0;
dev->pinw_req_in = 0;
return 0;
fail:
return rc;
}
void fdev_print_required_pins(struct fpga_model* model, int y, int x,
int type, int type_idx)
{
struct fpga_device* dev;
int i;
dev = fdev_p(model, y, x, type, type_idx);
if (!dev) { HERE(); return; }
// We don't want to reset or write the required pins in this
// function because it is mainly used for debugging purposes
// and the caller should not suddenly be working with old
// required pins when the print() function is not called.
printf("y%i x%i %s %i inpin", y, x, fdev_type2str(type), type_idx);
if (!dev->pinw_req_in)
printf(" -\n");
else {
for (i = 0; i < dev->pinw_req_in; i++)
printf(" %s", fdev_pinw_idx2str(type, dev->pinw_req_for_cfg[i]));
printf("\n");
}
printf("y%i x%i %s %i outpin", y, x, fdev_type2str(type), type_idx);
if (dev->pinw_req_total <= dev->pinw_req_in)
printf(" -\n");
else {
for (i = dev->pinw_req_in; i < dev->pinw_req_total; i++)
printf(" %s", fdev_pinw_idx2str(type, dev->pinw_req_for_cfg[i]));
printf("\n");
}
}
static void add_req_inpin(struct fpga_device* dev, pinw_idx_t pinw_i)
{
int i;
// check for duplicate
for (i = 0; i < dev->pinw_req_in; i++) {
if (dev->pinw_req_for_cfg[i] == pinw_i)
return;
}
if (dev->pinw_req_total > dev->pinw_req_in) {
memmove(&dev->pinw_req_for_cfg[dev->pinw_req_in+1],
&dev->pinw_req_for_cfg[dev->pinw_req_in],
(dev->pinw_req_total-dev->pinw_req_in)
*sizeof(*dev->pinw_req_for_cfg));
}
dev->pinw_req_for_cfg[dev->pinw_req_in] = pinw_i;
dev->pinw_req_in++;
dev->pinw_req_total++;
}
static void add_req_outpin(struct fpga_device* dev, pinw_idx_t pinw_i)
{
int i;
// check for duplicate
for (i = dev->pinw_req_in; i < dev->pinw_req_total; i++) {
if (dev->pinw_req_for_cfg[i] == pinw_i)
return;
}
dev->pinw_req_for_cfg[dev->pinw_req_total] = pinw_i;
dev->pinw_req_total++;
}
//
// logic device
//
int fdev_logic_setconf(struct fpga_model* model, int y, int x,
int type_idx, const struct fpgadev_logic* logic_cfg)
{
struct fpga_device* dev;
int lut, rc;
RC_CHECK(model);
dev = fdev_p(model, y, x, DEV_LOGIC, type_idx);
if (!dev) FAIL(EINVAL);
rc = reset_required_pins(dev);
if (rc) FAIL(rc);
for (lut = LUT_A; lut <= LUT_D; lut++) {
if (logic_cfg->a2d[lut].out_used)
dev->u.logic.a2d[lut].out_used = 1;
if (logic_cfg->a2d[lut].lut6) {
rc = fdev_logic_a2d_lut(model, y, x, type_idx,
lut, 6, logic_cfg->a2d[lut].lut6, ZTERM);
if (rc) FAIL(rc);
}
if (logic_cfg->a2d[lut].lut5) {
rc = fdev_logic_a2d_lut(model, y, x, type_idx,
lut, 5, logic_cfg->a2d[lut].lut5, ZTERM);
if (rc) FAIL(rc);
}
if (logic_cfg->a2d[lut].ff) {
if (!logic_cfg->a2d[lut].ff_mux
|| !logic_cfg->a2d[lut].ff_srinit)
FAIL(EINVAL);
dev->u.logic.a2d[lut].ff = logic_cfg->a2d[lut].ff;
dev->u.logic.a2d[lut].ff_mux = logic_cfg->a2d[lut].ff_mux;
dev->u.logic.a2d[lut].ff_srinit = logic_cfg->a2d[lut].ff_srinit;
}
if (logic_cfg->a2d[lut].out_mux)
dev->u.logic.a2d[lut].out_mux = logic_cfg->a2d[lut].out_mux;
if (logic_cfg->a2d[lut].ff5_srinit)
dev->u.logic.a2d[lut].ff5_srinit = logic_cfg->a2d[lut].ff5_srinit;
if (logic_cfg->a2d[lut].cy0)
dev->u.logic.a2d[lut].cy0 = logic_cfg->a2d[lut].cy0;
}
if (logic_cfg->clk_inv)
dev->u.logic.clk_inv = logic_cfg->clk_inv;
if (logic_cfg->sync_attr)
dev->u.logic.sync_attr = logic_cfg->sync_attr;
if (logic_cfg->ce_used)
dev->u.logic.ce_used = logic_cfg->ce_used;
if (logic_cfg->sr_used)
dev->u.logic.sr_used = logic_cfg->sr_used;
if (logic_cfg->we_mux)
dev->u.logic.we_mux = logic_cfg->we_mux;
if (logic_cfg->cout_used)
dev->u.logic.cout_used = logic_cfg->cout_used;
if (logic_cfg->precyinit)
dev->u.logic.precyinit = logic_cfg->precyinit;
dev->instantiated = 1;
rc = fdev_set_required_pins(model, y, x, DEV_LOGIC, type_idx);
if (rc) FAIL(rc);
return 0;
fail:
return rc;
}
int fdev_logic_a2d_out_used(struct fpga_model* model, int y, int x,
int type_idx, int lut_a2d, int used)
{
struct fpga_device* dev;
int rc;
RC_CHECK(model);
dev = fdev_p(model, y, x, DEV_LOGIC, type_idx);
if (!dev) FAIL(EINVAL);
rc = reset_required_pins(dev);
if (rc) FAIL(rc);
dev->u.logic.a2d[lut_a2d].out_used = (used != 0);
dev->instantiated = 1;
return 0;
fail:
return rc;
}
int fdev_logic_a2d_lut(struct fpga_model* model, int y, int x, int type_idx,
int lut_a2d, int lut_5or6, const char* lut_str, int lut_len)
{
struct fpga_device* dev;
char** lut_ptr;
int rc;
RC_CHECK(model);
dev = fdev_p(model, y, x, DEV_LOGIC, type_idx);
if (!dev) FAIL(EINVAL);
rc = reset_required_pins(dev);
if (rc) FAIL(rc);
lut_ptr = (lut_5or6 == 5)
? &dev->u.logic.a2d[lut_a2d].lut5
: &dev->u.logic.a2d[lut_a2d].lut6;
if (*lut_ptr == 0) {
*lut_ptr = malloc(MAX_LUT_LEN);
if (!(*lut_ptr)) FAIL(ENOMEM);
}
if (lut_len == ZTERM) lut_len = strlen(lut_str);
memcpy(*lut_ptr, lut_str, lut_len);
(*lut_ptr)[lut_len] = 0;
dev->instantiated = 1;
return 0;
fail:
return rc;
}
int fdev_logic_a2d_ff(struct fpga_model* model, int y, int x, int type_idx,
int lut_a2d, int ff_mux, int srinit)
{
struct fpga_device* dev;
int rc;
RC_CHECK(model);
dev = fdev_p(model, y, x, DEV_LOGIC, type_idx);
if (!dev) FAIL(EINVAL);
rc = reset_required_pins(dev);
if (rc) FAIL(rc);
dev->u.logic.a2d[lut_a2d].ff = FF_FF;
dev->u.logic.a2d[lut_a2d].ff_mux = ff_mux;
dev->u.logic.a2d[lut_a2d].ff_srinit = srinit;
// A flip-flop also needs a clock (and sync attribute) to operate.
dev->instantiated = 1;
return 0;
fail:
return rc;
}
int fdev_logic_a2d_ff5_srinit(struct fpga_model* model, int y, int x,
int type_idx, int lut_a2d, int srinit)
{
struct fpga_device* dev;
int rc;
RC_CHECK(model);
dev = fdev_p(model, y, x, DEV_LOGIC, type_idx);
if (!dev) FAIL(EINVAL);
rc = reset_required_pins(dev);
if (rc) FAIL(rc);
dev->u.logic.a2d[lut_a2d].ff5_srinit = srinit;
dev->instantiated = 1;
return 0;
fail:
return rc;
}
int fdev_logic_a2d_out_mux(struct fpga_model* model, int y, int x,
int type_idx, int lut_a2d, int out_mux)
{
struct fpga_device* dev;
int rc;
RC_CHECK(model);
dev = fdev_p(model, y, x, DEV_LOGIC, type_idx);
if (!dev) FAIL(EINVAL);
rc = reset_required_pins(dev);
if (rc) FAIL(rc);
dev->u.logic.a2d[lut_a2d].out_mux = out_mux;
dev->instantiated = 1;
return 0;
fail:
return rc;
}
int fdev_logic_a2d_cy0(struct fpga_model* model, int y, int x,
int type_idx, int lut_a2d, int cy0)
{
struct fpga_device* dev;
int rc;
RC_CHECK(model);
dev = fdev_p(model, y, x, DEV_LOGIC, type_idx);
if (!dev) FAIL(EINVAL);
rc = reset_required_pins(dev);
if (rc) FAIL(rc);
dev->u.logic.a2d[lut_a2d].cy0 = cy0;
dev->instantiated = 1;
return 0;
fail:
return rc;
}
int fdev_logic_clk(struct fpga_model* model, int y, int x, int type_idx,
int clk)
{
struct fpga_device* dev;
int rc;
RC_CHECK(model);
dev = fdev_p(model, y, x, DEV_LOGIC, type_idx);
if (!dev) FAIL(EINVAL);
rc = reset_required_pins(dev);
if (rc) FAIL(rc);
dev->u.logic.clk_inv = clk;
dev->instantiated = 1;
return 0;
fail:
return rc;
}
int fdev_logic_sync(struct fpga_model* model, int y, int x, int type_idx,
int sync_attr)
{
struct fpga_device* dev;
int rc;
RC_CHECK(model);
dev = fdev_p(model, y, x, DEV_LOGIC, type_idx);
if (!dev) FAIL(EINVAL);
rc = reset_required_pins(dev);
if (rc) FAIL(rc);
dev->u.logic.sync_attr = sync_attr;
dev->instantiated = 1;
return 0;
fail:
return rc;
}
int fdev_logic_ce_used(struct fpga_model* model, int y, int x, int type_idx)
{
struct fpga_device* dev;
int rc;
RC_CHECK(model);
dev = fdev_p(model, y, x, DEV_LOGIC, type_idx);
if (!dev) FAIL(EINVAL);
rc = reset_required_pins(dev);
if (rc) FAIL(rc);
dev->u.logic.ce_used = 1;
dev->instantiated = 1;
return 0;
fail:
return rc;
}
int fdev_logic_sr_used(struct fpga_model* model, int y, int x, int type_idx)
{
struct fpga_device* dev;
int rc;
RC_CHECK(model);
dev = fdev_p(model, y, x, DEV_LOGIC, type_idx);
if (!dev) FAIL(EINVAL);
rc = reset_required_pins(dev);
if (rc) FAIL(rc);
dev->u.logic.sr_used = 1;
dev->instantiated = 1;
return 0;
fail:
return rc;
}
int fdev_logic_we_mux(struct fpga_model* model, int y, int x,
int type_idx, int we_mux)
{
struct fpga_device* dev;
int rc;
RC_CHECK(model);
dev = fdev_p(model, y, x, DEV_LOGIC, type_idx);
if (!dev) FAIL(EINVAL);
rc = reset_required_pins(dev);
if (rc) FAIL(rc);
dev->u.logic.we_mux = we_mux;
dev->instantiated = 1;
return 0;
fail:
return rc;
}
int fdev_logic_cout_used(struct fpga_model* model, int y, int x,
int type_idx, int used)
{
struct fpga_device* dev;
int rc;
RC_CHECK(model);
dev = fdev_p(model, y, x, DEV_LOGIC, type_idx);
if (!dev) FAIL(EINVAL);
rc = reset_required_pins(dev);
if (rc) FAIL(rc);
dev->u.logic.cout_used = (used != 0);
dev->instantiated = 1;
return 0;
fail:
return rc;
}
int fdev_logic_precyinit(struct fpga_model* model, int y, int x,
int type_idx, int precyinit)
{
struct fpga_device* dev;
int rc;
RC_CHECK(model);
dev = fdev_p(model, y, x, DEV_LOGIC, type_idx);
if (!dev) FAIL(EINVAL);
rc = reset_required_pins(dev);
if (rc) FAIL(rc);
dev->u.logic.precyinit = precyinit;
dev->instantiated = 1;
return 0;
fail:
return rc;
}
//
// iob device
//
int fdev_iob_input(struct fpga_model* model, int y, int x, int type_idx,
const char* io_std)
{
struct fpga_device* dev;
int rc;
RC_CHECK(model);
dev = fdev_p(model, y, x, DEV_IOB, type_idx);
if (!dev) FAIL(EINVAL);
rc = reset_required_pins(dev);
if (rc) FAIL(rc);
strcpy(dev->u.iob.istandard, io_std);
dev->u.iob.bypass_mux = BYPASS_MUX_I;
dev->u.iob.I_mux = IMUX_I;
dev->instantiated = 1;
return 0;
fail:
return rc;
}
int fdev_iob_output(struct fpga_model* model, int y, int x, int type_idx,
const char* io_std)
{
struct fpga_device* dev;
int rc;
RC_CHECK(model);
dev = fdev_p(model, y, x, DEV_IOB, type_idx);
if (!dev) FAIL(EINVAL);
rc = reset_required_pins(dev);
if (rc) FAIL(rc);
strcpy(dev->u.iob.ostandard, io_std);
dev->u.iob.O_used = 1;
dev->u.iob.suspend = SUSP_3STATE;
if (strcmp(io_std, IO_SSTL2_I)) {
// also see ug381 page 31
if (!strcmp(io_std, IO_LVCMOS33)
|| !strcmp(io_std, IO_LVCMOS25))
dev->u.iob.drive_strength = 12;
else if (!strcmp(io_std, IO_LVCMOS12)
|| !strcmp(io_std, IO_LVCMOS12_JEDEC))
dev->u.iob.drive_strength = 6;
else
dev->u.iob.drive_strength = 8;
dev->u.iob.slew = SLEW_SLOW;
}
dev->instantiated = 1;
return 0;
fail:
return rc;
}
int fdev_iob_IMUX(struct fpga_model* model, int y, int x,
int type_idx, int mux)
{
struct fpga_device* dev;
int rc;
RC_CHECK(model);
dev = fdev_p(model, y, x, DEV_IOB, type_idx);
if (!dev) FAIL(EINVAL);
rc = reset_required_pins(dev);
if (rc) FAIL(rc);
dev->u.iob.I_mux = mux;
dev->instantiated = 1;
return 0;
fail:
return rc;
}
int fdev_iob_slew(struct fpga_model* model, int y, int x,
int type_idx, int slew)
{
struct fpga_device* dev;
int rc;
RC_CHECK(model);
dev = fdev_p(model, y, x, DEV_IOB, type_idx);
if (!dev) FAIL(EINVAL);
rc = reset_required_pins(dev);
if (rc) FAIL(rc);
dev->u.iob.slew = slew;
dev->instantiated = 1;
return 0;
fail:
return rc;
}
int fdev_iob_drive(struct fpga_model* model, int y, int x,
int type_idx, int drive_strength)
{
struct fpga_device* dev;
int rc;
RC_CHECK(model);
dev = fdev_p(model, y, x, DEV_IOB, type_idx);
if (!dev) FAIL(EINVAL);
rc = reset_required_pins(dev);
if (rc) FAIL(rc);
dev->u.iob.drive_strength = drive_strength;
dev->instantiated = 1;
return 0;
fail:
return rc;
}
int fdev_bufgmux(struct fpga_model* model, int y, int x,
int type_idx, int clk, int disable_attr, int s_inv)
{
struct fpga_device* dev;
int rc;
RC_CHECK(model);
dev = fdev_p(model, y, x, DEV_BUFGMUX, type_idx);
if (!dev) FAIL(EINVAL);
rc = reset_required_pins(dev);
if (rc) FAIL(rc);
dev->u.bufgmux.clk = clk;
dev->u.bufgmux.disable_attr = disable_attr;
dev->u.bufgmux.s_inv = s_inv;
dev->instantiated = 1;
return 0;
fail:
return rc;
}
static void scan_lut_digits(const char* s, int* digits)
{
int i;
for (i = 0; i < 6; i++)
digits[i] = 0;
if (!s) return;
// Note special cases "0" and "1" for a lut that
// always results in 0 or 1.
for (i = 0; s[i]; i++) {
if (s[i] != 'A' && s[i] != 'a')
continue;
if (s[i+1] >= '1' && s[i+1] <= '6')
digits[s[++i]-'1']++;
}
}
int fdev_set_required_pins(struct fpga_model* model, int y, int x, int type,
int type_idx)
{
struct fpga_device* dev;
int digits[6];
int i, j, rc;
RC_CHECK(model);
dev = fdev_p(model, y, x, type, type_idx);
if (!dev) FAIL(EINVAL);
rc = reset_required_pins(dev);
if (rc) FAIL(rc);
if (type == DEV_LOGIC) {
if (dev->u.logic.clk_inv)
add_req_inpin(dev, LI_CLK);
if (dev->u.logic.ce_used)
add_req_inpin(dev, LI_CE);
if (dev->u.logic.sr_used)
add_req_inpin(dev, LI_SR);
if (dev->u.logic.cout_used)
add_req_outpin(dev, LO_COUT);
if (dev->u.logic.precyinit == PRECYINIT_AX)
add_req_inpin(dev, LI_AX);
if (dev->u.logic.a2d[LUT_A].out_mux == MUX_F7
|| dev->u.logic.a2d[LUT_A].ff_mux == MUX_F7)
add_req_inpin(dev, LI_AX);
if (dev->u.logic.a2d[LUT_C].out_mux == MUX_F7
|| dev->u.logic.a2d[LUT_C].ff_mux == MUX_F7)
add_req_inpin(dev, LI_CX);
if (dev->u.logic.a2d[LUT_B].out_mux == MUX_F8
|| dev->u.logic.a2d[LUT_B].ff_mux == MUX_F8) {
add_req_inpin(dev, LI_AX);
add_req_inpin(dev, LI_BX);
add_req_inpin(dev, LI_CX);
}
for (i = LUT_A; i <= LUT_D; i++) {
if (dev->u.logic.a2d[i].out_used) {
// LO_A..LO_D are in sequence
add_req_outpin(dev, LO_A+i);
}
if (dev->u.logic.a2d[i].out_mux) {
// LO_AMUX..LO_DMUX are in sequence
add_req_outpin(dev, LO_AMUX+i);
}
if (dev->u.logic.a2d[i].ff) {
// LO_AQ..LO_DQ are in sequence
add_req_outpin(dev, LO_AQ+i);
}
if (dev->u.logic.a2d[i].ff_mux == MUX_X
|| dev->u.logic.a2d[i].cy0 == CY0_X) {
// LI_AX..LI_DX are in sequence
add_req_inpin(dev, LI_AX+i);
}
if (dev->u.logic.a2d[i].lut6) {
scan_lut_digits(dev->u.logic.a2d[i].lut6, digits);
for (j = 0; j < 6; j++) {
if (!digits[j]) continue;
add_req_inpin(dev, LI_A1+i*6+j);
}
}
if (dev->u.logic.a2d[i].lut5) {
// A6 must be high/vcc if lut5 is used
add_req_inpin(dev, LI_A6+i*6);
scan_lut_digits(dev->u.logic.a2d[i].lut5, digits);
for (j = 0; j < 6; j++) {
if (!digits[j]) continue;
add_req_inpin(dev, LI_A1+i*6+j);
}
}
if ((dev->u.logic.a2d[i].ff_mux == MUX_XOR
|| dev->u.logic.a2d[i].out_mux == MUX_XOR)
&& !dev->u.logic.precyinit)
add_req_inpin(dev, LI_CIN);
}
return 0;
}
if (type == DEV_IOB) {
if (dev->u.iob.I_mux)
add_req_outpin(dev, IOB_OUT_I);
if (dev->u.iob.O_used)
add_req_inpin(dev, IOB_IN_O);
}
return 0;
fail:
return rc;
}
void fdev_delete(struct fpga_model* model, int y, int x, int type, int type_idx)
{
struct fpga_device* dev;
int i;
dev = fdev_p(model, y, x, type, type_idx);
if (!dev) { HERE(); return; }
if (!dev->instantiated) return;
free(dev->pinw_req_for_cfg);
dev->pinw_req_for_cfg = 0;
dev->pinw_req_total = 0;
dev->pinw_req_in = 0;
if (dev->type == DEV_LOGIC) {
for (i = LUT_A; i <= LUT_D; i++) {
free(dev->u.logic.a2d[i].lut6);
dev->u.logic.a2d[i].lut6 = 0;
free(dev->u.logic.a2d[i].lut5);
dev->u.logic.a2d[i].lut5 = 0;
}
}
dev->instantiated = 0;
memset(&dev->u, 0, sizeof(dev->u));
}
int fpga_connpt_find(struct fpga_model* model, int y, int x,
str16_t name_i, int* connpt_dests_o, int* num_dests)
{
struct fpga_tile* tile;
int i;
RC_CHECK(model);
tile = YX_TILE(model, y, x);
for (i = 0; i < tile->num_conn_point_names; i++) {
if (tile->conn_point_names[i*2+1] == name_i)
break;
}
if (i >= tile->num_conn_point_names)
{ HERE(); goto fail; }
if (num_dests) {
*num_dests = (i < tile->num_conn_point_names-1)
? tile->conn_point_names[(i+1)*2]
- tile->conn_point_names[i*2]
: tile->num_conn_point_dests
- tile->conn_point_names[i*2];
}
if (connpt_dests_o)
*connpt_dests_o = tile->conn_point_names[i*2];
return i;
fail:
return NO_CONN;
}
void fpga_conn_dest(struct fpga_model* model, int y, int x,
int connpt_dest_idx, int* dest_y, int* dest_x, str16_t* str_i)
{
struct fpga_tile* tile;
tile = YX_TILE(model, y, x);
if (connpt_dest_idx < 0
|| connpt_dest_idx >= tile->num_conn_point_dests) {
HERE();
return;
}
*dest_x = tile->conn_point_dests[connpt_dest_idx*3];
*dest_y = tile->conn_point_dests[connpt_dest_idx*3+1];
*str_i = tile->conn_point_dests[connpt_dest_idx*3+2];
}
int fpga_find_conn(struct fpga_model* model, int search_y, int search_x,
str16_t* pt, int target_y, int target_x, str16_t target_pt)
{
struct fpga_tile* tile;
int i, j, dests_end;
RC_CHECK(model);
tile = YX_TILE(model, search_y, search_x);
for (i = 0; i < tile->num_conn_point_names; i++) {
dests_end = (i < tile->num_conn_point_names-1)
? tile->conn_point_names[(i+1)*2]
: tile->num_conn_point_dests;
for (j = tile->conn_point_names[i*2]; j < dests_end; j++) {
if (tile->conn_point_dests[j*3] == target_x
&& tile->conn_point_dests[j*3+1] == target_y
&& tile->conn_point_dests[j*3+2] == target_pt) {
*pt = tile->conn_point_names[i*2+1];
return 0;
}
}
}
*pt = STRIDX_NO_ENTRY;
return 0;
}
swidx_t fpga_switch_first(struct fpga_model* model, int y, int x,
str16_t name_i, int from_to)
{
struct fpga_tile* tile;
int i, connpt_o;
RC_CHECK(model);
// Finds the first switch either from or to the name given.
if (name_i == STRIDX_NO_ENTRY) { HERE(); return NO_SWITCH; }
tile = YX_TILE(model, y, x);
for (i = 0; i < tile->num_switches; i++) {
connpt_o = SW_I(tile->switches[i], from_to);
if (tile->conn_point_names[connpt_o*2+1] == name_i)
break;
}
return (i >= tile->num_switches) ? NO_SWITCH : i;
}
static swidx_t fpga_switch_search(struct fpga_model* model, int y, int x,
swidx_t last, swidx_t search_beg, int from_to)
{
struct fpga_tile* tile;
int connpt_o, name_i, i;
RC_CHECK(model);
tile = YX_TILE(model, y, x);
if (last & FIRST_SW) {
connpt_o = fpga_connpt_find(model, y, x, last & ~FIRST_SW,
/*dests_o*/ 0, /*num_dests*/ 0);
if (connpt_o == NO_CONN) { HERE(); return NO_SWITCH; }
} else
connpt_o = SW_I(tile->switches[last], from_to);
name_i = tile->conn_point_names[connpt_o*2+1];
for (i = search_beg; i < tile->num_switches; i++) {
connpt_o = SW_I(tile->switches[i], from_to);
if (tile->conn_point_names[connpt_o*2+1] == name_i)
break;
}
return (i >= tile->num_switches) ? NO_SWITCH : i;
}
swidx_t fpga_switch_next(struct fpga_model* model, int y, int x,
swidx_t last, int from_to)
{
return fpga_switch_search(model, y, x, last,
(last & FIRST_SW) ? 0 : last+1, from_to);
}
swidx_t fpga_switch_backtofirst(struct fpga_model* model, int y, int x,
swidx_t last, int from_to)
{
return fpga_switch_search(model, y, x, last, /*search_beg*/ 0, from_to);
}
int fpga_swset_fromto(struct fpga_model* model, int y, int x,
str16_t start_switch, int from_to, struct sw_set* set)
{
swidx_t idx;
RC_CHECK(model);
set->len = 0;
idx = fpga_switch_first(model, y, x, start_switch, from_to);
while (idx != NO_SWITCH) {
if (set->len >= SW_SET_SIZE)
{ HERE(); return 0; }
set->sw[set->len++] = idx;
idx = fpga_switch_next(model, y, x, idx, from_to);
}
return 0;
}
int fpga_swset_contains(struct fpga_model* model, int y, int x,
const struct sw_set* set, int from_to, str16_t connpt)
{
struct fpga_tile* tile;
int i;
RC_CHECK(model);
tile = YX_TILE(model, y, x);
for (i = 0; i < set->len; i++) {
if (CONNPT_STR16(tile, SW_I(set->sw[i], from_to)) == connpt)
return i;
}
return -1;
}
void fpga_swset_remove_connpt(struct fpga_model* model, int y, int x,
struct sw_set* set, int from_to, str16_t connpt)
{
int i;
while ((i = fpga_swset_contains(model, y, x, set,
from_to, connpt)) != -1) {
if (set->len > i+1)
memmove(&set->sw[i], &set->sw[i+1],
(set->len-i-1)*sizeof(set->sw[0]));
set->len--;
}
}
void fpga_swset_remove_loop(struct fpga_model* model, int y, int x,
struct sw_set* set, const struct sw_set* parents, int from_to)
{
int i;
struct fpga_tile* tile;
tile = YX_TILE(model, y, x);
for (i = 0; i < parents->len; i++) {
fpga_swset_remove_connpt(model, y, x, set, !from_to,
CONNPT_STR16(tile, SW_I(parents->sw[i], from_to)));
}
}
void fpga_swset_remove_sw(struct fpga_model* model, int y, int x,
struct sw_set* set, swidx_t sw)
{
int sw_from_connpt, sw_to_connpt, cur_from_connpt, cur_to_connpt, i;
sw_from_connpt = SW_I(sw, SW_FROM);
sw_to_connpt = SW_I(sw, SW_TO);
for (i = 0; i < set->len; i++) {
cur_from_connpt = SW_I(set->sw[i], SW_FROM);
cur_to_connpt = SW_I(set->sw[i], SW_TO);
if (cur_from_connpt == sw_from_connpt
&& cur_to_connpt == sw_to_connpt) {
if ((sw & SWITCH_BIDIRECTIONAL)
!= (set->sw[i] & SWITCH_BIDIRECTIONAL))
HERE();
if (set->len > i+1)
memmove(&set->sw[i], &set->sw[i+1],
(set->len-i-1)*sizeof(set->sw[0]));
set->len--;
return;
}
if (cur_from_connpt == sw_to_connpt
&& cur_to_connpt == sw_from_connpt)
HERE();
}
}
int fpga_swset_level_down(struct fpga_model* model, int y, int x,
struct sw_set* set, int from_to)
{
int i;
RC_CHECK(model);
i = 0;
while (i < set->len) {
set->sw[i] = fpga_switch_first(model, y, x,fpga_switch_str_i(
model, y, x, set->sw[i], !from_to), from_to);
if (set->sw[i] == NO_SWITCH) {
if (set->len > i+1)
memmove(&set->sw[i], &set->sw[i+1],
(set->len-i-1)*sizeof(set->sw[0]));
set->len--;
} else
i++;
}
return 0;
}
void fpga_swset_print(struct fpga_model* model, int y, int x,
struct sw_set* set, int from_to)
{
int i;
for (i = 0; i < set->len; i++) {
printf("swset %i %s\n", i, fpga_switch_print(model,
y, x, set->sw[i]));
}
}
int fpga_swset_is_used(struct fpga_model* model, int y, int x,
swidx_t* sw, int len)
{
int i;
for (i = 0; i < len; i++) {
if (fpga_switch_is_used(model, y, x, sw[i]))
return 1;
}
return 0;
}
int fpga_switch_same_fromto(struct fpga_model* model, int y, int x,
swidx_t sw, int from_to, swidx_t* same_sw, int *same_len)
{
swidx_t cur_sw;
int max_len, rc;
RC_CHECK(model);
max_len = *same_len;
*same_len = 0;
if (max_len < 1) FAIL(EINVAL);
cur_sw = fpga_switch_search(model, y, x, sw, /*search_beg*/ 0, from_to);
// We should at least find sw itself, if not something is wrong...
if (cur_sw == NO_SWITCH) FAIL(EINVAL);
same_sw[(*same_len)++] = cur_sw;
while ((cur_sw = fpga_switch_search(model, y, x, sw, cur_sw+1, from_to)) != NO_SWITCH) {
same_sw[(*same_len)++] = cur_sw;
if ((*same_len) >= max_len) FAIL(EINVAL);
}
return 0;
fail:
return rc;
}
swidx_t fpga_switch_lookup(struct fpga_model* model, int y, int x,
str16_t from_str_i, str16_t to_str_i)
{
int from_connpt_o, to_connpt_o, i;
struct fpga_tile* tile;
from_connpt_o = fpga_connpt_find(model, y, x, from_str_i,
/*dests_o*/ 0, /*num_dests*/ 0);
to_connpt_o = fpga_connpt_find(model, y, x, to_str_i,
/*dests_o*/ 0, /*num_dests*/ 0);
if (from_connpt_o == NO_CONN || to_connpt_o == NO_CONN)
return NO_SWITCH;
tile = YX_TILE(model, y, x);
for (i = 0; i < tile->num_switches; i++) {
if (SW_FROM_I(tile->switches[i]) == from_connpt_o
&& SW_TO_I(tile->switches[i]) == to_connpt_o)
return i;
}
return NO_SWITCH;
}
#define NUM_CONNPT_BUFS 64
#define CONNPT_BUF_SIZE 128
static const char* connpt_str(struct fpga_model* model, int y, int x, int connpt_o)
{
// We have a little local ringbuffer to make passing
// around pointers with unknown lifetime and possible
// overlap with writing functions more stable.
static char switch_get_buf[NUM_CONNPT_BUFS][CONNPT_BUF_SIZE];
static int last_buf = 0;
const char* hash_str;
int str_i;
str_i = YX_TILE(model, y, x)->conn_point_names[connpt_o*2+1];
hash_str = strarray_lookup(&model->str, str_i);
if (!hash_str || (strlen(hash_str) >= CONNPT_BUF_SIZE)) {
HERE();
return 0;
}
last_buf = (last_buf+1)%NUM_CONNPT_BUFS;
return strcpy(switch_get_buf[last_buf], hash_str);
}
const char* fpga_switch_str(struct fpga_model* model, int y, int x,
swidx_t swidx, int from_to)
{
uint32_t sw = YX_TILE(model, y, x)->switches[swidx];
return connpt_str(model, y, x, SW_I(sw, from_to));
}
str16_t fpga_switch_str_i(struct fpga_model* model, int y, int x,
swidx_t swidx, int from_to)
{
struct fpga_tile* tile;
uint32_t sw;
int connpt_o;
tile = YX_TILE(model, y, x);
sw = tile->switches[swidx];
connpt_o = SW_I(sw, from_to);
return tile->conn_point_names[connpt_o*2+1];
}
const char* fpga_switch_print(struct fpga_model* model, int y, int x,
swidx_t swidx)
{
enum { NUM_BUFS = 16, BUF_SIZE = 128 };
static char buf[NUM_BUFS][BUF_SIZE];
static int last_buf = 0;
uint32_t sw;
sw = YX_TILE(model, y, x)->switches[swidx];
last_buf = (last_buf+1)%NUM_BUFS;
snprintf(buf[last_buf], sizeof(*buf), "%s %s %s",
connpt_str(model, y, x, SW_FROM_I(sw)),
sw & SWITCH_BIDIRECTIONAL ? "<->" : "->",
connpt_str(model, y, x, SW_TO_I(sw)));
return buf[last_buf];
}
int fpga_switch_is_bidir(struct fpga_model* model, int y, int x,
swidx_t swidx)
{
return (YX_TILE(model, y, x)->switches[swidx] & SWITCH_BIDIRECTIONAL) != 0;
}
int fpga_switch_is_used(struct fpga_model* model, int y, int x,
swidx_t swidx)
{
return (YX_TILE(model, y, x)->switches[swidx] & SWITCH_USED) != 0;
}
void fpga_switch_enable(struct fpga_model* model, int y, int x,
swidx_t swidx)
{
YX_TILE(model, y, x)->switches[swidx] |= SWITCH_USED;
}
int fpga_switch_set_enable(struct fpga_model* model, int y, int x,
struct sw_set* set)
{
int i;
for (i = 0; i < set->len; i++)
fpga_switch_enable(model, y, x, set->sw[i]);
return 0;
}
void fpga_switch_disable(struct fpga_model* model, int y, int x,
swidx_t swidx)
{
YX_TILE(model, y, x)->switches[swidx] &= ~SWITCH_USED;
}
#define SW_BUF_SIZE 256
#define NUM_SW_BUFS 64
static const char* fmt_swset_el(struct fpga_model* model, int y, int x,
swidx_t sw, int from_to)
{
static char sw_buf[NUM_SW_BUFS][SW_BUF_SIZE];
static int last_buf = 0;
char midstr[64];
last_buf = (last_buf+1)%NUM_SW_BUFS;
if (fpga_switch_is_bidir(model, y, x, sw))
strcpy(midstr, "<->");
else
strcpy(midstr, "->");
// fmt_swset_el() prints only the destination side of the
// switch (!from_to), because it is the significant one in
// a chain of switches, and if the caller wants the source
// side they can add it outside.
snprintf(sw_buf[last_buf], sizeof(sw_buf[0]), "%s%s%s",
(from_to == SW_FROM) ? ""
: fpga_switch_str(model, y, x, sw, SW_FROM),
midstr,
(from_to == SW_TO) ? ""
: fpga_switch_str(model, y, x, sw, SW_TO));
return sw_buf[last_buf];
}
#define FMT_SWSET_BUF_SIZE 2048
#define FMT_SWSET_NUM_BUFS 8
const char* fmt_swset(struct fpga_model* model, int y, int x,
struct sw_set* set, int from_to)
{
static char buf[FMT_SWSET_NUM_BUFS][FMT_SWSET_BUF_SIZE];
static int last_buf = 0;
int i, o;
last_buf = (last_buf+1)%FMT_SWSET_NUM_BUFS;
o = 0;
if (set->len) {
if (from_to == SW_FROM) {
strcpy(&buf[last_buf][o], fpga_switch_str(model, y, x, set->sw[0], SW_FROM));
o += strlen(&buf[last_buf][o]);
for (i = 0; i < set->len; i++) {
buf[last_buf][o++] = ' ';
strcpy(&buf[last_buf][o],
fmt_swset_el(model, y, x, set->sw[i], SW_FROM));
o += strlen(&buf[last_buf][o]);
}
} else { // SW_TO
for (i = set->len-1; i >= 0; i--) {
if (i < set->len-1) buf[last_buf][o++] = ' ';
strcpy(&buf[last_buf][o],
fmt_swset_el(model, y, x, set->sw[i], SW_TO));
o += strlen(&buf[last_buf][o]);
}
buf[last_buf][o++] = ' ';
strcpy(&buf[last_buf][o], fpga_switch_str(model, y, x, set->sw[0], SW_TO));
o += strlen(&buf[last_buf][o]);
}
}
buf[last_buf][o] = 0;
return buf[last_buf];
}
int construct_sw_chain(struct sw_chain* chain, struct fpga_model* model,
int y, int x, str16_t start_switch, int from_to, int max_depth,
net_idx_t exclusive_net, swidx_t* block_list, int block_list_len)
{
RC_CHECK(model);
#ifdef DBG_ENUM_SWITCH
printf("construct_sw_chain() %s (%s)\n",
strarray_lookup(&model->str, start_switch),
(from_to == SW_FROM) ? "SW_FROM" : "SW_TO");
#endif
memset(chain, 0, sizeof(*chain));
chain->model = model;
chain->y = y;
chain->x = x;
chain->from_to = from_to;
chain->max_depth = (max_depth < 0) ? SW_SET_SIZE : max_depth;
chain->exclusive_net = exclusive_net;
if (block_list) {
chain->block_list = block_list;
chain->block_list_len = block_list_len;
// internal_block_list is 0 from memset()
} else {
chain->internal_block_list = malloc(
MAX_SWITCHBOX_SIZE * sizeof(*chain->block_list));
if (!chain->internal_block_list)
RC_FAIL(model, ENOMEM);
chain->block_list = chain->internal_block_list;
chain->block_list_len = 0;
}
// at every level, the first round returns all members
// at that level, then the second round tries to go
// one level down for each member. This sorts the
// returned switches in a nice way.
chain->first_round = 1;
chain->set.len = 1;
chain->set.sw[0] = FIRST_SW | start_switch;
RC_RETURN(model);
}
void destruct_sw_chain(struct sw_chain* chain)
{
free(chain->internal_block_list);
memset(chain, 0, sizeof(*chain));
}
// returns NO_SWITCH if sw is not found in list, otherwise
// the offset in list where it is found.
static int switch_list_contains(struct fpga_model* model, int y, int x,
swidx_t* list, int list_len, swidx_t sw)
{
int sw_from_connpt, sw_to_connpt, cur_from_connpt, cur_to_connpt, i;
sw_from_connpt = SW_I(sw, SW_FROM);
sw_to_connpt = SW_I(sw, SW_TO);
for (i = 0; i < list_len; i++) {
cur_from_connpt = SW_I(list[i], SW_FROM);
cur_to_connpt = SW_I(list[i], SW_TO);
if (cur_from_connpt == sw_from_connpt
&& cur_to_connpt == sw_to_connpt) {
if ((sw & SWITCH_BIDIRECTIONAL)
!= (list[i] & SWITCH_BIDIRECTIONAL))
HERE();
return i;
}
if (cur_from_connpt == sw_to_connpt
&& cur_to_connpt == sw_from_connpt)
HERE();
}
return NO_SWITCH;
}
int fpga_switch_chain(struct sw_chain* ch)
{
swidx_t idx;
struct fpga_tile* tile;
int child_from_to, level_down, i;
if (!ch->set.len)
{ HERE(); goto internal_error; }
if (ch->first_round) {
// first go through all members at present level
while (1) {
idx = fpga_switch_next(ch->model, ch->y, ch->x,
ch->set.sw[ch->set.len-1], ch->from_to);
if (idx == NO_SWITCH)
break;
ch->set.sw[ch->set.len-1] = idx;
if ((ch->exclusive_net == NO_NET
|| !fpga_swset_in_other_net(ch->model, ch->y,
ch->x, &idx, /*len*/ 1,
ch->exclusive_net))
&& switch_list_contains(ch->model, ch->y, ch->x,
ch->block_list, ch->block_list_len, idx)
== NO_SWITCH)
return 0;
}
// if there are no more, start child round
ch->first_round = 0;
idx = fpga_switch_backtofirst(ch->model, ch->y, ch->x,
ch->set.sw[ch->set.len-1], ch->from_to);
if (idx == NO_SWITCH) {
ch->set.len = 0;
return NO_SWITCH;
}
#ifdef DBG_ENUM_SWITCH
printf("back_to_first from %s to %s\n",
fpga_switch_print(ch->model, ch->y, ch->x,
ch->set.sw[ch->set.len-1]),
fpga_switch_print(ch->model, ch->y, ch->x,
idx));
#endif
ch->set.sw[ch->set.len-1] = idx;
}
// look for children
tile = YX_TILE(ch->model, ch->y, ch->x);
while (1) {
idx = fpga_switch_first(ch->model, ch->y, ch->x,
fpga_switch_str_i(ch->model, ch->y, ch->x,
ch->set.sw[ch->set.len-1], !ch->from_to),
ch->from_to);
#ifdef DBG_ENUM_SWITCH
printf("child_check %s result %s\n", fpga_switch_str(
ch->model, ch->y, ch->x,
ch->set.sw[ch->set.len-1], !ch->from_to),
idx == NO_SWITCH ? "NO_SWITCH" : fpga_switch_print(
ch->model, ch->y, ch->x, idx));
#endif
if (idx != NO_SWITCH) {
// There are four reasons why we don't want to
// go down one level:
// 1) switch is used
// 2) switch loop back to parent of chain
// 3) switch is blocked
// 4) max depth reached
level_down = 1;
child_from_to = SW_I(tile->switches[ch->set.sw[
ch->set.len-1]], !ch->from_to);
#ifdef DBG_ENUM_SWITCH
printf(" child_from_to %s\n", connpt_str(
ch->model, ch->y, ch->x,
child_from_to));
#endif
if (ch->exclusive_net != NO_NET
&& fpga_swset_in_other_net(ch->model, ch->y, ch->x,
&idx, /*len*/ 1, ch->exclusive_net))
level_down = 0;
if (level_down) {
// If we have the same from-switch already
// among the parents, don't enter into a loop.
for (i = 0; i < ch->set.len; i++) {
int parent_connpt = SW_I(tile->switches[
ch->set.sw[i]], ch->from_to);
#ifdef DBG_ENUM_SWITCH
printf(" parent connpt %s%s\n", connpt_str(
ch->model, ch->y, ch->x,
parent_connpt), parent_connpt
== child_from_to ? " (match)" : "");
#endif
if (parent_connpt == child_from_to) {
level_down = 0;
break;
}
}
}
if (level_down) {
// only go down if not blocked
level_down = switch_list_contains(ch->model,
ch->y, ch->x, ch->block_list,
ch->block_list_len, idx) == NO_SWITCH;
}
if (level_down) {
if (ch->set.len >= SW_SET_SIZE)
{ HERE(); goto internal_error; }
if (ch->max_depth < 1
|| ch->set.len < ch->max_depth) {
// back to first round at next level
#ifdef DBG_ENUM_SWITCH
printf(" level_down %s\n",
fpga_switch_print(ch->model,
ch->y, ch->x, idx));
#endif
ch->first_round = 1;
ch->set.sw[ch->set.len] = idx;
ch->set.len++;
return 0;
}
}
}
while (1) {
// todo: don't know why we catch blocklist duplicates
// if ch->set.len > 1 - needs more debugging
if (switch_list_contains(ch->model, ch->y, ch->x,
ch->block_list, ch->block_list_len,
ch->set.sw[ch->set.len-1]) == NO_SWITCH) {
#ifdef DBG_ENUM_SWITCH
printf(" block_list_add %s\n", fpga_switch_print(
ch->model, ch->y, ch->x,
ch->set.sw[ch->set.len-1]));
#endif
if (ch->block_list_len >= MAX_SWITCHBOX_SIZE)
{ HERE(); goto internal_error; }
ch->block_list[ch->block_list_len++]
= ch->set.sw[ch->set.len-1];
}
ch->set.sw[ch->set.len-1] = fpga_switch_next(
ch->model, ch->y, ch->x,
ch->set.sw[ch->set.len-1], ch->from_to);
if (ch->set.sw[ch->set.len-1] != NO_SWITCH) {
if (ch->exclusive_net != NO_NET
&& fpga_swset_in_other_net(ch->model, ch->y, ch->x,
&ch->set.sw[ch->set.len-1], /*len*/ 1,
ch->exclusive_net)) {
#ifdef DBG_ENUM_SWITCH
printf(" skipping used %s\n",
fpga_switch_print(ch->model, ch->y,
ch->x, ch->set.sw[ch->set.len-1]));
#endif
continue;
}
#ifdef DBG_ENUM_SWITCH
printf(" found %s\n", fpga_switch_print(
ch->model, ch->y, ch->x,
ch->set.sw[ch->set.len-1]));
#endif
break;
}
if (ch->set.len <= 1) {
ch->set.len = 0;
return NO_SWITCH;
}
#ifdef DBG_ENUM_SWITCH
printf(" level_up\n");
#endif
ch->set.len--;
}
}
internal_error:
ch->set.len = 0;
return NO_SWITCH;
}
int construct_sw_conns(struct sw_conns* conns, struct fpga_model* model,
int y, int x, str16_t start_switch, int from_to, int max_depth,
net_idx_t exclusive_net)
{
RC_CHECK(model);
memset(conns, 0, sizeof(*conns));
construct_sw_chain(&conns->chain, model, y, x, start_switch,
from_to, max_depth, exclusive_net,
/*block_list*/ 0, /*block_list_len*/ 0);
RC_RETURN(model);
}
void destruct_sw_conns(struct sw_conns* conns)
{
destruct_sw_chain(&conns->chain);
memset(conns, 0, sizeof(*conns));
}
int fpga_multi_switch_lookup(struct fpga_model *model, int y, int x,
str16_t from_sw, str16_t to_sw, int max_depth, net_idx_t exclusive_net,
struct sw_set *sw_set)
{
struct sw_chain sw_chain;
sw_set->len = 0;
construct_sw_chain(&sw_chain, model, y, x, from_sw, SW_FROM, max_depth,
exclusive_net, /*block_list*/ 0, /*block_list_len*/ 0);
RC_CHECK(model);
while (fpga_switch_chain(&sw_chain) != NO_CONN) {
RC_ASSERT(model, sw_chain.set.len);
if (fpga_switch_str_i(model, y, x, sw_chain.set.sw[sw_chain.set.len-1],
SW_TO) == to_sw) {
*sw_set = sw_chain.set;
break;
}
}
destruct_sw_chain(&sw_chain);
RC_RETURN(model);
}
int fpga_switch_conns(struct sw_conns* conns)
{
str16_t end_of_chain_str;
if (conns->chain.model->rc
|| !conns->chain.set.len)
{ HERE(); goto internal_error; }
#ifdef DBG_SWITCH_TO_YX
printf("fpga_switch_conns() dest_i %i num_dests %i\n", conns->dest_i, conns->num_dests);
#endif
// on the first call, both dest_i and num_dests are 0
while (conns->dest_i >= conns->num_dests) {
fpga_switch_chain(&conns->chain);
if (conns->chain.set.len == 0) {
#ifdef DBG_SWITCH_TO_YX
printf(" no more switches\n");
#endif
return NO_CONN;
}
end_of_chain_str = fpga_switch_str_i(conns->chain.model,
conns->chain.y, conns->chain.x,
conns->chain.set.sw[conns->chain.set.len-1],
!conns->chain.from_to);
if (end_of_chain_str == STRIDX_NO_ENTRY)
{ HERE(); goto internal_error; }
conns->dest_i = 0;
fpga_connpt_find(conns->chain.model, conns->chain.y,
conns->chain.x, end_of_chain_str,
&conns->connpt_dest_start, &conns->num_dests);
if (conns->num_dests) {
#ifdef DBG_SWITCH_TO_YX
printf(" %s: %i conns\n", strarray_lookup(&conns->chain.model->str,
end_of_chain_str), conns->num_dests);
#endif
break;
}
#ifdef DBG_SWITCH_TO_YX
printf(" %s: no conns\n", strarray_lookup(
&conns->chain.model->str, end_of_chain_str));
#endif
}
fpga_conn_dest(conns->chain.model, conns->chain.y, conns->chain.x,
conns->connpt_dest_start + conns->dest_i,
&conns->dest_y, &conns->dest_x, &conns->dest_str_i);
if (conns->dest_str_i == STRIDX_NO_ENTRY)
{ HERE(); goto internal_error; }
conns->dest_i++;
return 0;
internal_error:
conns->chain.set.len = 0;
return NO_CONN;
}
int fpga_first_conn(struct fpga_model *model, int sw_y, int sw_x, str16_t sw_str,
int from_to, int max_depth, net_idx_t exclusive_net,
struct sw_set *sw_set, int *dest_y, int *dest_x, str16_t *dest_connpt)
{
struct sw_conns sw_conns;
construct_sw_conns(&sw_conns, model, sw_y, sw_x, sw_str, from_to,
max_depth, exclusive_net);
RC_CHECK(model);
if (fpga_switch_conns(&sw_conns) == NO_CONN)
RC_FAIL(model, EINVAL);
*sw_set = sw_conns.chain.set;
*dest_y = sw_conns.dest_y;
*dest_x = sw_conns.dest_x;
*dest_connpt = sw_conns.dest_str_i;
destruct_sw_conns(&sw_conns);
RC_RETURN(model);
}
void printf_swchain(struct fpga_model* model, int y, int x,
str16_t sw, int from_to, int max_depth, swidx_t* block_list,
int* block_list_len)
{
struct sw_chain chain;
int count = 0;
printf("printf_swchain() y%i x%i %s blist_len %i\n",
y, x, strarray_lookup(&model->str, sw),
block_list_len ? *block_list_len : 0);
if (construct_sw_chain(&chain, model, y, x, sw, from_to, max_depth,
NO_NET, block_list, block_list_len ? *block_list_len : 0))
{ HERE(); return; }
while (fpga_switch_chain(&chain) != NO_CONN) {
printf("sw %i %s\n", count++, fmt_swset(model, y, x,
&chain.set, from_to));
}
printf("sw - block_list_len %i\n", chain.block_list_len);
if (block_list_len)
*block_list_len = chain.block_list_len;
destruct_sw_chain(&chain);
}
void printf_swconns(struct fpga_model* model, int y, int x,
str16_t sw, int from_to, int max_depth)
{
struct sw_conns conns;
if (construct_sw_conns(&conns, model, y, x, sw, from_to,
max_depth, NO_NET))
{ HERE(); return; }
while (fpga_switch_conns(&conns) != NO_CONN) {
printf("sw %s conn y%i x%i %s\n", fmt_swset(model, y, x,
&conns.chain.set, from_to),
conns.dest_y, conns.dest_x,
strarray_lookup(&model->str, conns.dest_str_i));
}
printf("sw -\n");
destruct_sw_conns(&conns);
}
int fpga_switch_to_yx(struct switch_to_yx* p)
{
struct sw_conns conns;
struct sw_set best_set;
int best_y, best_x, best_distance, distance;
int best_num_dests;
str16_t best_connpt;
RC_CHECK(p->model);
#ifdef DBG_SWITCH_TO_YX
printf("fpga_switch_to_yx() %s y%i-x%i-%s yx_req %Xh flags %Xh excl_net %i\n",
p->from_to == SW_FROM ? "SW_FROM" : "SW_TO",
p->y, p->x, strarray_lookup(&p->model->str, p->start_switch),
p->yx_req, p->flags, p->exclusive_net);
#endif
construct_sw_conns(&conns, p->model, p->y, p->x, p->start_switch,
p->from_to, SW_SET_SIZE, p->exclusive_net);
RC_CHECK(p->model);
best_y = -1;
while (fpga_switch_conns(&conns) != NO_CONN) {
if (!is_atyx(p->yx_req, p->model, conns.dest_y, conns.dest_x))
continue;
#ifdef DBG_SWITCH_TO_YX
printf(" sw %s conn y%i x%i %s\n",
fmt_swset(p->model, p->y, p->x,
&conns.chain.set, p->from_to),
conns.dest_y, conns.dest_x,
strarray_lookup(&p->model->str, conns.dest_str_i));
#endif
if (best_y != -1) {
distance = abs(conns.dest_y-p->y)
+abs(conns.dest_x-p->x);
if (distance > best_distance)
continue;
else if (conns.num_dests > best_num_dests)
continue;
else if (conns.chain.set.len > best_set.len)
continue;
}
best_set = conns.chain.set;
best_y = conns.dest_y;
best_x = conns.dest_x;
best_num_dests = conns.num_dests;
best_connpt = conns.dest_str_i;
best_distance = abs(conns.dest_y-p->y)
+abs(conns.dest_x-p->x);
if (!p->flags & SWTO_YX_CLOSEST)
break;
}
if (best_y == -1)
p->set.len = 0;
else {
p->set = best_set;
p->dest_y = best_y;
p->dest_x = best_x;
p->dest_connpt = best_connpt;
}
destruct_sw_conns(&conns);
RC_RETURN(p->model);
}
void printf_switch_to_yx_result(struct switch_to_yx* p)
{
printf("switch_to_yx() from y%i x%i connpt %s (%s)\n",
p->y, p->x, strarray_lookup(&p->model->str, p->start_switch),
p->from_to == SW_FROM ? "SW_FROM" : "SW_TO");
printf(" %s y%i x%i %s via %s\n",
p->from_to == SW_FROM ? "to" : "from",
p->dest_y, p->dest_x,
strarray_lookup(&p->model->str, p->dest_connpt),
fmt_swset(p->model, p->y, p->x, &p->set, p->from_to));
}
int fpga_switch_to_yx_l2(struct switch_to_yx_l2 *p)
{
RC_CHECK(p->l1.model);
fpga_switch_to_yx(&p->l1);
RC_CHECK(p->l1.model);
p->l2_set.len = 0;
if (!p->l1.set.len) {
struct sw_conns conns;
struct switch_to_yx l2 = p->l1;
construct_sw_conns(&conns, p->l1.model, p->l1.y, p->l1.x, p->l1.start_switch,
p->l1.from_to, SW_SET_SIZE, p->l1.exclusive_net);
RC_CHECK(p->l1.model);
while (fpga_switch_conns(&conns) != NO_CONN) {
l2.y = conns.dest_y;
l2.x = conns.dest_x;
l2.start_switch = conns.dest_str_i;
fpga_switch_to_yx(&l2);
RC_CHECK(l2.model);
if (l2.set.len) {
p->l1.set = conns.chain.set;
p->l1.dest_y = l2.dest_y;
p->l1.dest_x = l2.dest_x;
p->l1.dest_connpt = l2.dest_connpt;
p->l2_set = l2.set;
p->l2_y = l2.y;
p->l2_x = l2.x;
break;
}
}
destruct_sw_conns(&conns);
}
RC_RETURN(p->l1.model);
}
int fpga_switch_to_rel(struct switch_to_rel *p)
{
struct sw_conns conns;
struct sw_set best_set;
int best_y, best_x, best_distance;
str16_t best_connpt;
RC_CHECK(p->model);
#ifdef DBG_SWITCH_TO_REL
printf("fpga_switch_to_rel() %s y%i-x%i-%s flags %Xh rel_y %i rel_x %i target_connpt %s\n",
p->from_to == SW_FROM ? "SW_FROM" : "SW_TO",
p->start_y, p->start_x, strarray_lookup(&p->model->str, p->start_switch),
p->flags, p->rel_y, p->rel_x,
p->target_connpt == STRIDX_NO_ENTRY ? "-" :
strarray_lookup(&p->model->str, p->target_connpt));
#endif
construct_sw_conns(&conns, p->model, p->start_y, p->start_x,
p->start_switch, p->from_to, SW_SET_SIZE, NO_NET);
RC_CHECK(p->model);
best_y = -1;
while (fpga_switch_conns(&conns) != NO_CONN) {
#ifdef DBG_SWITCH_TO_REL
printf(" sw %s conn y%i x%i %s\n",
fmt_swset(p->model, p->start_y, p->start_x,
&conns.chain.set, p->from_to),
conns.dest_y, conns.dest_x,
strarray_lookup(&p->model->str, conns.dest_str_i));
#endif
// Do not continue with connections that do not lead to
// a switch.
if (fpga_switch_first(p->model, conns.dest_y, conns.dest_x,
conns.dest_str_i, p->from_to) == NO_SWITCH) {
#ifdef DBG_SWITCH_TO_REL
printf(" no_switch\n");
#endif
continue;
}
if (conns.dest_y != p->start_y + p->rel_y
|| conns.dest_x != p->start_x + p->rel_x) {
if (!(p->flags & SWTO_REL_WEAK_TARGET))
continue;
if (best_y != -1) {
int distance = abs(conns.dest_y - (p->start_y+p->rel_y))
+ abs(conns.dest_x - (p->start_x+p->rel_x));
if (distance > best_distance)
continue;
}
best_set = conns.chain.set;
best_y = conns.dest_y;
best_x = conns.dest_x;
best_connpt = conns.dest_str_i;
best_distance = abs(conns.dest_y - (p->start_y+p->rel_y))
+ abs(conns.dest_x - (p->start_x+p->rel_x));
continue;
}
if (p->target_connpt != STRIDX_NO_ENTRY
&& conns.dest_str_i != p->target_connpt)
continue;
best_set = conns.chain.set;
best_y = conns.dest_y;
best_x = conns.dest_x;
best_connpt = conns.dest_str_i;
break;
}
if (best_y == -1)
p->set.len = 0;
else {
#ifdef DBG_SWITCH_TO_REL
printf(" sw %s\n", fmt_swset(p->model, p->start_y, p->start_x,
&best_set, p->from_to));
printf(" dest y%i-x%i-%s\n", best_y, best_x,
strarray_lookup(&p->model->str, best_connpt));
#endif
p->set = best_set;
p->dest_y = best_y;
p->dest_x = best_x;
p->dest_connpt = best_connpt;
}
destruct_sw_conns(&conns);
RC_RETURN(p->model);
}
void printf_switch_to_rel_result(struct switch_to_rel* p)
{
printf("switch_to_rel() from y%i x%i connpt %s (%s)\n",
p->start_y, p->start_x, strarray_lookup(&p->model->str, p->start_switch),
p->from_to == SW_FROM ? "SW_FROM" : "SW_TO");
printf(" %s y%i x%i %s via %s\n",
p->from_to == SW_FROM ? "to" : "from",
p->dest_y, p->dest_x,
strarray_lookup(&p->model->str, p->dest_connpt),
fmt_swset(p->model, p->start_y, p->start_x, &p->set, p->from_to));
}
#define NET_ALLOC_INCREMENT 64
static int fnet_useidx(struct fpga_model* model, net_idx_t new_idx)
{
void* new_ptr;
int new_array_size;
RC_CHECK(model);
RC_ASSERT(model, new_idx > NO_NET);
if (new_idx > model->highest_used_net)
model->highest_used_net = new_idx;
if ((new_idx-1) < model->nets_array_size)
return 0;
new_array_size = ((new_idx-1)/NET_ALLOC_INCREMENT+1)*NET_ALLOC_INCREMENT;
new_ptr = realloc(model->nets, new_array_size*sizeof(*model->nets));
if (!new_ptr) RC_FAIL(model, ENOMEM);
// the memset will set the 'len' of each new net to 0
memset(new_ptr + model->nets_array_size*sizeof(*model->nets), 0,
(new_array_size - model->nets_array_size)*sizeof(*model->nets));
model->nets = new_ptr;
model->nets_array_size = new_array_size;
RC_RETURN(model);
}
int fnet_new(struct fpga_model* model, net_idx_t* new_idx)
{
int rc;
RC_CHECK(model);
// highest_used_net is initialized to NO_NET which becomes 1
rc = fnet_useidx(model, model->highest_used_net+1);
if (rc) return rc;
*new_idx = model->highest_used_net;
return 0;
}
void fnet_delete(struct fpga_model* model, net_idx_t net_idx)
{
struct fpga_net* net;
int i;
net = &model->nets[net_idx-1];
for (i = 0; i < net->len; i++) {
if (net->el[i].idx & NET_IDX_IS_PINW)
continue;
if (!fpga_switch_is_used(model, net->el[i].y, net->el[i].x,
net->el[i].idx))
HERE();
fpga_switch_disable(model, net->el[i].y, net->el[i].x,
net->el[i].idx);
}
model->nets[net_idx-1].len = 0;
if (model->highest_used_net == net_idx)
model->highest_used_net--;
}
int fnet_enum(struct fpga_model* model, net_idx_t last, net_idx_t* next)
{
int i;
RC_CHECK(model);
// last can be NO_NET which becomes 1 = the first net index
for (i = last+1; i <= model->highest_used_net; i++) {
if (model->nets[i-1].len) {
*next = i;
return 0;
}
}
*next = NO_NET;
return 0;
}
struct fpga_net* fnet_get(struct fpga_model* model, net_idx_t net_i)
{
// function must work even if model->rc is set
if (net_i <= NO_NET
|| net_i > model->highest_used_net) {
fprintf(stderr, "%s:%i net_i %i highest_used %i\n", __FILE__,
__LINE__, net_i, model->highest_used_net);
return 0;
}
return &model->nets[net_i-1];
}
void fnet_free_all(struct fpga_model* model)
{
free(model->nets);
model->nets = 0;
model->nets_array_size = 0;
model->highest_used_net = 0;
}
int fpga_swset_in_other_net(struct fpga_model *model, int y, int x,
const swidx_t* sw, int len, net_idx_t our_net)
{
struct fpga_net* net_p;
int i, j;
net_p = fnet_get(model, our_net);
if (!net_p) { HERE(); return 0; }
for (i = 0; i < len; i++) {
if (!fpga_switch_is_used(model, y, x, sw[i]))
continue;
for (j = 0; j < net_p->len; j++) {
if (net_p->el[j].idx & NET_IDX_IS_PINW)
continue;
if (net_p->el[j].y == y
&& net_p->el[j].x == x
&& net_p->el[j].idx == sw[i])
break;
}
if (j >= net_p->len) {
// switch must be in other net
return 1;
}
}
return 0;
}
int fnet_add_port(struct fpga_model* model, net_idx_t net_i,
int y, int x, enum fpgadev_type type, dev_type_idx_t type_idx,
pinw_idx_t pinw_idx)
{
struct fpga_net* net;
fnet_useidx(model, net_i);
RC_CHECK(model);
net = &model->nets[net_i-1];
RC_ASSERT(model, net->len < MAX_NET_LEN);
net->el[net->len].y = y;
net->el[net->len].x = x;
net->el[net->len].idx = pinw_idx | NET_IDX_IS_PINW;
net->el[net->len].dev_idx = fpga_dev_idx(model, y, x, type, type_idx);
RC_ASSERT(model, net->el[net->len].dev_idx != NO_DEV);
net->len++;
RC_RETURN(model);
}
int fnet_add_sw(struct fpga_model* model, net_idx_t net_i,
int y, int x, const swidx_t* switches, int num_sw)
{
struct fpga_net* net;
int i, j;
fnet_useidx(model, net_i);
RC_CHECK(model);
// Check that none of the switches isn't already in use
// in another net.
if (fpga_swset_in_other_net(model, y, x, switches, num_sw, net_i))
RC_FAIL(model, EINVAL);
net = &model->nets[net_i-1];
for (i = 0; i < num_sw; i++) {
if (switches[i] == NO_SWITCH)
{ HERE(); continue; }
// check whether the switch is already in the net
for (j = 0; j < net->len; j++) {
if (net->el[j].y == y
&& net->el[j].x == x
&& net->el[j].idx == switches[i])
break;
}
if (j < net->len) continue;
// add the switch
RC_ASSERT(model, net->len < MAX_NET_LEN);
net->el[net->len].y = y;
net->el[net->len].x = x;
RC_ASSERT(model, !OUT_OF_U16(switches[i]));
if (fpga_switch_is_used(model, y, x, switches[i]))
HERE();
fpga_switch_enable(model, y, x, switches[i]);
net->el[net->len].idx = switches[i];
net->len++;
}
RC_RETURN(model);
}
static void _fnet_remove_sw(struct fpga_model *model, struct fpga_net *net_p, int i)
{
if (!fpga_switch_is_used(model, net_p->el[i].y, net_p->el[i].x, net_p->el[i].idx))
HERE();
fpga_switch_disable(model, net_p->el[i].y, net_p->el[i].x, net_p->el[i].idx);
if (net_p->len > i+1)
memmove(&net_p->el[i], &net_p->el[i+1],
(net_p->len-i-1)*sizeof(net_p->el[0]));
net_p->len--;
}
int fnet_remove_sw(struct fpga_model* model, net_idx_t net_i,
int y, int x, const swidx_t* switches, int num_sw)
{
struct fpga_net* net;
int i, j;
RC_CHECK(model);
RC_ASSERT(model, net_i <= model->highest_used_net);
net = &model->nets[net_i-1];
if (!net->len) {
HERE();
return 0;
}
for (i = 0; i < num_sw; i++) {
for (j = 0; j < net->len; j++) {
if (net->el[j].y == y
&& net->el[j].x == x
&& net->el[j].idx == switches[i])
break;
}
if (j >= net->len) {
// for now we expect the 'to-be-removed'
// switches to be in the net
HERE();
continue;
}
_fnet_remove_sw(model, net, j);
}
RC_RETURN(model);
}
int fnet_remove_all_sw(struct fpga_model* model, net_idx_t net_i)
{
struct fpga_net* net_p;
int i;
RC_CHECK(model);
net_p = fnet_get(model, net_i);
RC_ASSERT(model, net_p);
for (i = 0; i < net_p->len; i++) {
if (net_p->el[i].idx & NET_IDX_IS_PINW)
continue;
_fnet_remove_sw(model, net_p, i);
}
RC_RETURN(model);
}
static void fprintf_inout_pin(FILE* f, struct fpga_model* model,
net_idx_t net_i, struct net_el* el)
{
struct fpga_tile* tile;
pinw_idx_t pinw_i;
dev_idx_t dev_idx;
int in_pin;
const char* pin_str;
char buf[1024];
if (!(el->idx & NET_IDX_IS_PINW))
{ HERE(); return; }
tile = YX_TILE(model, el->y, el->x);
dev_idx = el->dev_idx;
if (dev_idx < 0 || dev_idx >= tile->num_devs)
{ HERE(); return; }
pinw_i = el->idx & NET_IDX_MASK;
if (pinw_i < 0 || pinw_i >= tile->devs[dev_idx].num_pinw_total)
{ HERE(); return; }
in_pin = pinw_i < tile->devs[dev_idx].num_pinw_in;
pin_str = fdev_pinw_idx2str(tile->devs[dev_idx].type, pinw_i);
if (!pin_str) { HERE(); return; }
snprintf(buf, sizeof(buf), "net %i %s y%i x%i %s %i pin %s\n",
net_i, in_pin ? "in" : "out", el->y, el->x,
fdev_type2str(tile->devs[dev_idx].type),
fdev_typeidx(model, el->y, el->x, dev_idx),
pin_str);
fprintf(f, "%s", buf);
}
void fnet_printf(FILE* f, struct fpga_model* model, net_idx_t net_i)
{
struct fpga_net* net;
int i;
net = fnet_get(model, net_i);
if (!net) { HERE(); return; }
for (i = 0; i < net->len; i++) {
if (net->el[i].idx & NET_IDX_IS_PINW) {
fprintf_inout_pin(f, model, net_i, &net->el[i]);
continue;
}
// switch
fprintf(f, "net %i sw y%i x%i %s\n",
net_i, net->el[i].y, net->el[i].x,
fpga_switch_print(model, net->el[i].y,
net->el[i].x, net->el[i].idx));
}
}
//
// routing
//
// locates the n'th (idx) inpin or outpin (is_out) in the net
static int fnet_pinw(struct fpga_model *model, net_idx_t net_i,
int is_out, int idx)
{
struct fpga_net *net_p;
struct fpga_device *dev_p;
int i, next_idx;
if (model->rc) { HERE(); return -1; };
net_p = fnet_get(model, net_i);
if (!net_p) { HERE(); return -1; };
next_idx = 0;
for (i = 0; i < net_p->len; i++) {
if (!(net_p->el[i].idx & NET_IDX_IS_PINW))
continue;
dev_p = FPGA_DEV(model, net_p->el[i].y,
net_p->el[i].x, net_p->el[i].dev_idx);
if ((is_out && (net_p->el[i].idx & NET_IDX_MASK) < dev_p->num_pinw_in)
|| (!is_out && (net_p->el[i].idx & NET_IDX_MASK) >= dev_p->num_pinw_in))
continue;
if (next_idx == idx)
return i;
next_idx++;
}
return -1;
}
static int fpga_switch_2sets(struct fpga_model* model, int from_y, int from_x,
str16_t from_pt, int to_y, int to_x, str16_t to_pt,
struct sw_set* from_set, struct sw_set* to_set)
{
struct sw_conns conns;
struct sw_set to_switches;
int i;
#ifdef DBG_SWITCH_2SETS
printf("fpga_switch_2sets() from y%i-x%i-%s to y%i-x%i-%s\n",
from_y, from_x, strarray_lookup(&model->str, from_pt),
to_y, to_x, strarray_lookup(&model->str, to_pt));
#endif
// only supports 1 switch on the end side right now
fpga_swset_fromto(model, to_y, to_x, to_pt, SW_TO, &to_switches);
RC_ASSERT(model, to_switches.len);
construct_sw_conns(&conns, model, from_y, from_x, from_pt,
SW_FROM, /*max_depth*/ 2, NO_NET);
while (fpga_switch_conns(&conns) != NO_CONN) {
#ifdef DBG_SWITCH_2SETS
printf(" sw %s conn y%i-x%i-%s\n", fmt_swset(model, from_y,
from_x, &conns.chain.set, SW_FROM),
conns.dest_y, conns.dest_x,
strarray_lookup(&model->str, conns.dest_str_i));
#endif
if (conns.dest_y != to_y
|| conns.dest_x != to_x) continue;
for (i = 0; i < to_switches.len; i++) {
if (conns.dest_str_i != fpga_switch_str_i(model, to_y,
to_x, to_switches.sw[i], SW_FROM))
continue;
*from_set = conns.chain.set;
to_set->len = 1;
to_set->sw[0] = to_switches.sw[i];
RC_RETURN(model);
}
}
destruct_sw_conns(&conns);
from_set->len = 0;
to_set->len = 0;
RC_RETURN(model);
}
static int fnet_dir_route(struct fpga_model* model, int from_y, int from_x,
str16_t from_pt, int to_y, int to_x, str16_t to_pt, net_idx_t net_i)
{
struct sw_set from_set, to_set;
struct switch_to_rel switch_to_rel;
int dist;
RC_CHECK(model);
do {
fpga_switch_2sets(model, from_y, from_x, from_pt, to_y, to_x, to_pt,
&from_set, &to_set);
RC_CHECK(model);
if (from_set.len && to_set.len) {
fnet_add_sw(model, net_i, from_y, from_x, from_set.sw, from_set.len);
fnet_add_sw(model, net_i, to_y, to_x, to_set.sw, to_set.len);
RC_RETURN(model);
}
dist = abs(to_y - from_y) + abs(to_x - from_x);
// Go through all single-depth conns and try
// switch_2sets from there.
if (dist <= 4) {
struct sw_conns sw_conns;
construct_sw_conns(&sw_conns, model, from_y, from_x,
from_pt, SW_FROM, /*max_depth*/ 1, net_i);
RC_CHECK(model);
while (fpga_switch_conns(&sw_conns) != NO_CONN) {
if ((fpga_switch_first(model, sw_conns.dest_y, sw_conns.dest_x,
sw_conns.dest_str_i, SW_FROM) == NO_SWITCH)
|| (abs(sw_conns.dest_y - from_y) + abs(sw_conns.dest_x - from_x) >= dist))
continue;
fpga_switch_2sets(model, sw_conns.dest_y,
sw_conns.dest_x, sw_conns.dest_str_i,
to_y, to_x, to_pt, &from_set, &to_set);
RC_CHECK(model);
if (from_set.len && to_set.len) {
fnet_add_sw(model, net_i, from_y, from_x, sw_conns.chain.set.sw, sw_conns.chain.set.len);
fnet_add_sw(model, net_i, sw_conns.dest_y, sw_conns.dest_x, from_set.sw, from_set.len);
fnet_add_sw(model, net_i, to_y, to_x, to_set.sw, to_set.len);
destruct_sw_conns(&sw_conns);
RC_RETURN(model);
}
}
destruct_sw_conns(&sw_conns);
}
switch_to_rel.model = model;
switch_to_rel.start_y = from_y;
switch_to_rel.start_x = from_x;
switch_to_rel.start_switch = from_pt;
switch_to_rel.from_to = SW_FROM;
switch_to_rel.flags = SWTO_REL_WEAK_TARGET;
switch_to_rel.rel_y = to_y - from_y;
switch_to_rel.rel_x = to_x - from_x;
switch_to_rel.target_connpt = STRIDX_NO_ENTRY;
fpga_switch_to_rel(&switch_to_rel);
RC_ASSERT(model, switch_to_rel.set.len);
fnet_add_sw(model, net_i, switch_to_rel.start_y, switch_to_rel.start_x,
switch_to_rel.set.sw, switch_to_rel.set.len);
from_y = switch_to_rel.dest_y;
from_x = switch_to_rel.dest_x;
from_pt = switch_to_rel.dest_connpt;
} while (1);
RC_RETURN(model);
}
static int fpga_switch_2sets_add(struct fpga_model* model, int from_y, int from_x,
str16_t from_pt, int to_y, int to_x, str16_t to_pt, net_idx_t net_i)
{
struct sw_set from_set, to_set;
fpga_switch_2sets(model, from_y, from_x, from_pt, to_y, to_x, to_pt,
&from_set, &to_set);
RC_ASSERT(model, from_set.len && to_set.len);
fnet_add_sw(model, net_i, from_y, from_x, from_set.sw, from_set.len);
fnet_add_sw(model, net_i, to_y, to_x, to_set.sw, to_set.len);
RC_RETURN(model);
}
static int fnet_route_iob_to_clock(struct fpga_model *model, net_idx_t net_i, int out_i, int in_i)
{
struct fpga_net *net_p;
struct fpga_device *out_dev, *in_dev;
struct switch_to_yx_l2 switch_to_yx_l2;
struct switch_to_rel switch_to_rel;
int hclk_y;
net_p = fnet_get(model, net_i);
RC_ASSERT(model, net_p);
out_dev = FPGA_DEV(model, net_p->el[out_i].y, net_p->el[out_i].x, net_p->el[out_i].dev_idx);
in_dev = FPGA_DEV(model, net_p->el[in_i].y, net_p->el[in_i].x, net_p->el[in_i].dev_idx);
RC_ASSERT(model, out_dev && in_dev);
// to regs (l2 allows one intermediate hop)
switch_to_yx_l2.l1.yx_req = YX_X_CENTER_CMTPLL | YX_Y_CENTER;
switch_to_yx_l2.l1.flags = SWTO_YX_CLOSEST;
switch_to_yx_l2.l1.model = model;
switch_to_yx_l2.l1.y = net_p->el[out_i].y;
switch_to_yx_l2.l1.x = net_p->el[out_i].x;
switch_to_yx_l2.l1.start_switch = out_dev->pinw[net_p->el[out_i].idx
& NET_IDX_MASK];
switch_to_yx_l2.l1.from_to = SW_FROM;
switch_to_yx_l2.l1.exclusive_net = NO_NET;
fpga_switch_to_yx_l2(&switch_to_yx_l2);
RC_ASSERT(model, switch_to_yx_l2.l1.set.len);
fnet_add_sw(model, net_i, switch_to_yx_l2.l1.y, switch_to_yx_l2.l1.x,
switch_to_yx_l2.l1.set.sw, switch_to_yx_l2.l1.set.len);
if (switch_to_yx_l2.l2_set.len)
fnet_add_sw(model, net_i, switch_to_yx_l2.l2_y, switch_to_yx_l2.l2_x,
switch_to_yx_l2.l2_set.sw, switch_to_yx_l2.l2_set.len);
// to center (possibly over intermediate)
switch_to_rel.dest_y = switch_to_yx_l2.l1.dest_y;
switch_to_rel.dest_x = switch_to_yx_l2.l1.dest_x;
switch_to_rel.dest_connpt = switch_to_yx_l2.l1.dest_connpt;
do {
switch_to_rel.model = model;
switch_to_rel.start_y = switch_to_rel.dest_y;
switch_to_rel.start_x = switch_to_rel.dest_x;
switch_to_rel.start_switch = switch_to_rel.dest_connpt;
switch_to_rel.from_to = SW_FROM;
switch_to_rel.flags = SWTO_REL_WEAK_TARGET;
switch_to_rel.rel_y = model->center_y - switch_to_rel.start_y;
switch_to_rel.rel_x = model->center_x - switch_to_rel.start_x;
switch_to_rel.target_connpt = STRIDX_NO_ENTRY;
fpga_switch_to_rel(&switch_to_rel);
RC_ASSERT(model, switch_to_rel.set.len);
fnet_add_sw(model, net_i, switch_to_rel.start_y, switch_to_rel.start_x,
switch_to_rel.set.sw, switch_to_rel.set.len);
} while (switch_to_rel.dest_y != model->center_y
|| switch_to_rel.dest_x != model->center_x);
// to hclk
RC_ASSERT(model, switch_to_rel.dest_y == model->center_y
&& switch_to_rel.dest_x == model->center_x);
hclk_y = y_to_hclk(net_p->el[in_i].y, model);
RC_ASSERT(model, hclk_y != -1);
do {
switch_to_rel.model = model;
switch_to_rel.start_y = switch_to_rel.dest_y;
switch_to_rel.start_x = switch_to_rel.dest_x;
switch_to_rel.start_switch = switch_to_rel.dest_connpt;
switch_to_rel.from_to = SW_FROM;
switch_to_rel.flags = SWTO_REL_WEAK_TARGET;
switch_to_rel.rel_y = hclk_y - switch_to_rel.start_y;
switch_to_rel.rel_x = 0;
switch_to_rel.target_connpt = STRIDX_NO_ENTRY;
fpga_switch_to_rel(&switch_to_rel);
RC_ASSERT(model, switch_to_rel.set.len);
fnet_add_sw(model, net_i, switch_to_rel.start_y, switch_to_rel.start_x,
switch_to_rel.set.sw, switch_to_rel.set.len);
} while (switch_to_rel.dest_y != hclk_y);
// to routing col
do {
switch_to_rel.model = model;
switch_to_rel.start_y = switch_to_rel.dest_y;
switch_to_rel.start_x = switch_to_rel.dest_x;
switch_to_rel.start_switch = switch_to_rel.dest_connpt;
switch_to_rel.from_to = SW_FROM;
switch_to_rel.flags = SWTO_REL_WEAK_TARGET;
switch_to_rel.rel_y = 0;
switch_to_rel.rel_x = net_p->el[in_i].x-1 - switch_to_rel.start_x;
switch_to_rel.target_connpt = STRIDX_NO_ENTRY;
fpga_switch_to_rel(&switch_to_rel);
RC_ASSERT(model, switch_to_rel.set.len);
fnet_add_sw(model, net_i, switch_to_rel.start_y, switch_to_rel.start_x,
switch_to_rel.set.sw, switch_to_rel.set.len);
} while (switch_to_rel.dest_x != net_p->el[in_i].x-1);
// to logic device routing
switch_to_rel.model = model;
switch_to_rel.start_y = switch_to_rel.dest_y;
switch_to_rel.start_x = switch_to_rel.dest_x;
switch_to_rel.start_switch = switch_to_rel.dest_connpt;
switch_to_rel.from_to = SW_FROM;
switch_to_rel.flags = SWTO_REL_DEFAULT;
switch_to_rel.rel_y = net_p->el[in_i].y - switch_to_rel.start_y;
switch_to_rel.rel_x = net_p->el[in_i].x-1 - switch_to_rel.start_x;
switch_to_rel.target_connpt = STRIDX_NO_ENTRY;
fpga_switch_to_rel(&switch_to_rel);
RC_ASSERT(model, switch_to_rel.set.len);
fnet_add_sw(model, net_i, switch_to_rel.start_y, switch_to_rel.start_x,
switch_to_rel.set.sw, switch_to_rel.set.len);
// connect with pinw
fpga_switch_2sets_add(model,
net_p->el[in_i].y, net_p->el[in_i].x-1, switch_to_rel.dest_connpt,
net_p->el[in_i].y, net_p->el[in_i].x,
in_dev->pinw[net_p->el[in_i].idx & NET_IDX_MASK], net_i);
RC_RETURN(model);
}
static int fnet_route_iob_to_logic(struct fpga_model *model, net_idx_t net_i, int out_i, int in_i)
{
struct fpga_net *net_p;
struct fpga_device *out_dev, *in_dev;
struct switch_to_yx switch_to;
struct switch_to_rel switch_to_rel;
net_p = fnet_get(model, net_i);
RC_ASSERT(model, net_p);
out_dev = FPGA_DEV(model, net_p->el[out_i].y, net_p->el[out_i].x, net_p->el[out_i].dev_idx);
in_dev = FPGA_DEV(model, net_p->el[in_i].y, net_p->el[in_i].x, net_p->el[in_i].dev_idx);
RC_ASSERT(model, out_dev && in_dev);
// switch to ilogic
switch_to.yx_req = YX_DEV_ILOGIC;
switch_to.flags = SWTO_YX_DEF;
switch_to.model = model;
switch_to.y = net_p->el[out_i].y;
switch_to.x = net_p->el[out_i].x;
switch_to.start_switch = out_dev->pinw[net_p->el[out_i].idx
& NET_IDX_MASK];
switch_to.from_to = SW_FROM;
switch_to.exclusive_net = NO_NET;
fpga_switch_to_yx(&switch_to);
fnet_add_sw(model, net_i, switch_to.y, switch_to.x,
switch_to.set.sw, switch_to.set.len);
// switch to ilogic routing
switch_to.yx_req = YX_ROUTING_TILE;
switch_to.flags = SWTO_YX_DEF;
switch_to.model = model;
switch_to.y = switch_to.dest_y;
switch_to.x = switch_to.dest_x;
switch_to.start_switch = switch_to.dest_connpt;
switch_to.from_to = SW_FROM;
switch_to.exclusive_net = net_i;
fpga_switch_to_yx(&switch_to);
fnet_add_sw(model, net_i, switch_to.y, switch_to.x,
switch_to.set.sw, switch_to.set.len);
// switch backwards from logic tile to logic routing tile
switch_to_rel.model = model;
switch_to_rel.start_y = net_p->el[in_i].y;
switch_to_rel.start_x = net_p->el[in_i].x;
switch_to_rel.start_switch =
in_dev->pinw[net_p->el[in_i].idx & NET_IDX_MASK];
switch_to_rel.from_to = SW_TO;
switch_to_rel.flags = SWTO_REL_DEFAULT;
switch_to_rel.rel_y = 0;
switch_to_rel.rel_x = -1;
switch_to_rel.target_connpt = STRIDX_NO_ENTRY;
fpga_switch_to_rel(&switch_to_rel);
RC_ASSERT(model, switch_to_rel.set.len);
fnet_add_sw(model, net_i, switch_to_rel.start_y,
switch_to_rel.start_x, switch_to_rel.set.sw,
switch_to_rel.set.len);
// route from ilogic routing to logic routing
fpga_switch_2sets_add(model, switch_to.dest_y, switch_to.dest_x,
switch_to.dest_connpt,
switch_to_rel.dest_y, switch_to_rel.dest_x,
switch_to_rel.dest_connpt,
net_i);
RC_RETURN(model);
}
static int fnet_route_logic_to_iob(struct fpga_model *model, net_idx_t net_i, int out_i, int in_i)
{
struct fpga_net *net_p;
struct fpga_device *out_dev, *in_dev;
struct switch_to_yx switch_to_yx;
struct switch_to_rel switch_to_rel;
net_p = fnet_get(model, net_i);
RC_ASSERT(model, net_p);
out_dev = FPGA_DEV(model, net_p->el[out_i].y, net_p->el[out_i].x, net_p->el[out_i].dev_idx);
in_dev = FPGA_DEV(model, net_p->el[in_i].y, net_p->el[in_i].x, net_p->el[in_i].dev_idx);
RC_ASSERT(model, out_dev && in_dev);
// switch from ologic to iob
switch_to_yx.yx_req = YX_DEV_OLOGIC;
switch_to_yx.flags = SWTO_YX_DEF;
switch_to_yx.model = model;
switch_to_yx.y = net_p->el[in_i].y;
switch_to_yx.x = net_p->el[in_i].x;
switch_to_yx.start_switch = in_dev->pinw[net_p->el[in_i].idx
& NET_IDX_MASK];
switch_to_yx.from_to = SW_TO;
switch_to_yx.exclusive_net = net_i;
fpga_switch_to_yx(&switch_to_yx);
fnet_add_sw(model, net_i, switch_to_yx.y, switch_to_yx.x,
switch_to_yx.set.sw, switch_to_yx.set.len);
// switches inside ologic to ologic routing
switch_to_yx.yx_req = YX_ROUTING_TILE;
switch_to_yx.flags = SWTO_YX_DEF;
switch_to_yx.model = model;
switch_to_yx.y = switch_to_yx.dest_y;
switch_to_yx.x = switch_to_yx.dest_x;
switch_to_yx.start_switch = switch_to_yx.dest_connpt;
switch_to_yx.from_to = SW_TO;
switch_to_yx.exclusive_net = net_i;
fpga_switch_to_yx(&switch_to_yx);
fnet_add_sw(model, net_i, switch_to_yx.y, switch_to_yx.x,
switch_to_yx.set.sw, switch_to_yx.set.len);
// switch inside logic tile
switch_to_rel.model = model;
switch_to_rel.start_y = net_p->el[out_i].y;
switch_to_rel.start_x = net_p->el[out_i].x;
switch_to_rel.start_switch =
out_dev->pinw[net_p->el[out_i].idx & NET_IDX_MASK];
switch_to_rel.from_to = SW_FROM;
switch_to_rel.flags = SWTO_REL_DEFAULT;
switch_to_rel.rel_y = 0;
switch_to_rel.rel_x = -1;
switch_to_rel.target_connpt = STRIDX_NO_ENTRY;
fpga_switch_to_rel(&switch_to_rel);
fnet_add_sw(model, net_i, switch_to_rel.start_y,
switch_to_rel.start_x, switch_to_rel.set.sw,
switch_to_rel.set.len);
// route from logic routing to ilogic routing
fnet_dir_route(model, switch_to_rel.dest_y,
switch_to_rel.dest_x, switch_to_rel.dest_connpt,
switch_to_yx.dest_y, switch_to_yx.dest_x, switch_to_yx.dest_connpt,
net_i);
RC_RETURN(model);
}
static int fnet_route_logic_carry(struct fpga_model *model, net_idx_t net_i, int out_i, int in_i)
{
struct fpga_net *net_p;
struct fpga_device *out_dev, *in_dev;
int xm_col, from_str_i, to_str_i;
swidx_t sw;
net_p = fnet_get(model, net_i);
RC_ASSERT(model, net_p);
out_dev = FPGA_DEV(model, net_p->el[out_i].y, net_p->el[out_i].x, net_p->el[out_i].dev_idx);
in_dev = FPGA_DEV(model, net_p->el[in_i].y, net_p->el[in_i].x, net_p->el[in_i].dev_idx);
RC_ASSERT(model, out_dev && in_dev);
RC_ASSERT(model, (net_p->el[in_i].x == net_p->el[out_i].x)
&& (net_p->el[in_i].y == regular_row_up(net_p->el[out_i].y, model)));
xm_col = has_device_type(model, net_p->el[out_i].y, net_p->el[out_i].x, DEV_LOGIC, LOGIC_M);
if (xm_col) {
from_str_i = strarray_find(&model->str, "M_COUT");
to_str_i = strarray_find(&model->str, "M_COUT_N");
} else { // xl
from_str_i = strarray_find(&model->str, "XL_COUT");
to_str_i = strarray_find(&model->str, "XL_COUT_N");
}
RC_ASSERT(model, from_str_i != STRIDX_NO_ENTRY && !OUT_OF_U16(from_str_i));
RC_ASSERT(model, to_str_i != STRIDX_NO_ENTRY && !OUT_OF_U16(to_str_i));
sw = fpga_switch_lookup(model, net_p->el[out_i].y, net_p->el[out_i].x,
from_str_i, to_str_i);
fnet_add_sw(model, net_i, net_p->el[out_i].y, net_p->el[out_i].x,
&sw, /*len*/ 1);
RC_RETURN(model);
}
static int fnet_route_logic_to_self(struct fpga_model *model,
net_idx_t net_i, int out_i, int in_i)
{
struct fpga_net *net_p;
int logic_y, logic_x, logic_dev_idx;
struct fpga_device *logic_dev;
struct sw_set sw_set;
int out_dest_y, out_dest_x, in_dest_y, in_dest_x;
str16_t out_dest_connpt, in_dest_connpt;
net_p = fnet_get(model, net_i);
RC_ASSERT(model, net_p);
logic_y = net_p->el[out_i].y;
logic_x = net_p->el[out_i].x;
logic_dev_idx = net_p->el[out_i].dev_idx;
RC_ASSERT(model, net_p->el[in_i].y == logic_y
&& net_p->el[in_i].x == logic_x
&& net_p->el[in_i].dev_idx == logic_dev_idx);
logic_dev = FPGA_DEV(model, logic_y, logic_x, logic_dev_idx);
RC_ASSERT(model, logic_dev);
fpga_first_conn(model, logic_y, logic_x,
logic_dev->pinw[net_p->el[out_i].idx & NET_IDX_MASK], SW_FROM,
/*max_depth*/ 2, net_i,
&sw_set, &out_dest_y, &out_dest_x, &out_dest_connpt);
RC_CHECK(model);
fnet_add_sw(model, net_i, logic_y, logic_x, sw_set.sw, sw_set.len);
fpga_first_conn(model, logic_y, logic_x,
logic_dev->pinw[net_p->el[in_i].idx & NET_IDX_MASK], SW_TO,
/*max_depth*/ 2, net_i,
&sw_set, &in_dest_y, &in_dest_x, &in_dest_connpt);
RC_ASSERT(model, out_dest_y == in_dest_y
&& out_dest_x == in_dest_x);
fnet_add_sw(model, net_i, logic_y, logic_x, sw_set.sw, sw_set.len);
fpga_multi_switch_lookup(model, out_dest_y, out_dest_x,
out_dest_connpt, in_dest_connpt, /*max_depth*/ 2, net_i,
&sw_set);
RC_ASSERT(model, sw_set.len);
fnet_add_sw(model, net_i, out_dest_y, out_dest_x, sw_set.sw, sw_set.len);
RC_RETURN(model);
}
static int fnet_route_to_inpin(struct fpga_model *model, net_idx_t net_i, int out_i, int in_i)
{
struct fpga_net *net_p;
struct fpga_device *out_dev, *in_dev;
net_p = fnet_get(model, net_i);
RC_ASSERT(model, net_p);
out_dev = FPGA_DEV(model, net_p->el[out_i].y, net_p->el[out_i].x, net_p->el[out_i].dev_idx);
in_dev = FPGA_DEV(model, net_p->el[in_i].y, net_p->el[in_i].x, net_p->el[in_i].dev_idx);
RC_ASSERT(model, out_dev && in_dev);
if (out_dev->type == DEV_IOB) {
if (in_dev->type != DEV_LOGIC)
RC_FAIL(model, ENOTSUP);
if ((net_p->el[in_i].idx & NET_IDX_MASK) == LI_CLK)
fnet_route_iob_to_clock(model, net_i, out_i, in_i);
else
fnet_route_iob_to_logic(model, net_i, out_i, in_i);
} else if (out_dev->type == DEV_LOGIC) {
if (in_dev->type == DEV_IOB)
fnet_route_logic_to_iob(model, net_i, out_i, in_i);
else if (in_dev->type == DEV_LOGIC) {
if (net_p->el[in_i].y == net_p->el[out_i].y
&& net_p->el[in_i].x == net_p->el[out_i].x) {
fnet_route_logic_to_self(model, net_i, out_i, in_i);
} else {
RC_ASSERT(model, (net_p->el[out_i].idx & NET_IDX_MASK) == LO_COUT
&& (net_p->el[in_i].idx & NET_IDX_MASK) == LI_CIN);
fnet_route_logic_carry(model, net_i, out_i, in_i);
}
} else RC_FAIL(model, ENOTSUP);
} else
RC_FAIL(model, ENOTSUP);
RC_RETURN(model);
}
int fnet_route(struct fpga_model* model, net_idx_t net_i)
{
int out_i, in_i, in_enum;
RC_CHECK(model);
out_i = fnet_pinw(model, net_i, /*is_out*/ 1, /*idx*/ 0);
if (out_i == -1) { HERE(); return 0; }
in_i = fnet_pinw(model, net_i, /*is_out*/ 0, /*idx*/ 0);
if (in_i == -1) { HERE(); return 0; }
if (fnet_pinw(model, net_i, /*is_out*/ 1, /*idx*/ 1) != -1)
RC_FAIL(model, EINVAL);
in_enum = 0;
do {
fnet_route_to_inpin(model, net_i, out_i, in_i);
RC_CHECK(model);
in_i = fnet_pinw(model, net_i, /*is_out*/ 0, /*idx*/ ++in_enum);
} while (in_i != -1);
RC_RETURN(model);
}
int fnet_vcc_gnd(struct fpga_model *model, net_idx_t net_i, int is_vcc)
{
struct fpga_net *net_p;
int out_i, in_i, in_enum;
struct fpga_device *in_dev;
str16_t from_i;
RC_CHECK(model);
out_i = fnet_pinw(model, net_i, /*is_out*/ 1, /*idx*/ 0);
if (out_i != -1) { HERE(); return 0; }
in_i = fnet_pinw(model, net_i, /*is_out*/ 0, /*idx*/ 0);
if (in_i == -1) { HERE(); return 0; }
net_p = fnet_get(model, net_i);
RC_ASSERT(model, net_p);
from_i = strarray_find(&model->str, is_vcc ? "VCC_WIRE" : "GND_WIRE");
RC_ASSERT(model, !OUT_OF_U16(from_i));
in_enum = 0;
do {
in_dev = FPGA_DEV(model, net_p->el[in_i].y,
net_p->el[in_i].x, net_p->el[in_i].dev_idx & NET_IDX_MASK);
RC_ASSERT(model, in_dev);
if (in_dev->type == DEV_LOGIC) {
fpga_switch_2sets_add(model,
net_p->el[in_i].y, net_p->el[in_i].x-1, from_i,
net_p->el[in_i].y, net_p->el[in_i].x,
in_dev->pinw[net_p->el[in_i].idx & NET_IDX_MASK],
net_i);
RC_CHECK(model);
} else HERE();
in_i = fnet_pinw(model, net_i, /*is_out*/ 0, /*idx*/ ++in_enum);
} while (in_i != -1);
RC_RETURN(model);
}
fpgatools-201212/libs/control.h 0000664 0000000 0000000 00000034512 12065743015 0016373 0 ustar 00root root 0000000 0000000 //
// Author: Wolfgang Spraul
//
// This is free and unencumbered software released into the public domain.
// For details see the UNLICENSE file at the root of the source tree.
//
typedef int net_idx_t; // net indices are 1-based
#define NO_NET 0
const char* fpga_enum_iob(struct fpga_model* model, int enum_idx,
int* y, int* x, dev_type_idx_t* type_idx);
int fpga_find_iob(struct fpga_model* model, const char* sitename,
int* y, int* x, dev_type_idx_t* idx);
const char* fpga_iob_sitename(struct fpga_model* model, int y, int x,
dev_type_idx_t idx);
//
// When dealing with devices, there are two indices:
// 1. The index of the device in the device array for that tile.
// 2. The index of the device within devices of the same type in the tile.
//
// If index is past the last device of that type,
// y is returned as -1.
int fdev_enum(struct fpga_model* model, enum fpgadev_type type, int enum_i,
int *y, int *x, int *type_idx);
const char* fdev_type2str(enum fpgadev_type type);
enum fpgadev_type fdev_str2type(const char* str, int len);
// returns 0 if device not found
struct fpga_device* fdev_p(struct fpga_model* model,
int y, int x, enum fpgadev_type type, dev_type_idx_t type_idx);
// Looks up a device index based on the type index.
// returns NO_DEV (-1) if not found
dev_idx_t fpga_dev_idx(struct fpga_model* model,
int y, int x, enum fpgadev_type type, dev_type_idx_t type_idx);
// Counts how many devices of the same type as dev_idx are in
// the array up to dev_idx.
dev_type_idx_t fdev_typeidx(struct fpga_model* model, int y, int x,
dev_idx_t dev_idx);
#define PINW_NO_IDX -1
pinw_idx_t fdev_pinw_str2idx(int devtype, const char* str, int len);
// returns 0 when idx not found for the given devtype
const char* fdev_pinw_idx2str(int devtype, pinw_idx_t idx);
// ld1_type can be LOGIC_M or LOGIC_L to specify whether
// we are in a XM or XL column. You can |LD1 to idx for
// the second logic device (L or M).
const char* fdev_logic_pinstr(pinw_idx_t idx, int ld1_type);
str16_t fdev_logic_pinstr_i(struct fpga_model* model, pinw_idx_t idx, int ld1_type);
int fdev_logic_setconf(struct fpga_model* model, int y, int x,
int type_idx, const struct fpgadev_logic* logic_cfg);
// lut_a2d is LUT_A to LUT_D
int fdev_logic_a2d_out_used(struct fpga_model* model, int y, int x,
int type_idx, int lut_a2d, int used);
// lut_5or6 is int 5 or int 6
int fdev_logic_a2d_lut(struct fpga_model* model, int y, int x, int type_idx,
int lut_a2d, int lut_5or6, const char* lut_str, int lut_len);
// srinit is FF_SRINIT0 or FF_SRINIT1
int fdev_logic_a2d_ff(struct fpga_model* model, int y, int x, int type_idx,
int lut_a2d, int ff_mux, int srinit);
int fdev_logic_a2d_ff5_srinit(struct fpga_model* model, int y, int x,
int type_idx, int lut_a2d, int srinit);
int fdev_logic_a2d_out_mux(struct fpga_model* model, int y, int x,
int type_idx, int lut_a2d, int out_mux);
// cy0 is CY0_X or CY0_O5
int fdev_logic_a2d_cy0(struct fpga_model* model, int y, int x,
int type_idx, int lut_a2d, int cy0);
// clk is CLKINV_B or CLKINV_CLK
int fdev_logic_clk(struct fpga_model* model, int y, int x, int type_idx,
int clk);
// sync is SYNCATTR_SYNC or SYNCATTR_ASYNC
int fdev_logic_sync(struct fpga_model* model, int y, int x, int type_idx,
int sync_attr);
int fdev_logic_ce_used(struct fpga_model* model, int y, int x, int type_idx);
int fdev_logic_sr_used(struct fpga_model* model, int y, int x, int type_idx);
// we_mux can be WEMUX_WE or WEMUX_CE
int fdev_logic_we_mux(struct fpga_model* model, int y, int x,
int type_idx, int we_mux);
int fdev_logic_cout_used(struct fpga_model* model, int y, int x,
int type_idx, int used);
// precyinit can be PRECYINIT_O, PRECYINIT_1 or PRECYINIT_AX
int fdev_logic_precyinit(struct fpga_model* model, int y, int x,
int type_idx, int precyinit);
int fdev_iob_input(struct fpga_model* model, int y, int x,
int type_idx, const char* io_std);
int fdev_iob_output(struct fpga_model* model, int y, int x,
int type_idx, const char* io_std);
int fdev_iob_IMUX(struct fpga_model* model, int y, int x,
int type_idx, int mux);
int fdev_iob_slew(struct fpga_model* model, int y, int x,
int type_idx, int slew);
int fdev_iob_drive(struct fpga_model* model, int y, int x,
int type_idx, int drive_strength);
int fdev_bufgmux(struct fpga_model* model, int y, int x,
int type_idx, int clk, int disable_attr, int s_inv);
int fdev_set_required_pins(struct fpga_model* model, int y, int x, int type,
int type_idx);
void fdev_print_required_pins(struct fpga_model* model, int y, int x,
int type, int type_idx);
void fdev_delete(struct fpga_model* model, int y, int x, int type,
int type_idx);
// Returns the connpt index or NO_CONN if the name was not
// found. connpt_dests_o and num_dests are optional and may
// return the offset into the connpt's destination array
// and number of elements there.
int fpga_connpt_find(struct fpga_model* model, int y, int x,
str16_t name_i, int* connpt_dests_o, int* num_dests);
void fpga_conn_dest(struct fpga_model* model, int y, int x,
int connpt_dest_idx, int* dest_y, int* dest_x, str16_t* str_i);
// Searches a connection in search_y/search_x that connects to
// target_y/target_x/target_pt.
int fpga_find_conn(struct fpga_model* model, int search_y, int search_x,
str16_t* pt, int target_y, int target_x, str16_t target_pt);
//
// switches
//
typedef int swidx_t; // swidx_t is an index into the uint32_t switches array
// SW_SET_SIZE should be enough for:
// *) largest number of switches that can go from or to one
// specific connection point (ca. 32)
// *) largest depth inside a switchbox (ca. 20)
// *) some wires that go 'everywhere' like GFAN (70)
#define SW_SET_SIZE 128
struct sw_set
{
swidx_t sw[SW_SET_SIZE];
int len;
};
// returns a switch index, or -1 (NO_SWITCH) if no switch was found
swidx_t fpga_switch_first(struct fpga_model* model, int y, int x,
str16_t name_i, int from_to);
swidx_t fpga_switch_next(struct fpga_model* model, int y, int x,
swidx_t last, int from_to);
swidx_t fpga_switch_backtofirst(struct fpga_model* model, int y, int x,
swidx_t last, int from_to);
int fpga_swset_fromto(struct fpga_model* model, int y, int x,
str16_t start_switch, int from_to, struct sw_set* set);
// returns -1 if not found, otherwise index into the set
int fpga_swset_contains(struct fpga_model* model, int y, int x,
const struct sw_set* set, int from_to, str16_t connpt);
void fpga_swset_remove_connpt(struct fpga_model* model, int y, int x,
struct sw_set* set, int from_to, str16_t connpt);
// removes all switches from set whose !from_to is equal to the
// from_to in parents
void fpga_swset_remove_loop(struct fpga_model* model, int y, int x,
struct sw_set* set, const struct sw_set* parents, int from_to);
void fpga_swset_remove_sw(struct fpga_model* model, int y, int x,
struct sw_set* set, swidx_t sw);
int fpga_swset_level_down(struct fpga_model* model, int y, int x,
struct sw_set* set, int from_to);
void fpga_swset_print(struct fpga_model* model, int y, int x,
struct sw_set* set, int from_to);
int fpga_swset_is_used(struct fpga_model* model, int y, int x,
swidx_t* sw, int len);
// When calling, same_len must contain the size of the
// same_sw array. Upon return same_len returns how many
// switches were found and written to same_sw.
int fpga_switch_same_fromto(struct fpga_model* model, int y, int x,
swidx_t sw, int from_to, swidx_t* same_sw, int *same_len);
// fpga_switch_lookup() returns NO_SWITCH if switch not found.
swidx_t fpga_switch_lookup(struct fpga_model* model, int y, int x,
str16_t from_str_i, str16_t to_str_i);
const char* fpga_switch_str(struct fpga_model* model, int y, int x,
swidx_t swidx, int from_to);
str16_t fpga_switch_str_i(struct fpga_model* model, int y, int x,
swidx_t swidx, int from_to);
const char* fpga_switch_print(struct fpga_model* model, int y, int x,
swidx_t swidx);
int fpga_switch_is_bidir(struct fpga_model* model, int y, int x,
swidx_t swidx);
int fpga_switch_is_used(struct fpga_model* model, int y, int x,
swidx_t swidx);
void fpga_switch_enable(struct fpga_model* model, int y, int x,
swidx_t swidx);
int fpga_switch_set_enable(struct fpga_model* model, int y, int x,
struct sw_set* set);
void fpga_switch_disable(struct fpga_model* model, int y, int x,
swidx_t swidx);
const char* fmt_swset(struct fpga_model* model, int y, int x,
struct sw_set* set, int from_to);
// MAX_SWITCHBOX_SIZE can be used to allocate the block
// list and should be larger than the largest known number
// of switches in a tile, currently 3459 in a slx9 routing tile.
#define MAX_SWITCHBOX_SIZE 4000
struct sw_chain
{
// start and recurring values:
struct fpga_model* model;
int y;
int x;
int from_to;
int max_depth;
// exclusive_net will skip switches that are in use by any
// net other than exclusive_net.
// Set to NO_NET to accept any switch.
net_idx_t exclusive_net;
//
// block_list works as if all switches from or to the ones
// on the block list are blocked, that is the recursion will
// never step into a part of the tree that goes through a
// blocked from or to point.
// Every call to fpga_switch_chain(), even the last one that
// returns NO_SWITCH, may add switches to the block list.
//
swidx_t* block_list;
int block_list_len;
// return value: set is carried forward through the
// enumeration and must only be read from.
struct sw_set set;
// internal:
int first_round;
swidx_t* internal_block_list;
};
int construct_sw_chain(struct sw_chain* chain, struct fpga_model* model,
int y, int x, str16_t start_switch, int from_to, int max_depth,
net_idx_t exclusive_net, swidx_t* block_list, int block_list_len);
void destruct_sw_chain(struct sw_chain* chain);
// Returns 0 if another switchset is returned in chain, or
// NO_SWITCH (-1) if there is no other switchset.
// set.len is 0 when there are no more switches in the tree
int fpga_switch_chain(struct sw_chain* chain);
int fpga_multi_switch_lookup(struct fpga_model *model, int y, int x,
str16_t from_sw, str16_t to_sw, int max_depth, net_idx_t exclusive_net,
struct sw_set *sw_set);
struct sw_conns
{
struct sw_chain chain;
int connpt_dest_start;
int num_dests;
int dest_i;
int dest_y;
int dest_x;
str16_t dest_str_i;
};
int construct_sw_conns(struct sw_conns* conns, struct fpga_model* model,
int y, int x, str16_t start_switch, int from_to, int max_depth,
net_idx_t exclusive_net);
void destruct_sw_conns(struct sw_conns* conns);
// Returns 0 if another connection is returned in conns, or
// NO_CONN (-1) if there is no other connection.
int fpga_switch_conns(struct sw_conns* conns);
int fpga_first_conn(struct fpga_model *model, int sw_y, int sw_x, str16_t sw_str,
int from_to, int max_depth, net_idx_t exclusive_net,
struct sw_set *sw_set, int *dest_y, int *dest_x, str16_t *dest_connpt);
// max_depth can be -1 for internal maximum (SW_SET_SIZE)
void printf_swchain(struct fpga_model* model, int y, int x,
str16_t sw, int from_to, int max_depth, swidx_t* block_list,
int* block_list_len);
void printf_swconns(struct fpga_model* model, int y, int x,
str16_t sw, int from_to, int max_depth);
#define SWTO_YX_DEF 0
// SWTO_YX_CLOSEST finds the closest tile that satisfies
// the YX requirement.
#define SWTO_YX_CLOSEST 0x0001
struct switch_to_yx
{
// input:
int yx_req; // YX_-value
int flags; // SWTO_YX-value
struct fpga_model* model;
int y;
int x;
str16_t start_switch;
int from_to;
net_idx_t exclusive_net; // can be NO_NET
// output:
struct sw_set set;
int dest_y;
int dest_x;
str16_t dest_connpt;
};
int fpga_switch_to_yx(struct switch_to_yx *p);
void printf_switch_to_yx_result(struct switch_to_yx *p);
struct switch_to_yx_l2
{
struct switch_to_yx l1;
// l2 y/x/set is inserted between l1.y/x/start_switch
// and l1.dest_y/dest_x/dest_connpt
struct sw_set l2_set;
int l2_y, l2_x;
};
// fpga_switch_to_yx_l2() allows for an optional intermediate tile
// to come before the yx_req. If a direct link was found, l2_set.len
// will be 0 and l2_y and l2_x are undefined.
int fpga_switch_to_yx_l2(struct switch_to_yx_l2 *p);
#define SWTO_REL_DEFAULT 0
// If a connection to the actual target is not found,
// WEAK_TARGET will allow to return the connection that
// reaches as close as possible to the x/y target.
#define SWTO_REL_WEAK_TARGET 0x0001
struct switch_to_rel
{
// input:
struct fpga_model* model;
int start_y;
int start_x;
str16_t start_switch;
int from_to;
int flags; // SWTO_REL-value
int rel_y;
int rel_x;
str16_t target_connpt; // can be STRIDX_NO_ENTRY
// output:
struct sw_set set;
int dest_y;
int dest_x;
str16_t dest_connpt;
};
// if no switches are found, the returned set.len will be 0.
int fpga_switch_to_rel(struct switch_to_rel* p);
void printf_switch_to_rel_result(struct switch_to_rel* p);
//
// nets
//
// The last m1 soc has about 20k nets with about 470k
// connection points. The largest net has about 110
// connection points. For now we work with a simple
// fixed-size array, we can later make this more dynamic
// depending on which load on the memory manager is better.
#define MAX_NET_LEN 128
#define NET_IDX_IS_PINW 0x8000
#define NET_IDX_MASK 0x7FFF
struct net_el
{
uint16_t y;
uint16_t x;
// idx is either an index into tile->switches[]
// if bit15 (NET_IDX_IS_PINW) is off, or an index
// into dev->pinw[] if bit15 is on.
uint16_t idx;
uint16_t dev_idx; // only used if idx&NET_IDX_IS_PINW
};
struct fpga_net
{
int len;
struct net_el el[MAX_NET_LEN];
};
int fnet_new(struct fpga_model* model, net_idx_t* new_idx);
void fnet_delete(struct fpga_model* model, net_idx_t net_idx);
// start a new enumeration by calling with last==NO_NET
int fnet_enum(struct fpga_model* model, net_idx_t last, net_idx_t* next);
struct fpga_net* fnet_get(struct fpga_model* model, net_idx_t net_i);
void fnet_free_all(struct fpga_model* model);
int fpga_swset_in_other_net(struct fpga_model *model, int y, int x,
const swidx_t* sw, int len, net_idx_t our_net);
int fnet_add_port(struct fpga_model* model, net_idx_t net_i,
int y, int x, enum fpgadev_type type, dev_type_idx_t type_idx,
pinw_idx_t pinw_idx);
int fnet_add_sw(struct fpga_model* model, net_idx_t net_i,
int y, int x, const swidx_t* switches, int num_sw);
int fnet_remove_sw(struct fpga_model* model, net_idx_t net_i,
int y, int x, const swidx_t* switches, int num_sw);
int fnet_remove_all_sw(struct fpga_model* model, net_idx_t net_i);
void fnet_printf(FILE* f, struct fpga_model* model, net_idx_t net_i);
int fnet_route(struct fpga_model* model, net_idx_t net_i);
// is_vcc == 1 for a vcc net, is_vcc == 0 for a gnd net
int fnet_vcc_gnd(struct fpga_model* model, net_idx_t net_i, int is_vcc);
fpgatools-201212/libs/floorplan.c 0000664 0000000 0000000 00000112726 12065743015 0016706 0 ustar 00root root 0000000 0000000 //
// Author: Wolfgang Spraul
//
// This is free and unencumbered software released into the public domain.
// For details see the UNLICENSE file at the root of the source tree.
//
#include
#include "model.h"
#include "control.h"
#include "floorplan.h"
void printf_version(FILE* f)
{
fprintf(f, "fpga_floorplan_format 1\n");
}
#define PRINT_FLAG(fp, flag) if ((tf) & (flag)) \
{ fprintf (fp, " %s", #flag); tf &= ~(flag); }
int printf_tiles(FILE* f, struct fpga_model* model)
{
struct fpga_tile* tile;
int x, y;
RC_CHECK(model);
for (x = 0; x < model->x_width; x++) {
fprintf(f, "\n");
for (y = 0; y < model->y_height; y++) {
tile = &model->tiles[y*model->x_width + x];
if (tile->type != NA)
fprintf(f, "tile y%i x%i name %s\n", y, x,
fpga_tiletype_str(tile->type));
if (tile->flags) {
int tf = tile->flags;
fprintf(f, "tile y%i x%i flags", y, x);
PRINT_FLAG(f, TF_FABRIC_ROUTING_COL);
PRINT_FLAG(f, TF_FABRIC_LOGIC_XM_COL);
PRINT_FLAG(f, TF_FABRIC_LOGIC_XL_COL);
PRINT_FLAG(f, TF_FABRIC_BRAM_VIA_COL);
PRINT_FLAG(f, TF_FABRIC_MACC_VIA_COL);
PRINT_FLAG(f, TF_FABRIC_BRAM_COL);
PRINT_FLAG(f, TF_FABRIC_MACC_COL);
PRINT_FLAG(f, TF_ROUTING_NO_IO);
PRINT_FLAG(f, TF_BRAM_DEV);
PRINT_FLAG(f, TF_MACC_DEV);
PRINT_FLAG(f, TF_LOGIC_XL_DEV);
PRINT_FLAG(f, TF_LOGIC_XM_DEV);
PRINT_FLAG(f, TF_IOLOGIC_DELAY_DEV);
PRINT_FLAG(f, TF_DCM_DEV);
PRINT_FLAG(f, TF_PLL_DEV);
PRINT_FLAG(f, TF_WIRED);
if (tf) fprintf(f, " 0x%x", tf);
fprintf(f, "\n");
}
}
}
return 0;
}
static int printf_IOB(FILE* f, struct fpga_model* model,
int y, int x, int config_only)
{
struct fpga_tile* tile;
char pref[256];
int type_count, i;
RC_CHECK(model);
tile = YX_TILE(model, y, x);
type_count = 0;
for (i = 0; i < tile->num_devs; i++) {
if (tile->devs[i].type != DEV_IOB)
continue;
if (config_only && !(tile->devs[i].instantiated)) {
type_count++;
continue;
}
snprintf(pref, sizeof(pref), "dev y%i x%i IOB %i",
y, x, type_count);
type_count++;
if (!config_only) {
fprintf(f, "%s type %s\n", pref,
tile->devs[i].subtype == IOBM ? "M" : "S");
}
if (tile->devs[i].u.iob.istandard[0])
fprintf(f, "%s istd %s\n", pref,
tile->devs[i].u.iob.istandard);
if (tile->devs[i].u.iob.ostandard[0])
fprintf(f, "%s ostd %s\n", pref,
tile->devs[i].u.iob.ostandard);
switch (tile->devs[i].u.iob.bypass_mux) {
case BYPASS_MUX_I:
fprintf(f, "%s bypass_mux I\n", pref);
break;
case BYPASS_MUX_O:
fprintf(f, "%s bypass_mux O\n", pref);
break;
case BYPASS_MUX_T:
fprintf(f, "%s bypass_mux T\n", pref);
break;
case 0: break; default: EXIT(1);
}
switch (tile->devs[i].u.iob.I_mux) {
case IMUX_I_B:
fprintf(f, "%s imux I_B\n", pref);
break;
case IMUX_I:
fprintf(f, "%s imux I\n", pref);
break;
case 0: break; default: EXIT(1);
}
if (tile->devs[i].u.iob.drive_strength)
fprintf(f, "%s strength %i\n", pref,
tile->devs[i].u.iob.drive_strength);
switch (tile->devs[i].u.iob.slew) {
case SLEW_SLOW:
fprintf(f, "%s slew SLOW\n", pref);
break;
case SLEW_FAST:
fprintf(f, "%s slew FAST\n", pref);
break;
case SLEW_QUIETIO:
fprintf(f, "%s slew QUIETIO\n", pref);
break;
case 0: break; default: EXIT(1);
}
if (tile->devs[i].u.iob.O_used)
fprintf(f, "%s O_used\n", pref);
switch (tile->devs[i].u.iob.suspend) {
case SUSP_LAST_VAL:
fprintf(f, "%s suspend DRIVE_LAST_VALUE\n", pref);
break;
case SUSP_3STATE:
fprintf(f, "%s suspend 3STATE\n", pref);
break;
case SUSP_3STATE_PULLUP:
fprintf(f, "%s suspend 3STATE_PULLUP\n", pref);
break;
case SUSP_3STATE_PULLDOWN:
fprintf(f, "%s suspend 3STATE_PULLDOWN\n", pref);
break;
case SUSP_3STATE_KEEPER:
fprintf(f, "%s suspend 3STATE_KEEPER\n", pref);
break;
case SUSP_3STATE_OCT_ON:
fprintf(f, "%s suspend 3STATE_OCT_ON\n", pref);
break;
case 0: break; default: EXIT(1);
}
switch (tile->devs[i].u.iob.in_term) {
case ITERM_NONE:
fprintf(f, "%s in_term NONE\n", pref);
break;
case ITERM_UNTUNED_25:
fprintf(f, "%s in_term UNTUNED_SPLIT_25\n", pref);
break;
case ITERM_UNTUNED_50:
fprintf(f, "%s in_term UNTUNED_SPLIT_50\n", pref);
break;
case ITERM_UNTUNED_75:
fprintf(f, "%s in_term UNTUNED_SPLIT_75\n", pref);
break;
case 0: break; default: EXIT(1);
}
switch (tile->devs[i].u.iob.out_term) {
case OTERM_NONE:
fprintf(f, "%s out_term NONE\n", pref);
break;
case OTERM_UNTUNED_25:
fprintf(f, "%s out_term UNTUNED_25\n", pref);
break;
case OTERM_UNTUNED_50:
fprintf(f, "%s out_term UNTUNED_50\n", pref);
break;
case OTERM_UNTUNED_75:
fprintf(f, "%s out_term UNTUNED_75\n", pref);
break;
case 0: break; default: EXIT(1);
}
}
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->u.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->u.iob.istandard, w2, w2_len);
dev->u.iob.istandard[w2_len] = 0;
goto inst_2;
}
if (!str_cmp(w1, w1_len, "ostd", ZTERM)) {
memcpy(dev->u.iob.ostandard, w2, w2_len);
dev->u.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->u.iob.bypass_mux = BYPASS_MUX_I;
else if (!str_cmp(w2, w2_len, "O", ZTERM))
dev->u.iob.bypass_mux = BYPASS_MUX_O;
else if (!str_cmp(w2, w2_len, "T", ZTERM))
dev->u.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->u.iob.I_mux = IMUX_I_B;
else if (!str_cmp(w2, w2_len, "I", ZTERM))
dev->u.iob.I_mux = IMUX_I;
else return 0;
goto inst_2;
}
if (!str_cmp(w1, w1_len, "strength", ZTERM)) {
dev->u.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->u.iob.slew = SLEW_SLOW;
else if (!str_cmp(w2, w2_len, "FAST", ZTERM))
dev->u.iob.slew = SLEW_FAST;
else if (!str_cmp(w2, w2_len, "QUIETIO", ZTERM))
dev->u.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->u.iob.suspend = SUSP_LAST_VAL;
else if (!str_cmp(w2, w2_len, "3STATE", ZTERM))
dev->u.iob.suspend = SUSP_3STATE;
else if (!str_cmp(w2, w2_len, "3STATE_PULLUP", ZTERM))
dev->u.iob.suspend = SUSP_3STATE_PULLUP;
else if (!str_cmp(w2, w2_len, "3STATE_PULLDOWN", ZTERM))
dev->u.iob.suspend = SUSP_3STATE_PULLDOWN;
else if (!str_cmp(w2, w2_len, "3STATE_KEEPER", ZTERM))
dev->u.iob.suspend = SUSP_3STATE_KEEPER;
else if (!str_cmp(w2, w2_len, "3STATE_OCT_ON", ZTERM))
dev->u.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->u.iob.in_term = ITERM_NONE;
else if (!str_cmp(w2, w2_len, "UNTUNED_SPLIT_25", ZTERM))
dev->u.iob.in_term = ITERM_UNTUNED_25;
else if (!str_cmp(w2, w2_len, "UNTUNED_SPLIT_50", ZTERM))
dev->u.iob.in_term = ITERM_UNTUNED_50;
else if (!str_cmp(w2, w2_len, "UNTUNED_SPLIT_75", ZTERM))
dev->u.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->u.iob.out_term = OTERM_NONE;
else if (!str_cmp(w2, w2_len, "UNTUNED_25", ZTERM))
dev->u.iob.out_term = OTERM_UNTUNED_25;
else if (!str_cmp(w2, w2_len, "UNTUNED_50", ZTERM))
dev->u.iob.out_term = OTERM_UNTUNED_50;
else if (!str_cmp(w2, w2_len, "UNTUNED_75", ZTERM))
dev->u.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 = 1;
return 2;
}
static int printf_LOGIC(FILE* f, struct fpga_model* model,
int y, int x, int config_only)
{
struct fpga_tile* tile;
struct fpgadev_logic* cfg;
char pref[256];
int type_count, i, j, rc;
RC_CHECK(model);
tile = YX_TILE(model, y, x);
type_count = 0;
for (i = 0; i < tile->num_devs; i++) {
if (tile->devs[i].type != DEV_LOGIC)
continue;
if (config_only && !(tile->devs[i].instantiated)) {
type_count++;
continue;
}
snprintf(pref, sizeof(pref), "dev y%i x%i LOGIC %i",
y, x, type_count);
type_count++;
if (!config_only) {
switch (tile->devs[i].subtype) {
case LOGIC_X:
fprintf(f, "%s type X\n", pref);
break;
case LOGIC_L:
fprintf(f, "%s type L\n", pref);
break;
case LOGIC_M:
fprintf(f, "%s type M\n", pref);
break;
default: EXIT(1);
}
}
cfg = &tile->devs[i].u.logic;
for (j = LUT_D; j >= LUT_A; j--) {
if (cfg->a2d[j].lut6 && cfg->a2d[j].lut6[0])
fprintf(f, "%s %c6_lut %s\n", pref, 'A'+j,
cfg->a2d[j].lut6);
if (cfg->a2d[j].lut5 && cfg->a2d[j].lut5[0])
fprintf(f, "%s %c5_lut %s\n", pref, 'A'+j,
cfg->a2d[j].lut5);
if (cfg->a2d[j].out_used)
fprintf(f, "%s %c_used\n", pref, 'A'+j);
switch (cfg->a2d[j].ff) {
case FF_OR2L:
fprintf(f, "%s %c_ff OR2L\n", pref, 'A'+j);
break;
case FF_AND2L:
fprintf(f, "%s %c_ff AND2L\n", pref, 'A'+j);
break;
case FF_LATCH:
fprintf(f, "%s %c_ff LATCH\n", pref, 'A'+j);
break;
case FF_FF:
fprintf(f, "%s %c_ff FF\n", pref, 'A'+j);
break;
case 0: break; default: FAIL(EINVAL);
}
switch (cfg->a2d[j].ff_mux) {
case MUX_O6:
fprintf(f, "%s %c_ffmux O6\n", pref, 'A'+j);
break;
case MUX_O5:
fprintf(f, "%s %c_ffmux O5\n", pref, 'A'+j);
break;
case MUX_X:
fprintf(f, "%s %c_ffmux X\n", pref, 'A'+j);
break;
case MUX_CY:
fprintf(f, "%s %c_ffmux CY\n", pref, 'A'+j);
break;
case MUX_XOR:
fprintf(f, "%s %c_ffmux XOR\n", pref, 'A'+j);
break;
case MUX_F7:
fprintf(f, "%s %c_ffmux F7\n", pref, 'A'+j);
break;
case MUX_F8:
fprintf(f, "%s %c_ffmux F8\n", pref, 'A'+j);
break;
case MUX_MC31:
fprintf(f, "%s %c_ffmux MC31\n", pref, 'A'+j);
break;
case 0: break; default: FAIL(EINVAL);
}
switch (cfg->a2d[j].ff_srinit) {
case FF_SRINIT0:
fprintf(f, "%s %c_ffsrinit 0\n", pref, 'A'+j);
break;
case FF_SRINIT1:
fprintf(f, "%s %c_ffsrinit 1\n", pref, 'A'+j);
break;
case 0: break; default: FAIL(EINVAL);
}
switch (cfg->a2d[j].out_mux) {
case MUX_O6:
fprintf(f, "%s %c_outmux O6\n", pref, 'A'+j);
break;
case MUX_O5:
fprintf(f, "%s %c_outmux O5\n", pref, 'A'+j);
break;
case MUX_5Q:
fprintf(f, "%s %c_outmux 5Q\n", pref, 'A'+j);
break;
case MUX_CY:
fprintf(f, "%s %c_outmux CY\n", pref, 'A'+j);
break;
case MUX_XOR:
fprintf(f, "%s %c_outmux XOR\n", pref, 'A'+j);
break;
case MUX_F7:
fprintf(f, "%s %c_outmux F7\n", pref, 'A'+j);
break;
case MUX_F8:
fprintf(f, "%s %c_outmux F8\n", pref, 'A'+j);
break;
case MUX_MC31:
fprintf(f, "%s %c_outmux MC31\n", pref, 'A'+j);
break;
case 0: break; default: FAIL(EINVAL);
}
switch (cfg->a2d[j].ff5_srinit) {
case FF_SRINIT0:
fprintf(f, "%s %c5_ffsrinit 0\n", pref, 'A'+j);
break;
case FF_SRINIT1:
fprintf(f, "%s %c5_ffsrinit 1\n", pref, 'A'+j);
break;
case 0: break; default: FAIL(EINVAL);
}
switch (cfg->a2d[j].cy0) {
case CY0_X:
fprintf(f, "%s %c_cy0 X\n", pref, 'A'+j);
break;
case CY0_O5:
fprintf(f, "%s %c_cy0 O5\n", pref, 'A'+j);
break;
case 0: break; default: FAIL(EINVAL);
}
}
switch (cfg->clk_inv) {
case CLKINV_B:
fprintf(f, "%s clk CLK_B\n", pref);
break;
case CLKINV_CLK:
fprintf(f, "%s clk CLK\n", pref);
break;
case 0: break; default: FAIL(EINVAL);
}
switch (cfg->sync_attr) {
case SYNCATTR_SYNC:
fprintf(f, "%s sync SYNC\n", pref);
break;
case SYNCATTR_ASYNC:
fprintf(f, "%s sync ASYNC\n", pref);
break;
case 0: break; default: FAIL(EINVAL);
}
if (cfg->ce_used)
fprintf(f, "%s ce_used\n", pref);
if (cfg->sr_used)
fprintf(f, "%s sr_used\n", pref);
switch (cfg->we_mux) {
case WEMUX_WE:
fprintf(f, "%s wemux WE\n", pref);
break;
case WEMUX_CE:
fprintf(f, "%s wemux CE\n", pref);
break;
case 0: break; default: FAIL(EINVAL);
}
if (cfg->cout_used)
fprintf(f, "%s cout_used\n", pref);
switch (cfg->precyinit) {
case PRECYINIT_0:
fprintf(f, "%s precyinit 0\n", pref);
break;
case PRECYINIT_1:
fprintf(f, "%s precyinit 1\n", pref);
break;
case PRECYINIT_AX:
fprintf(f, "%s precyinit AX\n", pref);
break;
case 0: break; default: FAIL(EINVAL);
}
}
return 0;
fail:
return rc;
}
static int read_LOGIC_attr(struct fpga_model* model, int y, int x, int type_idx,
const char* w1, int w1_len, const char* w2, int w2_len)
{
struct fpga_device* dev;
char cmp_str[128];
int i, rc;
dev = fdev_p(model, y, x, DEV_LOGIC, type_idx);
if (!dev) { HERE(); return 0; }
// First the one-word attributes.
for (i = LUT_A; i <= LUT_D; i++) {
snprintf(cmp_str, sizeof(cmp_str), "%c_used", 'A'+i);
if (!str_cmp(w1, w1_len, cmp_str, ZTERM)) {
dev->u.logic.a2d[i].out_used = 1;
goto inst_1;
}
}
if (!str_cmp(w1, w1_len, "ce_used", ZTERM)) {
dev->u.logic.ce_used = 1;
goto inst_1;
}
if (!str_cmp(w1, w1_len, "sr_used", ZTERM)) {
dev->u.logic.sr_used = 1;
goto inst_1;
}
if (!str_cmp(w1, w1_len, "cout_used", ZTERM)) {
dev->u.logic.cout_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
for (i = LUT_A; i <= LUT_D; i++) {
snprintf(cmp_str, sizeof(cmp_str), "%c6_lut", 'A'+i);
if (!str_cmp(w1, w1_len, cmp_str, ZTERM)) {
rc = fdev_logic_a2d_lut(model, y, x, type_idx, i, 6, w2, w2_len);
if (rc) return 0;
goto inst_2;
}
snprintf(cmp_str, sizeof(cmp_str), "%c5_lut", 'A'+i);
if (!str_cmp(w1, w1_len, cmp_str, ZTERM)) {
rc = fdev_logic_a2d_lut(model, y, x, type_idx, i, 5, w2, w2_len);
if (rc) return 0;
goto inst_2;
}
snprintf(cmp_str, sizeof(cmp_str), "%c_ffmux", 'A'+i);
if (!str_cmp(w1, w1_len, cmp_str, ZTERM)) {
if (!str_cmp(w2, w2_len, "O6", ZTERM))
dev->u.logic.a2d[i].ff_mux = MUX_O6;
else if (!str_cmp(w2, w2_len, "O5", ZTERM))
dev->u.logic.a2d[i].ff_mux = MUX_O5;
else if (!str_cmp(w2, w2_len, "X", ZTERM))
dev->u.logic.a2d[i].ff_mux = MUX_X;
else if (!str_cmp(w2, w2_len, "CY", ZTERM))
dev->u.logic.a2d[i].ff_mux = MUX_CY;
else if (!str_cmp(w2, w2_len, "XOR", ZTERM))
dev->u.logic.a2d[i].ff_mux = MUX_XOR;
else if (!str_cmp(w2, w2_len, "F7", ZTERM))
dev->u.logic.a2d[i].ff_mux = MUX_F7;
else if (!str_cmp(w2, w2_len, "F8", ZTERM))
dev->u.logic.a2d[i].ff_mux = MUX_F8;
else if (!str_cmp(w2, w2_len, "MC31", ZTERM))
dev->u.logic.a2d[i].ff_mux = MUX_MC31;
else return 0;
goto inst_2;
}
snprintf(cmp_str, sizeof(cmp_str), "%c_ffsrinit", 'A'+i);
if (!str_cmp(w1, w1_len, cmp_str, ZTERM)) {
if (!str_cmp(w2, w2_len, "0", ZTERM))
dev->u.logic.a2d[i].ff_srinit = FF_SRINIT0;
else if (!str_cmp(w2, w2_len, "1", ZTERM))
dev->u.logic.a2d[i].ff_srinit = FF_SRINIT1;
else return 0;
goto inst_2;
}
snprintf(cmp_str, sizeof(cmp_str), "%c5_ffsrinit", 'A'+i);
if (!str_cmp(w1, w1_len, cmp_str, ZTERM)) {
if (!str_cmp(w2, w2_len, "0", ZTERM))
dev->u.logic.a2d[i].ff5_srinit = FF_SRINIT0;
else if (!str_cmp(w2, w2_len, "1", ZTERM))
dev->u.logic.a2d[i].ff5_srinit = FF_SRINIT1;
else return 0;
goto inst_2;
}
snprintf(cmp_str, sizeof(cmp_str), "%c_outmux", 'A'+i);
if (!str_cmp(w1, w1_len, cmp_str, ZTERM)) {
if (!str_cmp(w2, w2_len, "O6", ZTERM))
dev->u.logic.a2d[i].out_mux = MUX_O6;
else if (!str_cmp(w2, w2_len, "O5", ZTERM))
dev->u.logic.a2d[i].out_mux = MUX_O5;
else if (!str_cmp(w2, w2_len, "5Q", ZTERM))
dev->u.logic.a2d[i].out_mux = MUX_5Q;
else if (!str_cmp(w2, w2_len, "CY", ZTERM))
dev->u.logic.a2d[i].out_mux = MUX_CY;
else if (!str_cmp(w2, w2_len, "XOR", ZTERM))
dev->u.logic.a2d[i].out_mux = MUX_XOR;
else if (!str_cmp(w2, w2_len, "F7", ZTERM))
dev->u.logic.a2d[i].out_mux = MUX_F7;
else if (!str_cmp(w2, w2_len, "F8", ZTERM))
dev->u.logic.a2d[i].out_mux = MUX_F8;
else if (!str_cmp(w2, w2_len, "MC31", ZTERM))
dev->u.logic.a2d[i].out_mux = MUX_MC31;
else return 0;
goto inst_2;
}
snprintf(cmp_str, sizeof(cmp_str), "%c_ff", 'A'+i);
if (!str_cmp(w1, w1_len, cmp_str, ZTERM)) {
if (!str_cmp(w2, w2_len, "OR2L", ZTERM))
dev->u.logic.a2d[i].ff = FF_OR2L;
else if (!str_cmp(w2, w2_len, "AND2L", ZTERM))
dev->u.logic.a2d[i].ff = FF_AND2L;
else if (!str_cmp(w2, w2_len, "LATCH", ZTERM))
dev->u.logic.a2d[i].ff = FF_LATCH;
else if (!str_cmp(w2, w2_len, "FF", ZTERM))
dev->u.logic.a2d[i].ff = FF_FF;
else return 0;
goto inst_2;
}
snprintf(cmp_str, sizeof(cmp_str), "%c_cy0", 'A'+i);
if (!str_cmp(w1, w1_len, cmp_str, ZTERM)) {
if (!str_cmp(w2, w2_len, "X", ZTERM))
dev->u.logic.a2d[i].cy0 = CY0_X;
else if (!str_cmp(w2, w2_len, "O5", ZTERM))
dev->u.logic.a2d[i].cy0 = CY0_O5;
else return 0;
goto inst_2;
}
}
if (!str_cmp(w1, w1_len, "clk", ZTERM)) {
if (!str_cmp(w2, w2_len, "CLK_B", ZTERM))
dev->u.logic.clk_inv = CLKINV_B;
else if (!str_cmp(w2, w2_len, "CLK", ZTERM))
dev->u.logic.clk_inv = CLKINV_CLK;
else return 0;
goto inst_2;
}
if (!str_cmp(w1, w1_len, "sync", ZTERM)) {
if (!str_cmp(w2, w2_len, "SYNC", ZTERM))
dev->u.logic.sync_attr = SYNCATTR_SYNC;
else if (!str_cmp(w2, w2_len, "ASYNC", ZTERM))
dev->u.logic.sync_attr = SYNCATTR_ASYNC;
else return 0;
goto inst_2;
}
if (!str_cmp(w1, w1_len, "wemux", ZTERM)) {
if (!str_cmp(w2, w2_len, "WE", ZTERM))
dev->u.logic.we_mux = WEMUX_WE;
else if (!str_cmp(w2, w2_len, "CE", ZTERM))
dev->u.logic.we_mux = WEMUX_CE;
else return 0;
goto inst_2;
}
if (!str_cmp(w1, w1_len, "precyinit", ZTERM)) {
if (!str_cmp(w2, w2_len, "0", ZTERM))
dev->u.logic.precyinit = PRECYINIT_0;
else if (!str_cmp(w2, w2_len, "1", ZTERM))
dev->u.logic.precyinit = PRECYINIT_1;
else if (!str_cmp(w2, w2_len, "AX", ZTERM))
dev->u.logic.precyinit = PRECYINIT_AX;
else return 0;
goto inst_2;
}
return 0;
inst_1:
dev->instantiated = 1;
return 1;
inst_2:
dev->instantiated = 1;
return 2;
}
static int printf_BUFGMUX(FILE* f, struct fpga_model* model,
int y, int x, int config_only)
{
struct fpga_tile *tile;
struct fpgadev_bufgmux *cfg;
char pref[256];
int type_count, i, rc;
RC_CHECK(model);
tile = YX_TILE(model, y, x);
type_count = 0;
for (i = 0; i < tile->num_devs; i++) {
if (tile->devs[i].type != DEV_BUFGMUX)
continue;
if (config_only && !(tile->devs[i].instantiated)) {
type_count++;
continue;
}
snprintf(pref, sizeof(pref), "dev y%i x%i BUFGMUX %i",
y, x, type_count++);
if (!config_only)
fprintf(f, "%s\n", pref);
cfg = &tile->devs[i].u.bufgmux;
switch (cfg->clk) {
case BUFG_CLK_ASYNC:
fprintf(f, "%s clk ASYNC\n", pref);
break;
case BUFG_CLK_SYNC:
fprintf(f, "%s clk SYNC\n", pref);
break;
case 0: break; default: FAIL(EINVAL);
}
switch (cfg->disable_attr) {
case BUFG_DISATTR_LOW:
fprintf(f, "%s disable_attr LOW\n", pref);
break;
case BUFG_DISATTR_HIGH:
fprintf(f, "%s disable_attr HIGH\n", pref);
break;
case 0: break; default: FAIL(EINVAL);
}
switch (cfg->s_inv) {
case BUFG_SINV_N:
fprintf(f, "%s s_inv NO\n", pref);
break;
case BUFG_SINV_Y:
fprintf(f, "%s s_inv YES\n", pref);
break;
case 0: break; default: FAIL(EINVAL);
}
}
return 0;
fail:
return rc;
}
static int read_BUFGMUX_attr(struct fpga_model *model, struct fpga_device *dev,
const char *w1, int w1_len, const char *w2, int w2_len)
{
// BUFGMUX only has 2-word attributes
if (w2_len < 1) return 0;
if (!str_cmp(w1, w1_len, "clk", ZTERM)) {
if (!str_cmp(w2, w2_len, "ASYNC", ZTERM))
dev->u.bufgmux.clk = BUFG_CLK_ASYNC;
else if (!str_cmp(w2, w2_len, "SYNC", ZTERM))
dev->u.bufgmux.clk = BUFG_CLK_SYNC;
else return 0;
goto inst;
}
if (!str_cmp(w1, w1_len, "disable_attr", ZTERM)) {
if (!str_cmp(w2, w2_len, "LOW", ZTERM))
dev->u.bufgmux.disable_attr = BUFG_DISATTR_LOW;
else if (!str_cmp(w2, w2_len, "HIGH", ZTERM))
dev->u.bufgmux.disable_attr = BUFG_DISATTR_HIGH;
else return 0;
goto inst;
}
if (!str_cmp(w1, w1_len, "s_inv", ZTERM)) {
if (!str_cmp(w2, w2_len, "NO", ZTERM))
dev->u.bufgmux.s_inv = BUFG_SINV_N;
else if (!str_cmp(w2, w2_len, "YES", ZTERM))
dev->u.bufgmux.s_inv = BUFG_SINV_Y;
else return 0;
goto inst;
}
return 0;
inst:
dev->instantiated = 1;
return 2;
}
static int printf_BUFIO(FILE* f, struct fpga_model* model,
int y, int x, int config_only)
{
struct fpga_tile *tile;
struct fpgadev_bufio *cfg;
char pref[256];
int type_count, i, rc;
RC_CHECK(model);
tile = YX_TILE(model, y, x);
type_count = 0;
for (i = 0; i < tile->num_devs; i++) {
if (tile->devs[i].type != DEV_BUFIO)
continue;
if (config_only && !(tile->devs[i].instantiated)) {
type_count++;
continue;
}
snprintf(pref, sizeof(pref), "dev y%i x%i BUFIO %i",
y, x, type_count++);
if (!config_only)
fprintf(f, "%s\n", pref);
cfg = &tile->devs[i].u.bufio;
if (cfg->divide)
fprintf(f, "%s divide %i\n", pref, cfg->divide);
switch (cfg->divide_bypass) {
case BUFIO_DIVIDEBP_N:
fprintf(f, "%s divide_bypass NO\n", pref);
break;
case BUFIO_DIVIDEBP_Y:
fprintf(f, "%s divide_bypass YES\n", pref);
break;
case 0: break; default: FAIL(EINVAL);
}
switch (cfg->i_inv) {
case BUFIO_IINV_N:
fprintf(f, "%s i_inv NO\n", pref);
break;
case BUFIO_IINV_Y:
fprintf(f, "%s i_inv YES\n", pref);
break;
case 0: break; default: FAIL(EINVAL);
}
}
return 0;
fail:
return rc;
}
static int read_BUFIO_attr(struct fpga_model *model, struct fpga_device *dev,
const char *w1, int w1_len, const char *w2, int w2_len)
{
// BUFIO only has 2-word attributes
if (w2_len < 1) return 0;
if (!str_cmp(w1, w1_len, "divide", ZTERM)) {
dev->u.bufio.divide = to_i(w2, w2_len);
goto inst;
}
if (!str_cmp(w1, w1_len, "divide_bypass", ZTERM)) {
if (!str_cmp(w2, w2_len, "NO", ZTERM))
dev->u.bufio.divide_bypass = BUFIO_DIVIDEBP_N;
else if (!str_cmp(w2, w2_len, "YES", ZTERM))
dev->u.bufio.divide_bypass = BUFIO_DIVIDEBP_Y;
else return 0;
goto inst;
}
if (!str_cmp(w1, w1_len, "i_inv", ZTERM)) {
if (!str_cmp(w2, w2_len, "NO", ZTERM))
dev->u.bufio.i_inv = BUFIO_IINV_N;
else if (!str_cmp(w2, w2_len, "YES", ZTERM))
dev->u.bufio.i_inv = BUFIO_IINV_Y;
else return 0;
goto inst;
}
return 0;
inst:
dev->instantiated = 1;
return 2;
}
static int printf_BSCAN(FILE* f, struct fpga_model* model,
int y, int x, int config_only)
{
struct fpga_tile *tile;
struct fpgadev_bscan *cfg;
char pref[256];
int type_count, i, rc;
RC_CHECK(model);
tile = YX_TILE(model, y, x);
type_count = 0;
for (i = 0; i < tile->num_devs; i++) {
if (tile->devs[i].type != DEV_BSCAN)
continue;
if (config_only && !(tile->devs[i].instantiated)) {
type_count++;
continue;
}
snprintf(pref, sizeof(pref), "dev y%i x%i BSCAN %i",
y, x, type_count++);
if (!config_only)
fprintf(f, "%s\n", pref);
cfg = &tile->devs[i].u.bscan;
if (cfg->jtag_chain)
fprintf(f, "%s jtag_chain %i\n", pref, cfg->jtag_chain);
switch (cfg->jtag_test) {
case BSCAN_JTAG_TEST_N:
fprintf(f, "%s jtag_test NO\n", pref);
break;
case BSCAN_JTAG_TEST_Y:
fprintf(f, "%s jtag_test YES\n", pref);
break;
case 0: break; default: FAIL(EINVAL);
}
}
return 0;
fail:
return rc;
}
static int read_BSCAN_attr(struct fpga_model *model, struct fpga_device *dev,
const char *w1, int w1_len, const char *w2, int w2_len)
{
// BSCAN only has 2-word attributes
if (w2_len < 1) return 0;
if (!str_cmp(w1, w1_len, "jtag_chain", ZTERM)) {
dev->u.bscan.jtag_chain = to_i(w2, w2_len);
goto inst;
}
if (!str_cmp(w1, w1_len, "jtag_test", ZTERM)) {
if (!str_cmp(w2, w2_len, "NO", ZTERM))
dev->u.bscan.jtag_test = BSCAN_JTAG_TEST_N;
else if (!str_cmp(w2, w2_len, "YES", ZTERM))
dev->u.bscan.jtag_test = BSCAN_JTAG_TEST_Y;
else return 0;
goto inst;
}
return 0;
inst:
dev->instantiated = 1;
return 2;
}
int printf_devices(FILE* f, struct fpga_model* model, int config_only)
{
int x, y, i, rc;
struct fpga_tile* tile;
RC_CHECK(model);
for (x = 0; x < model->x_width; x++) {
for (y = 0; y < model->y_height; y++) {
rc = printf_IOB(f, model, y, x, config_only);
if (rc) goto fail;
}
}
for (x = 0; x < model->x_width; x++) {
for (y = 0; y < model->y_height; y++) {
rc = printf_LOGIC(f, model, y, x, config_only);
if (rc) goto fail;
}
}
for (x = 0; x < model->x_width; x++) {
for (y = 0; y < model->y_height; y++) {
rc = printf_BUFGMUX(f, model, y, x, config_only);
if (rc) goto fail;
}
}
for (x = 0; x < model->x_width; x++) {
for (y = 0; y < model->y_height; y++) {
rc = printf_BUFIO(f, model, y, x, config_only);
if (rc) goto fail;
}
}
for (x = 0; x < model->x_width; x++) {
for (y = 0; y < model->y_height; y++) {
rc = printf_BSCAN(f, model, y, x, config_only);
if (rc) goto fail;
}
}
for (x = 0; x < model->x_width; x++) {
for (y = 0; y < model->y_height; y++) {
tile = YX_TILE(model, y, x);
for (i = 0; i < tile->num_devs; i++) {
if (config_only && !(tile->devs[i].instantiated))
continue;
if (tile->devs[i].type == DEV_LOGIC
|| tile->devs[i].type == DEV_IOB
|| tile->devs[i].type == DEV_BUFGMUX
|| tile->devs[i].type == DEV_BUFIO
|| tile->devs[i].type == DEV_BSCAN)
continue; // handled earlier
fprintf(f, "dev y%i x%i %s\n", y, x,
fdev_type2str(tile->devs[i].type));
}
}
}
return 0;
fail:
return rc;
}
int printf_ports(FILE* f, struct fpga_model* model)
{
struct fpga_tile* tile;
const char* conn_point_name_src;
int x, y, i, conn_point_dests_o, num_dests_for_this_conn_point;
int first_port_printed;
RC_CHECK(model);
for (x = 0; x < model->x_width; x++) {
for (y = 0; y < model->y_height; y++) {
tile = &model->tiles[y*model->x_width + x];
first_port_printed = 0;
for (i = 0; i < tile->num_conn_point_names; i++) {
conn_point_dests_o = tile->conn_point_names[i*2];
if (i < tile->num_conn_point_names-1)
num_dests_for_this_conn_point = tile->conn_point_names[(i+1)*2] - conn_point_dests_o;
else
num_dests_for_this_conn_point = tile->num_conn_point_dests - conn_point_dests_o;
if (num_dests_for_this_conn_point)
// ports is only for connection-less endpoints
continue;
conn_point_name_src = strarray_lookup(&model->str, tile->conn_point_names[i*2+1]);
if (!conn_point_name_src) {
fprintf(stderr, "Cannot lookup src conn point name index %i, x%i y%i i%i\n",
tile->conn_point_names[i*2+1], x, y, i);
continue;
}
if (!first_port_printed) {
first_port_printed = 1;
fprintf(f, "\n");
}
fprintf(f, "port y%i x%i %s\n",
y, x, conn_point_name_src);
}
}
}
return 0;
}
int printf_conns(FILE* f, struct fpga_model* model)
{
struct fpga_tile* tile;
char tmp_line[512];
const char* conn_point_name_src, *other_tile_connpt_str;
uint16_t other_tile_connpt_str_i;
int x, y, i, j, k, conn_point_dests_o, num_dests_for_this_conn_point;
int other_tile_x, other_tile_y, first_conn_printed;
RC_CHECK(model);
for (x = 0; x < model->x_width; x++) {
for (y = 0; y < model->y_height; y++) {
tile = &model->tiles[y*model->x_width + x];
first_conn_printed = 0;
for (i = 0; i < tile->num_conn_point_names; i++) {
conn_point_dests_o = tile->conn_point_names[i*2];
if (i < tile->num_conn_point_names-1)
num_dests_for_this_conn_point = tile->conn_point_names[(i+1)*2] - conn_point_dests_o;
else
num_dests_for_this_conn_point = tile->num_conn_point_dests - conn_point_dests_o;
if (!num_dests_for_this_conn_point)
continue;
conn_point_name_src = strarray_lookup(&model->str, tile->conn_point_names[i*2+1]);
if (!conn_point_name_src) {
fprintf(stderr, "Cannot lookup src conn point name index %i, x%i y%i i%i\n",
tile->conn_point_names[i*2+1], x, y, i);
continue;
}
for (j = 0; j < num_dests_for_this_conn_point; j++) {
other_tile_x = tile->conn_point_dests[(conn_point_dests_o+j)*3];
other_tile_y = tile->conn_point_dests[(conn_point_dests_o+j)*3+1];
other_tile_connpt_str_i = tile->conn_point_dests[(conn_point_dests_o+j)*3+2];
other_tile_connpt_str = strarray_lookup(&model->str, other_tile_connpt_str_i);
if (!other_tile_connpt_str) {
fprintf(stderr, "Lookup err line %i, dest pt %i, dest x%i y%i, from x%i y%i j%i num_dests %i src_pt %s\n",
__LINE__, other_tile_connpt_str_i, other_tile_x, other_tile_y, x, y, j, num_dests_for_this_conn_point, conn_point_name_src);
continue;
}
if (!first_conn_printed) {
first_conn_printed = 1;
fprintf(f, "\n");
}
sprintf(tmp_line, "conn y%i x%i %s ",
y, x, conn_point_name_src);
k = strlen(tmp_line);
while (k < 45)
tmp_line[k++] = ' ';
sprintf(&tmp_line[k], "y%i x%i %s\n",
other_tile_y, other_tile_x, other_tile_connpt_str);
fprintf(f, "%s", tmp_line);
}
}
}
}
return 0;
}
int printf_switches(FILE* f, struct fpga_model* model)
{
struct fpga_tile* tile;
int x, y, i, first_switch_printed;
RC_CHECK(model);
for (x = 0; x < model->x_width; x++) {
for (y = 0; y < model->y_height; y++) {
tile = YX_TILE(model, y, x);
first_switch_printed = 0;
for (i = 0; i < tile->num_switches; i++) {
if (!first_switch_printed) {
first_switch_printed = 1;
fprintf(f, "\n");
}
fprintf(f, "sw y%i x%i %s\n",
y, x, fpga_switch_print(model, y, x, i));
}
}
}
return 0;
}
int printf_nets(FILE* f, struct fpga_model* model)
{
net_idx_t net_i;
int rc;
RC_CHECK(model);
net_i = NO_NET;
while (!(rc = fnet_enum(model, net_i, &net_i)) && net_i != NO_NET)
fnet_printf(f, model, net_i);
if (rc) FAIL(rc);
return 0;
fail:
return rc;
}
static int coord(const char* s, int start, int* end, int* y, int* x)
{
int y_beg, y_end, x_beg, x_end, rc;
next_word(s, start, &y_beg, &y_end);
next_word(s, y_end, &x_beg, &x_end);
if (y_end < y_beg+2 || x_end < x_beg+2
|| s[y_beg] != 'y' || s[x_beg] != 'x'
|| !all_digits(&s[y_beg+1], y_end-y_beg-1)
|| !all_digits(&s[x_beg+1], x_end-x_beg-1)) {
FAIL(EINVAL);
}
*y = to_i(&s[y_beg+1], y_end-y_beg-1);
*x = to_i(&s[x_beg+1], x_end-x_beg-1);
*end = x_end;
return 0;
fail:
return rc;
}
static void read_net_line(struct fpga_model* model, const char* line, int start)
{
int coord_end, y_coord, x_coord;
int from_beg, from_end, from_str_i;
int direction_beg, direction_end, is_bidir;
int to_beg, to_end, to_str_i;
int net_idx_beg, net_idx_end, el_type_beg, el_type_end;
int dev_str_beg, dev_str_end, dev_type_idx_str_beg, dev_type_idx_str_end;
int pin_str_beg, pin_str_end, pin_name_beg, pin_name_end;
enum fpgadev_type dev_type;
char buf[1024];
net_idx_t net_idx;
pinw_idx_t pinw_idx;
int sw_is_bidir;
// net lines will be one of the following three types:
// in-port: net 1 in y68 x13 LOGIC 1 pin D3
// out-port: net 1 out y72 x12 IOB 0 pin I
// switch: net 1 sw y72 x12 BIOB_IBUF0_PINW -> BIOB_IBUF0
next_word(line, start, &net_idx_beg, &net_idx_end);
if (net_idx_end == net_idx_beg
|| !all_digits(&line[net_idx_beg], net_idx_end-net_idx_beg))
{ HERE(); return; }
net_idx = to_i(&line[net_idx_beg], net_idx_end-net_idx_beg);
if (net_idx < 1)
{ HERE(); return; }
next_word(line, net_idx_end, &el_type_beg, &el_type_end);
if (!str_cmp(&line[el_type_beg], el_type_end-el_type_beg, "sw", 2)) {
struct sw_set sw;
if (coord(line, el_type_end, &coord_end, &y_coord, &x_coord))
return;
next_word(line, coord_end, &from_beg, &from_end);
next_word(line, from_end, &direction_beg, &direction_end);
next_word(line, direction_end, &to_beg, &to_end);
if (from_end <= from_beg || direction_end <= direction_beg
|| to_end <= to_beg) {
HERE();
return;
}
memcpy(buf, &line[from_beg], from_end-from_beg);
buf[from_end-from_beg] = 0;
from_str_i = strarray_find(&model->str, buf);
if (from_str_i == STRIDX_NO_ENTRY) {
HERE();
return;
}
if (!str_cmp(&line[direction_beg], direction_end-direction_beg,
"->", 2))
is_bidir = 0;
else if (!str_cmp(&line[direction_beg], direction_end-direction_beg,
"<->", 3))
is_bidir = 1;
else {
HERE();
return;
}
memcpy(buf, &line[to_beg], to_end-to_beg);
buf[to_end-to_beg] = 0;
to_str_i = strarray_find(&model->str, buf);
if (to_str_i == STRIDX_NO_ENTRY) {
HERE();
return;
}
sw.sw[0] = fpga_switch_lookup(model, y_coord, x_coord, from_str_i, to_str_i);
if (sw.sw[0] == NO_SWITCH) {
HERE();
return;
}
sw_is_bidir = fpga_switch_is_bidir(model, y_coord, x_coord, sw.sw[0]);
if ((is_bidir && !sw_is_bidir)
|| (!is_bidir && sw_is_bidir)) {
HERE();
return;
}
if (fpga_switch_is_used(model, y_coord, x_coord, sw.sw[0]))
HERE();
sw.len = 1;
if (fnet_add_sw(model, net_idx, y_coord, x_coord, sw.sw, sw.len))
HERE();
return;
}
if (str_cmp(&line[el_type_beg], el_type_end-el_type_beg, "in", 2)
&& str_cmp(&line[el_type_beg], el_type_end-el_type_beg, "out", 3))
{ HERE(); return; }
if (coord(line, el_type_end, &coord_end, &y_coord, &x_coord))
return;
next_word(line, coord_end, &dev_str_beg, &dev_str_end);
next_word(line, dev_str_end, &dev_type_idx_str_beg, &dev_type_idx_str_end);
next_word(line, dev_type_idx_str_end, &pin_str_beg, &pin_str_end);
next_word(line, pin_str_end, &pin_name_beg, &pin_name_end);
if (dev_str_end <= dev_str_beg
|| dev_type_idx_str_end <= dev_type_idx_str_beg
|| pin_str_end <= pin_str_beg
|| pin_name_end <= pin_name_beg
|| !all_digits(&line[dev_type_idx_str_beg], dev_type_idx_str_end-dev_type_idx_str_beg)
|| str_cmp(&line[pin_str_beg], pin_str_end-pin_str_beg, "pin", 3))
{ HERE(); return; }
dev_type = fdev_str2type(&line[dev_str_beg], dev_str_end-dev_str_beg);
if (dev_type == DEV_NONE) { HERE(); return; }
pinw_idx = fdev_pinw_str2idx(dev_type, &line[pin_name_beg],
pin_name_end-pin_name_beg);
if (pinw_idx == PINW_NO_IDX) { HERE(); return; }
if (fnet_add_port(model, net_idx, y_coord, x_coord, dev_type,
to_i(&line[dev_type_idx_str_beg], dev_type_idx_str_end
-dev_type_idx_str_beg), pinw_idx))
HERE();
}
static void read_dev_line(struct fpga_model* model, const char* line, int start)
{
int coord_end, y_coord, x_coord;
int type_beg, type_end, idx_beg, idx_end;
enum fpgadev_type dev_type;
int dev_type_idx, dev_idx, words_consumed;
struct fpga_device* dev_ptr;
int next_beg, next_end, second_beg, second_end;
if (coord(line, start, &coord_end, &y_coord, &x_coord))
return;
next_word(line, coord_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)) {
HERE();
return;
}
dev_type = fdev_str2type(&line[type_beg], type_end-type_beg);
dev_type_idx = to_i(&line[idx_beg], idx_end-idx_beg);
dev_idx = fpga_dev_idx(model, y_coord, x_coord, dev_type, dev_type_idx);
if (dev_idx == NO_DEV) {
fprintf(stderr, "%s:%i y%i x%i dev_type %i "
"dev_type_idx %i dev_idx %i\n",
__FILE__, __LINE__, y_coord, x_coord, dev_type,
dev_type_idx, dev_idx);
return;
}
dev_ptr = FPGA_DEV(model, y_coord, x_coord, dev_idx);
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, y_coord,
x_coord, dev_type_idx,
&line[next_beg], next_end-next_beg,
&line[second_beg],
second_end-second_beg);
break;
case DEV_BUFGMUX:
words_consumed = read_BUFGMUX_attr(model, dev_ptr,
&line[next_beg], next_end-next_beg,
&line[second_beg],
second_end-second_beg);
break;
case DEV_BUFIO:
words_consumed = read_BUFIO_attr(model, dev_ptr,
&line[next_beg], next_end-next_beg,
&line[second_beg],
second_end-second_beg);
break;
case DEV_BSCAN:
words_consumed = read_BSCAN_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);
return;
}
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;
}
}
int read_floorplan(struct fpga_model* model, FILE* f)
{
char line[1024];
int beg, end;
RC_CHECK(model);
while (fgets(line, sizeof(line), f)) {
next_word(line, 0, &beg, &end);
if (end == beg) continue;
if (end-beg == 3
&& !str_cmp(&line[beg], 3, "net", 3)) {
read_net_line(model, line, end);
}
if (end-beg == 3
&& !str_cmp(&line[beg], 3, "dev", 3)) {
read_dev_line(model, line, end);
}
}
return 0;
}
int write_floorplan(FILE* f, struct fpga_model* model, int flags)
{
if (!(flags & FP_NO_HEADER))
printf_version(f);
if (model->rc)
fprintf(f, "rc %i\n", model->rc);
else {
printf_devices(f, model, /*config_only*/ 1);
printf_nets(f, model);
}
RC_RETURN(model);
}
fpgatools-201212/libs/floorplan.h 0000664 0000000 0000000 00000002532 12065743015 0016704 0 ustar 00root root 0000000 0000000 //
// Author: Wolfgang Spraul
//
// This is free and unencumbered software released into the public domain.
// For details see the UNLICENSE file at the root of the source tree.
//
//
// Design principles of a floorplan file
//
// What needs to be in the file:
// - all devices, configuration for each device
// probably multiple lines that are adding config strings
// - wires maybe separately, and/or as named connection points
// in tiles?
// - connection pairs that can be enabled/disabled
// - global flags and configuration registers
// - the static data should be optional (unused conn pairs,
// unused devices, wires)
//
// - each line should be in the global namespace, line order
// should not matter
// - file should be easily parsable with bison
// - lines should typically not exceed 80 characters
//
int read_floorplan(struct fpga_model* model, FILE* f);
#define FP_DEFAULT 0x0000
#define FP_NO_HEADER 0x0001
int write_floorplan(FILE* f, struct fpga_model* model, int flags);
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);
int printf_ports(FILE* f, struct fpga_model* model);
int printf_conns(FILE* f, struct fpga_model* model);
int printf_switches(FILE* f, struct fpga_model* model);
int printf_nets(FILE* f, struct fpga_model* model);
fpgatools-201212/libs/helper.c 0000664 0000000 0000000 00000064132 12065743015 0016166 0 ustar 00root root 0000000 0000000 //
// Author: Wolfgang Spraul
//
// This is free and unencumbered software released into the public domain.
// For details see the UNLICENSE file at the root of the source tree.
//
#include
#include
#include "model.h"
const char *bitstr(uint32_t value, int digits)
{
static char str[2 /* "0b" */ + 32 + 1 /* '\0' */];
int i;
str[0] = '0';
str[1] = 'b';
for (i = 0; i < digits; i++)
str[digits-i+1] = (value & (1< 15)
indent = 15;
for (i = 0; i < indent; i++)
indent_str[i] = ' ';
indent_str[i] = 0;
i = 0;
if (len <= 0x100)
fmt_str[5] = '2';
else if (len <= 0x10000)
fmt_str[5] = '4';
else
fmt_str[5] = '6';
while (i < len) {
printf(fmt_str, indent_str, i, data[i]);
for (j = 1; (j < 8) && (i + j < len); j++) {
if (i + j >= len) break;
printf(" %02x", data[i+j]);
}
printf("\n");
i += 8;
}
}
uint16_t __swab16(uint16_t x)
{
return (((x & 0x00ffU) << 8) | \
((x & 0xff00U) >> 8)); \
}
uint32_t __swab32(uint32_t x)
{
return (((x & 0x000000ffUL) << 24) | \
((x & 0x0000ff00UL) << 8) | \
((x & 0x00ff0000UL) >> 8) | \
((x & 0xff000000UL) >> 24)); \
}
int atom_found(char *bits, const cfg_atom_t *atom)
{
int i;
for (i = 0; atom->must_0[i] != -1; i++)
if (bits[atom->must_0[i]])
break;
if (atom->must_0[i] != -1)
return 0;
for (i = 0; atom->must_1[i] != -1; i++)
if (!bits[atom->must_1[i]])
break;
return atom->must_1[i] == -1;
}
void atom_remove(char *bits, const cfg_atom_t *atom)
{
int i;
for (i = 0; atom->must_1[i] != -1; i++) {
if (bits[atom->must_1[i]])
bits[atom->must_1[i]] = 0;
}
}
// for an equivalent schematic, see lut.svg
const int lut_base_vars[6] = {0 /* A1 */, 1, 0 /* A3 - not used */,
0, 0, 1 /* A6 */};
static int bool_nextlen(const char *expr, int len)
{
int i, depth;
if (!len) return -1;
i = 0;
if (expr[i] == '~') {
i++;
if (i >= len) return -1;
}
if (expr[i] == '(') {
if (i+2 >= len) return -1;
i++;
for (depth = 1; depth && i < len; i++) {
if (expr[i] == '(')
depth++;
else if (expr[i] == ')')
depth--;
}
if (depth) return -1;
return i;
}
if (expr[i] == 'A') {
i++;
if (i >= len) return -1;
if (expr[i] < '1' || expr[i] > '6') return -1;
return i+1;
}
return -1;
}
// + or, * and, @ xor, ~ not
// var must point to array of A1..A6 variables
static int bool_eval(const char *expr, int len, const int *var)
{
int i, negate, result, oplen;
if (len == 1) {
if (*expr == '1') return 1;
if (*expr == '0') return 0;
}
oplen = bool_nextlen(expr, len);
if (oplen < 1) goto fail;
i = 0;
negate = 0;
if (expr[i] == '~') {
negate = 1;
if (++i >= oplen) goto fail;
}
if (expr[i] == '(') {
if (i+2 >= oplen) goto fail;
result = bool_eval(&expr[i+1], oplen-i-2, var);
if (result == -1) goto fail;
} else if (expr[i] == 'A') {
if (i+1 >= oplen) goto fail;
if (expr[i+1] < '1' || expr[i+1] > '6')
goto fail;
result = var[expr[i+1]-'1'];
if (oplen != i+2) goto fail;
} else goto fail;
if (negate) result = !result;
i = oplen;
while (i < len) {
if (expr[i] == '+') {
if (result) return 1;
return bool_eval(&expr[i+1], len-i-1, var);
}
if (expr[i] == '@') {
int right_side = bool_eval(&expr[i+1], len-i-1, var);
if (right_side == -1) goto fail;
return (result && !right_side) || (!result && right_side);
}
if (expr[i] != '*') goto fail;
if (!result) break;
if (++i >= len) goto fail;
oplen = bool_nextlen(&expr[i], len-i);
if (oplen < 1) goto fail;
result = bool_eval(&expr[i], oplen, var);
if (result == -1) goto fail;
i += oplen;
}
return result;
fail:
return -1;
}
uint64_t map_bits(uint64_t u64, int num_bits, int *src_pos)
{
uint64_t result;
int i;
result = 0;
for (i = 0; i < num_bits; i++) {
if (u64 & (1ULL<<(src_pos[i])))
result |= 1ULL<= mt_size[round]) {
mt[round][mt_size[round]].a[0] = new_term[0];
mt[round][mt_size[round]].a[1] = new_term[1];
mt[round][mt_size[round]].a[2] = new_term[2];
mt[round][mt_size[round]].a[3] = new_term[3];
mt[round][mt_size[round]].a[4] = new_term[4];
mt[round][mt_size[round]].a[5] = new_term[5];
mt_size[round]++;
}
mt[round-1][i].merged = 1;
mt[round-1][j].merged = 1;
}
}
}
}
str_end = 0;
for (round = 0; round < 7; round++) {
for (i = 0; i < mt_size[round]; i++) {
if (!mt[round][i].merged) {
if (str_end)
str[str_end++] = '+';
first_op = 1;
for (j = 0; j < bit_width; j++) {
if (mt[round][i].a[j] != 2) {
if (!first_op)
str[str_end++] = '*';
if (!mt[round][i].a[j])
str[str_end++] = '~';
str[str_end++] = 'A';
str[str_end++] = '1' + j;
first_op = 0;
}
}
}
}
}
str[str_end] = 0;
// TODO: This could be further simplified, see Petrick's method.
// XOR don't simplify well, try A2@A3
return str;
}
void printf_type2(uint8_t *d, int len, int inpos, int num_entries)
{
uint64_t u64;
uint16_t u16;
int i, j;
for (i = 0; i < num_entries; i++) {
u64 = frame_get_u64(&d[inpos+i*8]);
if (!u64) continue;
printf("type2 8*%i 0x%016lX\n", i, u64);
for (j = 0; j < 4; j++) {
u16 = frame_get_u16(&d[inpos+i*8+j*2]);
if (u16)
printf("type2 2*%i 8*%i+%i 0x%04X\n", i*4+j, i, j, u16);
}
}
}
void printf_ramb16_data(uint8_t *bits, int inpos)
{
int nonzero_head, nonzero_tail;
uint8_t init_byte;
char init_str[65];
int i, j, k, bit_off;
// check head and tail
nonzero_head = 0;
for (i = 0; i < 18; i++) {
if (bits[inpos + i]) {
nonzero_head = 1;
break;
}
}
nonzero_tail = 0;
for (i = 0; i < 18; i++) {
if (bits[inpos + 18*130-18 + i]) {
nonzero_tail = 1;
break;
}
}
if (nonzero_head || nonzero_tail)
printf(" #W Unexpected data.\n");
if (nonzero_head) {
printf(" head");
for (i = 0; i < 18; i++)
printf(" %02X", bits[inpos + i]);
printf("\n");
}
if (nonzero_tail) {
printf(" tail");
for (i = 0; i < 18; i++)
printf(" %02X", bits[inpos + 18*130-18 + i]);
printf("\n");
}
// 8 parity configs
for (i = 0; i < 8; i++) {
// 32 bytes per config
for (j = 0; j < 32; j++) {
init_byte = 0;
for (k = 0; k < 8; k++) {
bit_off = (i*(2048+256)) + (31-j)*4*18;
bit_off += 1+(k/2)*18-(k&1);
if (bits[inpos+18+bit_off/8]
& (1<<(7-(bit_off%8))))
init_byte |= 1<= 0)
if (d[l]) return 0;
return 1;
}
int count_bits(const uint8_t *d, int l)
{
int bits = 0;
while (--l >= 0) {
if (d[l] & 0x01) bits++;
if (d[l] & 0x02) bits++;
if (d[l] & 0x04) bits++;
if (d[l] & 0x08) bits++;
if (d[l] & 0x10) bits++;
if (d[l] & 0x20) bits++;
if (d[l] & 0x40) bits++;
if (d[l] & 0x80) bits++;
}
return bits;
}
int frame_get_bit(const uint8_t *frame_d, int bit)
{
uint8_t v = 1<<(7-(bit%8));
return (frame_d[(bit/16)*2 + !((bit/8)%2)] & v) != 0;
}
void frame_clear_bit(uint8_t *frame_d, int bit)
{
uint8_t v = 1<<(7-(bit%8));
frame_d[(bit/16)*2 + !((bit/8)%2)] &= ~v;
}
void frame_set_bit(uint8_t *frame_d, int bit)
{
uint8_t v = 1<<(7-(bit%8));
frame_d[(bit/16)*2 + !((bit/8)%2)] |= v;
}
// see ug380, table 2-5, bit ordering
int frame_get_pinword(const void *bits)
{
int byte0, byte1;
byte0 = ((uint8_t*)bits)[0];
byte1 = ((uint8_t*)bits)[1];
return byte0 << 8 | byte1;
}
void frame_set_pinword(void* bits, int v)
{
((uint8_t*)bits)[0] = v >> 8;
((uint8_t*)bits)[1] = v & 0xFF;
}
uint8_t frame_get_u8(const uint8_t *frame_d)
{
uint8_t v = 0;
int i;
for (i = 0; i < 8; i++)
if (*frame_d & (1<> 8;
low_b = v & 0xFF;
frame_set_u8(frame_d, high_b);
frame_set_u8(frame_d+1, low_b);
}
void frame_set_u32(uint8_t* frame_d, uint32_t v)
{
uint32_t high_w, low_w;
high_w = v >> 16;
low_w = v & 0xFFFF;
frame_set_u16(frame_d, low_w);
frame_set_u16(frame_d+2, high_w);
}
void frame_set_u64(uint8_t* frame_d, uint64_t v)
{
uint32_t high_w, low_w;
low_w = v & 0xFFFFFFFF;
high_w = v >> 32;
frame_set_u32(frame_d, low_w);
frame_set_u32(frame_d+4, high_w);
}
uint64_t frame_get_lut64(const uint8_t* two_minors, int v32)
{
int off_in_frame, i;
uint32_t m0, m1;
uint64_t lut64;
off_in_frame = v32*4;
if (off_in_frame >= 64)
off_in_frame += XC6_HCLK_BYTES;
m0 = frame_get_u32(&two_minors[off_in_frame]);
m1 = frame_get_u32(&two_minors[FRAME_SIZE + off_in_frame]);
lut64 = 0;
for (i = 0; i < 32; i++) {
if (m0 & (1<= 64)
off_in_frame += XC6_HCLK_BYTES;
frame_set_u32(&two_minors[off_in_frame], m0);
frame_set_u32(&two_minors[FRAME_SIZE + off_in_frame], m1);
}
// see ug380, table 2-5, bit ordering
static int xc6_bit2pin(int bit)
{
int pin = bit % XC6_WORD_BITS;
if (pin >= 8) return 15-(pin-8);
return 7-pin;
}
int printf_frames(const uint8_t* bits, int max_frames,
int row, int major, int minor, int print_empty, int no_clock)
{
int i, i_without_clk;
char prefix[128], suffix[128];
if (row < 0)
sprintf(prefix, "f%i ", abs(row));
else
sprintf(prefix, "r%i ma%i mi%i ", row, major, minor);
if (is_empty(bits, 130)) {
for (i = 1; i < max_frames; i++) {
if (!is_empty(&bits[i*130], 130))
break;
}
if (print_empty) {
if (i > 1)
printf("%s- *%i\n", prefix, i);
else
printf("%s-\n", prefix);
}
return i;
}
// value 128 chosen randomly for readability to decide
// between printing individual bits or a hex block.
if (count_bits(bits, 130) <= 128) {
for (i = 0; i < FRAME_SIZE*8; i++) {
if (!frame_get_bit(bits, i)) continue;
if (i >= 512 && i < 528) { // hclk
if (!no_clock)
printf("%sbit %i\n", prefix, i);
continue;
}
i_without_clk = i;
if (i_without_clk >= 528)
i_without_clk -= 16;
snprintf(suffix, sizeof(suffix), "64*%i+%i 256*%i+%i pin %i",
i_without_clk/64, i_without_clk%64,
i_without_clk/256, i_without_clk%256,
xc6_bit2pin(i_without_clk));
printf("%sbit %i %s\n", prefix, i, suffix);
}
return 1;
}
printf("%shex\n", prefix);
printf("{\n");
hexdump(1, bits, 130);
printf("}\n");
return 1;
}
void printf_clock(const uint8_t* frame, int row, int major, int minor)
{
int i;
for (i = 0; i < 16; i++) {
if (frame_get_bit(frame, 512 + i))
printf("r%i ma%i mi%i clock %i pin %i\n",
row, major, minor, i, xc6_bit2pin(i));
}
}
int clb_empty(uint8_t* maj_bits, int idx)
{
int byte_off, i, minor;
byte_off = idx * 8;
if (idx >= 8) byte_off += 2;
for (i = 0; i < 16; i++) {
for (minor = 20; minor < 31; minor++) {
if (!is_empty(&maj_bits[minor*130 + byte_off], 8))
return 0;
}
}
return 1;
}
void printf_extrabits(const uint8_t* maj_bits, int start_minor, int num_minors,
int start_bit, int num_bits, int row, int major)
{
int minor, bit, bit_no_clk;
for (minor = start_minor; minor < start_minor + num_minors; minor++) {
for (bit = start_bit; bit < start_bit + num_bits; bit++) {
if (frame_get_bit(&maj_bits[minor*FRAME_SIZE], bit)) {
bit_no_clk = bit;
if (bit_no_clk >= 528)
bit_no_clk -= XC6_HCLK_BITS;
printf("r%i ma%i mi%i bit %i 64*%i+%i 256*%i+%i\n",
row, major, minor, bit,
bit_no_clk/64, bit_no_clk%64,
bit_no_clk/256, bit_no_clk%256);
}
}
}
}
void write_lut64(uint8_t* two_minors, int off_in_frame, uint64_t u64)
{
int i;
for (i = 0; i < 16; i++) {
if (u64 & (1LL << (i*4)))
frame_set_bit(two_minors, off_in_frame+i*2);
if (u64 & (1LL << (i*4+1)))
frame_set_bit(two_minors, off_in_frame+(i*2)+1);
if (u64 & (1LL << (i*4+2)))
frame_set_bit(two_minors + FRAME_SIZE, off_in_frame+i*2);
if (u64 & (1LL << (i*4+3)))
frame_set_bit(two_minors + FRAME_SIZE, off_in_frame+(i*2)+1);
}
}
int get_vm_mb(void)
{
FILE* statusf = fopen("/proc/self/status", "r");
char line[1024];
int vm_size = 0;
while (fgets(line, sizeof(line), statusf)) {
if (sscanf(line, "VmSize: %i kB", &vm_size) == 1)
break;
}
fclose(statusf);
if (!vm_size) return 0;
return (vm_size+1023)/1024;
}
int get_random(void)
{
int random_f, random_num;
random_f = open("/dev/urandom", O_RDONLY);
read(random_f, &random_num, sizeof(random_num));
close(random_f);
return random_num;
}
int compare_with_number(const char* a, const char* b)
{
int i, a_i, b_i, non_numeric_result, a_num, b_num;
for (i = 0; a[i] && (a[i] == b[i]); i++);
if (a[i] == b[i]) {
if (a[i]) fprintf(stderr, "Internal error in line %i\n", __LINE__);
return 0;
}
non_numeric_result = a[i] - b[i];
// go back to beginning of numeric section
while (i && a[i-1] >= '0' && a[i-1] <= '9')
i--;
// go forward to first non-digit
for (a_i = i; a[a_i] >= '0' && a[a_i] <= '9'; a_i++ );
for (b_i = i; b[b_i] >= '0' && b[b_i] <= '9'; b_i++ );
// There must be at least one digit in both a and b
// and the suffix must match.
if (a_i <= i || b_i <= i
|| strcmp(&a[a_i], &b[b_i]))
return non_numeric_result;
a_num = strtol(&a[i], 0 /* endptr */, 10);
b_num = strtol(&b[i], 0 /* endptr */, 10);
return a_num - b_num;
}
void next_word(const char*s, int start, int* beg, int* end)
{
int i = start;
while (s[i] == ' ' || s[i] == '\t' || s[i] == '\n') i++;
*beg = i;
while (s[i] != ' ' && s[i] != '\t' && s[i] != '\n' && s[i]) i++;
*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;
for (base = 1, num = 0; len; num += base*(s[--len]-'0'), base *= 10);
return num;
}
int mod4_calc(int a, int b)
{
return (unsigned int) (a+b)%4;
}
int all_zero(const void* d, int num_bytes)
{
int i;
for (i = 0; i < num_bytes; i++)
if (((uint8_t*)d)[i]) return 0;
return 1;
}
void printf_wrap(FILE* f, char* line, int prefix_len,
const char* fmt, ...)
{
va_list list;
int i;
va_start(list, fmt);
i = strlen(line);
if (i >= 80) {
line[i] = '\n';
line[i+1] = 0;
fprintf(f, "%s", line);
line[prefix_len] = 0;
i = prefix_len;
}
line[i] = ' ';
vsnprintf(&line[i+1], 256, fmt, list);
va_end(list);
}
// Dan Bernstein's hash function
uint32_t hash_djb2(const unsigned char* str)
{
uint32_t hash = 5381;
int c;
while ((c = *str++) != 0)
hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
return hash;
}
//
// The format of each entry in a bin is.
// uint32_t idx
// uint16_t entry len including 4-byte header
// char[] zero-terminated string
//
// Offsets point to the zero-terminated string, so the len
// is at off-2, the index at off-6. offset0 can thus be
// used as a special value to signal 'no entry'.
//
#define BIN_STR_HEADER (4+2)
#define BIN_MIN_OFFSET BIN_STR_HEADER
#define BIN_INCREMENT 32768
const char* strarray_lookup(struct hashed_strarray* array, int idx)
{
int bin, offset;
if (!array->index_to_bin || !array->bin_offsets || idx==STRIDX_NO_ENTRY)
return 0;
bin = array->index_to_bin[idx-1];
offset = array->bin_offsets[idx-1];
// bin 0 offset 0 is a special value that signals 'no
// entry'. Normal offsets cannot be less than BIN_MIN_OFFSET.
if (!bin && !offset) return 0;
if (!array->bin_strings[bin] || offset >= array->bin_len[bin]
|| offset < BIN_MIN_OFFSET) {
// This really should never happen and is an internal error.
fprintf(stderr, "Internal error.\n");
return 0;
}
return &array->bin_strings[bin][offset];
}
int strarray_find(struct hashed_strarray* array, const char* str)
{
int bin, search_off, i;
uint32_t hash;
hash = hash_djb2((const unsigned char*) str);
bin = hash % array->num_bins;
// iterate over strings in bin to find match
if (array->bin_strings[bin]) {
search_off = BIN_MIN_OFFSET;
while (search_off < array->bin_len[bin]) {
if (!strcmp(&array->bin_strings[bin][search_off], str)) {
i = *(uint32_t*)&array->bin_strings[bin][search_off-6];
if (!i) {
fprintf(stderr, "Internal error - index 0.\n");
return STRIDX_NO_ENTRY;
}
return i+1;
}
search_off += *(uint16_t*)&array->bin_strings[bin][search_off-2];
}
}
return STRIDX_NO_ENTRY;
}
int s_stash_at_bin(struct hashed_strarray* array, const char* str, int idx, int bin);
int strarray_add(struct hashed_strarray* array, const char* str, int* idx)
{
int bin, i, free_index, rc, start_index;
unsigned long hash;
*idx = strarray_find(array, str);
if (*idx != STRIDX_NO_ENTRY) return 0;
hash = hash_djb2((const unsigned char*) str);
// search free index
start_index = hash % array->highest_index;
for (i = 0; i < array->highest_index; i++) {
int cur_i = (start_index+i)%array->highest_index;
if (!cur_i) // never issue index 0
continue;
if (!array->bin_offsets[cur_i])
break;
}
if (i >= array->highest_index) {
fprintf(stderr, "All array indices full.\n");
return -1;
}
free_index = (start_index+i)%array->highest_index;
bin = hash % array->num_bins;
rc = s_stash_at_bin(array, str, free_index, bin);
if (rc) return rc;
*idx = free_index + 1;
return 0;
}
int s_stash_at_bin(struct hashed_strarray* array, const char* str, int idx, int bin)
{
int str_len = strlen(str);
// check whether bin needs expansion
if (!(array->bin_len[bin]%BIN_INCREMENT)
|| array->bin_len[bin]%BIN_INCREMENT + BIN_STR_HEADER+str_len+1 > BIN_INCREMENT)
{
int new_alloclen;
void* new_ptr;
new_alloclen = ((array->bin_len[bin]
+ BIN_STR_HEADER+str_len+1)/BIN_INCREMENT + 1)
* BIN_INCREMENT;
new_ptr = realloc(array->bin_strings[bin], new_alloclen);
if (!new_ptr) {
fprintf(stderr, "Out of memory.\n");
return -1;
}
if (new_alloclen > array->bin_len[bin])
memset(new_ptr+array->bin_len[bin], 0, new_alloclen-array->bin_len[bin]);
array->bin_strings[bin] = new_ptr;
}
// append new string at end of bin
*(uint32_t*)&array->bin_strings[bin][array->bin_len[bin]] = idx;
*(uint16_t*)&array->bin_strings[bin][array->bin_len[bin]+4] = BIN_STR_HEADER+str_len+1;
strcpy(&array->bin_strings[bin][array->bin_len[bin]+BIN_STR_HEADER], str);
array->index_to_bin[idx] = bin;
array->bin_offsets[idx] = array->bin_len[bin]+BIN_STR_HEADER;
array->bin_len[bin] += BIN_STR_HEADER+str_len+1;
return 0;
}
int strarray_stash(struct hashed_strarray* array, const char* str, int idx)
{
// The bin is just a random number here, because find
// cannot be used after stash anyway, only lookup can.
return s_stash_at_bin(array, str, idx-1, idx % array->num_bins);
}
int strarray_used_slots(struct hashed_strarray* array)
{
int i, num_used_slots;
num_used_slots = 0;
if (!array->bin_offsets) return 0;
for (i = 0; i < array->highest_index; i++) {
if (array->bin_offsets[i])
num_used_slots++;
}
return num_used_slots;
}
int strarray_init(struct hashed_strarray* array, int highest_index)
{
memset(array, 0, sizeof(*array));
array->highest_index = highest_index;
array->num_bins = highest_index / 64;
array->bin_strings = calloc(array->num_bins,sizeof(*array->bin_strings));
array->bin_len = calloc(array->num_bins,sizeof(*array->bin_len));
array->bin_offsets = calloc(array->highest_index,sizeof(*array->bin_offsets));
array->index_to_bin = calloc(array->highest_index,sizeof(*array->index_to_bin));
if (!array->bin_strings || !array->bin_len
|| !array->bin_offsets || !array->index_to_bin) {
fprintf(stderr, "Out of memory in %s:%i\n", __FILE__, __LINE__);
free(array->bin_strings);
free(array->bin_len);
free(array->bin_offsets);
free(array->index_to_bin);
return -1;
}
return 0;
}
void strarray_free(struct hashed_strarray* array)
{
int i;
for (i = 0; i < sizeof(array->bin_strings)/
sizeof(array->bin_strings[0]); i++) {
free(array->bin_strings[i]);
array->bin_strings[i] = 0;
}
free(array->bin_strings);
array->bin_strings = 0;
free(array->bin_len);
array->bin_len = 0;
free(array->bin_offsets);
array->bin_offsets = 0;
free(array->index_to_bin);
array->index_to_bin = 0;
}
int row_pos_to_y(int num_rows, int row, int pos)
{
int y;
if (row >= num_rows) {
HERE();
return -1;
}
y = TOP_IO_TILES;
if (row < num_rows/2)
y++; // below center
y += num_rows - row - 1; // hclk in full rows from top
if (pos >= HALF_ROW)
y++; // hclk in row
return y;
}
int cmdline_help(int argc, char **argv)
{
int i;
for (i = 1; i < argc; i++) {
if (!strcmp(argv[i], "--help")) {
printf( "\n"
"%s floorplan\n"
"\n"
"Usage: %s [--part=xc6slx9]\n"
" %*s [--package=tqg144|ftg256]\n"
" %*s [--help]\n",
*argv, *argv, (int) strlen(*argv), "",
(int) strlen(*argv), "");
return 1;
}
}
return 0;
}
int cmdline_part(int argc, char **argv)
{
int i;
for (i = 1; i < argc; i++) {
if (!strcmp(argv[i], "--part=xc6slx9"))
return XC6SLX9;
}
return XC6SLX9;
}
int cmdline_package(int argc, char **argv)
{
int i;
for (i = 1; i < argc; i++) {
if (!strcmp(argv[i], "--package=tqg144"))
return TQG144;
if (!strcmp(argv[i], "--package=ftg256"))
return FTG256;
}
return TQG144;
}
const char *cmdline_strvar(int argc, char **argv, const char *var)
{
enum { NUM_BUFS = 32, BUF_SIZE = 256 };
static char buf[NUM_BUFS][BUF_SIZE];
static int last_buf = 0;
char scan_str[128];
int i, next_buf;
next_buf = (last_buf+1)%NUM_BUFS;
snprintf(scan_str, sizeof(scan_str), "-D%s=%%s", var);
for (i = 1; i < argc; i++) {
if (sscanf(argv[i], scan_str, buf[next_buf]) == 1) {
last_buf = next_buf;
return buf[last_buf];
}
}
return 0;
}
int cmdline_intvar(int argc, char **argv, const char *var)
{
char buf[128];
int i, out_int;
snprintf(buf, sizeof(buf), "-D%s=%%i", var);
for (i = 1; i < argc; i++) {
if (sscanf(argv[i], buf, &out_int) == 1)
return out_int;
}
return 0;
}
fpgatools-201212/libs/helper.h 0000664 0000000 0000000 00000014024 12065743015 0016166 0 ustar 00root root 0000000 0000000 //
// Author: Wolfgang Spraul
//
// This is free and unencumbered software released into the public domain.
// For details see the UNLICENSE file at the root of the source tree.
//
#include
#include
#include
#include
#include
#include
#include
#define PROGRAM_REVISION "2012-06-27"
#define MACRO_STR(arg) #arg
#define OUT_OF_MEM() { fprintf(stderr, \
"#E Out of memory in %s:%i\n", __FILE__, __LINE__); }
#define EXIT(expr) if (expr) { fprintf(stderr, \
"#E Internal error in %s:%i\n", __FILE__, __LINE__); exit(1); }
#define HERE() fprintf(stderr, "#E Internal error in %s:%i\n", \
__FILE__, __LINE__)
#define FAIL(code) do { HERE(); rc = (code); goto fail; } while (0)
#define XOUT() do { HERE(); goto xout; } while (0)
#define ASSERT(what) do { if (!(what)) FAIL(EINVAL); } while (0)
#define CLEAR(x) memset(&(x), 0, sizeof(x))
#define RC_CHECK(model) do { if ((model)->rc) RC_RETURN(model); } while (0)
#define RC_ASSERT(model, what) do { RC_CHECK(model); if (!(what)) RC_FAIL(model, EINVAL); } while (0)
#define RC_FAIL(model, code) do { HERE(); if (!(model)->rc) (model)->rc = (code); RC_RETURN(model); } while (0)
#define RC_RETURN(model) return (model)->rc
#define OUT_OF_U16(val) ((val) < 0 || (val) > 0xFFFF)
const char* bitstr(uint32_t value, int digits);
void hexdump(int indent, const uint8_t* data, int len);
uint16_t __swab16(uint16_t x);
uint32_t __swab32(uint32_t x);
#define __be32_to_cpu(x) __swab32((uint32_t)(x))
#define __be16_to_cpu(x) __swab16((uint16_t)(x))
#define __cpu_to_be32(x) __swab32((uint32_t)(x))
#define __cpu_to_be16(x) __swab16((uint16_t)(x))
#define __le32_to_cpu(x) ((uint32_t)(x))
#define __le16_to_cpu(x) ((uint16_t)(x))
#define __cpu_to_le32(x) ((uint32_t)(x))
#define __cpu_to_le16(x) ((uint16_t)(x))
#define ATOM_MAX_BITS 32+1 // -1 signals end of array
typedef struct _cfg_atom
{
int must_0[ATOM_MAX_BITS];
int must_1[ATOM_MAX_BITS];
const char* str;
int flag; // used to remember a state such as 'found'
} cfg_atom_t;
int atom_found(char* bits, const cfg_atom_t* atom);
void atom_remove(char* bits, const cfg_atom_t* atom);
uint64_t map_bits(uint64_t u64, int num_bits, int* src_pos);
int bool_str2bits(const char* str, uint64_t* u64, int num_bits);
const char* bool_bits2str(uint64_t u64, int num_bits);
void printf_type2(uint8_t* d, int len, int inpos, int num_entries);
void printf_ramb16_data(uint8_t* bits, int inpos);
int is_empty(const uint8_t* d, int l);
int count_bits(const uint8_t* d, int l);
int frame_get_bit(const uint8_t* frame_d, int bit);
void frame_clear_bit(uint8_t* frame_d, int bit);
void frame_set_bit(uint8_t* frame_d, int bit);
int frame_get_pinword(const void *bits);
void frame_set_pinword(void* bits, int v);
uint8_t frame_get_u8(const uint8_t* frame_d);
uint16_t frame_get_u16(const uint8_t* frame_d);
uint32_t frame_get_u32(const uint8_t* frame_d);
uint64_t frame_get_u64(const uint8_t* frame_d);
void frame_set_u8(uint8_t* frame_d, uint8_t v);
void frame_set_u16(uint8_t* frame_d, uint16_t v);
void frame_set_u32(uint8_t* frame_d, uint32_t v);
void frame_set_u64(uint8_t* frame_d, uint64_t v);
uint64_t frame_get_lut64(const uint8_t* two_minors, int v32);
// In a lut pair, lut5 is always mapped to LOW32, lut6 to HIGH32.
#define ULL_LOW32(v) ((uint32_t) (((uint64_t)v) & 0xFFFFFFFFULL))
#define ULL_HIGH32(v) ((uint32_t) (((uint64_t)v) >> 32))
void frame_set_lut64(uint8_t* two_minors, int v32, uint64_t v);
// if row is negative, it's an absolute frame number and major and
// minor are ignored
int printf_frames(const uint8_t* bits, int max_frames, int row, int major,
int minor, int print_empty, int no_clock);
void printf_clock(const uint8_t* frame, int row, int major, int minor);
int clb_empty(uint8_t* maj_bits, int idx);
void printf_extrabits(const uint8_t* maj_bits, int start_minor, int num_minors,
int start_bit, int num_bits, int row, int major);
void write_lut64(uint8_t* two_minors, int off_in_frame, uint64_t u64);
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);
int mod4_calc(int a, int b);
int all_zero(const void* d, int num_bytes);
void printf_wrap(FILE* f, char* line, int prefix_len,
const char* fmt, ...);
uint32_t hash_djb2(const unsigned char* str);
// Strings are distributed among bins. Each bin is
// one continuous stream of zero-terminated strings
// prefixed with a 32+16=48-bit header. The allocation
// increment for each bin is 32k.
struct hashed_strarray
{
int highest_index;
uint32_t* bin_offsets; // min offset is 4, 0 means no entry
uint16_t* index_to_bin;
char** bin_strings;
int* bin_len;
int num_bins;
};
#define STRIDX_64K 0xFFFF
#define STRIDX_1M 1000000
typedef uint16_t str16_t;
int strarray_init(struct hashed_strarray* array, int highest_index);
void strarray_free(struct hashed_strarray* array);
const char* strarray_lookup(struct hashed_strarray* array, int idx);
// The found or created index will never be 0, so the caller
// can use 0 as a special value to indicate 'no string'.
#define STRIDX_NO_ENTRY 0
int strarray_find(struct hashed_strarray* array, const char* str);
int strarray_add(struct hashed_strarray* array, const char* str, int* idx);
// If you stash a string to a fixed index, you cannot use strarray_find()
// anymore, only strarray_lookup().
int strarray_stash(struct hashed_strarray* array, const char* str, int idx);
int strarray_used_slots(struct hashed_strarray* array);
int row_pos_to_y(int num_rows, int row, int pos);
int cmdline_help(int argc, char **argv);
int cmdline_part(int argc, char **argv);
int cmdline_package(int argc, char **argv);
const char *cmdline_strvar(int argc, char **argv, const char *var);
int cmdline_intvar(int argc, char **argv, const char *var);
fpgatools-201212/libs/model.h 0000664 0000000 0000000 00000105757 12065743015 0016025 0 ustar 00root root 0000000 0000000 //
// Author: Wolfgang Spraul
//
// This is free and unencumbered software released into the public domain.
// For details see the UNLICENSE file at the root of the source tree.
//
#include
#include
#include
#include
#include
#include
#include
#include "helper.h"
#include "parts.h"
#define LEFT_SIDE_MAJOR 1
struct fpga_model
{
int rc; // if rc != 0, all function calls will immediately return
const struct xc_die *die;
const struct xc6_pkg_info *pkg;
int x_width, y_height;
int center_x;
int center_y;
// Left and right gclk separators will be located on
// the device column (+1 or +2) of the logic or dsp/macc
// column as indicated in the chip's cfg_columns with a 'g'.
int left_gclk_sep_x, right_gclk_sep_x;
// x_major is an array of column indices for each x coordinate,
// starting with column 1 for the left side, and incrementing
// through the configuration columns. This corresponds to the
// 'majors' in the bitstream.
int x_major[512];
struct xc6_routing_bitpos* sw_bitpos;
int num_bitpos;
struct fpga_tile* tiles;
struct hashed_strarray str;
int nets_array_size;
int highest_used_net; // 1-based net_idx_t
struct fpga_net* nets;
// tmp_str will be allocated to hold max(x_width, y_height)
// pointers, useful for string seeding when running wires.
const char** tmp_str;
};
enum fpga_tile_type
{
NA = 0,
ROUTING, ROUTING_BRK, ROUTING_VIA,
HCLK_ROUTING_XM, HCLK_ROUTING_XL, HCLK_LOGIC_XM, HCLK_LOGIC_XL,
LOGIC_XM, LOGIC_XL,
REGH_ROUTING_XM, REGH_ROUTING_XL, REGH_LOGIC_XM, REGH_LOGIC_XL,
BRAM_ROUTING, BRAM_ROUTING_BRK,
BRAM,
BRAM_ROUTING_TERM_T, BRAM_ROUTING_TERM_B, BRAM_ROUTING_VIA_TERM_T, BRAM_ROUTING_VIA_TERM_B,
BRAM_TERM_LT, BRAM_TERM_RT, BRAM_TERM_LB, BRAM_TERM_RB,
HCLK_BRAM_ROUTING, HCLK_BRAM_ROUTING_VIA, HCLK_BRAM,
REGH_BRAM_ROUTING, REGH_BRAM_ROUTING_VIA, REGH_BRAM_L, REGH_BRAM_R,
MACC,
HCLK_MACC_ROUTING, HCLK_MACC_ROUTING_VIA, HCLK_MACC,
REGH_MACC_ROUTING, REGH_MACC_ROUTING_VIA, REGH_MACC_L,
PLL_T, DCM_T, PLL_B, DCM_B, REG_T,
REG_TERM_T, REG_TERM_B, REG_B,
REGV_TERM_T, REGV_TERM_B,
HCLK_REGV,
REGV, REGV_BRK, REGV_T, REGV_B, REGV_MIDBUF_T, REGV_HCLKBUF_T, REGV_HCLKBUF_B, REGV_MIDBUF_B,
REGC_ROUTING, REGC_LOGIC, REGC_CMT,
CENTER, // unique center tile in the middle of the chip
IO_T, IO_B, IO_TERM_T, IO_TERM_B, IO_ROUTING, IO_LOGIC_TERM_T, IO_LOGIC_TERM_B,
IO_OUTER_T, IO_INNER_T, IO_OUTER_B, IO_INNER_B,
IO_BUFPLL_TERM_T, IO_LOGIC_REG_TERM_T, IO_BUFPLL_TERM_B, IO_LOGIC_REG_TERM_B,
LOGIC_ROUTING_TERM_B, LOGIC_NOIO_TERM_B,
MACC_ROUTING_TERM_T, MACC_ROUTING_TERM_B, MACC_VIA_TERM_T,
MACC_TERM_TL, MACC_TERM_TR, MACC_TERM_BL, MACC_TERM_BR,
ROUTING_VIA_REGC, ROUTING_VIA_IO, ROUTING_VIA_IO_DCM, ROUTING_VIA_CARRY,
CORNER_TERM_L, CORNER_TERM_R,
IO_TERM_L_UPPER_TOP, IO_TERM_L_UPPER_BOT, IO_TERM_L_LOWER_TOP, IO_TERM_L_LOWER_BOT,
IO_TERM_R_UPPER_TOP, IO_TERM_R_UPPER_BOT, IO_TERM_R_LOWER_TOP, IO_TERM_R_LOWER_BOT,
IO_TERM_L, IO_TERM_R,
HCLK_TERM_L, HCLK_TERM_R,
REGH_IO_TERM_L, REGH_IO_TERM_R,
REG_L, REG_R,
IO_PCI_L, IO_PCI_R, IO_RDY_L, IO_RDY_R,
IO_L, IO_R,
IO_PCI_CONN_L, IO_PCI_CONN_R,
CORNER_TERM_T, CORNER_TERM_B,
ROUTING_IO_L,
HCLK_ROUTING_IO_L, HCLK_ROUTING_IO_R, REGH_ROUTING_IO_L, REGH_ROUTING_IO_R,
ROUTING_IO_L_BRK, ROUTING_GCLK,
REGH_IO_L, REGH_IO_R, REGH_MCB, HCLK_MCB,
ROUTING_IO_VIA_L, ROUTING_IO_VIA_R, ROUTING_IO_PCI_CE_L, ROUTING_IO_PCI_CE_R,
CORNER_TL, CORNER_BL,
CORNER_TR_UPPER, CORNER_TR_LOWER, CORNER_BR_UPPER, CORNER_BR_LOWER,
HCLK_IO_TOP_UP_L, HCLK_IO_TOP_UP_R,
HCLK_IO_TOP_SPLIT_L, HCLK_IO_TOP_SPLIT_R,
HCLK_IO_TOP_DN_L, HCLK_IO_TOP_DN_R,
HCLK_IO_BOT_UP_L, HCLK_IO_BOT_UP_R,
HCLK_IO_BOT_SPLIT_L, HCLK_IO_BOT_SPLIT_R,
HCLK_IO_BOT_DN_L, HCLK_IO_BOT_DN_R,
};
// Some macros to make the code more readable
#define LEFT_OUTER_COL 0
#define LEFT_INNER_COL 1
#define LEFT_IO_ROUTING 2
#define LEFT_IO_DEVS 3
#define LEFT_MCB_COL 4
#define LEFT_SIDE_WIDTH 5
#define RIGHT_SIDE_WIDTH 5
#define LEFT_LOCAL_HEIGHT 1
#define RIGHT_LOCAL_HEIGHT 2
#define TOP_IO_TILES 2
#define TOPBOT_IO_ROWS 2 // OUTER and INNER IO
// todo: maybe rename TOP_OUTER_ROW to TOP_OUTER_TERM and
// TOP_INNER_ROW to TOP_INNER_TERM?
#define TOP_OUTER_ROW 0
#define TOP_INNER_ROW 1
#define TOP_FIRST_REGULAR 2
#define TOP_OUTER_IO 2
#define TOP_INNER_IO 3
#define HALF_ROW 8
#define HCLK_POS 8 // hclk pos in row
#define LAST_POS_IN_ROW 16 // including hclk at 8
#define ROW_SIZE (HALF_ROW+1+HALF_ROW)
#define CENTER_X_PLUS_1 1 // routing col adjacent to center
#define CENTER_X_PLUS_2 2 // logic col adjacent to center
#define CENTER_Y_PLUS_1 1
#define CENTER_Y_PLUS_2 2
#define CENTER_Y_MINUS_1 1
#define CENTER_Y_MINUS_2 2
#define CENTER_Y_MINUS_3 3
#define CENTER_Y_MINUS_4 4
#define CENTER_TOP_IOB_O 3 // deduct from center_y
#define CENTER_BOT_IOB_O 1 // add to center_y
// Some offsets that are being deducted from their origin
#define BOT_IO_TILES 2
// todo: rename BOT_OUTER_ROW to BOT_OUTER_TERM and BOT_INNER_ROW
// to BOT_INNER_TERM?
#define BOT_OUTER_ROW 1
#define BOT_INNER_ROW 2
#define BOT_LAST_REGULAR_O 3
#define BOT_OUTER_IO 3
#define BOT_INNER_IO 4
#define RIGHT_OUTER_O 1
#define RIGHT_INNER_O 2
#define RIGHT_MCB_O 3
#define RIGHT_IO_DEVS_O 4
#define RIGHT_IO_ROUTING_O 5
#define CENTER_CMTPLL_O 1
#define CENTER_LOGIC_O 2
#define CENTER_ROUTING_O 3
#define YX_TILE(model, y, x) (&(model)->tiles[(y)*(model)->x_width+(x)])
// tile flags
#define TF_FABRIC_ROUTING_COL 0x00000001 // only set in y==0, not for left and right IO routing or center
#define TF_FABRIC_LOGIC_XM_COL 0x00000002 // only set in y==0
#define TF_FABRIC_LOGIC_XL_COL 0x00000004 // only set in y==0
#define TF_FABRIC_BRAM_VIA_COL 0x00000008 // only set in y==0
#define TF_FABRIC_MACC_VIA_COL 0x00000010 // only set in y==0
#define TF_FABRIC_BRAM_COL 0x00000020 // only set in y==0
#define TF_FABRIC_MACC_COL 0x00000040 // only set in y==0
// TF_ROUTING_NO_IO is only set in y==0 - automatically for BRAM and MACC
// routing, and manually for logic routing with the noio flag in the column
// configuration string
#define TF_ROUTING_NO_IO 0x00000080
#define TF_BRAM_DEV 0x00000100
#define TF_MACC_DEV 0x00000200
#define TF_LOGIC_XL_DEV 0x00000400
#define TF_LOGIC_XM_DEV 0x00000800
#define TF_IOLOGIC_DELAY_DEV 0x00001000
#define TF_DCM_DEV 0x00002000
#define TF_PLL_DEV 0x00004000
// TF_WIRED is only set for x==0 on the left side or x==x_width-1
// on the right side.
#define TF_WIRED 0x00008000
#define TF_CENTER_MIDBUF 0x00010000
#define Y_OUTER_TOP 0x0001
#define Y_INNER_TOP 0x0002
#define Y_INNER_BOTTOM 0x0004
#define Y_OUTER_BOTTOM 0x0008
#define Y_CHIP_HORIZ_REGS 0x0010
#define Y_ROW_HORIZ_AXSYMM 0x0020
#define Y_BOTTOM_OF_ROW 0x0040
#define Y_LEFT_WIRED 0x0080
#define Y_RIGHT_WIRED 0x0100
// Y_TOPBOT_IO_RANGE checks if y points to the top or bottom outer or
// inner rows. todo: same as TOP_OUTER|TOP_INNER|BOT_INNER|BOT_OUTER?
#define Y_TOPBOT_IO_RANGE 0x0200
#define Y_TOP_OUTER_IO 0x0400
#define Y_TOP_INNER_IO 0x0800
#define Y_BOT_INNER_IO 0x1000
#define Y_BOT_OUTER_IO 0x2000
#define Y_TOP_FIRST_REGULAR Y_TOP_OUTER_IO
#define Y_BOT_LAST_REGULAR Y_BOT_OUTER_IO
#define Y_REGULAR_ROW 0x4000
// multiple checks are combined with OR logic
int is_aty(int check, struct fpga_model* model, int y);
#define X_FABRIC_LOGIC_COL (X_FABRIC_LOGIC_XM_COL \
|X_FABRIC_LOGIC_XL_COL)
#define X_FABRIC_LOGIC_ROUTING_COL (X_FABRIC_LOGIC_XM_ROUTING_COL \
|X_FABRIC_LOGIC_XL_ROUTING_COL)
#define X_FABRIC_ROUTING_COL (X_FABRIC_LOGIC_XM_ROUTING_COL \
|X_FABRIC_LOGIC_XL_ROUTING_COL \
|X_FABRIC_BRAM_ROUTING_COL \
|X_FABRIC_MACC_ROUTING_COL)
#define X_ROUTING_COL (X_FABRIC_ROUTING_COL \
|X_CENTER_ROUTING_COL \
|X_LEFT_IO_ROUTING_COL \
|X_RIGHT_IO_ROUTING_COL)
#define X_CENTER_MAJOR (X_CENTER_ROUTING_COL \
|X_CENTER_LOGIC_COL \
|X_CENTER_CMTPLL_COL \
|X_CENTER_REGS_COL)
// todo and realizations:
// * is_at() which combines X_ Y_ and YX_ into 64-bit and adds a AT_AND
// to enable AND logic. then #define is_atx() and is_aty() onto is_at()
// * maybe the many special cases for bram are better
// tied to no-io columns?
#define X_OUTER_LEFT 0x00000001
#define X_INNER_LEFT 0x00000002
#define X_INNER_RIGHT 0x00000004
#define X_OUTER_RIGHT 0x00000008
#define X_ROUTING_NO_IO 0x00000010
#define X_FABRIC_LOGIC_XM_ROUTING_COL 0x00000020 // logic-xm only
//X_FABRIC_LOGIC_XL_ROUTING_IO
//X_FABRIC_LOGIC_XL_ROUTING_NO_IO
//X_FABRIC_LOGIC_XL_IO
//X_FABRIC_LOGIC_XL_NO_IO
#define X_FABRIC_LOGIC_XL_ROUTING_COL 0x00000040 // logic-xl only
#define X_FABRIC_LOGIC_XM_COL 0x00000080
#define X_FABRIC_LOGIC_XL_COL 0x00000100
#define X_FABRIC_BRAM_ROUTING_COL 0x00000200 // BRAM only
#define X_FABRIC_MACC_ROUTING_COL 0x00000400 // MACC only
#define X_FABRIC_BRAM_VIA_COL 0x00000800 // second routing col for BRAM
#define X_FABRIC_MACC_VIA_COL 0x00001000 // second routing col for MACC
#define X_FABRIC_BRAM_COL 0x00002000
#define X_FABRIC_MACC_COL 0x00004000
#define X_CENTER_ROUTING_COL 0x00008000
#define X_CENTER_LOGIC_COL 0x00010000
#define X_CENTER_CMTPLL_COL 0x00020000
#define X_CENTER_REGS_COL 0x00040000
#define X_LEFT_IO_ROUTING_COL 0x00080000
#define X_LEFT_IO_DEVS_COL 0x00100000
#define X_RIGHT_IO_ROUTING_COL 0x00200000
#define X_RIGHT_IO_DEVS_COL 0x00400000
#define X_LEFT_SIDE 0x00800000 // true for anything left of the center (not including center)
#define X_LEFT_MCB 0x01000000
#define X_RIGHT_MCB 0x02000000
#define IS_TOP_ROW(row, model) ((row) == (model)->cfg_rows-1)
#define IS_BOTTOM_ROW(row, model) ((row) == 0)
#define IS_CENTER_Y(row, model) ((row) == (model)->center_y)
#define BOT_TERM(model) ((model)->y_height-BOT_INNER_ROW)
#define TOP_TERM(model) (TOP_INNER_ROW)
// multiple checks are combined with OR logic
int is_atx(int check, struct fpga_model* model, int x);
// True for all tiles that are in the regular 0..15 row tiles of a routing col
#define YX_ROUTING_TILE 0x0001
#define YX_IO_ROUTING 0x0002
#define YX_ROUTING_TO_FABLOGIC 0x0004 // left of a regular fabric logic device
#define YX_DEV_ILOGIC 0x0008
#define YX_DEV_OLOGIC 0x0010
#define YX_DEV_LOGIC 0x0020
#define YX_DEV_IOB 0x0040
#define YX_CENTER_MIDBUF 0x0080
#define YX_OUTER_TERM 0x0100
#define YX_INNER_TERM 0x0200
// outside_of_routing is true for anything outside of the outer
// boundary of the regular routing area.
#define YX_OUTSIDE_OF_ROUTING 0x0400
#define YX_X_CENTER_CMTPLL 0x0800
#define YX_Y_CENTER 0x1000
#define YX_CENTER 0x2000
int is_atyx(int check, struct fpga_model* model, int y, int x);
// if not in row, both return values (if given) will
// be set to -1. the row_pos is 0..7 for the upper half,
// 8 for the hclk, and 9..16 for the lower half.
void is_in_row(const struct fpga_model* model, int y,
int* row_num, int* row_pos);
// which_row() and pos_in_row() return -1 if y is outside of a row
int which_row(int y, struct fpga_model *model);
int pos_in_row(int y, struct fpga_model *model);
// regular_row_pos() returns the index (0..15) without hclk, or -1 if y is a hclk.
int regular_row_pos(int y, struct fpga_model *model);
int row_to_hclk(int row, struct fpga_model *model);
int y_to_hclk(int y, struct fpga_model *model);
// returns -1 if we are at TOP_FIRST_REGULAR
int regular_row_up(int y, struct fpga_model *model);
const char* logicin_s(int wire, int routing_io);
enum fpgadev_type
{ DEV_NONE = 0,
DEV_LOGIC, DEV_TIEOFF, DEV_MACC, DEV_IOB,
DEV_ILOGIC, DEV_OLOGIC, DEV_IODELAY, DEV_BRAM16, DEV_BRAM8,
DEV_BUFH, DEV_BUFIO, DEV_BUFIO_FB, DEV_BUFPLL, DEV_BUFPLL_MCB,
DEV_BUFGMUX, DEV_BSCAN, DEV_DCM, DEV_PLL, DEV_ICAP,
DEV_POST_CRC_INTERNAL, DEV_STARTUP, DEV_SLAVE_SPI,
DEV_SUSPEND_SYNC, DEV_OCT_CALIBRATE, DEV_SPI_ACCESS,
DEV_DNA, DEV_PMV, DEV_PCILOGIC_SE, DEV_MCB };
#define FPGA_DEV_STR \
{ 0, \
"LOGIC", "TIEOFF", "MACC", "IOB", \
"ILOGIC", "OLOGIC", "IODELAY", "BRAM16", "BRAM8", \
"BUFH", "BUFIO", "BUFIO_FB", "BUFPLL", "BUFPLL_MCB", \
"BUFGMUX", "BSCAN", "DCM", "PLL", "ICAP", \
"POST_CRC_INTERNAL", "STARTUP", "SLAVE_SPI", \
"SUSPEND_SYNC", "OCT_CALIBRATE", "SPI_ACCESS", \
"DNA", "PMV", "PCILOGIC_SE", "MCB" }
// We use two types of device indices, one is a flat index
// into the tile->devs array (dev_idx_t), the other
// one counts up from 0 through devices of one particular
// type in the tile. The first logic device has type_idx == 0,
// the second logic device has type_idx == 1, etc, no matter
// at which index they are in the device array. The type indices
// are used in the floorplan, the flat array indices internally
// in memory.
typedef int dev_idx_t;
typedef int dev_type_idx_t;
#define NO_DEV -1
#define FPGA_DEV(model, y, x, dev_idx) \
(((dev_idx) == NO_DEV) ? 0 : (&YX_TILE(model, y, x)->devs[dev_idx]))
//
// DEV_LOGIC
//
// M and L device is always at type index 0, X device
// is always at type index 1.
#define DEV_LOG_M_OR_L 0
#define DEV_LOG_X 1
// All device configuration is structured so that the value
// 0 is never a valid configured setting. That way all config
// data can safely be initialized to 0 meaning unconfigured.
enum { LOGIC_M = 1, LOGIC_L, LOGIC_X };
// LD1 stands for logic device 1 and can be OR'ed to the LI_A1
// or LO_A values to indicate the second logic device in a tile,
// either an M or L device.
#define LD1 0x100
// All LOGICIN_IN A..D sequences must be exactly sequential as
// here to match initialization in model_devices.c:init_logic()
// and control.c:fdev_set_required_pins().
enum {
// input:
LI_FIRST = 0,
LI_A1 = LI_FIRST, LI_A2, LI_A3, LI_A4, LI_A5, LI_A6,
LI_B1, LI_B2, LI_B3, LI_B4, LI_B5, LI_B6,
LI_C1, LI_C2, LI_C3, LI_C4, LI_C5, LI_C6,
LI_D1, LI_D2, LI_D3, LI_D4, LI_D5, LI_D6,
LI_AX, LI_BX, LI_CX, LI_DX,
LI_CLK, LI_CE, LI_SR,
// only for L and M:
LI_CIN,
// only for M:
LI_WE, LI_AI, LI_BI, LI_CI, LI_DI,
LI_LAST = LI_DI,
// output:
LO_FIRST,
LO_A = LO_FIRST, LO_B, LO_C, LO_D,
LO_AMUX, LO_BMUX, LO_CMUX, LO_DMUX,
LO_AQ, LO_BQ, LO_CQ, LO_DQ,
LO_COUT, // only some L and M devs have this
LO_LAST = LO_COUT };
#define LOGIC_PINW_STR \
{ "A1", "A2", "A3", "A4", "A5", "A6", \
"B1", "B2", "B3", "B4", "B5", "B6", \
"C1", "C2", "C3", "C4", "C5", "C6", \
"D1", "D2", "D3", "D4", "D5", "D6", \
"AX", "BX", "CX", "DX", \
"CLK", "CE", "SR", \
"CIN", \
"WE", "AI", "BI", "CI", "DI", \
"A", "B", "C", "D", \
"AMUX", "BMUX", "CMUX", "DMUX", \
"AQ", "BQ", "CQ", "DQ", \
"COUT" }
enum { LUT_A = 0, LUT_B, LUT_C, LUT_D }; // offset into a2d[]
enum { FF_SRINIT0 = 1, FF_SRINIT1 };
enum { MUX_O6 = 1, MUX_O5, MUX_5Q, MUX_X, MUX_CY, MUX_XOR, MUX_F7, MUX_F8, MUX_MC31 };
enum { FF_OR2L = 1, FF_AND2L, FF_LATCH, FF_FF };
enum { CY0_X = 1, CY0_O5 };
enum { CLKINV_B = 1, CLKINV_CLK };
enum { SYNCATTR_SYNC = 1, SYNCATTR_ASYNC };
enum { WEMUX_WE = 1, WEMUX_CE };
enum { PRECYINIT_0 = 1, PRECYINIT_1, PRECYINIT_AX };
#define MAX_LUT_LEN 2048
#define NUM_LUTS 4
struct fpgadev_logic_a2d
{
int out_used;
char* lut6;
char* lut5;
int ff_mux; // O6, O5, X, F7(a/c), F8(b), MC31(d), CY, XOR
int ff_srinit; // SRINIT0, SRINIT1
int ff5_srinit; // SRINIT0, SRINIT1
int out_mux; // O6, O5, 5Q, F7(a/c), F8(b), MC31(d), CY, XOR
int ff; // OR2L, AND2L, LATCH, FF
int cy0; // X, O5
};
struct fpgadev_logic
{
struct fpgadev_logic_a2d a2d[NUM_LUTS];
int clk_inv; // CLKINV_B, CLKINV_CLK
int sync_attr; // SYNCATTR_SYNC, SYNCATTR_ASYNC
int ce_used;
int sr_used;
int we_mux; // WEMUX_WE, WEMUX_CE
int cout_used;
int precyinit; // PRECYINIT_0, PRECYINIT_1, PRECYINIT_AX
};
//
// DEV_IOB
//
enum { IOBM = 1, IOBS };
typedef char IOSTANDARD[32];
#define IO_LVTTL "LVTTL"
#define IO_LVCMOS33 "LVCMOS33"
#define IO_LVCMOS25 "LVCMOS25"
#define IO_LVCMOS18 "LVCMOS18"
#define IO_LVCMOS18_JEDEC "LVCMOS18_JEDEC"
#define IO_LVCMOS15 "LVCMOS15"
#define IO_LVCMOS15_JEDEC "LVCMOS15_JEDEC"
#define IO_LVCMOS12 "LVCMOS12"
#define IO_LVCMOS12_JEDEC "LVCMOS12_JEDEC"
#define IO_SSTL2_I "SSTL2_I" // TODO: sstl not fully supported
enum { BYPASS_MUX_I = 1, BYPASS_MUX_O, BYPASS_MUX_T };
enum { IMUX_I_B = 1, IMUX_I };
enum { SLEW_SLOW = 1, SLEW_FAST, SLEW_QUIETIO };
enum { SUSP_LAST_VAL = 1, SUSP_3STATE, SUSP_3STATE_PULLUP,
SUSP_3STATE_PULLDOWN, SUSP_3STATE_KEEPER, SUSP_3STATE_OCT_ON };
enum { ITERM_NONE = 1, ITERM_UNTUNED_25, ITERM_UNTUNED_50,
ITERM_UNTUNED_75 };
enum { OTERM_NONE = 1, OTERM_UNTUNED_25, OTERM_UNTUNED_50,
OTERM_UNTUNED_75 };
enum { // input:
IOB_IN_O = 0, IOB_IN_T, IOB_IN_DIFFI_IN, IOB_IN_DIFFO_IN,
// output:
IOB_OUT_I, IOB_OUT_PADOUT, IOB_OUT_PCI_RDY, IOB_OUT_DIFFO_OUT };
#define IOB_LAST_INPUT_PINW IOB_IN_DIFFO_IN
#define IOB_LAST_OUTPUT_PINW IOB_OUT_DIFFO_OUT
#define IOB_PINW_STR \
{ "O", "T", "DIFFI_IN", "DIFFO_IN", \
"I", "PADOUT", "PCI_RDY", "DIFFO_OUT" }
struct fpgadev_iob
{
IOSTANDARD istandard;
IOSTANDARD ostandard;
int bypass_mux;
int I_mux;
int drive_strength; // supports 2,4,6,8,12,16 and 24
int slew;
int O_used;
int suspend;
int in_term;
int out_term;
};
//
// DEV_BUFGMUX
//
enum { BUFG_CLK_ASYNC = 1, BUFG_CLK_SYNC };
enum { BUFG_DISATTR_LOW = 1, BUFG_DISATTR_HIGH };
enum { BUFG_SINV_N = 1, BUFG_SINV_Y };
struct fpgadev_bufgmux
{
int clk;
int disable_attr;
int s_inv;
};
//
// DEV_BUFIO
//
enum { BUFIO_DIVIDEBP_N = 1, BUFIO_DIVIDEBP_Y };
enum { BUFIO_IINV_N = 1, BUFIO_IINV_Y };
struct fpgadev_bufio
{
int divide;
int divide_bypass;
int i_inv;
};
//
// DEV_BSCAN
//
enum { BSCAN_JTAG_TEST_N = 1, BSCAN_JTAG_TEST_Y };
struct fpgadev_bscan
{
int jtag_chain; // 1-4
int jtag_test;
};
//
// DEV_BRAM
//
// B8_0 or B8_1 can be or'ed into the BI/BO values
// to designate the first and second BRAM8 device,
// instead of the default BRAM16 device.
#define B8_0 0x100
#define B8_1 0x200
#define BW_FLAGS (B8_0|B8_1)
enum {
// input:
BI_FIRST = 0,
// port A
BI_ADDRA0 = BI_FIRST, BI_ADDRA1, BI_ADDRA2, BI_ADDRA3, BI_ADDRA4, BI_ADDRA5,
BI_ADDRA6, BI_ADDRA7, BI_ADDRA8, BI_ADDRA9, BI_ADDRA10, BI_ADDRA11,
BI_ADDRA12, BI_ADDRA13,
BI_DIA0, BI_DIA1, BI_DIA2, BI_DIA3, BI_DIA4, BI_DIA5,
BI_DIA6, BI_DIA7, BI_DIA8, BI_DIA9, BI_DIA10, BI_DIA11,
BI_DIA12, BI_DIA13, BI_DIA14, BI_DIA15, BI_DIA16, BI_DIA17,
BI_DIA18, BI_DIA19, BI_DIA20, BI_DIA21, BI_DIA22, BI_DIA23,
BI_DIA24, BI_DIA25, BI_DIA26, BI_DIA27, BI_DIA28, BI_DIA29,
BI_DIA30, BI_DIA31,
BI_DIPA0, BI_DIPA1, BI_DIPA2, BI_DIPA3,
BI_WEA0, BI_WEA1, BI_WEA2, BI_WEA3,
BI_REGCEA,
BI_ENA,
// port B
BI_ADDRB0, BI_ADDRB1, BI_ADDRB2, BI_ADDRB3, BI_ADDRB4, BI_ADDRB5,
BI_ADDRB6, BI_ADDRB7, BI_ADDRB8, BI_ADDRB9, BI_ADDRB10, BI_ADDRB11,
BI_ADDRB12, BI_ADDRB13,
BI_DIB0, BI_DIB1, BI_DIB2, BI_DIB3, BI_DIB4, BI_DIB5,
BI_DIB6, BI_DIB7, BI_DIB8, BI_DIB9, BI_DIB10, BI_DIB11,
BI_DIB12, BI_DIB13, BI_DIB14, BI_DIB15, BI_DIB16, BI_DIB17,
BI_DIB18, BI_DIB19, BI_DIB20, BI_DIB21, BI_DIB22, BI_DIB23,
BI_DIB24, BI_DIB25, BI_DIB26, BI_DIB27, BI_DIB28, BI_DIB29,
BI_DIB30, BI_DIB31,
BI_DIPB0, BI_DIPB1, BI_DIPB2, BI_DIPB3,
BI_WEB0, BI_WEB1, BI_WEB2, BI_WEB3,
BI_REGCEB,
BI_ENB,
BI_LAST = BI_ENB,
// output:
BO_FIRST,
// port A
BO_DOA0 = BO_FIRST, BO_DOA1, BO_DOA2, BO_DOA3, BO_DOA4, BO_DOA5,
BO_DOA6, BO_DOA7, BO_DOA8, BO_DOA9, BO_DOA10, BO_DOA11,
BO_DOA12, BO_DOA13, BO_DOA14, BO_DOA15, BO_DOA16, BO_DOA17,
BO_DOA18, BO_DOA19, BO_DOA20, BO_DOA21, BO_DOA22, BO_DOA23,
BO_DOA24, BO_DOA25, BO_DOA26, BO_DOA27, BO_DOA28, BO_DOA29,
BO_DOA30, BO_DOA31,
BO_DOPA0, BO_DOPA1, BO_DOPA2, BO_DOPA3,
// port B
BO_DOB0, BO_DOB1, BO_DOB2, BO_DOB3, BO_DOB4, BO_DOB5,
BO_DOB6, BO_DOB7, BO_DOB8, BO_DOB9, BO_DOB10, BO_DOB11,
BO_DOB12, BO_DOB13, BO_DOB14, BO_DOB15, BO_DOB16, BO_DOB17,
BO_DOB18, BO_DOB19, BO_DOB20, BO_DOB21, BO_DOB22, BO_DOB23,
BO_DOB24, BO_DOB25, BO_DOB26, BO_DOB27, BO_DOB28, BO_DOB29,
BO_DOB30, BO_DOB31,
BO_DOPB0, BO_DOPB1, BO_DOPB2, BO_DOPB3,
BO_LAST = BO_DOPB3
};
//
// DEV_MACC
//
enum {
// input:
MI_FIRST = 0,
MI_CEA = MI_FIRST, MI_CEB, MI_CEC, MI_CED, MI_CEM, MI_CEP,
MI_CE_OPMODE, MI_CE_CARRYIN,
MI_OPMODE0, MI_OPMODE1, MI_OPMODE2, MI_OPMODE3,
MI_OPMODE4, MI_OPMODE5, MI_OPMODE6, MI_OPMODE7,
MI_A0, MI_A1, MI_A2, MI_A3, MI_A4, MI_A5, MI_A6, MI_A7,
MI_A8, MI_A9, MI_A10, MI_A11, MI_A12, MI_A13, MI_A14, MI_A15,
MI_A16, MI_A17,
MI_B0, MI_B1, MI_B2, MI_B3, MI_B4, MI_B5, MI_B6, MI_B7,
MI_B8, MI_B9, MI_B10, MI_B11, MI_B12, MI_B13, MI_B14, MI_B15,
MI_B16, MI_B17,
MI_C0, MI_C1, MI_C2, MI_C3, MI_C4, MI_C5, MI_C6, MI_C7,
MI_C8, MI_C9, MI_C10, MI_C11, MI_C12, MI_C13, MI_C14, MI_C15,
MI_C16, MI_C17, MI_C18, MI_C19, MI_C20, MI_C21, MI_C22, MI_C23,
MI_C24, MI_C25, MI_C26, MI_C27, MI_C28, MI_C29, MI_C30, MI_C31,
MI_C32, MI_C33, MI_C34, MI_C35, MI_C36, MI_C37, MI_C38, MI_C39,
MI_C40, MI_C41, MI_C42, MI_C43, MI_C44, MI_C45, MI_C46, MI_C47,
MI_D0, MI_D1, MI_D2, MI_D3, MI_D4, MI_D5, MI_D6, MI_D7,
MI_D8, MI_D9, MI_D10, MI_D11, MI_D12, MI_D13, MI_D14, MI_D15,
MI_D16, MI_D17,
MI_LAST = MI_D17,
// output:
MO_FIRST,
MO_CARRYOUT = MO_FIRST,
MO_P0, MO_P1, MO_P2, MO_P3, MO_P4, MO_P5, MO_P6, MO_P7,
MO_P8, MO_P9, MO_P10, MO_P11, MO_P12, MO_P13, MO_P14, MO_P15,
MO_P16, MO_P17, MO_P18, MO_P19, MO_P20, MO_P21, MO_P22, MO_P23,
MO_P24, MO_P25, MO_P26, MO_P27, MO_P28, MO_P29, MO_P30, MO_P31,
MO_P32, MO_P33, MO_P34, MO_P35, MO_P36, MO_P37, MO_P38, MO_P39,
MO_P40, MO_P41, MO_P42, MO_P43, MO_P44, MO_P45, MO_P46, MO_P47,
MO_M0, MO_M1, MO_M2, MO_M3, MO_M4, MO_M5, MO_M6, MO_M7,
MO_M8, MO_M9, MO_M10, MO_M11, MO_M12, MO_M13, MO_M14, MO_M15,
MO_M16, MO_M17, MO_M18, MO_M19, MO_M20, MO_M21, MO_M22, MO_M23,
MO_M24, MO_M25, MO_M26, MO_M27, MO_M28, MO_M29, MO_M30, MO_M31,
MO_M32, MO_M33, MO_M34, MO_M35,
MO_LAST = MO_M35
};
//
// fpga_device
//
typedef int pinw_idx_t; // index into pinw array
// A bram dev has about 190 pinwires (input and output
// combined), macc about 350, mcb about 1200.
#define MAX_NUM_PINW 2048
struct fpga_device
{
enum fpgadev_type type;
// subtypes:
// IOB: IOBM, IOBS
// LOGIC: LOGIC_M, LOGIC_L, LOGIC_X
int subtype;
int instantiated;
int num_pinw_total, num_pinw_in;
// The array holds first the input wires, then the output wires.
// Unused members are set to STRIDX_NO_ENTRY.
str16_t* pinw;
// required pinwires depend on the given config and will
// be deleted/invalidated on any config change.
int pinw_req_total, pinw_req_in;
pinw_idx_t* pinw_req_for_cfg;
// the rest will be memset to 0 on any device removal/uninstantiation
union {
struct fpgadev_logic logic;
struct fpgadev_iob iob;
struct fpgadev_bufgmux bufgmux;
struct fpgadev_bufio bufio;
struct fpgadev_bscan bscan;
} u;
};
#define SWITCH_USED 0x80000000
#define SWITCH_BIDIRECTIONAL 0x40000000
#define SWITCH_MAX_CONNPT_O 0x7FFF // 15 bits
#define SW_FROM_I(u32) (((u32) >> 15) & SWITCH_MAX_CONNPT_O)
#define SW_TO_I(u32) ((u32) & SWITCH_MAX_CONNPT_O)
#define SW_I(u32, from_to) ((from_to) ? SW_FROM_I(u32) : SW_TO_I(u32))
// SW_FROM and SW_TO values are chosen such that ! inverts them,
// and swf() assumes that SW_FROM is positive.
#define SW_FROM 1
#define SW_TO 0
#define NO_SWITCH -1
// FIRST_SW must be high enough to be above switch indices or
// connpt or str16.
#define FIRST_SW 0x80000
#define NO_CONN -1
typedef int connpt_t; // index into conn_point_names (not yet *2)
#define CONNPT_STR16(tile, connpt) ((tile)->conn_point_names[(connpt)*2+1])
struct fpga_tile
{
enum fpga_tile_type type;
int flags;
// expect up to 64 devices per tile
int num_devs;
struct fpga_device* devs;
// expect up to 5k connection point names per tile
// 2*16 bit per entry
// - index into conn_point_dests (not multiplied by 3) (16bit)
// - hashed string array index (16 bit)
// each conn point name exists only once in the array
int num_conn_point_names; // conn_point_names is 2*num_conn_point_names 16-bit words
uint16_t* conn_point_names; // num_conn_point_names*2 16-bit-words: 16(conn)-16(str)
// expect up to 28k connection point destinations to other tiles per tile
// 3*16 bit per destination:
// - x coordinate of other tile (16bit)
// - y coordinate of other tile (16bit)
// - hashed string array index for conn_point_names name in other tile (16bit)
int num_conn_point_dests; // conn_point_dests array is 3*num_conn_point_dests 16-bit words
uint16_t* conn_point_dests; // num_conn_point_dests*3 16-bit words: 16(x)-16(y)-16(conn_name)
// expect up to 4k switches per tile
// 32bit: 31 off: no connection on: connected
// 30 off: unidirectional on: bidirectional
// 29:15 from, index into conn_point_names (not yet *2)
// 14:0 to, index into conn_point_names (not yet *2)
int num_switches;
uint32_t* switches;
};
int fpga_build_model(struct fpga_model* model, int idcode, enum xc6_pkg pkg);
// returns model->rc (model itself will be memset to 0)
int fpga_free_model(struct fpga_model* model);
const char* fpga_tiletype_str(enum fpga_tile_type type);
int init_tiles(struct fpga_model* model);
int init_devices(struct fpga_model* model);
void free_devices(struct fpga_model* model);
int init_ports(struct fpga_model* model, int dup_warn);
int init_conns(struct fpga_model* model);
int init_switches(struct fpga_model* model, int routing_sw);
// replicate_routing_switches() is a high-speed optimized way to
// initialize the routing switches, will only work before ports,
// connections or other switches.
int replicate_routing_switches(struct fpga_model* model);
const char* pf(const char* fmt, ...);
const char* wpref(struct fpga_model* model, int y, int x, const char* wire_name);
char next_non_whitespace(const char* s);
char last_major(const char* str, int cur_o);
int has_connpt(struct fpga_model* model, int y, int x, const char* name);
// add_connpt_name(): name_i and conn_point_o can be 0
int add_connpt_name(struct fpga_model* model, int y, int x,
const char* connpt_name, int warn_if_duplicate, uint16_t* name_i,
int* conn_point_o);
// has_device() and has_device_type() return the number of devices
// for the given type or type/subtype.
int has_device(struct fpga_model* model, int y, int x, int dev);
int has_device_type(struct fpga_model* model, int y, int x, int dev, int subtype);
int add_connpt_2(struct fpga_model* model, int y, int x,
const char* connpt_name, const char* suffix1, const char* suffix2,
int dup_warn);
typedef int (*add_conn_f)(struct fpga_model* model,
int y1, int x1, const char* name1,
int y2, int x2, const char* name2);
#define NOPREF_BI_F add_conn_bi
#define PREF_BI_F add_conn_bi_pref
int add_conn_bi(struct fpga_model* model,
int y1, int x1, const char* name1,
int y2, int x2, const char* name2);
int add_conn_bi_pref(struct fpga_model* model,
int y1, int x1, const char* name1,
int y2, int x2, const char* name2);
int add_conn_range(struct fpga_model* model, add_conn_f add_conn_func,
int y1, int x1, const char* name1, int start1, int last1,
int y2, int x2, const char* name2, int start2);
//
// switches
//
int add_switch(struct fpga_model* model, int y, int x, const char* from,
const char* to, int is_bidirectional);
int add_switch_set(struct fpga_model* model, int y, int x, const char* prefix,
const char** pairs, int suffix_inc);
// This will replicate the entire conn_point_names and switches arrays
// from one tile to another, assuming that all of conn_point_names,
// switches and conn_point_dests in the destination tile are empty.
int replicate_switches_and_names(struct fpga_model* model,
int y_from, int x_from, int y_to, int x_to);
struct seed_data
{
int flags;
const char* str;
};
void seed_strx(struct fpga_model *model, const struct seed_data *data);
void seed_stry(struct fpga_model *model, const struct seed_data *data);
#define MAX_WIRENAME_LEN 64
// The LWF flags are OR'ed into the logic_wire enum
#define LWF_SOUTH0 0x0100
#define LWF_NORTH3 0x0200
#define LWF_BIDIR 0x0400
#define LWF_FAN_B 0x0800
#define LWF_WIRE_MASK 0x00FF // namespace for the enums
// ordered to match the LOGICIN_B?? enumeration
// todo: both enums logicin_wire and logicout_wire are not really
// ideal for supporting L_ and XX_ variants, maybe use pinwires
// and LD1 instead?
enum logicin_wire {
/* 0 */ X_A1 = 0,
X_A2, X_A3, X_A4, X_A5, X_A6, X_AX,
/* 7 */ X_B1, X_B2, X_B3, X_B4, X_B5, X_B6, X_BX,
/* 14 */ X_C1, X_C2, X_C3, X_C4, X_C5, X_C6, X_CE, X_CX,
/* 22 */ X_D1, X_D2, X_D3, X_D4, X_D5, X_D6, X_DX,
/* 29 */ M_A1, M_A2, M_A3, M_A4, M_A5, M_A6, M_AX, M_AI,
/* 37 */ M_B1, M_B2, M_B3, M_B4, M_B5, M_B6, M_BX, M_BI,
/* 45 */ M_C1, M_C2, M_C3, M_C4, M_C5, M_C6, M_CE, M_CX, M_CI,
/* 54 */ M_D1, M_D2, M_D3, M_D4, M_D5, M_D6, M_DX, M_DI,
/* 62 */ M_WE
};
// ordered to match the LOGICOUT_B?? enumeration
enum logicout_wire {
/* 0 */ X_A = 0,
X_AMUX, X_AQ, X_B, X_BMUX, X_BQ,
/* 6 */ X_C, X_CMUX, X_CQ, X_D, X_DMUX, X_DQ,
/* 12 */ M_A, M_AMUX, M_AQ, M_B, M_BMUX, M_BQ,
/* 18 */ M_C, M_CMUX, M_CQ, M_D, M_DMUX, M_DQ
};
const char* logicin_str(enum logicin_wire w);
const char* logicout_str(enum logicout_wire w);
// The wires are ordered clockwise. Order is important for
// wire_to_NESW4().
enum wire_type
{
FIRST_LEN1 = 1,
W_NL1 = FIRST_LEN1,
W_NR1,
W_EL1,
W_ER1,
W_SL1,
W_SR1,
W_WL1,
W_WR1,
LAST_LEN1 = W_WR1,
FIRST_LEN2,
W_NN2 = FIRST_LEN2,
W_NE2,
W_EE2,
W_SE2,
W_SS2,
W_SW2,
W_WW2,
W_NW2,
LAST_LEN2 = W_NW2,
FIRST_LEN4,
W_NN4 = FIRST_LEN4,
W_NE4,
W_EE4,
W_SE4,
W_SS4,
W_SW4,
W_WW4,
W_NW4,
LAST_LEN4 = W_NW4
};
#define W_CLOCKWISE(w) rotate_wire((w), 1)
#define W_CLOCKWISE_2(w) rotate_wire((w), 2)
#define W_COUNTER_CLOCKWISE(w) rotate_wire((w), -1)
#define W_COUNTER_CLOCKWISE_2(w) rotate_wire((w), -2)
#define W_IS_LEN1(w) ((w) >= FIRST_LEN1 && (w) <= LAST_LEN1)
#define W_IS_LEN2(w) ((w) >= FIRST_LEN2 && (w) <= LAST_LEN2)
#define W_IS_LEN4(w) ((w) >= FIRST_LEN4 && (w) <= LAST_LEN4)
#define W_TO_LEN1(w) wire_to_len(w, FIRST_LEN1)
#define W_TO_LEN2(w) wire_to_len(w, FIRST_LEN2)
#define W_TO_LEN4(w) wire_to_len(w, FIRST_LEN4)
const char* wire_base(enum wire_type w);
enum wire_type base2wire(const char* str);
enum wire_type rotate_wire(enum wire_type cur, int off);
enum wire_type wire_to_len(enum wire_type w, int first_len);
// These three flags can be OR'ed into the DW..DW_LAST range.
// DIR_BEG signals a 'B' line - the default is 'E' endpoint.
// DIR_S0 turns 0 into _S0
// DIR_N3 turns 3 into _N3.
// First flag must be higher than LAST_LEN4 (25) * 4 + 3 = 103
#define DIR_BEG 0x80
#define DIR_S0 0x100
#define DIR_N3 0x200
#define DIR_FLAGS (DIR_BEG|DIR_S0|DIR_N3)
// some more direction-related macros mostly to make code
// more readable and not directly related to enum extra_wires.
#define DIR_IN 0
#define DIR_OUT 1
#define DIR_POS +1
#define DIR_NEG -1
#define DIR_LEFT DIR_NEG
#define DIR_RIGHT DIR_POS
#define DIR_UP DIR_NEG
#define DIR_DOWN DIR_POS
enum { DIR_NORTH = 0, DIR_EAST, DIR_SOUTH, DIR_WEST };
#define LOGICOUT_HIGHEST 23
#define LOGICIN_HIGHEST 62
// The extra wires must not overlap with logicin_wire or logicout_wire
// namespaces so that they can be combined with either of them.
enum extra_wires {
// NO_WIRE is not compatible with the old X_A1/M_A1 system, but
// compatible with the new LW + LI_A1 system.
NO_WIRE = 0,
UNDEF = 100, // use UNDEF with old system, can be removed after
// old system is gone
FAN_B,
GFAN0,
GFAN1,
CLK0, // == clka for bram
CLK1, // == clkb for bram
SR0, // == rsta for bram
SR1, // == rstb for bram
LOGICIN20,
LOGICIN21,
LOGICIN44,
LOGICIN52,
LOGICIN_N21,
LOGICIN_N28,
LOGICIN_N52,
LOGICIN_N60,
LOGICIN_S20,
LOGICIN_S36,
LOGICIN_S44,
LOGICIN_S62,
IOCE,
IOCLK,
PLLCE,
PLLCLK,
CKPIN,
CLK_FEEDBACK,
CLK_INDIRECT,
CFB0, CFB1, CFB2, CFB3, CFB4, CFB5, CFB6, CFB7,
CFB8, CFB9, CFB10, CFB11, CFB12, CFB13, CFB14, CFB15,
DFB0, DFB1, DFB2, DFB3, DFB4, DFB5, DFB6, DFB7,
CLKPIN0, CLKPIN1, CLKPIN2, CLKPIN3, CLKPIN4, CLKPIN5, CLKPIN6, CLKPIN7,
DQSN0, DQSN1, DQSN2, DQSN3,
DQSP0, DQSP1, DQSP2, DQSP3,
VCC_WIRE,
GND_WIRE,
GCLK0, GCLK1, GCLK2, GCLK3, GCLK4, GCLK5, GCLK6, GCLK7,
GCLK8, GCLK9, GCLK10, GCLK11, GCLK12, GCLK13, GCLK14, GCLK15,
LOGICOUT_B0, LOGICOUT_B1, LOGICOUT_B2, LOGICOUT_B3,
LOGICOUT_B4, LOGICOUT_B5, LOGICOUT_B6, LOGICOUT_B7,
LOGICOUT_B8, LOGICOUT_B9, LOGICOUT_B10, LOGICOUT_B11,
LOGICOUT_B12, LOGICOUT_B13, LOGICOUT_B14, LOGICOUT_B15,
LOGICOUT_B16, LOGICOUT_B17, LOGICOUT_B18, LOGICOUT_B19,
LOGICOUT_B20, LOGICOUT_B21, LOGICOUT_B22, LOGICOUT_B23,
LOGICIN_B0, LOGICIN_B1, LOGICIN_B2, LOGICIN_B3,
LOGICIN_B4, LOGICIN_B5, LOGICIN_B6, LOGICIN_B7,
LOGICIN_B8, LOGICIN_B9, LOGICIN_B10, LOGICIN_B11,
LOGICIN_B12, LOGICIN_B13, LOGICIN_B14, LOGICIN_B15,
LOGICIN_B16, LOGICIN_B17, LOGICIN_B18, LOGICIN_B19,
LOGICIN_B20, LOGICIN_B21, LOGICIN_B22, LOGICIN_B23,
LOGICIN_B24, LOGICIN_B25, LOGICIN_B26, LOGICIN_B27,
LOGICIN_B28, LOGICIN_B29, LOGICIN_B30, LOGICIN_B31,
LOGICIN_B32, LOGICIN_B33, LOGICIN_B34, LOGICIN_B35,
LOGICIN_B36, LOGICIN_B37, LOGICIN_B38, LOGICIN_B39,
LOGICIN_B40, LOGICIN_B41, LOGICIN_B42, LOGICIN_B43,
LOGICIN_B44, LOGICIN_B45, LOGICIN_B46, LOGICIN_B47,
LOGICIN_B48, LOGICIN_B49, LOGICIN_B50, LOGICIN_B51,
LOGICIN_B52, LOGICIN_B53, LOGICIN_B54, LOGICIN_B55,
LOGICIN_B56, LOGICIN_B57, LOGICIN_B58, LOGICIN_B59,
LOGICIN_B60, LOGICIN_B61, LOGICIN_B62,
// direction wires
DW = 500,
// dirwires can be encoded times-4, for example
// NL1E2 = DW + W_NL1*4 + 2
// DIR_BEG and DIR_S0N3 can be OR'ed into this range.
DW_LAST = 1499,
// logic wires
LW,
// logic wires are encoded here as LOGIC_BEG+LI_A1. LD1 (0x100)
// can be OR'ed to the LI or LO value.
LW_LAST = 1999,
// bram wires are BW + (BI_/BO_, ORed with B8_0(0x100) or B8_1(0x200))
BW,
BW_LAST = 2999,
// macc wires are MW + MI_/MO_
MW,
MW_LAST = 3499,
};
const char *fpga_connpt_str(struct fpga_model *model, enum extra_wires wire,
int y, int x, int dest_y, int dest_x);
const char* fpga_wire2str(enum extra_wires wire);
str16_t fpga_wire2str_i(struct fpga_model* model, enum extra_wires wire);
enum extra_wires fpga_str2wire(const char* str);
int fdev_logic_inbit(pinw_idx_t idx);
int fdev_logic_outbit(pinw_idx_t idx);
// physically, tile3 is at the top, tile0 at the bottom
// errors are returned as -1 in tile0_to_3
void fdev_bram_inbit(enum extra_wires wire, int* tile0_to_3, int* wire0_to_62);
void fdev_bram_outbit(enum extra_wires wire, int* tile0_to_3, int* wire0_to_23);
int fdev_is_bram8_inwire(int bi_wire); // direct BI_ value
int fdev_is_bram8_outwire(int bo_wire); // direct BO_ value
void fdev_macc_inbit(enum extra_wires wire, int* tile0_to_3, int* wire0_to_62);
void fdev_macc_outbit(enum extra_wires wire, int* tile0_to_3, int* wire0_to_23);
//
// integer-based net (w_net_i)
//
struct w_yx { int y, x; };
#define MAX_NET_I_YX 128
struct w_net_i
{
enum extra_wires wire;
int wire_inc; // 0 = no-inc, 1 = wire+0 and wire+1, etc.
int num_yx;
struct w_yx yx[MAX_NET_I_YX];
};
int add_conn_net_i(struct fpga_model *model, const struct w_net_i *net);
//
// string-based net (w_net)
//
// COUNT_DOWN can be OR'ed to start_count to make
// the enumerated wires count from start_count down.
#define COUNT_DOWN 0x100
#define COUNT_MASK 0xFF
struct w_point // wire point
{
const char* name;
int start_count; // if there is a %i in the name, this is the start number
int y, x;
};
#define NO_INCREMENT 0
#define MAX_NET_POINTS 128
struct w_net
{
// if !last_inc, no incrementing will happen (NO_INCREMENT)
// if last_inc > 0, incrementing will happen to
// the %i in the name from pt.start_count:last_inc
int last_inc;
int num_pts;
struct w_point pt[MAX_NET_POINTS];
};
#define NO_PREF 0
#define ADD_PREF 1
int add_conn_net(struct fpga_model* model, int add_pref, const struct w_net *net);
fpgatools-201212/libs/model_conns.c 0000664 0000000 0000000 00000505613 12065743015 0017213 0 ustar 00root root 0000000 0000000 //
// Author: Wolfgang Spraul
//
// This is free and unencumbered software released into the public domain.
// For details see the UNLICENSE file at the root of the source tree.
//
#include
#include "model.h"
static int bufpll(struct fpga_model *model);
static int reg_ioclk(struct fpga_model *model);
static int reg_lock(struct fpga_model *model);
static int reg_pll_dcm(struct fpga_model *model);
static int gtp(struct fpga_model *model);
static int pci(struct fpga_model *model);
static int macc(struct fpga_model *model);
static int clkc(struct fpga_model *model);
static int mui(struct fpga_model *model);
static int cfb_dfb_clkpin_dqsn_dqsp(struct fpga_model *model);
static int pcice(struct fpga_model *model);
static int term_topbot(struct fpga_model *model);
static int term_leftright(struct fpga_model *model);
static int term_to_io(struct fpga_model *model, enum extra_wires wire);
static int clkpll(struct fpga_model *model);
static int ckpin(struct fpga_model *model);
static int clkindirect_feedback(struct fpga_model *model, enum extra_wires wire);
static int run_gclk(struct fpga_model *model);
static int run_gclk_horiz_regs(struct fpga_model *model);
static int run_gclk_vert_regs(struct fpga_model *model);
static int run_logic_inout(struct fpga_model *model);
static int run_io_wires(struct fpga_model *model);
static int run_gfan(struct fpga_model *model);
static int connect_clk_sr(struct fpga_model *model, const char *clk_sr);
static int connect_logic_carry(struct fpga_model *model);
static int run_dirwires(struct fpga_model *model);
int init_conns(struct fpga_model *model)
{
RC_CHECK(model);
bufpll(model);
reg_ioclk(model);
reg_lock(model);
reg_pll_dcm(model);
gtp(model);
macc(model);
clkc(model);
mui(model);
cfb_dfb_clkpin_dqsn_dqsp(model);
pci(model);
pcice(model);
term_topbot(model);
term_leftright(model);
term_to_io(model, IOCE);
term_to_io(model, IOCLK);
term_to_io(model, PLLCE);
term_to_io(model, PLLCLK);
clkpll(model);
ckpin(model);
clkindirect_feedback(model, CLK_INDIRECT);
clkindirect_feedback(model, CLK_FEEDBACK);
run_gclk(model);
run_gclk_horiz_regs(model);
run_gclk_vert_regs(model);
connect_logic_carry(model);
connect_clk_sr(model, "CLK");
connect_clk_sr(model, "SR");
run_gfan(model);
run_io_wires(model);
run_logic_inout(model);
// it's a little faster to do the dirwires last
run_dirwires(model);
RC_RETURN(model);
}
static int bufpll_x(struct fpga_model *model, int x)
{
RC_CHECK(model);
add_switch(model, model->center_y-CENTER_Y_MINUS_2, x,
"CLK0", "INT_BUFPLL_GCLK2", /*bidir*/ 0);
add_switch(model, model->center_y-CENTER_Y_MINUS_2, x,
"CLK1", "INT_BUFPLL_GCLK3", /*bidir*/ 0);
add_switch(model, model->center_y-CENTER_Y_MINUS_1, x,
"CLK0", "INT_BUFPLL_GCLK0", /*bidir*/ 0);
add_switch(model, model->center_y-CENTER_Y_MINUS_1, x,
"CLK1", "INT_BUFPLL_GCLK1", /*bidir*/ 0);
RC_RETURN(model);
}
static int bufpll(struct fpga_model *model)
{
RC_CHECK(model);
bufpll_x(model, LEFT_IO_ROUTING);
bufpll_x(model, model->x_width-RIGHT_IO_ROUTING_O);
RC_RETURN(model);
}
static int find_pll_dcm_y(struct fpga_model *model,
int *top_pll_y, int *top_dcm_y,
int *bot_pll_y, int *bot_dcm_y)
{
int y;
*top_pll_y = *top_dcm_y = *bot_pll_y = *bot_dcm_y = -1;
RC_CHECK(model);
for (y = TOP_FIRST_REGULAR; y <= model->y_height - BOT_LAST_REGULAR_O; y++) {
if (y < model->center_y
&& has_device(model, y, model->center_x-CENTER_CMTPLL_O, DEV_PLL)) {
RC_ASSERT(model, *top_pll_y == -1);
*top_pll_y = y;
} else if (y < model->center_y
&& has_device(model, y, model->center_x-CENTER_CMTPLL_O, DEV_DCM)) {
RC_ASSERT(model, *top_dcm_y == -1);
*top_dcm_y = y;
} else if (y > model->center_y
&& has_device(model, y, model->center_x-CENTER_CMTPLL_O, DEV_PLL)) {
RC_ASSERT(model, *bot_pll_y == -1);
*bot_pll_y = y;
} else if (y > model->center_y
&& has_device(model, y, model->center_x-CENTER_CMTPLL_O, DEV_DCM)) {
RC_ASSERT(model, *bot_dcm_y == -1);
*bot_dcm_y = y;
}
}
RC_RETURN(model);
}
static int reg_ioclk(struct fpga_model *model)
{
int top_pll_y, top_dcm_y, bot_pll_y, bot_dcm_y, i, rc;
RC_CHECK(model);
find_pll_dcm_y(model, &top_pll_y, &top_dcm_y, &bot_pll_y, &bot_dcm_y);
RC_ASSERT(model, top_pll_y != -1 && top_dcm_y != -1
&& bot_pll_y != -1 && bot_dcm_y != -1);
for (i = 0; i <= 5; i++) {
struct w_net n = {
.last_inc = 0, .num_pts = (i == 2 || i == 3) ? 3 : 4, .pt =
{{ pf("REGT_PLL_IOCLK_UP%i", i), 0, TOP_OUTER_ROW, model->center_x-CENTER_CMTPLL_O },
{ pf("REGT_TERM_PLL_IOCLK_UP%i", i), 0, TOP_INNER_ROW, model->center_x-CENTER_CMTPLL_O },
{ pf("PLL_IOCLK_UP%i", i), 0, top_pll_y, model->center_x-CENTER_CMTPLL_O },
{ pf("DCM_IOCLK_UP%i", i), 0, top_dcm_y, model->center_x-CENTER_CMTPLL_O }}};
if ((rc = add_conn_net(model, NO_PREF, &n))) RC_FAIL(model, rc);
}
rc = add_conn_range(model, NOPREF_BI_F,
top_pll_y, model->center_x-CENTER_CMTPLL_O, "PLL_IOCLK_DN%i", 2, 3,
top_dcm_y, model->center_x-CENTER_CMTPLL_O, "DCM_IOCLK_UP%i", 2);
if (rc) RC_FAIL(model, rc);
rc = add_conn_range(model, NOPREF_BI_F,
top_dcm_y, model->center_x-CENTER_CMTPLL_O, "DCM_IOCLK_DOWN%i", 0, 3,
model->center_y, model->center_x-CENTER_CMTPLL_O, "REGC_PLLCLK_UP_IN%i", 0);
if (rc) RC_FAIL(model, rc);
rc = add_conn_range(model, NOPREF_BI_F,
top_dcm_y, model->center_x-CENTER_CMTPLL_O, "DCM_IOCLK_DOWN%i", 4, 5,
model->center_y, model->center_x-CENTER_CMTPLL_O, "REGC_PLLCLK_UP_OUT%i", 0);
if (rc) RC_FAIL(model, rc);
{ struct w_net n = {
.last_inc = 1, .num_pts = 3, .pt =
{{ "REGC_PLLCLK_DN_OUT%i", 0, model->center_y, model->center_x-CENTER_CMTPLL_O },
{ "PLL_IOCLK_UP%i", 4, bot_pll_y, model->center_x-CENTER_CMTPLL_O },
{ "DCM_IOCLK_UP%i", 4, bot_dcm_y, model->center_x-CENTER_CMTPLL_O }}};
if ((rc = add_conn_net(model, NO_PREF, &n))) RC_FAIL(model, rc); }
for (i = 0; i <= 3; i++) {
struct w_net n = {
.last_inc = 0, .num_pts = (i < 2) ? 3 : 2, .pt =
{{ pf("REGC_PLLCLK_DN_IN%i", i), 0, model->center_y, model->center_x-CENTER_CMTPLL_O },
{ pf("PLL_IOCLK_UP%i", i), 0, bot_pll_y, model->center_x-CENTER_CMTPLL_O },
{ pf("DCM_IOCLK_UP%i", i), 0, bot_dcm_y, model->center_x-CENTER_CMTPLL_O }}};
if ((rc = add_conn_net(model, NO_PREF, &n))) RC_FAIL(model, rc);
}
rc = add_conn_range(model, NOPREF_BI_F,
bot_pll_y, model->center_x-CENTER_CMTPLL_O, "PLL_IOCLK_DN%i", 2, 3,
bot_dcm_y, model->center_x-CENTER_CMTPLL_O, "DCM_IOCLK_UP%i", 2);
if (rc) RC_FAIL(model, rc);
{ struct w_net n = {
.last_inc = 5, .num_pts = 3, .pt =
{{ "DCM_IOCLK_DOWN%i", 0, bot_dcm_y, model->center_x-CENTER_CMTPLL_O },
{ "REGB_TERM_PLL_IOCLK_DOWN%i", 0, model->y_height-BOT_INNER_ROW, model->center_x-CENTER_CMTPLL_O },
{ "REGB_PLL_IOCLK_DOWN%i", 0, model->y_height-BOT_OUTER_ROW, model->center_x-CENTER_CMTPLL_O }}};
if ((rc = add_conn_net(model, NO_PREF, &n))) RC_FAIL(model, rc); }
RC_RETURN(model);
}
static int reg_lock(struct fpga_model *model)
{
int top_pll_y, top_dcm_y, bot_pll_y, bot_dcm_y, i;
RC_CHECK(model);
// left
{ struct w_net n = {
.last_inc = 1, .num_pts = 4, .pt =
{{ "REGL_LOCK%i", 0, model->center_y, LEFT_OUTER_COL },
{ "REGH_LTERM_LOCK%i", 0, model->center_y, LEFT_INNER_COL },
{ "REGH_IOI_INT_LOCK%i", 0, model->center_y, LEFT_IO_ROUTING },
{ "INT_BUFPLL_LOCK_LR%i", 0, model->center_y-CENTER_Y_MINUS_1, LEFT_IO_ROUTING }}};
add_conn_net(model, NO_PREF, &n); }
add_switch(model, model->center_y-CENTER_Y_MINUS_1, LEFT_IO_ROUTING,
"INT_BUFPLL_LOCK_LR0", "LOGICOUT0", /*bidir*/ 0);
add_switch(model, model->center_y-CENTER_Y_MINUS_1, LEFT_IO_ROUTING,
"INT_BUFPLL_LOCK_LR1", "LOGICOUT1", /*bidir*/ 0);
// right
{ struct w_net n = {
.last_inc = 1, .num_pts = 6, .pt =
{{ "REGR_LOCK%i", 0, model->center_y, model->x_width-RIGHT_OUTER_O },
{ "REGH_RTERM_LOCK%i", 0, model->center_y, model->x_width-RIGHT_INNER_O },
{ "MCB_REGH_LOCK%i", 0, model->center_y, model->x_width-RIGHT_MCB_O },
{ "REGH_RIOI_LOCK%i", 0, model->center_y, model->x_width-RIGHT_IO_DEVS_O },
{ "REGH_RIOI_INT_LOCK%i", 0, model->center_y, model->x_width-RIGHT_IO_ROUTING_O },
{ "INT_BUFPLL_LOCK_LR%i", 0, model->center_y-CENTER_Y_MINUS_1, model->x_width-RIGHT_IO_ROUTING_O }}};
add_conn_net(model, NO_PREF, &n); }
add_switch(model, model->center_y-CENTER_Y_MINUS_1, model->x_width-RIGHT_IO_ROUTING_O,
"INT_BUFPLL_LOCK_LR0", "LOGICOUT0", /*bidir*/ 0);
add_switch(model, model->center_y-CENTER_Y_MINUS_1, model->x_width-RIGHT_IO_ROUTING_O,
"INT_BUFPLL_LOCK_LR1", "LOGICOUT1", /*bidir*/ 0);
// top
{ struct w_net n = {
.last_inc = 1, .num_pts = 5, .pt =
{{ "REGT_LOCK%i", 0, TOP_OUTER_ROW, model->center_x-CENTER_CMTPLL_O },
{ "REGT_TTERM_LOCK%i", 0, TOP_INNER_ROW, model->center_x-CENTER_CMTPLL_O },
{ "REGV_TTERM_LOCK%i", 0, TOP_INNER_ROW, model->center_x },
{ "PLLBUF_TOP_LOCK%i", 0, TOP_INNER_ROW, model->center_x+CENTER_X_PLUS_1 },
{ "INT_BUFPLL_LOCK%i", 0, TOP_OUTER_IO, model->center_x+CENTER_X_PLUS_1 }}};
add_conn_net(model, NO_PREF, &n); }
add_switch(model, TOP_OUTER_IO, model->center_x+CENTER_X_PLUS_1,
"INT_BUFPLL_LOCK0", "LOGICOUT18", /*bidir*/ 0);
add_switch(model, TOP_OUTER_IO, model->center_x+CENTER_X_PLUS_1,
"INT_BUFPLL_LOCK1", "LOGICOUT19", /*bidir*/ 0);
// bottom
{ struct w_net n = {
.last_inc = 1, .num_pts = 8, .pt =
{{ "REGB_LOCK%i", 0, model->y_height-BOT_OUTER_ROW, model->center_x-CENTER_CMTPLL_O },
{ "REGB_BTERM_LOCK%i", 0, model->y_height-BOT_INNER_ROW, model->center_x-CENTER_CMTPLL_O },
{ "REGV_BTERM_LOCK%i", 0, model->y_height-BOT_INNER_ROW, model->center_x },
{ "BUFPLL_BOT_LOCK%i", 0, model->y_height-BOT_INNER_ROW, model->center_x+CENTER_X_PLUS_1 },
{ "REGB_BOT_LOCK%i", 0, model->y_height-BOT_INNER_ROW, model->center_x+CENTER_X_PLUS_2 },
{ "BIOI_OUTER_LOCK%i", 0, model->y_height-BOT_OUTER_IO, model->center_x+CENTER_X_PLUS_2 },
{ "BIOI_INNER_LOCK%i", 0, model->y_height-BOT_INNER_IO, model->center_x+CENTER_X_PLUS_2 },
{ "INT_BUFPLL_LOCK_DN%i", 0, model->y_height-BOT_INNER_IO, model->center_x+CENTER_X_PLUS_1 }}};
add_conn_net(model, NO_PREF, &n); }
add_switch(model, model->y_height-BOT_INNER_IO, model->center_x+CENTER_X_PLUS_1,
"INT_BUFPLL_LOCK_DN0", "LOGICOUT18", /*bidir*/ 0);
add_switch(model, model->y_height-BOT_INNER_IO, model->center_x+CENTER_X_PLUS_1,
"INT_BUFPLL_LOCK_DN1", "LOGICOUT19", /*bidir*/ 0);
find_pll_dcm_y(model, &top_pll_y, &top_dcm_y, &bot_pll_y, &bot_dcm_y);
RC_ASSERT(model, top_pll_y != -1 && top_dcm_y != -1
&& bot_pll_y != -1 && bot_dcm_y != -1);
for (i = 0; i <= 2; i++) {
// nets for :0 and :2 include the dcm, the :1 net ends at the pll
struct w_net n = {
.last_inc = 0, .num_pts = (i != 1) ? 4 : 3, .pt =
{{ pf("REGT_LOCKIN%i", i), 0, TOP_OUTER_ROW, model->center_x-CENTER_CMTPLL_O },
{ pf("REGT_TERM_LOCKIN%i", i), 0, TOP_INNER_ROW, model->center_x-CENTER_CMTPLL_O },
{ pf("CMT_PLL_LOCK_UP%i", i), 0, top_pll_y, model->center_x-CENTER_CMTPLL_O },
{ pf("CMT_DCM_LOCK_UP%i", i), 0, top_dcm_y, model->center_x-CENTER_CMTPLL_O }}};
add_conn_net(model, NO_PREF, &n);
}
// :1 between pll and dcm
add_conn_bi(model,
top_pll_y, model->center_x-CENTER_CMTPLL_O, "CMT_PLL_LOCK_DN1",
top_dcm_y, model->center_x-CENTER_CMTPLL_O, "CMT_DCM_LOCK_UP1");
// 0:2 between dcm and center_y
add_conn_range(model, NOPREF_BI_F,
top_dcm_y, model->center_x-CENTER_CMTPLL_O, "CMT_DCM_LOCK_DN%i", 0, 2,
model->center_y, model->center_x-CENTER_CMTPLL_O, "PLL_LOCK_TOP%i", 0);
for (i = 0; i <= 2; i++) {
// nets for :0 and :2 include the dcm, the :1 net ends at the pll
struct w_net n = {
.last_inc = 0, .num_pts = (i != 1) ? 3 : 2, .pt =
{{ pf("PLL_LOCK_BOT%i", i), 0, model->center_y, model->center_x-CENTER_CMTPLL_O },
{ pf("CMT_PLL_LOCK_UP%i", i), 0, bot_pll_y, model->center_x-CENTER_CMTPLL_O },
{ pf("CMT_DCM_LOCK_UP%i", i), 0, bot_dcm_y, model->center_x-CENTER_CMTPLL_O }}};
add_conn_net(model, NO_PREF, &n);
}
// :1 between pll and dcm
add_conn_bi(model,
bot_pll_y, model->center_x-CENTER_CMTPLL_O, "CMT_PLL_LOCK_DN1",
bot_dcm_y, model->center_x-CENTER_CMTPLL_O, "CMT_DCM_LOCK_UP1");
// 0:2 to bottom reg
{ struct w_net n = {
.last_inc = 2, .num_pts = 3, .pt =
{{ "CMT_DCM_LOCK_DN%i", 0, bot_dcm_y, model->center_x-CENTER_CMTPLL_O },
{ "REGB_TERM_LOCKIN%i", 0, model->y_height-BOT_INNER_ROW, model->center_x-CENTER_CMTPLL_O },
{ "REGB_LOCKIN%i", 0, model->y_height-BOT_OUTER_ROW, model->center_x-CENTER_CMTPLL_O }}};
add_conn_net(model, NO_PREF, &n); }
RC_RETURN(model);
}
static int pll_dcm_clk(struct fpga_model *model, int pll_y, int dcm_y)
{
RC_CHECK(model);
add_conn_range(model, NOPREF_BI_F,
pll_y, model->center_x-CENTER_CMTPLL_O, "CMT_CLK_TO_DCM%i", 1, 2,
dcm_y, model->center_x-CENTER_CMTPLL_O, "DCM%i_CLK_FROM_PLL", 1);
add_conn_range(model, NOPREF_BI_F,
pll_y, model->center_x-CENTER_CMTPLL_O, "CMT_CLK_FROM_DCM%i", 1, 2,
dcm_y, model->center_x-CENTER_CMTPLL_O, "DCM%i_CLK_TO_PLL", 1);
add_conn_range(model, NOPREF_BI_F,
pll_y, model->center_x-CENTER_CMTPLL_O, "CMT_DCM%i_CLKFB", 1, 2,
dcm_y, model->center_x-CENTER_CMTPLL_O, "DCM%i_CLKFB_TOPLL", 1);
add_conn_range(model, NOPREF_BI_F,
pll_y, model->center_x-CENTER_CMTPLL_O, "CMT_DCM%i_CLKIN", 1, 2,
dcm_y, model->center_x-CENTER_CMTPLL_O, "DCM%i_CLKIN_TOPLL", 1);
RC_RETURN(model);
}
static int reg_pll_dcm(struct fpga_model *model)
{
int y, i, top_pll_y, top_dcm_y, bot_pll_y, bot_dcm_y;
RC_CHECK(model);
for (y = TOP_FIRST_REGULAR; y < model->y_height - BOT_LAST_REGULAR_O; y++) {
// connections at each hclk row
if (is_aty(Y_ROW_HORIZ_AXSYMM, model, y)) {
add_conn_range(model, NOPREF_BI_F,
y, model->center_x, "REGV_PLL_HCLK%i", 0, 15,
y-1, model->center_x-CENTER_CMTPLL_O,
has_device(model, y-1, model->center_x
- CENTER_CMTPLL_O, DEV_PLL)
? "CMT_PLL_HCLK%i" : "DCM_HCLK%i", 0);
}
}
find_pll_dcm_y(model, &top_pll_y, &top_dcm_y, &bot_pll_y, &bot_dcm_y);
RC_ASSERT(model, top_pll_y != -1 && top_dcm_y != -1
&& bot_pll_y != -1 && bot_dcm_y != -1);
//
// casc
//
// from top_pll_y down to top_dcm_y
add_conn_range(model, NOPREF_BI_F,
top_pll_y, model->center_x-CENTER_CMTPLL_O, "CLK_PLLCASC_OUT%i", 0, 15,
top_dcm_y, model->center_x-CENTER_CMTPLL_O, "PLL_CLK_CASC_TOP%i", 0);
// from center up to top_dcm_y and down to bot_pll_y
{ struct w_net n = {
.last_inc = 15, .num_pts = 3, .pt =
{{ "CLKC_PLL_U%i", 0,
model->center_y, model->center_x },
{ "REGC_CMT_CLKPLL_U%i", 0,
model->center_y, model->center_x-CENTER_CMTPLL_O },
{ "PLL_CLK_CASC_BOT%i", 0,
top_dcm_y, model->center_x-CENTER_CMTPLL_O }}};
add_conn_net(model, NO_PREF, &n); }
{ struct w_net n = {
.last_inc = 15, .num_pts = 3, .pt =
{{ "CLKC_PLL_L%i", 0,
model->center_y, model->center_x },
{ "REGC_CMT_CLKPLL_L%i", 0,
model->center_y, model->center_x-CENTER_CMTPLL_O },
{ "PLL_CLK_CASC_IN%i", 0,
bot_pll_y, model->center_x-CENTER_CMTPLL_O }}};
add_conn_net(model, NO_PREF, &n); }
for (i = 0; i <= 15; i++) {
add_switch(model, bot_pll_y, model->center_x-CENTER_CMTPLL_O,
pf("CLK_PLLCASC_OUT%i", i), pf("PLL_CLK_CASC_IN%i", i),
/*bidir*/ 0);
}
// from bot_pll_y down to bot_dcm_y
add_conn_range(model, NOPREF_BI_F,
bot_pll_y, model->center_x-CENTER_CMTPLL_O, "CLK_PLLCASC_OUT%i", 0, 15,
bot_dcm_y, model->center_x-CENTER_CMTPLL_O, "PLL_CLK_CASC_TOP%i", 0);
//
// clk between pll and dcm, top and bottom side
//
pll_dcm_clk(model, top_pll_y, top_dcm_y);
pll_dcm_clk(model, bot_pll_y, bot_dcm_y);
RC_RETURN(model);
}
static int gtp(struct fpga_model *model)
{
RC_CHECK(model);
// left
add_conn_range(model, NOPREF_BI_F,
model->center_y, LEFT_OUTER_COL, "REGL_GTPCLK%i", 0, 7,
model->center_y, LEFT_INNER_COL, "REGH_LTERM_GTPCLK%i", 0);
add_conn_range(model, NOPREF_BI_F,
model->center_y, LEFT_OUTER_COL, "REGL_GTPFB%i", 0, 7,
model->center_y, LEFT_INNER_COL, "REGH_LTERM_GTPFB%i", 0);
// right
add_conn_range(model, NOPREF_BI_F,
model->center_y, model->x_width-RIGHT_OUTER_O, "REGR_GTPCLK%i", 0, 7,
model->center_y, model->x_width-RIGHT_INNER_O, "REGH_RTERM_GTPCLK%i", 0);
add_conn_range(model, NOPREF_BI_F,
model->center_y, model->x_width-RIGHT_OUTER_O, "REGR_GTPFB%i", 0, 7,
model->center_y, model->x_width-RIGHT_INNER_O, "REGH_RTERM_GTPFB%i", 0);
// top
add_conn_range(model, NOPREF_BI_F,
TOP_OUTER_ROW, model->center_x-CENTER_CMTPLL_O, "REGT_GTPCLK%i", 0, 7,
TOP_INNER_ROW, model->center_x-CENTER_CMTPLL_O, "REGT_TTERM_GTPCLK%i", 0);
add_conn_range(model, NOPREF_BI_F,
TOP_OUTER_ROW, model->center_x-CENTER_CMTPLL_O, "REGT_GTPFB%i", 0, 7,
TOP_INNER_ROW, model->center_x-CENTER_CMTPLL_O, "REGT_TTERM_GTPFB%i", 0);
// bottom
add_conn_range(model, NOPREF_BI_F,
model->y_height-BOT_OUTER_ROW, model->center_x-CENTER_CMTPLL_O, "REGB_GTPCLK%i", 0, 7,
model->y_height-BOT_INNER_ROW, model->center_x-CENTER_CMTPLL_O, "REGB_BTERM_GTPCLK%i", 0);
add_conn_range(model, NOPREF_BI_F,
model->y_height-BOT_OUTER_ROW, model->center_x-CENTER_CMTPLL_O, "REGB_GTPFB%i", 0, 7,
model->y_height-BOT_INNER_ROW, model->center_x-CENTER_CMTPLL_O, "REGB_BTERM_GTPFB%i", 0);
RC_RETURN(model);
}
static int pci(struct fpga_model *model)
{
static const int pci_wnum[3] = {24, 7, 5};
int i;
RC_CHECK(model);
//
// left side
//
{ struct w_net n = {
.last_inc = 0, .num_pts = 4, .pt =
{{ "REGL_PCI_IRDY_IOB", 0, model->center_y, LEFT_OUTER_COL },
{ "LIOB_PCI_IT_RDY", 0, model->center_y-CENTER_Y_MINUS_1, LEFT_OUTER_COL },
{ "LIOB_PCI_IT_RDY", 0, model->center_y-CENTER_Y_MINUS_2, LEFT_OUTER_COL },
{ "LIOB_PCICE_TRDY_EXT", 0, model->center_y-CENTER_Y_MINUS_3, LEFT_OUTER_COL }}};
add_conn_net(model, NO_PREF, &n); }
{ struct w_net n = {
.last_inc = 0, .num_pts = 2, .pt =
{{ "REGL_PCI_TRDY_IOB", 0, model->center_y, LEFT_OUTER_COL },
{ "LIOB_PCI_IT_RDY", 0, model->center_y+CENTER_Y_PLUS_1, LEFT_OUTER_COL }}};
add_conn_net(model, NO_PREF, &n); }
{ struct w_net n = {
.last_inc = 0, .num_pts = 3, .pt =
{{ "REGL_PCI_IRDY_PINW", 0, model->center_y, LEFT_OUTER_COL },
{ "REGH_LTERM_IRDY_PINW", 0, model->center_y, LEFT_INNER_COL },
{ "REGH_LEFT_PCI_IRDY_PINW", 0, model->center_y, LEFT_IO_ROUTING }}};
add_conn_net(model, NO_PREF, &n); }
{ struct w_net n = {
.last_inc = 0, .num_pts = 3, .pt =
{{ "REGL_PCI_TRDY_PINW", 0, model->center_y, LEFT_OUTER_COL },
{ "REGH_LTERM_TRDY_PINW", 0, model->center_y, LEFT_INNER_COL },
{ "REGH_LEFT_PCI_TRDY_PINW", 0, model->center_y, LEFT_IO_ROUTING }}};
add_conn_net(model, NO_PREF, &n); }
{ struct w_net n = {
.last_inc = 2, .num_pts = 2, .pt =
{{ "IOI_INT_I%i", 1, model->center_y-CENTER_Y_MINUS_1, LEFT_IO_ROUTING },
{ "REGH_PCI_I%i_INT", 1, model->center_y, LEFT_IO_ROUTING }}};
add_conn_net(model, NO_PREF, &n); }
for (i = 1; i <= 3; i++) {
add_switch(model, model->center_y-CENTER_Y_MINUS_1, LEFT_IO_ROUTING,
pf("LOGICIN_B%i", pci_wnum[i-1]), pf("IOI_INT_I%i", i), /*bidir*/ 0);
add_switch(model, model->center_y, LEFT_IO_ROUTING,
pf("REGH_PCI_I%i_INT", i), pf("REGL_PCI_I%i_PINW", i), /*bidir*/ 0);
}
//
// right side
//
{ struct w_net n = {
.last_inc = 0, .num_pts = 4, .pt =
{{ "REGR_PCI_IRDY_IOB", 0, model->center_y, model->x_width-RIGHT_OUTER_O },
{ "RIOB_PCI_IT_RDY", 0, model->center_y-CENTER_Y_MINUS_1, model->x_width-RIGHT_OUTER_O },
{ "RIOB_PCI_IT_RDY", 0, model->center_y-CENTER_Y_MINUS_2, model->x_width-RIGHT_OUTER_O },
{ "RIOB_PCI_IT_RDY", 0, model->center_y-CENTER_Y_MINUS_3, model->x_width-RIGHT_OUTER_O }}};
add_conn_net(model, NO_PREF, &n); }
{ struct w_net n = {
.last_inc = 0, .num_pts = 2, .pt =
{{ "REGR_PCI_TRDY_IOB", 0, model->center_y, model->x_width-RIGHT_OUTER_O },
{ "RIOB_PCI_TRDY_EXT", 0, model->center_y+CENTER_Y_PLUS_1, model->x_width-RIGHT_OUTER_O }}};
add_conn_net(model, NO_PREF, &n); }
{ struct w_net n = {
.last_inc = 0, .num_pts = 4, .pt =
{{ "REGR_PCI_IRDY_PINW", 0, model->center_y, model->x_width-RIGHT_OUTER_O },
{ "REGH_RTERM_IRDY_PINW", 0, model->center_y, model->x_width-RIGHT_INNER_O },
{ "MCB_REGH_IRDY_PINW", 0, model->center_y, model->x_width-RIGHT_MCB_O },
{ "REGR_RTERM_IRDY_PINW", 0, model->center_y, model->x_width-RIGHT_IO_DEVS_O }}};
add_conn_net(model, NO_PREF, &n); }
{ struct w_net n = {
.last_inc = 0, .num_pts = 4, .pt =
{{ "REGR_PCI_TRDY_PINW", 0, model->center_y, model->x_width-RIGHT_OUTER_O },
{ "REGH_RTERM_TRDY_PINW", 0, model->center_y, model->x_width-RIGHT_INNER_O },
{ "MCB_REGH_TRDY_PINW", 0, model->center_y, model->x_width-RIGHT_MCB_O },
{ "REGR_RTERM_TRDY_PINW", 0, model->center_y, model->x_width-RIGHT_IO_DEVS_O }}};
add_conn_net(model, NO_PREF, &n); }
{ struct w_net n = {
.last_inc = 2, .num_pts = 3, .pt =
{{ "REGH_RIOI_PCI_I%i", 1, model->center_y, model->x_width-RIGHT_IO_DEVS_O },
{ "REGH_IOI_INT_I%i", 1, model->center_y, model->x_width-RIGHT_IO_ROUTING_O },
{ "IOI_INT_I%i", 1, model->center_y-CENTER_Y_MINUS_1, model->x_width-RIGHT_IO_ROUTING_O }}};
add_conn_net(model, NO_PREF, &n); }
for (i = 1; i <= 3; i++) {
add_switch(model, model->center_y-CENTER_Y_MINUS_1, model->x_width-RIGHT_IO_ROUTING_O,
pf("LOGICIN_B%i", pci_wnum[i-1]), pf("IOI_INT_I%i", i), /*bidir*/ 0);
add_switch(model, model->center_y, model->x_width-RIGHT_IO_DEVS_O,
pf("REGH_RIOI_PCI_I%i", i), pf("REGR_PCI_I%i_PINW", i), /*bidir*/ 0);
}
RC_RETURN(model);
}
static int macc_vert_chain(struct fpga_model *model, int y_start, int x);
static int macc(struct fpga_model *model)
{
int y, x, y_dist;
RC_CHECK(model);
for (x = LEFT_SIDE_WIDTH; x < model->x_width - RIGHT_SIDE_WIDTH; x++) {
if (!is_atx(X_FABRIC_MACC_ROUTING_COL, model, x))
continue;
for (y = TOP_IO_TILES; y < model->y_height - BOT_IO_TILES; y++) {
for (y_dist = 0; y_dist < 4; y_dist++) {
if (has_device(model, y+y_dist, x+2, DEV_MACC))
break;
}
if (y_dist >= 4) continue;
// clk, sr and logicin
{ struct w_net_i n = { .wire = CLK0, .wire_inc = 1, .num_yx = 3,
{{ .y = y, .x = x },
{ .y = y, .x = x+1 },
{ .y = y+y_dist, .x = x+2 }}};
add_conn_net_i(model, &n);
n.wire = SR0;
add_conn_net_i(model, &n);
n.wire = LOGICIN_B0;
n.wire_inc = LOGICIN_HIGHEST;
add_conn_net_i(model, &n); }
// logicout has two nets - one between routing and
// via, and one between via and macc dev
{ struct w_net_i n = { .wire = LOGICOUT_B0, .wire_inc = LOGICOUT_HIGHEST, .num_yx = 2,
{{ .y = y, .x = x+1 }}};
n.yx[1].y = y;
n.yx[1].x = x;
add_conn_net_i(model, &n);
n.yx[1].y = y+y_dist;
n.yx[1].x = x+2;
add_conn_net_i(model, &n); }
}
macc_vert_chain(model, model->y_height - BOT_LAST_REGULAR_O, x+2);
}
RC_RETURN(model);
}
static int macc_vert_chain(struct fpga_model *model, int y_start, int x)
{
struct w_net net;
int cur_y, next_y, rc;
RC_CHECK(model);
cur_y = y_start;
while (cur_y - 4 >= TOP_FIRST_REGULAR) {
// CARRYOUT
net.last_inc = 0;
net.pt[0].name = "CARRYOUT_DSP48A1_B_SITE";
net.pt[0].start_count = 0;
net.pt[0].y = cur_y;
net.pt[0].x = x;
net.num_pts = 1;
if (is_aty(Y_ROW_HORIZ_AXSYMM, model, cur_y-4)) {
net.pt[net.num_pts].name = "MACCSITE2_HCLK_CCARRY_CIN";
net.pt[net.num_pts].start_count = 0;
net.pt[net.num_pts].y = cur_y-4;
net.pt[net.num_pts].x = x;
net.num_pts++;
next_y = cur_y-5;
} else if (is_aty(Y_CHIP_HORIZ_REGS, model, cur_y-4)) {
net.pt[net.num_pts].name = "MACCSITE2_REGH_CIN";
net.pt[net.num_pts].start_count = 0;
net.pt[net.num_pts].y = cur_y-4;
net.pt[net.num_pts].x = x;
net.num_pts++;
next_y = cur_y-5;
} else
next_y = cur_y-4;
net.pt[net.num_pts].name = "CARRYIN_DSP48A1_SITE";
net.pt[net.num_pts].start_count = 0;
net.pt[net.num_pts].y = next_y;
net.pt[net.num_pts].x = x;
net.num_pts++;
if ((rc = add_conn_net(model, NO_PREF, &net))) RC_FAIL(model, rc);
// BCOUT
net.last_inc = 17;
net.pt[0].name = "BCOUT%i_DSP48A1_B_SITE";
net.pt[0].start_count = 0;
net.pt[0].y = cur_y;
net.pt[0].x = x;
net.num_pts = 1;
if (is_aty(Y_ROW_HORIZ_AXSYMM, model, cur_y-4)) {
net.pt[net.num_pts].name = "MACCSITE2_HCLK_CCARRY_BCIN%i";
net.pt[net.num_pts].start_count = 0;
net.pt[net.num_pts].y = cur_y-4;
net.pt[net.num_pts].x = x;
net.num_pts++;
next_y = cur_y-5;
} else if (is_aty(Y_CHIP_HORIZ_REGS, model, cur_y-4)) {
net.pt[net.num_pts].name = "MACCSITE2_REGH_BCIN%i";
net.pt[net.num_pts].start_count = 0;
net.pt[net.num_pts].y = cur_y-4;
net.pt[net.num_pts].x = x;
net.num_pts++;
next_y = cur_y-5;
} else
next_y = cur_y-4;
net.pt[net.num_pts].name = "BCIN%i_DSP48A1_SITE";
net.pt[net.num_pts].start_count = 0;
net.pt[net.num_pts].y = next_y;
net.pt[net.num_pts].x = x;
net.num_pts++;
if ((rc = add_conn_net(model, NO_PREF, &net))) RC_FAIL(model, rc);
// PCOUT
net.last_inc = 47;
net.pt[0].name = "PCOUT%i_DSP48A1_B_SITE";
net.pt[0].start_count = 0;
net.pt[0].y = cur_y;
net.pt[0].x = x;
net.num_pts = 1;
if (is_aty(Y_ROW_HORIZ_AXSYMM, model, cur_y-4)) {
net.pt[net.num_pts].name = "MACCSITE2_HCLK_CCARRY_PCIN%i";
net.pt[net.num_pts].start_count = 0;
net.pt[net.num_pts].y = cur_y-4;
net.pt[net.num_pts].x = x;
net.num_pts++;
next_y = cur_y-5;
} else if (is_aty(Y_CHIP_HORIZ_REGS, model, cur_y-4)) {
net.pt[net.num_pts].name = "MACCSITE2_REGH_PCIN%i";
net.pt[net.num_pts].start_count = 0;
net.pt[net.num_pts].y = cur_y-4;
net.pt[net.num_pts].x = x;
net.num_pts++;
next_y = cur_y-5;
} else
next_y = cur_y-4;
net.pt[net.num_pts].name = "PCIN%i_DSP48A1_SITE";
net.pt[net.num_pts].start_count = 0;
net.pt[net.num_pts].y = next_y;
net.pt[net.num_pts].x = x;
net.num_pts++;
if ((rc = add_conn_net(model, NO_PREF, &net))) RC_FAIL(model, rc);
cur_y = next_y;
}
RC_RETURN(model);
}
static int clkc(struct fpga_model *model)
{
int i, rc;
RC_CHECK(model);
for (i = 0; i < sizeof(model->die->sel_logicin)/sizeof(model->die->sel_logicin[0]); i++) {
struct w_net n = {
.last_inc = 0, .num_pts = 5, .pt =
{{ pf("CLKC_SEL%i_PLL", i), 0,
model->center_y, model->center_x },
{ pf("REGC_CMT_SEL%i", i), 0,
model->center_y, model->center_x-CENTER_CMTPLL_O },
{ pf("REGC_CLE_SEL%i", i), 0,
model->center_y, model->center_x-CENTER_LOGIC_O },
{ pf("INT_INTERFACE_REGC_LOGICBIN%i", model->die->sel_logicin[i]), 0,
model->center_y-CENTER_Y_MINUS_1, model->center_x-CENTER_LOGIC_O },
{ pf("LOGICIN_B%i", model->die->sel_logicin[i]), 0,
model->center_y-CENTER_Y_MINUS_1, model->center_x-CENTER_ROUTING_O }}};
if ((rc = add_conn_net(model, NO_PREF, &n))) RC_FAIL(model, rc);
}
RC_RETURN(model);
}
static int find_mui_pos(struct fpga_model *model, int y)
{
int i;
for (i = 0; i < model->die->num_mui; i++) {
if (y == model->die->mui_pos[i] || y == model->die->mui_pos[i]+1)
return i;
}
return -1;
}
static int mui_x(struct fpga_model *model, int x)
{
int y, i;
RC_CHECK(model);
for (y = TOP_FIRST_REGULAR; y <= model->y_height - BOT_LAST_REGULAR_O; y++) {
if ((i = find_mui_pos(model, y)) != -1) {
// clk, sr and logicin
{ struct w_net_i n = { .wire = CLK0, .wire_inc = 1, .num_yx = 3,
{{ .y = y, .x = x },
{ .y = y, .x = x+1 },
{ .y = model->die->mui_pos[i]+1, .x = x+2 }}};
add_conn_net_i(model, &n);
n.wire = SR0;
add_conn_net_i(model, &n);
n.wire = LOGICIN_B0;
n.wire_inc = LOGICIN_HIGHEST;
add_conn_net_i(model, &n); }
// logicout has two nets - one back to the routing col, one forward to the mcb col
{ struct w_net_i n = { .wire = LOGICOUT_B0, .wire_inc = LOGICOUT_HIGHEST, .num_yx = 2,
{{ .y = y, .x = x+1 }}};
n.yx[1].y = y;
n.yx[1].x = x;
add_conn_net_i(model, &n);
n.yx[1].y = model->die->mui_pos[i]+1;
n.yx[1].x = x+2;
add_conn_net_i(model, &n); }
}
}
RC_RETURN(model);
}
static int mui(struct fpga_model *model)
{
RC_CHECK(model);
mui_x(model, LEFT_IO_ROUTING);
mui_x(model, model->x_width - RIGHT_IO_ROUTING_O);
RC_RETURN(model);
}
int add_conn_net_i(struct fpga_model *model, const struct w_net_i *net)
{
int i, j, k, rc;
char i_str[MAX_WIRENAME_LEN], j_str[MAX_WIRENAME_LEN];
RC_CHECK(model);
if (net->num_yx < 2) RC_FAIL(model, EINVAL);
for (i = 0; i < net->num_yx; i++) {
for (j = i+1; j < net->num_yx; j++) {
if (net->yx[j].y == net->yx[i].y
&& net->yx[j].x == net->yx[i].x)
continue;
for (k = 0; k <= net->wire_inc; k++) {
snprintf(i_str, sizeof(i_str), "%s", fpga_connpt_str(model, net->wire+k, net->yx[i].y, net->yx[i].x, net->yx[j].y, net->yx[j].x));
snprintf(j_str, sizeof(j_str), "%s", fpga_connpt_str(model, net->wire+k, net->yx[j].y, net->yx[j].x, net->yx[i].y, net->yx[i].x));
RC_ASSERT(model, i_str[0] && j_str[0]);
if ((rc = add_conn_bi(model,
net->yx[i].y, net->yx[i].x, i_str,
net->yx[j].y, net->yx[j].x, j_str))) RC_FAIL(model, rc);
}
}
}
RC_RETURN(model);
}
static void net_mirror_y(struct fpga_model *model, struct w_net_i *net)
{
int i;
for (i = 0; i < net->num_yx; i++)
net->yx[i].y = model->y_height - 1 - net->yx[i].y;
}
static void net_mirror_x(struct fpga_model *model, struct w_net_i *net)
{
int i;
for (i = 0; i < net->num_yx; i++)
net->yx[i].x = model->x_width - 1 - net->yx[i].x;
}
static const char *io_site_connpt(struct fpga_model *model, int y, int x, int wire)
{
if (wire >= CFB0 && wire <= CFB7) {
if ((wire-CFB0)%2) return "CFB0_ILOGIC_SITE_S";
return "CFB0_ILOGIC_SITE";
}
if (wire >= CFB8 && wire <= CFB15) {
if ((wire-CFB8)%2) return "CFB1_ILOGIC_SITE_S";
return "CFB1_ILOGIC_SITE";
}
if (wire >= DFB0 && wire <= DFB7) {
if ((wire-DFB0)%2) return "DFB_ILOGIC_SITE_S";
return "DFB_ILOGIC_SITE";
}
if (wire >= DQSN0 && wire <= DQSN3) return "OUTN_IODELAY_SITE";
if (wire >= DQSP0 && wire <= DQSP3) return "OUTP_IODELAY_SITE";
return 0;
}
static int add_cfb_dfb_clkpin_dqsn_dqsp_sw(struct fpga_model *model, const struct w_net_i *net)
{
char wstr[MAX_WIRENAME_LEN];
int y, x, i;
RC_CHECK(model);
y = net->yx[net->num_yx-1].y;
x = net->yx[net->num_yx-1].x;
if (is_atx(X_INNER_LEFT|X_INNER_RIGHT, model, x)) {
for (i = 0; i <= net->wire_inc; i++) {
strcpy(wstr, fpga_connpt_str(model, net->wire+i, y, x, -1, -1));
if (net->wire >= CLKPIN0 && net->wire <= CLKPIN7)
add_switch(model, y, x, pf("%cTERM_IOB_IBUF%i",
x < model->center_x ? 'L' : 'R', i),
wstr, /*bidir*/ 0);
else
add_switch(model, y, x, pf("%s_%c",
wstr, x < model->center_x ? 'E' : 'W'),
wstr, /*bidir*/ 0);
}
} else if (is_atyx(YX_DEV_ILOGIC, model, y, x)) {
for (i = 0; i <= net->wire_inc; i++) {
const char *site_str = io_site_connpt(model, y, x, net->wire+i);
if (!site_str) continue;
add_switch(model, y, x, site_str,
fpga_connpt_str(model, net->wire+i, y, x, -1, -1),
/*bidir*/ 0);
}
}
RC_RETURN(model);
}
static int add_cfb_dfb_clkpin_dqsn_dqsp_wires(struct fpga_model *model,
enum extra_wires first_wire, int num_wires)
{
RC_CHECK(model);
if (num_wires != 4 && num_wires != 8) RC_FAIL(model, EINVAL);
//
// left side of top and bottom center
//
// top term
{ struct w_net_i n = { .wire = first_wire, .wire_inc = num_wires/2-1, .num_yx = 3,
{{ .y = TOP_OUTER_ROW, .x = model->center_x-CENTER_CMTPLL_O },
{ .y = TOP_INNER_ROW, .x = model->center_x-CENTER_CMTPLL_O },
{ .y = TOP_INNER_ROW, .x = model->center_x-CENTER_LOGIC_O }}};
add_conn_net_i(model, &n);
// bottom term
net_mirror_y(model, &n);
n.wire = first_wire + num_wires/2;
add_conn_net_i(model, &n); }
if (first_wire != CLKPIN0) {
// top into outer io
{ struct w_net_i n = { .wire = first_wire, .wire_inc = num_wires/4-1, .num_yx = 2,
{{ .y = TOP_INNER_ROW, .x = model->center_x-CENTER_LOGIC_O },
{ .y = TOP_OUTER_IO, .x = model->center_x-CENTER_LOGIC_O }}};
add_conn_net_i(model, &n);
add_cfb_dfb_clkpin_dqsn_dqsp_sw(model, &n);
// bottom into outer io
net_mirror_y(model, &n);
n.wire = first_wire + num_wires/2;
add_conn_net_i(model, &n);
add_cfb_dfb_clkpin_dqsn_dqsp_sw(model, &n); }
// top into inner io
{ struct w_net_i n = { .wire = first_wire+num_wires/4, .wire_inc = num_wires/4-1, .num_yx = 3,
{{ .y = TOP_INNER_ROW, .x = model->center_x-CENTER_LOGIC_O },
{ .y = TOP_OUTER_IO, .x = model->center_x-CENTER_LOGIC_O },
{ .y = TOP_INNER_IO, .x = model->center_x-CENTER_LOGIC_O }}};
add_conn_net_i(model, &n);
add_cfb_dfb_clkpin_dqsn_dqsp_sw(model, &n);
// bottom into inner io
net_mirror_y(model, &n);
n.wire = first_wire+num_wires-num_wires/4;
add_conn_net_i(model, &n);
add_cfb_dfb_clkpin_dqsn_dqsp_sw(model, &n); }
}
//
// right side of top and bottom center
//
// top term
{ struct w_net_i n = { .wire = first_wire+num_wires/2, .wire_inc = num_wires/2-1, .num_yx = 5,
{{ .y = TOP_OUTER_ROW, .x = model->center_x-CENTER_CMTPLL_O },
{ .y = TOP_INNER_ROW, .x = model->center_x-CENTER_CMTPLL_O },
{ .y = TOP_INNER_ROW, .x = model->center_x },
{ .y = TOP_INNER_ROW, .x = model->center_x+CENTER_X_PLUS_1 },
{ .y = TOP_INNER_ROW, .x = model->center_x+CENTER_X_PLUS_2 }}};
add_conn_net_i(model, &n);
// bottom term
net_mirror_y(model, &n);
n.wire = first_wire;
add_conn_net_i(model, &n); }
if (first_wire != CLKPIN0) {
// top into outer io
{ struct w_net_i n = { .wire = first_wire+num_wires/2, .wire_inc = num_wires/4-1, .num_yx = 2,
{{ .y = TOP_INNER_ROW, .x = model->center_x+CENTER_X_PLUS_2 },
{ .y = TOP_OUTER_IO, .x = model->center_x+CENTER_X_PLUS_2 }}};
add_conn_net_i(model, &n);
add_cfb_dfb_clkpin_dqsn_dqsp_sw(model, &n);
// bottom into outer io
net_mirror_y(model, &n);
n.wire = first_wire;
add_conn_net_i(model, &n);
add_cfb_dfb_clkpin_dqsn_dqsp_sw(model, &n); }
// top into inner io
{ struct w_net_i n = { .wire = first_wire+num_wires-num_wires/4, .wire_inc = num_wires/4-1, .num_yx = 3,
{{ .y = TOP_INNER_ROW, .x = model->center_x+CENTER_X_PLUS_2 },
{ .y = TOP_OUTER_IO, .x = model->center_x+CENTER_X_PLUS_2 },
{ .y = TOP_INNER_IO, .x = model->center_x+CENTER_X_PLUS_2 }}};
add_conn_net_i(model, &n);
add_cfb_dfb_clkpin_dqsn_dqsp_sw(model, &n);
// bottom into inner io
net_mirror_y(model, &n);
n.wire = first_wire+num_wires/4;
add_conn_net_i(model, &n);
add_cfb_dfb_clkpin_dqsn_dqsp_sw(model, &n); }
}
//
// left and right center
//
// term: top side left center
{ struct w_net_i n = { .wire = first_wire+num_wires-num_wires/4, .wire_inc = num_wires/4-1, .num_yx = 6, .yx =
{{ .y = model->center_y, .x = LEFT_OUTER_COL },
{ .y = model->center_y, .x = LEFT_INNER_COL },
{ .y = model->center_y - CENTER_Y_MINUS_1, .x = LEFT_INNER_COL },
{ .y = model->center_y - CENTER_Y_MINUS_2, .x = LEFT_INNER_COL },
{ .y = model->center_y - CENTER_Y_MINUS_3, .x = LEFT_INNER_COL },
{ .y = model->center_y - CENTER_Y_MINUS_4, .x = LEFT_INNER_COL }}};
add_conn_net_i(model, &n);
add_cfb_dfb_clkpin_dqsn_dqsp_sw(model, &n);
n.num_yx--; // one less - remove CENTER_Y_MINUS_4
n.wire = first_wire+num_wires/2;
add_conn_net_i(model, &n);
add_cfb_dfb_clkpin_dqsn_dqsp_sw(model, &n);
// term: top side right center
n.num_yx++;
net_mirror_x(model, &n);
n.wire = first_wire;
add_conn_net_i(model, &n);
add_cfb_dfb_clkpin_dqsn_dqsp_sw(model, &n);
n.num_yx--; // one less - remove CENTER_Y_MINUS_4
n.wire = first_wire+num_wires/4;
add_conn_net_i(model, &n);
add_cfb_dfb_clkpin_dqsn_dqsp_sw(model, &n); }
// term: bottom side left center
{ struct w_net_i n = { .wire = first_wire, .wire_inc = num_wires/4-1, .num_yx = 4,
{{ .y = model->center_y, .x = LEFT_OUTER_COL },
{ .y = model->center_y, .x = LEFT_INNER_COL },
{ .y = model->center_y + CENTER_Y_PLUS_1, .x = LEFT_INNER_COL },
{ .y = model->center_y + CENTER_Y_PLUS_2, .x = LEFT_INNER_COL }}};
add_conn_net_i(model, &n);
add_cfb_dfb_clkpin_dqsn_dqsp_sw(model, &n);
n.num_yx--; // one less - remove CENTER_Y_PLUS_2
n.wire = first_wire+num_wires/4;
add_conn_net_i(model, &n);
add_cfb_dfb_clkpin_dqsn_dqsp_sw(model, &n);
// term: bottom side right center
n.num_yx++;
net_mirror_x(model, &n);
n.wire = first_wire+num_wires-num_wires/4;
add_conn_net_i(model, &n);
add_cfb_dfb_clkpin_dqsn_dqsp_sw(model, &n);
n.num_yx--; // one less - remove CENTER_Y_PLUS_2
n.wire = first_wire+num_wires/2;
add_conn_net_i(model, &n);
add_cfb_dfb_clkpin_dqsn_dqsp_sw(model, &n); }
if (first_wire != CLKPIN0) {
// io devs: left
{ struct w_net_i n = { .wire = first_wire, .wire_inc = num_wires/4-1, .num_yx = 3,
{{ .y = model->center_y + CENTER_Y_PLUS_2, .x = LEFT_INNER_COL },
{ .y = model->center_y + CENTER_Y_PLUS_2, .x = LEFT_IO_ROUTING },
{ .y = model->center_y + CENTER_Y_PLUS_2, .x = LEFT_IO_DEVS }}};
add_conn_net_i(model, &n);
add_cfb_dfb_clkpin_dqsn_dqsp_sw(model, &n);
n.wire = first_wire+num_wires/4;
n.yx[0].y = n.yx[1].y = n.yx[2].y = model->center_y + CENTER_Y_PLUS_1;
add_conn_net_i(model, &n);
add_cfb_dfb_clkpin_dqsn_dqsp_sw(model, &n);
n.wire = first_wire+(num_wires/4)*2;
n.yx[0].y = n.yx[1].y = n.yx[2].y = model->center_y - CENTER_Y_MINUS_3;
add_conn_net_i(model, &n);
add_cfb_dfb_clkpin_dqsn_dqsp_sw(model, &n);
n.wire = first_wire+(num_wires/4)*3;
n.yx[0].y = n.yx[1].y = n.yx[2].y = model->center_y - CENTER_Y_MINUS_4;
add_conn_net_i(model, &n);
add_cfb_dfb_clkpin_dqsn_dqsp_sw(model, &n); }
// io dev: right
{ struct w_net_i n = { .wire = first_wire, .wire_inc = num_wires/4-1, .num_yx = 2,
{{ .y = model->center_y - CENTER_Y_MINUS_4, .x = model->x_width - RIGHT_INNER_O },
{ .y = model->center_y - CENTER_Y_MINUS_4, .x = model->x_width - RIGHT_IO_DEVS_O }}};
add_conn_net_i(model, &n);
add_cfb_dfb_clkpin_dqsn_dqsp_sw(model, &n);
n.wire = first_wire+num_wires/4;
n.yx[0].y = n.yx[1].y = model->center_y - CENTER_Y_MINUS_3;
add_conn_net_i(model, &n);
add_cfb_dfb_clkpin_dqsn_dqsp_sw(model, &n);
n.wire = first_wire+(num_wires/4)*2;
n.yx[0].y = n.yx[1].y = model->center_y + CENTER_Y_PLUS_1;
add_conn_net_i(model, &n);
add_cfb_dfb_clkpin_dqsn_dqsp_sw(model, &n);
n.wire = first_wire+(num_wires/4)*3;
n.yx[0].y = n.yx[1].y = model->center_y + CENTER_Y_PLUS_2;
add_conn_net_i(model, &n);
add_cfb_dfb_clkpin_dqsn_dqsp_sw(model, &n); }
}
RC_RETURN(model);
}
static int cfb_dfb_clkpin_dqsn_dqsp(struct fpga_model *model)
{
RC_CHECK(model);
add_cfb_dfb_clkpin_dqsn_dqsp_wires(model, CFB0, 8);
add_cfb_dfb_clkpin_dqsn_dqsp_wires(model, CFB8, 8);
add_cfb_dfb_clkpin_dqsn_dqsp_wires(model, DFB0, 8);
add_cfb_dfb_clkpin_dqsn_dqsp_wires(model, CLKPIN0, 8);
add_cfb_dfb_clkpin_dqsn_dqsp_wires(model, DQSN0, 4);
add_cfb_dfb_clkpin_dqsn_dqsp_wires(model, DQSP0, 4);
RC_RETURN(model);
}
static int pcice_ew(struct fpga_model *model, int y);
static int pcice_ew_run(struct fpga_model *model, int y, int start_x, int x_dir);
static int pcice_ew_fill_net(struct fpga_model *model, int y, int *cur_x, int x_dir, struct w_net *net);
static int pcice_left_right_io(struct fpga_model *model, int x);
static int pcice_fill_net_io(struct fpga_model *model, struct w_net *net,
int hclk_start_y, const char *hclk_str, int y_range, int y_dir, int x);
static int pcice_left_right_devs(struct fpga_model *model, int x);
static int pcice_fill_net_devs(struct fpga_model *model, struct w_net *net,
int first_y, int last_y, int x);
static int pcice(struct fpga_model *model)
{
struct w_net net;
int x, rc;
RC_CHECK(model);
rc = add_conn_bi(model,
model->center_y, LEFT_IO_ROUTING, "REGL_PCI_CE_PINW",
model->center_y, LEFT_IO_DEVS, "REGH_IOI_PCI_CE");
if (rc) RC_FAIL(model, rc);
rc = pcice_left_right_io(model, LEFT_IO_DEVS);
if (rc) RC_FAIL(model, rc);
rc = pcice_left_right_io(model, model->x_width - RIGHT_IO_DEVS_O);
if (rc) RC_FAIL(model, rc);
rc = pcice_left_right_devs(model, LEFT_IO_DEVS);
if (rc) RC_FAIL(model, rc);
rc = pcice_left_right_devs(model, model->x_width - RIGHT_IO_DEVS_O);
if (rc) RC_FAIL(model, rc);
for (x = LEFT_SIDE_WIDTH; x < model->x_width - RIGHT_SIDE_WIDTH; x++) {
if (has_device(model, TOP_OUTER_IO, x, DEV_ILOGIC)) {
net.last_inc = 0;
net.pt[0].name = "TTERM_CLB_PCICE_S";
net.pt[0].start_count = 0;
net.pt[0].y = TOP_INNER_ROW;
net.pt[0].x = x;
net.pt[1].name = "IOI_PCI_CE";
net.pt[1].start_count = 0;
net.pt[1].y = TOP_OUTER_IO;
net.pt[1].x = x;
net.pt[2].name = "IOI_PCI_CE";
net.pt[2].start_count = 0;
net.pt[2].y = TOP_INNER_IO;
net.pt[2].x = x;
net.num_pts = 3;
if ((rc = add_conn_net(model, NO_PREF, &net))) RC_FAIL(model, rc);
}
if (has_device(model, model->y_height - BOT_OUTER_IO, x, DEV_ILOGIC)) {
net.last_inc = 0;
net.pt[0].name = "IOI_PCI_CE";
net.pt[0].start_count = 0;
net.pt[0].y = model->y_height - BOT_INNER_IO;
net.pt[0].x = x;
net.pt[1].name = "IOI_PCI_CE";
net.pt[1].start_count = 0;
net.pt[1].y = model->y_height - BOT_OUTER_IO;
net.pt[1].x = x;
net.pt[2].name = "BTERM_CLB_PCICE_N";
net.pt[2].start_count = 0;
net.pt[2].y = model->y_height - BOT_INNER_ROW;
net.pt[2].x = x;
net.num_pts = 3;
if ((rc = add_conn_net(model, NO_PREF, &net))) RC_FAIL(model, rc);
}
}
// top and bottom east-west wiring
rc = pcice_ew(model, TOP_INNER_ROW);
if (rc) RC_FAIL(model, rc);
rc = pcice_ew(model, model->y_height - BOT_INNER_ROW);
if (rc) RC_FAIL(model, rc);
RC_RETURN(model);
}
static int pcice_ew(struct fpga_model *model, int y)
{
int rc;
const struct seed_data top_seeds[] = {
{ X_LEFT_IO_DEVS_COL
| X_RIGHT_IO_DEVS_COL, "IOI_PCICE_EW" },
{ X_LEFT_MCB
| X_RIGHT_MCB, "MCB_PCICE_EW" },
{ X_FABRIC_LOGIC_ROUTING_COL
| X_CENTER_ROUTING_COL
| X_RIGHT_IO_ROUTING_COL, "IOI_TTERM_PCICE_EW" },
{ X_FABRIC_LOGIC_COL
| X_CENTER_LOGIC_COL, "TTERM_CLB_PCICE" },
{ X_FABRIC_BRAM_ROUTING_COL, "RAMB_TTERM_PCICE" },
{ X_FABRIC_BRAM_VIA_COL, "BRAM_INTER_PCICE" },
{ X_FABRIC_MACC_ROUTING_COL, "DSP_TTERM_PCICE" },
{ X_FABRIC_MACC_VIA_COL, "DSP_INTER_PCICE" },
{ 0 }};
const struct seed_data bot_seeds[] = {
{ X_LEFT_IO_DEVS_COL
| X_RIGHT_IO_DEVS_COL, "IOI_PCICE_EW" },
{ X_LEFT_MCB
| X_RIGHT_MCB, "MCB_PCICE_EW" },
{ X_FABRIC_LOGIC_ROUTING_COL
| X_CENTER_ROUTING_COL
| X_RIGHT_IO_ROUTING_COL
| X_FABRIC_MACC_ROUTING_COL, "IOI_TTERM_PCICE_EW" },
{ X_FABRIC_LOGIC_COL
| X_CENTER_LOGIC_COL
| X_FABRIC_MACC_VIA_COL, "BTERM_CLB_PCICE" },
{ X_FABRIC_BRAM_ROUTING_COL, "RAMB_TTERM_PCICE" },
{ X_FABRIC_BRAM_VIA_COL, "BRAM_INTER_PCICE" },
{ 0 }};
RC_CHECK(model);
if (y == TOP_INNER_ROW)
seed_strx(model, top_seeds);
else if (y == model->y_height - BOT_INNER_ROW)
seed_strx(model, bot_seeds);
else RC_FAIL(model, EINVAL);
//
// PCICE east-west wiring
//
// Go from center leftwards and rightwards, connect nets at
// bram and macc columns.
//
rc = pcice_ew_run(model, y, model->center_x - CENTER_LOGIC_O, DIR_LEFT);
if (rc) RC_FAIL(model, rc);
rc = pcice_ew_run(model, y, model->center_x + CENTER_X_PLUS_2, DIR_RIGHT);
if (rc) RC_FAIL(model, rc);
RC_RETURN(model);
}
static int pcice_ew_run(struct fpga_model *model, int y, int start_x, int x_dir)
{
int cur_x, rc;
struct w_net net;
RC_CHECK(model);
cur_x = start_x;
do {
rc = pcice_ew_fill_net(model, y, &cur_x, x_dir, &net);
if (rc) RC_FAIL(model, rc);
if ((rc = add_conn_net(model, NO_PREF, &net))) RC_FAIL(model, rc);
} while (cur_x != -1);
RC_RETURN(model);
}
static int pcice_ew_fill_net(struct fpga_model *model, int y, int *cur_x, int x_dir, struct w_net *net)
{
RC_CHECK(model);
net->last_inc = 0;
net->num_pts = 0;
if (is_atx(X_FABRIC_BRAM_COL|X_FABRIC_MACC_COL, model, *cur_x)) {
net->pt[net->num_pts].name =
is_atx(X_FABRIC_BRAM_COL, model, *cur_x)
? "BRAM_TTERM_PCICE_IN" : "MACCSITE2_TTERM_PCICE_IN";
net->pt[net->num_pts].start_count = 0;
net->pt[net->num_pts].y = y;
net->pt[net->num_pts].x = *cur_x;
net->num_pts++;
*cur_x += x_dir;
}
while (1) {
if (is_atx(X_FABRIC_BRAM_COL|X_FABRIC_MACC_COL, model, *cur_x)) {
net->pt[net->num_pts].name =
is_atx(X_FABRIC_BRAM_COL, model, *cur_x)
? "BRAM_TTERM_PCICE_OUT" : "MACCSITE2_TTERM_PCICE_OUT";
net->pt[net->num_pts].start_count = 0;
net->pt[net->num_pts].y = y;
net->pt[net->num_pts].x = *cur_x;
net->num_pts++;
break;
}
// todo: special case until is_at() system is better
if (y > model->center_y
&& is_atx(X_FABRIC_LOGIC_COL, model, *cur_x)
&& is_atx(X_ROUTING_NO_IO, model, (*cur_x)-1))
net->pt[net->num_pts].name = "CLB_EMP_TTERM_PCICE";
else
net->pt[net->num_pts].name = model->tmp_str[*cur_x];
net->pt[net->num_pts].start_count = 0;
net->pt[net->num_pts].y = y;
net->pt[net->num_pts].x = *cur_x;
net->num_pts++;
if (is_atx(X_LEFT_IO_DEVS_COL|X_RIGHT_IO_DEVS_COL, model, *cur_x)) {
*cur_x = -1;
break;
}
*cur_x += x_dir;
}
RC_RETURN(model);
}
static int pcice_left_right_io(struct fpga_model *model, int x)
{
struct w_net net;
int rc;
RC_CHECK(model);
// bottom-side
if ((rc = pcice_fill_net_io(model, &net, model->center_y + 1 + HCLK_POS,
"HCLK_PCI_CE_IN", HALF_ROW + ROW_SIZE, DIR_RIGHT, x))) RC_FAIL(model, rc);
if ((rc = add_conn_net(model, NO_PREF, &net))) RC_FAIL(model, rc);
if ((rc = pcice_fill_net_io(model, &net, model->center_y + 1 + HCLK_POS,
"HCLK_PCI_CE_OUT", HALF_ROW, DIR_LEFT, x))) RC_FAIL(model, rc);
if ((rc = add_conn_net(model, NO_PREF, &net))) RC_FAIL(model, rc);
// top-side
if ((rc = pcice_fill_net_io(model, &net, model->center_y - 1 - HCLK_POS,
"HCLK_PCI_CE_IN", HALF_ROW, DIR_RIGHT, x))) RC_FAIL(model, rc);
if ((rc = add_conn_net(model, NO_PREF, &net))) RC_FAIL(model, rc);
if ((rc = pcice_fill_net_io(model, &net, model->center_y - 1 - HCLK_POS,
"HCLK_PCI_CE_OUT", HALF_ROW + ROW_SIZE, DIR_LEFT, x))) RC_FAIL(model, rc);
if ((rc = add_conn_net(model, NO_PREF, &net))) RC_FAIL(model, rc);
RC_RETURN(model);
}
static int pcice_fill_net_io(struct fpga_model *model, struct w_net *net,
int hclk_start_y, const char *hclk_str, int y_range, int y_dir, int x)
{
int i, wired_flag;
RC_CHECK(model);
net->last_inc = 0;
net->pt[0].name = hclk_str;
net->pt[0].start_count = 0;
net->pt[0].y = hclk_start_y;
net->pt[0].x = x;
net->num_pts = 1;
wired_flag = (x < model->center_x) ? Y_LEFT_WIRED : Y_RIGHT_WIRED;
i = 0;
do {
i += y_dir;
if (is_aty(Y_ROW_HORIZ_AXSYMM, model, hclk_start_y+i)) {
net->pt[net->num_pts].name = "HCLK_PCI_CE_INOUT";
net->pt[net->num_pts].start_count = 0;
net->pt[net->num_pts].y = hclk_start_y+i;
net->pt[net->num_pts].x = x;
net->num_pts++;
} else if (is_aty(wired_flag, model, hclk_start_y+i)) {
while (net->pt[net->num_pts-1].y != hclk_start_y+i-1*y_dir) {
net->pt[net->num_pts].name = "EMP_IOI_PCI_CE";
net->pt[net->num_pts].start_count = 0;
net->pt[net->num_pts].y = net->pt[net->num_pts-1].y+y_dir;
net->pt[net->num_pts].x = x;
net->num_pts++;
}
net->pt[net->num_pts].name = "IOI_PCI_CE";
net->pt[net->num_pts].start_count = 0;
net->pt[net->num_pts].y = hclk_start_y+i;
net->pt[net->num_pts].x = x;
net->num_pts++;
}
} while (i != y_range*y_dir);
RC_RETURN(model);
}
static int pcice_left_right_devs(struct fpga_model *model, int x)
{
struct w_net net;
RC_CHECK(model);
// Connect the left and right center upwards and downwards
// one half-row including the subsequent hclk.
pcice_fill_net_devs(model, &net, model->center_y - HCLK_POS - 1, model->center_y + HCLK_POS + 1, x);
add_conn_net(model, NO_PREF, &net);
add_switch(model, TOP_INNER_ROW, x,
"IOI_PCICE_TB", "IOI_PCICE_EW", /*bidir*/ 0);
RC_ASSERT(model, model->center_y-HCLK_POS-1-ROW_SIZE == TOP_FIRST_REGULAR+HCLK_POS);
add_switch(model, TOP_FIRST_REGULAR+HCLK_POS, x,
"HCLK_PCI_CE_SPLIT", "HCLK_PCI_CE_INOUT", /*bidir*/ 0);
add_switch(model, model->center_y-HCLK_POS-1, x,
"HCLK_PCI_CE_OUT", "HCLK_PCI_CE_IN", /*bidir*/ 0);
add_switch(model, model->center_y-HCLK_POS-1, x,
"HCLK_PCI_CE_TRUNK_IN", "HCLK_PCI_CE_TRUNK_OUT", /*bidir*/ 0);
add_switch(model, model->center_y, x,
"REGH_IOI_PCI_CE", "REGH_IOI_PCICE_TB", /*bidir*/ 0);
// top-side net
pcice_fill_net_devs(model, &net, TOP_INNER_ROW, model->center_y - HCLK_POS - 1, x);
add_conn_net(model, NO_PREF, &net);
// bottom-side net
pcice_fill_net_devs(model, &net, model->center_y + HCLK_POS + 1, model->y_height - BOT_INNER_ROW, x);
add_conn_net(model, NO_PREF, &net);
RC_ASSERT(model, model->y_height-BOT_LAST_REGULAR_O-HCLK_POS-ROW_SIZE == model->center_y+1+HCLK_POS);
add_switch(model, model->center_y+1+HCLK_POS, x,
"HCLK_PCI_CE_IN", "HCLK_PCI_CE_OUT", /*bidir*/ 0);
add_switch(model, model->center_y+1+HCLK_POS, x,
"HCLK_PCI_CE_TRUNK_OUT", "HCLK_PCI_CE_TRUNK_IN", /*bidir*/ 0);
add_switch(model, model->y_height-BOT_LAST_REGULAR_O-HCLK_POS, x,
"HCLK_PCI_CE_SPLIT", "HCLK_PCI_CE_INOUT", /*bidir*/ 0);
add_switch(model, model->y_height-BOT_INNER_ROW, x,
"IOI_PCICE_TB", "IOI_PCICE_EW", /*bidir*/ 0);
RC_RETURN(model);
}
static int pcice_fill_net_devs(struct fpga_model *model, struct w_net *net,
int first_y, int last_y, int x)
{
int y, wired_flag;
RC_CHECK(model);
//
// rules for non-regular tiles:
//
// term: pcice_tb
// if first y is hclk: trunk_in
// middle hclk: ce_split
// center regs: pcice_tb
// if last y is hclk: trunk_out
//
net->last_inc = 0;
net->num_pts = 0;
wired_flag = (x < model->center_x) ? Y_LEFT_WIRED : Y_RIGHT_WIRED;
for (y = first_y; y <= last_y; y++) {
if (is_aty(Y_INNER_TOP | Y_INNER_BOTTOM, model, y))
net->pt[net->num_pts].name = "IOI_PCICE_TB";
else if (is_aty(Y_CHIP_HORIZ_REGS, model, y))
net->pt[net->num_pts].name = "REGH_IOI_PCICE_TB";
else if (is_aty(Y_ROW_HORIZ_AXSYMM, model, y)) {
if (y == first_y)
net->pt[net->num_pts].name = "HCLK_PCI_CE_TRUNK_IN";
else if (y == last_y)
net->pt[net->num_pts].name = "HCLK_PCI_CE_TRUNK_OUT";
else
net->pt[net->num_pts].name = "HCLK_PCI_CE_SPLIT";
} else {
RC_ASSERT(model, is_aty(Y_REGULAR_ROW, model, y));
// todo: this logic also appears in run_logic_inout() and
// may justify a better subfunc
if (has_device(model, y, x, DEV_BSCAN)
|| has_device(model, y, x, DEV_OCT_CALIBRATE)
|| has_device(model, y, x, DEV_STARTUP))
net->pt[net->num_pts].name = "EMP_IOI_PCI_CE";
else
net->pt[net->num_pts].name =
is_aty(wired_flag, model, y)
? "IOI_PCI_CE_THRU" : "EMP_IOI_PCI_CE_THRU";
}
net->pt[net->num_pts].start_count = 0;
net->pt[net->num_pts].y = y;
net->pt[net->num_pts].x = x;
net->num_pts++;
}
RC_RETURN(model);
}
static int term_topbot(struct fpga_model* model)
{
struct w_net net;
int x, y, i, rc;
RC_CHECK(model);
//
// wires going from the top and bottom term tiles vertically to
// support the two ILOGIC/OLOGIC/IODELAY tiles below or above the
// term tile.
//
for (x = LEFT_SIDE_WIDTH+1; x < model->x_width - RIGHT_SIDE_WIDTH; x++) {
//
// top
//
y = TOP_INNER_ROW;
if (has_device(model, y+1, x, DEV_ILOGIC)) {
{struct w_net n = {
.last_inc = 3, .num_pts = 3, .pt =
{{ "TTERM_CLB_IOCE%i_S", 0, y, x },
{ "TIOI_IOCE%i", 0, y+1, x },
{ "TIOI_INNER_IOCE%i", 0, y+2, x }}};
if ((rc = add_conn_net(model, NO_PREF, &n))) RC_FAIL(model, rc); }
{struct w_net n = {
.last_inc = 3, .num_pts = 3, .pt =
{{ "TTERM_CLB_IOCLK%i_S", 0, y, x },
{ "TIOI_IOCLK%i", 0, y+1, x },
{ "TIOI_INNER_IOCLK%i", 0, y+2, x }}};
if ((rc = add_conn_net(model, NO_PREF, &n))) RC_FAIL(model, rc); }
{struct w_net n = {
.last_inc = 1, .num_pts = 3, .pt =
{{ "TTERM_CLB_PLLCE%i_S", 0, y, x },
{ "TIOI_PLLCE%i", 0, y+1, x },
{ "TIOI_INNER_PLLCE%i", 0, y+2, x }}};
if ((rc = add_conn_net(model, NO_PREF, &n))) RC_FAIL(model, rc); }
{struct w_net n = {
.last_inc = 1, .num_pts = 3, .pt =
{{ "TTERM_CLB_PLLCLK%i_S", 0, y, x },
{ "TIOI_PLLCLK%i", 0, y+1, x },
{ "TIOI_INNER_PLLCLK%i", 0, y+2, x }}};
if ((rc = add_conn_net(model, NO_PREF, &n))) RC_FAIL(model, rc); }
}
//
// bottom
//
y = model->y_height - BOT_INNER_ROW;
// wiring up of IOLOGIC devices:
if (has_device(model, y-1, x, DEV_ILOGIC)) {
// IOCE
{struct w_net n = {
.last_inc = 3, .num_pts = 3, .pt =
{{ "BTERM_CLB_CEOUT%i_N", 0, y, x },
{ "TIOI_IOCE%i", 0, y-1, x },
{ "BIOI_INNER_IOCE%i", 0, y-2, x }}};
if ((rc = add_conn_net(model, NO_PREF, &n))) RC_FAIL(model, rc); }
// IOCLK
{struct w_net n = {
.last_inc = 3, .num_pts = 3, .pt =
{{ "BTERM_CLB_CLKOUT%i_N", 0, y, x },
{ "TIOI_IOCLK%i", 0, y-1, x },
{ "BIOI_INNER_IOCLK%i", 0, y-2, x }}};
if ((rc = add_conn_net(model, NO_PREF, &n))) RC_FAIL(model, rc); }
// PLLCE
{struct w_net n = {
.last_inc = 1, .num_pts = 3, .pt =
{{ "BTERM_CLB_PLLCEOUT%i_N", 0, y, x },
{ "TIOI_PLLCE%i", 0, y-1, x },
{ "BIOI_INNER_PLLCE%i", 0, y-2, x }}};
if ((rc = add_conn_net(model, NO_PREF, &n))) RC_FAIL(model, rc); }
// PLLCLK
{struct w_net n = {
.last_inc = 1, .num_pts = 3, .pt =
{{ "BTERM_CLB_PLLCLKOUT%i_N", 0, y, x },
{ "TIOI_PLLCLK%i", 0, y-1, x },
{ "BIOI_INNER_PLLCLK%i", 0, y-2, x }}};
if ((rc = add_conn_net(model, NO_PREF, &n))) RC_FAIL(model, rc); }
}
}
//
// Horizontally connect the top and bottom center of the chip
// to the left and right side termination tiles. IOCE and IOCLK
// have two separate nets on the left and right side, PLLCE
// and PLLCLK have one net covering the entire chip from
// left to right.
//
//
// top
//
rc = add_conn_range(model, NOPREF_BI_F,
TOP_OUTER_ROW, model->center_x-CENTER_CMTPLL_O, "REGT_PLLCLK%i", 0, 1,
TOP_INNER_ROW, model->center_x-CENTER_CMTPLL_O, "REGT_TTERM_PLL_CLKOUT%i_N", 0);
if (rc) RC_FAIL(model, rc);
rc = add_conn_range(model, NOPREF_BI_F,
TOP_OUTER_ROW, model->center_x-CENTER_CMTPLL_O, "REGT_CEOUT%i", 0, 1,
TOP_INNER_ROW, model->center_x-CENTER_CMTPLL_O, "REGT_TTERM_PLL_CEOUT%i_N", 0);
if (rc) RC_FAIL(model, rc);
{
// strings are filled in below - must match offsets
struct seed_data seeds[] = {
/* 0 */ { X_FABRIC_LOGIC_ROUTING_COL | X_CENTER_ROUTING_COL },
/* 1 */ { X_FABRIC_LOGIC_COL | X_CENTER_LOGIC_COL },
/* 2 */ { X_FABRIC_BRAM_ROUTING_COL | X_FABRIC_BRAM_COL },
/* 3 */ { X_FABRIC_BRAM_VIA_COL },
/* 4 */ { X_FABRIC_MACC_ROUTING_COL | X_FABRIC_MACC_COL },
/* 5 */ { X_FABRIC_MACC_VIA_COL },
/* 6 */ { X_CENTER_CMTPLL_COL },
/* 7 */ { X_CENTER_REGS_COL },
{ 0 }};
y = TOP_INNER_ROW;
for (i = 0; i < 4; i++) {
if (i == 0) { // 0 = IOCE
seeds[0].str = "IOI_TTERM_IOCE%i";
seeds[1].str = "TTERM_CLB_IOCE%i";
seeds[2].str = "BRAM_TTERM_IOCE%i";
seeds[3].str = "BRAM_INTER_TTERM_IOCE%i";
seeds[4].str = "DSP_TTERM_IOCE%i";
seeds[5].str = "DSP_INTER_TTERM_IOCE%i";
seeds[6].str = "REGT_TTERM_IOCEOUT%i";
seeds[7].str = "REGV_TTERM_IOCEOUT%i";
net.last_inc = 3;
seed_strx(model, seeds);
for (x = LEFT_SIDE_WIDTH+1; x < model->x_width - RIGHT_SIDE_WIDTH; x++) {
// CEOUT to center
if (x == model->center_x-CENTER_CMTPLL_O) {
rc = add_conn_range(model, NOPREF_BI_F, y, x,
model->tmp_str[x], 0, 7,
y-1, model->center_x-CENTER_CMTPLL_O,
"REGT_IOCEOUT%i", 0);
if (rc) RC_FAIL(model, rc);
} else if (x == model->center_x) {
rc = add_conn_range(model, NOPREF_BI_F, y, x,
model->tmp_str[x], 4, 7,
y-1, model->center_x-CENTER_CMTPLL_O,
"REGT_IOCEOUT%i", 4);
if (rc) RC_FAIL(model, rc);
} else {
rc = add_conn_range(model, NOPREF_BI_F, y, x,
model->tmp_str[x], 0, 3,
y-1, model->center_x-CENTER_CMTPLL_O,
"REGT_IOCEOUT%i", x < model->center_x ? 0 : 4);
if (rc) RC_FAIL(model, rc);
}
}
} else if (i == 1) { // 1 = IOCLK
seeds[0].str = "IOI_TTERM_IOCLK%i";
seeds[1].str = "TTERM_CLB_IOCLK%i";
seeds[2].str = "BRAM_TTERM_IOCLK%i";
seeds[3].str = "BRAM_INTER_TTERM_IOCLK%i";
seeds[4].str = "DSP_TTERM_IOCLK%i";
seeds[5].str = "DSP_INTER_TTERM_IOCLK%i";
seeds[6].str = "REGT_TTERM_IOCLKOUT%i";
seeds[7].str = "REGV_TTERM_IOCLKOUT%i";
net.last_inc = 3;
seed_strx(model, seeds);
for (x = LEFT_SIDE_WIDTH+1; x < model->x_width - RIGHT_SIDE_WIDTH; x++) {
// CLKOUT to center
if (x == model->center_x-CENTER_CMTPLL_O) {
rc = add_conn_range(model, NOPREF_BI_F, y, x,
model->tmp_str[x], 0, 7,
y-1, model->center_x-CENTER_CMTPLL_O,
"REGT_IOCLKOUT%i", 0);
if (rc) RC_FAIL(model, rc);
} else if (x == model->center_x) {
rc = add_conn_range(model, NOPREF_BI_F, y, x,
model->tmp_str[x], 4, 7,
y-1, model->center_x-CENTER_CMTPLL_O,
"REGT_IOCLKOUT%i", 4);
if (rc) RC_FAIL(model, rc);
} else {
rc = add_conn_range(model, NOPREF_BI_F, y, x,
model->tmp_str[x], 0, 3,
y-1, model->center_x-CENTER_CMTPLL_O,
"REGT_IOCLKOUT%i", x < model->center_x ? 0 : 4);
if (rc) RC_FAIL(model, rc);
}
}
} else if (i == 2) { // 2 = PLLCE
seeds[0].str = "IOI_TTERM_PLLCE%i";
seeds[1].str = "TTERM_CLB_PLLCE%i";
seeds[2].str = "BRAM_TTERM_PLLCE%i";
seeds[3].str = "BRAM_INTER_TTERM_PLLCE%i";
seeds[4].str = "DSP_TTERM_PLLCE%i";
seeds[5].str = "DSP_INTER_TTERM_PLLCE%i";
seeds[6].str = "REGT_TTERM_PLL_CEOUT%i";
seeds[7].str = "REGV_TTERM_CEOUT%i";
net.last_inc = 1;
seed_strx(model, seeds);
} else { // 3 = PLLCLK
seeds[0].str = "IOI_TTERM_PLLCLK%i";
seeds[1].str = "TTERM_CLB_PLLCLK%i";
seeds[2].str = "BRAM_TTERM_PLLCLK%i";
seeds[3].str = "BRAM_INTER_TTERM_PLLCLK%i";
seeds[4].str = "DSP_TTERM_PLLCLK%i";
seeds[5].str = "DSP_INTER_TTERM_PLLCLK%i";
seeds[6].str = "REGT_TTERM_PLL_CLKOUT%i";
seeds[7].str = "REGV_TTERM_CLKOUT%i";
net.last_inc = 1;
seed_strx(model, seeds);
}
net.num_pts = 0;
// The leftmost and rightmost columns of the fabric area are exempt.
for (x = LEFT_SIDE_WIDTH+1; x < model->x_width - RIGHT_SIDE_WIDTH; x++) {
EXIT(net.num_pts >= sizeof(net.pt)/sizeof(net.pt[0]));
EXIT(!model->tmp_str[x]);
// left and right half separate only for CEOUT and CLKOUT
if (i < 2 && is_atx(X_CENTER_CMTPLL_COL, model, x)) {
// connect left side
// left side connects to 0:3, right side to 4:7
net.pt[net.num_pts].start_count = 0;
net.pt[net.num_pts].x = x;
net.pt[net.num_pts].y = TOP_INNER_ROW;
net.pt[net.num_pts].name = model->tmp_str[x];
net.num_pts++;
if ((rc = add_conn_net(model, NO_PREF, &net))) RC_FAIL(model, rc);
// start right half
net.pt[0].start_count = 4;
net.pt[0].x = x;
net.pt[0].y = TOP_INNER_ROW;
net.pt[0].name = model->tmp_str[x];
x++;
net.pt[1].start_count = 4;
net.pt[1].x = x;
net.pt[1].y = TOP_INNER_ROW;
net.pt[1].name = model->tmp_str[x];
net.num_pts = 2;
} else {
net.pt[net.num_pts].start_count = 0;
net.pt[net.num_pts].x = x;
net.pt[net.num_pts].y = TOP_INNER_ROW;
net.pt[net.num_pts].name = model->tmp_str[x];
net.num_pts++;
}
}
// connect all (PLL) or just right side
if ((rc = add_conn_net(model, NO_PREF, &net))) RC_FAIL(model, rc);
}
}
//
// bottom
//
rc = add_conn_range(model, NOPREF_BI_F,
model->y_height-BOT_OUTER_ROW, model->center_x-CENTER_CMTPLL_O, "REGB_PLLCLK%i", 0, 1,
model->y_height-BOT_INNER_ROW, model->center_x-CENTER_CMTPLL_O, "REGB_BTERM_PLL_CLKOUT%i_S", 0);
if (rc) RC_FAIL(model, rc);
rc = add_conn_range(model, NOPREF_BI_F,
model->y_height-BOT_OUTER_ROW, model->center_x-CENTER_CMTPLL_O, "REGB_CEOUT%i", 0, 1,
model->y_height-BOT_INNER_ROW, model->center_x-CENTER_CMTPLL_O, "REGB_BTERM_PLL_CEOUT%i_S", 0);
if (rc) RC_FAIL(model, rc);
{
// strings are filled in below - must match offsets
struct seed_data seeds[] = {
/* 0 */ { X_FABRIC_ROUTING_COL | X_FABRIC_MACC_COL
| X_FABRIC_BRAM_COL | X_CENTER_ROUTING_COL },
/* 1 */ { X_FABRIC_LOGIC_COL | X_FABRIC_BRAM_VIA_COL
| X_FABRIC_MACC_VIA_COL | X_CENTER_LOGIC_COL },
/* 2 */ { X_CENTER_CMTPLL_COL },
/* 3 */ { X_CENTER_REGS_COL },
{ 0 }};
y = model->y_height - BOT_INNER_ROW;
for (i = 0; i < 4; i++) {
if (i == 0) { // 0 = CEOUT
seeds[0].str = "IOI_BTERM_CEOUT%i";
seeds[1].str = "BTERM_CLB_CEOUT%i";
seeds[2].str = "REGB_BTERM_IOCEOUT%i";
seeds[3].str = "REGV_BTERM_CEOUT%i";
net.last_inc = 3;
seed_strx(model, seeds);
for (x = LEFT_SIDE_WIDTH+1; x < model->x_width - RIGHT_SIDE_WIDTH; x++) {
// CEOUT to center
if (x == model->center_x-CENTER_CMTPLL_O) {
rc = add_conn_range(model, NOPREF_BI_F, y, x,
model->tmp_str[x], 0, 7,
y+1, model->center_x-CENTER_CMTPLL_O,
"REGB_IOCEOUT%i", 0);
if (rc) RC_FAIL(model, rc);
} else {
rc = add_conn_range(model, NOPREF_BI_F, y, x,
model->tmp_str[x], 0, 3,
y+1, model->center_x-CENTER_CMTPLL_O,
"REGB_IOCEOUT%i", x < model->center_x ? 4 : 0);
if (rc) RC_FAIL(model, rc);
}
}
} else if (i == 1) { // 1 = CLKOUT
seeds[0].str = "IOI_BTERM_CLKOUT%i";
seeds[1].str = "BTERM_CLB_CLKOUT%i";
seeds[2].str = "REGB_BTERM_IOCLKOUT%i";
seeds[3].str = "REGV_BTERM_CLKOUT%i";
net.last_inc = 3;
seed_strx(model, seeds);
for (x = LEFT_SIDE_WIDTH+1; x < model->x_width - RIGHT_SIDE_WIDTH; x++) {
// CECLK to center
if (x == model->center_x-CENTER_CMTPLL_O) {
rc = add_conn_range(model, NOPREF_BI_F, y, x,
model->tmp_str[x], 0, 7,
y+1, model->center_x-CENTER_CMTPLL_O,
"REGB_IOCLKOUT%i", 0);
if (rc) RC_FAIL(model, rc);
} else {
rc = add_conn_range(model, NOPREF_BI_F, y, x,
model->tmp_str[x], 0, 3,
y+1, model->center_x-CENTER_CMTPLL_O,
"REGB_IOCLKOUT%i", x < model->center_x ? 4 : 0);
if (rc) RC_FAIL(model, rc);
}
}
} else if (i == 2) { // 2 = PLLCEOUT
seeds[0].str = "IOI_BTERM_PLLCEOUT%i";
seeds[1].str = "BTERM_CLB_PLLCEOUT%i";
seeds[2].str = "REGB_BTERM_PLL_CEOUT%i";
seeds[3].str = "REGV_BTERM_PLLCEOUT%i";
net.last_inc = 1;
seed_strx(model, seeds);
} else { // 3 = PLLCLKOUT
seeds[0].str = "IOI_BTERM_PLLCLKOUT%i";
seeds[1].str = "BTERM_CLB_PLLCLKOUT%i";
seeds[2].str = "REGB_BTERM_PLL_CLKOUT%i";
seeds[3].str = "REGV_BTERM_PLLCLKOUT%i";
net.last_inc = 1;
seed_strx(model, seeds);
}
net.num_pts = 0;
// The leftmost and rightmost columns of the fabric area are exempt.
for (x = LEFT_SIDE_WIDTH+1; x < model->x_width - RIGHT_SIDE_WIDTH; x++) {
EXIT(net.num_pts >= sizeof(net.pt)/sizeof(net.pt[0]));
EXIT(!model->tmp_str[x]);
// left and right half separate only for CEOUT and CLKOUT
if (i < 2 && is_atx(X_CENTER_CMTPLL_COL, model, x)) {
// connect left side
// left side connects to 4:7, right side to 0:3
net.pt[net.num_pts].start_count = 4;
net.pt[net.num_pts].x = x;
net.pt[net.num_pts].y = model->y_height - BOT_INNER_ROW;
net.pt[net.num_pts].name = model->tmp_str[x];
net.num_pts++;
if ((rc = add_conn_net(model, NO_PREF, &net))) RC_FAIL(model, rc);
// start right half
net.num_pts = 0;
}
net.pt[net.num_pts].start_count = 0;
net.pt[net.num_pts].x = x;
net.pt[net.num_pts].y = model->y_height - BOT_INNER_ROW;
net.pt[net.num_pts].name = model->tmp_str[x];
net.num_pts++;
}
// connect all (PLL) or just right side
if ((rc = add_conn_net(model, NO_PREF, &net))) RC_FAIL(model, rc);
}
}
RC_RETURN(model);
}
static int term_leftright_x(struct fpga_model *model, int x)
{
struct w_net net;
int y, i, rc;
const char *tmp_str;
// strings are filled in below - must match offsets
struct seed_data seeds[] = {
/* 0 */ { Y_REGULAR_ROW },
/* 1 */ { Y_ROW_HORIZ_AXSYMM },
/* 2 */ { Y_CHIP_HORIZ_REGS },
{ 0 }};
RC_CHECK(model);
//
// Similar to term_topbot(), there are vertical nets connecting
// IOCE/IOCLK and PLLCE/PLLCLK through the left and right term
// tiles. The IO nets are covering the entire chip top-to-bottom,
// the PLL nets are split between top and bottom net.
// The upmost and bottommost half-row are not included in the nets.
//
for (i = 0; i < 4; i++) { // IOCE (0), IOCLK (1), PLLCE (2), PLLCLK (3)
// 1. seeding and single connections from inner_col
// to outer_col center (IOCE and IOCLK only).
if (i == 0) { // 0 = IOCE
if (x == LEFT_INNER_COL) {
seeds[0].str = "IOI_LTERM_IOCE%i";
seeds[1].str = "HCLK_IOI_LTERM_IOCE%i";
seeds[2].str = "REGH_LTERM_IOCEOUT%i";
tmp_str = "REGL_IOCEOUT%i";
} else if (x == model->x_width - RIGHT_INNER_O) {
seeds[0].str = "IOI_RTERM_IOCE%i";
seeds[1].str = "HCLK_IOI_RTERM_IOCE%i";
seeds[2].str = "REGH_RTERM_IOCEOUT%i";
tmp_str = "REGR_IOCEOUT%i";
} else RC_FAIL(model, EINVAL);
net.last_inc = 3;
seed_stry(model, seeds);
for (y = TOP_FIRST_REGULAR + HALF_ROW; y <= model->y_height
- BOT_LAST_REGULAR_O - HALF_ROW; y++) {
rc = add_conn_range(model, NOPREF_BI_F, y, x,
model->tmp_str[y], 0, (y == model->center_y) ? 7 : 3,
model->center_y,
(x == LEFT_INNER_COL) ? LEFT_OUTER_COL : model->x_width-RIGHT_OUTER_O,
tmp_str, (y == model->center_y) ? 0
: (((y < model->center_y) ^ (x != LEFT_INNER_COL)) ? 4 : 0));
if (rc) RC_FAIL(model, rc);
}
} else if (i == 1) { // 1 = IOCLK
if (x == LEFT_INNER_COL) {
seeds[0].str = "IOI_LTERM_IOCLK%i";
seeds[1].str = "HCLK_IOI_LTERM_IOCLK%i";
seeds[2].str = "REGH_LTERM_IOCLKOUT%i";
tmp_str = "REGL_IOCLKOUT%i";
} else if (x == model->x_width - RIGHT_INNER_O) {
seeds[0].str = "IOI_RTERM_IOCLK%i";
seeds[1].str = "HCLK_IOI_RTERM_IOCLK%i";
seeds[2].str = "REGH_RTERM_IOCLKOUT%i";
tmp_str = "REGR_IOCLKOUT%i";
} else RC_FAIL(model, EINVAL);
net.last_inc = 3;
seed_stry(model, seeds);
for (y = TOP_FIRST_REGULAR + HALF_ROW; y <= model->y_height
- BOT_LAST_REGULAR_O - HALF_ROW; y++) {
rc = add_conn_range(model, NOPREF_BI_F, y, x,
model->tmp_str[y], 0, (y == model->center_y) ? 7 : 3,
model->center_y,
(x == LEFT_INNER_COL) ? LEFT_OUTER_COL : model->x_width-RIGHT_OUTER_O,
tmp_str, (y == model->center_y) ? 0
: (((y < model->center_y) ^ (x != LEFT_INNER_COL)) ? 4 : 0));
if (rc) RC_FAIL(model, rc);
}
} else if (i == 2) { // 2 = PLLCE
if (x == LEFT_INNER_COL) {
seeds[0].str = "IOI_LTERM_PLLCE%i";
seeds[1].str = "HCLK_IOI_LTERM_PLLCE%i";
seeds[2].str = "REGH_LTERM_PLL_CEOUT%i";
} else if (x == model->x_width - RIGHT_INNER_O) {
seeds[0].str = "IOI_RTERM_PLLCEOUT%i";
seeds[1].str = "HCLK_IOI_RTERM_PLLCEOUT%i";
seeds[2].str = "REGH_RTERM_PLL_CEOUT%i";
} else RC_FAIL(model, EINVAL);
net.last_inc = 1;
seed_stry(model, seeds);
} else { // 3 = PLLCLK
if (x == LEFT_INNER_COL) {
seeds[0].str = "IOI_LTERM_PLLCLK%i";
seeds[1].str = "HCLK_IOI_LTERM_PLLCLK%i";
seeds[2].str = "REGH_LTERM_PLL_CLKOUT%i";
} else if (x == model->x_width - RIGHT_INNER_O) {
seeds[0].str = "IOI_RTERM_PLLCLKOUT%i";
seeds[1].str = "HCLK_IOI_RTERM_PLLCLKOUT%i";
seeds[2].str = "REGH_RTERM_PLL_CLKOUT%i";
} else RC_FAIL(model, EINVAL);
net.last_inc = 1;
seed_stry(model, seeds);
}
// 2. vertical net inside inner_col
net.num_pts = 0;
for (y = TOP_FIRST_REGULAR + HALF_ROW; y <= model->y_height
- BOT_LAST_REGULAR_O - HALF_ROW; y++) {
RC_ASSERT(model, net.num_pts < sizeof(net.pt)/sizeof(net.pt[0])
&& model->tmp_str[y]);
// top and bottom half separate for IOCE and IOCLK
if (i < 2 && is_aty(Y_CHIP_HORIZ_REGS, model, y)) {
// connect top half:
// left top to 4:7, left bottom to 0:3
// right top to 0:3, right bottom to 4:7
net.pt[net.num_pts].start_count =
(x == LEFT_INNER_COL) ? 4 : 0;
net.pt[net.num_pts].x = x;
net.pt[net.num_pts].y = y;
net.pt[net.num_pts].name = model->tmp_str[y];
net.num_pts++;
if ((rc = add_conn_net(model, NO_PREF, &net))) RC_FAIL(model, rc);
// start bottom
net.pt[0].start_count =
(x == LEFT_INNER_COL) ? 0 : 4;
net.pt[0].x = x;
net.pt[0].y = y;
net.pt[0].name = model->tmp_str[y];
net.num_pts = 1;
continue;
}
net.pt[net.num_pts].start_count = 0;
net.pt[net.num_pts].x = x;
net.pt[net.num_pts].y = y;
net.pt[net.num_pts].name = model->tmp_str[y];
net.num_pts++;
}
// connect all (PLL) or just top/bottom (IO)
if ((rc = add_conn_net(model, NO_PREF, &net))) RC_FAIL(model, rc);
}
RC_RETURN(model);
}
static int term_leftright(struct fpga_model *model)
{
int rc;
RC_CHECK(model);
rc = term_leftright_x(model, LEFT_INNER_COL);
if (rc) RC_FAIL(model, rc);
rc = term_leftright_x(model, model->x_width - RIGHT_INNER_O);
if (rc) RC_FAIL(model, rc);
RC_RETURN(model);
}
static int net_up_down(struct fpga_model *model, int hclk_y, int up_down_x,
enum extra_wires wire, struct w_net *up_net, struct w_net *down_net)
{
const char *s1;
int last_inc, i;
RC_CHECK(model);
if (wire == IOCE) {
s1 = "IOCE";
last_inc = 3;
} else if (wire == IOCLK) {
s1 = "IOCLK";
last_inc = 3;
} else if (wire == PLLCE) {
s1 = "PLLCE";
last_inc = 1;
} else if (wire == PLLCLK) {
s1 = "PLLCLK";
last_inc = 1;
} else RC_FAIL(model, EINVAL);
up_net->last_inc = last_inc;
up_net->pt[0].name = pf("HCLK_IOIL_%s%%i_UP", s1);
up_net->pt[0].start_count = 0;
up_net->pt[0].y = hclk_y;
up_net->pt[0].x = up_down_x;
up_net->num_pts = 1;
down_net->last_inc = last_inc;
down_net->pt[0].name = pf("HCLK_IOIL_%s%%i_DOWN", s1);
down_net->pt[0].start_count = 0;
down_net->pt[0].y = hclk_y;
down_net->pt[0].x = up_down_x;
down_net->num_pts = 1;
for (i = 0; i < HALF_ROW; i++) {
if (has_device(model, hclk_y-1-i, up_down_x, DEV_IODELAY)) {
while (up_net->pt[up_net->num_pts-1].y > hclk_y-1-i+1) {
up_net->pt[up_net->num_pts].name = pf("INT_INTERFACE_%s%%i", s1);
up_net->pt[up_net->num_pts].start_count = 0;
up_net->pt[up_net->num_pts].y = up_net->pt[up_net->num_pts-1].y-1;
up_net->pt[up_net->num_pts].x = up_down_x;
up_net->num_pts++;
}
up_net->pt[up_net->num_pts].name = pf("%s_%s%%i",
up_down_x < model->center_x ? "IOI" : "RIOI", s1);
up_net->pt[up_net->num_pts].start_count = 0;
up_net->pt[up_net->num_pts].y = hclk_y-1-i;
up_net->pt[up_net->num_pts].x = up_down_x;
up_net->num_pts++;
}
if (has_device(model, hclk_y+1+i, up_down_x, DEV_IODELAY)) {
while (down_net->pt[down_net->num_pts-1].y < hclk_y+1+i-1) {
down_net->pt[down_net->num_pts].name = pf("INT_INTERFACE_%s%%i", s1);
down_net->pt[down_net->num_pts].start_count = 0;
down_net->pt[down_net->num_pts].y = down_net->pt[down_net->num_pts-1].y+1;
down_net->pt[down_net->num_pts].x = up_down_x;
down_net->num_pts++;
}
down_net->pt[down_net->num_pts].name = pf("%s_%s%%i",
up_down_x < model->center_x ? "IOI" : "RIOI", s1);
down_net->pt[down_net->num_pts].start_count = 0;
down_net->pt[down_net->num_pts].y = hclk_y+1+i;
down_net->pt[down_net->num_pts].x = up_down_x;
down_net->num_pts++;
}
}
RC_RETURN(model);
}
static int term_to_io(struct fpga_model *model, enum extra_wires wire)
{
struct w_net up_net, down_net, net;
const char *s1;
int last_inc, y, i, rc;
RC_CHECK(model);
// from termination into fabric via hclk
if (wire == IOCE) {
s1 = "IOCE";
last_inc = 3;
} else if (wire == IOCLK) {
s1 = "IOCLK";
last_inc = 3;
} else if (wire == PLLCE) {
s1 = "PLLCE";
last_inc = 1;
} else if (wire == PLLCLK) {
s1 = "PLLCLK";
last_inc = 1;
} else RC_FAIL(model, EINVAL);
//
// left
//
if (wire == PLLCLK) {
rc = add_conn_range(model, NOPREF_BI_F,
model->center_y, LEFT_OUTER_COL, "REGL_PLL_CLKOUT%i_LEFT", 0, 1,
model->center_y, LEFT_INNER_COL, "REGH_LTERM_PLL_CLKOUT%i_W", 0);
if (rc) RC_FAIL(model, rc);
} else if (wire == PLLCE) {
rc = add_conn_range(model, NOPREF_BI_F,
model->center_y, LEFT_OUTER_COL, "REGL_PLL_CEOUT%i_LEFT", 0, 1,
model->center_y, LEFT_INNER_COL, "REGH_LTERM_PLL_CEOUT%i_W", 0);
if (rc) RC_FAIL(model, rc);
}
for (y = TOP_FIRST_REGULAR; y <= model->y_height - BOT_LAST_REGULAR_O; y++) {
if (!is_aty(Y_ROW_HORIZ_AXSYMM, model, y))
continue;
{ struct w_net n = {
.last_inc = last_inc, .num_pts = 3, .pt =
{{ pf("HCLK_IOI_LTERM_%s%%i_E", s1), 0, y, LEFT_INNER_COL },
{ pf("HCLK_IOI_INT_%s%%i", s1), 0, y, LEFT_IO_ROUTING },
{ pf("HCLK_IOIL_%s%%i", s1), 0, y, LEFT_IO_DEVS }}};
if (wire == PLLCLK
&& model->die->mcb_ypos >= y-HALF_ROW
&& model->die->mcb_ypos <= y+HALF_ROW ) {
n.pt[3].name = "HCLK_MCB_PLLCLKOUT%i_W";
n.pt[3].start_count = 0;
n.pt[3].y = y;
n.pt[3].x = LEFT_MCB_COL;
n.num_pts = 4;
rc = add_conn_bi(model,
y, LEFT_MCB_COL, "MCB_HCLK_PLLCLKO_PINW",
model->die->mcb_ypos, LEFT_MCB_COL, "MCB_L_PLLCLK0_PW");
if (rc) RC_FAIL(model, rc);
rc = add_conn_bi(model,
y, LEFT_MCB_COL, "MCB_HCLK_PLLCLK1_PINW",
model->die->mcb_ypos, LEFT_MCB_COL, "MCB_L_PLLCLK1_PW");
if (rc) RC_FAIL(model, rc);
} else if (wire == PLLCE
&& model->die->mcb_ypos >= y-HALF_ROW
&& model->die->mcb_ypos <= y+HALF_ROW ) {
n.pt[3].name = "HCLK_MCB_PLLCEOUT%i_W";
n.pt[3].start_count = 0;
n.pt[3].y = y;
n.pt[3].x = LEFT_MCB_COL;
n.num_pts = 4;
rc = add_conn_range(model, NOPREF_BI_F,
y, LEFT_MCB_COL, "MCB_HCLK_PLLCE%i_PINW", 0, 1,
model->die->mcb_ypos, LEFT_MCB_COL, "MCB_L_PLLCE%i_PW", 0);
if (rc) RC_FAIL(model, rc);
}
if ((rc = add_conn_net(model, NO_PREF, &n))) RC_FAIL(model, rc); }
// wire up and down the row (8 each) to reach all io devices
if ((rc = net_up_down(model, y, LEFT_IO_DEVS,
wire, &up_net, &down_net))) RC_FAIL(model, rc);
if (up_net.num_pts > 1
&& (rc = add_conn_net(model, NO_PREF, &up_net))) RC_FAIL(model, rc);
if (down_net.num_pts > 1
&& (rc = add_conn_net(model, NO_PREF, &down_net))) RC_FAIL(model, rc);
}
//
// right
//
if (wire == PLLCLK) {
rc = add_conn_range(model, NOPREF_BI_F,
model->center_y, model->x_width-RIGHT_OUTER_O, "REGR_PLLCLK%i", 0, 1,
model->center_y, model->x_width-RIGHT_INNER_O, "REGH_RTERM_PLL_CLKOUT%i_E", 0);
if (rc) RC_FAIL(model, rc);
} else if (wire == PLLCE) {
rc = add_conn_range(model, NOPREF_BI_F,
model->center_y, model->x_width-RIGHT_OUTER_O, "REGR_CEOUT%i", 0, 1,
model->center_y, model->x_width-RIGHT_INNER_O, "REGH_RTERM_PLL_CEOUT%i_E", 0);
if (rc) RC_FAIL(model, rc);
}
for (y = TOP_FIRST_REGULAR; y <= model->y_height - BOT_LAST_REGULAR_O; y++) {
if (!is_aty(Y_ROW_HORIZ_AXSYMM, model, y))
continue;
if (wire == IOCE || wire == IOCLK) {
net.last_inc = 0;
net.num_pts = 3;
for (i = 0; i <= 3; i++) {
net.pt[0].name = pf("HCLK_IOI_RTERM_%s%i_W", s1, i);
net.pt[0].start_count = 0;
net.pt[0].y = y;
net.pt[0].x = model->x_width - RIGHT_INNER_O;
net.pt[1].name = pf("HCLK_MCB_%s%i_W", s1, i);
net.pt[1].start_count = 0;
net.pt[1].y = y;
net.pt[1].x = model->x_width - RIGHT_MCB_O;
net.pt[2].name = pf("HCLK_IOIL_%s%i", s1, 3-i);
net.pt[2].start_count = 0;
net.pt[2].y = y;
net.pt[2].x = model->x_width - RIGHT_IO_DEVS_O;
if ((rc = add_conn_net(model, NO_PREF, &net))) RC_FAIL(model, rc);
}
} else { // PLLCE/PLLCLK
struct w_net n = {
.last_inc = last_inc, .num_pts = 3, .pt =
{{ wire == PLLCE ? "HCLK_IOI_RTERM_PLLCEOUT%i_W"
: "HCLK_IOI_RTERM_PLLCLKOUT%i_W",
0, y, model->x_width - RIGHT_INNER_O },
{ wire == PLLCE ? "HCLK_MCB_PLLCEOUT%i_W"
: "HCLK_MCB_PLLCLKOUT%i_W",
0, y, model->x_width - RIGHT_MCB_O },
{ pf("HCLK_IOIL_%s%%i", s1), 0, y, model->x_width - RIGHT_IO_DEVS_O }}};
if ((rc = add_conn_net(model, NO_PREF, &n))) RC_FAIL(model, rc);
}
// wire up and down the row (8 each) to reach all io devices
if ((rc = net_up_down(model, y, model->x_width - RIGHT_IO_DEVS_O,
wire, &up_net, &down_net))) RC_FAIL(model, rc);
if (up_net.num_pts > 1
&& (rc = add_conn_net(model, NO_PREF, &up_net))) RC_FAIL(model, rc);
if (down_net.num_pts > 1
&& (rc = add_conn_net(model, NO_PREF, &down_net))) RC_FAIL(model, rc);
}
RC_RETURN(model);
}
//
// clkpll() ckpin() and clkindirect_feedback() run a set of wire strings
// horizontally through the entire chip from left to right over the center
// reg row. The wires meet at the middle of each half of the chip on
// the left and right side, as well as in the center.
//
static int clkpll(struct fpga_model *model)
{
int x, rc;
struct w_net net;
RC_CHECK(model);
//
// clk pll 0:1
//
// two nets - one for left side, one for right side
{ struct seed_data seeds[] = {
{ X_OUTER_LEFT, "REGL_CLKPLL%i" },
{ X_INNER_LEFT, "REGL_LTERM_CLKPLL%i" },
{ X_LEFT_MCB | X_RIGHT_MCB, "MCB_CLKPLL%i" },
{ X_FABRIC_ROUTING_COL
| X_LEFT_IO_ROUTING_COL
| X_RIGHT_IO_ROUTING_COL
| X_FABRIC_BRAM_COL, "INT_CLKPLL%i" },
{ X_LEFT_IO_DEVS_COL
| X_FABRIC_BRAM_VIA_COL
| X_FABRIC_MACC_VIA_COL
| X_FABRIC_LOGIC_COL
| X_RIGHT_IO_DEVS_COL, "CLE_CLKPLL%i" },
{ X_FABRIC_MACC_COL, "DSP_CLKPLL%i" },
{ X_CENTER_ROUTING_COL, "REGC_INT_CLKPLL_IO_RT%i" },
{ X_CENTER_LOGIC_COL, "REGC_CLECLKPLL_IO_LT%i" },
{ X_CENTER_CMTPLL_COL, "REGC_CLKPLL_IO_LT%i" },
{ X_CENTER_REGS_COL, "CLKC_PLL_IO_RT%i" },
{ X_INNER_RIGHT, "REGR_RTERM_CLKPLL%i" },
{ X_OUTER_RIGHT, "REGR_CLKPLL%i" },
{ 0 }};
seed_strx(model, seeds);
net.last_inc = 1;
net.num_pts = 0;
for (x = 0; x < model->x_width; x++) {
RC_ASSERT(model, model->tmp_str[x]);
RC_ASSERT(model, net.num_pts < sizeof(net.pt)/sizeof(net.pt[0]));
net.pt[net.num_pts].start_count = 0;
net.pt[net.num_pts].x = x;
net.pt[net.num_pts].y = model->center_y;
net.pt[net.num_pts].name = model->tmp_str[x];
net.num_pts++;
if (is_atx(X_CENTER_CMTPLL_COL, model, x)) {
// left-side net
if ((rc = add_conn_net(model, NO_PREF, &net))) RC_FAIL(model, rc);
// start right side
net.pt[0].start_count = 0;
net.pt[0].x = x;
net.pt[0].y = model->center_y;
net.pt[0].name = "REGC_CLKPLL_IO_RT%i";
net.num_pts = 1;
}
}
// right-side net
if ((rc = add_conn_net(model, NO_PREF, &net))) RC_FAIL(model, rc); }
//
// clk pll lock 0:1
//
// two nets - one for left side, one for right side
{ struct seed_data seeds[] = {
{ X_OUTER_LEFT, "REGL_LOCKED%i" },
{ X_INNER_LEFT, "REGH_LTERM_LOCKED%i" },
{ X_LEFT_MCB | X_RIGHT_MCB, "MCB_CLKPLL_LOCK%i" },
{ X_FABRIC_ROUTING_COL
| X_LEFT_IO_ROUTING_COL
| X_RIGHT_IO_ROUTING_COL
| X_FABRIC_BRAM_COL, "INT_CLKPLL_LOCK%i" },
{ X_LEFT_IO_DEVS_COL
| X_FABRIC_BRAM_VIA_COL
| X_FABRIC_MACC_VIA_COL
| X_FABRIC_LOGIC_COL
| X_RIGHT_IO_DEVS_COL, "CLE_CLKPLL_LOCK%i" },
{ X_FABRIC_MACC_COL, "DSP_CLKPLL_LOCK%i" },
{ X_CENTER_ROUTING_COL, "REGC_INT_CLKPLL_LOCK_RT%i" },
{ X_CENTER_LOGIC_COL, "REGC_CLECLKPLL_LOCK_LT%i" },
{ X_CENTER_CMTPLL_COL, "CLK_PLL_LOCK_LT%i" },
{ X_CENTER_REGS_COL, "CLKC_PLL_LOCK_RT%i" },
{ X_INNER_RIGHT, "REGH_RTERM_LOCKED%i" },
{ X_OUTER_RIGHT, "REGR_LOCKED%i" },
{ 0 }};
seed_strx(model, seeds);
net.last_inc = 1;
net.num_pts = 0;
for (x = 0; x < model->x_width; x++) {
RC_ASSERT(model, model->tmp_str[x]);
RC_ASSERT(model, net.num_pts < sizeof(net.pt)/sizeof(net.pt[0]));
net.pt[net.num_pts].start_count = 0;
net.pt[net.num_pts].x = x;
net.pt[net.num_pts].y = model->center_y;
net.pt[net.num_pts].name = model->tmp_str[x];
net.num_pts++;
if (is_atx(X_CENTER_CMTPLL_COL, model, x)) {
// left-side net
if ((rc = add_conn_net(model, NO_PREF, &net))) RC_FAIL(model, rc);
// start right side
net.pt[0].start_count = 0;
net.pt[0].x = x;
net.pt[0].y = model->center_y;
net.pt[0].name = "CLK_PLL_LOCK_RT%i";
net.num_pts = 1;
}
}
// right-side net
if ((rc = add_conn_net(model, NO_PREF, &net))) RC_FAIL(model, rc); }
RC_RETURN(model);
}
static int ckpin(struct fpga_model *model)
{
int y, x, rc;
struct w_net net;
RC_CHECK(model);
//
// ckpin is made out of 8 nets.
//
// 4 vertical through center_x:
// 1. top edge to top midbuf
// 2. top midbuf to center
// 3. center to bottom midbuf
// 4. bottom midbuf to bottom edge
// 4 horizontal through center_y:
// 1. left edge to left_gclk_sep_x
// 2. left_gclk_sep_x to center
// 3. center to right_gclk_sep_x
// 4. right_gclk_sep_x to right edge
//
// vertical
{ struct seed_data y_seeds[] = {
{ Y_INNER_TOP, "REGV_TTERM_CKPIN%i" },
{ Y_ROW_HORIZ_AXSYMM, "CLKV_HCLK_CKPIN%i" },
{ Y_CHIP_HORIZ_REGS, "CLKC_CKTB%i" },
{ Y_INNER_BOTTOM, "REGV_BTERM_CKPIN%i" },
{ Y_REGULAR_ROW, "CLKV_CKPIN%i" },
{ 0 }};
seed_stry(model, y_seeds);
net.last_inc = 7;
net.pt[0].start_count = 0;
net.pt[0].x = model->center_x-CENTER_CMTPLL_O;
net.pt[0].y = TOP_OUTER_ROW;
net.pt[0].name = "REGT_CKPIN%i";
net.pt[1].start_count = 0;
net.pt[1].x = model->center_x-CENTER_CMTPLL_O;
net.pt[1].y = TOP_INNER_ROW;
net.pt[1].name = "REGT_TTERM_CKPIN%i";
net.num_pts = 2;
for (y = TOP_INNER_ROW; y <= model->y_height - BOT_INNER_ROW; y++) {
RC_ASSERT(model, model->tmp_str[y]);
RC_ASSERT(model, net.num_pts < sizeof(net.pt)/sizeof(net.pt[0]));
net.pt[net.num_pts].start_count = 0;
net.pt[net.num_pts].x = model->center_x;
net.pt[net.num_pts].y = y;
net.pt[net.num_pts].name = model->tmp_str[y];
net.num_pts++;
if (y < model->center_y
&& YX_TILE(model, y+1, model->center_x)->flags & TF_CENTER_MIDBUF) {
net.pt[net.num_pts-1].name = "CLKV_CKPIN_BUF%i";
if ((rc = add_conn_net(model, NO_PREF, &net))) RC_FAIL(model, rc);
net.pt[0].start_count = 0;
net.pt[0].x = model->center_x;
net.pt[0].y = y;
net.pt[0].name = "CLKV_MIDBUF_TOP_CKPIN%i";
net.num_pts = 1;
} else if (is_aty(Y_CHIP_HORIZ_REGS, model, y)) {
if ((rc = add_conn_net(model, NO_PREF, &net))) RC_FAIL(model, rc);
net.pt[0].start_count = 8;
net.pt[0].x = model->center_x;
net.pt[0].y = y;
net.pt[0].name = "CLKC_CKTB%i";
net.num_pts = 1;
} else if (y > model->center_y
&& YX_TILE(model, y-1, model->center_x)->flags & TF_CENTER_MIDBUF) {
net.pt[net.num_pts-1].name = "CLKV_CKPIN_BOT_BUF%i";
if ((rc = add_conn_net(model, NO_PREF, &net))) RC_FAIL(model, rc);
net.pt[0].start_count = 0;
net.pt[0].x = model->center_x;
net.pt[0].y = y;
net.pt[0].name = "CLKV_MIDBUF_BOT_CKPIN%i";
net.num_pts = 1;
}
}
net.pt[net.num_pts].start_count = 0;
net.pt[net.num_pts].x = model->center_x-CENTER_CMTPLL_O;
net.pt[net.num_pts].y = model->y_height-BOT_INNER_ROW;
net.pt[net.num_pts].name = "REGB_BTERM_CKPIN%i";
net.num_pts++;
net.pt[net.num_pts].start_count = 0;
net.pt[net.num_pts].x = model->center_x-CENTER_CMTPLL_O;
net.pt[net.num_pts].y = model->y_height-BOT_OUTER_ROW;
net.pt[net.num_pts].name = "REGB_CKPIN%i";
net.num_pts++;
if ((rc = add_conn_net(model, NO_PREF, &net))) RC_FAIL(model, rc); }
// horizontal
{ struct seed_data x_seeds[] = {
{ X_OUTER_LEFT, "REGL_CKPIN%i" },
{ X_INNER_LEFT, "REGH_LTERM_CKPIN%i" },
{ X_LEFT_MCB | X_RIGHT_MCB, "MCB_REGH_CKPIN%i" },
{ X_FABRIC_ROUTING_COL
| X_LEFT_IO_ROUTING_COL
| X_RIGHT_IO_ROUTING_COL
| X_FABRIC_BRAM_COL, "REGH_CKPIN%i_INT" },
{ X_LEFT_IO_DEVS_COL
| X_FABRIC_BRAM_VIA_COL
| X_FABRIC_MACC_VIA_COL
| X_FABRIC_LOGIC_COL
| X_RIGHT_IO_DEVS_COL, "REGH_CKPIN%i_CLB" },
{ X_FABRIC_MACC_COL, "REGH_CKPIN%i_DSP" },
{ X_CENTER_ROUTING_COL, "REGC_INT_CKPIN%i_INT" },
{ X_CENTER_LOGIC_COL, "REGC_CLECKPIN%i_CLB" },
{ X_CENTER_CMTPLL_COL, "REGC_CMT_CKPIN%i" },
{ X_CENTER_REGS_COL, "CLKC_CKLR%i" },
{ X_INNER_RIGHT, "REGH_RTERM_CKPIN%i" },
{ X_OUTER_RIGHT, "REGR_CKPIN%i" },
{ 0 }};
seed_strx(model, x_seeds);
net.last_inc = 7;
net.num_pts = 0;
for (x = 0; x < model->x_width; x++) {
RC_ASSERT(model, model->tmp_str[x]);
RC_ASSERT(model, net.num_pts < sizeof(net.pt)/sizeof(net.pt[0]));
net.pt[net.num_pts].start_count =
is_atx(X_CENTER_MAJOR, model, x) ? 8 : 0;
net.pt[net.num_pts].x = x;
net.pt[net.num_pts].y = model->center_y;
net.pt[net.num_pts].name = model->tmp_str[x];
net.num_pts++;
if (x == model->left_gclk_sep_x) {
net.pt[net.num_pts-1].name = "REGH_DSP_IN_CKPIN%i";
if ((rc = add_conn_net(model, NO_PREF, &net))) RC_FAIL(model, rc);
net.pt[0].start_count = 0;
net.pt[0].x = x;
net.pt[0].y = model->center_y;
net.pt[0].name = "REGH_DSP_OUT_CKPIN%i";
net.num_pts = 1;
} else if (x == model->center_x) {
if ((rc = add_conn_net(model, NO_PREF, &net))) RC_FAIL(model, rc);
net.pt[0].start_count = 0;
net.pt[0].x = x;
net.pt[0].y = model->center_y;
net.pt[0].name = "CLKC_CKLR%i";
net.num_pts = 1;
} else if (x == model->right_gclk_sep_x) {
net.pt[net.num_pts-1].name = "REGH_DSP_OUT_CKPIN%i";
if ((rc = add_conn_net(model, NO_PREF, &net))) RC_FAIL(model, rc);
net.pt[0].start_count = 0;
net.pt[0].x = x;
net.pt[0].y = model->center_y;
net.pt[0].name = "REGH_DSP_IN_CKPIN%i";
net.num_pts = 1;
}
}
if ((rc = add_conn_net(model, NO_PREF, &net))) RC_FAIL(model, rc); }
RC_RETURN(model);
}
static int clkindirect_feedback(struct fpga_model *model, enum extra_wires wire)
{
const struct seed_data clk_indirect_seeds[] = {
{ X_OUTER_LEFT, "REGL_CLK_INDIRECT%i" },
{ X_INNER_LEFT, "REGH_LTERM_CLKINDIRECT%i" },
{ X_LEFT_MCB | X_RIGHT_MCB, "MCB_REGH_CLKINDIRECT_LR%i" },
{ X_FABRIC_ROUTING_COL
| X_LEFT_IO_ROUTING_COL
| X_RIGHT_IO_ROUTING_COL
| X_FABRIC_BRAM_COL, "REGH_CLKINDIRECT_LR%i_INT" },
{ X_LEFT_IO_DEVS_COL
| X_FABRIC_BRAM_VIA_COL
| X_FABRIC_MACC_VIA_COL
| X_FABRIC_LOGIC_COL
| X_RIGHT_IO_DEVS_COL, "REGH_CLKINDIRECT_LR%i_CLB" },
{ X_FABRIC_MACC_COL, "REGH_CLKINDIRECT_LR%i_DSP" },
{ X_CENTER_ROUTING_COL, "REGC_INT_CLKINDIRECT_LR%i_INT" },
{ X_CENTER_LOGIC_COL, "REGC_CLECLKINDIRECT_LR%i_CLB" },
{ X_CENTER_CMTPLL_COL, "REGC_CMT_CLKINDIRECT_LR%i" },
{ X_CENTER_REGS_COL, "REGC_CLKINDIRECT_LR%i" },
{ X_INNER_RIGHT, "REGH_RTERM_CLKINDIRECT%i" },
{ X_OUTER_RIGHT, "REGR_CLK_INDIRECT%i" },
{ 0 }};
const struct seed_data clk_feedback_seeds[] = {
{ X_OUTER_LEFT, "REGL_CLK_FEEDBACK%i" },
{ X_INNER_LEFT, "REGH_LTERM_CLKFEEDBACK%i" },
{ X_LEFT_MCB | X_RIGHT_MCB, "MCB_REGH_CLKFEEDBACK_LR%i" },
{ X_FABRIC_ROUTING_COL
| X_LEFT_IO_ROUTING_COL
| X_RIGHT_IO_ROUTING_COL
| X_FABRIC_BRAM_COL, "REGH_CLKFEEDBACK_LR%i_INT" },
{ X_LEFT_IO_DEVS_COL
| X_FABRIC_BRAM_VIA_COL
| X_FABRIC_MACC_VIA_COL
| X_FABRIC_LOGIC_COL
| X_RIGHT_IO_DEVS_COL, "REGH_CLKFEEDBACK_LR%i_CLB" },
{ X_FABRIC_MACC_COL, "REGH_CLKFEEDBACK_LR%i_DSP" },
{ X_CENTER_ROUTING_COL, "REGC_INT_CLKFEEDBACK_LR%i_INT" },
{ X_CENTER_LOGIC_COL, "REGC_CLECLKFEEDBACK_LR%i_CLB" },
{ X_CENTER_CMTPLL_COL, "REGC_CMT_CLKFEEDBACK_LR%i" },
{ X_CENTER_REGS_COL, "REGC_CLKFEEDBACK_LR%i" },
{ X_INNER_RIGHT, "REGH_RTERM_CLKFEEDBACK%i" },
{ X_OUTER_RIGHT, "REGR_CLK_FEEDBACK%i" },
{ 0 }};
int y, x, i, top_pll_y, top_dcm_y, bot_pll_y, bot_dcm_y;
int regular_pts, rc;
const char *wstr;
struct w_net net;
RC_CHECK(model);
//
// clk_indirect and clk_feedback have 6 nets:
//
// 2 small nets - one for the top side, one for the bottom side, that
// connect the pll and dcm devices on each side to their termination
// tiles.
//
// Then 4 larger nets each covering one quarter of the chip (bottom-left,
// bottom-right, top-left and top-right). They connect together 4 wires
// of the dcm and pll devices on one side to the entire center_y row
// (separately for left and right columns). The bottom pll/dcm go to
// center row 0:3, the top pll/dcm go to center row 4:7.
//
if (wire == CLK_INDIRECT) {
seed_strx(model, clk_indirect_seeds);
wstr = "INDIRECT";
} else if (wire == CLK_FEEDBACK) {
seed_strx(model, clk_feedback_seeds);
wstr = "FEEDBACK";
} else RC_FAIL(model, EINVAL);
//
// 2 termination to pll/dcm nets (top and bottom side)
//
top_pll_y = -1;
top_dcm_y = -1;
bot_pll_y = -1;
bot_dcm_y = -1;
net.last_inc = 7;
net.pt[0].name = pf("REGT_CLK_%s%%i", wstr);
net.pt[0].start_count = 0;
net.pt[0].y = TOP_OUTER_ROW;
net.pt[0].x = model->center_x - CENTER_CMTPLL_O;
net.pt[1].name = pf("REGT_TTERM_CLK%s%%i", wstr);
net.pt[1].start_count = 0;
net.pt[1].y = TOP_INNER_ROW;
net.pt[1].x = model->center_x - CENTER_CMTPLL_O;
net.num_pts = 2;
for (y = TOP_FIRST_REGULAR; y <= model->y_height - BOT_LAST_REGULAR_O; y++) {
if (y < model->center_y
&& has_device(model, y, model->center_x-CENTER_CMTPLL_O, DEV_PLL)) {
top_pll_y = y;
net.pt[net.num_pts].name = pf("PLL_CLK_%s_TB%%i", wstr);
net.pt[net.num_pts].start_count = 0;
net.pt[net.num_pts].y = y;
net.pt[net.num_pts].x = model->center_x - CENTER_CMTPLL_O;
net.num_pts++;
} else if (y < model->center_y
&& has_device(model, y, model->center_x-CENTER_CMTPLL_O, DEV_DCM)) {
top_dcm_y = y;
net.pt[net.num_pts].name = pf("DCM_CLK_%s_LR_TOP%%i", wstr);
net.pt[net.num_pts].start_count = 0;
net.pt[net.num_pts].y = y;
net.pt[net.num_pts].x = model->center_x - CENTER_CMTPLL_O;
net.num_pts++;
} else if (y == model->center_y) {
if ((rc = add_conn_net(model, NO_PREF, &net))) RC_FAIL(model, rc);
// start bottom side net
net.num_pts = 0;
} else if (y > model->center_y
&& has_device(model, y, model->center_x-CENTER_CMTPLL_O, DEV_PLL)) {
bot_pll_y = y;
net.pt[net.num_pts].name = pf("CMT_PLL_CLK_%s_LRBOT%%i", wstr);
net.pt[net.num_pts].start_count = 0;
net.pt[net.num_pts].y = y;
net.pt[net.num_pts].x = model->center_x - CENTER_CMTPLL_O;
net.num_pts++;
} else if (y > model->center_y
&& has_device(model, y, model->center_x-CENTER_CMTPLL_O, DEV_DCM)) {
bot_dcm_y = y;
net.pt[net.num_pts].name = pf("DCM_CLK_%s_TB_BOT%%i", wstr);
net.pt[net.num_pts].start_count = 0;
net.pt[net.num_pts].y = y;
net.pt[net.num_pts].x = model->center_x - CENTER_CMTPLL_O;
net.num_pts++;
}
}
net.pt[net.num_pts].name = pf("REGB_BTERM_CLK%s%%i", wstr);
net.pt[net.num_pts].start_count = 0;
net.pt[net.num_pts].y = model->y_height - BOT_INNER_ROW;
net.pt[net.num_pts].x = model->center_x - CENTER_CMTPLL_O;
net.num_pts++;
net.pt[net.num_pts].name = pf("REGB_CLK_%s%%i", wstr);
net.pt[net.num_pts].start_count = 0;
net.pt[net.num_pts].y = model->y_height - BOT_OUTER_ROW;
net.pt[net.num_pts].x = model->center_x - CENTER_CMTPLL_O;
net.num_pts++;
if ((rc = add_conn_net(model, NO_PREF, &net))) RC_FAIL(model, rc);
// todo: this function doesn't support more than one pll or dcm
// tile per chip side right now.
RC_ASSERT(model, top_pll_y != -1 && top_dcm_y != -1
&& bot_pll_y != -1 && bot_dcm_y != -1);
//
// 4 nets for each quarter of the chip
//
net.last_inc = 3;
net.num_pts = 0;
for (x = LEFT_IO_ROUTING; x < model->x_width - RIGHT_INNER_O; x++) {
if (is_atx(X_CENTER_ROUTING_COL, model, x)) {
// finish bottom net on left side
for (i = 0; i < net.num_pts; i++)
net.pt[i].start_count = 0;
regular_pts = net.num_pts;
// pll and dcm
net.pt[net.num_pts].name = pf("PLL_CLK_%s_TB%%i", wstr);
net.pt[net.num_pts].start_count = 4;
net.pt[net.num_pts].y = bot_pll_y;
net.pt[net.num_pts].x = model->center_x - CENTER_CMTPLL_O;
net.num_pts++;
net.pt[net.num_pts].name = pf("DCM_CLK_%s_LR_TOP%%i", wstr);
net.pt[net.num_pts].start_count = 4;
net.pt[net.num_pts].y = bot_dcm_y;
net.pt[net.num_pts].x = model->center_x - CENTER_CMTPLL_O;
net.num_pts++;
// left termination
net.pt[net.num_pts].name = model->tmp_str[LEFT_OUTER_COL];
net.pt[net.num_pts].start_count = 0;
net.pt[net.num_pts].y = model->center_y;
net.pt[net.num_pts].x = LEFT_OUTER_COL;
net.num_pts++;
net.pt[net.num_pts].name = model->tmp_str[LEFT_INNER_COL];
net.pt[net.num_pts].start_count = 0;
net.pt[net.num_pts].y = model->center_y;
net.pt[net.num_pts].x = LEFT_INNER_COL;
net.num_pts++;
// 3 columns from center major
net.pt[net.num_pts].start_count = 0;
net.pt[net.num_pts].y = model->center_y;
net.pt[net.num_pts].x = model->center_x - CENTER_ROUTING_O;
net.pt[net.num_pts].name = model->tmp_str[net.pt[net.num_pts].x];
net.num_pts++;
net.pt[net.num_pts].start_count = 8;
net.pt[net.num_pts].y = model->center_y;
net.pt[net.num_pts].x = model->center_x - CENTER_LOGIC_O;
net.pt[net.num_pts].name = model->tmp_str[net.pt[net.num_pts].x];
net.num_pts++;
net.pt[net.num_pts].start_count = 8;
net.pt[net.num_pts].y = model->center_y;
net.pt[net.num_pts].x = model->center_x - CENTER_CMTPLL_O;
net.pt[net.num_pts].name = model->tmp_str[net.pt[net.num_pts].x];
net.num_pts++;
if ((rc = add_conn_net(model, NO_PREF, &net))) RC_FAIL(model, rc);
// finish top net on left side
net.num_pts = regular_pts;
for (i = 0; i < net.num_pts; i++)
net.pt[i].start_count = 4;
// pll and dcm
net.pt[net.num_pts].name = pf("CMT_PLL_CLK_%s_LRBOT%%i", wstr);
net.pt[net.num_pts].start_count = 4;
net.pt[net.num_pts].y = top_pll_y;
net.pt[net.num_pts].x = model->center_x - CENTER_CMTPLL_O;
net.num_pts++;
net.pt[net.num_pts].name = pf("DCM_CLK_%s_TB_BOT%%i", wstr);
net.pt[net.num_pts].start_count = 4;
net.pt[net.num_pts].y = top_dcm_y;
net.pt[net.num_pts].x = model->center_x - CENTER_CMTPLL_O;
net.num_pts++;
// left termination
net.pt[net.num_pts].name = model->tmp_str[LEFT_OUTER_COL];
net.pt[net.num_pts].start_count = 4;
net.pt[net.num_pts].y = model->center_y;
net.pt[net.num_pts].x = LEFT_OUTER_COL;
net.num_pts++;
net.pt[net.num_pts].name = model->tmp_str[LEFT_INNER_COL];
net.pt[net.num_pts].start_count = 4;
net.pt[net.num_pts].y = model->center_y;
net.pt[net.num_pts].x = LEFT_INNER_COL;
net.num_pts++;
// 3 colums from center major
net.pt[net.num_pts].start_count = 4;
net.pt[net.num_pts].y = model->center_y;
net.pt[net.num_pts].x = model->center_x - CENTER_ROUTING_O;
net.pt[net.num_pts].name = model->tmp_str[net.pt[net.num_pts].x];
net.num_pts++;
net.pt[net.num_pts].start_count = 12;
net.pt[net.num_pts].y = model->center_y;
net.pt[net.num_pts].x = model->center_x - CENTER_LOGIC_O;
net.pt[net.num_pts].name = model->tmp_str[net.pt[net.num_pts].x];
net.num_pts++;
net.pt[net.num_pts].start_count = 12;
net.pt[net.num_pts].y = model->center_y;
net.pt[net.num_pts].x = model->center_x - CENTER_CMTPLL_O;
net.pt[net.num_pts].name = model->tmp_str[net.pt[net.num_pts].x];
net.num_pts++;
if ((rc = add_conn_net(model, NO_PREF, &net))) RC_FAIL(model, rc);
// continue on right side
net.num_pts = 0;
x = model->center_x;
continue;
}
net.pt[net.num_pts].name = model->tmp_str[x];
net.pt[net.num_pts].y = model->center_y;
net.pt[net.num_pts].x = x;
net.num_pts++;
}
// finish bottom net on right side
for (i = 0; i < net.num_pts; i++)
net.pt[i].start_count = 0;
regular_pts = net.num_pts;
// pll and dcm
net.pt[net.num_pts].name = pf("PLL_CLK_%s_TB%%i", wstr);
net.pt[net.num_pts].start_count = 0;
net.pt[net.num_pts].y = bot_pll_y;
net.pt[net.num_pts].x = model->center_x - CENTER_CMTPLL_O;
net.num_pts++;
net.pt[net.num_pts].name = pf("DCM_CLK_%s_LR_TOP%%i", wstr);
net.pt[net.num_pts].start_count = 0;
net.pt[net.num_pts].y = bot_dcm_y;
net.pt[net.num_pts].x = model->center_x - CENTER_CMTPLL_O;
net.num_pts++;
// right termination
net.pt[net.num_pts].start_count = 4;
net.pt[net.num_pts].y = model->center_y;
net.pt[net.num_pts].x = model->x_width - RIGHT_OUTER_O;
net.pt[net.num_pts].name = model->tmp_str[net.pt[net.num_pts].x];
net.num_pts++;
net.pt[net.num_pts].start_count = 4;
net.pt[net.num_pts].y = model->center_y;
net.pt[net.num_pts].x = model->x_width - RIGHT_INNER_O;
net.pt[net.num_pts].name = model->tmp_str[net.pt[net.num_pts].x];
net.num_pts++;
// 2 columns from center major
net.pt[net.num_pts].start_count = 4;
net.pt[net.num_pts].y = model->center_y;
net.pt[net.num_pts].x = model->center_x - CENTER_CMTPLL_O;
net.pt[net.num_pts].name = model->tmp_str[net.pt[net.num_pts].x];
net.num_pts++;
net.pt[net.num_pts].start_count = 4;
net.pt[net.num_pts].y = model->center_y;
net.pt[net.num_pts].x = model->center_x;
net.pt[net.num_pts].name = model->tmp_str[net.pt[net.num_pts].x];
net.num_pts++;
if ((rc = add_conn_net(model, NO_PREF, &net))) RC_FAIL(model, rc);
// finish top net on right side
net.num_pts = regular_pts;
for (i = 0; i < net.num_pts; i++)
net.pt[i].start_count = 4;
// pll and dcm
net.pt[net.num_pts].name = pf("CMT_PLL_CLK_%s_LRBOT%%i", wstr);
net.pt[net.num_pts].start_count = 0;
net.pt[net.num_pts].y = top_pll_y;
net.pt[net.num_pts].x = model->center_x - CENTER_CMTPLL_O;
net.num_pts++;
net.pt[net.num_pts].name = pf("DCM_CLK_%s_TB_BOT%%i", wstr);
net.pt[net.num_pts].start_count = 0;
net.pt[net.num_pts].y = top_dcm_y;
net.pt[net.num_pts].x = model->center_x - CENTER_CMTPLL_O;
net.num_pts++;
// right termination
net.pt[net.num_pts].start_count = 0;
net.pt[net.num_pts].y = model->center_y;
net.pt[net.num_pts].x = model->x_width - RIGHT_OUTER_O;
net.pt[net.num_pts].name = model->tmp_str[net.pt[net.num_pts].x];
net.num_pts++;
net.pt[net.num_pts].start_count = 0;
net.pt[net.num_pts].y = model->center_y;
net.pt[net.num_pts].x = model->x_width - RIGHT_INNER_O;
net.pt[net.num_pts].name = model->tmp_str[net.pt[net.num_pts].x];
net.num_pts++;
// 2 columns from center major
net.pt[net.num_pts].start_count = 0;
net.pt[net.num_pts].y = model->center_y;
net.pt[net.num_pts].x = model->center_x - CENTER_CMTPLL_O;
net.pt[net.num_pts].name = model->tmp_str[net.pt[net.num_pts].x];
net.num_pts++;
net.pt[net.num_pts].start_count = 0;
net.pt[net.num_pts].y = model->center_y;
net.pt[net.num_pts].x = model->center_x;
net.pt[net.num_pts].name = model->tmp_str[net.pt[net.num_pts].x];
net.num_pts++;
if ((rc = add_conn_net(model, NO_PREF, &net))) RC_FAIL(model, rc);
RC_RETURN(model);
}
static int run_gclk(struct fpga_model* model)
{
int x, i, rc, row, row_top_y, is_break;
struct w_net gclk_net;
RC_CHECK(model);
for (row = model->die->num_rows-1; row >= 0; row--) {
row_top_y = TOP_IO_TILES + (model->die->num_rows-1-row)*(8+1/* middle of row */+8);
if (row < (model->die->num_rows/2)) row_top_y++; // center regs
// net that connects the hclk of half the chip together horizontally
gclk_net.last_inc = 15;
gclk_net.num_pts = 0;
for (x = LEFT_IO_ROUTING;; x++) {
if (gclk_net.num_pts >= sizeof(gclk_net.pt) / sizeof(gclk_net.pt[0])) {
fprintf(stderr, "Internal error in line %i\n", __LINE__);
goto xout;
}
gclk_net.pt[gclk_net.num_pts].start_count = 0;
gclk_net.pt[gclk_net.num_pts].x = x;
gclk_net.pt[gclk_net.num_pts].y = row_top_y+8;
if (is_atx(X_LEFT_IO_ROUTING_COL|X_FABRIC_ROUTING_COL|X_CENTER_ROUTING_COL, model, x)) {
gclk_net.pt[gclk_net.num_pts++].name = "HCLK_GCLK%i_INT";
} else if (is_atx(X_LEFT_MCB, model, x)) {
gclk_net.pt[gclk_net.num_pts++].name = "HCLK_GCLK%i_MCB";
} else if (is_atx(X_FABRIC_LOGIC_COL|X_CENTER_LOGIC_COL|X_LEFT_IO_DEVS_COL, model, x)) {
gclk_net.pt[gclk_net.num_pts++].name = "HCLK_GCLK%i_CLB";
} else if (is_atx(X_FABRIC_BRAM_VIA_COL|X_FABRIC_MACC_VIA_COL, model, x)) {
gclk_net.pt[gclk_net.num_pts++].name = "HCLK_GCLK%i_BRAM_INTER";
} else if (is_atx(X_FABRIC_BRAM_COL, model, x)) {
gclk_net.pt[gclk_net.num_pts++].name = "HCLK_GCLK%i_BRAM";
} else if (is_atx(X_FABRIC_MACC_COL, model, x)) {
gclk_net.pt[gclk_net.num_pts++].name = "HCLK_GCLK%i_DSP";
} else if (is_atx(X_CENTER_CMTPLL_COL, model, x)) {
gclk_net.pt[gclk_net.num_pts].y = row_top_y+7;
gclk_net.pt[gclk_net.num_pts++].name = "HCLK_CMT_GCLK%i_CLB";
} else if (is_atx(X_CENTER_REGS_COL, model, x)) {
gclk_net.pt[gclk_net.num_pts++].name = "CLKV_BUFH_LEFT_L%i";
// connect left half
if ((rc = add_conn_net(model, NO_PREF, &gclk_net))) goto xout;
// start right half
gclk_net.pt[0].start_count = 0;
gclk_net.pt[0].x = x;
gclk_net.pt[0].y = row_top_y+8;
gclk_net.pt[0].name = "CLKV_BUFH_RIGHT_R%i";
gclk_net.num_pts = 1;
} else if (is_atx(X_RIGHT_IO_ROUTING_COL, model, x)) {
gclk_net.pt[gclk_net.num_pts++].name = "HCLK_GCLK%i_INT";
// connect right half
if ((rc = add_conn_net(model, NO_PREF, &gclk_net))) goto xout;
break;
}
if (x >= model->x_width) {
fprintf(stderr, "Internal error in line %i\n", __LINE__);
goto xout;
}
}
}
for (x = 0; x < model->x_width; x++) {
if (is_atx(X_ROUTING_COL, model, x)) {
for (row = model->die->num_rows-1; row >= 0; row--) {
row_top_y = 2 /* top IO */ + (model->die->num_rows-1-row)*(8+1/* middle of row */+8);
if (row < (model->die->num_rows/2)) row_top_y++; // center regs
is_break = 0;
if (is_atx(X_LEFT_IO_ROUTING_COL|X_RIGHT_IO_ROUTING_COL, model, x)) {
if (row && row != model->die->num_rows/2)
is_break = 1;
} else {
if (row)
is_break = 1;
else if (is_atx(X_FABRIC_BRAM_ROUTING_COL|X_FABRIC_MACC_ROUTING_COL, model, x))
is_break = 1;
}
// vertical net inside row, pulling together 16 gclk
// wires across top (8 tiles) and bottom (8 tiles) half
// of the row.
for (i = 0; i < 8; i++) {
gclk_net.pt[i].name = "GCLK%i";
gclk_net.pt[i].start_count = 0;
gclk_net.pt[i].y = row_top_y+i;
gclk_net.pt[i].x = x;
}
gclk_net.last_inc = 15;
gclk_net.num_pts = 8;
if ((rc = add_conn_net(model, NO_PREF, &gclk_net))) goto xout;
for (i = 0; i < 8; i++)
gclk_net.pt[i].y += 9;
if (is_break)
gclk_net.pt[7].name = "GCLK%i_BRK";
if ((rc = add_conn_net(model, NO_PREF, &gclk_net))) goto xout;
// vertically connects gclk of each row tile to
// hclk tile at the middle of the row
for (i = 0; i < 8; i++) {
if ((rc = add_conn_range(model, NOPREF_BI_F,
row_top_y+i, x, "GCLK%i", 0, 15,
row_top_y+8, x, "HCLK_GCLK_UP%i", 0))) goto xout;
if ((rc = add_conn_range(model, NOPREF_BI_F,
row_top_y+9+i, x, (i == 7 && is_break) ? "GCLK%i_BRK" : "GCLK%i", 0, 15,
row_top_y+8, x, "HCLK_GCLK%i", 0))) goto xout;
}
}
}
}
RC_RETURN(model);
xout:
return rc;
}
static int run_gclk_horiz_regs(struct fpga_model* model)
{
int x, rc;
RC_CHECK(model);
// local nets around the center on the left side
{ struct w_net net = {
.last_inc = 3, .num_pts = 3, .pt =
{{ "REGL_GCLK%i", 0, model->center_y, LEFT_OUTER_COL },
{ "REGH_LTERM_GCLK%i", 0, model->center_y, LEFT_INNER_COL },
{ "REGH_IOI_INT_GCLK%i", 0, model->center_y, LEFT_IO_ROUTING }}};
if ((rc = add_conn_net(model, NO_PREF, &net))) goto xout; }
{
const char* str[3] = {"REGL_GCLK%i", "REGH_LTERM_GCLK%i", "REGH_IOI_INT_GCLK%i"};
if ((rc = add_conn_range(model, NOPREF_BI_F,
model->center_y-2, LEFT_IO_ROUTING, "INT_BUFPLL_GCLK%i", 2, 3,
model->center_y-1, LEFT_IO_ROUTING, "INT_BUFPLL_GCLK%i_EXT", 2))) goto xout;
for (x = LEFT_OUTER_COL; x <= LEFT_IO_ROUTING; x++) {
if ((rc = add_conn_range(model, NOPREF_BI_F,
model->center_y-1, LEFT_IO_ROUTING, "INT_BUFPLL_GCLK%i", 0, 1,
model->center_y, x, str[x], 0))) goto xout;
if ((rc = add_conn_range(model, NOPREF_BI_F,
model->center_y-1, LEFT_IO_ROUTING, "INT_BUFPLL_GCLK%i_EXT", 2, 3,
model->center_y, x, str[x], 2))) goto xout;
if ((rc = add_conn_range(model, NOPREF_BI_F,
model->center_y-2, LEFT_IO_ROUTING, "INT_BUFPLL_GCLK%i", 2, 3,
model->center_y, x, str[x], 2))) goto xout;
}
}
// and right side
{ struct w_net net = {
.last_inc = 3, .num_pts = 3, .pt =
{{ "REGH_RIOI_GCLK%i", 0, model->center_y, model->x_width-RIGHT_IO_DEVS_O },
{ "MCB_REGH_GCLK%i", 0, model->center_y, model->x_width-RIGHT_MCB_O },
{ "REGR_GCLK%i", 0, model->center_y, model->x_width-RIGHT_OUTER_O }}};
if ((rc = add_conn_net(model, NO_PREF, &net))) goto xout; }
{
const char* str[5] = {"REGH_IOI_INT_GCLK%i", "REGH_RIOI_GCLK%i", "MCB_REGH_GCLK%i", "REGR_RTERM_GCLK%i", "REGR_GCLK%i"};
if ((rc = add_conn_range(model, NOPREF_BI_F,
model->center_y-2, model->x_width-RIGHT_IO_ROUTING_O, "INT_BUFPLL_GCLK%i", 2, 3,
model->center_y-1, model->x_width-RIGHT_IO_ROUTING_O, "INT_BUFPLL_GCLK%i_EXT", 2))) goto xout;
for (x = model->x_width-RIGHT_IO_ROUTING_O; x <= model->x_width-RIGHT_OUTER_O; x++) {
if ((rc = add_conn_range(model, NOPREF_BI_F,
model->center_y-1, model->x_width-RIGHT_IO_ROUTING_O, "INT_BUFPLL_GCLK%i_EXT", 2, 3,
model->center_y, x, str[x-(model->x_width-RIGHT_IO_ROUTING_O)], 2))) goto xout;
if ((rc = add_conn_range(model, NOPREF_BI_F,
model->center_y-2, model->x_width-RIGHT_IO_ROUTING_O, "INT_BUFPLL_GCLK%i", 2, 3,
model->center_y, x, str[x-(model->x_width-RIGHT_IO_ROUTING_O)], 2))) goto xout;
}
}
{ struct w_net net = {
.last_inc = 1, .num_pts = 4, .pt =
{{ "INT_BUFPLL_GCLK%i", 0, model->center_y-1, model->x_width-RIGHT_IO_ROUTING_O },
{ "REGH_RIOI_INT_GCLK%i", 0, model->center_y, model->x_width-RIGHT_IO_ROUTING_O },
{ "REGH_RIOI_GCLK%i", 0, model->center_y, model->x_width-RIGHT_IO_DEVS_O },
{ "REGH_RTERM_GCLK%i", 0, model->center_y, model->x_width-RIGHT_INNER_O }}};
if ((rc = add_conn_net(model, NO_PREF, &net))) goto xout; }
{ struct w_net net = {
.last_inc = 1, .num_pts = 3, .pt =
{{ "REGH_IOI_INT_GCLK%i", 2, model->center_y, model->x_width-RIGHT_IO_ROUTING_O },
{ "REGH_RIOI_GCLK%i", 2, model->center_y, model->x_width-RIGHT_IO_DEVS_O },
{ "REGR_RTERM_GCLK%i", 2, model->center_y, model->x_width-RIGHT_INNER_O }}};
if ((rc = add_conn_net(model, NO_PREF, &net))) goto xout; }
// the naming is a little messed up here, and the networks are
// actually simpler than represented here (with full 0:3 connections).
// But until we have better representation of wire networks, this has
// to suffice.
if ((rc = add_conn_range(model, NOPREF_BI_F,
model->center_y, model->x_width-RIGHT_OUTER_O,
"REGR_GCLK%i", 0, 1,
model->center_y-1, model->x_width-RIGHT_IO_ROUTING_O,
"INT_BUFPLL_GCLK%i", 0))) goto xout;
if ((rc = add_conn_range(model, NOPREF_BI_F,
model->center_y, model->x_width-RIGHT_OUTER_O,
"REGR_GCLK%i", 0, 1,
model->center_y, model->x_width-RIGHT_IO_ROUTING_O,
"REGH_RIOI_INT_GCLK%i", 0))) goto xout;
if ((rc = add_conn_range(model, NOPREF_BI_F,
model->center_y, model->x_width-RIGHT_OUTER_O,
"REGR_GCLK%i", 2, 3,
model->center_y, model->x_width-RIGHT_IO_ROUTING_O,
"REGH_IOI_INT_GCLK%i", 2))) goto xout;
if ((rc = add_conn_range(model, NOPREF_BI_F,
model->center_y, model->x_width-RIGHT_OUTER_O,
"REGR_GCLK%i", 0, 1,
model->center_y, model->x_width-RIGHT_INNER_O,
"REGH_RTERM_GCLK%i", 0))) goto xout;
if ((rc = add_conn_range(model, NOPREF_BI_F,
model->center_y, model->x_width-RIGHT_OUTER_O,
"REGR_GCLK%i", 2, 3,
model->center_y, model->x_width-RIGHT_INNER_O,
"REGR_RTERM_GCLK%i", 2))) goto xout;
// same from MCB_REGH_GCLK...
if ((rc = add_conn_range(model, NOPREF_BI_F,
model->center_y, model->x_width-RIGHT_MCB_O,
"MCB_REGH_GCLK%i", 0, 1,
model->center_y-1, model->x_width-RIGHT_IO_ROUTING_O,
"INT_BUFPLL_GCLK%i", 0))) goto xout;
if ((rc = add_conn_range(model, NOPREF_BI_F,
model->center_y, model->x_width-RIGHT_MCB_O,
"MCB_REGH_GCLK%i", 0, 1,
model->center_y, model->x_width-RIGHT_IO_ROUTING_O,
"REGH_RIOI_INT_GCLK%i", 0))) goto xout;
if ((rc = add_conn_range(model, NOPREF_BI_F,
model->center_y, model->x_width-RIGHT_MCB_O,
"MCB_REGH_GCLK%i", 2, 3,
model->center_y, model->x_width-RIGHT_IO_ROUTING_O,
"REGH_IOI_INT_GCLK%i", 2))) goto xout;
if ((rc = add_conn_range(model, NOPREF_BI_F,
model->center_y, model->x_width-RIGHT_MCB_O,
"MCB_REGH_GCLK%i", 0, 1,
model->center_y, model->x_width-RIGHT_INNER_O,
"REGH_RTERM_GCLK%i", 0))) goto xout;
if ((rc = add_conn_range(model, NOPREF_BI_F,
model->center_y, model->x_width-RIGHT_MCB_O,
"MCB_REGH_GCLK%i", 2, 3,
model->center_y, model->x_width-RIGHT_INNER_O,
"REGR_RTERM_GCLK%i", 2))) goto xout;
RC_RETURN(model);
xout:
return rc;
}
static int run_gclk_vert_regs(struct fpga_model* model)
{
struct w_net net;
int rc, i;
RC_CHECK(model);
// net tying together 15 gclk lines from row 10..27
net.last_inc = 15;
for (net.num_pts = 0; net.num_pts <= 17; net.num_pts++) {
if (is_aty(Y_ROW_HORIZ_AXSYMM, model, net.num_pts+10))
net.pt[net.num_pts].name = "CLKV_GCLKH_MAIN%i_FOLD";
else if (net.num_pts == 9) // row 19
net.pt[net.num_pts].name = "CLKV_GCLK_MAIN%i_BUF";
else
net.pt[net.num_pts].name = "CLKV_GCLK_MAIN%i_FOLD";
net.pt[net.num_pts].start_count = 0;
net.pt[net.num_pts].y = net.num_pts+10;
net.pt[net.num_pts].x = model->center_x;
}
if ((rc = add_conn_net(model, NO_PREF, &net))) goto xout;
// net tying together 15 gclk lines from row 19..53
net.last_inc = 15;
for (net.num_pts = 0; net.num_pts <= 34; net.num_pts++) { // row 19..53
if (is_aty(Y_ROW_HORIZ_AXSYMM, model, net.num_pts+19))
net.pt[net.num_pts].name = "REGV_GCLKH_MAIN%i";
else if (is_aty(Y_CHIP_HORIZ_REGS, model, net.num_pts+19))
net.pt[net.num_pts].name = "CLKC_GCLK_MAIN%i";
else if (net.num_pts == 16) // row 35
net.pt[net.num_pts].name = "CLKV_GCLK_MAIN%i_BRK";
else
net.pt[net.num_pts].name = "CLKV_GCLK_MAIN%i";
net.pt[net.num_pts].start_count = 0;
net.pt[net.num_pts].y = net.num_pts+19;
net.pt[net.num_pts].x = model->center_x;
}
if ((rc = add_conn_net(model, NO_PREF, &net))) goto xout;
// net tying together 15 gclk lines from row 45..62
net.last_inc = 15;
for (net.num_pts = 0; net.num_pts <= 17; net.num_pts++) {
if (is_aty(Y_ROW_HORIZ_AXSYMM, model, net.num_pts+45))
net.pt[net.num_pts].name = "CLKV_GCLKH_MAIN%i_FOLD";
else if (net.num_pts == 8) // row 53
net.pt[net.num_pts].name = "CLKV_GCLK_MAIN%i_BUF";
else
net.pt[net.num_pts].name = "CLKV_GCLK_MAIN%i_FOLD";
net.pt[net.num_pts].start_count = 0;
net.pt[net.num_pts].y = net.num_pts+45;
net.pt[net.num_pts].x = model->center_x;
}
if ((rc = add_conn_net(model, NO_PREF, &net))) goto xout;
// a few local gclk networks at the center top and bottom
{ struct w_net n = {
.last_inc = 1, .num_pts = 4, .pt =
{{ "REGT_GCLK%i", 0, TOP_OUTER_ROW, model->center_x-1 },
{ "REGT_TTERM_GCLK%i", 0, TOP_INNER_ROW, model->center_x-1 },
{ "REGV_TTERM_GCLK%i", 0, TOP_INNER_ROW, model->center_x },
{ "BUFPLL_TOP_GCLK%i", 0, TOP_INNER_ROW, model->center_x+1 }}};
if ((rc = add_conn_net(model, NO_PREF, &n))) goto xout; }
{ struct w_net n = {
.last_inc = 1, .num_pts = 4, .pt =
{{ "REGB_GCLK%i", 0, model->y_height-1, model->center_x-1 },
{ "REGB_BTERM_GCLK%i", 0, model->y_height-2, model->center_x-1 },
{ "REGV_BTERM_GCLK%i", 0, model->y_height-2, model->center_x },
{ "BUFPLL_BOT_GCLK%i", 0, model->y_height-2, model->center_x+1 }}};
if ((rc = add_conn_net(model, NO_PREF, &n))) goto xout; }
// wire up gclk from tterm down to top 8 rows at center_x+1
for (i = TOP_IO_TILES; i <= TOP_IO_TILES+HALF_ROW; i++) {
if ((rc = add_conn_range(model, NOPREF_BI_F,
TOP_INNER_ROW, model->center_x+1,
"IOI_TTERM_GCLK%i", 0, 15,
i, model->center_x+1,
(i == TOP_IO_TILES+HALF_ROW) ?
"HCLK_GCLK_UP%i" : "GCLK%i", 0))) goto xout;
}
// same at the bottom upwards
for (i = model->y_height-2-1; i >= model->y_height-2-HALF_ROW-1; i--) {
if ((rc = add_conn_range(model, NOPREF_BI_F,
model->y_height-2, model->center_x+1,
"IOI_BTERM_GCLK%i", 0, 15,
i, model->center_x+1,
(i == model->y_height-2-HALF_ROW-1) ?
"HCLK_GCLK%i" : "GCLK%i", 0))) goto xout;
}
RC_RETURN(model);
xout:
return rc;
}
static int connect_logic_carry(struct fpga_model* model)
{
int x, y, rc;
RC_CHECK(model);
for (x = 0; x < model->x_width; x++) {
if (is_atx(X_FABRIC_LOGIC_COL|X_CENTER_LOGIC_COL, model, x)) {
for (y = TOP_IO_TILES; y < model->y_height - BOT_IO_TILES; y++) {
if (has_device_type(model, y, x, DEV_LOGIC, LOGIC_M)) {
if (is_aty(Y_CHIP_HORIZ_REGS, model, y-1)
&& has_device_type(model, y-2, x, DEV_LOGIC, LOGIC_M)) {
struct w_net net = {
.last_inc = 0, .num_pts = 3, .pt =
{{ "M_CIN", 0, y-2, x },
{ "REGH_CLEXM_COUT", 0, y-1, x },
{ "M_COUT_N", 0, y, x }}};
if ((rc = add_conn_net(model, NO_PREF, &net))) goto xout;
} else if (is_aty(Y_ROW_HORIZ_AXSYMM, model, y-1)
&& has_device_type(model, y-2, x, DEV_LOGIC, LOGIC_M)) {
struct w_net net = {
0, 3,
{{ "M_CIN", 0, y-2, x },
{ "HCLK_CLEXM_COUT", 0, y-1, x },
{ "M_COUT_N", 0, y, x }}};
if ((rc = add_conn_net(model, NO_PREF, &net))) goto xout;
} else if (has_device_type(model, y-1, x, DEV_LOGIC, LOGIC_M)) {
if ((rc = add_conn_bi(model, y, x, "M_COUT_N", y-1, x, "M_CIN"))) goto xout;
}
}
else if (has_device_type(model, y, x, DEV_LOGIC, LOGIC_L)) {
if (is_aty(Y_CHIP_HORIZ_REGS, model, y-1)) {
if (x == model->center_x - CENTER_LOGIC_O) {
struct w_net net = {
.last_inc = 0, .num_pts = 4, .pt =
{{ "L_CIN", 0, y-3, x },
{ "INT_INTERFACE_COUT", 0, y-2, x },
{ "REGC_CLE_COUT", 0, y-1, x },
{ "XL_COUT_N", 0, y, x }}};
if ((rc = add_conn_net(model, NO_PREF, &net))) goto xout;
} else {
struct w_net net = {
.last_inc = 0, .num_pts = 3, .pt =
{{ "L_CIN", 0, y-2, x },
{ "REGH_CLEXL_COUT", 0, y-1, x },
{ "XL_COUT_N", 0, y, x }}};
if ((rc = add_conn_net(model, NO_PREF, &net))) goto xout;
}
} else if (is_aty(Y_ROW_HORIZ_AXSYMM, model, y-1)) {
struct w_net net = {
.last_inc = 0, .num_pts = 3, .pt =
{{ "L_CIN", 0, y-2, x },
{ "HCLK_CLEXL_COUT", 0, y-1, x },
{ "XL_COUT_N", 0, y, x }}};
if ((rc = add_conn_net(model, NO_PREF, &net))) goto xout;
} else if (is_aty(Y_ROW_HORIZ_AXSYMM, model, y-2)
&& (x == model->center_x - CENTER_LOGIC_O)) {
struct w_net net = {
.last_inc = 0, .num_pts = 5, .pt =
{{ "L_CIN", 0, y-4, x },
{ "INT_INTERFACE_COUT", 0, y-3, x },
{ "HCLK_CLEXL_COUT", 0, y-2, x },
{ "INT_INTERFACE_COUT_BOT", 0, y-1, x },
{ "XL_COUT_N", 0, y, x }}};
if ((rc = add_conn_net(model, NO_PREF, &net))) goto xout;
} else if (has_device_type(model, y-1, x, DEV_LOGIC, LOGIC_L)) {
if ((rc = add_conn_bi(model, y, x, "XL_COUT_N", y-1, x, "L_CIN"))) goto xout;
}
}
}
}
}
RC_RETURN(model);
xout:
return rc;
}
static int connect_clk_sr(struct fpga_model* model, const char* clk_sr)
{
int x, y, i, rc;
RC_CHECK(model);
// fabric logic, bram, macc
for (x = LEFT_SIDE_WIDTH; x < model->x_width - RIGHT_SIDE_WIDTH; x++) {
if (is_atx(X_FABRIC_BRAM_ROUTING_COL, model, x)) {
for (y = TOP_IO_TILES; y < model->y_height - BOT_IO_TILES; y++) {
if (has_device(model, y, x+2, DEV_BRAM16)) {
for (i = 0; i <= 3; i++) {
struct w_net n = {
.last_inc = 1, .num_pts = 3, .pt =
{{ pf("%s%%i", clk_sr), 0, y-i, x },
{ pf("INT_INTERFACE_%s%%i", clk_sr), 0, y-i, x+1 },
{ pf("BRAM_%s%%i_INT%i", clk_sr, i), 0, y, x+2 }}};
if ((rc = add_conn_net(model, NO_PREF, &n))) RC_FAIL(model, rc);
}
}
}
}
if (is_atx(X_FABRIC_LOGIC_ROUTING_COL|X_CENTER_ROUTING_COL, model, x)) {
for (y = TOP_IO_TILES; y < model->y_height - BOT_IO_TILES; y++) {
if (has_device_type(model, y, x+1, DEV_LOGIC, LOGIC_M)) {
if ((rc = add_conn_range(model,
NOPREF_BI_F,
y, x, pf("%s%%i", clk_sr), 0, 1,
y, x+1, pf("CLEXM_%s%%i", clk_sr), 0)))
RC_FAIL(model, rc);
} else if (has_device_type(model, y, x+1, DEV_LOGIC, LOGIC_L)) {
if ((rc = add_conn_range(model,
NOPREF_BI_F,
y, x, pf("%s%%i", clk_sr), 0, 1,
y, x+1, pf("CLEXL_%s%%i", clk_sr), 0)))
RC_FAIL(model, rc);
} else if (has_device(model, y, x+1, DEV_ILOGIC)) {
if ((rc = add_conn_range(model,
NOPREF_BI_F,
y, x, pf("%s%%i", clk_sr), 0, 1,
y, x+1, pf("IOI_%s%%i", clk_sr), 0)))
RC_FAIL(model, rc);
}
}
}
}
// center PLLs and DCMs
if ((rc = add_conn_range(model, NOPREF_BI_F,
model->center_y-1, model->center_x-CENTER_ROUTING_O, pf("%s%%i", clk_sr), 0, 1,
model->center_y-1, model->center_x-CENTER_LOGIC_O, pf("INT_INTERFACE_REGC_%s%%i", clk_sr), 0)))
RC_FAIL(model, rc);
for (y = TOP_IO_TILES; y < model->y_height - BOT_IO_TILES; y++) {
if (is_aty(Y_ROW_HORIZ_AXSYMM, model, y)) {
if (has_device(model, y-1, model->center_x-CENTER_CMTPLL_O, DEV_PLL)) {
{ struct w_net net = {
.last_inc = 1, .num_pts = 3, .pt =
{{ pf("%s%%i", clk_sr), 0, y-1, model->center_x-CENTER_ROUTING_O },
{ pf("INT_INTERFACE_%s%%i", clk_sr), 0, y-1, model->center_x-CENTER_LOGIC_O },
{ pf("PLL_CLB2_%s%%i", clk_sr), 0, y-1, model->center_x-CENTER_CMTPLL_O }}};
if ((rc = add_conn_net(model, NO_PREF, &net))) RC_FAIL(model, rc); }
{ struct w_net net = {
.last_inc = 1, .num_pts = 3, .pt =
{{ pf("%s%%i", clk_sr), 0, y+1, model->center_x-CENTER_ROUTING_O },
{ pf("INT_INTERFACE_%s%%i", clk_sr), 0, y+1, model->center_x-CENTER_LOGIC_O },
{ pf("PLL_CLB1_%s%%i", clk_sr), 0, y-1, model->center_x-CENTER_CMTPLL_O }}};
if ((rc = add_conn_net(model, NO_PREF, &net))) RC_FAIL(model, rc); }
}
if (has_device(model, y-1, model->center_x-CENTER_CMTPLL_O, DEV_DCM)) {
{ struct w_net net = {
.last_inc = 1, .num_pts = 3, .pt =
{{ pf("%s%%i", clk_sr), 0, y-1, model->center_x-CENTER_ROUTING_O },
{ pf("INT_INTERFACE_%s%%i", clk_sr), 0, y-1, model->center_x-CENTER_LOGIC_O },
{ pf("DCM_CLB2_%s%%i", clk_sr), 0, y-1, model->center_x-CENTER_CMTPLL_O }}};
if ((rc = add_conn_net(model, NO_PREF, &net))) RC_FAIL(model, rc); }
{ struct w_net net = {
.last_inc = 1, .num_pts = 3, .pt =
{{ pf("%s%%i", clk_sr), 0, y+1, model->center_x-CENTER_ROUTING_O },
{ pf("INT_INTERFACE_%s%%i", clk_sr), 0, y+1, model->center_x-CENTER_LOGIC_O },
{ pf("DCM_CLB1_%s%%i", clk_sr), 0, y-1, model->center_x-CENTER_CMTPLL_O }}};
if ((rc = add_conn_net(model, NO_PREF, &net))) RC_FAIL(model, rc); }
}
}
}
// left and right side
for (y = TOP_IO_TILES; y < model->y_height - BOT_IO_TILES; y++) {
if (is_aty(Y_ROW_HORIZ_AXSYMM|Y_CHIP_HORIZ_REGS, model, y)
|| find_mui_pos(model, y) != -1) // hanled in mui()
continue;
x = LEFT_IO_ROUTING;
if (y < TOP_IO_TILES+LEFT_LOCAL_HEIGHT || y > model->y_height-BOT_IO_TILES-LEFT_LOCAL_HEIGHT-1) {
if ((rc = add_conn_range(model, NOPREF_BI_F, y, x, pf("%s%%i", clk_sr), 0, 1, y, x+1, pf("INT_INTERFACE_LOCAL_%s%%i", clk_sr), 0))) RC_FAIL(model, rc);
} else if (is_aty(Y_LEFT_WIRED, model, y)) {
if ((rc = add_conn_range(model, NOPREF_BI_F, y, x, pf("%s%%i", clk_sr), 0, 1, y, x+1, pf("IOI_%s%%i", clk_sr), 0))) RC_FAIL(model, rc);
} else {
if ((rc = add_conn_range(model, NOPREF_BI_F, y, x, pf("%s%%i", clk_sr), 0, 1, y, x+1, pf("INT_INTERFACE_%s%%i", clk_sr), 0))) RC_FAIL(model, rc);
}
x = model->x_width - RIGHT_IO_ROUTING_O;
if (y < TOP_IO_TILES+RIGHT_LOCAL_HEIGHT || y > model->y_height-BOT_IO_TILES-RIGHT_LOCAL_HEIGHT-1) {
if ((rc = add_conn_range(model, NOPREF_BI_F, y, x, pf("%s%%i", clk_sr), 0, 1, y, x+1, pf("INT_INTERFACE_LOCAL_%s%%i", clk_sr), 0))) RC_FAIL(model, rc);
} else if (is_aty(Y_RIGHT_WIRED, model, y)) {
if ((rc = add_conn_range(model, NOPREF_BI_F, y, x, pf("%s%%i", clk_sr), 0, 1, y, x+1, pf("IOI_%s%%i", clk_sr), 0))) RC_FAIL(model, rc);
} else {
if ((rc = add_conn_range(model, NOPREF_BI_F, y, x, pf("%s%%i", clk_sr), 0, 1, y, x+1, pf("INT_INTERFACE_%s%%i", clk_sr), 0))) RC_FAIL(model, rc);
}
}
RC_RETURN(model);
}
static int run_gfan(struct fpga_model* model)
{
int x, y, i;
RC_CHECK(model);
// left and right IO devs
for (y = TOP_IO_TILES; y < model->y_height-BOT_IO_TILES; y++) {
if (is_aty(Y_LEFT_WIRED, model, y)) {
add_conn_range(model, NOPREF_BI_F,
y, LEFT_IO_ROUTING, "INT_IOI_GFAN%i", 0, 1,
y, LEFT_IO_DEVS, "IOI_GFAN%i", 0);
}
if (is_aty(Y_RIGHT_WIRED, model, y)) {
add_conn_range(model, NOPREF_BI_F,
y, model->x_width-RIGHT_IO_ROUTING_O,
"INT_IOI_GFAN%i", 0, 1,
y, model->x_width-RIGHT_IO_DEVS_O,
"IOI_GFAN%i", 0);
}
}
// top and bottom IO devs
for (x = LEFT_SIDE_WIDTH; x < model->x_width - RIGHT_SIDE_WIDTH; x++) {
if (!is_atx(X_FABRIC_LOGIC_ROUTING_COL|X_CENTER_ROUTING_COL, model, x)
|| is_atx(X_ROUTING_NO_IO, model, x))
continue;
for (i = 0; i < TOPBOT_IO_ROWS; i++) {
add_conn_range(model, NOPREF_BI_F,
TOP_OUTER_IO+i, x, "INT_IOI_GFAN%i", 0, 1,
TOP_OUTER_IO+i, x+1, "IOI_GFAN%i", 0);
add_conn_range(model, NOPREF_BI_F,
model->y_height-BOT_OUTER_IO-i, x,
"INT_IOI_GFAN%i", 0, 1,
model->y_height-BOT_OUTER_IO-i, x+1,
"IOI_GFAN%i", 0);
}
}
// center devs
for (y = TOP_IO_TILES; y < model->y_height - BOT_IO_TILES; y++) {
if (is_aty(Y_ROW_HORIZ_AXSYMM, model, y)) {
if (YX_TILE(model, y-1, model->center_x-CENTER_CMTPLL_O)->flags & TF_DCM_DEV) {
{ struct w_net net = {
.last_inc = 1, .num_pts = 3, .pt =
{{ "INT_IOI_GFAN%i", 0, y-1, model->center_x-CENTER_ROUTING_O },
{ "INT_INTERFACE_GFAN%i", 0, y-1, model->center_x-CENTER_LOGIC_O },
{ "DCM2_GFAN%i", 0, y-1, model->center_x-CENTER_CMTPLL_O }}};
add_conn_net(model, NO_PREF, &net); }
{ struct w_net net = {
.last_inc = 1, .num_pts = 3, .pt =
{{ "INT_IOI_GFAN%i", 0, y+1, model->center_x-CENTER_ROUTING_O },
{ "INT_INTERFACE_GFAN%i", 0, y+1, model->center_x-CENTER_LOGIC_O },
{ "DCM1_GFAN%i", 0, y-1, model->center_x-CENTER_CMTPLL_O }}};
add_conn_net(model, NO_PREF, &net); }
} else if (YX_TILE(model, y-1, model->center_x-CENTER_CMTPLL_O)->flags & TF_PLL_DEV) {
struct w_net net = {
.last_inc = 1, .num_pts = 3, .pt =
{{ "INT_IOI_GFAN%i", 0, y-1, model->center_x-CENTER_ROUTING_O },
{ "INT_INTERFACE_GFAN%i", 0, y-1, model->center_x-CENTER_LOGIC_O },
{ "PLL_CLB2_GFAN%i", 0, y-1, model->center_x-CENTER_CMTPLL_O }}};
add_conn_net(model, NO_PREF, &net);
}
}
}
RC_RETURN(model);
}
static int run_io_wires(struct fpga_model* model)
{
static const char* s[] = { "IBUF", "O", "T", "" };
int x, y, i, rc;
RC_CHECK(model);
//
// 1. input wires from IBUF into the chip "IBUF"
// 2. output wires from the chip into O "O"
// 3. T wires "T"
//
for (x = LEFT_SIDE_WIDTH; x < model->x_width - RIGHT_SIDE_WIDTH; x++) {
y = 0;
if (has_device(model, y, x, DEV_IOB)) {
for (i = 0; s[i][0]; i++) {
struct w_net net1 = {
.last_inc = 1, .num_pts = 4, .pt =
{{ pf("TIOB_%s%%i", s[i]), 0, y, x },
{ pf("IOI_TTERM_IOIUP_%s%%i", s[i]), 0, y+1, x },
{ pf("TTERM_IOIUP_%s%%i", s[i]), 0, y+1, x+1 },
{ pf("TIOI_OUTER_%s%%i", s[i]), 0, y+2, x+1 }}};
struct w_net net2 = {
.last_inc = 1, .num_pts = 5, .pt =
{{ pf("TIOB_%s%%i", s[i]), 2, y, x },
{ pf("IOI_TTERM_IOIBOT_%s%%i", s[i]), 0, y+1, x },
{ pf("TTERM_IOIBOT_%s%%i", s[i]), 0, y+1, x+1 },
{ pf("TIOI_OUTER_%s%%i_EXT", s[i]), 0, y+2, x+1 },
{ pf("TIOI_INNER_%s%%i", s[i]), 0, y+3, x+1 }}};
if ((rc = add_conn_net(model, NO_PREF, &net1))) goto xout;
if ((rc = add_conn_net(model, NO_PREF, &net2))) goto xout;
}
}
y = model->y_height - BOT_OUTER_ROW;
if (has_device(model, y, x, DEV_IOB)) {
for (i = 0; s[i][0]; i++) {
struct w_net net1 = {
.last_inc = 1, .num_pts = 5, .pt =
{{ pf("BIOI_INNER_%s%%i", s[i]), 0, y-3, x+1 },
{ pf("BIOI_OUTER_%s%%i_EXT", s[i]), 0, y-2, x+1 },
{ pf("BTERM_IOIUP_%s%%i", s[i]), 0, y-1, x+1 },
{ pf("IOI_BTERM_IOIUP_%s%%i", s[i]), 0, y-1, x },
{ pf("BIOB_%s%%i", s[i]), 0, y, x }}};
if ((rc = add_conn_net(model, NO_PREF, &net1))) goto xout;
// The following is actually a net, but add_conn_net()/w_net
// does not support COUNT_DOWN ranges right now.
rc = add_conn_range(model, NOPREF_BI_F, y, x, pf("BIOB_%s%%i", s[i]), 2, 3, y-1, x, pf("IOI_BTERM_IOIBOT_%s%%i", s[i]), 1 | COUNT_DOWN);
if (rc) goto xout;
rc = add_conn_range(model, NOPREF_BI_F, y, x, pf("BIOB_%s%%i", s[i]), 2, 3, y-1, x+1, pf("BTERM_IOIBOT_%s%%i", s[i]), 1 | COUNT_DOWN);
if (rc) goto xout;
rc = add_conn_range(model, NOPREF_BI_F, y, x, pf("BIOB_%s%%i", s[i]), 2, 3, y-2, x+1, pf("BIOI_OUTER_%s%%i", s[i]), 1 | COUNT_DOWN);
if (rc) goto xout;
rc = add_conn_range(model, NOPREF_BI_F, y-1, x, pf("IOI_BTERM_IOIBOT_%s%%i", s[i]), 0, 1, y-1, x+1, pf("BTERM_IOIBOT_%s%%i", s[i]), 0);
if (rc) goto xout;
rc = add_conn_range(model, NOPREF_BI_F, y-1, x, pf("IOI_BTERM_IOIBOT_%s%%i", s[i]), 0, 1, y-2, x+1, pf("BIOI_OUTER_%s%%i", s[i]), 0);
if (rc) goto xout;
rc = add_conn_range(model, NOPREF_BI_F, y-1, x+1, pf("BTERM_IOIBOT_%s%%i", s[i]), 0, 1, y-2, x+1, pf("BIOI_OUTER_%s%%i", s[i]), 0);
if (rc) goto xout;
}
}
}
for (y = TOP_IO_TILES; y < model->y_height - BOT_IO_TILES; y++) {
if (has_device(model, y, LEFT_IO_DEVS, DEV_ILOGIC)) {
x = 0;
for (i = 0; s[i][0]; i++) {
struct w_net net = {
.last_inc = 1, .num_pts = 4, .pt =
{{ pf("LIOB_%s%%i", s[i]), 0, y, x },
{ pf("LTERM_IOB_%s%%i", s[i]), 0, y, x+1 },
{ pf("LIOI_INT_%s%%i", s[i]), 0, y, x+2 },
{ pf("LIOI_IOB_%s%%i", s[i]), 0, y, x+3 }}};
if ((rc = add_conn_net(model, NO_PREF, &net))) goto xout;
}
}
if (has_device(model, y, model->x_width - RIGHT_IO_DEVS_O, DEV_ILOGIC)) {
x = model->x_width - RIGHT_OUTER_O;
for (i = 0; s[i][0]; i++) {
struct w_net net = {
.last_inc = 1, .num_pts = 4, .pt =
{{ pf("RIOB_%s%%i", s[i]), 0, y, x },
{ pf("RTERM_IOB_%s%%i", s[i]), 0, y, x-1 },
{ pf("MCB_%s%%i", s[i]), 0, y, x-2 },
{ pf("RIOI_IOB_%s%%i", s[i]), 0, y, x-3 }}};
if ((rc = add_conn_net(model, NO_PREF, &net))) goto xout;
}
}
}
RC_RETURN(model);
xout:
return rc;
}
static int run_logic_inout(struct fpga_model* model)
{
struct fpga_tile* tile;
char buf[128];
int x, y, i, j, rc;
RC_CHECK(model);
// LOGICOUT
for (x = 0; x < model->x_width; x++) {
if (is_atx(X_FABRIC_LOGIC_ROUTING_COL|X_CENTER_ROUTING_COL, model, x)) {
for (y = 0; y < model->y_height; y++) {
tile = &model->tiles[y * model->x_width + x];
if (tile[1].flags & TF_LOGIC_XM_DEV) {
if ((rc = add_conn_range(model, NOPREF_BI_F, y, x, "LOGICOUT%i", 0, 23, y, x+1, "CLEXM_LOGICOUT%i", 0))) RC_FAIL(model, rc);
}
if (tile[1].flags & TF_LOGIC_XL_DEV) {
if ((rc = add_conn_range(model, NOPREF_BI_F, y, x, "LOGICOUT%i", 0, 23, y, x+1, "CLEXL_LOGICOUT%i", 0))) RC_FAIL(model, rc);
}
if (tile[1].flags & TF_IOLOGIC_DELAY_DEV) {
if ((rc = add_conn_range(model, NOPREF_BI_F, y, x, "LOGICOUT%i", 0, 23, y, x+1, "IOI_LOGICOUT%i", 0))) RC_FAIL(model, rc);
}
}
}
if (is_atx(X_FABRIC_BRAM_ROUTING_COL, model, x)) {
for (y = TOP_IO_TILES; y < model->y_height - BOT_IO_TILES; y++) {
if (is_aty(Y_ROW_HORIZ_AXSYMM|Y_CHIP_HORIZ_REGS,
model, y))
continue;
if ((rc = add_conn_range(model, NOPREF_BI_F, y, x, "LOGICOUT%i", 0, 23, y, x+1, "INT_INTERFACE_LOGICOUT%i", 0))) RC_FAIL(model, rc);
if (YX_TILE(model, y, x)[2].flags & TF_BRAM_DEV) {
if ((rc = add_conn_range(model, NOPREF_BI_F, y-3, x+1, "INT_INTERFACE_LOGICOUT_%i", 0, 23, y, x+2, "BRAM_LOGICOUT%i_INT3", 0))) RC_FAIL(model, rc);
if ((rc = add_conn_range(model, NOPREF_BI_F, y-2, x+1, "INT_INTERFACE_LOGICOUT_%i", 0, 23, y, x+2, "BRAM_LOGICOUT%i_INT2", 0))) RC_FAIL(model, rc);
if ((rc = add_conn_range(model, NOPREF_BI_F, y-1, x+1, "INT_INTERFACE_LOGICOUT_%i", 0, 23, y, x+2, "BRAM_LOGICOUT%i_INT1", 0))) RC_FAIL(model, rc);
if ((rc = add_conn_range(model, NOPREF_BI_F, y, x+1, "INT_INTERFACE_LOGICOUT_%i", 0, 23, y, x+2, "BRAM_LOGICOUT%i_INT0", 0))) RC_FAIL(model, rc);
}
}
}
if (is_atx(X_CENTER_ROUTING_COL, model, x)) {
for (y = TOP_IO_TILES; y < model->y_height - BOT_IO_TILES; y++) {
if (is_aty(Y_ROW_HORIZ_AXSYMM, model, y)) {
if ((rc = add_conn_range(model, NOPREF_BI_F, y-1, x, "LOGICOUT%i", 0, 23, y-1, x+1, "INT_INTERFACE_LOGICOUT%i", 0))) RC_FAIL(model, rc);
if ((rc = add_conn_range(model, NOPREF_BI_F, y+1, x, "LOGICOUT%i", 0, 23, y+1, x+1, "INT_INTERFACE_LOGICOUT%i", 0))) RC_FAIL(model, rc);
if (YX_TILE(model, y-1, x+2)->flags & TF_DCM_DEV) {
if ((rc = add_conn_range(model, NOPREF_BI_F, y-1, x+1, "INT_INTERFACE_LOGICOUT_%i", 0, 23, y-1, x+2, "DCM_CLB2_LOGICOUT%i", 0))) RC_FAIL(model, rc);
if ((rc = add_conn_range(model, NOPREF_BI_F, y+1, x+1, "INT_INTERFACE_LOGICOUT_%i", 0, 23, y-1, x+2, "DCM_CLB1_LOGICOUT%i", 0))) RC_FAIL(model, rc);
} else if (YX_TILE(model, y-1, x+2)->flags & TF_PLL_DEV) {
if ((rc = add_conn_range(model, NOPREF_BI_F, y-1, x+1, "INT_INTERFACE_LOGICOUT_%i", 0, 23, y-1, x+2, "PLL_CLB2_LOGICOUT%i", 0))) RC_FAIL(model, rc);
if ((rc = add_conn_range(model, NOPREF_BI_F, y+1, x+1, "INT_INTERFACE_LOGICOUT_%i", 0, 23, y-1, x+2, "PLL_CLB1_LOGICOUT%i", 0))) RC_FAIL(model, rc);
}
}
if (is_aty(Y_CHIP_HORIZ_REGS, model, y)) {
if ((rc = add_conn_range(model, NOPREF_BI_F, y-1, x, "LOGICOUT%i", 0, 23, y-1, x+1, "INT_INTERFACE_REGC_LOGICOUT%i", 0))) RC_FAIL(model, rc);
}
}
}
if (is_atx(X_LEFT_IO_ROUTING_COL|X_RIGHT_IO_ROUTING_COL, model, x)) {
int wired_side, local_size;
if (is_atx(X_LEFT_IO_ROUTING_COL, model, x)) {
local_size = LEFT_LOCAL_HEIGHT;
wired_side = Y_LEFT_WIRED;
} else {
local_size = RIGHT_LOCAL_HEIGHT;
wired_side = Y_RIGHT_WIRED;
}
for (y = TOP_IO_TILES; y < model->y_height - BOT_IO_TILES; y++) {
if (is_aty(Y_ROW_HORIZ_AXSYMM|Y_CHIP_HORIZ_REGS,
model, y))
continue;
if (y < TOP_IO_TILES+local_size || y > model->y_height-BOT_IO_TILES-local_size-1) {
if ((rc = add_conn_range(model, NOPREF_BI_F, y, x, "LOGICOUT%i", 0, 23, y, x+1, "INT_INTERFACE_LOCAL_LOGICOUT%i", 0))) RC_FAIL(model, rc);
} else if (is_aty(wired_side, model, y)) {
if ((rc = add_conn_range(model, NOPREF_BI_F, y, x, "LOGICOUT%i", 0, 23, y, x+1, "IOI_LOGICOUT%i", 0))) RC_FAIL(model, rc);
} else {
// mui case is handled in mui()
if (find_mui_pos(model, y) == -1) {
if ((rc = add_conn_range(model, NOPREF_BI_F, y, x, "LOGICOUT%i", 0, 23,
y, x+1, "INT_INTERFACE_LOGICOUT%i", 0))) RC_FAIL(model, rc);
}
}
}
}
}
// LOGICIN
for (i = 0; i < model->die->num_rows; i++) {
y = TOP_IO_TILES + HALF_ROW + i*ROW_SIZE;
if (y > model->center_y) y++; // central regs
if (i%2) { // DCM
if ((rc = add_conn_range(model, NOPREF_BI_F,
y-1, model->center_x-CENTER_LOGIC_O, "INT_INTERFACE_LOGICBIN%i", 0, 3,
y-1, model->center_x-CENTER_CMTPLL_O, "DCM_CLB2_LOGICINB%i", 0))) RC_FAIL(model, rc);
if ((rc = add_conn_bi(model,
y-1, model->center_x-CENTER_LOGIC_O, "INT_INTERFACE_IOI_LOGICBIN4",
y-1, model->center_x-CENTER_CMTPLL_O, "DCM_CLB2_LOGICINB4"))) RC_FAIL(model, rc);
if ((rc = add_conn_range(model, NOPREF_BI_F,
y-1, model->center_x-CENTER_LOGIC_O, "INT_INTERFACE_LOGICBIN%i", 5, 9,
y-1, model->center_x-CENTER_CMTPLL_O, "DCM_CLB2_LOGICINB%i", 5))) RC_FAIL(model, rc);
if ((rc = add_conn_bi(model,
y-1, model->center_x-CENTER_LOGIC_O, "INT_INTERFACE_IOI_LOGICBIN10",
y-1, model->center_x-CENTER_CMTPLL_O, "DCM_CLB2_LOGICINB10"))) RC_FAIL(model, rc);
if ((rc = add_conn_range(model, NOPREF_BI_F,
y-1, model->center_x-CENTER_LOGIC_O, "INT_INTERFACE_LOGICBIN%i", 11, 62,
y-1, model->center_x-CENTER_CMTPLL_O, "DCM_CLB2_LOGICINB%i", 11))) RC_FAIL(model, rc);
if ((rc = add_conn_range(model, NOPREF_BI_F,
y+1, model->center_x-CENTER_LOGIC_O, "INT_INTERFACE_LOGICBIN%i", 0, 3,
y-1, model->center_x-CENTER_CMTPLL_O, "DCM_CLB1_LOGICINB%i", 0))) RC_FAIL(model, rc);
if ((rc = add_conn_bi(model,
y+1, model->center_x-CENTER_LOGIC_O, "INT_INTERFACE_IOI_LOGICBIN4",
y-1, model->center_x-CENTER_CMTPLL_O, "DCM_CLB1_LOGICINB4"))) RC_FAIL(model, rc);
if ((rc = add_conn_range(model, NOPREF_BI_F,
y+1, model->center_x-CENTER_LOGIC_O, "INT_INTERFACE_LOGICBIN%i", 5, 9,
y-1, model->center_x-CENTER_CMTPLL_O, "DCM_CLB1_LOGICINB%i", 5))) RC_FAIL(model, rc);
if ((rc = add_conn_bi(model,
y+1, model->center_x-CENTER_LOGIC_O, "INT_INTERFACE_IOI_LOGICBIN10",
y-1, model->center_x-CENTER_CMTPLL_O, "DCM_CLB1_LOGICINB10"))) RC_FAIL(model, rc);
if ((rc = add_conn_range(model, NOPREF_BI_F,
y+1, model->center_x-CENTER_LOGIC_O, "INT_INTERFACE_LOGICBIN%i", 11, 62,
y-1, model->center_x-CENTER_CMTPLL_O, "DCM_CLB1_LOGICINB%i", 11))) RC_FAIL(model, rc);
} else { // PLL
if ((rc = add_conn_range(model, NOPREF_BI_F,
y-1, model->center_x-CENTER_LOGIC_O, "INT_INTERFACE_LOGICBIN%i", 0, 3,
y-1, model->center_x-CENTER_CMTPLL_O, "PLL_CLB2_LOGICINB%i", 0))) RC_FAIL(model, rc);
if ((rc = add_conn_bi(model,
y-1, model->center_x-CENTER_LOGIC_O, "INT_INTERFACE_IOI_LOGICBIN4",
y-1, model->center_x-CENTER_CMTPLL_O, "PLL_CLB2_LOGICINB4"))) RC_FAIL(model, rc);
if ((rc = add_conn_range(model, NOPREF_BI_F,
y-1, model->center_x-CENTER_LOGIC_O, "INT_INTERFACE_LOGICBIN%i", 5, 9,
y-1, model->center_x-CENTER_CMTPLL_O, "PLL_CLB2_LOGICINB%i", 5))) RC_FAIL(model, rc);
if ((rc = add_conn_bi(model,
y-1, model->center_x-CENTER_LOGIC_O, "INT_INTERFACE_IOI_LOGICBIN10",
y-1, model->center_x-CENTER_CMTPLL_O, "PLL_CLB2_LOGICINB10"))) RC_FAIL(model, rc);
if ((rc = add_conn_range(model, NOPREF_BI_F,
y-1, model->center_x-CENTER_LOGIC_O, "INT_INTERFACE_LOGICBIN%i", 11, 62,
y-1, model->center_x-CENTER_CMTPLL_O, "PLL_CLB2_LOGICINB%i", 11))) RC_FAIL(model, rc);
if ((rc = add_conn_range(model, NOPREF_BI_F,
y+1, model->center_x-CENTER_LOGIC_O, "INT_INTERFACE_LOGICBIN%i", 0, 62,
y-1, model->center_x-CENTER_CMTPLL_O, "PLL_CLB1_LOGICINB%i", 0))) RC_FAIL(model, rc);
}
}
for (x = LEFT_IO_ROUTING;; x = model->x_width - RIGHT_IO_ROUTING_O) {
for (y = TOP_FIRST_REGULAR; y <= model->y_height - BOT_LAST_REGULAR_O; y++) {
if (has_device(model, y, x+1, DEV_BSCAN)
|| has_device(model, y, x+1, DEV_OCT_CALIBRATE)
|| has_device(model, y, x+1, DEV_STARTUP)) {
if ((rc = add_conn_range(model, NOPREF_BI_F,
y, x, "LOGICIN_B%i", 0, 62,
y, x+1, "INT_INTERFACE_LOCAL_LOGICBIN%i", 0))) RC_FAIL(model, rc);
} else if (y > model->die->mcb_ypos-6 && y <= model->die->mcb_ypos+6) {
struct w_net n = {
.last_inc = 62, .num_pts = 3, .pt =
{{ "LOGICIN_B%i", 0, y, x },
{ "INT_INTERFACE_LOGICBIN%i", 0, y, x+1 },
{ pf("MCB_L_CLEXM_LOGICIN_B%%i_%i", y-(model->die->mcb_ypos-6)), 0, model->die->mcb_ypos, x+2 }}};
if ((rc = add_conn_net(model, NO_PREF, &n))) RC_FAIL(model, rc);
} else {
if (find_mui_pos(model, y) == -1
&& !is_aty(Y_ROW_HORIZ_AXSYMM|Y_CHIP_HORIZ_REGS, model, y)
&& !has_device(model, y, x+1, DEV_IODELAY)) {
if ((rc = add_conn_range(model, NOPREF_BI_F,
y, x, "LOGICIN_B%i", 0, 62,
y, x+1, "INT_INTERFACE_LOGICBIN%i", 0))) RC_FAIL(model, rc);
}
}
}
if (x == model->x_width-RIGHT_IO_ROUTING_O)
break;
}
for (y = 0; y < model->y_height; y++) {
for (x = 0; x < model->x_width; x++) {
tile = YX_TILE(model, y, x);
if (is_atyx(YX_ROUTING_TILE, model, y, x)) {
static const int north_p[4] = {21, 28, 52, 60};
static const int south_p[4] = {20, 36, 44, 62};
for (i = 0; i < sizeof(north_p)/sizeof(north_p[0]); i++) {
if (is_aty(Y_INNER_TOP, model, y-1)) {
if ((rc = add_conn_bi_pref(model, y, x, pf("LOGICIN%i", north_p[i]), y-1, x, pf("LOGICIN%i", north_p[i])))) RC_FAIL(model, rc);
} else {
if ((rc = add_conn_bi_pref(model, y, x, pf("LOGICIN%i", north_p[i]), y-1, x, pf("LOGICIN_N%i", north_p[i])))) RC_FAIL(model, rc);
}
if (is_aty(Y_ROW_HORIZ_AXSYMM|Y_CHIP_HORIZ_REGS, model, y-1)) {
if ((rc = add_conn_bi_pref(model, y, x, pf("LOGICIN%i", north_p[i]), y-2, x, pf("LOGICIN_N%i", north_p[i])))) RC_FAIL(model, rc);
if ((rc = add_conn_bi_pref(model, y-1, x, pf("LOGICIN_N%i", north_p[i]), y-2, x, pf("LOGICIN_N%i", north_p[i])))) RC_FAIL(model, rc);
}
if (is_aty(Y_INNER_BOTTOM, model, y+1) && !is_atx(X_FABRIC_BRAM_ROUTING_COL, model, x)) {
if ((rc = add_conn_bi_pref(model, y, x, pf("LOGICIN_N%i", north_p[i]), y+1, x, pf("LOGICIN_N%i", north_p[i])))) RC_FAIL(model, rc);
}
}
for (i = 0; i < sizeof(south_p)/sizeof(south_p[0]); i++) {
if (is_aty(Y_INNER_TOP, model, y-1)) {
if ((rc = add_conn_bi_pref(model, y, x, pf("LOGICIN_S%i", south_p[i]), y-1, x, pf("LOGICIN_S%i", south_p[i])))) RC_FAIL(model, rc);
}
if (is_aty(Y_ROW_HORIZ_AXSYMM|Y_CHIP_HORIZ_REGS, model, y+1)) {
if ((rc = add_conn_bi_pref(model, y, x, pf("LOGICIN%i", south_p[i]), y+1, x, pf("LOGICIN%i", south_p[i])))) RC_FAIL(model, rc);
if ((rc = add_conn_bi_pref(model, y, x, pf("LOGICIN%i", south_p[i]), y+2, x, pf("LOGICIN_S%i", south_p[i])))) RC_FAIL(model, rc);
if ((rc = add_conn_bi_pref(model, y+1, x, pf("LOGICIN%i", south_p[i]), y+2, x, pf("LOGICIN_S%i", south_p[i])))) RC_FAIL(model, rc);
} else if (is_aty(Y_INNER_BOTTOM, model, y+1)) {
if (!is_atx(X_FABRIC_BRAM_ROUTING_COL, model, x))
if ((rc = add_conn_bi_pref(model, y, x, pf("LOGICIN%i", south_p[i]), y+1, x, pf("LOGICIN%i", south_p[i])))) RC_FAIL(model, rc);
} else {
if ((rc = add_conn_bi_pref(model, y, x, pf("LOGICIN%i", south_p[i]), y+1, x, pf("LOGICIN_S%i", south_p[i])))) RC_FAIL(model, rc);
}
}
if (tile[1].flags & TF_LOGIC_XM_DEV) {
if ((rc = add_conn_range(model, NOPREF_BI_F, y, x, "LOGICIN_B%i", 0, 62, y, x+1, "CLEXM_LOGICIN_B%i", 0))) RC_FAIL(model, rc);
}
if (tile[1].flags & TF_LOGIC_XL_DEV) {
if ((rc = add_conn_range(model, NOPREF_BI_F, y, x, "LOGICIN_B%i", 0, 35, y, x+1, "CLEXL_LOGICIN_B%i", 0))) RC_FAIL(model, rc);
if ((rc = add_conn_range(model, NOPREF_BI_F, y, x, "LOGICIN_B%i", 37, 43, y, x+1, "CLEXL_LOGICIN_B%i", 37))) RC_FAIL(model, rc);
if ((rc = add_conn_range(model, NOPREF_BI_F, y, x, "LOGICIN_B%i", 45, 52, y, x+1, "CLEXL_LOGICIN_B%i", 45))) RC_FAIL(model, rc);
if ((rc = add_conn_range(model, NOPREF_BI_F, y, x, "LOGICIN_B%i", 54, 60, y, x+1, "CLEXL_LOGICIN_B%i", 54))) RC_FAIL(model, rc);
}
if (tile[1].flags & TF_IOLOGIC_DELAY_DEV) {
if ((rc = add_conn_range(model, NOPREF_BI_F, y, x, "LOGICIN_B%i", 0, 3, y, x+1, "IOI_LOGICINB%i", 0))) RC_FAIL(model, rc);
if ((rc = add_conn_range(model, NOPREF_BI_F, y, x, "LOGICIN_B%i", 5, 9, y, x+1, "IOI_LOGICINB%i", 5))) RC_FAIL(model, rc);
if ((rc = add_conn_range(model, NOPREF_BI_F, y, x, "LOGICIN_B%i", 11, 62, y, x+1, "IOI_LOGICINB%i", 11))) RC_FAIL(model, rc);
}
if (is_atx(X_FABRIC_BRAM_ROUTING_COL, model, x)) {
if ((rc = add_conn_range(model, NOPREF_BI_F, y, x, "LOGICIN_B%i", 0, 62, y, x+1, "INT_INTERFACE_LOGICBIN%i", 0))) RC_FAIL(model, rc);
if (tile[2].flags & TF_BRAM_DEV) {
for (i = 0; i < 4; i++) {
sprintf(buf, "BRAM_LOGICINB%%i_INT%i", 3-i);
if ((rc = add_conn_range(model, NOPREF_BI_F, y-(3-i), x, "LOGICIN_B%i", 0, 62, y, x+2, buf, 0))) RC_FAIL(model, rc);
if ((rc = add_conn_range(model, NOPREF_BI_F, y-(3-i), x+1, "INT_INTERFACE_LOGICBIN%i", 0, 62, y, x+2, buf, 0))) RC_FAIL(model, rc);
}
}
}
if (is_atx(X_CENTER_REGS_COL, model, x+3)) {
if (tile[2].flags & (TF_PLL_DEV|TF_DCM_DEV)) {
const char* prefix = (tile[2].flags & TF_PLL_DEV) ? "PLL_CLB2" : "DCM_CLB2";
for (i = 0;; i = 2) {
if ((rc = add_conn_range(model, NOPREF_BI_F, y+i, x, "LOGICIN_B%i", 0, 3, y+i, x+1, "INT_INTERFACE_LOGICBIN%i", 0))) RC_FAIL(model, rc);
if ((rc = add_conn_bi(model, y+i, x, "INT_IOI_LOGICIN_B4", y+i, x+1, "INT_INTERFACE_IOI_LOGICBIN4"))) RC_FAIL(model, rc);
if ((rc = add_conn_range(model, NOPREF_BI_F, y+i, x, "LOGICIN_B%i", 5, 9, y+i, x+1, "INT_INTERFACE_LOGICBIN%i", 5))) RC_FAIL(model, rc);
if ((rc = add_conn_bi(model, y+i, x, "INT_IOI_LOGICIN_B10", y+i, x+1, "INT_INTERFACE_IOI_LOGICBIN10"))) RC_FAIL(model, rc);
if ((rc = add_conn_range(model, NOPREF_BI_F, y+i, x, "LOGICIN_B%i", 11, 62, y+i, x+1, "INT_INTERFACE_LOGICBIN%i", 11))) RC_FAIL(model, rc);
if ((rc = add_conn_range(model, NOPREF_BI_F, y+i, x, "LOGICIN_B%i", 0, 3, y, x+2, pf("%s_LOGICINB%%i", prefix), 0))) RC_FAIL(model, rc);
if ((rc = add_conn_bi(model, y+i, x, "INT_IOI_LOGICIN_B4", y, x+2, pf("%s_LOGICINB4", prefix)))) RC_FAIL(model, rc);
if ((rc = add_conn_range(model, NOPREF_BI_F, y+i, x, "LOGICIN_B%i", 5, 9, y, x+2, pf("%s_LOGICINB%%i", prefix), 5))) RC_FAIL(model, rc);
if ((rc = add_conn_bi(model, y+i, x, "INT_IOI_LOGICIN_B10", y, x+2, pf("%s_LOGICINB10", prefix)))) RC_FAIL(model, rc);
if ((rc = add_conn_range(model, NOPREF_BI_F, y+i, x, "LOGICIN_B%i", 11, 62, y, x+2, pf("%s_LOGICINB%%i", prefix), 11))) RC_FAIL(model, rc);
if (tile[2].flags & TF_PLL_DEV) {
if ((rc = add_conn_range(model, NOPREF_BI_F, y+2, x, "LOGICIN_B%i", 0, 62, y+2, x+1, "INT_INTERFACE_LOGICBIN%i", 0))) RC_FAIL(model, rc);
if ((rc = add_conn_range(model, NOPREF_BI_F, y+2, x, "LOGICIN_B%i", 0, 62, y, x+2, "PLL_CLB1_LOGICINB%i", 0))) RC_FAIL(model, rc);
break;
}
if (i == 2) break;
prefix = "DCM_CLB1";
}
}
if (is_aty(Y_CHIP_HORIZ_REGS, model, y+1)) {
for (i = 0; i <= LOGICIN_HIGHEST; i++) {
for (j = 0; j < sizeof(model->die->sel_logicin)/sizeof(model->die->sel_logicin[0]); j++) {
if (i == model->die->sel_logicin[j])
break;
}
// the sel_logicin wires are done in clkc()
if (j >= sizeof(model->die->sel_logicin)/sizeof(model->die->sel_logicin[0])
&& (rc = add_conn_bi(model, y, x, pf("LOGICIN_B%i", i),
y, x+1, pf("INT_INTERFACE_REGC_LOGICBIN%i", i))))
RC_FAIL(model, rc);
}
}
}
}
}
}
RC_RETURN(model);
}
static int net_includes_routing(struct fpga_model *model, const struct w_net *net)
{
int i;
RC_CHECK(model);
for (i = 0; i < net->num_pts; i++)
if (is_atyx(YX_ROUTING_TILE, model, net->pt[i].y, net->pt[i].x))
return 1;
RC_RETURN(model);
}
static int y_to_regular(struct fpga_model *model, int y)
{
RC_CHECK(model);
if (y < TOP_FIRST_REGULAR)
return TOP_FIRST_REGULAR;
if (is_aty(Y_ROW_HORIZ_AXSYMM|Y_CHIP_HORIZ_REGS, model, y))
return y-1;
if (y > model->y_height-BOT_LAST_REGULAR_O)
return model->y_height-BOT_LAST_REGULAR_O;
return y;
}
static char dirwire_next_bamce(enum wire_type wire, char bamce)
{
if (W_IS_LEN4(wire)) {
// len-4 goes from B to A to M to C to E
if (bamce == 'B') return 'A';
if (bamce == 'A') return 'M';
if (bamce == 'M') return 'C';
if (bamce == 'C') return 'E';
if (bamce == 'E') return 'B';
} else if (W_IS_LEN2(wire)) {
// len-2 goes from B to M to E
if (bamce == 'B') return 'M';
if (bamce == 'M') return 'E';
if (bamce == 'E') return 'B';
} else if (W_IS_LEN1(wire)) {
// len-1 goes from B to E
if (bamce == 'B') return 'E';
if (bamce == 'E') return 'B';
}
HERE();
return bamce;
}
static void dirwire_next_hop(struct fpga_model *model, enum wire_type wire, char bamce, int *y, int *x)
{
if (wire == W_NN4 || wire == W_NN2 || wire == W_NL1 || wire == W_NR1)
(*y)--;
else if (wire == W_SS4 || wire == W_SS2 || wire == W_SL1 || wire == W_SR1)
(*y)++;
else if (wire == W_EE4 || wire == W_EE2 || wire == W_EL1 || wire == W_ER1)
(*x)++;
else if (wire == W_WW4 || wire == W_WW2 || wire == W_WL1 || wire == W_WR1)
(*x)--;
else if (wire == W_NW4 || wire == W_NW2) {
if (bamce == 'B' || bamce == 'A')
(*y)--;
else if (bamce == 'M') {
if (is_aty(Y_INNER_BOTTOM|Y_ROW_HORIZ_AXSYMM|Y_CHIP_HORIZ_REGS, model, *y))
(*y)--;
else
(*x)--;
} else if (bamce == 'C' || bamce == 'E')
(*x)--;
else HERE();
} else if (wire == W_NE4 || wire == W_NE2) {
if (bamce == 'B' || bamce == 'A')
(*y)--;
else if (bamce == 'M') {
if (is_aty(Y_INNER_BOTTOM|Y_ROW_HORIZ_AXSYMM|Y_CHIP_HORIZ_REGS, model, *y))
(*y)--;
else
(*x)++;
} else if (bamce == 'C' || bamce == 'E')
(*x)++;
else HERE();
} else if (wire == W_SW4 || wire == W_SW2) {
if (bamce == 'B' || bamce == 'A')
(*y)++;
else if (bamce == 'M') {
if (is_aty(Y_INNER_TOP, model, *y))
(*y)++;
else
(*x)--;
} else if (bamce == 'C' || bamce == 'E')
(*x)--;
else HERE();
} else if (wire == W_SE4 || wire == W_SE2) {
if (bamce == 'B' || bamce == 'A')
(*y)++;
else if (bamce == 'M') {
if (is_aty(Y_INNER_TOP, model, *y))
(*y)++;
else
(*x)++;
} else if (bamce == 'C' || bamce == 'E')
(*x)++;
else HERE();
} else HERE();
}
#define DIRW_STR_BE(_wire) \
if (wire_type == W_##_wire) \
{ \
if (bamce == 'B') { \
const char *s[4] = { \
MACRO_STR(_wire) "B0", \
MACRO_STR(_wire) "B1", \
MACRO_STR(_wire) "B2", \
MACRO_STR(_wire) "B3" }; \
return s[num_0to3]; \
} \
if (bamce == 'E') { \
const char *s[4] = { \
MACRO_STR(_wire) "E0", \
MACRO_STR(_wire) "E1", \
MACRO_STR(_wire) "E2", \
MACRO_STR(_wire) "E3" }; \
return s[num_0to3]; \
} \
}
#define DIRW_STR_M(_wire) \
if (wire_type == W_##_wire) \
{ \
if (bamce == 'M') { \
const char *s[4] = { \
MACRO_STR(_wire) "M0", \
MACRO_STR(_wire) "M1", \
MACRO_STR(_wire) "M2", \
MACRO_STR(_wire) "M3" }; \
return s[num_0to3]; \
} \
}
#define DIRW_STR_AC(_wire) \
if (wire_type == W_##_wire) \
{ \
if (bamce == 'A') { \
const char *s[4] = { \
MACRO_STR(_wire) "A0", \
MACRO_STR(_wire) "A1", \
MACRO_STR(_wire) "A2", \
MACRO_STR(_wire) "A3" }; \
return s[num_0to3]; \
} \
if (bamce == 'C') { \
const char *s[4] = { \
MACRO_STR(_wire) "C0", \
MACRO_STR(_wire) "C1", \
MACRO_STR(_wire) "C2", \
MACRO_STR(_wire) "C3" }; \
return s[num_0to3]; \
} \
}
// dirw_str() is an optimization to replace printf() calls
// with static strings and saves about 5% of model creation time.
static const char *dirw_str(enum wire_type wire_type, char bamce, int num_0to3)
{
// len-1
DIRW_STR_BE(NL1);
DIRW_STR_BE(NR1);
DIRW_STR_BE(EL1);
DIRW_STR_BE(ER1);
DIRW_STR_BE(SL1);
DIRW_STR_BE(SR1);
DIRW_STR_BE(WL1);
DIRW_STR_BE(WR1);
// len-2
DIRW_STR_BE(NN2); DIRW_STR_M(NN2);
DIRW_STR_BE(NE2); DIRW_STR_M(NE2);
DIRW_STR_BE(EE2); DIRW_STR_M(EE2);
DIRW_STR_BE(SE2); DIRW_STR_M(SE2);
DIRW_STR_BE(SS2); DIRW_STR_M(SS2);
DIRW_STR_BE(SW2); DIRW_STR_M(SW2);
DIRW_STR_BE(WW2); DIRW_STR_M(WW2);
DIRW_STR_BE(NW2); DIRW_STR_M(NW2);
// len-4
DIRW_STR_BE(NN4); DIRW_STR_M(NN4); DIRW_STR_AC(NN4);
DIRW_STR_BE(NE4); DIRW_STR_M(NE4); DIRW_STR_AC(NE4);
DIRW_STR_BE(EE4); DIRW_STR_M(EE4); DIRW_STR_AC(EE4);
DIRW_STR_BE(SE4); DIRW_STR_M(SE4); DIRW_STR_AC(SE4);
DIRW_STR_BE(SS4); DIRW_STR_M(SS4); DIRW_STR_AC(SS4);
DIRW_STR_BE(SW4); DIRW_STR_M(SW4); DIRW_STR_AC(SW4);
DIRW_STR_BE(WW4); DIRW_STR_M(WW4); DIRW_STR_AC(WW4);
DIRW_STR_BE(NW4); DIRW_STR_M(NW4); DIRW_STR_AC(NW4);
HERE();
return pf("%s%c%i", wire_base(wire_type), bamce, num_0to3);
}
static int set_BAMCE_point(struct fpga_model *model, struct w_net *net,
enum wire_type wire, char bamce, int num_0to3, int *cur_y, int *cur_x)
{
int y_dist_to_dev, row_pos, i;
RC_CHECK(model);
while (1) {
net->pt[net->num_pts].start_count = 0;
net->pt[net->num_pts].y = *cur_y;
net->pt[net->num_pts].x = *cur_x;
if (is_atx(X_FABRIC_BRAM_COL|X_FABRIC_MACC_COL, model, *cur_x)) {
row_pos = regular_row_pos(*cur_y, model);
if (row_pos == -1) {
net->pt[net->num_pts].name = dirw_str(wire, bamce, num_0to3);
} else {
y_dist_to_dev = 3-(row_pos%4);
if (y_dist_to_dev) {
net->pt[net->num_pts].y += y_dist_to_dev;
net->pt[net->num_pts].name = pf("%s%c%i_%i", wire_base(wire), bamce, num_0to3, y_dist_to_dev);
} else
net->pt[net->num_pts].name = dirw_str(wire, bamce, num_0to3);
}
} else if (is_atx(X_CENTER_CMTPLL_COL, model, *cur_x)) {
row_pos = regular_row_pos(*cur_y, model);
if (row_pos == -1)
net->pt[net->num_pts].name = dirw_str(wire, bamce, num_0to3);
else {
y_dist_to_dev = 7-row_pos;
if (y_dist_to_dev > 0) {
net->pt[net->num_pts].y += y_dist_to_dev;
net->pt[net->num_pts].name = pf("%s%c%i_%i", wire_base(wire), bamce, num_0to3, y_dist_to_dev);
} else if (!y_dist_to_dev)
net->pt[net->num_pts].name = dirw_str(wire, bamce, num_0to3);
else { // y_dist_to_dev < 0
net->pt[net->num_pts].y += y_dist_to_dev - /*hclk*/ 1;
net->pt[net->num_pts].name = pf("%s%c%i_%i", wire_base(wire), bamce, num_0to3, 16+y_dist_to_dev);
}
}
} else if (is_atx(X_LEFT_MCB|X_RIGHT_MCB, model, *cur_x)) {
if (*cur_y > model->die->mcb_ypos-6 && *cur_y <= model->die->mcb_ypos+6 ) {
net->pt[net->num_pts].y = model->die->mcb_ypos;
net->pt[net->num_pts].name = pf("%s%c%i_%i", wire_base(wire), bamce, num_0to3, model->die->mcb_ypos+6-*cur_y);
} else {
for (i = 0; i < model->die->num_mui; i++) {
if (*cur_y == model->die->mui_pos[i]) {
net->pt[net->num_pts].y++;
net->pt[net->num_pts].name = pf("%s%c%i_1", wire_base(wire), bamce, num_0to3);
break;
}
if (*cur_y == model->die->mui_pos[i]+1) {
net->pt[net->num_pts].name = pf("%s%c%i_0", wire_base(wire), bamce, num_0to3);
break;
}
}
if (i >= model->die->num_mui)
net->pt[net->num_pts].name = dirw_str(wire, bamce, num_0to3);
}
} else {
if (is_atx(X_INNER_LEFT, model, *cur_x) && wire == W_SE2 && bamce == 'E' && num_0to3 == 3)
net->pt[net->num_pts].name = "SE2M3";
else
net->pt[net->num_pts].name = dirw_str(wire, bamce, num_0to3);
}
net->num_pts++;
if (bamce == 'E') {
if (is_atyx(YX_ROUTING_TILE, model, *cur_y, *cur_x)) {
if ((wire == W_EL1 || wire == W_NE2 || wire == W_NW4 || wire == W_NW2 || wire == W_WW4 || wire == W_WR1) && num_0to3 == 0) {
// add _S0
net->pt[net->num_pts].start_count = 0;
net->pt[net->num_pts].y = (*cur_y)+1;
net->pt[net->num_pts].x = *cur_x;
if (is_aty(Y_INNER_BOTTOM, model, (*cur_y)+1)) {
if (!is_atx(X_FABRIC_BRAM_ROUTING_COL, model, *cur_x)) {
net->pt[net->num_pts].name = pf("%sE0", wire_base(wire));
net->num_pts++;
}
} else if (is_aty(Y_ROW_HORIZ_AXSYMM|Y_CHIP_HORIZ_REGS, model, (*cur_y)+1)) {
net->pt[net->num_pts].name = pf("%sE0", wire_base(wire));
net->num_pts++;
net->pt[net->num_pts].start_count = 0;
net->pt[net->num_pts].y = (*cur_y)+2;
net->pt[net->num_pts].x = *cur_x;
net->pt[net->num_pts].name = pf("%sE_S0", wire_base(wire));
net->num_pts++;
} else {
net->pt[net->num_pts].name = pf("%sE_S0", wire_base(wire));
net->num_pts++;
}
} else if ((wire == W_NN2 || wire == W_NL1) && num_0to3 == 0) {
// add _S0
net->pt[net->num_pts].start_count = 0;
net->pt[net->num_pts].y = (*cur_y)+1;
net->pt[net->num_pts].x = *cur_x;
if (is_aty(Y_INNER_BOTTOM, model, (*cur_y)+1)) {
net->pt[net->num_pts].name = pf("%sE_S0", wire_base(wire));
net->num_pts++;
} else if (is_aty(Y_ROW_HORIZ_AXSYMM|Y_CHIP_HORIZ_REGS, model, (*cur_y)+1)) {
net->pt[net->num_pts].name = pf("%sE_S0", wire_base(wire));
net->num_pts++;
net->pt[net->num_pts].start_count = 0;
net->pt[net->num_pts].y = (*cur_y)+2;
net->pt[net->num_pts].x = *cur_x;
net->pt[net->num_pts].name = pf("%sE_S0", wire_base(wire));
net->num_pts++;
} else {
net->pt[net->num_pts].name = pf("%sE_S0", wire_base(wire));
net->num_pts++;
}
} else if ((wire == W_SW4 || wire == W_SW2 || wire == W_ER1 || wire == W_WW2 || wire == W_WL1) && num_0to3 == 3) {
// add _N3
net->pt[net->num_pts].start_count = 0;
net->pt[net->num_pts].y = (*cur_y)-1;
net->pt[net->num_pts].x = *cur_x;
if (is_aty(Y_INNER_TOP, model, (*cur_y)-1)) {
net->pt[net->num_pts].name = pf("%sE3", wire_base(wire));
net->num_pts++;
} else if (is_aty(Y_ROW_HORIZ_AXSYMM|Y_CHIP_HORIZ_REGS, model, (*cur_y)-1)) {
net->pt[net->num_pts].name = pf("%sE_N3", wire_base(wire));
net->num_pts++;
net->pt[net->num_pts].start_count = 0;
net->pt[net->num_pts].y = (*cur_y)-2;
net->pt[net->num_pts].x = *cur_x;
net->pt[net->num_pts].name = pf("%sE_N3", wire_base(wire));
net->num_pts++;
} else {
net->pt[net->num_pts].name = pf("%sE_N3", wire_base(wire));
net->num_pts++;
}
} else if ((wire == W_SS4 || wire == W_SS2 || wire == W_SR1) && num_0to3 == 3) {
// add _N3
net->pt[net->num_pts].start_count = 0;
net->pt[net->num_pts].y = (*cur_y)-1;
net->pt[net->num_pts].x = *cur_x;
if (is_aty(Y_INNER_TOP, model, (*cur_y)-1)) {
net->pt[net->num_pts].name = pf("%sE_N3", wire_base(wire));
net->num_pts++;
} else if (is_aty(Y_ROW_HORIZ_AXSYMM|Y_CHIP_HORIZ_REGS, model, (*cur_y)-1)) {
net->pt[net->num_pts].name = pf("%sE_N3", wire_base(wire));
net->num_pts++;
net->pt[net->num_pts].start_count = 0;
net->pt[net->num_pts].y = (*cur_y)-2;
net->pt[net->num_pts].x = *cur_x;
net->pt[net->num_pts].name = pf("%sE_N3", wire_base(wire));
net->num_pts++;
} else {
net->pt[net->num_pts].name = pf("%sE_N3", wire_base(wire));
net->num_pts++;
}
}
break;
}
dirwire_next_hop(model, wire, bamce, cur_y, cur_x);
} else {
int prior_x_major = model->x_major[*cur_x];
int prior_y_regular = y_to_regular(model, *cur_y);
dirwire_next_hop(model, wire, bamce, cur_y, cur_x);
if (net_includes_routing(model, net)) {
if (prior_x_major != model->x_major[*cur_x])
break;
if (prior_y_regular != y_to_regular(model, *cur_y))
break;
}
}
if (is_atyx(YX_OUTER_TERM, model, *cur_y, *cur_x))
break;
}
RC_RETURN(model);
}
static int run_dirwire(struct fpga_model *model, int start_y, int start_x,
enum wire_type wire, char bamce_start, int num_0to3)
{
struct w_net net;
int cur_y, cur_x, outer_term_hit;
char cur_bamce;
RC_CHECK(model);
net.last_inc = 0;
net.num_pts = 0;
cur_y = start_y;
cur_x = start_x;
cur_bamce = bamce_start;
while (1) {
set_BAMCE_point(model, &net, wire, cur_bamce, num_0to3, &cur_y, &cur_x);
outer_term_hit = is_atyx(YX_OUTER_TERM, model, cur_y, cur_x);
if (cur_bamce == 'E' || outer_term_hit) {
if (net.num_pts < 2) RC_FAIL(model, EINVAL);
add_conn_net(model, ADD_PREF, &net);
net.num_pts = 0;
if (outer_term_hit)
break;
if (is_atx(X_FABRIC_BRAM_ROUTING_COL, model, cur_x)
&& ((wire == W_SS4 && cur_y >= model->y_height-BOT_INNER_ROW-4)
|| ((wire == W_SS2 || wire == W_SE4 || wire == W_SW4) && cur_y >= model->y_height-BOT_INNER_ROW-2)
|| ((wire == W_SL1 || wire == W_SR1 || wire == W_SE2 || wire == W_SW2) && cur_y >= model->y_height-BOT_INNER_ROW-1)))
break;
}
cur_bamce = dirwire_next_bamce(wire, cur_bamce);
}
RC_RETURN(model);
}
static int run_dirwire_0to3(struct fpga_model *model, int start_y, int start_x,
enum wire_type wire, char bamce_start)
{
int i;
RC_CHECK(model);
for (i = 0; i <= 3; i++)
run_dirwire(model, start_y, start_x, wire, bamce_start, i);
RC_RETURN(model);
}
static int run_dirwires(struct fpga_model* model)
{
int y, x, i;
RC_CHECK(model);
//
// A EE4-wire goes through the chip from left to right like this:
//
// E/B A M C E/B A M C E/B
// C E/B A M C E/B A M C
// M C E/B A M C E/B A M
// A M C E/B A M C E/B A
//
// set_BAMCE_point() adds net entries for one such point, run_dirwire()
// runs one wire through the chip, run_dirwires() goes through
// all rows vertically.
//
//
// EE4, EE2, EL1, ER1
// WW4, WW2, WL1, WR1
//
for (y = TOP_OUTER_IO; y <= model->y_height-BOT_OUTER_IO; y++) {
if (is_aty(Y_ROW_HORIZ_AXSYMM|Y_CHIP_HORIZ_REGS, model, y))
continue;
run_dirwire_0to3(model, y, LEFT_INNER_COL, W_EE4, 'E');
run_dirwire_0to3(model, y, LEFT_INNER_COL, W_EE4, 'C');
run_dirwire_0to3(model, y, LEFT_INNER_COL, W_EE4, 'M');
run_dirwire_0to3(model, y, LEFT_INNER_COL, W_EE4, 'A');
run_dirwire_0to3(model, y, LEFT_INNER_COL, W_EE2, 'E');
run_dirwire_0to3(model, y, LEFT_INNER_COL, W_EE2, 'M');
run_dirwire_0to3(model, y, LEFT_INNER_COL, W_EL1, 'E');
run_dirwire_0to3(model, y, LEFT_INNER_COL, W_ER1, 'E');
run_dirwire_0to3(model, y, model->x_width-RIGHT_INNER_O, W_WW4, 'E');
run_dirwire_0to3(model, y, model->x_width-RIGHT_INNER_O, W_WW4, 'C');
run_dirwire_0to3(model, y, model->x_width-RIGHT_INNER_O, W_WW4, 'M');
run_dirwire_0to3(model, y, model->x_width-RIGHT_INNER_O, W_WW4, 'A');
run_dirwire_0to3(model, y, model->x_width-RIGHT_INNER_O, W_WW2, 'E');
run_dirwire_0to3(model, y, model->x_width-RIGHT_INNER_O, W_WW2, 'M');
run_dirwire_0to3(model, y, model->x_width-RIGHT_INNER_O, W_WL1, 'E');
run_dirwire_0to3(model, y, model->x_width-RIGHT_INNER_O, W_WR1, 'E');
}
for (x = LEFT_IO_ROUTING; x <= model->x_width-RIGHT_IO_ROUTING_O; x++) {
if (!is_atx(X_ROUTING_COL, model, x))
continue;
add_conn_bi_pref(model, TOP_INNER_ROW, x, "WW4E_S0",
TOP_FIRST_REGULAR, x, "WW4E_S0");
add_conn_bi_pref(model, TOP_INNER_ROW, x, "EL1E_S0",
TOP_FIRST_REGULAR, x, "EL1E_S0");
add_conn_bi_pref(model, TOP_INNER_ROW, x, "WR1E_S0",
TOP_FIRST_REGULAR, x, "WR1E_S0");
if (!is_atx(X_FABRIC_BRAM_ROUTING_COL, model, x)) {
add_conn_bi_pref(model, model->y_height-BOT_INNER_ROW, x, "WW2E_N3",
model->y_height-BOT_LAST_REGULAR_O, x, "WW2E_N3");
add_conn_bi_pref(model, model->y_height-BOT_INNER_ROW, x, "ER1E_N3",
model->y_height-BOT_LAST_REGULAR_O, x, "ER1E_N3");
add_conn_bi_pref(model, model->y_height-BOT_INNER_ROW, x, "WL1E_N3",
model->y_height-BOT_LAST_REGULAR_O, x, "WL1E_N3");
}
}
//
// NN4, NN2, NL1, NR1
// SS4, SS2, SL1, SR1
//
for (x = LEFT_IO_ROUTING; x <= model->x_width-RIGHT_IO_ROUTING_O; x++) {
if (!is_atx(X_ROUTING_COL, model, x))
continue;
if (is_atx(X_FABRIC_BRAM_ROUTING_COL, model, x)) {
for (i = 0; i <= 3; i++)
run_dirwire_0to3(model, model->y_height-BOT_INNER_ROW-1-i, x, W_NN4, 'B');
run_dirwire_0to3(model, model->y_height-BOT_INNER_ROW-1, x, W_NN2, 'B');
run_dirwire_0to3(model, model->y_height-BOT_INNER_ROW-2, x, W_NN2, 'B');
add_conn_bi_pref(model,
model->y_height-BOT_INNER_ROW-2, x, "NN2E0",
model->y_height-BOT_INNER_ROW-1, x, "NN2E_S0");
run_dirwire_0to3(model, model->y_height-BOT_INNER_ROW-1, x, W_NL1, 'B');
run_dirwire_0to3(model, model->y_height-BOT_INNER_ROW-1, x, W_NR1, 'B');
} else {
run_dirwire_0to3(model, model->y_height-BOT_INNER_ROW, x, W_NN4, 'E');
run_dirwire_0to3(model, model->y_height-BOT_INNER_ROW, x, W_NN4, 'C');
run_dirwire_0to3(model, model->y_height-BOT_INNER_ROW, x, W_NN4, 'M');
run_dirwire_0to3(model, model->y_height-BOT_INNER_ROW, x, W_NN4, 'A');
run_dirwire_0to3(model, model->y_height-BOT_INNER_ROW, x, W_NN2, 'E');
run_dirwire_0to3(model, model->y_height-BOT_INNER_ROW, x, W_NN2, 'M');
run_dirwire_0to3(model, model->y_height-BOT_INNER_ROW, x, W_NL1, 'E');
run_dirwire_0to3(model, model->y_height-BOT_INNER_ROW, x, W_NR1, 'E');
}
run_dirwire_0to3(model, TOP_INNER_ROW, x, W_SS4, 'E');
run_dirwire_0to3(model, TOP_INNER_ROW, x, W_SS4, 'M');
run_dirwire_0to3(model, TOP_INNER_ROW, x, W_SS4, 'C');
run_dirwire_0to3(model, TOP_INNER_ROW, x, W_SS4, 'A');
run_dirwire_0to3(model, TOP_INNER_ROW, x, W_SS2, 'E');
run_dirwire_0to3(model, TOP_INNER_ROW, x, W_SS2, 'M');
run_dirwire_0to3(model, TOP_INNER_ROW, x, W_SL1, 'E');
run_dirwire_0to3(model, TOP_INNER_ROW, x, W_SR1, 'E');
}
for (x = LEFT_IO_ROUTING; x <= model->x_width-RIGHT_IO_ROUTING_O; x++) {
if (!is_atx(X_ROUTING_COL, model, x))
continue;
add_conn_bi_pref(model, TOP_INNER_ROW, x, "NN2E_S0",
TOP_FIRST_REGULAR, x, "NN2E_S0");
add_conn_bi_pref(model, TOP_INNER_ROW, x, "NL1E_S0",
TOP_FIRST_REGULAR, x, "NL1E_S0");
if (!is_atx(X_FABRIC_BRAM_ROUTING_COL, model, x)) {
add_conn_bi_pref(model, model->y_height-BOT_INNER_ROW, x, "SS4E_N3",
model->y_height-BOT_LAST_REGULAR_O, x, "SS4E_N3");
add_conn_bi_pref(model, model->y_height-BOT_INNER_ROW, x, "SS2E_N3",
model->y_height-BOT_LAST_REGULAR_O, x, "SS2E_N3");
add_conn_bi_pref(model, model->y_height-BOT_INNER_ROW, x, "SR1E_N3",
model->y_height-BOT_LAST_REGULAR_O, x, "SR1E_N3");
}
}
//
// SE4, SE2, SW4, SW2
//
for (x = LEFT_IO_ROUTING; x <= model->x_width-RIGHT_IO_ROUTING_O; x++) {
if (!is_atx(X_ROUTING_COL, model, x))
continue;
run_dirwire_0to3(model, TOP_INNER_ROW, x, W_SE4, 'M');
run_dirwire_0to3(model, TOP_INNER_ROW, x, W_SE4, 'A');
run_dirwire_0to3(model, TOP_INNER_ROW, x, W_SE2, 'M');
run_dirwire_0to3(model, TOP_INNER_ROW, x, W_SW4, 'M');
run_dirwire_0to3(model, TOP_INNER_ROW, x, W_SW4, 'A');
run_dirwire_0to3(model, TOP_INNER_ROW, x, W_SW2, 'M');
if (!is_atx(X_FABRIC_BRAM_ROUTING_COL, model, x)) {
add_conn_bi_pref(model, model->y_height-BOT_INNER_ROW, x, "SW4E_N3",
model->y_height-BOT_LAST_REGULAR_O, x, "SW4E_N3");
add_conn_bi_pref(model, model->y_height-BOT_INNER_ROW, x, "SW2E_N3",
model->y_height-BOT_LAST_REGULAR_O, x, "SW2E_N3");
}
}
for (y = TOP_OUTER_IO; y <= model->y_height-BOT_OUTER_IO; y++) {
if (is_aty(Y_ROW_HORIZ_AXSYMM|Y_CHIP_HORIZ_REGS, model, y))
continue;
run_dirwire_0to3(model, y, LEFT_INNER_COL, W_SE4, 'E');
run_dirwire_0to3(model, y, LEFT_INNER_COL, W_SE4, 'C');
run_dirwire_0to3(model, y, LEFT_INNER_COL, W_SE2, 'E');
run_dirwire_0to3(model, y, model->x_width-RIGHT_INNER_O, W_SW4, 'E');
run_dirwire_0to3(model, y, model->x_width-RIGHT_INNER_O, W_SW4, 'C');
run_dirwire_0to3(model, y, model->x_width-RIGHT_INNER_O, W_SW2, 'E');
}
//
// NE4, NE2
//
for (x = LEFT_IO_ROUTING; x <= model->x_width-RIGHT_IO_ROUTING_O; x++) {
if (!is_atx(X_ROUTING_COL, model, x))
continue;
if (is_atx(X_FABRIC_BRAM_ROUTING_COL, model, x)) {
// NE2B is one major right, NE4B is two majors right
int plus_one_major, plus_two_majors;
plus_one_major = x+1;
while (plus_one_major != -1
&& !is_atx(X_ROUTING_COL, model, plus_one_major)) {
if (++plus_one_major >= model->x_width)
plus_one_major = -1;
}
if (plus_one_major == -1)
plus_two_majors = -1;
else {
plus_two_majors = plus_one_major + 1;
while (plus_two_majors != -1
&& !is_atx(X_ROUTING_COL, model, plus_two_majors)) {
if (++plus_two_majors >= model->x_width)
plus_two_majors = -1;
}
}
if (plus_two_majors != -1) {
run_dirwire_0to3(model, model->y_height-BOT_INNER_ROW-1, plus_two_majors, W_NE4, 'B');
run_dirwire_0to3(model, model->y_height-BOT_INNER_ROW-2, plus_two_majors, W_NE4, 'B');
}
if (plus_one_major != -1) {
struct w_net net;
run_dirwire_0to3(model, model->y_height-BOT_INNER_ROW-1, plus_one_major, W_NE2, 'B');
net.last_inc = 2;
net.num_pts = 0;
for (i = x; i <= plus_one_major; i++) {
net.pt[net.num_pts].start_count = 1;
net.pt[net.num_pts].y = model->y_height-BOT_INNER_ROW-1;
net.pt[net.num_pts].x = i;
net.pt[net.num_pts].name = (i == plus_one_major) ? "NE2E%i" : "NE2M%i";
net.num_pts++;
}
add_conn_net(model, ADD_PREF, &net);
add_conn_bi_pref(model,
model->y_height-BOT_INNER_ROW-1, plus_one_major, "NE2E0",
model->y_height-BOT_INNER_ROW, plus_one_major, "NE2E0");
}
} else {
run_dirwire_0to3(model, model->y_height-BOT_INNER_ROW, x, W_NE4, 'M');
run_dirwire_0to3(model, model->y_height-BOT_INNER_ROW, x, W_NE4, 'A');
run_dirwire_0to3(model, model->y_height-BOT_INNER_ROW, x, W_NE2, 'M');
}
add_conn_bi_pref(model, TOP_INNER_ROW, x, "NE2E_S0",
TOP_FIRST_REGULAR, x, "NE2E_S0");
}
for (y = TOP_OUTER_IO; y <= model->y_height-BOT_OUTER_IO; y++) {
if (is_aty(Y_ROW_HORIZ_AXSYMM|Y_CHIP_HORIZ_REGS, model, y))
continue;
run_dirwire_0to3(model, y, LEFT_INNER_COL, W_NE4, 'E');
run_dirwire_0to3(model, y, LEFT_INNER_COL, W_NE4, 'C');
run_dirwire_0to3(model, y, LEFT_INNER_COL, W_NE2, 'E');
}
//
// NW4, NW2
//
for (x = LEFT_IO_ROUTING; x <= model->x_width-RIGHT_IO_ROUTING_O; x++) {
if (!is_atx(X_ROUTING_COL, model, x))
continue;
if (is_atx(X_FABRIC_BRAM_ROUTING_COL, model, x)) {
// NW2B is one major left, NW4B is two majors left
int minus_one_major, minus_two_majors;
minus_one_major = x-1;
while (minus_one_major != -1
&& !is_atx(X_ROUTING_COL, model, minus_one_major)) {
if (--minus_one_major < LEFT_IO_ROUTING)
minus_one_major = -1;
}
if (minus_one_major == -1)
minus_two_majors = -1;
else {
minus_two_majors = minus_one_major - 1;
while (minus_two_majors != -1
&& !is_atx(X_ROUTING_COL, model, minus_two_majors)) {
if (--minus_two_majors < LEFT_IO_ROUTING)
minus_two_majors = -1;
}
}
if (minus_two_majors != -1) {
run_dirwire_0to3(model, model->y_height-BOT_INNER_ROW-1, minus_two_majors, W_NW4, 'B');
run_dirwire_0to3(model, model->y_height-BOT_INNER_ROW-2, minus_two_majors, W_NW4, 'B');
add_conn_bi_pref(model,
model->y_height-BOT_INNER_ROW-2, minus_two_majors, "NW4E0",
model->y_height-BOT_INNER_ROW-1, minus_two_majors, "NW4E_S0");
add_conn_bi_pref(model,
model->y_height-BOT_INNER_ROW-1, minus_two_majors, "NW4E0",
model->y_height-BOT_INNER_ROW, minus_two_majors, "NW4E0");
}
if (minus_one_major != -1) {
run_dirwire_0to3(model, model->y_height-BOT_INNER_ROW-1, minus_one_major, W_NW2, 'B');
add_conn_bi_pref(model,
model->y_height-BOT_INNER_ROW-1, minus_one_major, "NW2E0",
model->y_height-BOT_INNER_ROW, minus_one_major, "NW2E0");
}
} else {
run_dirwire_0to3(model, model->y_height-BOT_INNER_ROW, x, W_NW4, 'M');
run_dirwire_0to3(model, model->y_height-BOT_INNER_ROW, x, W_NW4, 'A');
run_dirwire_0to3(model, model->y_height-BOT_INNER_ROW, x, W_NW2, 'M');
}
add_conn_bi_pref(model, TOP_INNER_ROW, x, "NW4E_S0",
TOP_FIRST_REGULAR, x, "NW4E_S0");
add_conn_bi_pref(model, TOP_INNER_ROW, x, "NW2E_S0",
TOP_FIRST_REGULAR, x, "NW2E_S0");
}
for (y = TOP_OUTER_IO; y <= model->y_height-BOT_OUTER_IO; y++) {
if (is_aty(Y_ROW_HORIZ_AXSYMM|Y_CHIP_HORIZ_REGS, model, y))
continue;
run_dirwire_0to3(model, y, model->x_width-RIGHT_INNER_O, W_NW4, 'E');
run_dirwire_0to3(model, y, model->x_width-RIGHT_INNER_O, W_NW4, 'C');
run_dirwire_0to3(model, y, model->x_width-RIGHT_INNER_O, W_NW2, 'E');
}
RC_RETURN(model);
}
fpgatools-201212/libs/model_devices.c 0000664 0000000 0000000 00000044520 12065743015 0017510 0 ustar 00root root 0000000 0000000 //
// Author: Wolfgang Spraul
//
// This is free and unencumbered software released into the public domain.
// For details see the UNLICENSE file at the root of the source tree.
//
#include
#include "model.h"
#include "control.h"
static int add_dev(struct fpga_model* model,
int y, int x, int type, int subtype);
static int init_iob(struct fpga_model* model, int y, int x, int idx);
static int init_logic(struct fpga_model* model, int y, int x, int idx);
int init_devices(struct fpga_model* model)
{
int x, y, i, j, rc;
RC_CHECK(model);
// DCM, PLL
for (i = 0; i < model->die->num_rows; i++) {
y = TOP_IO_TILES + HALF_ROW-1 + i*ROW_SIZE;
if (y > model->center_y) y++; // central regs
x = model->center_x-CENTER_CMTPLL_O;
if (i%2) {
if ((rc = add_dev(model, y, x, DEV_DCM, 0))) goto fail;
if ((rc = add_dev(model, y, x, DEV_DCM, 0))) goto fail;
} else
if ((rc = add_dev(model, y, x, DEV_PLL, 0))) goto fail;
}
// BSCAN
y = TOP_IO_TILES;
x = model->x_width-RIGHT_IO_DEVS_O;
if ((rc = add_dev(model, y, x, DEV_BSCAN, 0))) goto fail;
if ((rc = add_dev(model, y, x, DEV_BSCAN, 0))) goto fail;
// BSCAN, OCT_CALIBRATE
y = TOP_IO_TILES+1;
x = model->x_width-RIGHT_IO_DEVS_O;
if ((rc = add_dev(model, y, x, DEV_BSCAN, 0))) goto fail;
if ((rc = add_dev(model, y, x, DEV_BSCAN, 0))) goto fail;
if ((rc = add_dev(model, y, x, DEV_OCT_CALIBRATE, 0))) goto fail;
// ICAP, SPI_ACCESS, OCT_CALIBRATE
y = model->y_height-BOT_IO_TILES-1;
x = model->x_width-RIGHT_IO_DEVS_O;
if ((rc = add_dev(model, y, x, DEV_ICAP, 0))) goto fail;
if ((rc = add_dev(model, y, x, DEV_SPI_ACCESS, 0))) goto fail;
if ((rc = add_dev(model, y, x, DEV_OCT_CALIBRATE, 0))) goto fail;
// STARTUP, POST_CRC_INTERNAL, SLAVE_SPI, SUSPEND_SYNC
y = model->y_height-BOT_IO_TILES-2;
x = model->x_width-RIGHT_IO_DEVS_O;
if ((rc = add_dev(model, y, x, DEV_STARTUP, 0))) goto fail;
if ((rc = add_dev(model, y, x, DEV_POST_CRC_INTERNAL, 0))) goto fail;
if ((rc = add_dev(model, y, x, DEV_SLAVE_SPI, 0))) goto fail;
if ((rc = add_dev(model, y, x, DEV_SUSPEND_SYNC, 0))) goto fail;
// MCB
if ((rc = add_dev(model, model->die->mcb_ypos, LEFT_MCB_COL, DEV_MCB, 0))) goto fail;
if ((rc = add_dev(model, model->die->mcb_ypos, model->x_width-RIGHT_MCB_O, DEV_MCB, 0))) goto fail;
// OCT_CALIBRATE
x = LEFT_IO_DEVS;
if ((rc = add_dev(model, TOP_IO_TILES, x, DEV_OCT_CALIBRATE, 0)))
FAIL(rc);
if ((rc = add_dev(model, TOP_IO_TILES, x, DEV_OCT_CALIBRATE, 0)))
FAIL(rc);
if ((rc = add_dev(model, model->y_height-BOT_IO_TILES-1, x,
DEV_OCT_CALIBRATE, 0))) FAIL(rc);
if ((rc = add_dev(model, model->y_height-BOT_IO_TILES-1, x,
DEV_OCT_CALIBRATE, 0))) FAIL(rc);
// DNA, PMV
x = LEFT_IO_DEVS;
y = TOP_IO_TILES;
if ((rc = add_dev(model, y, x, DEV_DNA, 0))) FAIL(rc);
if ((rc = add_dev(model, y, x, DEV_PMV, 0))) FAIL(rc);
// PCILOGIC_SE
if ((rc = add_dev(model, model->center_y, LEFT_IO_ROUTING,
DEV_PCILOGIC_SE, 0))) FAIL(rc);
if ((rc = add_dev(model, model->center_y, model->x_width
- RIGHT_IO_DEVS_O, DEV_PCILOGIC_SE, 0))) FAIL(rc);
// BUFGMUX
y = model->center_y;
x = model->center_x;
for (i = 0; i < 16; i++)
if ((rc = add_dev(model, y, x, DEV_BUFGMUX, 0))) goto fail;
// BUFIO, BUFIO_FB, BUFPLL, BUFPLL_MCB
y = TOP_OUTER_ROW;
x = model->center_x-CENTER_CMTPLL_O;
if ((rc = add_dev(model, y, x, DEV_BUFPLL, 0))) goto fail;
if ((rc = add_dev(model, y, x, DEV_BUFPLL, 0))) goto fail;
if ((rc = add_dev(model, y, x, DEV_BUFPLL_MCB, 0))) goto fail;
for (j = 0; j < 8; j++) {
if ((rc = add_dev(model, y, x, DEV_BUFIO, 0))) goto fail;
if ((rc = add_dev(model, y, x, DEV_BUFIO_FB, 0))) goto fail;
}
y = model->center_y;
x = LEFT_OUTER_COL;
if ((rc = add_dev(model, y, x, DEV_BUFPLL, 0))) goto fail;
if ((rc = add_dev(model, y, x, DEV_BUFPLL, 0))) goto fail;
if ((rc = add_dev(model, y, x, DEV_BUFPLL_MCB, 0))) goto fail;
for (j = 0; j < 8; j++) {
if ((rc = add_dev(model, y, x, DEV_BUFIO, 0))) goto fail;
if ((rc = add_dev(model, y, x, DEV_BUFIO_FB, 0))) goto fail;
}
y = model->center_y;
x = model->x_width - RIGHT_OUTER_O;
if ((rc = add_dev(model, y, x, DEV_BUFPLL, 0))) goto fail;
if ((rc = add_dev(model, y, x, DEV_BUFPLL, 0))) goto fail;
if ((rc = add_dev(model, y, x, DEV_BUFPLL_MCB, 0))) goto fail;
for (j = 0; j < 8; j++) {
if ((rc = add_dev(model, y, x, DEV_BUFIO, 0))) goto fail;
if ((rc = add_dev(model, y, x, DEV_BUFIO_FB, 0))) goto fail;
}
y = model->y_height - BOT_OUTER_ROW;
x = model->center_x-CENTER_CMTPLL_O;
if ((rc = add_dev(model, y, x, DEV_BUFPLL, 0))) goto fail;
if ((rc = add_dev(model, y, x, DEV_BUFPLL, 0))) goto fail;
if ((rc = add_dev(model, y, x, DEV_BUFPLL_MCB, 0))) goto fail;
for (j = 0; j < 8; j++) {
if ((rc = add_dev(model, y, x, DEV_BUFIO, 0))) goto fail;
if ((rc = add_dev(model, y, x, DEV_BUFIO_FB, 0))) goto fail;
}
// BUFH
for (i = 0; i < model->die->num_rows; i++) {
y = TOP_IO_TILES + HALF_ROW + i*ROW_SIZE;
if (y > model->center_y) y++; // central regs
x = model->center_x;
for (j = 0; j < 32; j++)
if ((rc = add_dev(model, y, x, DEV_BUFH, 0))) goto fail;
}
// BRAM
for (x = 0; x < model->x_width; x++) {
if (!is_atx(X_FABRIC_BRAM_COL, model, x))
continue;
for (y = TOP_IO_TILES; y < model->y_height-BOT_IO_TILES; y++) {
if (!(YX_TILE(model, y, x)->flags & TF_BRAM_DEV))
continue;
if ((rc = add_dev(model, y, x, DEV_BRAM16, 0)))
goto fail;
if ((rc = add_dev(model, y, x, DEV_BRAM8, 0)))
goto fail;
if ((rc = add_dev(model, y, x, DEV_BRAM8, 0)))
goto fail;
}
}
// MACC
for (x = 0; x < model->x_width; x++) {
if (!is_atx(X_FABRIC_MACC_COL, model, x))
continue;
for (y = TOP_IO_TILES; y < model->y_height-BOT_IO_TILES; y++) {
if (!(YX_TILE(model, y, x)->flags & TF_MACC_DEV))
continue;
if ((rc = add_dev(model, y, x, DEV_MACC, 0))) goto fail;
}
}
// ILOGIC/OLOGIC/IODELAY
for (x = LEFT_SIDE_WIDTH; x < model->x_width - RIGHT_SIDE_WIDTH; x++) {
if (!is_atx(X_FABRIC_LOGIC_COL|X_CENTER_LOGIC_COL, model, x)
|| is_atx(X_ROUTING_NO_IO, model, x-1))
continue;
for (i = 0; i <= 1; i++) {
y = TOP_IO_TILES+i;
for (j = 0; j <= 1; j++) {
if ((rc = add_dev(model, y, x, DEV_ILOGIC, 0)))
goto fail;
if ((rc = add_dev(model, y, x, DEV_OLOGIC, 0)))
goto fail;
if ((rc = add_dev(model, y, x, DEV_IODELAY, 0)))
goto fail;
}
y = model->y_height-BOT_IO_TILES-i-1;
for (j = 0; j <= 1; j++) {
if ((rc = add_dev(model, y, x, DEV_ILOGIC, 0)))
goto fail;
if ((rc = add_dev(model, y, x, DEV_OLOGIC, 0)))
goto fail;
if ((rc = add_dev(model, y, x, DEV_IODELAY, 0)))
goto fail;
}
}
}
for (y = TOP_IO_TILES; y < model->y_height - BOT_IO_TILES; y++) {
if (is_aty(Y_LEFT_WIRED, model, y)) {
x = LEFT_IO_DEVS;
for (j = 0; j <= 1; j++) {
if ((rc = add_dev(model, y, x, DEV_ILOGIC, 0)))
goto fail;
if ((rc = add_dev(model, y, x, DEV_OLOGIC, 0)))
goto fail;
if ((rc = add_dev(model, y, x, DEV_IODELAY, 0)))
goto fail;
}
}
if (is_aty(Y_RIGHT_WIRED, model, y)) {
x = model->x_width-RIGHT_IO_DEVS_O;
for (j = 0; j <= 1; j++) {
if ((rc = add_dev(model, y, x, DEV_ILOGIC, 0)))
goto fail;
if ((rc = add_dev(model, y, x, DEV_OLOGIC, 0)))
goto fail;
if ((rc = add_dev(model, y, x, DEV_IODELAY, 0)))
goto fail;
}
}
}
// IOB
for (x = 0; x < model->x_width; x++) {
// Note that the order of sub-types IOBM and IOBS must match
// the order in the control.c sitename arrays.
if (is_atx(X_OUTER_LEFT, model, x)) {
for (y = TOP_IO_TILES; y < model->y_height - BOT_IO_TILES; y++) {
if (!is_aty(Y_LEFT_WIRED, model, y))
continue;
if ((rc = add_dev(model, y, x, DEV_IOB, IOBM))) goto fail;
if ((rc = add_dev(model, y, x, DEV_IOB, IOBS))) goto fail;
}
}
if (is_atx(X_OUTER_RIGHT, model, x)) {
for (y = TOP_IO_TILES; y < model->y_height - BOT_IO_TILES; y++) {
if (!is_aty(Y_RIGHT_WIRED, model, y))
continue;
if ((rc = add_dev(model, y, x, DEV_IOB, IOBM))) goto fail;
if ((rc = add_dev(model, y, x, DEV_IOB, IOBS))) goto fail;
}
}
if (is_atx(X_FABRIC_LOGIC_ROUTING_COL|X_CENTER_ROUTING_COL, model, x)
&& !is_atx(X_ROUTING_NO_IO, model, x)) {
y = TOP_OUTER_ROW;
if ((rc = add_dev(model, y, x, DEV_IOB, IOBM))) goto fail;
if ((rc = add_dev(model, y, x, DEV_IOB, IOBS))) goto fail;
if ((rc = add_dev(model, y, x, DEV_IOB, IOBM))) goto fail;
if ((rc = add_dev(model, y, x, DEV_IOB, IOBS))) goto fail;
y = model->y_height-BOT_OUTER_ROW;
if ((rc = add_dev(model, y, x, DEV_IOB, IOBM))) goto fail;
if ((rc = add_dev(model, y, x, DEV_IOB, IOBS))) goto fail;
if ((rc = add_dev(model, y, x, DEV_IOB, IOBS))) goto fail;
if ((rc = add_dev(model, y, x, DEV_IOB, IOBM))) goto fail;
}
}
// TIEOFF
y = model->center_y;
x = LEFT_OUTER_COL;
if ((rc = add_dev(model, y, x, DEV_TIEOFF, 0))) goto fail;
y = model->center_y;
x = model->x_width-RIGHT_OUTER_O;
if ((rc = add_dev(model, y, x, DEV_TIEOFF, 0))) goto fail;
y = TOP_OUTER_ROW;
x = model->center_x-1;
if ((rc = add_dev(model, y, x, DEV_TIEOFF, 0))) goto fail;
y = model->y_height-BOT_OUTER_ROW;
x = model->center_x-CENTER_CMTPLL_O;
if ((rc = add_dev(model, y, x, DEV_TIEOFF, 0))) goto fail;
for (x = 0; x < model->x_width; x++) {
if (is_atx(X_LEFT_IO_DEVS_COL, model, x)) {
for (y = TOP_IO_TILES; y < model->y_height - BOT_IO_TILES; y++) {
if (!is_aty(Y_LEFT_WIRED, model, y))
continue;
if ((rc = add_dev(model, y, x, DEV_TIEOFF, 0))) goto fail;
}
}
if (is_atx(X_RIGHT_IO_DEVS_COL, model, x)) {
for (y = TOP_IO_TILES; y < model->y_height - BOT_IO_TILES; y++) {
if (!is_aty(Y_RIGHT_WIRED, model, y))
continue;
if ((rc = add_dev(model, y, x, DEV_TIEOFF, 0))) goto fail;
}
}
if (is_atx(X_CENTER_CMTPLL_COL, model, x)) {
for (y = TOP_IO_TILES; y < model->y_height - BOT_IO_TILES; y++) {
if (!(YX_TILE(model, y, x)->flags & TF_PLL_DEV))
continue;
if ((rc = add_dev(model, y, x, DEV_TIEOFF, 0))) goto fail;
}
}
if (is_atx(X_ROUTING_COL, model, x)) {
for (y = TOP_IO_TILES; y < model->y_height - BOT_IO_TILES; y++) {
if (is_aty(Y_ROW_HORIZ_AXSYMM|Y_CHIP_HORIZ_REGS,
model, y))
continue;
if ((rc = add_dev(model, y, x, DEV_TIEOFF, 0))) goto fail;
}
}
if (is_atx(X_FABRIC_LOGIC_COL|X_CENTER_LOGIC_COL, model, x)
&& !is_atx(X_ROUTING_NO_IO, model, x-1)) {
for (i = 0; i <= 1; i++) {
y = TOP_IO_TILES+i;
if ((rc = add_dev(model, y, x, DEV_TIEOFF, 0))) goto fail;
y = model->y_height-BOT_IO_TILES-i-1;
if ((rc = add_dev(model, y, x, DEV_TIEOFF, 0))) goto fail;
}
}
}
// LOGIC
for (x = 0; x < model->x_width; x++) {
if (!is_atx(X_FABRIC_LOGIC_COL|X_CENTER_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 (DEV_LOG_M_OR_L),
// X is at index 1 (DEV_LOG_X).
if (YX_TILE(model, y, x)->flags & TF_LOGIC_XM_DEV) {
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_L))) goto fail;
if ((rc = add_dev(model, y, x, DEV_LOGIC, LOGIC_X))) goto fail;
}
}
}
return 0;
fail:
return rc;
}
void free_devices(struct fpga_model* model)
{
struct fpga_tile* tile;
int x, y, i;
// leave model->rc untouched
for (x = 0; x < model->x_width; x++) {
for (y = 0; y < model->y_height; y++) {
tile = YX_TILE(model, y, x);
if (!tile->num_devs)
continue;
if (!tile->devs) {
HERE();
continue;
}
for (i = 0; i < tile->num_devs; i++) {
fdev_delete(model, y, x, tile->devs[i].type,
fdev_typeidx(model, y, x, i));
}
free(tile->devs);
tile->devs = 0;
tile->num_devs = 0;
}
}
}
#define DEV_INCREMENT 4
static int add_dev(struct fpga_model* model,
int y, int x, int type, int subtype)
{
struct fpga_tile* tile;
int new_dev_i;
int rc;
RC_CHECK(model);
tile = YX_TILE(model, y, x);
if (!(tile->num_devs % DEV_INCREMENT)) {
void* new_ptr = realloc(tile->devs,
(tile->num_devs+DEV_INCREMENT)*sizeof(*tile->devs));
EXIT(!new_ptr);
memset(new_ptr + tile->num_devs * sizeof(*tile->devs),
0, DEV_INCREMENT*sizeof(*tile->devs));
tile->devs = new_ptr;
}
new_dev_i = tile->num_devs;
tile->num_devs++;
// init new device
tile->devs[new_dev_i].type = type;
tile->devs[new_dev_i].subtype = subtype;
if (type == DEV_IOB) {
rc = init_iob(model, y, x, new_dev_i);
if (rc) FAIL(rc);
} else if (type == DEV_LOGIC) {
rc = init_logic(model, y, x, new_dev_i);
if (rc) FAIL(rc);
}
return 0;
fail:
return rc;
}
static int init_iob(struct fpga_model* model, int y, int x, int idx)
{
struct fpga_tile* tile;
const char* prefix;
int type_idx, rc;
char tmp_str[128];
RC_CHECK(model);
tile = YX_TILE(model, y, x);
type_idx = fdev_typeidx(model, y, x, idx);
if (!y)
prefix = "TIOB";
else if (y == model->y_height - BOT_OUTER_ROW)
prefix = "BIOB";
else if (x == 0)
prefix = "LIOB";
else if (x == model->x_width - RIGHT_OUTER_O)
prefix = "RIOB";
else
FAIL(EINVAL);
tile->devs[idx].pinw = calloc((IOB_LAST_OUTPUT_PINW+1)
*sizeof(tile->devs[idx].pinw[0]), /*elsize*/ 1);
if (!tile->devs[idx].pinw) FAIL(ENOMEM);
tile->devs[idx].num_pinw_total = IOB_LAST_OUTPUT_PINW+1;
tile->devs[idx].num_pinw_in = IOB_LAST_INPUT_PINW+1;
snprintf(tmp_str, sizeof(tmp_str), "%s_O%i_PINW", prefix, type_idx);
rc = add_connpt_name(model, y, x, tmp_str, /*dup_warn*/ 1,
&tile->devs[idx].pinw[IOB_IN_O], 0);
if (rc) FAIL(rc);
snprintf(tmp_str, sizeof(tmp_str), "%s_T%i_PINW", prefix, type_idx);
rc = add_connpt_name(model, y, x, tmp_str, /*dup_warn*/ 1,
&tile->devs[idx].pinw[IOB_IN_T], 0);
if (rc) FAIL(rc);
snprintf(tmp_str, sizeof(tmp_str), "%s_DIFFI_IN%i", prefix, type_idx);
rc = add_connpt_name(model, y, x, tmp_str, /*dup_warn*/ 1,
&tile->devs[idx].pinw[IOB_IN_DIFFI_IN], 0);
if (rc) FAIL(rc);
snprintf(tmp_str, sizeof(tmp_str), "%s_DIFFO_IN%i", prefix, type_idx);
rc = add_connpt_name(model, y, x, tmp_str, /*dup_warn*/ 1,
&tile->devs[idx].pinw[IOB_IN_DIFFO_IN], 0);
if (rc) FAIL(rc);
snprintf(tmp_str, sizeof(tmp_str), "%s_IBUF%i_PINW", prefix, type_idx);
rc = add_connpt_name(model, y, x, tmp_str, /*dup_warn*/ 1,
&tile->devs[idx].pinw[IOB_OUT_I], 0);
if (rc) FAIL(rc);
snprintf(tmp_str, sizeof(tmp_str), "%s_PADOUT%i", prefix, type_idx);
rc = add_connpt_name(model, y, x, tmp_str, /*dup_warn*/ 1,
&tile->devs[idx].pinw[IOB_OUT_PADOUT], 0);
if (rc) FAIL(rc);
snprintf(tmp_str, sizeof(tmp_str), "%s_DIFFO_OUT%i", prefix, type_idx);
rc = add_connpt_name(model, y, x, tmp_str, /*dup_warn*/ 1,
&tile->devs[idx].pinw[IOB_OUT_DIFFO_OUT], 0);
if (rc) FAIL(rc);
if (!x && y == model->center_y - CENTER_TOP_IOB_O && type_idx == 1)
strcpy(tmp_str, "LIOB_TOP_PCI_RDY0");
else if (!x && y == model->center_y + CENTER_BOT_IOB_O && type_idx == 0)
strcpy(tmp_str, "LIOB_BOT_PCI_RDY0");
else if (x == model->x_width-RIGHT_OUTER_O && y == model->center_y - CENTER_TOP_IOB_O && type_idx == 0)
strcpy(tmp_str, "RIOB_BOT_PCI_RDY0");
else if (x == model->x_width-RIGHT_OUTER_O && y == model->center_y + CENTER_BOT_IOB_O && type_idx == 1)
strcpy(tmp_str, "RIOB_TOP_PCI_RDY1");
else {
snprintf(tmp_str, sizeof(tmp_str),
"%s_PCI_RDY%i", prefix, type_idx);
}
rc = add_connpt_name(model, y, x, tmp_str, /*dup_warn*/ 1,
&tile->devs[idx].pinw[IOB_OUT_PCI_RDY], 0);
if (rc) FAIL(rc);
return 0;
fail:
return rc;
}
static int init_logic(struct fpga_model* model, int y, int x, int idx)
{
struct fpga_tile* tile;
const char* pre;
int i, j, rc;
RC_CHECK(model);
tile = YX_TILE(model, y, x);
if (tile->devs[idx].subtype == LOGIC_M)
pre = "M_";
else if (tile->devs[idx].subtype == LOGIC_L)
pre = "L_";
else if (tile->devs[idx].subtype == LOGIC_X) {
pre = is_atx(X_FABRIC_LOGIC_XL_COL|X_CENTER_LOGIC_COL, model, x)
? "XX_" : "X_";
} else FAIL(EINVAL);
tile->devs[idx].pinw = calloc((LO_LAST+1)
*sizeof(tile->devs[idx].pinw[0]), /*elsize*/ 1);
if (!tile->devs[idx].pinw) FAIL(ENOMEM);
tile->devs[idx].num_pinw_total = LO_LAST+1;
tile->devs[idx].num_pinw_in = LI_LAST+1;
for (i = 0; i < 4; i++) { // 'A' to 'D'
for (j = 0; j < 6; j++) {
rc = add_connpt_name(model, y, x, pf("%s%c%i", pre, 'A'+i, j+1),
/*dup_warn*/ 1,
&tile->devs[idx].pinw[LI_A1+i*6+j], 0);
if (rc) FAIL(rc);
}
rc = add_connpt_name(model, y, x, pf("%s%cX", pre, 'A'+i),
/*dup_warn*/ 1,
&tile->devs[idx].pinw[LI_AX+i], 0);
if (rc) FAIL(rc);
if (tile->devs[idx].subtype == LOGIC_M) {
rc = add_connpt_name(model, y, x, pf("%s%cI", pre, 'A'+i),
/*dup_warn*/ 1,
&tile->devs[idx].pinw[LI_AI+i], 0);
if (rc) FAIL(rc);
} else
tile->devs[idx].pinw[LI_AI+i] = STRIDX_NO_ENTRY;
rc = add_connpt_name(model, y, x, pf("%s%c", pre, 'A'+i),
/*dup_warn*/ 1,
&tile->devs[idx].pinw[LO_A+i], 0);
if (rc) FAIL(rc);
rc = add_connpt_name(model, y, x, pf("%s%cMUX", pre, 'A'+i),
/*dup_warn*/ 1,
&tile->devs[idx].pinw[LO_AMUX+i], 0);
if (rc) FAIL(rc);
rc = add_connpt_name(model, y, x, pf("%s%cQ", pre, 'A'+i),
/*dup_warn*/ 1,
&tile->devs[idx].pinw[LO_AQ+i], 0);
if (rc) FAIL(rc);
}
rc = add_connpt_name(model, y, x, pf("%sCLK", pre),
/*dup_warn*/ 1,
&tile->devs[idx].pinw[LI_CLK], 0);
if (rc) FAIL(rc);
rc = add_connpt_name(model, y, x, pf("%sCE", pre),
/*dup_warn*/ 1,
&tile->devs[idx].pinw[LI_CE], 0);
if (rc) FAIL(rc);
rc = add_connpt_name(model, y, x, pf("%sSR", pre),
/*dup_warn*/ 1,
&tile->devs[idx].pinw[LI_SR], 0);
if (rc) FAIL(rc);
if (tile->devs[idx].subtype == LOGIC_M) {
rc = add_connpt_name(model, y, x, pf("%sWE", pre),
/*dup_warn*/ 1,
&tile->devs[idx].pinw[LI_WE], 0);
if (rc) FAIL(rc);
} else
tile->devs[idx].pinw[LI_WE] = STRIDX_NO_ENTRY;
if (tile->devs[idx].subtype != LOGIC_X) {
// Wire connections will go to some CIN later
// (and must not warn about duplicates), but we
// have to add the connection point here so
// that pinw[LI_CIN] is initialized.
rc = add_connpt_name(model, y, x, pf("%sCIN", pre),
/*dup_warn*/ 1,
&tile->devs[idx].pinw[LI_CIN], 0);
if (rc) FAIL(rc);
} else
tile->devs[idx].pinw[LI_CIN] = STRIDX_NO_ENTRY;
if (tile->devs[idx].subtype == LOGIC_M) {
rc = add_connpt_name(model, y, x, "M_COUT",
/*dup_warn*/ 1,
&tile->devs[idx].pinw[LO_COUT], 0);
if (rc) FAIL(rc);
} else if (tile->devs[idx].subtype == LOGIC_L) {
rc = add_connpt_name(model, y, x, "XL_COUT",
/*dup_warn*/ 1,
&tile->devs[idx].pinw[LO_COUT], 0);
if (rc) FAIL(rc);
} else
tile->devs[idx].pinw[LO_COUT] = STRIDX_NO_ENTRY;
return 0;
fail:
return rc;
}
fpgatools-201212/libs/model_helper.c 0000664 0000000 0000000 00000247472 12065743015 0017360 0 ustar 00root root 0000000 0000000 //
// Author: Wolfgang Spraul
//
// This is free and unencumbered software released into the public domain.
// For details see the UNLICENSE file at the root of the source tree.
//
#include
#include "model.h"
#define NUM_PF_BUFS 32
const char* pf(const char* fmt, ...)
{
// safe to call it NUM_PF_BUFStimes in 1 expression,
// such as function params or a net structure
static char pf_buf[NUM_PF_BUFS][128];
static int last_buf = 0;
va_list list;
last_buf = (last_buf+1)%NUM_PF_BUFS;
pf_buf[last_buf][0] = 0;
va_start(list, fmt);
vsnprintf(pf_buf[last_buf], sizeof(pf_buf[0]), fmt, list);
va_end(list);
return pf_buf[last_buf];
}
const char* wpref(struct fpga_model* model, int y, int x, const char* wire_name)
{
static char buf[8][128];
static int last_buf = 0;
const char *prefix;
int i;
prefix = "";
if (is_aty(Y_CHIP_HORIZ_REGS, model, y)) {
prefix = is_atx(X_CENTER_REGS_COL, model, x+3)
? "REGC_INT_" : "REGH_";
} else if (is_aty(Y_ROW_HORIZ_AXSYMM, model, y))
prefix = "HCLK_";
else if (is_aty(Y_INNER_TOP, model, y))
prefix = "IOI_TTERM_";
else if (is_aty(Y_INNER_BOTTOM, model, y))
prefix = "IOI_BTERM_";
else {
if (is_atx(X_FABRIC_LOGIC_COL|X_CENTER_LOGIC_COL
|X_RIGHT_IO_DEVS_COL|X_LEFT_IO_DEVS_COL
|X_FABRIC_BRAM_VIA_COL|X_FABRIC_MACC_VIA_COL,
model, x)) {
if (has_device_type(model, y, x, DEV_LOGIC, LOGIC_M))
prefix = "CLEXM_";
else if (has_device_type(model, y, x, DEV_LOGIC, LOGIC_L))
prefix = "CLEXL_";
else if (has_device(model, y, x, DEV_ILOGIC))
prefix = "IOI_";
else if (is_atx(X_CENTER_LOGIC_COL, model, x)
&& is_aty(Y_CHIP_HORIZ_REGS, model, y+1))
prefix = "INT_INTERFACE_REGC_";
else
prefix = "INT_INTERFACE_";
}
else if (is_atx(X_CENTER_CMTPLL_COL, model, x))
prefix = "CMT_PLL_";
else if (is_atx(X_RIGHT_MCB|X_LEFT_MCB, model, x)) {
if (y == model->die->mcb_ypos)
prefix = "MCB_";
else {
for (i = 0; i < model->die->num_mui; i++) {
if (y == model->die->mui_pos[i]+1) {
prefix = "MCB_MUI_";
break;
}
}
if (i >= model->die->num_mui)
prefix = "MCB_INT_";
}
} else if (is_atx(X_INNER_RIGHT, model, x))
prefix = "RTERM_";
else if (is_atx(X_INNER_LEFT, model, x))
prefix = "LTERM_";
else if (is_atx(X_CENTER_REGS_COL, model, x))
prefix = "CLKV_";
else if (is_atx(X_FABRIC_BRAM_COL, model, x))
prefix = "BRAMSITE_";
else if (is_atx(X_FABRIC_MACC_COL, model, x))
prefix = "MACCSITE_";
}
last_buf = (last_buf+1)%8;
snprintf(buf[last_buf], sizeof(*buf), "%s%s", prefix, wire_name);
return buf[last_buf];
}
int has_connpt(struct fpga_model* model, int y, int x,
const char* name)
{
struct fpga_tile* tile;
uint16_t name_i;
int i;
i = strarray_find(&model->str, name);
if (i == STRIDX_NO_ENTRY)
return 0;
name_i = i;
tile = YX_TILE(model, y, x);
for (i = 0; i < tile->num_conn_point_names; i++) {
if (tile->conn_point_names[i*2+1] == name_i)
return 1;
}
return 0;
}
#define CONN_NAMES_INCREMENT 128
// add_switch() assumes that the new element is appended
// at the end of the array.
static void connpt_names_array_append(struct fpga_tile* tile, int name_i)
{
if (!(tile->num_conn_point_names % CONN_NAMES_INCREMENT)) {
uint16_t* new_ptr = realloc(tile->conn_point_names,
(tile->num_conn_point_names+CONN_NAMES_INCREMENT)*2*sizeof(uint16_t));
if (!new_ptr) EXIT(ENOMEM);
tile->conn_point_names = new_ptr;
}
tile->conn_point_names[tile->num_conn_point_names*2] = tile->num_conn_point_dests;
tile->conn_point_names[tile->num_conn_point_names*2+1] = name_i;
tile->num_conn_point_names++;
}
static int add_connpt_name_i(struct fpga_model *model, int y, int x,
str16_t name_i, int warn_dup, int *conn_point_o)
{
struct fpga_tile *tile;
int i;
RC_CHECK(model);
tile = YX_TILE(model, y, x);
// All destinations for a connection point must be under
// one unique entry for that connection point, so we
// first have to search for existing destinations.
for (i = 0; i < tile->num_conn_point_names; i++) {
if (tile->conn_point_names[i*2+1] == name_i)
break;
}
if (conn_point_o) *conn_point_o = i;
if (i < tile->num_conn_point_names) {
if (warn_dup)
fprintf(stderr, "Duplicate connection point name "
"y%i x%i %s\n", y, x,
strarray_lookup(&model->str, name_i));
} else
// This is the first connection under name, add name.
connpt_names_array_append(tile, name_i);
RC_RETURN(model);
}
int add_connpt_name(struct fpga_model* model, int y, int x,
const char* connpt_name, int warn_if_duplicate, uint16_t* name_i,
int* conn_point_o)
{
int rc, i;
RC_CHECK(model);
rc = strarray_add(&model->str, connpt_name, &i);
if (rc) RC_FAIL(model, rc);
RC_ASSERT(model, !OUT_OF_U16(i));
if (name_i) *name_i = i;
return add_connpt_name_i(model, y, x, i, warn_if_duplicate, conn_point_o);
}
int has_device(struct fpga_model* model, int y, int x, int dev)
{
struct fpga_tile* tile = YX_TILE(model, y, x);
int i, type_count;
type_count = 0;
for (i = 0; i < tile->num_devs; i++) {
if (tile->devs[i].type == dev)
type_count++;
}
return type_count;
}
int has_device_type(struct fpga_model* model, int y, int x, int dev, int subtype)
{
struct fpga_tile* tile = YX_TILE(model, y, x);
int i, type_subtype_count;
type_subtype_count = 0;
for (i = 0; i < tile->num_devs; i++) {
if (tile->devs[i].type == dev
&& tile->devs[i].subtype == subtype)
type_subtype_count++;
}
return type_subtype_count;
}
int add_connpt_2(struct fpga_model* model, int y, int x,
const char* connpt_name, const char* suffix1, const char* suffix2,
int dup_warn)
{
char name_buf[MAX_WIRENAME_LEN];
RC_CHECK(model);
snprintf(name_buf, sizeof(name_buf), "%s%s", connpt_name, suffix1);
add_connpt_name(model, y, x, name_buf, dup_warn,
/*name_i*/ 0, /*connpt_o*/ 0);
snprintf(name_buf, sizeof(name_buf), "%s%s", connpt_name, suffix2);
add_connpt_name(model, y, x, name_buf, dup_warn,
/*name_i*/ 0, /*connpt_o*/ 0);
RC_RETURN(model);
}
#define CONNS_INCREMENT 128
#undef DBG_ADD_CONN_UNI
static int add_conn_uni_i(struct fpga_model *model,
int from_y, int from_x, str16_t from_name, int *from_connpt_o,
int to_y, int to_x, str16_t to_name)
{
struct fpga_tile *tile;
uint16_t *new_ptr;
int conn_start, num_conn_point_dests_for_this_wire, j;
RC_CHECK(model);
#ifdef DBG_ADD_CONN_UNI
fprintf(stderr, "add_conn_uni_i() from y%i x%i %s connpt %i"
" to y%i x%i %s\n", from_y, from_x,
strarray_lookup(&model->str, from_name), *from_connpt_o,
to_y, to_x, strarray_lookup(&model->str, to_name));
#endif
// this optimization saved about 30% of model creation time
if (*from_connpt_o == -1) {
add_connpt_name_i(model, from_y, from_x, from_name,
0 /* warn_if_duplicate */, from_connpt_o);
RC_CHECK(model);
}
tile = YX_TILE(model, from_y, from_x);
conn_start = tile->conn_point_names[(*from_connpt_o)*2];
if ((*from_connpt_o)+1 >= tile->num_conn_point_names)
num_conn_point_dests_for_this_wire = tile->num_conn_point_dests - conn_start;
else
num_conn_point_dests_for_this_wire = tile->conn_point_names[((*from_connpt_o)+1)*2] - conn_start;
// Is the connection made a second time?
for (j = conn_start; j < conn_start + num_conn_point_dests_for_this_wire; j++) {
if (tile->conn_point_dests[j*3] == to_x
&& tile->conn_point_dests[j*3+1] == to_y
&& tile->conn_point_dests[j*3+2] == to_name) {
fprintf(stderr, "Duplicate conn (num_conn_point_dests %i): y%i x%i %s - y%i x%i %s.\n",
num_conn_point_dests_for_this_wire,
from_y, from_x, strarray_lookup(&model->str, from_name),
to_y, to_x, strarray_lookup(&model->str, to_name));
for (j = conn_start; j < conn_start + num_conn_point_dests_for_this_wire; j++) {
fprintf(stderr, "c%i: y%i x%i %s -> y%i x%i %s\n", j,
from_y, from_x, strarray_lookup(&model->str, from_name),
tile->conn_point_dests[j*3+1], tile->conn_point_dests[j*3],
strarray_lookup(&model->str, tile->conn_point_dests[j*3+2]));
}
RC_RETURN(model);
}
}
if (!(tile->num_conn_point_dests % CONNS_INCREMENT)) {
new_ptr = realloc(tile->conn_point_dests,
(tile->num_conn_point_dests+CONNS_INCREMENT)*3*sizeof(uint16_t));
if (!new_ptr) RC_FAIL(model, ENOMEM);
tile->conn_point_dests = new_ptr;
}
if (tile->num_conn_point_dests > j)
memmove(&tile->conn_point_dests[(j+1)*3],
&tile->conn_point_dests[j*3],
(tile->num_conn_point_dests-j)*3*sizeof(uint16_t));
tile->conn_point_dests[j*3] = to_x;
tile->conn_point_dests[j*3+1] = to_y;
tile->conn_point_dests[j*3+2] = to_name;
tile->num_conn_point_dests++;
for (j = (*from_connpt_o)+1; j < tile->num_conn_point_names; j++)
tile->conn_point_names[j*2]++;
#ifdef DBG_ADD_CONN_UNI
fprintf(stderr, " conn_point_dests for y%i x%i %s now:\n",
from_y, from_x, strarray_lookup(&model->str, from_name));
for (j = conn_start; j < conn_start + num_conn_point_dests_for_this_wire+1; j++) {
fprintf(stderr, " c%i: y%i x%i %s -> y%i x%i %s\n",
j, from_y, from_x, strarray_lookup(&model->str, from_name),
tile->conn_point_dests[j*3+1], tile->conn_point_dests[j*3],
strarray_lookup(&model->str, tile->conn_point_dests[j*3+2]));
}
#endif
RC_RETURN(model);
}
static int add_conn_uni(struct fpga_model *model,
int y1, int x1, const char *name1,
int y2, int x2, const char *name2)
{
str16_t name1_i, name2_i;
int j, from_connpt_o, rc;
RC_CHECK(model);
rc = strarray_add(&model->str, name1, &j);
if (rc) RC_FAIL(model, rc);
RC_ASSERT(model, !OUT_OF_U16(j));
name1_i = j;
rc = strarray_add(&model->str, name2, &j);
if (rc) RC_FAIL(model, rc);
RC_ASSERT(model, !OUT_OF_U16(j));
name2_i = j;
from_connpt_o = -1;
return add_conn_uni_i(model, y1, x1, name1_i, &from_connpt_o, y2, x2, name2_i);
}
int add_conn_bi(struct fpga_model* model,
int y1, int x1, const char* name1,
int y2, int x2, const char* name2)
{
add_conn_uni(model, y1, x1, name1, y2, x2, name2);
add_conn_uni(model, y2, x2, name2, y1, x1, name1);
RC_RETURN(model);
}
int add_conn_bi_pref(struct fpga_model* model,
int y1, int x1, const char* name1,
int y2, int x2, const char* name2)
{
add_conn_bi(model, y1, x1, wpref(model, y1, x1, name1),
y2, x2, wpref(model, y2, x2, name2));
RC_RETURN(model);
}
int add_conn_range(struct fpga_model* model, add_conn_f add_conn_func,
int y1, int x1, const char* name1, int start1, int last1,
int y2, int x2, const char* name2, int start2)
{
char buf1[MAX_WIRENAME_LEN], buf2[MAX_WIRENAME_LEN];
int i;
RC_CHECK(model);
for (i = start1; i <= last1; i++) {
snprintf(buf1, sizeof(buf1), name1, i);
if (start2 & COUNT_DOWN)
snprintf(buf2, sizeof(buf2), name2, (start2 & COUNT_MASK)-(i-start1));
else
snprintf(buf2, sizeof(buf2), name2, (start2 & COUNT_MASK)+(i-start1));
(*add_conn_func)(model, y1, x1, buf1, y2, x2, buf2);
}
RC_RETURN(model);
}
int add_conn_net(struct fpga_model* model, int add_pref, const struct w_net *net)
{
int i, j, rc;
RC_CHECK(model);
if (net->num_pts < 2) RC_FAIL(model, EINVAL);
if (!net->last_inc) {
str16_t net_name_i[MAX_NET_POINTS];
int str_i, net_connpt_o[MAX_NET_POINTS];
for (i = 0; i < net->num_pts; i++) {
rc = strarray_add(&model->str, add_pref
? wpref(model,
net->pt[i].y, net->pt[i].x,
net->pt[i].name)
: net->pt[i].name, &str_i);
if (rc) RC_FAIL(model, rc);
RC_ASSERT(model, !OUT_OF_U16(str_i));
net_name_i[i] = str_i;
net_connpt_o[i] = -1;
}
for (i = 0; i < net->num_pts; i++) {
for (j = i+1; j < net->num_pts; j++) {
if (net->pt[j].y == net->pt[i].y
&& net->pt[j].x == net->pt[i].x)
continue;
add_conn_uni_i(model,
net->pt[i].y, net->pt[i].x, net_name_i[i],
&net_connpt_o[i],
net->pt[j].y, net->pt[j].x, net_name_i[j]);
add_conn_uni_i(model,
net->pt[j].y, net->pt[j].x, net_name_i[j],
&net_connpt_o[j],
net->pt[i].y, net->pt[i].x, net_name_i[i]);
}
}
} else { // last_inc != 0
for (i = 0; i < net->num_pts; i++) {
for (j = i+1; j < net->num_pts; j++) {
// We are buildings nets like a NN2 B-M-E net where
// we add the _S0 wire at the end, at the same x/y
// coordinate as the M point. Here we skip such
// connections back to the start tile.
if (net->pt[j].y == net->pt[i].y
&& net->pt[j].x == net->pt[i].x)
continue;
add_conn_range(model,
add_pref ? add_conn_bi_pref : add_conn_bi,
net->pt[i].y, net->pt[i].x,
net->pt[i].name,
net->pt[i].start_count,
net->pt[i].start_count + net->last_inc,
net->pt[j].y, net->pt[j].x,
net->pt[j].name,
net->pt[j].start_count);
}
}
}
RC_RETURN(model);
}
#define SWITCH_ALLOC_INCREMENT 256
#define DBG_ALLOW_ADDPOINTS
// Enable CHECK_DUPLICATES when working on the switch architecture,
// but otherwise keep it disabled since it slows down building the
// model a lot.
#undef CHECK_DUPLICATES
int add_switch(struct fpga_model* model, int y, int x, const char* from,
const char* to, int is_bidirectional)
{
struct fpga_tile* tile = YX_TILE(model, y, x);
int rc, i, from_idx, to_idx, from_connpt_o, to_connpt_o;
uint32_t new_switch;
RC_CHECK(model);
// later this can be strarray_find() and not strarray_add(), but
// then we need all wires and ports to be present first...
#ifdef DBG_ALLOW_ADDPOINTS
rc = strarray_add(&model->str, from, &from_idx);
if (rc) goto xout;
rc = strarray_add(&model->str, to, &to_idx);
if (rc) goto xout;
#else
from_idx = strarray_find(&model->str, from);
to_idx = strarray_find(&model->str, to);
#endif
if (from_idx == STRIDX_NO_ENTRY || to_idx == STRIDX_NO_ENTRY) {
fprintf(stderr, "No string for switch from %s (%i) or %s (%i).\n",
from, from_idx, to, to_idx);
return -1;
}
// It seems searching backwards is a little faster than
// searching forwards. Merging the two loops into one
// made the total slower, presumably due to cache issues.
from_connpt_o = -1;
for (i = tile->num_conn_point_names-1; i >= 0; i--) {
if (tile->conn_point_names[i*2+1] == from_idx) {
from_connpt_o = i;
break;
}
}
to_connpt_o = -1;
for (i = tile->num_conn_point_names-1; i >= 0; i--) {
if (tile->conn_point_names[i*2+1] == to_idx) {
to_connpt_o = i;
break;
}
}
#ifdef DBG_ALLOW_ADDPOINTS
if (from_connpt_o == -1) {
from_connpt_o = tile->num_conn_point_names;
connpt_names_array_append(tile, from_idx);
}
if (to_connpt_o == -1) {
to_connpt_o = tile->num_conn_point_names;
connpt_names_array_append(tile, to_idx);
}
#endif
if (from_connpt_o == -1 || to_connpt_o == -1) {
fprintf(stderr, "No conn point for switch from %s (%i/%i) or %s (%i/%i).\n",
from, from_idx, from_connpt_o, to, to_idx, to_connpt_o);
return -1;
}
if (from_connpt_o > SWITCH_MAX_CONNPT_O
|| to_connpt_o > SWITCH_MAX_CONNPT_O) {
fprintf(stderr, "Internal error in %s:%i (from_o %i to_o %i)\n",
__FILE__, __LINE__, from_connpt_o, to_connpt_o);
return -1;
}
new_switch = (from_connpt_o << 15) | to_connpt_o;
if (is_bidirectional)
new_switch |= SWITCH_BIDIRECTIONAL;
#ifdef CHECK_DUPLICATES
for (i = 0; i < tile->num_switches; i++) {
if ((tile->switches[i] & 0x3FFFFFFF) == (new_switch & 0x3FFFFFFF)) {
fprintf(stderr, "Internal error in %s:%i duplicate switch from %s to %s\n",
__FILE__, __LINE__, from, to);
return -1;
}
}
#endif
if (!(tile->num_switches % SWITCH_ALLOC_INCREMENT)) {
uint32_t* new_ptr = realloc(tile->switches,
(tile->num_switches+SWITCH_ALLOC_INCREMENT)*sizeof(*tile->switches));
if (!new_ptr) {
fprintf(stderr, "Out of memory %s:%i\n", __FILE__, __LINE__);
return -1;
}
tile->switches = new_ptr;
}
tile->switches[tile->num_switches++] = new_switch;
return 0;
xout:
return rc;
}
int add_switch_set(struct fpga_model* model, int y, int x, const char* prefix,
const char** pairs, int suffix_inc)
{
int i, j, from_len, to_len, rc;
char from[64], to[64];
RC_CHECK(model);
if (!prefix) prefix = "";
for (i = 0; pairs[i*2][0]; i++) {
snprintf(from, sizeof(from), "%s%s", prefix, pairs[i*2]);
snprintf(to, sizeof(to), "%s%s", prefix, pairs[i*2+1]);
if (!suffix_inc) {
rc = add_switch(model, y, x, from, to,
0 /* bidir */);
if (rc) goto xout;
} else {
from_len = strlen(from);
to_len = strlen(to);
for (j = 0; j <= suffix_inc; j++) {
snprintf(&from[from_len], sizeof(from)-from_len, "%i", j);
snprintf(&to[to_len], sizeof(to)-to_len, "%i", j);
rc = add_switch(model, y, x, from, to,
0 /* bidir */);
if (rc) goto xout;
}
}
}
return 0;
xout:
return rc;
}
int replicate_switches_and_names(struct fpga_model* model,
int y_from, int x_from, int y_to, int x_to)
{
struct fpga_tile* from_tile, *to_tile;
int rc;
RC_CHECK(model);
from_tile = YX_TILE(model, y_from, x_from);
to_tile = YX_TILE(model, y_to, x_to);
if (to_tile->num_conn_point_names
|| to_tile->num_conn_point_dests
|| to_tile->num_switches
|| from_tile->num_conn_point_dests
|| !from_tile->num_conn_point_names
|| !from_tile->num_switches) FAIL(EINVAL);
to_tile->conn_point_names = malloc(((from_tile->num_conn_point_names/CONN_NAMES_INCREMENT)+1)*CONN_NAMES_INCREMENT*2*sizeof(uint16_t));
if (!to_tile->conn_point_names) EXIT(ENOMEM);
memcpy(to_tile->conn_point_names, from_tile->conn_point_names, from_tile->num_conn_point_names*2*sizeof(uint16_t));
to_tile->num_conn_point_names = from_tile->num_conn_point_names;
to_tile->switches = malloc(((from_tile->num_switches/SWITCH_ALLOC_INCREMENT)+1)*SWITCH_ALLOC_INCREMENT*sizeof(*from_tile->switches));
if (!to_tile->switches) EXIT(ENOMEM);
memcpy(to_tile->switches, from_tile->switches, from_tile->num_switches*sizeof(*from_tile->switches));
to_tile->num_switches = from_tile->num_switches;
return 0;
fail:
return rc;
}
void seed_strx(struct fpga_model *model, const struct seed_data *data)
{
int x, i;
for (x = 0; x < model->x_width; x++) {
model->tmp_str[x] = 0;
for (i = 0; data[i].flags; i++) {
if (is_atx(data[i].flags, model, x))
model->tmp_str[x] = data[i].str;
}
}
}
void seed_stry(struct fpga_model *model, const struct seed_data *data)
{
int y, i;
for (y = 0; y < model->y_height; y++) {
model->tmp_str[y] = 0;
for (i = 0; data[i].flags; i++) {
if (is_aty(data[i].flags, model, y))
model->tmp_str[y] = data[i].str;
}
}
}
char next_non_whitespace(const char* s)
{
int i;
for (i = 0; s[i] == ' '; i++);
return s[i];
}
char last_major(const char* str, int cur_o)
{
for (; cur_o; cur_o--) {
if (str[cur_o-1] >= 'A' && str[cur_o-1] <= 'Z')
return str[cur_o-1];
}
return 0;
}
int is_aty(int check, struct fpga_model* model, int y)
{
if (y < 0) return 0;
if (check & Y_OUTER_TOP && y == TOP_OUTER_ROW) return 1;
if (check & Y_INNER_TOP && y == TOP_INNER_ROW) return 1;
if (check & Y_INNER_BOTTOM && y == model->y_height-BOT_INNER_ROW) return 1;
if (check & Y_OUTER_BOTTOM && y == model->y_height-BOT_OUTER_ROW) return 1;
if (check & Y_CHIP_HORIZ_REGS && y == model->center_y) return 1;
if (check & (Y_ROW_HORIZ_AXSYMM|Y_BOTTOM_OF_ROW|Y_REGULAR_ROW)) {
int row_pos;
is_in_row(model, y, 0 /* row_num */, &row_pos);
if (check & Y_ROW_HORIZ_AXSYMM && row_pos == 8) return 1;
if (check & Y_BOTTOM_OF_ROW && row_pos == 16) return 1;
if (check & Y_REGULAR_ROW && ((row_pos >= 0 && row_pos < 8) || (row_pos > 8 && row_pos <= 16))) return 1;
}
if (check & Y_LEFT_WIRED && model->tiles[y*model->x_width].flags & TF_WIRED) return 1;
if (check & Y_RIGHT_WIRED && model->tiles[y*model->x_width + model->x_width-RIGHT_OUTER_O].flags & TF_WIRED) return 1;
if (check & Y_TOPBOT_IO_RANGE
&& ((y > TOP_INNER_ROW && y <= TOP_INNER_ROW + TOP_IO_TILES)
|| (y >= model->y_height - BOT_INNER_ROW - BOT_IO_TILES && y < model->y_height - BOT_INNER_ROW))) return 1;
if (check & Y_TOP_OUTER_IO && y == TOP_OUTER_IO) return 1;
if (check & Y_TOP_INNER_IO && y == TOP_INNER_IO) return 1;
if (check & Y_BOT_INNER_IO && y == model->y_height-BOT_INNER_IO) return 1;
if (check & Y_BOT_OUTER_IO && y == model->y_height-BOT_OUTER_IO) return 1;
return 0;
}
int is_atx(int check, struct fpga_model* model, int x)
{
if (x < 0) return 0;
if (check & X_OUTER_LEFT && !x) return 1;
if (check & X_INNER_LEFT && x == 1) return 1;
if (check & X_INNER_RIGHT && x == model->x_width-2) return 1;
if (check & X_OUTER_RIGHT && x == model->x_width-1) return 1;
if (check & X_ROUTING_NO_IO
&& model->tiles[x].flags & TF_ROUTING_NO_IO) return 1;
if (check & X_FABRIC_LOGIC_XM_ROUTING_COL
&& model->tiles[x].flags & TF_FABRIC_ROUTING_COL
&& model->tiles[x+1].flags & TF_FABRIC_LOGIC_XM_COL) return 1;
if (check & X_FABRIC_LOGIC_XL_ROUTING_COL
&& model->tiles[x].flags & TF_FABRIC_ROUTING_COL
&& model->tiles[x+1].flags & TF_FABRIC_LOGIC_XL_COL) return 1;
if (check & X_FABRIC_LOGIC_XM_COL
&& model->tiles[x].flags & TF_FABRIC_LOGIC_XM_COL) return 1;
if (check & X_FABRIC_LOGIC_XL_COL
&& model->tiles[x].flags & TF_FABRIC_LOGIC_XL_COL) return 1;
if (check & X_FABRIC_BRAM_ROUTING_COL
&& model->tiles[x].flags & TF_FABRIC_ROUTING_COL
&& model->tiles[x+1].flags & TF_FABRIC_BRAM_VIA_COL
&& model->tiles[x+2].flags & TF_FABRIC_BRAM_COL) return 1;
if (check & X_FABRIC_MACC_ROUTING_COL
&& model->tiles[x].flags & TF_FABRIC_ROUTING_COL
&& model->tiles[x+1].flags & TF_FABRIC_MACC_VIA_COL
&& model->tiles[x+2].flags & TF_FABRIC_MACC_COL) return 1;
if (check & X_FABRIC_BRAM_VIA_COL && model->tiles[x].flags & TF_FABRIC_BRAM_VIA_COL) return 1;
if (check & X_FABRIC_MACC_VIA_COL && model->tiles[x].flags & TF_FABRIC_MACC_VIA_COL) return 1;
if (check & X_FABRIC_BRAM_COL && model->tiles[x].flags & TF_FABRIC_BRAM_COL) return 1;
if (check & X_FABRIC_MACC_COL && model->tiles[x].flags & TF_FABRIC_MACC_COL) return 1;
if (check & X_CENTER_ROUTING_COL && x == model->center_x-3) return 1;
if (check & X_CENTER_LOGIC_COL && x == model->center_x-2) return 1;
if (check & X_CENTER_CMTPLL_COL && x == model->center_x-1) return 1;
if (check & X_CENTER_REGS_COL && x == model->center_x) return 1;
if (check & X_LEFT_IO_ROUTING_COL && x == LEFT_IO_ROUTING) return 1;
if (check & X_LEFT_IO_DEVS_COL && x == LEFT_IO_DEVS) return 1;
if (check & X_RIGHT_IO_ROUTING_COL
&& x == model->x_width-RIGHT_IO_ROUTING_O) return 1;
if (check & X_RIGHT_IO_DEVS_COL
&& x == model->x_width-RIGHT_IO_DEVS_O) return 1;
if (check & X_LEFT_SIDE && x < model->center_x) return 1;
if (check & X_LEFT_MCB && x == LEFT_MCB_COL) return 1;
if (check & X_RIGHT_MCB && x == model->x_width-RIGHT_MCB_O) return 1;
return 0;
}
int is_atyx(int check, struct fpga_model* model, int y, int x)
{
struct fpga_tile* tile;
if (y < 0 || x < 0) return 0;
// todo: YX_ROUTING_TILE could be implemented using X_ROUTING_COL and Y_REGULAR_ROW ?
if (check & YX_ROUTING_TILE
&& (model->tiles[x].flags & TF_FABRIC_ROUTING_COL
|| x == LEFT_IO_ROUTING || x == model->x_width-RIGHT_IO_ROUTING_O
|| x == model->center_x-CENTER_ROUTING_O)) {
int row_pos;
is_in_row(model, y, 0 /* row_num */, &row_pos);
if (row_pos >= 0 && row_pos != 8) return 1;
}
tile = YX_TILE(model, y, x);
if (check & YX_IO_ROUTING
&& (tile->type == IO_ROUTING || tile->type == ROUTING_IO_L)) return 1;
if (check & YX_ROUTING_TO_FABLOGIC
&& model->tiles[x].flags & TF_FABRIC_ROUTING_COL
&& has_device(model, y, x+1, DEV_LOGIC)) return 1;
if (check & YX_DEV_ILOGIC && has_device(model, y, x, DEV_ILOGIC)) return 1;
if (check & YX_DEV_OLOGIC && has_device(model, y, x, DEV_OLOGIC)) return 1;
if (check & YX_DEV_LOGIC && has_device(model, y, x, DEV_LOGIC)) return 1;
if (check & YX_DEV_IOB && has_device(model, y, x, DEV_IOB)) return 1;
if (check & YX_CENTER_MIDBUF && tile->flags & TF_CENTER_MIDBUF) return 1;
if (check & YX_OUTER_TERM
&& (is_atx(X_OUTER_LEFT|X_OUTER_RIGHT, model, x)
|| is_aty(Y_OUTER_TOP|Y_OUTER_BOTTOM, model, y))) return 1;
if (check & YX_INNER_TERM
&& (is_atx(X_INNER_LEFT|X_INNER_RIGHT, model, x)
|| is_aty(Y_INNER_TOP|Y_INNER_BOTTOM, model, y))) return 1;
if (check & YX_OUTSIDE_OF_ROUTING
&& (x < LEFT_IO_ROUTING
|| x > model->x_width-RIGHT_IO_ROUTING_O
|| y <= TOP_INNER_ROW
|| y >= model->y_height-BOT_INNER_ROW )) return 1;
if (check & YX_X_CENTER_CMTPLL
&& is_atx(X_CENTER_CMTPLL_COL, model, x)) return 1;
if (check & YX_Y_CENTER
&& is_aty(Y_CHIP_HORIZ_REGS, model, y)) return 1;
if (check & YX_CENTER
&& is_atx(X_CENTER_REGS_COL, model, x)
&& is_aty(Y_CHIP_HORIZ_REGS, model, y)) return 1;
return 0;
}
void is_in_row(const struct fpga_model* model, int y,
int* row_num, int* row_pos)
{
int dist_to_center;
if (row_num) *row_num = -1;
if (row_pos) *row_pos = -1;
if (y < TOP_IO_TILES) return; // handles y==-1
// normalize y to beginning of rows
y -= TOP_IO_TILES;
// calculate distance to center and check
// that y is not pointing to the center
dist_to_center = (model->die->num_rows/2)*(8+1/*middle of row*/+8);
if (y == dist_to_center) return;
if (y > dist_to_center) y--;
// check that y is not pointing past the last row
if (y >= model->die->num_rows*(8+1+8)) return;
if (row_num) *row_num = model->die->num_rows-(y/(8+1+8))-1;
if (row_pos) *row_pos = y%(8+1+8);
}
int which_row(int y, struct fpga_model* model)
{
int result;
is_in_row(model, y, &result, 0 /* row_pos */);
return result;
}
int pos_in_row(int y, struct fpga_model* model)
{
int result;
is_in_row(model, y, 0 /* row_num */, &result);
return result;
}
int regular_row_pos(int y, struct fpga_model* model)
{
int row_pos = pos_in_row(y, model);
if (row_pos == -1 || row_pos == HCLK_POS) return -1;
if (row_pos > HCLK_POS) row_pos--;
return row_pos;
}
int row_to_hclk(int row, struct fpga_model *model)
{
int hclk_pos = model->y_height - BOT_LAST_REGULAR_O - row*ROW_SIZE - HCLK_POS;
if (hclk_pos < model->center_y)
hclk_pos--; // center regs
if (hclk_pos < TOP_FIRST_REGULAR)
{ HERE(); return -1; }
return hclk_pos;
}
int y_to_hclk(int y, struct fpga_model *model)
{
int row_num, row_pos;
is_in_row(model, y, &row_num, &row_pos);
if (row_num == -1
|| row_pos == -1 || row_pos == HCLK_POS)
{ HERE(); return -1; }
return row_to_hclk(row_num, model);
}
int regular_row_up(int y, struct fpga_model *model)
{
if (y <= TOP_FIRST_REGULAR) return -1;
y--;
if (is_aty(Y_CHIP_HORIZ_REGS|Y_ROW_HORIZ_AXSYMM, model, y))
y--;
return y;
}
const char* logicin_s(int wire, int routing_io)
{
if (routing_io && ((wire & LWF_WIRE_MASK) == X_A5 || (wire & LWF_WIRE_MASK) == X_B4))
return pf("INT_IOI_LOGICIN_B%i", wire & LWF_WIRE_MASK);
return pf("LOGICIN_B%i", wire & LWF_WIRE_MASK);
}
const char* logicin_str(enum logicin_wire w)
{
switch (w) {
case M_A1:
case X_A1: return "A1";
case M_A2:
case X_A2: return "A2";
case M_A3:
case X_A3: return "A3";
case M_A4:
case X_A4: return "A4";
case M_A5:
case X_A5: return "A5";
case M_A6:
case X_A6: return "A6";
case M_AX:
case X_AX: return "AX";
case M_B1:
case X_B1: return "B1";
case M_B2:
case X_B2: return "B2";
case M_B3:
case X_B3: return "B3";
case M_B4:
case X_B4: return "B4";
case M_B5:
case X_B5: return "B5";
case M_B6:
case X_B6: return "B6";
case M_BX:
case X_BX: return "BX";
case M_C1:
case X_C1: return "C1";
case M_C2:
case X_C2: return "C2";
case M_C3:
case X_C3: return "C3";
case M_C4:
case X_C4: return "C4";
case M_C5:
case X_C5: return "C5";
case M_C6:
case X_C6: return "C6";
case M_CE:
case X_CE: return "CE";
case M_CX:
case X_CX: return "CX";
case M_D1:
case X_D1: return "D1";
case M_D2:
case X_D2: return "D2";
case M_D3:
case X_D3: return "D3";
case M_D4:
case X_D4: return "D4";
case M_D5:
case X_D5: return "D5";
case M_D6:
case X_D6: return "D6";
case M_DX:
case X_DX: return "DX";
case M_AI: return "AI";
case M_BI: return "BI";
case M_CI: return "CI";
case M_DI: return "DI";
case M_WE: return "WE";
}
EXIT(1);
return 0;
}
const char* logicout_str(enum logicout_wire w)
{
switch (w) {
case X_A:
case M_A: return "A";
case X_AMUX:
case M_AMUX: return "AMUX";
case X_AQ:
case M_AQ: return "AQ";
case X_B:
case M_B: return "B";
case X_BMUX:
case M_BMUX: return "BMUX";
case X_BQ:
case M_BQ: return "BQ";
case X_C:
case M_C: return "C";
case X_CMUX:
case M_CMUX: return "CMUX";
case X_CQ:
case M_CQ: return "CQ";
case X_D:
case M_D: return "D";
case X_DMUX:
case M_DMUX: return "DMUX";
case X_DQ:
case M_DQ: return "DQ";
}
EXIT(1);
return 0;
}
const char *fpga_connpt_str(struct fpga_model *model, enum extra_wires wire,
int y, int x, int dest_y, int dest_x)
{
enum { NUM_BUFS = 8, BUF_SIZE = MAX_WIRENAME_LEN };
static char buf[NUM_BUFS][BUF_SIZE];
static int last_buf = 0;
const char *wstr;
int i, wnum, wchar;
if (dest_y == -1) dest_y = y;
if (dest_x == -1) dest_x = x;
last_buf = (last_buf+1)%NUM_BUFS;
buf[last_buf][0] = 0;
if (wire == CLK0 || wire == CLK1
|| wire == SR0 || wire == SR1) {
if (is_atx(X_LEFT_IO_DEVS_COL|X_FABRIC_LOGIC_COL|X_FABRIC_MACC_VIA_COL
|X_FABRIC_BRAM_VIA_COL|X_CENTER_LOGIC_COL|X_RIGHT_IO_DEVS_COL, model, x))
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"INT_INTERFACE_%s", fpga_wire2str(wire));
else if (is_atx(X_LEFT_MCB|X_RIGHT_MCB, model, x)) {
for (i = 0; i < model->die->num_mui; i++) {
if (y == model->die->mui_pos[i]+1) {
if (y-dest_y < 0 || y-dest_y > 1) HERE();
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"MUI_%s_INT%i", fpga_wire2str(wire), y-dest_y);
break;
}
}
if (i >= model->die->num_mui)
strcpy(buf[last_buf], fpga_wire2str(wire));
} else if (is_atx(X_FABRIC_MACC_COL, model, x)) {
if (has_device(model, y, x, DEV_MACC)) {
if (y-dest_y < 0 || y-dest_y >= 4) HERE();
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"MACC_%s_INT%i", fpga_wire2str(wire), y-dest_y);
} else
strcpy(buf[last_buf], fpga_wire2str(wire));
} else
strcpy(buf[last_buf], fpga_wire2str(wire));
} else if (wire >= LOGICOUT_B0 && wire <= LOGICOUT_B0 + LOGICOUT_HIGHEST) {
wnum = wire - LOGICOUT_B0;
if (is_atx(X_ROUTING_COL, model, x)) {
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"LOGICOUT%i", wnum);
} else if (is_atx(X_LEFT_IO_DEVS_COL|X_RIGHT_IO_DEVS_COL, model, x)) {
if (is_atx(X_LEFT_MCB|X_RIGHT_MCB, model, dest_x))
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"INT_INTERFACE_LOGICOUT_%i", wnum);
else
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"INT_INTERFACE_LOGICOUT%i", wnum);
} else if (is_atx(X_FABRIC_LOGIC_COL|X_CENTER_LOGIC_COL, model, x)) {
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"INT_INTERFACE_LOGICOUT%i", wnum);
} else if (is_atx(X_FABRIC_MACC_VIA_COL|X_FABRIC_BRAM_VIA_COL, model, x)) {
if (is_atx(X_FABRIC_MACC_COL, model, dest_x))
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"INT_INTERFACE_LOGICOUT_%i", wnum);
else
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"INT_INTERFACE_LOGICOUT%i", wnum);
} else if (is_atx(X_LEFT_MCB|X_RIGHT_MCB, model, x)) {
for (i = 0; i < model->die->num_mui; i++) {
if (y == model->die->mui_pos[i]+1) {
if (y-dest_y < 0 || y-dest_y > 1) HERE();
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"MUI_LOGICOUT%i_INT%i", wnum, y-dest_y);
break;
}
}
if (i >= model->die->num_mui)
strcpy(buf[last_buf], fpga_wire2str(wire));
} else if (is_atx(X_FABRIC_MACC_COL, model, x)) {
if (has_device(model, y, x, DEV_MACC)) {
if (y-dest_y < 0 || y-dest_y >= 4) HERE();
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"MACC_LOGICOUT%i_INT%i", wnum, y-dest_y);
} else
strcpy(buf[last_buf], fpga_wire2str(wire));
} else
strcpy(buf[last_buf], fpga_wire2str(wire));
} else if (wire >= LOGICIN_B0 && wire <= LOGICIN_B0 + LOGICIN_HIGHEST) {
wnum = wire - LOGICIN_B0;
if (is_atx(X_ROUTING_COL, model, x)) {
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"LOGICIN_B%i", wnum);
} else if (is_atx(X_LEFT_IO_DEVS_COL|X_FABRIC_LOGIC_COL|X_CENTER_LOGIC_COL
|X_RIGHT_IO_DEVS_COL|X_FABRIC_MACC_VIA_COL
|X_FABRIC_BRAM_VIA_COL, model, x)) {
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"INT_INTERFACE_LOGICBIN%i", wnum);
} else if (is_atx(X_LEFT_MCB|X_RIGHT_MCB, model, x)) {
for (i = 0; i < model->die->num_mui; i++) {
if (y == model->die->mui_pos[i]+1) {
if (y-dest_y < 0 || y-dest_y > 1) HERE();
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"MUI_LOGICINB%i_INT%i", wnum, y-dest_y);
break;
}
}
if (i >= model->die->num_mui)
strcpy(buf[last_buf], fpga_wire2str(wire));
} else if (is_atx(X_FABRIC_MACC_COL, model, x)) {
if (has_device(model, y, x, DEV_MACC)) {
if (y-dest_y < 0 || y-dest_y >= 4) HERE();
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"MACC_LOGICINB%i_INT%i", wnum, y-dest_y);
} else
strcpy(buf[last_buf], fpga_wire2str(wire));
} else
strcpy(buf[last_buf], fpga_wire2str(wire));
} else if ((wire >= CFB0 && wire <= CFB15)
|| (wire >= DFB0 && wire <= DFB7)) {
if (wire >= CFB0 && wire <= CFB15) {
wstr = "CFB";
wnum = wire-CFB0;
} else if (wire >= DFB0 && wire <= DFB7) {
wstr = "DFB";
wnum = wire-DFB0;
} else HERE();
if (is_aty(Y_OUTER_TOP, model, y)) {
if (is_atx(X_CENTER_CMTPLL_COL, model, x))
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"REGT_%s", fpga_wire2str(wire));
else HERE();
} else if (is_aty(Y_INNER_TOP, model, y)) {
if (is_atx(X_CENTER_LOGIC_COL, model, x)) {
if (wnum%8 < 4) {
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"IOI_REGT_%s%s_%c%i",
wstr,
wnum >= 8 ? "1" : "",
wnum%2 ? 'S' : 'M',
(wnum%4)/2+1);
if (is_atyx(YX_DEV_ILOGIC, model, dest_y, dest_x))
strcat(buf[last_buf], "_S");
} else HERE();
} else if (is_atx(X_CENTER_CMTPLL_COL, model, x))
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"REGT_TTERM_%s", fpga_wire2str(wire));
else if (is_atx(X_CENTER_REGS_COL, model, x))
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"REGV_TTERM_%s", fpga_wire2str(wire));
else if (x == model->center_x + CENTER_X_PLUS_1)
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"IOI_TTERM_%s", fpga_wire2str(wire));
else if (x == model->center_x + CENTER_X_PLUS_2) {
if (wnum%8 >= 4) {
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"IOI_REGT_%s%s_%c%i",
wstr,
wnum >= 8 ? "1" : "",
wnum % 2 ? 'S' : 'M',
(wnum%4)/2+1);
if (is_atyx(YX_DEV_ILOGIC, model, dest_y, dest_x))
strcat(buf[last_buf], "_S");
} else HERE();
} else HERE();
} else if (is_aty(Y_TOP_OUTER_IO, model, y)) {
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"TIOI_%s_%s%s_%c%s",
wnum%4 < 2 ? "OUTER" : "INNER",
wstr,
wnum >= 8 ? "1" : "",
wnum % 2 ? 'S' : 'M',
(wnum%4)/2 ? "_EXT" : "");
} else if (is_aty(Y_TOP_INNER_IO, model, y)) {
if (wnum%4 >= 2) {
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"TIOI_INNER_%s%s_%c", wstr,
wnum >= 8 ? "1" : "",
wnum%2 ? 'S' : 'M');
} else HERE();
} else if (is_aty(Y_BOT_INNER_IO, model, y)) {
if (wnum%4 >= 2) {
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"BIOI_INNER_%s%s_%c", wstr,
wnum >= 8 ? "1" : "",
wnum%2 ? 'S' : 'M');
} else HERE();
} else if (is_aty(Y_BOT_OUTER_IO, model, y)) {
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"BIOI_%s_%s%s_%c%s",
wnum%4 < 2 ? "OUTER" : "INNER",
wstr,
wnum >= 8 ? "1" : "",
wnum%2 ? 'S' : 'M',
(wnum%4)/2 ? "_EXT" : "");
} else if (is_aty(Y_INNER_BOTTOM, model, y)) {
if (is_atx(X_CENTER_LOGIC_COL, model, x)) {
if (wnum%8 >= 4) {
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"BTERM_CLB_%s", fpga_wire2str(wire));
if (is_atyx(YX_DEV_ILOGIC, model, dest_y, dest_x))
strcat(buf[last_buf], "_N");
} else HERE();
} else if (is_atx(X_CENTER_CMTPLL_COL, model, x)) {
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"REGB_BTERM_%s", fpga_wire2str(wire));
} else if (is_atx(X_CENTER_REGS_COL, model, x)) {
if (wnum%8 < 4) {
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"REGV_BTERM_%s", fpga_wire2str(wire+4));
} else HERE();
} else if (x == model->center_x + CENTER_X_PLUS_1) {
if (wnum < 4)
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"IOI_BTERM_%s", fpga_wire2str(wire+4));
else if (wnum >= 8 && wnum <= 11)
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"IOI_BTERM_BUFPLL_%s", fpga_wire2str(wire+4));
else HERE();
} else if (x == model->center_x + CENTER_X_PLUS_2) {
if (wnum%8 < 4) {
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"BTERM_CLB_%s", fpga_wire2str(wire+4));
if (is_atyx(YX_DEV_ILOGIC, model, dest_y, dest_x))
strcat(buf[last_buf], "_N");
} else HERE();
} else HERE();
} else if (is_aty(Y_OUTER_BOTTOM, model, y)) {
if (is_atx(X_CENTER_CMTPLL_COL, model, x))
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"REGB_%s", fpga_wire2str(wire));
else HERE();
} else if (is_atx(X_OUTER_LEFT, model, x)) {
if (is_aty(Y_CHIP_HORIZ_REGS, model, y))
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"REGL_%s", fpga_wire2str(wire));
else HERE();
} else if (is_atx(X_INNER_LEFT, model, x)) {
if (is_aty(Y_CHIP_HORIZ_REGS, model, y)) {
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"REGH_LTERM_%s", fpga_wire2str(wire));
} else if (y == model->center_y + CENTER_Y_PLUS_1) {
if (wnum%8 < 4) {
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"IOI_LTERM_TOP_%s", fpga_wire2str(wire));
if (is_atx(X_LEFT_IO_ROUTING_COL|X_LEFT_IO_DEVS_COL, model, dest_x))
strcat(buf[last_buf], "_E");
} else HERE();
} else if (y == model->center_y + CENTER_Y_PLUS_2) {
if (wnum%8 < 2) {
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"IOI_LTERM_BOT_%s", fpga_wire2str(wire));
if (is_atx(X_LEFT_IO_ROUTING_COL|X_LEFT_IO_DEVS_COL, model, dest_x))
strcat(buf[last_buf], "_E");
} else HERE();
} else if (y == model->center_y - CENTER_Y_MINUS_1
|| y == model->center_y - CENTER_Y_MINUS_2) {
if (wnum%8 >= 4)
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"IOI_LTERM_%s_EXT", fpga_wire2str(wire-4));
else HERE();
} else if (y == model->center_y - CENTER_Y_MINUS_3) {
if (wnum%8 >= 4) {
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"IOI_LTERM_BOT_%s", fpga_wire2str(wire-4));
if (is_atx(X_LEFT_IO_ROUTING_COL|X_LEFT_IO_DEVS_COL, model, dest_x))
strcat(buf[last_buf], "_E");
} else HERE();
} else if (y == model->center_y - CENTER_Y_MINUS_4) {
if (wnum%8 >= 4) {
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"IOI_LTERM_TOP_%s", fpga_wire2str(wire-4));
if (is_atx(X_LEFT_IO_ROUTING_COL|X_LEFT_IO_DEVS_COL, model, dest_x))
strcat(buf[last_buf], "_E");
} else HERE();
} else HERE();
} else if (is_atx(X_LEFT_IO_ROUTING_COL, model, x)) {
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"INT_%s%s_%c", wstr, wnum >= 8 ? "1" : "",
wnum%2 ? 'S' : 'M');
} else if (is_atx(X_LEFT_IO_DEVS_COL, model, x)) {
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"LIOI_%s%s_%c_ILOGIC", wstr, wnum >= 8 ? "1" : "",
wnum%2 ? 'S' : 'M');
} else if (is_atx(X_RIGHT_IO_DEVS_COL, model, x)) {
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"RIOI_%s%s_%c_ILOGIC", wstr, wnum >= 8 ? "1" : "",
wnum%2 ? 'S' : 'M');
} else if (is_atx(X_INNER_RIGHT, model, x)) {
if (is_aty(Y_CHIP_HORIZ_REGS, model, y)) {
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"REGH_RTERM_%s", fpga_wire2str(wire));
} else if (y == model->center_y + CENTER_Y_PLUS_1) {
if (wnum%8 >= 4) {
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"IOI_RTERM_TOP_%s", fpga_wire2str(wire-4));
if (is_atx(X_RIGHT_IO_DEVS_COL, model, dest_x))
strcat(buf[last_buf], "_W");
} else HERE();
} else if (y == model->center_y + CENTER_Y_PLUS_2) {
if (wnum%8 >= 6) {
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"IOI_RTERM_BOT_%s", fpga_wire2str(wire-4));
if (is_atx(X_RIGHT_IO_DEVS_COL, model, dest_x))
strcat(buf[last_buf], "_W");
} else HERE();
} else if (y == model->center_y - CENTER_Y_MINUS_1
|| y == model->center_y - CENTER_Y_MINUS_2) {
if (wnum%8 < 4)
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"IOI_RTERM_%s%s", fpga_wire2str(wire),
wnum < 8 ? "_EXT" : "");
else HERE();
} else if (y == model->center_y - CENTER_Y_MINUS_3) {
if (wnum%8 < 4) {
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"IOI_RTERM_BOT_%s", fpga_wire2str(wire));
if (is_atx(X_RIGHT_IO_DEVS_COL, model, dest_x))
strcat(buf[last_buf], "_W");
} else HERE();
} else if (y == model->center_y - CENTER_Y_MINUS_4) {
if (wnum%8 < 4) {
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"IOI_RTERM_TOP_%s", fpga_wire2str(wire));
if (is_atx(X_RIGHT_IO_DEVS_COL, model, dest_x))
strcat(buf[last_buf], "_W");
} else HERE();
} else HERE();
} else if (is_atx(X_OUTER_RIGHT, model, x)) {
if (is_aty(Y_CHIP_HORIZ_REGS, model, y))
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"REGR_%s", fpga_wire2str(wire));
else HERE();
} else HERE();
} else if (wire >= CLKPIN0 && wire <= CLKPIN7) {
wstr = "CLKPIN";
wnum = wire-CLKPIN0;
if (is_aty(Y_OUTER_TOP, model, y)) {
if (is_atx(X_CENTER_CMTPLL_COL, model, x))
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"REGT_%s", fpga_wire2str(wire));
else HERE();
} else if (is_aty(Y_INNER_TOP, model, y)) {
if (is_atx(X_CENTER_LOGIC_COL, model, x))
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"IOI_REGT_%s", fpga_wire2str(wire));
else if (is_atx(X_CENTER_CMTPLL_COL, model, x))
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"REGT_TTERM_%s", fpga_wire2str(wire));
else if (is_atx(X_CENTER_REGS_COL, model, x))
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"REGV_TTERM_%s", fpga_wire2str(wire));
else if (x == model->center_x + CENTER_X_PLUS_1)
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"IOI_TTERM_%s", fpga_wire2str(wire));
else if (x == model->center_x + CENTER_X_PLUS_2) {
if (wnum >= 4)
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"IOI_REGT_%s", fpga_wire2str(wire-4));
else
HERE();
} else HERE();
} else if (is_aty(Y_INNER_BOTTOM, model, y)) {
if (is_atx(X_CENTER_LOGIC_COL, model, x)) {
if (wnum >= 4) {
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"BTERM_CLB_%s", fpga_wire2str(wire));
} else HERE();
} else if (is_atx(X_CENTER_CMTPLL_COL, model, x)) {
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"REGB_BTERM_%s", fpga_wire2str(wire));
} else if (is_atx(X_CENTER_REGS_COL, model, x)) {
if (wnum%8 < 4) {
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"REGV_BTERM_%s", fpga_wire2str(wire+4));
} else HERE();
} else if (x == model->center_x + CENTER_X_PLUS_1) {
if (wnum < 4)
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"IOI_BTERM_%s", fpga_wire2str(wire+4));
else HERE();
} else if (x == model->center_x + CENTER_X_PLUS_2) {
if (wnum < 4) {
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"BTERM_CLB_%s", fpga_wire2str(wire+4));
} else HERE();
} else HERE();
} else if (is_aty(Y_OUTER_BOTTOM, model, y)) {
if (is_atx(X_CENTER_CMTPLL_COL, model, x))
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"REGB_%s", fpga_wire2str(wire));
else HERE();
} else if (is_atx(X_OUTER_LEFT, model, x)) {
if (is_aty(Y_CHIP_HORIZ_REGS, model, y))
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"REGL_%s", fpga_wire2str(wire));
else HERE();
} else if (is_atx(X_INNER_LEFT, model, x)) {
if (is_aty(Y_CHIP_HORIZ_REGS, model, y)) {
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"REGH_LTERM_%s", fpga_wire2str(wire));
} else if (y == model->center_y + CENTER_Y_PLUS_1) {
if (wnum < 4) {
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"IOI_LTERM_%s", fpga_wire2str(wire));
} else HERE();
} else if (y == model->center_y + CENTER_Y_PLUS_2) {
if (wnum < 2) {
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"IOI_LTERM_%s", fpga_wire2str(wire));
} else HERE();
} else if (y == model->center_y - CENTER_Y_MINUS_1
|| y == model->center_y - CENTER_Y_MINUS_2) {
if (wnum >= 4)
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"IOI_LTERM_%s_EXT", fpga_wire2str(wire-4));
else HERE();
} else if (y == model->center_y - CENTER_Y_MINUS_3) {
if (wnum >= 4) {
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"IOI_LTERM_%s", fpga_wire2str(wire-4));
} else HERE();
} else if (y == model->center_y - CENTER_Y_MINUS_4) {
if (wnum >= 4) {
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"IOI_LTERM_%s", fpga_wire2str(wire-4));
} else HERE();
} else HERE();
} else if (is_atx(X_INNER_RIGHT, model, x)) {
if (is_aty(Y_CHIP_HORIZ_REGS, model, y)) {
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"REGH_RTERM_%s", fpga_wire2str(wire));
} else if (y == model->center_y + CENTER_Y_PLUS_1) {
if (wnum >= 4) {
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"IOI_RTERM_%s", fpga_wire2str(wire-4));
} else HERE();
} else if (y == model->center_y + CENTER_Y_PLUS_2) {
if (wnum >= 6) {
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"IOI_RTERM_%s", fpga_wire2str(wire-4));
if (is_atx(X_RIGHT_IO_DEVS_COL, model, dest_x))
strcat(buf[last_buf], "_W");
} else HERE();
} else if (y == model->center_y - CENTER_Y_MINUS_1
|| y == model->center_y - CENTER_Y_MINUS_2) {
if (wnum < 4)
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"IOI_RTERM_%s%s", fpga_wire2str(wire),
wnum < 8 ? "_EXT" : "");
else HERE();
} else if (y == model->center_y - CENTER_Y_MINUS_3) {
if (wnum < 4) {
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"IOI_RTERM_%s", fpga_wire2str(wire));
} else HERE();
} else if (y == model->center_y - CENTER_Y_MINUS_4) {
if (wnum < 4) {
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"IOI_RTERM_%s", fpga_wire2str(wire));
} else HERE();
} else HERE();
} else if (is_atx(X_OUTER_RIGHT, model, x)) {
if (is_aty(Y_CHIP_HORIZ_REGS, model, y))
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"REGR_%s", fpga_wire2str(wire));
else HERE();
} else HERE();
} else if ((wire >= DQSN0 && wire <= DQSN3)
|| (wire >= DQSP0 && wire <= DQSP3)) {
if (wire >= DQSN0 && wire <= DQSN3) {
wchar = 'N';
wnum = wire - DQSN0;
} else if (wire >= DQSP0 && wire <= DQSP3) {
wchar = 'P';
wnum = wire - DQSP0;
} else HERE();
if (is_aty(Y_OUTER_TOP, model, y)) {
if (is_atx(X_CENTER_CMTPLL_COL, model, x))
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"REGT_%s", fpga_wire2str(wire));
else HERE();
} else if (is_aty(Y_INNER_TOP, model, y)) {
if (is_atx(X_CENTER_LOGIC_COL, model, x)) {
if (wnum%8 < 4) {
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"IOI_REGT_%s", fpga_wire2str(wire));
if (is_atyx(YX_DEV_ILOGIC, model, dest_y, dest_x))
strcat(buf[last_buf], "_S");
} else HERE();
} else if (is_atx(X_CENTER_CMTPLL_COL, model, x))
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"REGT_TTERM_%s", fpga_wire2str(wire));
else if (is_atx(X_CENTER_REGS_COL, model, x))
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"REGV_TTERM_%s", fpga_wire2str(wire));
else if (x == model->center_x + CENTER_X_PLUS_1)
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"IOI_TTERM_%s", fpga_wire2str(wire));
else if (x == model->center_x + CENTER_X_PLUS_2) {
if (wnum%8 >= 2) {
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"IOI_REGT_%s", fpga_wire2str(wire-2));
if (is_atyx(YX_DEV_ILOGIC, model, dest_y, dest_x))
strcat(buf[last_buf], "_S");
} else HERE();
} else HERE();
} else if (is_aty(Y_TOP_OUTER_IO, model, y)) {
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"TIOI_%s_OUT%c%s",
wnum%2 ? "INNER" : "UPPER", wchar,
wnum%2 ? "_EXT" : "");
} else if (is_aty(Y_TOP_INNER_IO, model, y)) {
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"TIOI_INNER_OUT%c", wchar);
} else if (is_aty(Y_BOT_INNER_IO, model, y)) {
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"BIOI_INNER_OUT%c", wchar);
} else if (is_aty(Y_BOT_OUTER_IO, model, y)) {
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"BIOI_%s_OUT%c%s",
wnum%2 ? "INNER" : "OUTER", wchar,
wnum%2 ? "_EXT" : "");
} else if (is_aty(Y_INNER_BOTTOM, model, y)) {
if (is_atx(X_CENTER_LOGIC_COL, model, x)) {
if (wnum >= 2) {
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"BTERM_CLB_%s", fpga_wire2str(wire));
if (is_atyx(YX_DEV_ILOGIC, model, dest_y, dest_x))
strcat(buf[last_buf], "_N");
} else HERE();
} else if (is_atx(X_CENTER_CMTPLL_COL, model, x)) {
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"REGB_BTERM_%s", fpga_wire2str(wire));
} else if (is_atx(X_CENTER_REGS_COL, model, x)) {
if (wnum < 2) {
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"REGV_BTERM_%s", fpga_wire2str(wire+2));
} else HERE();
} else if (x == model->center_x + CENTER_X_PLUS_1) {
if (wnum < 2)
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"IOI_BTERM_%s", fpga_wire2str(wire+2));
else HERE();
} else if (x == model->center_x + CENTER_X_PLUS_2) {
if (wnum < 2) {
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"BTERM_CLB_%s", fpga_wire2str(wire+2));
if (is_atyx(YX_DEV_ILOGIC, model, dest_y, dest_x))
strcat(buf[last_buf], "_N");
} else HERE();
} else HERE();
} else if (is_aty(Y_OUTER_BOTTOM, model, y)) {
if (is_atx(X_CENTER_CMTPLL_COL, model, x))
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"REGB_%s", fpga_wire2str(wire));
else HERE();
} else if (is_atx(X_OUTER_LEFT, model, x)) {
if (is_aty(Y_CHIP_HORIZ_REGS, model, y))
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"REGL_%s", fpga_wire2str(wire));
else HERE();
} else if (is_atx(X_INNER_LEFT, model, x)) {
if (is_aty(Y_CHIP_HORIZ_REGS, model, y)) {
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"REGH_LTERM_%s", fpga_wire2str(wire));
} else if (y == model->center_y + CENTER_Y_PLUS_1) {
if (wnum%8 < 4) {
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"IOI_LTERM_TOP_%s", fpga_wire2str(wire));
if (is_atx(X_LEFT_IO_ROUTING_COL|X_LEFT_IO_DEVS_COL, model, dest_x))
strcat(buf[last_buf], "_E");
} else HERE();
} else if (y == model->center_y + CENTER_Y_PLUS_2) {
if (wnum%8 < 2) {
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"IOI_LTERM_BOT_%s", fpga_wire2str(wire));
if (is_atx(X_LEFT_IO_ROUTING_COL|X_LEFT_IO_DEVS_COL, model, dest_x))
strcat(buf[last_buf], "_E");
} else HERE();
} else if (y == model->center_y - CENTER_Y_MINUS_1
|| y == model->center_y - CENTER_Y_MINUS_2) {
if (wnum >= 2)
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"IOI_LTERM_%s_EXT", fpga_wire2str(wire-2));
else HERE();
} else if (y == model->center_y - CENTER_Y_MINUS_3) {
if (wnum >= 2) {
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"IOI_LTERM_BOT_%s", fpga_wire2str(wire-2));
if (is_atx(X_LEFT_IO_ROUTING_COL|X_LEFT_IO_DEVS_COL, model, dest_x))
strcat(buf[last_buf], "_E");
} else HERE();
} else if (y == model->center_y - CENTER_Y_MINUS_4) {
if (wnum >= 2) {
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"IOI_LTERM_TOP_%s", fpga_wire2str(wire-2));
if (is_atx(X_LEFT_IO_ROUTING_COL|X_LEFT_IO_DEVS_COL, model, dest_x))
strcat(buf[last_buf], "_E");
} else HERE();
} else HERE();
} else if (is_atx(X_LEFT_IO_ROUTING_COL, model, x)) {
snprintf(buf[last_buf], sizeof(buf[last_buf]), "INT_OUT%c", wchar);
} else if (is_atx(X_LEFT_IO_DEVS_COL, model, x)) {
snprintf(buf[last_buf], sizeof(buf[last_buf]), "LIOI_OUT%c", wchar);
} else if (is_atx(X_RIGHT_IO_DEVS_COL, model, x)) {
snprintf(buf[last_buf], sizeof(buf[last_buf]), "RIOI_OUT%c", wchar);
} else if (is_atx(X_INNER_RIGHT, model, x)) {
if (is_aty(Y_CHIP_HORIZ_REGS, model, y)) {
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"REGH_RTERM_%s", fpga_wire2str(wire));
} else if (y == model->center_y + CENTER_Y_PLUS_1) {
if (wnum >= 2) {
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"IOI_RTERM_TOP_%s", fpga_wire2str(wire-2));
if (is_atx(X_RIGHT_IO_DEVS_COL, model, dest_x))
strcat(buf[last_buf], "_W");
} else HERE();
} else if (y == model->center_y + CENTER_Y_PLUS_2) {
if (wnum >= 3) {
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"IOI_RTERM_BOT_%s", fpga_wire2str(wire-2));
if (is_atx(X_RIGHT_IO_DEVS_COL, model, dest_x))
strcat(buf[last_buf], "_W");
} else HERE();
} else if (y == model->center_y - CENTER_Y_MINUS_1
|| y == model->center_y - CENTER_Y_MINUS_2) {
if (wnum < 2)
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"IOI_RTERM_%s%s", fpga_wire2str(wire),
wnum < 8 ? "_EXT" : "");
else HERE();
} else if (y == model->center_y - CENTER_Y_MINUS_3) {
if (wnum < 2) {
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"IOI_RTERM_BOT_%s", fpga_wire2str(wire));
if (is_atx(X_RIGHT_IO_DEVS_COL, model, dest_x))
strcat(buf[last_buf], "_W");
} else HERE();
} else if (y == model->center_y - CENTER_Y_MINUS_4) {
if (wnum < 2) {
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"IOI_RTERM_TOP_%s", fpga_wire2str(wire));
if (is_atx(X_RIGHT_IO_DEVS_COL, model, dest_x))
strcat(buf[last_buf], "_W");
} else HERE();
} else HERE();
} else if (is_atx(X_OUTER_RIGHT, model, x)) {
if (is_aty(Y_CHIP_HORIZ_REGS, model, y))
snprintf(buf[last_buf], sizeof(buf[last_buf]),
"REGR_%s", fpga_wire2str(wire));
else HERE();
} else HERE();
} else HERE();
return buf[last_buf];
}
const char* fpga_wire2str(enum extra_wires wire)
{
enum { NUM_BUFS = 8, BUF_SIZE = MAX_WIRENAME_LEN };
static char buf[NUM_BUFS][BUF_SIZE];
static int last_buf = 0;
int flags;
switch (wire) {
case GFAN0: return "GFAN0";
case GFAN1: return "GFAN1";
case CLK0: return "CLK0";
case CLK1: return "CLK1";
case SR0: return "SR0";
case SR1: return "SR1";
case GND_WIRE: return "GND_WIRE";
case VCC_WIRE: return "VCC_WIRE";
case FAN_B: return "FAN_B";
case LOGICIN20: return "LOGICIN20";
case LOGICIN21: return "LOGICIN21";
case LOGICIN44: return "LOGICIN44";
case LOGICIN52: return "LOGICIN52";
case LOGICIN_N21: return "LOGICIN_N21";
case LOGICIN_N28: return "LOGICIN_N28";
case LOGICIN_N52: return "LOGICIN_N52";
case LOGICIN_N60: return "LOGICIN_N60";
case LOGICIN_S20: return "LOGICIN_S20";
case LOGICIN_S36: return "LOGICIN_S36";
case LOGICIN_S44: return "LOGICIN_S44";
case LOGICIN_S62: return "LOGICIN_S62";
case IOCE: return "IOCE";
case IOCLK: return "IOCLK";
case PLLCE: return "PLLCE";
case PLLCLK: return "PLLCLK";
case CKPIN: return "CKPIN";
case CLK_FEEDBACK: return "CLK_FEEDBACK";
case CLK_INDIRECT: return "CLK_INDIRECT";
case CFB0: return "CFB0";
case CFB1: return "CFB1";
case CFB2: return "CFB2";
case CFB3: return "CFB3";
case CFB4: return "CFB4";
case CFB5: return "CFB5";
case CFB6: return "CFB6";
case CFB7: return "CFB7";
case CFB8: return "CFB1_0";
case CFB9: return "CFB1_1";
case CFB10: return "CFB1_2";
case CFB11: return "CFB1_3";
case CFB12: return "CFB1_4";
case CFB13: return "CFB1_5";
case CFB14: return "CFB1_6";
case CFB15: return "CFB1_7";
case DFB0: return "DFB0";
case DFB1: return "DFB1";
case DFB2: return "DFB2";
case DFB3: return "DFB3";
case DFB4: return "DFB4";
case DFB5: return "DFB5";
case DFB6: return "DFB6";
case DFB7: return "DFB7";
case CLKPIN0: return "CLKPIN0";
case CLKPIN1: return "CLKPIN1";
case CLKPIN2: return "CLKPIN2";
case CLKPIN3: return "CLKPIN3";
case CLKPIN4: return "CLKPIN4";
case CLKPIN5: return "CLKPIN5";
case CLKPIN6: return "CLKPIN6";
case CLKPIN7: return "CLKPIN7";
case DQSN0: return "DQSN0";
case DQSN1: return "DQSN1";
case DQSN2: return "DQSN2";
case DQSN3: return "DQSN3";
case DQSP0: return "DQSP0";
case DQSP1: return "DQSP1";
case DQSP2: return "DQSP2";
case DQSP3: return "DQSP3";
default: ;
}
last_buf = (last_buf+1)%NUM_BUFS;
buf[last_buf][0] = 0;
if (wire >= LOGICOUT_B0 && wire <= LOGICOUT_B0+LOGICOUT_HIGHEST)
snprintf(buf[last_buf], sizeof(buf[0]), "LOGICOUT%i", wire-LOGICOUT_B0);
else if (wire >= LOGICIN_B0 && wire <= LOGICIN_B0+LOGICIN_HIGHEST)
snprintf(buf[last_buf], sizeof(buf[0]), "LOGICIN%i", wire-LOGICIN_B0);
else if (wire >= GCLK0 && wire <= GCLK15)
snprintf(buf[last_buf], sizeof(buf[0]), "GCLK%i", wire-GCLK0);
else if (wire >= DW && wire <= DW_LAST) {
char beg_end;
wire -= DW;
flags = wire & DIR_FLAGS;
wire &= ~DIR_FLAGS;
beg_end = (flags & DIR_BEG) ? 'B' : 'E';
if (flags & DIR_S0 && wire%4 == 0)
snprintf(buf[last_buf], sizeof(buf[0]),
"%s%c_S0", wire_base(wire/4), beg_end);
else if (flags & DIR_N3 && wire%4 == 3)
snprintf(buf[last_buf], sizeof(buf[0]),
"%s%c_N3", wire_base(wire/4), beg_end);
else
snprintf(buf[last_buf], sizeof(buf[0]),
"%s%c%i", wire_base(wire/4), beg_end, wire%4);
} else if (wire >= LW && wire <= LW_LAST) {
wire -= LW;
if ((wire&(~LD1)) >= LI_FIRST && (wire&(~LD1)) <= LI_LAST)
snprintf(buf[last_buf], sizeof(buf[0]), "LOGICIN_B%i", fdev_logic_inbit(wire));
else if ((wire&(~LD1)) >= LO_FIRST && (wire&(~LD1)) <= LO_LAST)
snprintf(buf[last_buf], sizeof(buf[0]), "LOGICOUT%i", fdev_logic_outbit(wire));
else HERE();
} else if (wire >= BW && wire <= BW_LAST) {
const char* bram_pref;
int bram_w;
wire -= BW;
flags = wire & BW_FLAGS;
bram_w = wire & ~BW_FLAGS;
if (flags & B8_0)
bram_pref = "RAMB8BWER_0_";
else if (flags & B8_1)
bram_pref = "RAMB8BWER_1_";
else
bram_pref = "RAMB16BWER_";
if (bram_w >= BI_ADDRA0 && bram_w <= BI_ADDRA13) {
snprintf(buf[last_buf], sizeof(buf[0]), "%sADDRA%i", bram_pref, bram_w-BI_ADDRA0);
} else if (bram_w >= BI_ADDRB0 && bram_w <= BI_ADDRB13) {
snprintf(buf[last_buf], sizeof(buf[0]), "%sADDRB%i", bram_pref, bram_w-BI_ADDRB0);
} else if (bram_w >= BI_DIA0 && bram_w <= BI_DIA31) {
snprintf(buf[last_buf], sizeof(buf[0]), "%sDIA%i", bram_pref, bram_w-BI_DIA0);
} else if (bram_w >= BI_DIB0 && bram_w <= BI_DIB31) {
snprintf(buf[last_buf], sizeof(buf[0]), "%sDIB%i", bram_pref, bram_w-BI_DIB0);
} else if (bram_w >= BI_DIPA0 && bram_w <= BI_DIPA3) {
snprintf(buf[last_buf], sizeof(buf[0]), "%sDIPA%i", bram_pref, bram_w-BI_DIPA0);
} else if (bram_w >= BI_DIPB0 && bram_w <= BI_DIPB3) {
snprintf(buf[last_buf], sizeof(buf[0]), "%sDIPB%i", bram_pref, bram_w-BI_DIPB0);
} else if (bram_w >= BO_DOA0 && bram_w <= BO_DOA31) {
snprintf(buf[last_buf], sizeof(buf[0]), "%sDOA%i", bram_pref, bram_w-BO_DOA0);
} else if (bram_w >= BO_DOB0 && bram_w <= BO_DOB31) {
snprintf(buf[last_buf], sizeof(buf[0]), "%sDOB%i", bram_pref, bram_w-BO_DOB0);
} else if (bram_w >= BO_DOPA0 && bram_w <= BO_DOPA3) {
snprintf(buf[last_buf], sizeof(buf[0]), "%sDOPA%i", bram_pref, bram_w-BO_DOPA0);
} else if (bram_w >= BO_DOPB0 && bram_w <= BO_DOPB3) {
snprintf(buf[last_buf], sizeof(buf[0]), "%sDOPB%i", bram_pref, bram_w-BO_DOPB0);
} else if (bram_w >= BI_WEA0 && bram_w <= BI_WEA3) {
snprintf(buf[last_buf], sizeof(buf[0]), "%sWEA%i", bram_pref, bram_w-BI_WEA0);
} else if (bram_w >= BI_WEB0 && bram_w <= BI_WEB3) {
snprintf(buf[last_buf], sizeof(buf[0]), "%sWEB%i", bram_pref, bram_w-BI_WEB0);
} else if (bram_w == BI_REGCEA) {
snprintf(buf[last_buf], sizeof(buf[0]), "%sREGCEA", bram_pref);
} else if (bram_w == BI_REGCEB) {
snprintf(buf[last_buf], sizeof(buf[0]), "%sREGCEB", bram_pref);
} else if (bram_w == BI_ENA) {
snprintf(buf[last_buf], sizeof(buf[0]), "%sENA", bram_pref);
} else if (bram_w == BI_ENB) {
snprintf(buf[last_buf], sizeof(buf[0]), "%sENB", bram_pref);
} else HERE();
} else if (wire >= MW && wire <= MW_LAST) {
int macc_w = wire - MW;
if (macc_w >= MI_A0 && macc_w <= MI_A17)
snprintf(buf[last_buf], sizeof(buf[0]), "A%i_DSP48A1_SITE", macc_w-MI_A0);
else if (macc_w >= MI_B0 && macc_w <= MI_B17)
snprintf(buf[last_buf], sizeof(buf[0]), "B%i_DSP48A1_SITE", macc_w-MI_B0);
else if (macc_w >= MI_C0 && macc_w <= MI_C47)
snprintf(buf[last_buf], sizeof(buf[0]), "C%i_DSP48A1_SITE", macc_w-MI_C0);
else if (macc_w >= MI_D0 && macc_w <= MI_D17)
snprintf(buf[last_buf], sizeof(buf[0]), "D%i_DSP48A1_SITE", macc_w-MI_D0);
else if (macc_w >= MI_OPMODE0 && macc_w <= MI_OPMODE7)
snprintf(buf[last_buf], sizeof(buf[0]), "OPMODE%i_DSP48A1_SITE", macc_w-MI_OPMODE0);
else if (macc_w >= MO_P0 && macc_w <= MO_P47)
snprintf(buf[last_buf], sizeof(buf[0]), "P%i_DSP48A1_SITE", macc_w-MO_P0);
else if (macc_w >= MO_M0 && macc_w <= MO_M35)
snprintf(buf[last_buf], sizeof(buf[0]), "M%i_DSP48A1_SITE", macc_w-MO_M0);
else if (macc_w == MI_CEA)
snprintf(buf[last_buf], sizeof(buf[0]), "CEA_DSP48A1_SITE");
else if (macc_w == MI_CEB)
snprintf(buf[last_buf], sizeof(buf[0]), "CEB_DSP48A1_SITE");
else if (macc_w == MI_CEC)
snprintf(buf[last_buf], sizeof(buf[0]), "CEC_DSP48A1_SITE");
else if (macc_w == MI_CED)
snprintf(buf[last_buf], sizeof(buf[0]), "CED_DSP48A1_SITE");
else if (macc_w == MI_CEM)
snprintf(buf[last_buf], sizeof(buf[0]), "CEM_DSP48A1_SITE");
else if (macc_w == MI_CEP)
snprintf(buf[last_buf], sizeof(buf[0]), "CEP_DSP48A1_SITE");
else if (macc_w == MI_CE_OPMODE)
snprintf(buf[last_buf], sizeof(buf[0]), "CEOPMODE_DSP48A1_SITE");
else if (macc_w == MI_CE_CARRYIN)
snprintf(buf[last_buf], sizeof(buf[0]), "CECARRYIN_DSP48A1_SITE");
else if (macc_w == MO_CARRYOUT)
snprintf(buf[last_buf], sizeof(buf[0]), "CARRYOUTF_DSP48A1_SITE");
else HERE();
} else fprintf(stderr, "#E %s:%i unsupported wire %i\n", __FILE__, __LINE__, wire);
return buf[last_buf];
}
str16_t fpga_wire2str_i(struct fpga_model* model, enum extra_wires wire)
{
return strarray_find(&model->str, fpga_wire2str(wire));
}
enum extra_wires fpga_str2wire(const char* str)
{
const char* _str;
enum wire_type wtype;
int len, num, flags;
_str = str;
if (!strncmp(_str, "INT_IOI_", 8))
_str = &_str[8];
if (!strncmp(_str, "GCLK", 4)) {
len = strlen(_str);
if (!strcmp(&_str[len-4], "_BRK"))
len -= 4;
if (len > 4) {
num = to_i(&_str[4], len-4);
if (num >= 0 && num <= 15)
return GCLK0 + num;
}
}
if (!strncmp(_str, "LOGICIN_B", 9)) {
len = strlen(&_str[9]);
if (len) {
switch (to_i(&_str[9], len)) {
case X_A1: return LW + LI_A1;
case X_A2: return LW + LI_A2;
case X_A3: return LW + LI_A3;
case X_A4: return LW + LI_A4;
case X_A5: return LW + LI_A5;
case X_A6: return LW + LI_A6;
case X_AX: return LW + LI_AX;
case X_B1: return LW + LI_B1;
case X_B2: return LW + LI_B2;
case X_B3: return LW + LI_B3;
case X_B4: return LW + LI_B4;
case X_B5: return LW + LI_B5;
case X_B6: return LW + LI_B6;
case X_BX: return LW + LI_BX;
case X_C1: return LW + LI_C1;
case X_C2: return LW + LI_C2;
case X_C3: return LW + LI_C3;
case X_C4: return LW + LI_C4;
case X_C5: return LW + LI_C5;
case X_C6: return LW + LI_C6;
case X_CE: return LW + LI_CE;
case X_CX: return LW + LI_CX;
case X_D1: return LW + LI_D1;
case X_D2: return LW + LI_D2;
case X_D3: return LW + LI_D3;
case X_D4: return LW + LI_D4;
case X_D5: return LW + LI_D5;
case X_D6: return LW + LI_D6;
case X_DX: return LW + LI_DX;
case M_A1: return LW + (LI_A1|LD1);
case M_A2: return LW + (LI_A2|LD1);
case M_A3: return LW + (LI_A3|LD1);
case M_A4: return LW + (LI_A4|LD1);
case M_A5: return LW + (LI_A5|LD1);
case M_A6: return LW + (LI_A6|LD1);
case M_AX: return LW + (LI_AX|LD1);
case M_AI: return LW + (LI_AI|LD1);
case M_B1: return LW + (LI_B1|LD1);
case M_B2: return LW + (LI_B2|LD1);
case M_B3: return LW + (LI_B3|LD1);
case M_B4: return LW + (LI_B4|LD1);
case M_B5: return LW + (LI_B5|LD1);
case M_B6: return LW + (LI_B6|LD1);
case M_BX: return LW + (LI_BX|LD1);
case M_BI: return LW + (LI_BI|LD1);
case M_C1: return LW + (LI_C1|LD1);
case M_C2: return LW + (LI_C2|LD1);
case M_C3: return LW + (LI_C3|LD1);
case M_C4: return LW + (LI_C4|LD1);
case M_C5: return LW + (LI_C5|LD1);
case M_C6: return LW + (LI_C6|LD1);
case M_CE: return LW + (LI_CE|LD1);
case M_CX: return LW + (LI_CX|LD1);
case M_CI: return LW + (LI_CI|LD1);
case M_D1: return LW + (LI_D1|LD1);
case M_D2: return LW + (LI_D2|LD1);
case M_D3: return LW + (LI_D3|LD1);
case M_D4: return LW + (LI_D4|LD1);
case M_D5: return LW + (LI_D5|LD1);
case M_D6: return LW + (LI_D6|LD1);
case M_DX: return LW + (LI_DX|LD1);
case M_DI: return LW + (LI_DI|LD1);
case M_WE: return LW + (LI_WE|LD1);
}
}
}
if (!strncmp(_str, "LOGICOUT", 8)) {
len = strlen(&_str[8]);
if (len) {
switch (to_i(&_str[8], len)) {
case M_A: return LW + (LO_A|LD1);
case M_AMUX: return LW + (LO_AMUX|LD1);
case M_AQ: return LW + (LO_AQ|LD1);
case M_B: return LW + (LO_B|LD1);
case M_BMUX: return LW + (LO_BMUX|LD1);
case M_BQ: return LW + (LO_BQ|LD1);
case M_C: return LW + (LO_C|LD1);
case M_CMUX: return LW + (LO_CMUX|LD1);
case M_CQ: return LW + (LO_CQ|LD1);
case M_D: return LW + (LO_D|LD1);
case M_DMUX: return LW + (LO_DMUX|LD1);
case M_DQ: return LW + (LO_DQ|LD1);
case X_A: return LW + LO_A;
case X_AMUX: return LW + LO_AMUX;
case X_AQ: return LW + LO_AQ;
case X_B: return LW + LO_B;
case X_BMUX: return LW + LO_BMUX;
case X_BQ: return LW + LO_BQ;
case X_C: return LW + LO_C;
case X_CMUX: return LW + LO_CMUX;
case X_CQ: return LW + LO_CQ;
case X_D: return LW + LO_D;
case X_DMUX: return LW + LO_DMUX;
case X_DQ: return LW + LO_DQ;
}
}
}
if (!strcmp(_str, "GFAN0")) return GFAN0;
if (!strcmp(_str, "GFAN1")) return GFAN1;
if (!strcmp(_str, "CLK0")) return CLK0;
if (!strcmp(_str, "CLK1")) return CLK1;
if (!strcmp(_str, "SR0")) return SR0;
if (!strcmp(_str, "SR1")) return SR1;
if (!strcmp(_str, "GND_WIRE")) return GND_WIRE;
if (!strcmp(_str, "VCC_WIRE")) return VCC_WIRE;
if (!strcmp(_str, "FAN_B")) return FAN_B;
if (!strncmp(_str, "LOGICIN", 7)) {
if (!strcmp(&_str[7], "20")) return LOGICIN20;
if (!strcmp(&_str[7], "21")) return LOGICIN21;
if (!strcmp(&_str[7], "44")) return LOGICIN44;
if (!strcmp(&_str[7], "52")) return LOGICIN52;
if (!strcmp(&_str[7], "_N21")) return LOGICIN_N21;
if (!strcmp(&_str[7], "_N28")) return LOGICIN_N28;
if (!strcmp(&_str[7], "_N52")) return LOGICIN_N52;
if (!strcmp(&_str[7], "_N60")) return LOGICIN_N60;
if (!strcmp(&_str[7], "_S20")) return LOGICIN_S20;
if (!strcmp(&_str[7], "_S36")) return LOGICIN_S36;
if (!strcmp(&_str[7], "_S44")) return LOGICIN_S44;
if (!strcmp(&_str[7], "_S62")) return LOGICIN_S62;
}
if ((wtype = base2wire(_str))) {
flags = 0;
if (_str[3] == 'B')
flags |= DIR_BEG;
if (_str[3] != 'B' && _str[3] != 'E')
HERE();
else {
if (!strcmp(&_str[4], "_S0")) {
num = 0;
flags |= DIR_S0;
} else if (!strcmp(&_str[4], "_N3")) {
num = 3;
flags |= DIR_N3;
} else switch (_str[4]) {
case '0': num = 0; break;
case '1': num = 1; break;
case '2': num = 2; break;
case '3': num = 3; break;
default:
HERE();
num = -1;
break;
}
if (num != -1)
return DW + ((wtype*4 + num)|flags);
}
}
HERE();
return NO_WIRE;
}
int fdev_logic_inbit(pinw_idx_t idx)
{
if (idx & LD1) {
idx &= ~LD1;
if (idx >= LI_A1 && idx <= LI_C6)
return M_A1 + (idx/6)*8+idx%6;
if (idx >= LI_D1 && idx <= LI_D6)
return M_D1 + (idx-LI_D1);
switch (idx) {
case LI_AX: return M_AX;
case LI_BX: return M_BX;
case LI_CE: return M_CE;
case LI_CX: return M_CX;
case LI_DX: return M_DX;
case LI_AI: return M_AI;
case LI_BI: return M_BI;
case LI_CI: return M_CI;
case LI_DI: return M_DI;
case LI_WE: return M_WE;
}
HERE();
return -1;
}
if (idx >= LI_A1 && idx <= LI_C6)
return X_A1 + (idx/6)*7+idx%6;
else if (idx >= LI_D1 && idx <= LI_D6)
return X_D1 + (idx-LI_D1);
else switch (idx) {
case LI_AX: return X_AX;
case LI_BX: return X_BX;
case LI_CE: return X_CE;
case LI_CX: return X_CX;
case LI_DX: return X_DX;
}
HERE();
return -1;
}
int fdev_logic_outbit(pinw_idx_t idx)
{
if (idx & LD1) {
idx &= ~LD1;
switch (idx) {
case LO_A: return M_A;
case LO_AMUX: return M_AMUX;
case LO_AQ: return M_AQ;
case LO_B: return M_B;
case LO_BMUX: return M_BMUX;
case LO_BQ: return M_BQ;
case LO_C: return M_C;
case LO_CMUX: return M_CMUX;
case LO_CQ: return M_CQ;
case LO_D: return M_D;
case LO_DMUX: return M_DMUX;
case LO_DQ: return M_DQ;
}
HERE();
return -1;
}
switch (idx) {
case LO_A: return X_A;
case LO_AMUX: return X_AMUX;
case LO_AQ: return X_AQ;
case LO_B: return X_B;
case LO_BMUX: return X_BMUX;
case LO_BQ: return X_BQ;
case LO_C: return X_C;
case LO_CMUX: return X_CMUX;
case LO_CQ: return X_CQ;
case LO_D: return X_D;
case LO_DMUX: return X_DMUX;
case LO_DQ: return X_DQ;
}
HERE();
return -1;
}
void fdev_bram_inbit(enum extra_wires wire, int* tile0_to_3, int* wire0_to_62)
{
const int ramb16_map[4*63] = {
// tile #3 (topmost)
/* 0*/ 0, BW+BI_DIB25, 0, BW+BI_DIB24,
/* 4*/ BW+BI_DIB22, 0, 0, 0,
/* 8*/ BW+BI_DIB31, BW+BI_DIB29, BW+BI_WEA0, 0,
/*12*/ 0, 0, 0, 0,
/*16*/ 0, 0, 0, BW+BI_DIB26,
/*20*/ 0, 0, 0, BW+BI_DIB19,
/*24*/ BW+BI_ADDRB13, BW+BI_REGCEB, BW+BI_DIPB2, BW+BI_DIB27,
/*28*/ 0, 0, BW+BI_WEA1, 0,
/*32*/ 0, 0, 0, 0,
/*36*/ 0, 0, BW+BI_DIB18, BW+BI_DIB30,
/*40*/ 0, BW+BI_DIPB3, 0, 0,
/*44*/ BW+BI_WEA3, 0, 0, BW+BI_DIB17,
/*48*/ 0, 0, 0, 0,
/*52*/ 0, 0, BW+BI_DIB20, BW+BI_DIB23,
/*56*/ 0, BW+BI_DIB21, BW+BI_WEA2, BW+BI_DIB28,
/*60*/ 0, 0, BW+BI_DIB16,
// tile #2
/* 0*/ 0, 0, 0, BW+BI_DIA27,
/* 4*/ BW+BI_ADDRB10, BW+BI_ADDRB2, 0, BW+BI_DIA17,
/* 8*/ 0, BW+BI_DIA31, BW+BI_ADDRB12, 0,
/*12*/ BW+BI_ADDRB3, 0, 0, BW+BI_DIA16,
/*16*/ BW+BI_DIA19, BW+BI_ADDRB7, 0, BW+BI_DIA28,
/*20*/ BW+BI_DIA20, 0, 0, BW+BI_DIA22,
/*24*/ BW+BI_ADDRB0, BW+BI_ADDRB9, BW+BI_DIA24, BW+BI_DIA30,
/*28*/ BW+BI_DIA29, 0, BW+BI_DIA25, 0,
/*32*/ BW+BI_REGCEA, 0, 0, 0,
/*36*/ BW+BI_DIA18, 0, BW+BI_DIA21, 0,
/*40*/ 0, BW+BI_DIA26, BW+BI_ADDRB1, 0,
/*44*/ BW+BI_DIPA2, BW+BI_ADDRB6, 0, BW+BI_ADDRB5,
/*48*/ BW+BI_DIA23, 0, 0, 0,
/*52*/ 0, 0, BW+BI_ENB, BW+BI_DIPA3,
/*56*/ 0, BW+BI_ADDRB8, BW+BI_ADDRB11, 0,
/*60*/ 0, 0, BW+BI_ADDRB4,
// tile #1
/* 0*/ 0, BW+BI_ADDRA5, BW+BI_DIB13, BW+BI_DIB8,
/* 4*/ BW+BI_DIB5, 0, 0, 0,
/* 8*/ BW+BI_ADDRA11, BW+BI_ADDRA8, BW+BI_ADDRA3, 0,
/*12*/ BW+BI_DIB0, 0, BW+BI_DIB14, 0,
/*16*/ 0, 0, 0, BW+BI_DIB9,
/*20*/ 0, 0, 0, BW+BI_DIB3,
/*24*/ 0, 0, BW+BI_DIB7, BW+BI_ADDRA6,
/*28*/ BW+BI_DIB10, BW+BI_DIB11, BW+BI_DIPB1, BW+BI_ADDRA12,
/*32*/ BW+BI_ADDRA7, 0, BW+BI_ADDRA0, 0,
/*36*/ 0, BW+BI_DIB15, BW+BI_DIB2, BW+BI_ADDRA10,
/*40*/ 0, BW+BI_DIPB0, 0, 0,
/*44*/ BW+BI_ADDRA2, 0, 0, BW+BI_DIB1,
/*48*/ BW+BI_ENA, 0, 0, 0,
/*52*/ BW+BI_ADDRA9, 0, BW+BI_ADDRA1, BW+BI_DIB6,
/*56*/ 0, BW+BI_DIB4, BW+BI_ADDRA4, BW+BI_DIB12,
/*60*/ 0, 0, 0,
// tile #0 (bottommost)
/* 0*/ 0, 0, 0, BW+BI_DIA11,
/* 4*/ BW+BI_WEB0, 0, 0, BW+BI_DIA1,
/* 8*/ 0, BW+BI_DIA15, BW+BI_DIA10, 0,
/*12*/ 0, 0, 0, BW+BI_DIA0,
/*16*/ BW+BI_DIA3, 0, 0, BW+BI_DIA12,
/*20*/ BW+BI_DIA4, 0, 0, BW+BI_DIA6,
/*24*/ 0, BW+BI_WEB1, BW+BI_DIA8, BW+BI_DIA13,
/*28*/ 0, 0, BW+BI_DIA9, BW+BI_ADDRA13,
/*32*/ BW+BI_DIA14, 0, BW+BI_WEB3, 0,
/*36*/ BW+BI_DIA2, 0, BW+BI_DIA5, 0,
/*40*/ 0, 0, 0, 0,
/*44*/ 0, 0, 0, 0,
/*48*/ BW+BI_DIA7, 0, 0, 0,
/*52*/ 0, 0, BW+BI_WEB2, BW+BI_DIPA1,
/*56*/ 0, BW+BI_DIPA0, 0, 0,
/*60*/ 0, 0, 0 };
const int ramb8_map[4*63] = {
// tile #3 (topmost)
/* 0*/ 0, BW+(B8_1|BI_DIB9), 0, BW+(B8_1|BI_DIB8),
/* 4*/ BW+(B8_1|BI_DIB6), BW+(B8_1|BI_ADDRB4), 0, BW+(B8_1|BI_ADDRB2),
/* 8*/ BW+(B8_1|BI_DIB15), BW+(B8_1|BI_DIB13), BW+(B8_0|BI_WEA0), 0,
/*12*/ BW+(B8_1|BI_ADDRB6), 0, 0, BW+(B8_1|BI_ADDRB1),
/*16*/ BW+(B8_1|BI_ADDRB8), BW+(B8_1|BI_ADDRB10), 0, BW+(B8_1|BI_DIB10),
/*20*/ BW+(B8_1|BI_ADDRB7), 0, 0, BW+(B8_1|BI_DIB3),
/*24*/ BW+(B8_1|BI_ADDRB0), BW+(B8_0|BI_REGCEB), BW+(B8_1|BI_DIPB0), BW+(B8_1|BI_DIB11),
/*28*/ 0, 0, BW+(B8_0|BI_WEA1), 0,
/*32*/ 0, 0, BW+(B8_1|BI_ADDRB11), 0,
/*36*/ BW+(B8_1|BI_ADDRB5), 0, BW+(B8_1|BI_DIB2), BW+(B8_1|BI_DIB14),
/*40*/ 0, BW+(B8_1|BI_DIPB1), BW+(B8_1|BI_ADDRB3), 0,
/*44*/ BW+(B8_1|BI_WEA1), BW+(B8_1|BI_ADDRB9), 0, BW+(B8_1|BI_DIB1),
/*48*/ BW+(B8_1|BI_ADDRB12), 0, 0, 0,
/*52*/ 0, 0, BW+(B8_1|BI_DIB4), BW+(B8_1|BI_DIB7),
/*56*/ 0, BW+(B8_1|BI_DIB5), BW+(B8_1|BI_WEA0), BW+(B8_1|BI_DIB12),
/*60*/ 0, 0, BW+(B8_1|BI_DIB0),
// tile #2
/* 0*/ 0, 0, 0, BW+(B8_1|BI_DIA11),
/* 4*/ BW+(B8_0|BI_ADDRB10), BW+(B8_0|BI_ADDRB2), 0, BW+(B8_1|BI_DIA1),
/* 8*/ 0, BW+(B8_1|BI_DIA15), BW+(B8_0|BI_ADDRB12), 0,
/*12*/ BW+(B8_0|BI_ADDRB3), 0, 0, BW+(B8_1|BI_DIA0),
/*16*/ BW+(B8_1|BI_DIA3), BW+(B8_0|BI_ADDRB7), 0, BW+(B8_1|BI_DIA12),
/*20*/ BW+(B8_1|BI_DIA4), 0, 0, BW+(B8_1|BI_DIA6),
/*24*/ BW+(B8_0|BI_ADDRB0), BW+(B8_0|BI_ADDRB9), BW+(B8_1|BI_DIA8), BW+(B8_1|BI_DIA14),
/*28*/ BW+(B8_1|BI_DIA13), BW+(B8_1|BI_REGCEA), BW+(B8_1|BI_DIA9), 0,
/*32*/ BW+(B8_0|BI_REGCEA), 0, BW+(B8_1|BI_ENB), 0,
/*36*/ BW+(B8_1|BI_DIA2), 0, BW+(B8_1|BI_DIA5), 0,
/*40*/ 0, BW+(B8_1|BI_DIA10), BW+(B8_0|BI_ADDRB1), 0,
/*44*/ BW+(B8_1|BI_DIPA0), BW+(B8_0|BI_ADDRB6), 0, BW+(B8_0|BI_ADDRB5),
/*48*/ BW+(B8_1|BI_DIA7), 0, 0, 0,
/*52*/ 0, 0, BW+(B8_0|BI_ENB), BW+(B8_1|BI_DIPA1),
/*56*/ 0, BW+(B8_0|BI_ADDRB8), BW+(B8_0|BI_ADDRB11), BW+(B8_1|BI_REGCEB),
/*60*/ 0, 0, BW+(B8_0|BI_ADDRB4),
// tile #1
/* 0*/ 0, BW+(B8_0|BI_ADDRA5), BW+(B8_0|BI_DIB13), BW+(B8_0|BI_DIB8),
/* 4*/ BW+(B8_0|BI_DIB5), 0, 0, 0,
/* 8*/ BW+(B8_0|BI_ADDRA11), BW+(B8_0|BI_ADDRA8), BW+(B8_0|BI_ADDRA3), 0,
/*12*/ BW+(B8_0|BI_DIB0), 0, BW+(B8_0|BI_DIB14), 0,
/*16*/ 0, 0, 0, BW+(B8_0|BI_DIB9),
/*20*/ 0, 0, 0, BW+(B8_0|BI_DIB3),
/*24*/ 0, BW+(B8_1|BI_ENA), BW+(B8_0|BI_DIB7), BW+(B8_0|BI_ADDRA6),
/*28*/ BW+(B8_0|BI_DIB10), BW+(B8_0|BI_DIB11), BW+(B8_0|BI_DIPB1), BW+(B8_0|BI_ADDRA12),
/*32*/ BW+(B8_0|BI_ADDRA7), 0, BW+(B8_0|BI_ADDRA0), 0,
/*36*/ 0, BW+(B8_0|BI_DIB15), BW+(B8_0|BI_DIB2), BW+(B8_0|BI_ADDRA10),
/*40*/ 0, BW+(B8_0|BI_DIPB0), 0, 0,
/*44*/ BW+(B8_0|BI_ADDRA2), 0, 0, BW+(B8_0|BI_DIB1),
/*48*/ BW+(B8_0|BI_ENA), 0, 0, 0,
/*52*/ BW+(B8_0|BI_ADDRA9), 0, BW+(B8_0|BI_ADDRA1), BW+(B8_0|BI_DIB6),
/*56*/ 0, BW+(B8_0|BI_DIB4), BW+(B8_0|BI_ADDRA4), BW+(B8_0|BI_DIB12),
/*60*/ 0, 0, 0,
// tile #0 (bottommost)
/* 0*/ 0, BW+(B8_1|BI_ADDRA3), BW+(B8_1|BI_ADDRA8), BW+(B8_0|BI_DIA11),
/* 4*/ BW+(B8_0|BI_WEB0), 0, 0, BW+(B8_0|BI_DIA1),
/* 8*/ BW+(B8_1|BI_ADDRA12), BW+(B8_0|BI_DIA15), BW+(B8_0|BI_DIA10), 0,
/*12*/ 0, 0, BW+(B8_1|BI_ADDRA9), BW+(B8_0|BI_DIA0),
/*16*/ BW+(B8_0|BI_DIA3), 0, 0, BW+(B8_0|BI_DIA12),
/*20*/ BW+(B8_0|BI_DIA4), 0, 0, BW+(B8_0|BI_DIA6),
/*24*/ 0, BW+(B8_0|BI_WEB1), BW+(B8_0|BI_DIA8), BW+(B8_0|BI_DIA13),
/*28*/ BW+(B8_1|BI_ADDRA4), BW+(B8_1|BI_ADDRA5), BW+(B8_0|BI_DIA9), BW+(B8_1|BI_ADDRA0),
/*32*/ BW+(B8_0|BI_DIA14), 0, BW+(B8_1|BI_WEB1), 0,
/*36*/ BW+(B8_0|BI_DIA2), BW+(B8_1|BI_ADDRA11), BW+(B8_0|BI_DIA5), BW+(B8_1|BI_ADDRA10),
/*40*/ 0, BW+(B8_1|BI_ADDRA1), 0, 0,
/*44*/ 0, 0, 0, 0,
/*48*/ BW+(B8_0|BI_DIA7), 0, 0, 0,
/*52*/ BW+(B8_1|BI_ADDRA7), 0, BW+(B8_1|BI_WEB0), BW+(B8_0|BI_DIPA1),
/*56*/ 0, BW+(B8_0|BI_DIPA0), BW+(B8_1|BI_ADDRA2), BW+(B8_1|BI_ADDRA6),
/*60*/ 0, 0, 0 };
const int *search_map;
int i;
if (wire < BW || wire > BW_LAST) {
HERE();
*tile0_to_3 = -1;
return;
}
search_map = ((wire-BW) & BW_FLAGS) ? ramb8_map : ramb16_map;
for (i = 0; i < 4*63; i++) {
if (search_map[i] == wire) {
*tile0_to_3 = 3-(i/63);
*wire0_to_62 = i%63;
return;
}
}
fprintf(stderr, "#E %s:%i unknown wire %i\n",
__FILE__, __LINE__, wire);
*tile0_to_3 = -1;
}
void fdev_bram_outbit(enum extra_wires wire, int* tile0_to_3, int* wire0_to_23)
{
const int ramb16_map[4*24] = {
// tile #3 (topmost)
/* 0*/ 0, BW+BO_DOPB3, 0, BW+BO_DOB27,
/* 4*/ BW+BO_DOA29, BW+BO_DOA25, BW+BO_DOB29, BW+BO_DOA24,
/* 8*/ BW+BO_DOPA3, BW+BO_DOB31, BW+BO_DOB25, BW+BO_DOA31,
/*12*/ BW+BO_DOB24, 0, 0, BW+BO_DOA27,
/*16*/ BW+BO_DOA30, BW+BO_DOA26, BW+BO_DOA28, 0,
/*20*/ BW+BO_DOB28, BW+BO_DOB30, BW+BO_DOB26, 0,
// tile #2
/* 0*/ BW+BO_DOA18, BW+BO_DOB20, BW+BO_DOA16, BW+BO_DOPB2,
/* 4*/ BW+BO_DOA23, BW+BO_DOB18, BW+BO_DOB22, 0,
/* 8*/ BW+BO_DOA20, 0, BW+BO_DOA19, 0,
/*12*/ BW+BO_DOB17, BW+BO_DOA22, BW+BO_DOA17, 0,
/*16*/ BW+BO_DOB23, BW+BO_DOB19, BW+BO_DOA21, BW+BO_DOB16,
/*20*/ BW+BO_DOB21, 0, BW+BO_DOPA2, 0,
// tile #1
/* 0*/ BW+BO_DOB8, BW+BO_DOPA1, 0, BW+BO_DOA11,
/* 4*/ BW+BO_DOB13, BW+BO_DOA9, BW+BO_DOA13, 0,
/* 8*/ BW+BO_DOB11, BW+BO_DOB15, BW+BO_DOB9, BW+BO_DOA15,
/*12*/ BW+BO_DOA8, BW+BO_DOB12, 0, 0,
/*16*/ BW+BO_DOA14, BW+BO_DOA10, BW+BO_DOPB1, 0,
/*20*/ BW+BO_DOA12, BW+BO_DOB14, BW+BO_DOB10, 0,
// tile #0 (bottommost)
/* 0*/ BW+BO_DOA2, BW+BO_DOB4, BW+BO_DOA0, BW+BO_DOPB0,
/* 4*/ BW+BO_DOB6, BW+BO_DOB2, BW+BO_DOA6, BW+BO_DOA1,
/* 8*/ BW+BO_DOA4, 0, BW+BO_DOA3, 0,
/*12*/ BW+BO_DOB1, BW+BO_DOB5, BW+BO_DOB0, BW+BO_DOPA0,
/*16*/ BW+BO_DOA7, BW+BO_DOB3, BW+BO_DOA5, 0,
/*20*/ 0, BW+BO_DOB7, 0, 0
};
const int ramb8_map[4*24] = {
// tile #3 (topmost)
/* 0*/ 0, BW+(BO_DOPB1|B8_1), 0, BW+(BO_DOB11|B8_1),
/* 4*/ BW+(BO_DOA13|B8_1), BW+(BO_DOA9|B8_1), BW+(BO_DOB13|B8_1), BW+(BO_DOA8|B8_1),
/* 8*/ BW+(BO_DOPA1|B8_1), BW+(BO_DOB15|B8_1), BW+(BO_DOB9|B8_1), BW+(BO_DOA15|B8_1),
/*12*/ BW+(BO_DOB8|B8_1), 0, 0, BW+(BO_DOA11|B8_1),
/*16*/ BW+(BO_DOA14|B8_1), BW+(BO_DOA10|B8_1), BW+(BO_DOA12|B8_1), 0,
/*20*/ BW+(BO_DOB12|B8_1), BW+(BO_DOB14|B8_1), BW+(BO_DOB10|B8_1), 0,
// tile #2
/* 0*/ BW+(BO_DOA2|B8_1), BW+(BO_DOB4|B8_1), BW+(BO_DOA0|B8_1), BW+(BO_DOPB0|B8_1),
/* 4*/ BW+(BO_DOA7|B8_1), BW+(BO_DOB2|B8_1), BW+(BO_DOB6|B8_1), 0,
/* 8*/ BW+(BO_DOA4|B8_1), 0, BW+(BO_DOA3|B8_1), 0,
/*12*/ BW+(BO_DOB1|B8_1), BW+(BO_DOA6|B8_1), BW+(BO_DOA1|B8_1), 0,
/*16*/ BW+(BO_DOB7|B8_1), BW+(BO_DOB3|B8_1), BW+(BO_DOA5|B8_1), BW+(BO_DOB0|B8_1),
/*20*/ BW+(BO_DOB5|B8_1), 0, BW+(BO_DOPA0|B8_1), 0,
// tile #1
/* 0*/ BW+(BO_DOB8|B8_0), BW+(BO_DOPA1|B8_0), 0, BW+(BO_DOA11|B8_0),
/* 4*/ BW+(BO_DOB13|B8_0), BW+(BO_DOA9|B8_0), BW+(BO_DOA13|B8_0), 0,
/* 8*/ BW+(BO_DOB11|B8_0), BW+(BO_DOB15|B8_0), BW+(BO_DOB9|B8_0), BW+(BO_DOA15|B8_0),
/*12*/ BW+(BO_DOA8|B8_0), BW+(BO_DOB12|B8_0), 0, 0,
/*16*/ BW+(BO_DOA14|B8_0), BW+(BO_DOA10|B8_0), BW+(BO_DOPB1|B8_0), 0,
/*20*/ BW+(BO_DOA12|B8_0), BW+(BO_DOB14|B8_0), BW+(BO_DOB10|B8_0), 0,
// tile #0 (bottommost)
/* 0*/ BW+(BO_DOA2|B8_0), BW+(BO_DOB4|B8_0), BW+(BO_DOA0|B8_0), BW+(BO_DOPB0|B8_0),
/* 4*/ BW+(BO_DOB6|B8_0), BW+(BO_DOB2|B8_0), BW+(BO_DOA6|B8_0), BW+(BO_DOA1|B8_0),
/* 8*/ BW+(BO_DOA4|B8_0), 0, BW+(BO_DOA3|B8_0), 0,
/*12*/ BW+(BO_DOB1|B8_0), BW+(BO_DOB5|B8_0), BW+(BO_DOB0|B8_0), BW+(BO_DOPA0|B8_0),
/*16*/ BW+(BO_DOA7|B8_0), BW+(BO_DOB3|B8_0), BW+(BO_DOA5|B8_0), 0,
/*20*/ 0, BW+(BO_DOB7|B8_0), 0, 0
};
const int *search_map;
int i;
if (wire < BW || wire > BW_LAST) {
HERE();
*tile0_to_3 = -1;
return;
}
search_map = ((wire-BW) & BW_FLAGS) ? ramb8_map : ramb16_map;
for (i = 0; i < 4*24; i++) {
if (search_map[i] == wire) {
*tile0_to_3 = 3-(i/24);
*wire0_to_23 = i%24;
return;
}
}
fprintf(stderr, "#E %s:%i unknown wire %i\n",
__FILE__, __LINE__, wire);
*tile0_to_3 = -1;
}
int fdev_is_bram8_inwire(int bi_wire)
{
if (bi_wire == BI_ADDRA13 || bi_wire == BI_ADDRB13)
return 0;
if (bi_wire == BI_WEA2 || bi_wire == BI_WEA3
|| bi_wire == BI_WEB2 || bi_wire == BI_WEB3)
return 0;
if (bi_wire == BI_DIPA2 || bi_wire == BI_DIPA3
|| bi_wire == BI_DIPB2 || bi_wire == BI_DIPB3)
return 0;
if ((bi_wire >= BI_DIA16 && bi_wire <= BI_DIA31)
|| (bi_wire >= BI_DIB16 && bi_wire <= BI_DIB31))
return 0;
return 1;
}
int fdev_is_bram8_outwire(int bo_wire)
{
if (bo_wire == BO_DOPA2 || bo_wire == BO_DOPA3
|| bo_wire == BO_DOPB2 || bo_wire == BO_DOPB3)
return 0;
if ((bo_wire >= BO_DOA16 && bo_wire <= BO_DOA31)
|| (bo_wire >= BO_DOB16 && bo_wire <= BO_DOB31))
return 0;
return 1;
}
void fdev_macc_inbit(enum extra_wires wire, int* tile0_to_3, int* wire0_to_62)
{
const int map[4*63] = {
// tile #3 (topmost)
/* 0*/ 0, MW+MI_A12, 0, MW+MI_C43,
/* 4*/ MW+MI_C40, 0, 0, MW+MI_A6,
/* 8*/ MW+MI_A17, 0, MW+MI_C42, 0,
/*12*/ 0, 0, MW+MI_A16, MW+MI_A5,
/*16*/ MW+MI_A7, MW+MI_C38, 0, MW+MI_A13,
/*20*/ 0, 0, 0, MW+MI_A8,
/*24*/ 0, 0, MW+MI_A10, MW+MI_C44,
/*28*/ 0, MW+MI_A14, MW+MI_A11, 0,
/*32*/ MW+MI_C45, 0, 0, 0,
/*36*/ MW+MI_C36, MW+MI_C47, 0, MW+MI_C46,
/*40*/ 0, 0, 0, 0,
/*44*/ MW+MI_A9, 0, 0, MW+MI_C37,
/*48*/ 0, 0, 0, 0,
/*52*/ MW+MI_A15, 0, 0, MW+MI_C41,
/*56*/ 0, MW+MI_C39, 0, 0,
/*60*/ 0, 0, 0,
// tile #2
/* 0*/ 0, 0, 0, MW+MI_C31,
/* 4*/ MW+MI_C28, 0, 0, MW+MI_D16,
/* 8*/ MW+MI_A4, 0, MW+MI_C30, 0,
/*12*/ MW+MI_D17, 0, MW+MI_C34, MW+MI_OPMODE3,
/*16*/ MW+MI_C24, MW+MI_CED, 0, MW+MI_A0,
/*20*/ MW+MI_C25, 0, 0, MW+MI_C26,
/*24*/ MW+MI_OPMODE7, 0, MW+MI_C29, MW+MI_C32,
/*28*/ 0, MW+MI_A1, MW+MI_CEA, MW+MI_C35,
/*32*/ 0, 0, MW+MI_CE_CARRYIN, 0,
/*36*/ MW+MI_B16, 0, 0, MW+MI_A3,
/*40*/ 0, MW+MI_CEB, MW+MI_OPMODE2, 0,
/*44*/ MW+MI_CEP, 0, 0, MW+MI_B17,
/*48*/ MW+MI_C27, 0, 0, 0,
/*52*/ MW+MI_A2, 0, 0, MW+MI_CE_OPMODE,
/*56*/ 0, MW+MI_CEC, MW+MI_CEM, MW+MI_C33,
/*60*/ 0, 0, MW+MI_OPMODE5,
// tile #1
/* 0*/ 0, MW+MI_B12, MW+MI_D14, 0,
/* 4*/ MW+MI_D11, MW+MI_OPMODE4, 0, 0,
/* 8*/ MW+MI_OPMODE1, MW+MI_C23, MW+MI_D12, 0,
/*12*/ 0, 0, MW+MI_D15, MW+MI_C12,
/*16*/ MW+MI_OPMODE6, MW+MI_C15, 0, MW+MI_C21,
/*20*/ 0, 0, 0, MW+MI_D10,
/*24*/ 0, 0, MW+MI_C18, MW+MI_B13,
/*28*/ MW+MI_D13, 0, 0, MW+MI_OPMODE0,
/*32*/ MW+MI_C22, 0, MW+MI_B9, 0,
/*36*/ MW+MI_C13, 0, 0, MW+MI_B15,
/*40*/ 0, MW+MI_C19, 0, 0,
/*44*/ MW+MI_C17, MW+MI_D9, 0, MW+MI_C14,
/*48*/ MW+MI_C16, 0, 0, 0,
/*52*/ MW+MI_B14, 0, 0, MW+MI_B11,
/*56*/ 0, MW+MI_B10, MW+MI_C20, 0,
/*60*/ 0, 0, 0,
// tile #0 (bottommost)
/* 0*/ 0, MW+MI_D5, 0, MW+MI_C8,
/* 4*/ MW+MI_C5, 0, 0, MW+MI_D0,
/* 8*/ MW+MI_D8, 0, 0, 0,
/*12*/ 0, 0, MW+MI_C11, MW+MI_C0,
/*16*/ 0, MW+MI_C3, 0, 0,
/*20*/ MW+MI_C2, 0, 0, MW+MI_C4,
/*24*/ 0, MW+MI_D2, MW+MI_D4, 0,
/*28*/ MW+MI_C9, MW+MI_B6, MW+MI_B4, MW+MI_B8,
/*32*/ MW+MI_C10, 0, MW+MI_B2, 0,
/*36*/ 0, MW+MI_B7, MW+MI_B1, MW+MI_D7,
/*40*/ 0, MW+MI_C7, MW+MI_B0, 0,
/*44*/ MW+MI_B3, 0, 0, MW+MI_D1,
/*48*/ 0, 0, 0, 0,
/*52*/ 0, 0, 0, MW+MI_C6,
/*56*/ 0, MW+MI_D3, MW+MI_B5, MW+MI_D6,
/*60*/ 0, 0, MW+MI_C1 };
int i;
if (wire < MW || wire > MW_LAST) {
HERE();
*tile0_to_3 = -1;
return;
}
for (i = 0; i < 4*63; i++) {
if (map[i] == wire) {
*tile0_to_3 = 3-(i/63);
*wire0_to_62 = i%63;
return;
}
}
fprintf(stderr, "#E %s:%i unknown wire %i\n",
__FILE__, __LINE__, wire);
*tile0_to_3 = -1;
}
void fdev_macc_outbit(enum extra_wires wire, int* tile0_to_3, int* wire0_to_23)
{
const int map[4*24] = {
// tile #3 (topmost)
/* 0*/ MW+MO_P37, MW+MO_M33, MW+MO_P35, MW+MO_P41,
/* 4*/ MW+MO_M34, MW+MO_P38, MW+MO_P44, MW+MO_M29,
/* 8*/ MW+MO_M32, MW+MO_CARRYOUT, MW+MO_M30, MW+MO_P47,
/*12*/ MW+MO_P36, 0, 0, MW+MO_P40,
/*16*/ MW+MO_M35, MW+MO_M31, MW+MO_P42, MW+MO_M28,
/*20*/ MW+MO_P43, MW+MO_P45, MW+MO_P39, MW+MO_P46,
// tile #2
/* 0*/ MW+MO_M21, MW+MO_P29, MW+MO_M18, MW+MO_M23,
/* 4*/ MW+MO_P32, 0, MW+MO_P31, MW+MO_P24,
/* 8*/ MW+MO_P28, MW+MO_P34, MW+MO_P25, MW+MO_M27,
/*12*/ MW+MO_M20, MW+MO_M25, MW+MO_M19, MW+MO_M22,
/*16*/ 0, MW+MO_P26, MW+MO_P30, 0,
/*20*/ MW+MO_M24, MW+MO_P33, MW+MO_P27, MW+MO_M26,
// tile #1
/* 0*/ MW+MO_M11, MW+MO_P19, MW+MO_P12, MW+MO_M14,
/* 4*/ MW+MO_P21, MW+MO_M12, 0, MW+MO_P13,
/* 8*/ MW+MO_P18, 0, MW+MO_P15, MW+MO_P23,
/*12*/ MW+MO_P14, MW+MO_P20, MW+MO_M9, MW+MO_M13,
/*16*/ MW+MO_P22, MW+MO_P16, MW+MO_M15, MW+MO_M10,
/*20*/ MW+MO_M16, 0, MW+MO_P17, MW+MO_M17,
// tile #0 (bottommost)
/* 0*/ MW+MO_P2, MW+MO_P6, 0, MW+MO_M3,
/* 4*/ MW+MO_P9, MW+MO_P3, MW+MO_M6, MW+MO_P1,
/* 8*/ MW+MO_M4, MW+MO_P11, MW+MO_M1, 0,
/*12*/ MW+MO_M0, MW+MO_M5, MW+MO_P0, MW+MO_P5,
/*16*/ MW+MO_P10, MW+MO_M2, MW+MO_P7, 0,
/*20*/ MW+MO_P8, MW+MO_M7, MW+MO_P4, MW+MO_M8 };
int i;
if (wire < MW || wire > MW_LAST) {
HERE();
*tile0_to_3 = -1;
return;
}
for (i = 0; i < 4*24; i++) {
if (map[i] == wire) {
*tile0_to_3 = 3-(i/24);
*wire0_to_23 = i%24;
return;
}
}
fprintf(stderr, "#E %s:%i unknown wire %i\n",
__FILE__, __LINE__, wire);
*tile0_to_3 = -1;
}
fpgatools-201212/libs/model_main.c 0000664 0000000 0000000 00000015745 12065743015 0017021 0 ustar 00root root 0000000 0000000 //
// Author: Wolfgang Spraul
//
// This is free and unencumbered software released into the public domain.
// For details see the UNLICENSE file at the root of the source tree.
//
#include
#include "model.h"
static int s_high_speed_replicate = 1;
int fpga_build_model(struct fpga_model* model, int idcode, enum xc6_pkg pkg)
{
int rc;
memset(model, 0, sizeof(*model));
model->die = xc_die_info(idcode);
model->pkg = xc6_pkg_info(pkg);
if (!model->die || !model->pkg) RC_FAIL(model, EINVAL);
strarray_init(&model->str, STRIDX_64K);
rc = get_xc6_routing_bitpos(&model->sw_bitpos, &model->num_bitpos);
if (rc) RC_FAIL(model, rc);
// The order of tiles, then devices, then ports, then
// connections and finally switches is important so
// that the codes can build upon each other.
init_tiles(model);
init_devices(model);
if (s_high_speed_replicate)
replicate_routing_switches(model);
// todo: compare.ports only works if other switches and conns
// are disabled, as long as not all connections are supported
init_ports(model, /*dup_warn*/ !s_high_speed_replicate);
init_conns(model);
init_switches(model, /*routing_sw*/ !s_high_speed_replicate);
RC_RETURN(model);
}
int fpga_free_model(struct fpga_model* model)
{
int rc;
if (!model) return 0;
rc = model->rc;
free_devices(model);
free(model->tmp_str);
strarray_free(&model->str);
free(model->tiles);
free_xc6_routing_bitpos(model->sw_bitpos);
memset(model, 0, sizeof(*model));
return rc;
}
static const char* fpga_ttstr[] = // tile type strings
{
[NA] = "NA",
[ROUTING] = "ROUTING",
[ROUTING_BRK] = "ROUTING_BRK",
[ROUTING_VIA] = "ROUTING_VIA",
[HCLK_ROUTING_XM] = "HCLK_ROUTING_XM",
[HCLK_ROUTING_XL] = "HCLK_ROUTING_XL",
[HCLK_LOGIC_XM] = "HCLK_LOGIC_XM",
[HCLK_LOGIC_XL] = "HCLK_LOGIC_XL",
[LOGIC_XM] = "LOGIC_XM",
[LOGIC_XL] = "LOGIC_XL",
[REGH_ROUTING_XM] = "REGH_ROUTING_XM",
[REGH_ROUTING_XL] = "REGH_ROUTING_XL",
[REGH_LOGIC_XM] = "REGH_LOGIC_XM",
[REGH_LOGIC_XL] = "REGH_LOGIC_XL",
[BRAM_ROUTING] = "BRAM_ROUTING",
[BRAM_ROUTING_BRK] = "BRAM_ROUTING_BRK",
[BRAM] = "BRAM",
[BRAM_ROUTING_TERM_T] = "BRAM_ROUTING_TERM_T",
[BRAM_ROUTING_TERM_B] = "BRAM_ROUTING_TERM_B",
[BRAM_ROUTING_VIA_TERM_T] = "BRAM_ROUTING_VIA_TERM_T",
[BRAM_ROUTING_VIA_TERM_B] = "BRAM_ROUTING_VIA_TERM_B",
[BRAM_TERM_LT] = "BRAM_TERM_LT",
[BRAM_TERM_RT] = "BRAM_TERM_RT",
[BRAM_TERM_LB] = "BRAM_TERM_LB",
[BRAM_TERM_RB] = "BRAM_TERM_RB",
[HCLK_BRAM_ROUTING] = "HCLK_BRAM_ROUTING",
[HCLK_BRAM_ROUTING_VIA] = "HCLK_BRAM_ROUTING_VIA",
[HCLK_BRAM] = "HCLK_BRAM",
[REGH_BRAM_ROUTING] = "REGH_BRAM_ROUTING",
[REGH_BRAM_ROUTING_VIA] = "REGH_BRAM_ROUTING_VIA",
[REGH_BRAM_L] = "REGH_BRAM_L",
[REGH_BRAM_R] = "REGH_BRAM_R",
[MACC] = "MACC",
[HCLK_MACC_ROUTING] = "HCLK_MACC_ROUTING",
[HCLK_MACC_ROUTING_VIA] = "HCLK_MACC_ROUTING_VIA",
[HCLK_MACC] = "HCLK_MACC",
[REGH_MACC_ROUTING] = "REGH_MACC_ROUTING",
[REGH_MACC_ROUTING_VIA] = "REGH_MACC_ROUTING_VIA",
[REGH_MACC_L] = "REGH_MACC_L",
[PLL_T] = "PLL_T",
[DCM_T] = "DCM_T",
[PLL_B] = "PLL_B",
[DCM_B] = "DCM_B",
[REG_T] = "REG_T",
[REG_TERM_T] = "REG_TERM_T",
[REG_TERM_B] = "REG_TERM_B",
[REG_B] = "REG_B",
[REGV_TERM_T] = "REGV_TERM_T",
[REGV_TERM_B] = "REGV_TERM_B",
[HCLK_REGV] = "HCLK_REGV",
[REGV] = "REGV",
[REGV_BRK] = "REGV_BRK",
[REGV_T] = "REGV_T",
[REGV_B] = "REGV_B",
[REGV_MIDBUF_T] = "REGV_MIDBUF_T",
[REGV_HCLKBUF_T] = "REGV_HCLKBUF_T",
[REGV_HCLKBUF_B] = "REGV_HCLKBUF_B",
[REGV_MIDBUF_B] = "REGV_MIDBUF_B",
[REGC_ROUTING] = "REGC_ROUTING",
[REGC_LOGIC] = "REGC_LOGIC",
[REGC_CMT] = "REGC_CMT",
[CENTER] = "CENTER",
[IO_T] = "IO_T",
[IO_B] = "IO_B",
[IO_TERM_T] = "IO_TERM_T",
[IO_TERM_B] = "IO_TERM_B",
[IO_ROUTING] = "IO_ROUTING",
[IO_LOGIC_TERM_T] = "IO_LOGIC_TERM_T",
[IO_LOGIC_TERM_B] = "IO_LOGIC_TERM_B",
[IO_OUTER_T] = "IO_OUTER_T",
[IO_INNER_T] = "IO_INNER_T",
[IO_OUTER_B] = "IO_OUTER_B",
[IO_INNER_B] = "IO_INNER_B",
[IO_BUFPLL_TERM_T] = "IO_BUFPLL_TERM_T",
[IO_LOGIC_REG_TERM_T] = "IO_LOGIC_REG_TERM_T",
[IO_BUFPLL_TERM_B] = "IO_BUFPLL_TERM_B",
[IO_LOGIC_REG_TERM_B] = "IO_LOGIC_REG_TERM_B",
[LOGIC_ROUTING_TERM_B] = "LOGIC_ROUTING_TERM_B",
[LOGIC_NOIO_TERM_B] = "LOGIC_NOIO_TERM_B",
[MACC_ROUTING_TERM_T] = "MACC_ROUTING_TERM_T",
[MACC_ROUTING_TERM_B] = "MACC_ROUTING_TERM_B",
[MACC_VIA_TERM_T] = "MACC_VIA_TERM_T",
[MACC_TERM_TL] = "MACC_TERM_TL",
[MACC_TERM_TR] = "MACC_TERM_TR",
[MACC_TERM_BL] = "MACC_TERM_BL",
[MACC_TERM_BR] = "MACC_TERM_BR",
[ROUTING_VIA_REGC] = "ROUTING_VIA_REGC",
[ROUTING_VIA_IO] = "ROUTING_VIA_IO",
[ROUTING_VIA_IO_DCM] = "ROUTING_VIA_IO_DCM",
[ROUTING_VIA_CARRY] = "ROUTING_VIA_CARRY",
[CORNER_TERM_L] = "CORNER_TERM_L",
[CORNER_TERM_R] = "CORNER_TERM_R",
[IO_TERM_L_UPPER_TOP] = "IO_TERM_L_UPPER_TOP",
[IO_TERM_L_UPPER_BOT] = "IO_TERM_L_UPPER_BOT",
[IO_TERM_L_LOWER_TOP] = "IO_TERM_L_LOWER_TOP",
[IO_TERM_L_LOWER_BOT] = "IO_TERM_L_LOWER_BOT",
[IO_TERM_R_UPPER_TOP] = "IO_TERM_R_UPPER_TOP",
[IO_TERM_R_UPPER_BOT] = "IO_TERM_R_UPPER_BOT",
[IO_TERM_R_LOWER_TOP] = "IO_TERM_R_LOWER_TOP",
[IO_TERM_R_LOWER_BOT] = "IO_TERM_R_LOWER_BOT",
[IO_TERM_L] = "IO_TERM_L",
[IO_TERM_R] = "IO_TERM_R",
[HCLK_TERM_L] = "HCLK_TERM_L",
[HCLK_TERM_R] = "HCLK_TERM_R",
[REGH_IO_TERM_L] = "REGH_IO_TERM_L",
[REGH_IO_TERM_R] = "REGH_IO_TERM_R",
[REG_L] = "REG_L",
[REG_R] = "REG_R",
[IO_PCI_L] = "IO_PCI_L",
[IO_PCI_R] = "IO_PCI_R",
[IO_RDY_L] = "IO_RDY_L",
[IO_RDY_R] = "IO_RDY_R",
[IO_L] = "IO_L",
[IO_R] = "IO_R",
[IO_PCI_CONN_L] = "IO_PCI_CONN_L",
[IO_PCI_CONN_R] = "IO_PCI_CONN_R",
[CORNER_TERM_T] = "CORNER_TERM_T",
[CORNER_TERM_B] = "CORNER_TERM_B",
[ROUTING_IO_L] = "ROUTING_IO_L",
[HCLK_ROUTING_IO_L] = "HCLK_ROUTING_IO_L",
[HCLK_ROUTING_IO_R] = "HCLK_ROUTING_IO_R",
[REGH_ROUTING_IO_L] = "REGH_ROUTING_IO_L",
[REGH_ROUTING_IO_R] = "REGH_ROUTING_IO_R",
[ROUTING_IO_L_BRK] = "ROUTING_IO_L_BRK",
[ROUTING_GCLK] = "ROUTING_GCLK",
[REGH_IO_L] = "REGH_IO_L",
[REGH_IO_R] = "REGH_IO_R",
[REGH_MCB] = "REGH_MCB",
[HCLK_MCB] = "HCLK_MCB",
[ROUTING_IO_VIA_L] = "ROUTING_IO_VIA_L",
[ROUTING_IO_VIA_R] = "ROUTING_IO_VIA_R",
[ROUTING_IO_PCI_CE_L] = "ROUTING_IO_PCI_CE_L",
[ROUTING_IO_PCI_CE_R] = "ROUTING_IO_PCI_CE_R",
[CORNER_TL] = "CORNER_TL",
[CORNER_BL] = "CORNER_BL",
[CORNER_TR_UPPER] = "CORNER_TR_UPPER",
[CORNER_TR_LOWER] = "CORNER_TR_LOWER",
[CORNER_BR_UPPER] = "CORNER_BR_UPPER",
[CORNER_BR_LOWER] = "CORNER_BR_LOWER",
[HCLK_IO_TOP_UP_L] = "HCLK_IO_TOP_UP_L",
[HCLK_IO_TOP_UP_R] = "HCLK_IO_TOP_UP_R",
[HCLK_IO_TOP_SPLIT_L] = "HCLK_IO_TOP_SPLIT_L",
[HCLK_IO_TOP_SPLIT_R] = "HCLK_IO_TOP_SPLIT_R",
[HCLK_IO_TOP_DN_L] = "HCLK_IO_TOP_DN_L",
[HCLK_IO_TOP_DN_R] = "HCLK_IO_TOP_DN_R",
[HCLK_IO_BOT_UP_L] = "HCLK_IO_BOT_UP_L",
[HCLK_IO_BOT_UP_R] = "HCLK_IO_BOT_UP_R",
[HCLK_IO_BOT_SPLIT_L] = "HCLK_IO_BOT_SPLIT_L",
[HCLK_IO_BOT_SPLIT_R] = "HCLK_IO_BOT_SPLIT_R",
[HCLK_IO_BOT_DN_L] = "HCLK_IO_BOT_DN_L",
[HCLK_IO_BOT_DN_R] = "HCLK_IO_BOT_DN_R",
};
const char* fpga_tiletype_str(enum fpga_tile_type type)
{
if (type >= sizeof(fpga_ttstr)/sizeof(fpga_ttstr[0])
|| !fpga_ttstr[type]) return "UNK";
return fpga_ttstr[type];
}
fpgatools-201212/libs/model_ports.c 0000664 0000000 0000000 00000032644 12065743015 0017241 0 ustar 00root root 0000000 0000000 //
// Author: Wolfgang Spraul
//
// This is free and unencumbered software released into the public domain.
// For details see the UNLICENSE file at the root of the source tree.
//
#include
#include "model.h"
enum which_side
{
TOP_S, BOTTOM_S, RIGHT_S, LEFT_S
};
static int init_iologic_ports(struct fpga_model* model, int y, int x,
enum which_side side, int dup_warn)
{
static const char* prefix, *suffix1, *suffix2;
int rc, i;
RC_CHECK(model);
switch (side) {
case TOP_S: prefix = "TIOI"; break;
case BOTTOM_S: prefix = "BIOI"; break;
case LEFT_S: prefix = "LIOI"; break;
case RIGHT_S: prefix = "RIOI"; break;
default: EXIT(1);
}
if (side == LEFT_S || side == RIGHT_S) {
suffix1 = "_M";
suffix2 = "_S";
} else {
suffix1 = "_STUB";
suffix2 = "_S_STUB";
}
for (i = X_A /* 0 */; i <= M_DQ /* 23 */; i++) {
rc = add_connpt_name(model, y, x, pf("IOI_INTER_LOGICOUT%i", i),
dup_warn, /*name_i*/ 0, /*connpt_o*/ 0);
if (rc) goto xout;
}
rc = add_connpt_name(model, y, x, pf("%s_GND_TIEOFF", prefix),
dup_warn, 0, 0);
if (rc) goto xout;
rc = add_connpt_name(model, y, x, pf("%s_VCC_TIEOFF", prefix),
dup_warn, 0, 0);
if (rc) goto xout;
rc = add_connpt_name(model, y, x, pf("%s_KEEP1_STUB", prefix),
dup_warn, 0, 0);
if (rc) goto xout;
for (i = 0; i <= 4; i++) {
rc = add_connpt_2(model, y, x, pf("AUXADDR%i_IODELAY", i),
suffix1, suffix2, dup_warn);
if (rc) goto xout;
}
rc = add_connpt_2(model, y, x, "AUXSDOIN_IODELAY", suffix1, suffix2,
dup_warn);
if (rc) goto xout;
rc = add_connpt_2(model, y, x, "AUXSDO_IODELAY", suffix1, suffix2,
dup_warn);
if (rc) goto xout;
rc = add_connpt_2(model, y, x, "MEMUPDATE_IODELAY", suffix1, suffix2,
dup_warn);
if (rc) goto xout;
rc = add_connpt_name(model, y, x, "OUTN_IODELAY_SITE",
dup_warn, 0, 0);
if (rc) goto xout;
rc = add_connpt_name(model, y, x, "STUB_OUTN_IODELAY_S",
dup_warn, 0, 0);
if (rc) goto xout;
rc = add_connpt_name(model, y, x, "OUTP_IODELAY_SITE",
dup_warn, 0, 0);
if (rc) goto xout;
rc = add_connpt_name(model, y, x, "STUB_OUTP_IODELAY_S",
dup_warn, 0, 0);
if (rc) goto xout;
for (i = 1; i <= 4; i++) {
rc = add_connpt_2(model, y, x, pf("Q%i_ILOGIC_SITE", i), "", "_S",
dup_warn);
if (rc) goto xout;
rc = add_connpt_2(model, y, x, pf("D%i_OLOGIC_SITE", i), "", "_S",
dup_warn);
if (rc) goto xout;
rc = add_connpt_2(model, y, x, pf("T%i_OLOGIC_SITE", i), "", "_S",
dup_warn);
if (rc) goto xout;
rc = add_connpt_2(model, y, x, pf("SHIFTIN%i_OLOGIC_SITE", i), "", "_S",
dup_warn);
if (rc) goto xout;
rc = add_connpt_2(model, y, x, pf("SHIFTOUT%i_OLOGIC_SITE", i), "", "_S",
dup_warn);
if (rc) goto xout;
}
for (i = 0; i <= 1; i++) {
rc = add_connpt_2(model, y, x, pf("CFB%i_ILOGIC_SITE", i), "", "_S",
dup_warn);
if (rc) goto xout;
rc = add_connpt_2(model, y, x, pf("CLK%i_ILOGIC_SITE", i), "", "_S",
dup_warn);
if (rc) goto xout;
rc = add_connpt_2(model, y, x, pf("CLK%i_OLOGIC_SITE", i), "", "_S",
dup_warn);
if (rc) goto xout;
}
{
static const char* mcb_2[] = {
"BITSLIP_ILOGIC_SITE", "BUSY_IODELAY_SITE",
"CAL_IODELAY_SITE", "CE0_ILOGIC_SITE",
"CE_IODELAY_SITE", "CIN_IODELAY_SITE",
"CLKDIV_ILOGIC_SITE", "CLKDIV_OLOGIC_SITE",
"CLK_IODELAY_SITE", "DATAOUT_IODELAY_SITE",
"DDLY2_ILOGIC_SITE", "DDLY_ILOGIC_SITE",
"DFB_ILOGIC_SITE", "D_ILOGIC_IDATAIN_IODELAY",
"D_ILOGIC_SITE", "DOUT_IODELAY_SITE",
"FABRICOUT_ILOGIC_SITE", "IDATAIN_IODELAY_SITE",
"INCDEC_ILOGIC_SITE", "INC_IODELAY_SITE",
"IOCE_ILOGIC_SITE", "IOCE_OLOGIC_SITE",
"IOCLK1_IODELAY_SITE", "IOCLK_IODELAY_SITE",
"LOAD_IODELAY_SITE", "OCE_OLOGIC_SITE",
"ODATAIN_IODELAY_SITE", "OFB_ILOGIC_SITE",
"OQ_OLOGIC_SITE", "RCLK_IODELAY_SITE",
"READEN_IODELAY_UNUSED_SITE", "REV_ILOGIC_SITE",
"REV_OLOGIC_SITE", "RST_IODELAY_SITE",
"SHIFTIN_ILOGIC_SITE", "SHIFTOUT_ILOGIC_SITE",
"SR_ILOGIC_SITE", "SR_OLOGIC_SITE",
"TCE_OLOGIC_SITE", "TFB_ILOGIC_SITE",
"T_IODELAY_SITE", "TOUT_IODELAY_SITE",
"TQ_OLOGIC_SITE", "TRAIN_OLOGIC_SITE",
"VALID_ILOGIC_SITE", "" };
for (i = 0; mcb_2[i][0]; i++) {
rc = add_connpt_2(model, y, x, mcb_2[i], "", "_S",
dup_warn);
}
}
rc = add_connpt_name(model, y, x, "DATAOUT2_IODELAY_SITE",
dup_warn, 0, 0);
if (rc) goto xout;
rc = add_connpt_name(model, y, x, "DATAOUT2_IODELAY2_SITE_S",
dup_warn, 0, 0);
if (rc) goto xout;
for (i = 0; i <= 2; i++) {
rc = add_connpt_2(model, y, x, pf("IOI_CLK%iINTER", i),
"_M", "_S", dup_warn);
if (rc) goto xout;
}
for (i = 0; i <= 1; i++) {
rc = add_connpt_2(model, y, x, pf("IOI_CLKDIST_IOCE%i", i),
"_M", "_S", dup_warn);
if (rc) goto xout;
}
rc = add_connpt_2(model, y, x, "IOI_CLKDIST_CLK0_ILOGIC", "_M", "_S",
dup_warn);
if (rc) goto xout;
rc = add_connpt_2(model, y, x, "IOI_CLKDIST_CLK0_OLOGIC", "_M", "_S",
dup_warn);
if (rc) goto xout;
rc = add_connpt_2(model, y, x, "IOI_CLKDIST_CLK1", "_M", "_S",
dup_warn);
if (rc) goto xout;
if (side == TOP_S || side == BOTTOM_S) {
static const char* mcb_2[] = {
"IOI_MCB_DQIEN", "IOI_MCB_INBYP",
"IOI_MCB_IN", "IOI_MCB_OUTN",
"IOI_MCB_OUTP", "" };
static const char* mcb_1[] = {
"IOI_MCB_DRPADD", "IOI_MCB_DRPBROADCAST",
"IOI_MCB_DRPCLK", "IOI_MCB_DRPCS",
"IOI_MCB_DRPSDI", "IOI_MCB_DRPSDO",
"IOI_MCB_DRPTRAIN", "" };
for (i = 0; mcb_2[i][0]; i++) {
rc = add_connpt_2(model, y, x, mcb_2[i], "_M", "_S",
dup_warn);
if (rc) goto xout;
}
for (i = 0; mcb_1[i][0]; i++) {
rc = add_connpt_name(model, y, x, mcb_1[i],
dup_warn, 0, 0);
if (rc) goto xout;
}
}
return 0;
xout:
return rc;
}
int init_ports(struct fpga_model* model, int dup_warn)
{
int x, y, i, j, k, row_num, row_pos, rc;
RC_CHECK(model);
// inner and outer IO tiles (ILOGIC/ILOGIC/IODELAY)
for (x = LEFT_SIDE_WIDTH; x < model->x_width - RIGHT_SIDE_WIDTH; x++) {
if (has_device(model, TOP_OUTER_IO, x, DEV_ILOGIC)) {
rc = init_iologic_ports(model, TOP_OUTER_IO, x, TOP_S, dup_warn);
if (rc) goto xout;
}
if (has_device(model, TOP_INNER_IO, x, DEV_ILOGIC)) {
rc = init_iologic_ports(model, TOP_INNER_IO, x, TOP_S, dup_warn);
if (rc) goto xout;
}
if (has_device(model, model->y_height - BOT_INNER_IO, x, DEV_ILOGIC)) {
rc = init_iologic_ports(model, model->y_height - BOT_INNER_IO, x, BOTTOM_S, dup_warn);
if (rc) goto xout;
}
if (has_device(model, model->y_height - BOT_OUTER_IO, x, DEV_ILOGIC)) {
rc = init_iologic_ports(model, model->y_height - BOT_OUTER_IO, x, BOTTOM_S, dup_warn);
if (rc) goto xout;
}
}
for (y = TOP_IO_TILES; y < model->y_height - BOT_IO_TILES; y++) {
if (has_device(model, y, LEFT_IO_DEVS, DEV_ILOGIC)) {
rc = init_iologic_ports(model, y, LEFT_IO_DEVS, LEFT_S, dup_warn);
if (rc) goto xout;
}
if (has_device(model, y, model->x_width - RIGHT_IO_DEVS_O, DEV_ILOGIC)) {
rc = init_iologic_ports(model, y, model->x_width - RIGHT_IO_DEVS_O, RIGHT_S, dup_warn);
if (rc) goto xout;
}
}
for (x = 0; x < model->x_width; x++) {
// VCC, GND and fans
if (is_atx(X_ROUTING_COL, model, x)) {
for (y = TOP_IO_TILES; y < model->y_height - BOT_IO_TILES; y++) {
if (is_aty(Y_ROW_HORIZ_AXSYMM|Y_CHIP_HORIZ_REGS,
model, y))
continue;
rc = add_connpt_name(model, y, x, "VCC_WIRE",
dup_warn, 0, 0);
if (rc) goto xout;
rc = add_connpt_name(model, y, x, "GND_WIRE",
dup_warn, 0, 0);
if (rc) goto xout;
rc = add_connpt_name(model, y, x, "KEEP1_WIRE",
dup_warn, 0, 0);
if (rc) goto xout;
rc = add_connpt_name(model, y, x, "FAN",
dup_warn, 0, 0);
if (rc) goto xout;
rc = add_connpt_name(model, y, x, "FAN_B",
dup_warn, 0, 0);
if (rc) goto xout;
if (!is_atyx(YX_IO_ROUTING, model, y, x)) {
for (i = 0; i <= 1; i++) {
rc = add_connpt_name(model, y, x, pf("GFAN%i", i),
dup_warn, 0, 0);
if (rc) goto xout;
}
} else {
if (!is_atx(X_CENTER_ROUTING_COL, model, x)
|| is_aty(Y_TOPBOT_IO_RANGE, model, y)) {
// In the center those 2 wires are connected
// to the PLL, but elsewhere? Not clear what they
// connect to...
rc = add_connpt_name(model, y, x,
logicin_s(X_A5, 1 /* routing_io */),
dup_warn, 0, 0);
if (rc) goto xout;
rc = add_connpt_name(model, y, x,
logicin_s(X_B4, 1 /* routing_io */),
dup_warn, 0, 0);
if (rc) goto xout;
}
}
}
}
// logicin
if (is_atx(X_FABRIC_LOGIC_XL_ROUTING_COL
|X_CENTER_ROUTING_COL, model, x)) {
for (y = TOP_IO_TILES; y < model->y_height - BOT_IO_TILES; y++) {
static const int n[] = { 36, 44, 53, 61, 62 };
if (is_aty(Y_TOPBOT_IO_RANGE, model, y)
&& !is_atx(X_ROUTING_NO_IO, model, x))
continue;
if (is_aty(Y_ROW_HORIZ_AXSYMM|Y_CHIP_HORIZ_REGS,
model, y))
continue;
if (is_atx(X_CENTER_ROUTING_COL, model, x)
&& (is_aty(Y_ROW_HORIZ_AXSYMM|Y_CHIP_HORIZ_REGS,
model, y+1)
|| is_aty(Y_ROW_HORIZ_AXSYMM, model, y-1)))
continue;
for (i = 0; i < sizeof(n)/sizeof(*n); i++) {
rc = add_connpt_name(model, y, x,
pf("LOGICIN_B%i", n[i]), dup_warn, 0, 0);
if (rc) goto xout;
}
}
}
// bram
if (is_atx(X_FABRIC_BRAM_COL, model, x)) {
for (y = TOP_IO_TILES; y < model->y_height - BOT_IO_TILES; y++) {
if (YX_TILE(model, y, x)->flags & TF_BRAM_DEV) {
static const char* pass_str[3] = {"RAMB16BWER", "RAMB8BWER_0", "RAMB8BWER_1"};
// pass 0 is ramb16, pass 1 and 2 are for ramb8
for (i = 0; i <= 2; i++) {
for (j = 'A'; j <= 'B'; j++) {
rc = add_connpt_name(model, y, x, pf("%s_CLK%c", pass_str[i], j),
dup_warn, 0, 0);
if (rc) goto xout;
rc = add_connpt_name(model, y, x, pf("%s_EN%c", pass_str[i], j),
dup_warn, 0, 0);
if (rc) goto xout;
rc = add_connpt_name(model, y, x, pf("%s_REGCE%c", pass_str[i], j),
dup_warn, 0, 0);
if (rc) goto xout;
rc = add_connpt_name(model, y, x, pf("%s_RST%c", pass_str[i], j),
dup_warn, 0, 0);
if (rc) goto xout;
for (k = 0; k <= (!i ? 3 : 1); k++) {
rc = add_connpt_name(model, y, x, pf("%s_DIP%c%i", pass_str[i], j, k),
dup_warn, 0, 0);
if (rc) goto xout;
rc = add_connpt_name(model, y, x, pf("%s_DOP%c%i", pass_str[i], j, k),
dup_warn, 0, 0);
if (rc) goto xout;
rc = add_connpt_name(model, y, x, pf("%s_WE%c%i", pass_str[i], j, k),
dup_warn, 0, 0);
if (rc) goto xout;
}
for (k = 0; k <= (!i ? 13 : 12); k++) {
rc = add_connpt_name(model, y, x, pf("%s_ADDR%c%i", pass_str[i], j, k),
dup_warn, 0, 0);
if (rc) goto xout;
}
for (k = 0; k <= (!i ? 31 : 15); k++) {
rc = add_connpt_name(model, y, x, pf("%s_DI%c%i", pass_str[i], j, k),
dup_warn, 0, 0);
if (rc) goto xout;
rc = add_connpt_name(model, y, x, pf("%s_DO%c%i", pass_str[i], j, k),
dup_warn, 0, 0);
if (rc) goto xout;
}
}
}
}
}
}
// macc
if (is_atx(X_FABRIC_MACC_COL, model, x)) {
for (y = TOP_IO_TILES; y < model->y_height - BOT_IO_TILES; y++) {
if (YX_TILE(model, y, x)->flags & TF_MACC_DEV) {
static const char* pref[] = {"CE", "RST", ""};
static const char* seq[] = {"A", "B", "C", "D", "M", "P", "OPMODE", ""};
is_in_row(model, y, &row_num, &row_pos);
if (!row_num && row_pos == LAST_POS_IN_ROW) {
rc = add_connpt_name(model, y, x, "CARRYIN_DSP48A1_SITE",
dup_warn, 0, 0);
if (rc) goto xout;
for (i = 0; i <= 47; i++) {
rc = add_connpt_name(model, y, x, pf("PCIN%i_DSP48A1_SITE", i),
dup_warn, 0, 0);
if (rc) goto xout;
}
}
rc = add_connpt_name(model, y, x, "CLK_DSP48A1_SITE",
dup_warn, 0, 0);
if (rc) goto xout;
rc = add_connpt_name(model, y, x, "CARRYOUT_DSP48A1_SITE",
dup_warn, 0, 0);
if (rc) goto xout;
rc = add_connpt_name(model, y, x, "CARRYOUTF_DSP48A1_SITE",
dup_warn, 0, 0);
if (rc) goto xout;
for (i = 0; pref[i][0]; i++) {
rc = add_connpt_name(model, y, x, pf("%sCARRYIN_DSP48A1_SITE", pref[i]),
dup_warn, 0, 0);
if (rc) goto xout;
for (j = 0; seq[j][0]; j++) {
rc = add_connpt_name(model, y, x, pf("%s%s_DSP48A1_SITE", pref[i], seq[j]),
dup_warn, 0, 0);
if (rc) goto xout;
}
}
for (i = 0; i <= 17; i++) {
rc = add_connpt_name(model, y, x, pf("A%i_DSP48A1_SITE", i),
dup_warn, 0, 0);
if (rc) goto xout;
rc = add_connpt_name(model, y, x, pf("B%i_DSP48A1_SITE", i),
dup_warn, 0, 0);
if (rc) goto xout;
rc = add_connpt_name(model, y, x, pf("D%i_DSP48A1_SITE", i),
dup_warn, 0, 0);
if (rc) goto xout;
rc = add_connpt_name(model, y, x, pf("BCOUT%i_DSP48A1_SITE", i),
dup_warn, 0, 0);
if (rc) goto xout;
}
for (i = 0; i <= 47; i++) {
rc = add_connpt_name(model, y, x, pf("C%i_DSP48A1_SITE", i),
dup_warn, 0, 0);
if (rc) goto xout;
rc = add_connpt_name(model, y, x, pf("P%i_DSP48A1_SITE", i),
dup_warn, 0, 0);
if (rc) goto xout;
rc = add_connpt_name(model, y, x, pf("PCOUT%i_DSP48A1_SITE", i),
dup_warn, 0, 0);
if (rc) goto xout;
}
for (i = 0; i <= 35; i++) {
rc = add_connpt_name(model, y, x, pf("M%i_DSP48A1_SITE", i),
dup_warn, 0, 0);
if (rc) goto xout;
}
for (i = 0; i <= 7; i++) {
rc = add_connpt_name(model, y, x, pf("OPMODE%i_DSP48A1_SITE", i),
dup_warn, 0, 0);
if (rc) goto xout;
}
}
}
}
}
return 0;
xout:
return rc;
}
fpgatools-201212/libs/model_switches.c 0000664 0000000 0000000 00000263235 12065743015 0017725 0 ustar 00root root 0000000 0000000 //
// Author: Wolfgang Spraul
//
// This is free and unencumbered software released into the public domain.
// For details see the UNLICENSE file at the root of the source tree.
//
#include
#include "model.h"
static int centx_gtp(struct fpga_model *model);
static int centy_pci_rdy(struct fpga_model *model);
static int dev_oct_calibrate(struct fpga_model *model, int y, int x, int idx);
static int dev_dna(struct fpga_model *model);
static int dev_pmv(struct fpga_model *model);
static int dev_icap(struct fpga_model *model);
static int dev_spi_access(struct fpga_model *model);
static int dev_post_crc(struct fpga_model *model);
static int dev_startup(struct fpga_model *model);
static int dev_slave_spi(struct fpga_model *model);
static int dev_suspend_sync(struct fpga_model *model);
static int centy_bram_ckpin(struct fpga_model *model);
static int pcice_sw(struct fpga_model *model);
static int term_to_io_sw(struct fpga_model *model, enum extra_wires wire);
static int init_ce_clk(struct fpga_model *model);
static int init_io(struct fpga_model *model);
static int init_routing(struct fpga_model *model);
static int init_north_south_dirwire_term(struct fpga_model *model);
static int init_east_west_dirwire_term(struct fpga_model *model);
static int init_iologic(struct fpga_model *model);
static int init_logic(struct fpga_model *model);
static int init_center(struct fpga_model *model);
static int init_hclk(struct fpga_model *model);
static int init_logicout_fw(struct fpga_model *model);
static int init_bram(struct fpga_model *model);
static int init_macc(struct fpga_model *model);
static int init_topbot_tterm_gclk(struct fpga_model *model);
static int init_bufio(struct fpga_model *model);
static int init_bscan(struct fpga_model *model);
static int init_dcm(struct fpga_model *model);
static int init_pll(struct fpga_model *model);
static int init_center_hclk(struct fpga_model *model);
static int init_center_midbuf(struct fpga_model *model);
static int init_center_reg_tblr(struct fpga_model *model);
static int init_center_topbot_cfb_dfb(struct fpga_model *model);
int init_switches(struct fpga_model *model, int routing_sw)
{
RC_CHECK(model);
centx_gtp(model);
centy_pci_rdy(model);
dev_oct_calibrate(model, TOP_FIRST_REGULAR, LEFT_IO_DEVS, /*idx*/ 0);
dev_oct_calibrate(model, TOP_FIRST_REGULAR, LEFT_IO_DEVS, /*idx*/ 1);
dev_oct_calibrate(model, model->y_height - BOT_LAST_REGULAR_O, LEFT_IO_DEVS, /*idx*/ 0);
dev_oct_calibrate(model, model->y_height - BOT_LAST_REGULAR_O, LEFT_IO_DEVS, /*idx*/ 1);
dev_oct_calibrate(model, TOP_FIRST_REGULAR+1, model->x_width-RIGHT_IO_DEVS_O, /*idx*/ 0);
dev_oct_calibrate(model, model->y_height - BOT_LAST_REGULAR_O, model->x_width-RIGHT_IO_DEVS_O, /*idx*/ 0);
dev_dna(model);
dev_pmv(model);
dev_icap(model);
dev_spi_access(model);
dev_post_crc(model);
dev_startup(model);
dev_slave_spi(model);
dev_suspend_sync(model);
centy_bram_ckpin(model);
pcice_sw(model);
term_to_io_sw(model, IOCE);
term_to_io_sw(model, IOCLK);
term_to_io_sw(model, PLLCE);
term_to_io_sw(model, PLLCLK);
if (routing_sw)
init_routing(model);
init_logic(model);
init_iologic(model);
init_north_south_dirwire_term(model);
init_east_west_dirwire_term(model);
init_ce_clk(model);
init_io(model);
init_center(model);
init_hclk(model);
init_logicout_fw(model);
init_bram(model);
init_macc(model);
init_topbot_tterm_gclk(model);
init_bufio(model);
init_bscan(model);
init_dcm(model);
init_pll(model);
init_center_hclk(model);
init_center_midbuf(model);
init_center_reg_tblr(model);
init_center_topbot_cfb_dfb(model);
RC_RETURN(model);
}
static int centx_gtp(struct fpga_model *model)
{
RC_CHECK(model);
add_switch(model, TOP_INNER_ROW, model->center_x-CENTER_CMTPLL_O,
"REGT_TTERM_GTP_CLKOUTEW0",
"REGT_TTERM_ALTGTP_CLKINEAST0", /*bidir*/ 0);
add_switch(model, TOP_INNER_ROW, model->center_x-CENTER_CMTPLL_O,
"REGT_TTERM_ALTGTP_CLKOUTEW0",
"REGT_TTERM_GTP_CLKINWEST0", /*bidir*/ 0);
add_switch(model, model->y_height-BOT_INNER_ROW, model->center_x-CENTER_CMTPLL_O,
"REGB_BTERM_GTP_CLKOUTEW0",
"REGB_BTERM_ALTGTP_CLKINEAST0", /*bidir*/ 0);
add_switch(model, model->y_height-BOT_INNER_ROW, model->center_x-CENTER_CMTPLL_O,
"REGB_BTERM_ALTGTP_CLKOUTEW0",
"REGB_BTERM_GTP_CLKINWEST0", /*bidir*/ 0);
RC_RETURN(model);
}
static int centy_pci_rdy(struct fpga_model *model)
{
RC_CHECK(model);
add_switch(model, model->center_y-CENTER_Y_MINUS_3, LEFT_OUTER_COL,
"LIOB_TOP_PCI_RDY0", "LIOB_PCICE_TRDY_EXT", /*bidir*/ 0);
add_switch(model, model->center_y+CENTER_Y_PLUS_1, LEFT_OUTER_COL,
"LIOB_BOT_PCI_RDY0", "LIOB_PCI_IT_RDY", /*bidir*/ 0);
add_switch(model, model->center_y-CENTER_Y_MINUS_3, model->x_width-RIGHT_OUTER_O,
"RIOB_BOT_PCI_RDY0", "RIOB_PCI_IT_RDY", /*bidir*/ 0);
add_switch(model, model->center_y+CENTER_Y_PLUS_1, model->x_width-RIGHT_OUTER_O,
"RIOB_TOP_PCI_RDY1", "RIOB_PCI_TRDY_EXT", /*bidir*/ 0);
RC_RETURN(model);
}
static int dev_oct_calibrate(struct fpga_model *model, int y, int x, int idx)
{
static const int logicin_wnums[4] = {/*i0*/ 29, 32, /*i1*/ 15, 7};
RC_CHECK(model);
add_switch(model, y, x,
pf("INT_INTERFACE_LOCAL_LOGICBIN%i", logicin_wnums[idx*2]),
pf("OCT_CALIBRATE%s_SO_PINWIRE", idx ? "1" : ""),
/*bidir*/ 0);
add_switch(model, y, x,
pf("INT_INTERFACE_LOCAL_LOGICBIN%i", logicin_wnums[idx*2+1]),
pf("OCT_CALIBRATE%s_S1_PINWIRE", idx ? "1" : ""),
/*bidir*/ 0);
RC_RETURN(model);
}
static int dev_dna(struct fpga_model *model)
{
static const char *pairs[] = {
"INT_INTERFACE_LOCAL_CLK0", "DNA_PORT_CLK_PINWIRE",
"INT_INTERFACE_LOCAL_LOGICBIN14", "DNA_PORT_TEST_PINWIRE",
"INT_INTERFACE_LOCAL_LOGICBIN31", "DNA_PORT_READ_PINWIRE",
"INT_INTERFACE_LOCAL_LOGICBIN39", "DNA_PORT_DIN_PINWIRE",
"INT_INTERFACE_LOCAL_LOGICBIN8", "DNA_PORT_SHIFT_PINWIRE",
"DNA_PORT_DOUT_PINWIRE", "INT_INTERFACE_LOCAL_LOGICOUT_23",
"" };
RC_CHECK(model);
add_switch_set(model, TOP_OUTER_IO, LEFT_IO_DEVS,
/*prefix*/ 0, pairs, /*inc*/ 0);
RC_RETURN(model);
}
static int dev_pmv(struct fpga_model *model)
{
static const char *pairs[] = {
"INT_INTERFACE_LOCAL_LOGICBIN20", "PMV_ENABLEB_PINWIRE",
"INT_INTERFACE_LOCAL_LOGICBIN54", "PMV_SELECTB0_PINWIRE",
"INT_INTERFACE_LOCAL_LOGICBIN48", "PMV_SELECTB1_PINWIRE",
"INT_INTERFACE_LOCAL_LOGICBIN23", "PMV_SELECTB2_PINWIRE",
"INT_INTERFACE_LOCAL_LOGICBIN57", "PMV_SELECTB3_PINWIRE",
"INT_INTERFACE_LOCAL_LOGICBIN44", "PMV_SELECTB4_PINWIRE",
"INT_INTERFACE_LOCAL_LOGICBIN4", "PMV_SELECTB5_PINWIRE",
"PMV_OUT_PINWIRE", "INT_INTERFACE_LOCAL_LOGICOUT_0",
"PMV_OUT_DIV2_PINWIRE", "INT_INTERFACE_LOCAL_LOGICOUT_1",
"PMV_OUT_DIV4_PINWIRE", "INT_INTERFACE_LOCAL_LOGICOUT_2",
"" };
RC_CHECK(model);
add_switch_set(model, TOP_OUTER_IO, LEFT_IO_DEVS,
/*prefix*/ 0, pairs, /*inc*/ 0);
RC_RETURN(model);
}
static int dev_icap(struct fpga_model *model)
{
static const char *pairs[] = {
"INT_INTERFACE_LOCAL_CLK1", "ICAP_CLK_PINWIRE",
"INT_INTERFACE_LOCAL_LOGICBIN7", "ICAP_CE_PINWIRE",
"INT_INTERFACE_LOCAL_LOGICBIN42", "ICAP_WRITE_PINWIRE",
"ICAP_BUSY_PINWIRE", "INT_INTERFACE_LOCAL_LOGICOUT_3",
"" };
static const int icap_in_wnums[] =
{16, 5, 12, 47, 20, 45, 36, 17, 25, 34, 54, 48, 23, 57, 44, 4};
int i;
RC_CHECK(model);
add_switch_set(model, model->y_height-BOT_OUTER_IO, model->x_width-RIGHT_IO_DEVS_O,
/*prefix*/ 0, pairs, /*inc*/ 0);
for (i = 0; i <= 15; i++) {
add_switch(model, model->y_height-BOT_OUTER_IO,
model->x_width-RIGHT_IO_DEVS_O,
pf("INT_INTERFACE_LOCAL_LOGICBIN%i", icap_in_wnums[i]),
pf("ICAP_I%i_PINWIRE", i), /*bidir*/ 0);
add_switch(model, model->y_height-BOT_OUTER_IO,
model->x_width-RIGHT_IO_DEVS_O,
pf("ICAP_O%i_PINWIRE", i),
pf("INT_INTERFACE_LOCAL_LOGICOUT_%i", 4+i),
/*bidir*/ 0);
}
RC_RETURN(model);
}
static int dev_spi_access(struct fpga_model *model)
{
static const char *pairs[] = {
"INT_INTERFACE_LOCAL_CLK0", "SPI_ACCESS_CLK_PINWIRE",
"INT_INTERFACE_LOCAL_LOGICBIN24", "SPI_ACCESS_CSB_PINWIRE",
"INT_INTERFACE_LOCAL_SR0", "SPI_ACCESS_MOSI_PINWIRE",
"SPI_ACCESS_MISO_PINWIRE", "INT_INTERFACE_LOCAL_LOGICOUT_1",
"" };
RC_CHECK(model);
add_switch_set(model, model->y_height-BOT_OUTER_IO,
model->x_width-RIGHT_IO_DEVS_O, /*prefix*/ 0, pairs, /*inc*/ 0);
RC_RETURN(model);
}
static int dev_post_crc(struct fpga_model *model)
{
RC_CHECK(model);
add_switch(model, model->y_height-BOT_INNER_IO,
model->x_width-RIGHT_IO_DEVS_O,
"POST_CRC_CRCERROR_PINWIRE",
"INT_INTERFACE_LOCAL_LOGICOUT_8",
/*bidir*/ 0);
RC_RETURN(model);
}
static int dev_startup(struct fpga_model *model)
{
static const char *pairs[] = {
"INT_INTERFACE_LOCAL_CLK1", "STARTUP_CLK_PINWIRE",
"INT_INTERFACE_LOCAL_LOGICBIN1", "STARTUP_KEYCLEARB_PINWIRE",
"INT_INTERFACE_LOCAL_LOGICBIN24", "STARTUP_GTS_PINWIRE",
"INT_INTERFACE_LOCAL_SR1", "STARTUP_GSR_PINWIRE",
"STARTUP_CFGCLK_PINWIRE", "INT_INTERFACE_LOCAL_LOGICOUT_2",
"STARTUP_CFGMCLK_PINWIRE", "INT_INTERFACE_LOCAL_LOGICOUT_1",
"STARTUP_EOS_PINWIRE", "INT_INTERFACE_LOCAL_LOGICOUT_3",
"" };
RC_CHECK(model);
add_switch_set(model, model->y_height-BOT_INNER_IO,
model->x_width-RIGHT_IO_DEVS_O, /*prefix*/ 0, pairs, /*inc*/ 0);
RC_RETURN(model);
}
static int dev_slave_spi(struct fpga_model *model)
{
static const char *pairs[] = {
"INT_INTERFACE_LOCAL_LOGICBIN15", "SLAVE_SPI_CMPMISO_PINWIRE",
"SLAVE_SPI_CMPACTIVEB_PINWIRE", "INT_INTERFACE_LOCAL_LOGICOUT_7",
"SLAVE_SPI_CMPCLK_PINWIRE", "INT_INTERFACE_LOCAL_LOGICOUT_4",
"SLAVE_SPI_CMPCSB_PINWIRE", "INT_INTERFACE_LOCAL_LOGICOUT_5",
"SLAVE_SPI_CMPMOSI_PINWIRE", "INT_INTERFACE_LOCAL_LOGICOUT_6",
"" };
RC_CHECK(model);
add_switch_set(model, model->y_height-BOT_INNER_IO,
model->x_width-RIGHT_IO_DEVS_O, /*prefix*/ 0, pairs, /*inc*/ 0);
RC_RETURN(model);
}
static int dev_suspend_sync(struct fpga_model *model)
{
static const char *pairs[] = {
"INT_INTERFACE_LOCAL_CLK0", "SUSPEND_SYNC_CLK_PINWIRE",
"INT_INTERFACE_LOCAL_SR0", "SUSPEND_SYNC_SACK_PINWIRE",
"SUSPEND_SYNC_SREQ_PINWIRE", "INT_INTERFACE_LOCAL_LOGICOUT_0",
"" };
RC_CHECK(model);
add_switch_set(model, model->y_height-BOT_INNER_IO,
model->x_width-RIGHT_IO_DEVS_O, /*prefix*/ 0, pairs, /*inc*/ 0);
RC_RETURN(model);
}
static int centy_bram_ckpin(struct fpga_model *model)
{
int x, i;
RC_CHECK(model);
for (x = LEFT_SIDE_WIDTH; x < model->x_width-RIGHT_SIDE_WIDTH; x++) {
if (!is_atx(X_FABRIC_BRAM_COL, model, x))
continue;
for (i = 0; i <= 7; i++) {
add_switch(model, model->center_y, x,
pf("REGH_DSP_IN_CKPIN%i", i),
pf("REGH_DSP_OUT_CKPIN%i", i), /*bidir*/ 0);
}
}
RC_RETURN(model);
}
static int pcice_sw(struct fpga_model *model)
{
int x;
RC_CHECK(model);
for (x = LEFT_SIDE_WIDTH; x < model->x_width-RIGHT_SIDE_WIDTH; x++) {
if (is_atx(X_FABRIC_BRAM_COL, model, x)) {
add_switch(model, TOP_INNER_ROW, x,
"BRAM_TTERM_PCICE_IN",
"BRAM_TTERM_PCICE_OUT", /*bidir*/ 0);
add_switch(model, model->y_height-BOT_INNER_ROW, x,
"BRAM_TTERM_PCICE_IN",
"BRAM_TTERM_PCICE_OUT", /*bidir*/ 0);
} else if (is_atx(X_FABRIC_MACC_COL, model, x)) {
add_switch(model, TOP_INNER_ROW, x,
"MACCSITE2_TTERM_PCICE_IN",
"MACCSITE2_TTERM_PCICE_OUT", /*bidir*/ 0);
add_switch(model, model->y_height-BOT_INNER_ROW, x,
"MACCSITE2_TTERM_PCICE_IN",
"MACCSITE2_TTERM_PCICE_OUT", /*bidir*/ 0);
}
}
RC_RETURN(model);
}
static int term_to_io_x(struct fpga_model *model, enum extra_wires wire, int x)
{
const char *s1;
int last_inc, y, i;
RC_CHECK(model);
if (wire == IOCE) {
s1 = "IOCE";
last_inc = 3;
} else if (wire == IOCLK) {
s1 = "IOCLK";
last_inc = 3;
} else if (wire == PLLCE) {
s1 = "PLLCE";
last_inc = 1;
} else if (wire == PLLCLK) {
s1 = "PLLCLK";
last_inc = 1;
} else RC_FAIL(model, EINVAL);
for (y = TOP_FIRST_REGULAR; y <= model->y_height - BOT_LAST_REGULAR_O; y++) {
if (!is_aty(Y_ROW_HORIZ_AXSYMM, model, y))
continue;
// up
for (i = 1; i <= HALF_ROW; i++) {
if (is_aty((x < model->center_x) ? Y_LEFT_WIRED : Y_RIGHT_WIRED, model, y-i)) {
for (i = 0; i <= last_inc; i++) {
add_switch(model, y, x, pf("HCLK_IOIL_%s%i", s1, i),
pf("HCLK_IOIL_%s%i_UP", s1, i), /*bidir*/ 0);
}
break;
}
}
// down
for (i = 1; i <= HALF_ROW; i++) {
if (is_aty((x < model->center_x) ? Y_LEFT_WIRED : Y_RIGHT_WIRED, model, y+i)) {
for (i = 0; i <= last_inc; i++) {
add_switch(model, y, x, pf("HCLK_IOIL_%s%i", s1, i),
pf("HCLK_IOIL_%s%i_DOWN", s1, i), /*bidir*/ 0);
}
break;
}
}
}
RC_RETURN(model);
}
static int term_to_io_sw(struct fpga_model *model, enum extra_wires wire)
{
RC_CHECK(model);
term_to_io_x(model, wire, LEFT_IO_DEVS);
term_to_io_x(model, wire, model->x_width - RIGHT_IO_DEVS_O);
RC_RETURN(model);
}
static int init_logic_tile(struct fpga_model *model, int y, int x)
{
int rc, i, j, ml;
const char* xp;
RC_CHECK(model);
if (has_device_type(model, y, x, DEV_LOGIC, LOGIC_M)) {
ml = 'M';
xp = "X";
} else if (has_device_type(model, y, x, DEV_LOGIC, LOGIC_L)) {
ml = 'L';
xp = "XX";
} else RC_FAIL(model, EINVAL);
if ((rc = add_switch(model, y, x,
pf("CLEX%c_CLK0", ml), pf("%s_CLK", xp), 0 /* bidir */))) RC_FAIL(model, rc);
if ((rc = add_switch(model, y, x,
pf("CLEX%c_CLK1", ml), pf("%c_CLK", ml), 0 /* bidir */))) RC_FAIL(model, rc);
if ((rc = add_switch(model, y, x,
pf("CLEX%c_SR0", ml), pf("%s_SR", xp), 0 /* bidir */))) RC_FAIL(model, rc);
if ((rc = add_switch(model, y, x,
pf("CLEX%c_SR1", ml), pf("%c_SR", ml), 0 /* bidir */))) RC_FAIL(model, rc);
for (i = X_A1; i <= X_DX; i++) {
if ((rc = add_switch(model,y, x,
pf("CLEX%c_LOGICIN_B%i", ml, i),
pf("%s_%s", xp, logicin_str(i)),
0 /* bidir */))) RC_FAIL(model, rc);
}
for (i = M_A1; i <= M_WE; i++) {
if (ml == 'L' &&
(i == M_AI || i == M_BI || i == M_CI
|| i == M_DI || i == M_WE))
continue;
if ((rc = add_switch(model,y, x,
pf("CLEX%c_LOGICIN_B%i", ml, i),
pf("%c_%s", ml, logicin_str(i)),
0 /* bidir */))) RC_FAIL(model, rc);
}
for (i = X_A; i <= X_DQ; i++) {
if ((rc = add_switch(model, y, x,
pf("%s_%s", xp, logicout_str(i)),
pf("CLEX%c_LOGICOUT%i", ml, i),
0 /* bidir */))) RC_FAIL(model, rc);
}
for (i = M_A; i <= M_DQ; i++) {
if ((rc = add_switch(model, y, x,
pf("%c_%s", ml, logicout_str(i)),
pf("CLEX%c_LOGICOUT%i", ml, i),
0 /* bidir */))) RC_FAIL(model, rc);
}
for (i = 'A'; i <= 'D'; i++) {
for (j = 1; j <= 6; j++) {
if ((rc = add_switch(model, y, x,
pf("%c_%c%i", ml, i, j),
pf("%c_%c", ml, i),
0 /* bidir */))) RC_FAIL(model, rc);
if ((rc = add_switch(model, y, x,
pf("%s_%c%i", xp, i, j),
pf("%s_%c", xp, i),
0 /* bidir */))) RC_FAIL(model, rc);
}
if ((rc = add_switch(model, y, x,
pf("%c_%c", ml, i),
pf("%c_%cMUX", ml, i),
0 /* bidir */))) RC_FAIL(model, rc);
}
if (ml == 'L') {
if (has_connpt(model, y, x, "XL_COUT_N")) {
if ((rc = add_switch(model, y, x,
"XL_COUT", "XL_COUT_N",
0 /* bidir */))) RC_FAIL(model, rc);
}
if ((rc = add_switch(model, y, x,
"XL_COUT", "L_DMUX", 0 /* bidir */))) RC_FAIL(model, rc);
} else {
if (has_connpt(model, y, x, "M_COUT_N")) {
if ((rc = add_switch(model, y, x,
"M_COUT", "M_COUT_N",
0 /* bidir */))) RC_FAIL(model, rc);
}
if ((rc = add_switch(model, y, x,
"M_COUT", "M_DMUX", 0 /* bidir */))) RC_FAIL(model, rc);
}
RC_RETURN(model);
}
static int init_logic(struct fpga_model *model)
{
int x, y, rc;
RC_CHECK(model);
for (x = LEFT_SIDE_WIDTH; x < model->x_width-RIGHT_SIDE_WIDTH; x++) {
if (!is_atx(X_FABRIC_LOGIC_COL|X_CENTER_LOGIC_COL, model, x))
continue;
for (y = TOP_IO_TILES; y < model->y_height - BOT_IO_TILES; y++) {
if (has_device(model, y, x, DEV_LOGIC)) {
rc = init_logic_tile(model, y, x);
if (rc) RC_FAIL(model, rc);
}
}
}
RC_RETURN(model);
}
static int init_iologic_tile(struct fpga_model *model, int y, int x)
{
int i, j, rc;
const char* io_prefix, *prefix, *prefix2;
RC_CHECK(model);
if (x < LEFT_SIDE_WIDTH) {
EXIT(x != LEFT_IO_DEVS);
io_prefix = "IOI_";
prefix = "LIOI_";
prefix2 = "LIOI_IOB_";
} else if (x >= model->x_width-RIGHT_SIDE_WIDTH) {
EXIT(x != model->x_width - RIGHT_IO_DEVS_O);
io_prefix = "RIOI_";
prefix = "RIOI_";
prefix2 = "RIOI_IOB_";
} else {
if (y == TOP_OUTER_IO) {
io_prefix = "TIOI_";
prefix = "TIOI_";
prefix2 = "TIOI_OUTER_";
} else if (y == TOP_INNER_IO) {
io_prefix = "TIOI_INNER_";
prefix = "TIOI_";
prefix2 = "TIOI_INNER_";
} else if (y == model->y_height-BOT_INNER_IO) {
io_prefix = "BIOI_INNER_";
prefix = "BIOI_";
prefix2 = "BIOI_INNER_";
} else if (y == model->y_height-BOT_OUTER_IO) {
io_prefix = "TIOI_";
prefix = "BIOI_";
prefix2 = "BIOI_OUTER_";
} else
EXIT(1);
}
for (i = 0; i <= 23; i++) {
if ((rc = add_switch(model, y, x,
pf("IOI_INTER_LOGICOUT%i", i),
pf("IOI_LOGICOUT%i", i), 0 /* bidir */))) RC_FAIL(model, rc);
}
// switches going to IOI_INTER_LOGICOUT0:15
{ static const char* logicout_src[16] = {
/* 0 */ "FABRICOUT_ILOGIC_SITE",
"Q1_ILOGIC_SITE", "Q2_ILOGIC_SITE",
"Q3_ILOGIC_SITE", "Q4_ILOGIC_SITE",
"INCDEC_ILOGIC_SITE", "VALID_ILOGIC_SITE",
/* 7 */ "FABRICOUT_ILOGIC_SITE_S",
"Q1_ILOGIC_SITE_S", "Q2_ILOGIC_SITE_S",
"Q3_ILOGIC_SITE_S", "Q4_ILOGIC_SITE_S",
/* 12 */ "", "",
/* 14 */ "BUSY_IODELAY_SITE", "BUSY_IODELAY_SITE_S" };
for (i = 0; i < sizeof(logicout_src)/sizeof(logicout_src[0]); i++) {
if (logicout_src[i][0]) {
if ((rc = add_switch(model, y, x, logicout_src[i],
pf("IOI_INTER_LOGICOUT%i", i),
0 /* bidir */))) RC_FAIL(model, rc);
}
}}
// The 6 CE lines (4*IO_CE and 2*PLL_CE) can be switched
// to 4 IOCE destinations. Each IOCE line can be driven
// by 6 CE lines.
for (i = 0; i <= 3; i++) {
for (j = 0; j <= 3; j++) {
if ((rc = add_switch(model, y, x,
pf("%sIOCE%i", io_prefix, j),
pf("IOI_CLKDIST_IOCE%i%s",i/2,i%2?"_M":"_S"),
0 /* bidir */))) RC_FAIL(model, rc);
}
for (j = 0; j <= 1; j++) {
if ((rc = add_switch(model, y, x,
pf("%sPLLCE%i", io_prefix, j),
pf("IOI_CLKDIST_IOCE%i%s",i/2,i%2?"_M":"_S"),
0 /* bidir */))) RC_FAIL(model, rc);
}
}
// Incoming clocks and fan can be switched to intermediates
// (5 sources per intermediate), and then to the ilogic/ologic
// devices (3 sources each) or 2*CLK1 (2 sources each).
for (i = 0; i < 4; i++) {
if ((rc = add_switch(model, y, x,
pf("IOI_CLK%i", i/2),
pf("IOI_CLK%iINTER%s",i%2,i<2?"_M":"_S"),
0 /* bidir */))) RC_FAIL(model, rc);
if ((rc = add_switch(model, y, x,
pf("IOI_GFAN%i", i/2),
pf("IOI_CLK%iINTER%s",i%2,i<2?"_M":"_S"),
0 /* bidir */))) RC_FAIL(model, rc);
if ((rc = add_switch(model, y, x,
pf("%sIOCLK%i", io_prefix, i),
pf("IOI_CLK%iINTER%s",i%2,i<2?"_M":"_S"),
0 /* bidir */))) RC_FAIL(model, rc);
if ((rc = add_switch(model, y, x,
pf("%sPLLCLK%i", io_prefix, i/2),
pf("IOI_CLK%iINTER%s",i/2,i%2?"_M":"_S"),
0 /* bidir */))) RC_FAIL(model, rc);
// only PLLCLK goes to CLK2 intermediate
if ((rc = add_switch(model, y, x,
pf("%sPLLCLK%i", io_prefix, i/2),
pf("IOI_CLK2INTER%s",i%2?"_S":"_M"),
0 /* bidir */))) RC_FAIL(model, rc);
// 2 sources each for IOI_CLKDIST_CLK1_M/_S
if ((rc = add_switch(model, y, x,
pf("IOI_CLK%iINTER%s", i%2, i<2?"_M":"_S"),
pf("IOI_CLKDIST_CLK1%s", i<2?"_M":"_S"),
0 /* bidir */))) RC_FAIL(model, rc);
}
// 3 sources each:
for (i = 0; i < 6; i++) {
if ((rc = add_switch(model, y, x,
pf("IOI_CLK%iINTER%s", i%3, i<3?"_M":"_S"),
pf("IOI_CLKDIST_CLK0_ILOGIC%s", i<3?"_M":"_S"),
0 /* bidir */))) RC_FAIL(model, rc);
if ((rc = add_switch(model, y, x,
pf("IOI_CLK%iINTER%s", i%3, i<3?"_M":"_S"),
pf("IOI_CLKDIST_CLK0_OLOGIC%s", i<3?"_M":"_S"),
0 /* bidir */))) RC_FAIL(model, rc);
}
// logicin wires
{
static const char* iologic_logicin[] =
{
[X_A3] = "CAL_IODELAY_SITE",
[X_A4] = "CAL_IODELAY_SITE_S",
[X_A6] = "CE_IODELAY_SITE_S",
[X_B1] = "INC_IODELAY_SITE_S",
[X_B2] = "TRAIN_OLOGIC_SITE",
[X_B3] = "TCE_OLOGIC_SITE_S",
[X_B6] = "T3_OLOGIC_SITE_S",
[X_C1] = "REV_OLOGIC_SITE_S",
[X_C2] = "D1_OLOGIC_SITE_S",
[X_C3] = "D2_OLOGIC_SITE_S",
[X_C4] = "D3_OLOGIC_SITE_S",
[X_C6] = "BITSLIP_ILOGIC_SITE_S",
[X_CE] = "SR_ILOGIC_SITE_S",
[X_D2] = "TCE_OLOGIC_SITE",
[X_D3] = "T1_OLOGIC_SITE",
[X_D4] = "T2_OLOGIC_SITE",
[X_D5] = "T3_OLOGIC_SITE",
[X_D6] = "T4_OLOGIC_SITE",
[X_DX] = "TRAIN_OLOGIC_SITE_S",
[M_A1] = "REV_OLOGIC_SITE",
[M_A2] = "OCE_OLOGIC_SITE",
[M_A3] = "D1_OLOGIC_SITE",
[M_A4] = "D2_OLOGIC_SITE",
[M_A6] = "D4_OLOGIC_SITE",
[M_AI] = "SR_ILOGIC_SITE",
[M_B1] = "REV_ILOGIC_SITE",
[M_B2] = "CE0_ILOGIC_SITE",
[M_B3] = "OCE_OLOGIC_SITE_S",
[M_B5] = "RST_IODELAY_SITE_S",
[M_B6] = "T2_OLOGIC_SITE_S",
[M_BI] = "D3_OLOGIC_SITE",
[M_C1] = "T1_OLOGIC_SITE_S",
[M_C3] = "CE_IODELAY_SITE",
[M_C4] = "D4_OLOGIC_SITE_S",
[M_D1] = "T4_OLOGIC_SITE_S",
[M_D2] = "RST_IODELAY_SITE",
[M_D4] = "BITSLIP_ILOGIC_SITE",
[M_D5] = "INC_IODELAY_SITE",
[M_D6] = "REV_ILOGIC_SITE_S",
[M_WE] = "CE0_ILOGIC_SITE_S",
};
for (i = 0; i < sizeof(iologic_logicin)/sizeof(*iologic_logicin); i++) {
if (!iologic_logicin[i]) continue;
if ((rc = add_switch(model, y, x,
pf("IOI_LOGICINB%i", i),
iologic_logicin[i], /*bidir*/ 0))) RC_FAIL(model, rc);
}
}
// GND
{
static const char* s[] = { "REV_OLOGIC_SITE",
"SR_OLOGIC_SITE", "TRAIN_OLOGIC_SITE" };
for (i = 0; i < 6; i++) {
if ((rc = add_switch(model, y, x,
pf("%sGND_TIEOFF", prefix),
pf("%s%s", s[i/2], i%2 ? "" : "_S"),
/*bidir*/ 0))) RC_FAIL(model, rc);
}
}
// VCC
{
static const char* s[] = { "IOCE_ILOGIC_SITE",
"IOCE_OLOGIC_SITE" };
for (i = 0; i < 4; i++) {
if ((rc = add_switch(model, y, x,
pf("%sVCC_TIEOFF", prefix),
pf("%s%s", s[i/2], i%2 ? "" : "_S"),
/*bidir*/ 0))) RC_FAIL(model, rc);
}
}
// CLK
{
static const char* s[] = { "CLKDIV_ILOGIC_SITE",
"CLKDIV_OLOGIC_SITE", "CLK_IODELAY_SITE" };
for (i = 0; i < 6; i++) {
if ((rc = add_switch(model, y, x,
pf("IOI_CLK%i", !(i%2)),
pf("%s%s", s[i/2], i%2 ? "" : "_S"),
/*bidir*/ 0))) RC_FAIL(model, rc);
}
for (i = 0; i < 4; i++) {
if ((rc = add_switch(model, y, x,
pf("CLK%i_ILOGIC_SITE%s", i/2, i%2 ? "_S" : ""),
pf("CFB%i_ILOGIC_SITE%s", i/2, i%2 ? "_S" : ""),
/*bidir*/ 0))) RC_FAIL(model, rc);
}
}
// SR
{
static const char* s[] = { "SR_ILOGIC_SITE",
"SR_OLOGIC_SITE" };
for (i = 0; i < 4; i++) {
if ((rc = add_switch(model, y, x,
pf("IOI_SR%i", !(i%2)),
pf("%s%s", s[i/2], i%2 ? "" : "_S"),
/*bidir*/ 0))) RC_FAIL(model, rc);
}
}
// IOCLK
{
for (i = 0; i < 4; i++) {
if ((rc = add_switch(model, y, x,
pf("%sIOCLK%i", io_prefix, i),
pf("IOI_CLK%iINTER%s", i%2, (i/2)?"_M":"_S"),
/*bidir*/ 0))) RC_FAIL(model, rc);
}
}
{
const char* pairs[] = {
"D1_OLOGIC_SITE", "OQ_OLOGIC_SITE",
"DATAOUT_IODELAY_SITE", "DDLY_ILOGIC_SITE",
"DDLY2_ILOGIC_SITE", "FABRICOUT_ILOGIC_SITE",
"DDLY_ILOGIC_SITE", "DFB_ILOGIC_SITE",
"D_ILOGIC_IDATAIN_IODELAY", "D_ILOGIC_SITE",
"D_ILOGIC_IDATAIN_IODELAY", "IDATAIN_IODELAY_SITE",
"D_ILOGIC_SITE", "DFB_ILOGIC_SITE",
"D_ILOGIC_SITE", "FABRICOUT_ILOGIC_SITE",
"T1_OLOGIC_SITE", "TQ_OLOGIC_SITE",
"TQ_OLOGIC_SITE", "TFB_ILOGIC_SITE",
"TQ_OLOGIC_SITE", "T_IODELAY_SITE",
"OQ_OLOGIC_SITE", "ODATAIN_IODELAY_SITE",
"OQ_OLOGIC_SITE", "OFB_ILOGIC_SITE" };
for (i = 0; i < sizeof(pairs)/sizeof(*pairs)/2; i++) {
if ((rc = add_switch(model, y, x,
pairs[i*2],
pairs[i*2+1],
/*bidir*/ 0))) RC_FAIL(model, rc);
if ((rc = add_switch(model, y, x,
pf("%s%s", pairs[i*2], "_S"),
pf("%s%s", pairs[i*2+1], "_S"),
/*bidir*/ 0))) RC_FAIL(model, rc);
}
if ((rc = add_switch(model, y, x,
"DATAOUT2_IODELAY_SITE", "DDLY2_ILOGIC_SITE",
/*bidir*/ 0))) RC_FAIL(model, rc);
if ((rc = add_switch(model, y, x,
"DATAOUT2_IODELAY2_SITE_S", "DDLY2_ILOGIC_SITE_S",
/*bidir*/ 0))) RC_FAIL(model, rc);
}
for (i = 0; i < 2; i++) {
if ((rc = add_switch(model, y, x, "IOI_PCI_CE",
pf("OCE_OLOGIC_SITE%s", i?"_S":""),
/*bidir*/ 0))) RC_FAIL(model, rc);
}
for (i = 0; i < 3; i++) {
// 3 because IBUF1 cannot be switched to non-_S
if ((rc = add_switch(model, y, x,
pf("%sIBUF%i", prefix2, i/2),
pf("D_ILOGIC_IDATAIN_IODELAY%s", !(i%2)?"_S":""),
/*bidir*/ 0))) RC_FAIL(model, rc);
}
{
const char* pairs[] = {
"DOUT_IODELAY_SITE%s", "%sO%i",
"OQ_OLOGIC_SITE%s", "%sO%i",
"TOUT_IODELAY_SITE%s", "%sT%i",
"TQ_OLOGIC_SITE%s", "%sT%i" };
for (i = 0; i < 8; i++) {
if ((rc = add_switch(model, y, x,
pf(pairs[(i/2)*2], i%2?"_S":""),
pf(pairs[(i/2)*2+1], prefix2, i%2),
/*bidir*/ 0))) RC_FAIL(model, rc);
}
}
{
const char* pairs[] = {
"SHIFTOUT1_OLOGIC_SITE", "SHIFTIN1_OLOGIC_SITE_S",
"SHIFTOUT2_OLOGIC_SITE", "SHIFTIN2_OLOGIC_SITE_S",
"SHIFTOUT3_OLOGIC_SITE_S", "SHIFTIN3_OLOGIC_SITE",
"SHIFTOUT4_OLOGIC_SITE_S", "SHIFTIN4_OLOGIC_SITE",
"SHIFTOUT_ILOGIC_SITE", "SHIFTIN_ILOGIC_SITE_S",
"SHIFTOUT_ILOGIC_SITE_S", "SHIFTIN_ILOGIC_SITE" };
for (i = 0; i < sizeof(pairs)/sizeof(*pairs)/2; i++) {
if ((rc = add_switch(model, y, x,
pairs[i*2], pairs[i*2+1],
/*bidir*/ 0))) RC_FAIL(model, rc);
}
}
{
const char* pairs[] = {
"IOI_CLKDIST_CLK0_ILOGIC%s", "CLK0_ILOGIC_SITE%s",
"IOI_CLKDIST_CLK0_ILOGIC%s", "IOCLK_IODELAY_SITE%s",
"IOI_CLKDIST_CLK0_OLOGIC%s", "CLK0_OLOGIC_SITE%s",
"IOI_CLKDIST_CLK0_OLOGIC%s", "IOCLK_IODELAY_SITE%s",
"IOI_CLKDIST_CLK1%s", "CLK1_ILOGIC_SITE%s",
"IOI_CLKDIST_CLK1%s", "CLK1_OLOGIC_SITE%s",
"IOI_CLKDIST_CLK1%s", "IOCLK1_IODELAY_SITE%s",
"IOI_CLKDIST_IOCE0%s", "IOCE_ILOGIC_SITE%s",
"IOI_CLKDIST_IOCE1%s", "IOCE_OLOGIC_SITE%s" };
for (i = 0; i < sizeof(pairs)/sizeof(*pairs); i++) {
if ((rc = add_switch(model, y, x,
pf(pairs[(i/2)*2], i%2?"_S":"_M"),
pf(pairs[(i/2)*2+1], i%2?"_S":""),
/*bidir*/ 0))) RC_FAIL(model, rc);
}
}
{
const char* pairs[] = {
"IOI_MCB_DRPADD", "CAL_IODELAY_SITE%s",
"IOI_MCB_DRPBROADCAST", "RST_IODELAY_SITE%s",
"IOI_MCB_DRPCLK", "CLK_IODELAY_SITE%s",
"IOI_MCB_DRPCS", "INC_IODELAY_SITE%s",
"IOI_MCB_DRPSDO", "CE_IODELAY_SITE%s",
"IOI_MCB_DRPTRAIN", "TRAIN_OLOGIC_SITE%s" };
for (i = 0; i < sizeof(pairs)/sizeof(*pairs); i++) {
if ((rc = add_switch(model, y, x,
pairs[(i/2)*2],
pf(pairs[(i/2)*2+1], i%2?"_S":""),
/*bidir*/ 0))) RC_FAIL(model, rc);
}
}
{
const char* pairs[] = {
"IOI_MCB_OUTN_M", "D2_OLOGIC_SITE",
"IOI_MCB_OUTN_S", "D2_OLOGIC_SITE_S",
"IOI_MCB_OUTP_M", "D1_OLOGIC_SITE",
"IOI_MCB_OUTP_S", "D1_OLOGIC_SITE_S",
"IOI_MCB_DQIEN_M", "T2_OLOGIC_SITE",
"IOI_MCB_DQIEN_M", "T2_OLOGIC_SITE_S",
"IOI_MCB_DQIEN_S", "T1_OLOGIC_SITE",
"IOI_MCB_DQIEN_S", "T1_OLOGIC_SITE_S",
"FABRICOUT_ILOGIC_SITE", "IOI_MCB_INBYP_M",
"FABRICOUT_ILOGIC_SITE_S", "IOI_MCB_INBYP_S",
"OUTP_IODELAY_SITE", "IOI_MCB_IN_M",
"STUB_OUTP_IODELAY_S", "IOI_MCB_IN_S" };
for (i = 0; i < sizeof(pairs)/sizeof(*pairs)/2; i++) {
if ((rc = add_switch(model, y, x,
pairs[i*2], pairs[i*2+1],
/*bidir*/ 0))) RC_FAIL(model, rc);
}
}
if (x < LEFT_SIDE_WIDTH
|| x >= model->x_width-RIGHT_SIDE_WIDTH) {
if ((rc = add_switch(model, y, x,
"AUXSDOIN_IODELAY_M", "AUXSDO_IODELAY_M",
/*bidir*/ 0))) RC_FAIL(model, rc);
if ((rc = add_switch(model, y, x,
"AUXSDOIN_IODELAY_S", "AUXSDO_IODELAY_S",
/*bidir*/ 0))) RC_FAIL(model, rc);
} else {
if ((rc = add_switch(model, y, x,
"AUXSDOIN_IODELAY_S_STUB", "AUXSDO_IODELAY_S_STUB",
/*bidir*/ 0))) RC_FAIL(model, rc);
if ((rc = add_switch(model, y, x,
"AUXSDOIN_IODELAY_STUB", "AUXSDO_IODELAY_STUB",
/*bidir*/ 0))) RC_FAIL(model, rc);
}
RC_RETURN(model);
}
static int init_iologic(struct fpga_model *model)
{
int x, y, rc;
RC_CHECK(model);
for (x = LEFT_SIDE_WIDTH; x < model->x_width - RIGHT_SIDE_WIDTH; x++) {
if (has_device(model, TOP_OUTER_IO, x, DEV_ILOGIC)) {
if ((rc = init_iologic_tile(model,
TOP_OUTER_IO, x))) RC_FAIL(model, rc);
}
if (has_device(model, TOP_INNER_IO, x, DEV_ILOGIC)) {
if ((rc = init_iologic_tile(model,
TOP_INNER_IO, x))) RC_FAIL(model, rc);
}
if (has_device(model, model->y_height-BOT_INNER_IO, x, DEV_ILOGIC)) {
if ((rc = init_iologic_tile(model,
model->y_height-BOT_INNER_IO, x))) RC_FAIL(model, rc);
}
if (has_device(model, model->y_height-BOT_OUTER_IO, x, DEV_ILOGIC)) {
if ((rc = init_iologic_tile(model,
model->y_height-BOT_OUTER_IO, x))) RC_FAIL(model, rc);
}
}
for (y = TOP_IO_TILES; y < model->y_height - BOT_IO_TILES; y++) {
if (has_device(model, y, LEFT_IO_DEVS, DEV_ILOGIC)) {
if ((rc = init_iologic_tile(model,
y, LEFT_IO_DEVS))) RC_FAIL(model, rc);
}
if (has_device(model, y, model->x_width-RIGHT_IO_DEVS_O, DEV_ILOGIC)) {
if ((rc = init_iologic_tile(model,
y, model->x_width-RIGHT_IO_DEVS_O))) RC_FAIL(model, rc);
}
}
RC_RETURN(model);
}
static int init_north_south_dirwire_term(struct fpga_model *model)
{
static const int logicin_pairs[] = {21,20, 28,36, 52,44, 60,62};
int x, i, rc;
RC_CHECK(model);
for (x = 0; x < model->x_width; x++) {
if (!is_atx(X_ROUTING_COL, model, x))
continue;
// top
for (i = 0; i < 4; i++) {
rc = add_switch(model,
TOP_INNER_ROW, x,
pf("IOI_TTERM_LOGICIN%i", logicin_pairs[i*2]),
pf("IOI_TTERM_LOGICIN_S%i", logicin_pairs[i*2+1]),
0 /* bidir */);
if (rc) RC_FAIL(model, rc);
}
{ const char* s0_switches[] = {
"ER1E3", "EL1E_S0",
"SR1E_N3", "NL1E_S0",
"SS2E_N3", "NN2E_S0",
"SS4E3", "NW4E_S0",
"SW2E3", "NE2E_S0",
"SW4E3", "WW4E_S0",
"WL1E3", "WR1E_S0",
"WW2E3", "NW2E_S0", "" };
if ((rc = add_switch_set(model, TOP_INNER_ROW, x,
"IOI_TTERM_", s0_switches, /*inc*/ 0))) RC_FAIL(model, rc); }
{ const char* dir[] = {
"NN4B", "SS4A", "NN4A", "SS4M", "NN4M", "SS4C", "NN4C", "SS4E",
"NN2B", "SS2M", "NN2M", "SS2E",
"NE4B", "SE4A", "NE4A", "SE4M",
"NE2B", "SE2M",
"NW4B", "SW4A", "NW4A", "SW4M", "NW2B", "SW2M",
"NL1B", "SL1E",
"NR1B", "SR1E", "" };
if ((rc = add_switch_set(model, TOP_INNER_ROW, x,
"IOI_TTERM_", dir, /*inc*/ 3))) RC_FAIL(model, rc); }
// bottom
if (is_atx(X_FABRIC_BRAM_ROUTING_COL, model, x))
continue;
for (i = 0; i < 4; i++) {
rc = add_switch(model,
model->y_height-BOT_INNER_ROW, x,
pf("IOI_BTERM_LOGICIN%i", logicin_pairs[i*2+1]),
pf("IOI_BTERM_LOGICIN_N%i", logicin_pairs[i*2]),
0 /* bidir */);
if (rc) RC_FAIL(model, rc);
}
{ const char* n3_switches[] = {
"EL1E0", "ER1E_N3",
"NE2E0", "SW2E_N3",
"NL1E_S0", "SR1E_N3",
"NN2E_S0", "SS2E_N3",
"NW2E0", "WW2E_N3",
"NW4E0", "SS4E_N3",
"WR1E0", "WL1E_N3",
"WW4E0", "SW4E_N3", "" };
if ((rc = add_switch_set(model, model->y_height-BOT_INNER_ROW,
x, "IOI_BTERM_", n3_switches, /*inc*/ 0))) RC_FAIL(model, rc); }
{ const char* dir[] = {
"SS4B", "NN4A", "SS4A", "NN4M", "SS4M", "NN4C", "SS4C", "NN4E",
"SS2B", "NN2M", "SS2M", "NN2E",
"SE4B", "NE4A", "SE4A", "NE4M",
"SE2B", "NE2M",
"SW4B", "NW4A", "SW4A", "NW4M", "SW2B", "NW2M",
"NL1E", "SL1B",
"SR1B", "NR1E", "" };
if ((rc = add_switch_set(model, model->y_height-BOT_INNER_ROW,
x, "IOI_BTERM_", dir, /*inc*/ 3))) RC_FAIL(model, rc); }
}
RC_RETURN(model);
}
static int init_east_west_dirwire_term(struct fpga_model *model)
{
int y, rc;
RC_CHECK(model);
for (y = TOP_IO_TILES; y < model->y_height-BOT_IO_TILES; y++) {
if (is_aty(Y_ROW_HORIZ_AXSYMM|Y_CHIP_HORIZ_REGS, model, y))
continue;
// left
{ const char* s[] = {
"NE4C", "NW4M", "SW4C", "SE4E", "SW4M", "SE4C",
"WW4A", "EE4M", "WW4B", "EE4A", "WW4C", "EE4E", "WW4M", "EE4C",
"NW4C", "NE4E",
"WW2B", "EE2M", "WW2M", "EE2E", "NW2M", "NE2E",
"WL1B", "EL1E", "WR1B", "ER1E", "" };
if ((rc = add_switch_set(model, y, LEFT_INNER_COL,
"LTERM_", s, /*inc*/ 3))) RC_FAIL(model, rc); }
{ const char* s[] = { "SW2M", "SE2E", "" };
if ((rc = add_switch_set(model, y, LEFT_INNER_COL,
"LTERM_", s, /*inc*/ 2))) RC_FAIL(model, rc); }
rc = add_switch(model, y, LEFT_INNER_COL,
"LTERM_SW2M3", "LTERM_SE2M3", 0 /* bidir */);
if (rc) RC_FAIL(model, rc);
// right
{ const char* s[] = {
"EE4A", "WW4M", "EE4B", "WW4A", "EE4C", "WW4E", "EE4M", "WW4C",
"SE4C", "SW4E", "SE4M", "SW4C",
"NE4C", "NW4E", "NE4M", "NW4C",
"NE2M", "NW2E", "EE2B", "WW2M", "EE2M", "WW2E", "SE2M", "SW2E",
"EL1B", "WL1E", "ER1B", "WR1E", "" };
if ((rc = add_switch_set(model, y, model->x_width-RIGHT_INNER_O,
"RTERM_", s, /*inc*/ 3))) RC_FAIL(model, rc); }
}
RC_RETURN(model);
}
static int init_ce_clk(struct fpga_model *model)
{
int x, y, i, rc;
RC_CHECK(model);
// There are CE and CLK wires for IO and PLL that are going
// horizontally through the HCLK and vertically through the logic
// dev columns (except no-io).
// The following sets up their corresponding switches in the term
// tiles.
for (y = TOP_IO_TILES; y < model->y_height - BOT_IO_TILES; y++) {
if (is_aty(Y_ROW_HORIZ_AXSYMM, model, y)) {
// left
for (i = 0; i <= 3; i++) {
rc = add_switch(model, y, LEFT_INNER_COL,
pf("HCLK_IOI_LTERM_IOCE%i", i),
pf("HCLK_IOI_LTERM_IOCE%i_E", i),
0 /* bidir */);
if (rc) RC_FAIL(model, rc);
rc = add_switch(model, y, LEFT_INNER_COL,
pf("HCLK_IOI_LTERM_IOCLK%i", i),
pf("HCLK_IOI_LTERM_IOCLK%i_E", i),
0 /* bidir */);
if (rc) RC_FAIL(model, rc);
}
for (i = 0; i <= 1; i++) {
rc = add_switch(model, y, LEFT_INNER_COL,
pf("HCLK_IOI_LTERM_PLLCE%i", i),
pf("HCLK_IOI_LTERM_PLLCE%i_E", i),
0 /* bidir */);
if (rc) RC_FAIL(model, rc);
rc = add_switch(model, y, LEFT_INNER_COL,
pf("HCLK_IOI_LTERM_PLLCLK%i", i),
pf("HCLK_IOI_LTERM_PLLCLK%i_E", i),
0 /* bidir */);
if (rc) RC_FAIL(model, rc);
}
// right
for (i = 0; i <= 3; i++) {
rc = add_switch(model, y, model->x_width-RIGHT_INNER_O,
pf("HCLK_IOI_RTERM_IOCE%i", i),
pf("HCLK_IOI_RTERM_IOCE%i_W", 3-i),
0 /* bidir */);
if (rc) RC_FAIL(model, rc);
rc = add_switch(model, y, model->x_width-RIGHT_INNER_O,
pf("HCLK_IOI_RTERM_IOCLK%i", i),
pf("HCLK_IOI_RTERM_IOCLK%i_W", 3-i),
0 /* bidir */);
if (rc) RC_FAIL(model, rc);
}
for (i = 0; i <= 1; i++) {
rc = add_switch(model, y, model->x_width-RIGHT_INNER_O,
pf("HCLK_IOI_RTERM_PLLCEOUT%i", i),
pf("HCLK_IOI_RTERM_PLLCEOUT%i_W", i),
0 /* bidir */);
if (rc) RC_FAIL(model, rc);
rc = add_switch(model, y, model->x_width-RIGHT_INNER_O,
pf("HCLK_IOI_RTERM_PLLCLKOUT%i", i),
pf("HCLK_IOI_RTERM_PLLCLKOUT%i_W", i),
0 /* bidir */);
if (rc) RC_FAIL(model, rc);
}
}
}
for (x = LEFT_SIDE_WIDTH; x < model->x_width - RIGHT_SIDE_WIDTH; x++) {
if (is_atx(X_FABRIC_LOGIC_COL|X_CENTER_LOGIC_COL, model, x)
&& !is_atx(X_ROUTING_NO_IO, model, x-1)) {
// top
for (i = 0; i <= 3; i++) {
rc = add_switch(model, TOP_INNER_ROW, x,
pf("TTERM_CLB_IOCE%i", i),
pf("TTERM_CLB_IOCE%i_S", i),
0 /* bidir */);
if (rc) RC_FAIL(model, rc);
rc = add_switch(model, TOP_INNER_ROW, x,
pf("TTERM_CLB_IOCLK%i", i),
pf("TTERM_CLB_IOCLK%i_S", i),
0 /* bidir */);
if (rc) RC_FAIL(model, rc);
}
for (i = 0; i <= 1; i++) {
rc = add_switch(model, TOP_INNER_ROW, x,
pf("TTERM_CLB_PLLCE%i", i),
pf("TTERM_CLB_PLLCE%i_S", i),
0 /* bidir */);
if (rc) RC_FAIL(model, rc);
rc = add_switch(model, TOP_INNER_ROW, x,
pf("TTERM_CLB_PLLCLK%i", i),
pf("TTERM_CLB_PLLCLK%i_S", i),
0 /* bidir */);
if (rc) RC_FAIL(model, rc);
}
rc = add_switch(model, TOP_INNER_ROW, x,
"TTERM_CLB_PCICE",
"TTERM_CLB_PCICE_S",
0 /* bidir */);
// bottom
if (rc) RC_FAIL(model, rc);
for (i = 0; i <= 3; i++) {
rc = add_switch(model, model->y_height - BOT_INNER_ROW, x,
pf("BTERM_CLB_CEOUT%i", i),
pf("BTERM_CLB_CEOUT%i_N", i),
0 /* bidir */);
if (rc) RC_FAIL(model, rc);
rc = add_switch(model, model->y_height - BOT_INNER_ROW, x,
pf("BTERM_CLB_CLKOUT%i", i),
pf("BTERM_CLB_CLKOUT%i_N", i),
0 /* bidir */);
if (rc) RC_FAIL(model, rc);
}
for (i = 0; i <= 1; i++) {
rc = add_switch(model, model->y_height - BOT_INNER_ROW, x,
pf("BTERM_CLB_PLLCEOUT%i", i),
pf("BTERM_CLB_PLLCEOUT%i_N", i),
0 /* bidir */);
if (rc) RC_FAIL(model, rc);
rc = add_switch(model, model->y_height - BOT_INNER_ROW, x,
pf("BTERM_CLB_PLLCLKOUT%i", i),
pf("BTERM_CLB_PLLCLKOUT%i_N", i),
0 /* bidir */);
if (rc) RC_FAIL(model, rc);
}
rc = add_switch(model, model->y_height - BOT_INNER_ROW, x,
"BTERM_CLB_PCICE",
"BTERM_CLB_PCICE_N",
0 /* bidir */);
if (rc) RC_FAIL(model, rc);
}
}
RC_RETURN(model);
}
static int init_io_tile(struct fpga_model *model, int y, int x)
{
const char* prefix;
int i, num_devs, rc;
RC_CHECK(model);
if (!y) {
prefix = "TIOB";
rc = add_switch(model, y, x,
pf("%s_DIFFO_OUT2", prefix),
pf("%s_DIFFO_IN3", prefix), 0 /* bidir */);
if (rc) RC_FAIL(model, rc);
num_devs = 2;
} else if (y == model->y_height - BOT_OUTER_ROW) {
prefix = "BIOB";
rc = add_switch(model, y, x,
pf("%s_DIFFO_OUT3", prefix),
pf("%s_DIFFO_IN2", prefix), 0 /* bidir */);
if (rc) RC_FAIL(model, rc);
num_devs = 2;
} else if (!x) {
prefix = "LIOB";
num_devs = 1;
} else if (x == model->x_width - RIGHT_OUTER_O) {
prefix = "RIOB";
num_devs = 1;
} else
EXIT(1);
for (i = 0; i < num_devs*2; i++) {
rc = add_switch(model, y, x,
pf("%s_IBUF%i_PINW", prefix, i),
pf("%s_IBUF%i", prefix, i), 0 /* bidir */);
if (rc) RC_FAIL(model, rc);
rc = add_switch(model, y, x,
pf("%s_O%i", prefix, i),
pf("%s_O%i_PINW", prefix, i), 0 /* bidir */);
if (rc) RC_FAIL(model, rc);
rc = add_switch(model, y, x,
pf("%s_T%i", prefix, i),
pf("%s_T%i_PINW", prefix, i), 0 /* bidir */);
if (rc) RC_FAIL(model, rc);
}
rc = add_switch(model, y, x,
pf("%s_DIFFO_OUT0", prefix),
pf("%s_DIFFO_IN1", prefix), 0 /* bidir */);
if (rc) RC_FAIL(model, rc);
for (i = 0; i <= 1; i++) {
rc = add_switch(model, y, x,
pf("%s_PADOUT%i", prefix, i),
pf("%s_DIFFI_IN%i", prefix, 1-i),
0 /* bidir */);
if (rc) RC_FAIL(model, rc);
}
if (num_devs > 1) {
for (i = 0; i <= 1; i++) {
rc = add_switch(model, y, x,
pf("%s_PADOUT%i", prefix, i+2),
pf("%s_DIFFI_IN%i", prefix, 3-i),
0 /* bidir */);
if (rc) RC_FAIL(model, rc);
}
}
RC_RETURN(model);
}
static int init_io(struct fpga_model *model)
{
int x, y, rc;
RC_CHECK(model);
for (x = 0; x < model->x_width; x++) {
if (has_device(model, /*y*/ 0, x, DEV_IOB)) {
rc = init_io_tile(model, 0, x);
if (rc) RC_FAIL(model, rc);
}
if (has_device(model, model->y_height - BOT_OUTER_ROW, x,
DEV_IOB)) {
rc = init_io_tile(model,
model->y_height-BOT_OUTER_ROW, x);
if (rc) RC_FAIL(model, rc);
}
}
for (y = 0; y < model->y_height; y++) {
if (has_device(model, y, /*x*/ 0, DEV_IOB)) {
rc = init_io_tile(model, y, 0);
if (rc) RC_FAIL(model, rc);
}
if (has_device(model, y, model->x_width - RIGHT_OUTER_O,
DEV_IOB)) {
rc = init_io_tile(model,
y, model->x_width - RIGHT_OUTER_O);
if (rc) RC_FAIL(model, rc);
}
}
RC_RETURN(model);
}
const char* wire_base(enum wire_type w)
{
switch (w) {
case W_NL1: return "NL1";
case W_NR1: return "NR1";
case W_EL1: return "EL1";
case W_ER1: return "ER1";
case W_SL1: return "SL1";
case W_SR1: return "SR1";
case W_WL1: return "WL1";
case W_WR1: return "WR1";
case W_NN2: return "NN2";
case W_NE2: return "NE2";
case W_EE2: return "EE2";
case W_SE2: return "SE2";
case W_SS2: return "SS2";
case W_SW2: return "SW2";
case W_WW2: return "WW2";
case W_NW2: return "NW2";
case W_NN4: return "NN4";
case W_NE4: return "NE4";
case W_EE4: return "EE4";
case W_SE4: return "SE4";
case W_SS4: return "SS4";
case W_SW4: return "SW4";
case W_WW4: return "WW4";
case W_NW4: return "NW4";
}
HERE();
return "";
}
enum wire_type base2wire(const char* str)
{
if (!strncmp(str, "NL1", 3)) return W_NL1;
if (!strncmp(str, "NR1", 3)) return W_NR1;
if (!strncmp(str, "EL1", 3)) return W_EL1;
if (!strncmp(str, "ER1", 3)) return W_ER1;
if (!strncmp(str, "SL1", 3)) return W_SL1;
if (!strncmp(str, "SR1", 3)) return W_SR1;
if (!strncmp(str, "WL1", 3)) return W_WL1;
if (!strncmp(str, "WR1", 3)) return W_WR1;
if (!strncmp(str, "NN2", 3)) return W_NN2;
if (!strncmp(str, "NE2", 3)) return W_NE2;
if (!strncmp(str, "EE2", 3)) return W_EE2;
if (!strncmp(str, "SE2", 3)) return W_SE2;
if (!strncmp(str, "SS2", 3)) return W_SS2;
if (!strncmp(str, "SW2", 3)) return W_SW2;
if (!strncmp(str, "WW2", 3)) return W_WW2;
if (!strncmp(str, "NW2", 3)) return W_NW2;
if (!strncmp(str, "NN4", 3)) return W_NN4;
if (!strncmp(str, "NE4", 3)) return W_NE4;
if (!strncmp(str, "EE4", 3)) return W_EE4;
if (!strncmp(str, "SE4", 3)) return W_SE4;
if (!strncmp(str, "SS4", 3)) return W_SS4;
if (!strncmp(str, "SW4", 3)) return W_SW4;
if (!strncmp(str, "WW4", 3)) return W_WW4;
if (!strncmp(str, "NW4", 3)) return W_NW4;
fprintf(stderr, "#E %s:%i base2wire() %s unknown\n", __FILE__, __LINE__, str);
return 0;
}
static int rotate_num(int cur, int off, int first, int last)
{
if (cur+off > last)
return first + (cur+off-last-1) % ((last+1)-first);
if (cur+off < first)
return last - (first-(cur+off)-1) % ((last+1)-first);
return cur+off;
}
enum wire_type rotate_wire(enum wire_type cur, int off)
{
if (W_IS_LEN1(cur))
return rotate_num(cur, off, FIRST_LEN1, LAST_LEN1);
if (W_IS_LEN2(cur))
return rotate_num(cur, off, FIRST_LEN2, LAST_LEN2);
if (W_IS_LEN4(cur))
return rotate_num(cur, off, FIRST_LEN4, LAST_LEN4);
EXIT(1);
}
enum wire_type wire_to_len(enum wire_type w, int first_len)
{
if (W_IS_LEN1(w))
return w-FIRST_LEN1 + first_len;
if (W_IS_LEN2(w))
return w-FIRST_LEN2 + first_len;
if (W_IS_LEN4(w))
return w-FIRST_LEN4 + first_len;
EXIT(1);
}
static const char* routing_wirestr(enum extra_wires wire,
int routing_io, int gclk_brk)
{
if (routing_io) {
if (wire == GFAN0) return "INT_IOI_GFAN0";
if (wire == GFAN1) return "INT_IOI_GFAN1";
if (wire == LW + LI_A5) return "INT_IOI_LOGICIN_B4";
if (wire == LW + LI_B4) return "INT_IOI_LOGICIN_B10";
}
if (gclk_brk) {
switch (wire) {
case GCLK0: return "GCLK0_BRK";
case GCLK1: return "GCLK1_BRK";
case GCLK2: return "GCLK2_BRK";
case GCLK3: return "GCLK3_BRK";
case GCLK4: return "GCLK4_BRK";
case GCLK5: return "GCLK5_BRK";
case GCLK6: return "GCLK6_BRK";
case GCLK7: return "GCLK7_BRK";
case GCLK8: return "GCLK8_BRK";
case GCLK9: return "GCLK9_BRK";
case GCLK10: return "GCLK10_BRK";
case GCLK11: return "GCLK11_BRK";
case GCLK12: return "GCLK12_BRK";
case GCLK13: return "GCLK13_BRK";
case GCLK14: return "GCLK14_BRK";
case GCLK15: return "GCLK15_BRK";
default: ;
}
}
return fpga_wire2str(wire);
}
static int init_routing_tile(struct fpga_model *model, int y, int x)
{
int i, routing_io, gclk_brk, from_wire, to_wire, is_bidir, rc;
struct fpga_tile* tile;
RC_CHECK(model);
tile = YX_TILE(model, y, x);
routing_io = (tile->type == IO_ROUTING || tile->type == ROUTING_IO_L);
gclk_brk = (tile->type == ROUTING_BRK || tile->type == BRAM_ROUTING_BRK);
// KEEP1
for (i = X_A1; i <= M_WE; i++) {
rc = add_switch(model, y, x, "KEEP1_WIRE",
logicin_s(i, routing_io), 0 /* bidir */);
if (rc) RC_FAIL(model, rc);
}
rc = add_switch(model, y, x, "KEEP1_WIRE", "FAN_B", 0 /* bidir */);
if (rc) RC_FAIL(model, rc);
for (i = 0; i <= 1; i++) {
rc = add_switch(model, y, x, "KEEP1_WIRE",
pf("CLK%i", i), 0 /* bidir */);
if (rc) RC_FAIL(model, rc);
rc = add_switch(model, y, x, "KEEP1_WIRE",
pf("SR%i", i), 0 /* bidir */);
if (rc) RC_FAIL(model, rc);
rc = add_switch(model, y, x,
"KEEP1_WIRE", routing_wirestr(GFAN0+i, routing_io, gclk_brk), 0 /* bidir */);
if (rc) RC_FAIL(model, rc);
}
for (i = 0; i < model->num_bitpos; i++) {
from_wire = model->sw_bitpos[i].from;
to_wire = model->sw_bitpos[i].to;
is_bidir = model->sw_bitpos[i].bidir;
if (routing_io) {
if (from_wire == GFAN0 || from_wire == GFAN1) {
from_wire = VCC_WIRE;
is_bidir = 0;
} else if (to_wire == GFAN0 || to_wire == GFAN1)
is_bidir = 0;
}
rc = add_switch(model, y, x,
routing_wirestr(from_wire, routing_io, gclk_brk),
routing_wirestr(to_wire, routing_io, gclk_brk),
is_bidir);
if (rc) RC_FAIL(model, rc);
if (is_bidir) {
rc = add_switch(model, y, x,
routing_wirestr(to_wire, routing_io, gclk_brk),
routing_wirestr(from_wire, routing_io, gclk_brk),
/* bidir */ 1);
if (rc) RC_FAIL(model, rc);
}
}
if (routing_io) {
// These switches don't come out of the general model because
// they are bidir there and skipped on the reverse side, but
// fall back to regular unidir switches in the io tiles. Can
// be cleaned up one day.
rc = add_switch(model, y, x, "LOGICIN_B6", "INT_IOI_GFAN0", 0);
if (rc) RC_FAIL(model, rc);
rc = add_switch(model, y, x, "LOGICIN_B35", "INT_IOI_GFAN0", 0);
if (rc) RC_FAIL(model, rc);
rc = add_switch(model, y, x, "LOGICIN_B51", "INT_IOI_GFAN1", 0);
if (rc) RC_FAIL(model, rc);
rc = add_switch(model, y, x, "LOGICIN_B53", "INT_IOI_GFAN1", 0);
if (rc) RC_FAIL(model, rc);
}
{ const int logicin_b[] = {20, 21, 28, 36, 44, 52, 60, 62};
for (i = 0; i < sizeof(logicin_b)/sizeof(*logicin_b); i++) {
rc = add_switch(model, y, x,
pf("LOGICIN_B%i", logicin_b[i]),
pf("LOGICIN%i", logicin_b[i]),
/* bidir */ 0);
if (rc) RC_FAIL(model, rc);
}}
RC_RETURN(model);
}
static int init_routing(struct fpga_model *model)
{
int x, y, rc;
RC_CHECK(model);
for (x = 0; x < model->x_width; x++) {
if (!is_atx(X_ROUTING_COL, model, x))
continue;
for (y = TOP_IO_TILES; y < model->y_height-BOT_IO_TILES; y++) {
if (is_aty(Y_ROW_HORIZ_AXSYMM|Y_CHIP_HORIZ_REGS,
model, y))
continue;
rc = init_routing_tile(model, y, x);
if (rc) RC_FAIL(model, rc);
}
}
RC_RETURN(model);
}
int replicate_routing_switches(struct fpga_model *model)
{
struct fpga_tile* tile;
int x, y, first_y, first_x, rc;
RC_CHECK(model);
first_y = -1;
for (x = 0; x < model->x_width; x++) {
if (!is_atx(X_ROUTING_COL, model, x))
continue;
for (y = TOP_IO_TILES; y < model->y_height-BOT_IO_TILES; y++) {
if (is_aty(Y_ROW_HORIZ_AXSYMM|Y_CHIP_HORIZ_REGS,
model, y))
continue;
tile = YX_TILE(model, y, x);
// Some tiles are different so we cannot include
// them in the high-speed replication scheme.
if (tile->type == IO_ROUTING || tile->type == ROUTING_IO_L
|| tile->type == ROUTING_BRK || tile->type == BRAM_ROUTING_BRK) {
rc = init_routing_tile(model, y, x);
if (rc) RC_FAIL(model, rc);
continue;
}
if (first_y == -1) {
first_y = y;
first_x = x;
rc = init_routing_tile(model, y, x);
if (rc) RC_FAIL(model, rc);
continue;
}
rc = replicate_switches_and_names(model,
first_y, first_x, y, x);
if (rc) RC_FAIL(model, rc);
}
}
RC_RETURN(model);
}
static int init_center(struct fpga_model *model)
{
int i, j, rc;
RC_CHECK(model);
{ const char* pairs[] =
{ "CLKC_CKLR%i", "CLKC_GCLK%i",
"CLKC_CKTB%i", "CLKC_GCLK%i",
"CLKC_PLL_L%i", "CLKC_GCLK%i",
"CLKC_PLL_U%i", "CLKC_GCLK%i",
"CLKC_SEL%i_PLL", "S_GCLK_SITE%i",
"I0_GCLK_SITE%i", "O_GCLK_SITE%i",
"O_GCLK_SITE%i", "CLKC_GCLK_MAIN%i" };
int i_dest[2][16] =
{{ 0,1,2,4,3,5,6,7,8,9,10,12,11,13,14,15 },
{ 1,0,3,5,2,4,7,6,9,8,11,13,10,12,15,14 }};
for (i = 0; i < sizeof(pairs)/sizeof(*pairs)/2; i++) {
for (j = 0; j <= 15; j++) {
if ((rc = add_switch(model, model->center_y, model->center_x,
pf(pairs[i*2], j), pf(pairs[i*2+1], j),
/*bidir*/ 0))) RC_FAIL(model, rc);
}
}
for (j = 0; j <= 15; j++) {
if ((rc = add_switch(model, model->center_y, model->center_x,
pf("CLKC_GCLK%i", j), pf("I0_GCLK_SITE%i", i_dest[0][j]),
/*bidir*/ 0))) RC_FAIL(model, rc);
if ((rc = add_switch(model, model->center_y, model->center_x,
pf("CLKC_GCLK%i", j), pf("I1_GCLK_SITE%i", i_dest[1][j]),
/*bidir*/ 0))) RC_FAIL(model, rc);
}}
{ const char *to[] = {
"CLK_PLL_LOCK_LT0", "CLK_PLL_LOCK_LT1",
"CLK_PLL_LOCK_RT0", "CLK_PLL_LOCK_RT1" };
const char *from[] = {
"PLL_LOCK_BOT0", "PLL_LOCK_BOT1",
"PLL_LOCK_TOP0", "PLL_LOCK_TOP1" };
for (i = 0; i < sizeof(to)/sizeof(*to); i++) {
for (j = 0; j < sizeof(from)/sizeof(*from); j++) {
if ((rc = add_switch(model, model->center_y,
model->center_x-CENTER_CMTPLL_O,
from[j], to[i], /*bidir*/ 0))) RC_FAIL(model, rc);
}
}}
{ const char* pairs[] = {
"PLL_LOCK_BOT0", "PLL_LOCK_TOP2",
"PLL_LOCK_BOT1", "PLL_LOCK_TOP2",
"PLL_LOCK_TOP0", "PLL_LOCK_BOT2",
"PLL_LOCK_TOP1", "PLL_LOCK_BOT2" };
for (i = 0; i < sizeof(pairs)/sizeof(*pairs)/2; i++) {
if ((rc = add_switch(model, model->center_y,
model->center_x-CENTER_CMTPLL_O,
pairs[i*2], pairs[i*2+1],
/*bidir*/ 0))) RC_FAIL(model, rc);
}}
{ const char *to[] = {
"REGC_CLKPLL_IO_LT0", "REGC_CLKPLL_IO_LT1",
"REGC_CLKPLL_IO_RT0", "REGC_CLKPLL_IO_RT1",
"REGC_PLLCLK_UP_OUT0", "REGC_PLLCLK_UP_OUT1" };
for (i = 0; i <= 3; i++) {
for (j = 0; j < sizeof(to)/sizeof(*to); j++) {
if ((rc = add_switch(model, model->center_y,
model->center_x-CENTER_CMTPLL_O,
pf("REGC_PLLCLK_DN_IN%i", i), to[j],
/*bidir*/ 0))) RC_FAIL(model, rc);
}
}}
{ const char *to[] = {
"REGC_CLKPLL_IO_LT0", "REGC_CLKPLL_IO_LT1",
"REGC_CLKPLL_IO_RT0", "REGC_CLKPLL_IO_RT1",
"REGC_PLLCLK_DN_OUT0", "REGC_PLLCLK_DN_OUT1" };
for (i = 0; i <= 3; i++) {
for (j = 0; j < sizeof(to)/sizeof(*to); j++) {
if ((rc = add_switch(model, model->center_y,
model->center_x-CENTER_CMTPLL_O,
pf("REGC_PLLCLK_UP_IN%i", i), to[j],
/*bidir*/ 0))) RC_FAIL(model, rc);
}
}}
RC_RETURN(model);
}
static int init_hclk(struct fpga_model *model)
{
int x, y, i, rc;
RC_CHECK(model);
for (x = 0; x < model->x_width; x++) {
if (!is_atx(X_ROUTING_COL, model, x))
continue;
for (y = TOP_IO_TILES; y < model->y_height-BOT_IO_TILES; y++) {
if (!is_aty(Y_ROW_HORIZ_AXSYMM, model, y))
continue;
for (i = 0; i <= 15; i++) {
if ((rc = add_switch(model, y, x,
pf("HCLK_GCLK%i_INT", i), pf("HCLK_GCLK%i", i),
/*bidir*/ 0))) RC_FAIL(model, rc);
if ((rc = add_switch(model, y, x,
pf("HCLK_GCLK%i_INT", i), pf("HCLK_GCLK_UP%i", i),
/*bidir*/ 0))) RC_FAIL(model, rc);
}
}
}
RC_RETURN(model);
}
static int init_logicout_fw(struct fpga_model *model)
{
int i, x, y, rc;
RC_CHECK(model);
for (x = 0; x < model->x_width; x++) {
if (is_atx(X_FABRIC_BRAM_VIA_COL|X_FABRIC_MACC_VIA_COL, model, x)) {
for (y = TOP_IO_TILES; y < model->y_height - BOT_IO_TILES; y++) {
if (is_aty(Y_CHIP_HORIZ_REGS|Y_ROW_HORIZ_AXSYMM, model, y))
continue;
for (i = 0; i <= 23; i++) {
if ((rc = add_switch(model, y, x,
pf("INT_INTERFACE_LOGICOUT_%i", i), pf("INT_INTERFACE_LOGICOUT%i", i),
/*bidir*/ 0))) RC_FAIL(model, rc);
}
}
continue;
}
if (is_atx(X_CENTER_ROUTING_COL, model, x)) {
for (y = TOP_IO_TILES; y < model->y_height - BOT_IO_TILES; y++) {
if (!is_aty(Y_ROW_HORIZ_AXSYMM, model, y))
continue;
for (i = 0; i <= 23; i++) {
if ((rc = add_switch(model, y-1, model->center_x-CENTER_LOGIC_O,
pf("INT_INTERFACE_LOGICOUT_%i", i), pf("INT_INTERFACE_LOGICOUT%i", i),
/*bidir*/ 0))) RC_FAIL(model, rc);
if ((rc = add_switch(model, y+1, model->center_x-CENTER_LOGIC_O,
pf("INT_INTERFACE_LOGICOUT_%i", i), pf("INT_INTERFACE_LOGICOUT%i", i),
/*bidir*/ 0))) RC_FAIL(model, rc);
}
}
continue;
}
if (is_atx(X_LEFT_IO_DEVS_COL, model, x)) {
for (y = TOP_IO_TILES; y < model->y_height - BOT_IO_TILES; y++) {
if (is_aty(Y_CHIP_HORIZ_REGS|Y_ROW_HORIZ_AXSYMM, model, y)
|| has_device(model, y, LEFT_IO_DEVS, DEV_ILOGIC))
continue;
if (has_device(model, y, LEFT_IO_DEVS, DEV_OCT_CALIBRATE)) {
for (i = 0; i <= 23; i++) {
if ((rc = add_switch(model, y, x,
pf("INT_INTERFACE_LOCAL_LOGICOUT_%i", i), pf("INT_INTERFACE_LOCAL_LOGICOUT%i", i),
/*bidir*/ 0))) RC_FAIL(model, rc);
}
continue;
}
// todo: this is probably not right...
if (y == model->center_y-1 || y == model->center_y-2
|| y < TOP_IO_TILES + HALF_ROW
|| y == model->y_height-BOT_INNER_IO)
continue;
for (i = 0; i <= 23; i++) {
if ((rc = add_switch(model, y, x,
pf("INT_INTERFACE_LOGICOUT_%i", i), pf("INT_INTERFACE_LOGICOUT%i", i),
/*bidir*/ 0))) RC_FAIL(model, rc);
}
}
continue;
}
if (is_atx(X_RIGHT_IO_DEVS_COL, model, x)) {
for (y = TOP_IO_TILES; y < model->y_height - BOT_IO_TILES; y++) {
if (is_aty(Y_CHIP_HORIZ_REGS|Y_ROW_HORIZ_AXSYMM, model, y)
|| has_device(model, y, model->x_width-RIGHT_IO_DEVS_O, DEV_ILOGIC))
continue;
if (has_device(model, y, model->x_width-RIGHT_IO_DEVS_O, DEV_BSCAN)
|| has_device(model, y, model->x_width-RIGHT_IO_DEVS_O, DEV_ICAP)
|| has_device(model, y, model->x_width-RIGHT_IO_DEVS_O, DEV_SLAVE_SPI)) {
for (i = 0; i <= 23; i++) {
if ((rc = add_switch(model, y, x,
pf("INT_INTERFACE_LOCAL_LOGICOUT_%i", i), pf("INT_INTERFACE_LOCAL_LOGICOUT%i", i),
/*bidir*/ 0))) RC_FAIL(model, rc);
}
continue;
}
// todo: this is probably not right...
if (y == model->center_y-1 || y == model->center_y-2
|| y < TOP_IO_TILES + HALF_ROW)
continue;
for (i = 0; i <= 23; i++) {
if ((rc = add_switch(model, y, x,
pf("INT_INTERFACE_LOGICOUT_%i", i), pf("INT_INTERFACE_LOGICOUT%i", i),
/*bidir*/ 0))) RC_FAIL(model, rc);
}
}
continue;
}
}
RC_RETURN(model);
}
static int init_bram(struct fpga_model *model)
{
int i, x, y, tile0_to_3, wire_num, rc;
RC_CHECK(model);
for (x = 0; x < model->x_width; x++) {
if (!is_atx(X_FABRIC_BRAM_COL, model, x))
continue;
for (y = TOP_IO_TILES; y < model->y_height - BOT_IO_TILES; y++) {
if (!has_device(model, y, x, DEV_BRAM16))
continue;
{ const char* pairs[] = {
"BRAM_CLK%c_INT1", "RAMB16BWER_CLK%c",
"BRAM_CLK%c_INT1", "RAMB8BWER_0_CLK%c",
"BRAM_CLK%c_INT2", "RAMB8BWER_1_CLK%c" };
for (i = 0; i < sizeof(pairs)/sizeof(*pairs)/2; i++) {
if ((rc = add_switch(model, y, x,
pf(pairs[i*2], '0'+0), pf(pairs[i*2+1], 'A'+0),
/*bidir*/ 0))) RC_FAIL(model, rc);
if ((rc = add_switch(model, y, x,
pf(pairs[i*2], '0'+1), pf(pairs[i*2+1], 'A'+1),
/*bidir*/ 0))) RC_FAIL(model, rc);
}}
{ const char *s[] = {
"BRAM_SR0_INT1", "RAMB16BWER_RSTA",
"BRAM_SR0_INT1", "RAMB8BWER_0_RSTA",
"BRAM_SR0_INT2", "RAMB8BWER_1_RSTA",
"BRAM_SR1_INT1", "RAMB16BWER_RSTB",
"BRAM_SR1_INT1", "RAMB8BWER_0_RSTB",
"BRAM_SR1_INT2", "RAMB8BWER_1_RSTB" };
for (i = 0; i < sizeof(s)/sizeof(*s)/2; i++) {
if ((rc = add_switch(model, y, x, s[i*2],
s[i*2+1], /*bidir*/ 0))) RC_FAIL(model, rc);
}}
for (i = BI_FIRST; i <= BI_LAST; i++) {
fdev_bram_inbit(BW+i, &tile0_to_3, &wire_num);
if (tile0_to_3 == -1) { HERE(); continue; }
if ((rc = add_switch(model, y, x,
pf("BRAM_LOGICINB%i_INT%i", wire_num, tile0_to_3),
fpga_wire2str(BW+i),
/*bidir*/ 0))) RC_FAIL(model, rc);
if (fdev_is_bram8_inwire(i)) {
fdev_bram_inbit(BW+(B8_0|i), &tile0_to_3, &wire_num);
if (tile0_to_3 == -1) { HERE(); continue; }
if ((rc = add_switch(model, y, x,
pf("BRAM_LOGICINB%i_INT%i", wire_num, tile0_to_3),
fpga_wire2str(BW+(B8_0|i)),
/*bidir*/ 0))) RC_FAIL(model, rc);
fdev_bram_inbit(BW+(B8_1|i), &tile0_to_3, &wire_num);
if (tile0_to_3 == -1) { HERE(); continue; }
if ((rc = add_switch(model, y, x,
pf("BRAM_LOGICINB%i_INT%i", wire_num, tile0_to_3),
fpga_wire2str(BW+(B8_1|i)),
/*bidir*/ 0))) RC_FAIL(model, rc);
}
}
for (i = BO_FIRST; i <= BO_LAST; i++) {
fdev_bram_outbit(BW+i, &tile0_to_3, &wire_num);
if (tile0_to_3 == -1) { HERE(); continue; }
if ((rc = add_switch(model, y, x,
fpga_wire2str(BW+i),
pf("BRAM_LOGICOUT%i_INT%i", wire_num, tile0_to_3),
/*bidir*/ 0))) RC_FAIL(model, rc);
if (fdev_is_bram8_outwire(i)) {
fdev_bram_outbit(BW+(B8_0|i), &tile0_to_3, &wire_num);
if (tile0_to_3 == -1) { HERE(); continue; }
if ((rc = add_switch(model, y, x,
fpga_wire2str(BW+(B8_0|i)),
pf("BRAM_LOGICOUT%i_INT%i", wire_num, tile0_to_3),
/*bidir*/ 0))) RC_FAIL(model, rc);
fdev_bram_outbit(BW+(B8_1|i), &tile0_to_3, &wire_num);
if (tile0_to_3 == -1) { HERE(); continue; }
if ((rc = add_switch(model, y, x,
fpga_wire2str(BW+(B8_1|i)),
pf("BRAM_LOGICOUT%i_INT%i", wire_num, tile0_to_3),
/*bidir*/ 0))) RC_FAIL(model, rc);
}
}
}
}
RC_RETURN(model);
}
static int init_macc(struct fpga_model *model)
{
int i, x, y, tile0_to_3, wire_num, rc;
RC_CHECK(model);
for (x = 0; x < model->x_width; x++) {
if (!is_atx(X_FABRIC_MACC_COL, model, x))
continue;
for (y = TOP_IO_TILES; y < model->y_height - BOT_IO_TILES; y++) {
if (!has_device(model, y, x, DEV_MACC))
continue;
{ const char *s[] = {
"MACC_SR0_INT0", "RSTD_DSP48A1_SITE",
"MACC_SR0_INT1", "RSTP_DSP48A1_SITE",
"MACC_SR0_INT2", "RSTC_DSP48A1_SITE",
"MACC_SR0_INT3", "RSTA_DSP48A1_SITE",
"MACC_SR1_INT0", "RSTCARRYIN_DSP48A1_SITE",
"MACC_SR1_INT1", "RSTOPMODE_DSP48A1_SITE",
"MACC_SR1_INT2", "RSTM_DSP48A1_SITE",
"MACC_SR1_INT3", "RSTB_DSP48A1_SITE",
"MACC_CLK0_INT2", "CLK_DSP48A1_SITE" };
for (i = 0; i < sizeof(s)/sizeof(*s)/2; i++) {
if ((rc = add_switch(model, y, x, s[i*2],
s[i*2+1], /*bidir*/ 0))) RC_FAIL(model, rc);
}}
for (i = MI_FIRST; i <= MI_LAST; i++) {
fdev_macc_inbit(MW+i, &tile0_to_3, &wire_num);
if (tile0_to_3 == -1) { HERE(); continue; }
if ((rc = add_switch(model, y, x,
pf("MACC_LOGICINB%i_INT%i", wire_num, tile0_to_3),
fpga_wire2str(MW+i),
/*bidir*/ 0))) RC_FAIL(model, rc);
}
for (i = MO_FIRST; i <= MO_LAST; i++) {
fdev_macc_outbit(MW+i, &tile0_to_3, &wire_num);
if (tile0_to_3 == -1) { HERE(); continue; }
if ((rc = add_switch(model, y, x,
fpga_wire2str(MW+i),
pf("MACC_LOGICOUT%i_INT%i", wire_num, tile0_to_3),
/*bidir*/ 0))) RC_FAIL(model, rc);
}
if (y != TOP_IO_TILES+3) { // exclude topmost macc dev
if ((rc = add_switch(model, y, x,
"CARRYOUT_DSP48A1_SITE", "CARRYOUT_DSP48A1_B_SITE",
/*bidir*/ 0))) RC_FAIL(model, rc);
for (i = 0; i <= 17; i++) {
if ((rc = add_switch(model, y, x,
pf("BCOUT%i_DSP48A1_SITE", i), pf("BCOUT%i_DSP48A1_B_SITE", i),
/*bidir*/ 0))) RC_FAIL(model, rc);
}
for (i = 0; i <= 47; i++) {
if ((rc = add_switch(model, y, x,
pf("PCOUT%i_DSP48A1_SITE", i), pf("PCOUT%i_DSP48A1_B_SITE", i),
/*bidir*/ 0))) RC_FAIL(model, rc);
}
}
}
}
RC_RETURN(model);
}
static int init_topbot_tterm_gclk(struct fpga_model *model)
{
int i, rc;
RC_CHECK(model);
for (i = 0; i <= 15; i++) {
if ((rc = add_switch(model, TOP_INNER_ROW, model->center_x + CENTER_X_PLUS_1, pf("IOI_TTERM_GCLK%i", i),
"BUFPLL_TOP_GCLK0", /*bidir*/ 0))) RC_FAIL(model, rc);
if ((rc = add_switch(model, TOP_INNER_ROW, model->center_x + CENTER_X_PLUS_1, pf("IOI_TTERM_GCLK%i", i),
"BUFPLL_TOP_GCLK1", /*bidir*/ 0))) RC_FAIL(model, rc);
if ((rc = add_switch(model, model->y_height - BOT_INNER_ROW, model->center_x + CENTER_X_PLUS_1, pf("IOI_BTERM_GCLK%i", i),
"BUFPLL_BOT_GCLK0", /*bidir*/ 0))) RC_FAIL(model, rc);
if ((rc = add_switch(model, model->y_height - BOT_INNER_ROW, model->center_x + CENTER_X_PLUS_1, pf("IOI_BTERM_GCLK%i", i),
"BUFPLL_BOT_GCLK1", /*bidir*/ 0))) RC_FAIL(model, rc);
}
RC_RETURN(model);
}
static int init_bufio_tile(struct fpga_model *model, int y, int x, const char *s1, const char *s2)
{
int i, j, rc;
RC_CHECK(model);
{ static const char *s[] = {
"I_BUFIO2_%s_SITE%i", "O_BUFIO2_%s_SITE%i",
"I_BUFIO2_%s_SITE%i", "ODIV_BUFIO2_%s_SITE%i",
"IFB_BUFIO2FB_%s_SITE%i", "OFB_BUFIO2FB_%s_SITE%i" };
for (i = 0; i < sizeof(s)/sizeof(*s)/2; i++) {
for (j = 0; j <= 7; j++) {
if ((rc = add_switch(model, y, x, pf(s[i*2], s2, j),
pf(s[i*2+1], s2, j), /*bidir*/ 0))) RC_FAIL(model, rc);
}
}}
{ static const char *s[] = {
"O_BUFIO2_%s_SITE%i", "%s_IOCLKOUT%i",
"ODIV_BUFIO2_%s_SITE%i", "%s_CKPIN_OUT%i",
"OE_BUFIO2_%s_SITE%i", "%s_IOCEOUT%i",
"OFB_BUFIO2FB_%s_SITE%i", "%s_CLK_FEEDBACK%i" };
for (i = 0; i < sizeof(s)/sizeof(*s)/2; i++) {
for (j = 0; j <= 7; j++) {
if ((rc = add_switch(model, y, x, pf(s[i*2], s2, j),
pf(s[i*2+1], s1, j), /*bidir*/ 0))) RC_FAIL(model, rc);
}
}}
{ static const char *s[] = {
"%s_CFB%i", "IFB_BUFIO2FB_%s_SITE%i",
"%s_CFB1_%i", "IB_BUFIO2FB_%s_SITE%i",
"%s_DFB%i", "IFB_BUFIO2FB_%s_SITE%i",
"%s_DFB%i", "I_BUFIO2_%s_SITE%i",
"%s_GTPFB%i", "IFB_BUFIO2FB_%s_SITE%i",
"%s_CLKPIN%i", "IB_BUFIO2_%s_SITE%i",
"%s_CLKPIN%i", "I_BUFIO2_%s_SITE%i" };
for (i = 0; i < sizeof(s)/sizeof(*s)/2; i++) {
for (j = 0; j <= 7; j++) {
if ((rc = add_switch(model, y, x, pf(s[i*2], s1, j),
pf(s[i*2+1], s2, j), /*bidir*/ 0))) RC_FAIL(model, rc);
}
}}
for (j = 0; j <= 7; j++) {
if ((rc = add_switch(model, y, x, pf("%s_VCC", s1),
pf("IB_BUFIO2_%s_SITE%i", s2, j),
/*bidir*/ 0))) RC_FAIL(model, rc);
}
{ int n[] = { 1, 0, 3, 2, 5, 4, 7, 6 };
const char *s[] = {
"%s_CLKPIN%i", "IFB_BUFIO2FB_%s_SITE%i",
"%s_DFB%i", "IB_BUFIO2_%s_SITE%i" };
for (i = 0; i < sizeof(s)/sizeof(*s)/2; i++) {
for (j = 0; j <= 7; j++) {
if ((rc = add_switch(model, y, x, pf(s[i*2], s1, j),
pf(s[i*2+1], s2, n[j]),
/*bidir*/ 0))) RC_FAIL(model, rc);
}
}}
{ int n1[] = { 1, 0, 3, 2, 0, 0, 2, 2};
int n2[] = { 4, 4, 6, 6, 1, 1, 3, 3};
int n3[] = { 5, 5, 7, 7, 5, 4, 7, 6};
const char *s[] = {
"%s_CLKPIN%i", "IB_BUFIO2_%s_SITE%i",
"%s_CLKPIN%i", "I_BUFIO2_%s_SITE%i" };
for (i = 0; i < sizeof(s)/sizeof(*s)/2; i++) {
for (j = 0; j <= 7; j++) {
if ((rc = add_switch(model, y, x, pf(s[i*2], s1, j),
pf(s[i*2+1], s2, n1[j]),
/*bidir*/ 0))) RC_FAIL(model, rc);
if ((rc = add_switch(model, y, x, pf(s[i*2], s1, j),
pf(s[i*2+1], s2, n2[j]),
/*bidir*/ 0))) RC_FAIL(model, rc);
if ((rc = add_switch(model, y, x, pf(s[i*2], s1, j),
pf(s[i*2+1], s2, n3[j]),
/*bidir*/ 0))) RC_FAIL(model, rc);
}
}}
RC_RETURN(model);
}
static int init_bufio(struct fpga_model *model)
{
int y, x, j, rc;
const char *s1, *s2;
const int lr_n[] = { 0, 0, 2, 2, 4, 5, 6, 7 };
RC_CHECK(model);
y = TOP_OUTER_ROW;
x = model->center_x-CENTER_CMTPLL_O;
s1 = "REGT";
s2 = "TOP";
rc = init_bufio_tile(model, y, x, s1, s2);
if (rc) RC_FAIL(model, rc);
for (j = 0; j <= 7; j++) {
if ((rc = add_switch(model, y, x, pf("%s_GTPCLK%i", s1, j),
pf("I_BUFIO2_%s_SITE%i", s2, j), /*bidir*/ 0))) RC_FAIL(model, rc);
}
y = model->center_y;
x = LEFT_OUTER_COL;
s1 = "REGL";
s2 = "LEFT";
rc = init_bufio_tile(model, y, x, s1, s2);
if (rc) RC_FAIL(model, rc);
for (j = 0; j <= 7; j++) {
if ((rc = add_switch(model, y, x, pf("%s_GTPCLK%i", s1, lr_n[j]),
pf("I_BUFIO2_%s_SITE%i", s2, j), /*bidir*/ 0))) RC_FAIL(model, rc);
}
y = model->center_y;
x = model->x_width-RIGHT_OUTER_O;
s1 = "REGR";
s2 = "RIGHT";
rc = init_bufio_tile(model, y, x, s1, s2);
if (rc) RC_FAIL(model, rc);
for (j = 0; j <= 7; j++) {
if ((rc = add_switch(model, y, x, pf("%s_GTPCLK%i", s1, lr_n[j]),
pf("I_BUFIO2_%s_SITE%i", s2, j), /*bidir*/ 0))) RC_FAIL(model, rc);
}
y = model->y_height-BOT_OUTER_ROW;
x = model->center_x-CENTER_CMTPLL_O;
s1 = "REGB";
s2 = "BOT";
rc = init_bufio_tile(model, y, x, s1, s2);
if (rc) RC_FAIL(model, rc);
for (j = 0; j <= 7; j++) {
if ((rc = add_switch(model, y, x, pf("%s_GTPCLK%i", s1, j),
pf("I_BUFIO2_%s_SITE%i", s2, j), /*bidir*/ 0))) RC_FAIL(model, rc);
}
RC_RETURN(model);
}
static int init_bscan(struct fpga_model *model)
{
int y, x, num_bscan_devs, i, j, rc;
const char *s[] = {
"BSCAN%i_CAPTURE_PINWIRE",
"BSCAN%i_DRCK_PINWIRE",
"BSCAN%i_RESET_PINWIRE",
"BSCAN%i_RUNTEST_PINWIRE",
"BSCAN%i_SHIFT_PINWIRE",
"BSCAN%i_TCK_PINWIRE",
"BSCAN%i_TDI_PINWIRE",
"BSCAN%i_TMS_PINWIRE",
"BSCAN%i_UPDATE_PINWIRE",
"BSCAN%i_SEL_PINWIRE" };
RC_CHECK(model);
x = model->x_width-RIGHT_IO_DEVS_O;
for (y = TOP_IO_TILES; y < model->y_height-BOT_IO_TILES; y++) {
num_bscan_devs = has_device(model, y, x, DEV_BSCAN);
if (!num_bscan_devs) continue;
if (num_bscan_devs != 2) {
HERE();
continue;
}
for (i = 0; i <= 1; i++) {
for (j = 0; j < sizeof(s)/sizeof(*s); j++) {
if ((rc = add_switch(model, y, x, pf(s[j], i+1),
pf("INT_INTERFACE_LOCAL_LOGICOUT_%i", i*10+j), /*bidir*/ 0))) RC_FAIL(model, rc);
}
if ((rc = add_switch(model, y, x, pf("INT_INTERFACE_LOCAL_LOGICBIN%i", i+1),
pf("BSCAN%i_TDO_PINWIRE", i+1), /*bidir*/ 0))) RC_FAIL(model, rc);
}
}
RC_RETURN(model);
}
static int init_dcm(struct fpga_model *model)
{
int y, x, i, j, k, num_devs, rc;
RC_CHECK(model);
x = model->center_x-CENTER_CMTPLL_O;
for (y = TOP_IO_TILES; y < model->y_height-BOT_IO_TILES; y++) {
num_devs = has_device(model, y, x, DEV_DCM);
if (!num_devs) continue;
if (num_devs != 2) {
HERE();
continue;
}
for (i = 0; i <= 1; i++) { // 2 dcm devs
for (j = 0; j <= 9; j++) { // 10 clk outs
for (k = 0; k <= 15; k++) { // 16 hclk dests
if ((rc = add_switch(model, y, x,
pf("DCM%i_CLKOUT%i", i+1, j),
pf("DCM_HCLK%i", k),
/*bidir*/ 0))) RC_FAIL(model, rc);
}
}
}
for (k = 0; k <= 15; k++) { // 16 hclk dests
if ((rc = add_switch(model, y, x,
pf("DCM_FABRIC_CLK%i", k), pf("DCM_HCLK%i", k),
/*bidir*/ 0))) RC_FAIL(model, rc);
if ((rc = add_switch(model, y, x,
pf("DCM_HCLK%i", k), pf("DCM_HCLK%i_N", k),
/*bidir*/ 0))) RC_FAIL(model, rc);
if (y > model->center_y) { // lower half
if ((rc = add_switch(model, y, x,
pf("DCM_HCLK%i_N", k), pf("PLL_CLK_CASC_TOP%i", k),
/*bidir*/ 0))) RC_FAIL(model, rc);
if ((rc = add_switch(model, y, x,
pf("PLL_CLK_CASC_BOT%i", k), pf("PLL_CLK_CASC_TOP%i", k),
/*bidir*/ 0))) RC_FAIL(model, rc);
} else { // upper half
if ((rc = add_switch(model, y, x,
pf("DCM_HCLK%i_N", k), pf("PLL_CLK_CASC_BOT%i", k),
/*bidir*/ 0))) RC_FAIL(model, rc);
if ((rc = add_switch(model, y, x,
pf("PLL_CLK_CASC_TOP%i", k), pf("PLL_CLK_CASC_BOT%i", k),
/*bidir*/ 0))) RC_FAIL(model, rc);
}
}
for (i = 0; i <= 7; i++) { // 8 wires
for (j = 1; j <= 2; j++) { // dcm 1 and 2
if ((rc = add_switch(model, y, x,
pf("DCM_CLK_FEEDBACK_LR_TOP%i", i), pf("DCM%i_CLKFB", j),
/*bidir*/ 0))) RC_FAIL(model, rc);
if ((rc = add_switch(model, y, x,
pf("DCM_CLK_FEEDBACK_TB_BOT%i", i), pf("DCM%i_CLKFB", j),
/*bidir*/ 0))) RC_FAIL(model, rc);
if ((rc = add_switch(model, y, x,
pf("DCM_CLK_INDIRECT_LR_TOP%i", i), pf("DCM%i_CLKIN", j),
/*bidir*/ 0))) RC_FAIL(model, rc);
if ((rc = add_switch(model, y, x,
pf("DCM_CLK_INDIRECT_TB_BOT%i", i), pf("DCM%i_CLKIN", j),
/*bidir*/ 0))) RC_FAIL(model, rc);
}
}
// logicin
{ const char *clb1_in0_to_62[] = {
/* 0*/ 0, 0, 0, 0, 0, "DCM2_STSADRS3", 0, 0,
/* 8*/ 0, 0, 0, 0, "DCM2_STSADRS2", 0, 0, "DCM2_PSINCDEC",
/*16*/ "DCM2_STSADRS0", 0, 0, 0, 0, 0, 0, 0,
/*24*/ "DCM2_PSEN", "DCM2_SE_CLK_IN1", 0, 0, 0, 0, 0, 0,
/*32*/ 0, 0, "DCM2_CTLOSC2", 0, "DCM2_STSADRS4", 0, 0, 0,
/*40*/ 0, 0, "DCM2_FREEZEDFS", 0, 0, 0, 0, "DCM2_RST",
/*48*/ 0, 0, 0, 0, 0, 0, "DCM2_CTLOSC1", 0,
/*56*/ 0, "DCM2_SE_CLK_IN0", 0, 0, 0, 0, "DCM2_STSADRS1" };
const char *clb2_in0_to_62[] = {
/* 0*/ 0, 0, "DCM_FABRIC_CLK13", "DCM_FABRIC_CLK5", 0, "DCM1_STSADRS3", 0, 0,
/* 8*/ "DCM_FABRIC_CLK15", 0, 0, 0, "DCM1_STSADRS2", 0, 0, "DCM1_PSINCDEC",
/*16*/ "DCM1_STSADRS0", 0, 0, "DCM_FABRIC_CLK7", 0, 0, 0, 0,
/*24*/ "DCM1_PSEN", "DCM1_SE_CLK_IN1", "DCM_FABRIC_CLK2", 0, "DCM_FABRIC_CLK8", "DCM_FABRIC_CLK9", "DCM_FABRIC_CLK3", 0,
/*32*/ "DCM_FABRIC_CLK10", 0, "DCM1_CTLOSC2", 0, "DCM1_STSADRS4", 0, 0, "DCM_FABRIC_CLK14",
/*40*/ 0, "DCM_FABRIC_CLK4", "DCM1_FREEZEDFS", 0, "DCM_FABRIC_CLK0", 0, 0, "DCM1_RST",
/*48*/ 0, 0, 0, 0, "DCM_FABRIC_CLK12", 0, "DCM1_CTLOSC1", "DCM_FABRIC_CLK1",
/*56*/ 0, "DCM1_SE_CLK_IN0", "DCM_FABRIC_CLK6", "DCM_FABRIC_CLK11", 0, 0, "DCM1_STSADRS1" };
for (i = 0; i < 63; i++) {
if (clb1_in0_to_62[i])
if ((rc = add_switch(model, y, x,
pf("DCM_CLB1_LOGICINB%i", i), clb1_in0_to_62[i],
/*bidir*/ 0))) RC_FAIL(model, rc);
if (clb2_in0_to_62[i])
if ((rc = add_switch(model, y, x,
pf("DCM_CLB2_LOGICINB%i", i), clb2_in0_to_62[i],
/*bidir*/ 0))) RC_FAIL(model, rc);
}}
// logicout
for (i = 0; i <= 7; i++) {
if ((rc = add_switch(model, y, x,
pf("DCM1_STATUS%i", i), pf("DCM_CLB2_LOGICOUT%i", 16+i),
/*bidir*/ 0))) RC_FAIL(model, rc);
if ((rc = add_switch(model, y, x,
pf("DCM2_STATUS%i", i), pf("DCM_CLB1_LOGICOUT%i", 16+i),
/*bidir*/ 0))) RC_FAIL(model, rc);
}
if ((rc = add_switch(model, y, x, "DCM1_LOCKED",
"DCM_CLB2_LOGICOUT14", /*bidir*/ 0))) RC_FAIL(model, rc);
if ((rc = add_switch(model, y, x, "DCM1_PSDONE",
"DCM_CLB2_LOGICOUT15", /*bidir*/ 0))) RC_FAIL(model, rc);
if ((rc = add_switch(model, y, x, "DCM2_LOCKED",
"DCM_CLB1_LOGICOUT14", /*bidir*/ 0))) RC_FAIL(model, rc);
if ((rc = add_switch(model, y, x, "DCM2_PSDONE",
"DCM_CLB1_LOGICOUT15", /*bidir*/ 0))) RC_FAIL(model, rc);
{ const char *s[] = {
"CLK0", "CLK90", "CLK180", "CLK270", "CLK2X",
"CLK2X180", "CLKDV", "CLKFX", "CLKFX180", "CONCUR" };
for (i = 0; i < sizeof(s)/sizeof(*s); i++) {
for (j = 1; j <= 2; j++) { // dcm1 and dcm2
if ((rc = add_switch(model, y, x, pf("DCM%i_%s", j, s[i]),
pf("DCM%i_CLKOUT%i", j, i), /*bidir*/ 0))) RC_FAIL(model, rc);
if ((rc = add_switch(model, y, x, pf("DCM%i_%s", j, s[i]),
pf("DCM%i_CLK_TO_PLL", j), /*bidir*/ 0))) RC_FAIL(model, rc);
if ((rc = add_switch(model, y, x, pf("DCM%i_%s", j, s[i]),
pf("DCM%i_%s_TEST", j, s[i]), /*bidir*/ 0))) RC_FAIL(model, rc);
if ((rc = add_switch(model, y, x, pf("DCM%i_%s_TEST", j, s[i]),
pf("DCM_%i_TESTCLK_PINWIRE", j==1?1:0), /*bidir*/ 0))) RC_FAIL(model, rc);
}
}}
{ const char *s[] = {
"CMT_DCM_LOCK_UP0", "CMT_DCM_LOCK_DN0",
"CMT_DCM_LOCK_UP1", "CMT_DCM_LOCK_DN1",
"DCM_IOCLK_UP0", "DCM_IOCLK_DOWN0",
"DCM_IOCLK_UP1", "DCM_IOCLK_DOWN1",
"DCM_IOCLK_UP2", "DCM_IOCLK_DOWN2",
"DCM_IOCLK_UP3", "DCM_IOCLK_DOWN3",
"DCM1_CLK_TO_PLL", "DCM_1_MUXED_CLK_PINWIRE",
"DCM2_CLK_TO_PLL", "DCM_0_MUXED_CLK_PINWIRE",
"DCM_CLB1_CLK0", "DCM2_CLK_FROM_BUFG0",
"DCM_CLB1_CLK1", "DCM2_CLK_FROM_BUFG1",
"DCM_CLB2_CLK0", "DCM1_CLK_FROM_BUFG0",
"DCM_CLB2_CLK1", "DCM1_CLK_FROM_BUFG1",
"DCM1_GFAN1", "DCM2_PSCLK",
"DCM2_GFAN1", "DCM1_PSCLK" };
for (i = 0; i < sizeof(s)/sizeof(*s)/2; i++) {
if ((rc = add_switch(model, y, x, s[i*2], s[i*2+1],
/*bidir*/ 0))) RC_FAIL(model, rc);
}}
{ const char *s[] = {
"DCM%i_CLK_FROM_BUFG0", "DCM%i_CLKFB",
"DCM%i_CLK_FROM_BUFG1", "DCM%i_CLKIN",
"DCM%i_CLK_FROM_PLL", "DCM%i_CLKIN",
"DCM%i_SE_CLK_IN0", "DCM%i_CLKFB",
"DCM%i_SE_CLK_IN1", "DCM%i_CLKIN" };
for (j = 1; j <= 2; j++) { // dcm1 and dcm2
for (i = 0; i < sizeof(s)/sizeof(*s)/2; i++) {
if ((rc = add_switch(model, y, x, pf(s[i*2], j), pf(s[i*2+1], j),
/*bidir*/ 0))) RC_FAIL(model, rc);
}
}}
if (y > model->center_y) { // lower half
const char *s[] = {
"CMT_DCM_LOCK_UP2", "CMT_DCM_LOCK_DN2",
"DCM_IOCLK_UP4", "DCM_IOCLK_DOWN4",
"DCM_IOCLK_UP5", "DCM_IOCLK_DOWN5" };
for (i = 0; i < sizeof(s)/sizeof(*s)/2; i++) {
if ((rc = add_switch(model, y, x, s[i*2], s[i*2+1],
/*bidir*/ 0))) RC_FAIL(model, rc);
}
} else { // upper half
const char *s[] = {
"CMT_DCM_LOCK_DN2", "CMT_DCM_LOCK_UP2",
"DCM_IOCLK_DOWN4", "DCM_IOCLK_UP4",
"DCM_IOCLK_DOWN5", "DCM_IOCLK_UP5" };
for (i = 0; i < sizeof(s)/sizeof(*s)/2; i++) {
if ((rc = add_switch(model, y, x, s[i*2], s[i*2+1],
/*bidir*/ 0))) RC_FAIL(model, rc);
}
}
}
RC_RETURN(model);
}
static int init_pll(struct fpga_model *model)
{
int y, x, i, j, num_devs, rc;
RC_CHECK(model);
x = model->center_x-CENTER_CMTPLL_O;
for (y = TOP_IO_TILES; y < model->y_height-BOT_IO_TILES; y++) {
num_devs = has_device(model, y, x, DEV_PLL);
if (!num_devs) continue;
if (num_devs != 1) {
HERE();
continue;
}
for (i = 0; i <= 5; i++) { // 6 clk outs
for (j = 0; j <= 15; j++) { // 16 hclk dests
if ((rc = add_switch(model, y, x,
pf("CMT_PLL_CLKOUT%i", i),
pf("CMT_PLL_HCLK%i", j),
/*bidir*/ 0))) RC_FAIL(model, rc);
}
}
for (i = 0; i <= 15; i++) {
if ((rc = add_switch(model, y, x,
"CMT_CLKFB",
pf("CMT_PLL_HCLK%i", i),
/*bidir*/ 0))) RC_FAIL(model, rc);
if ((rc = add_switch(model, y, x,
"CMT_SE_CLK_OUT",
pf("CMT_PLL_HCLK%i", i),
/*bidir*/ 0))) RC_FAIL(model, rc);
if ((rc = add_switch(model, y, x,
pf("CMT_FABRIC_CLK%i", i),
pf("CMT_PLL_HCLK%i", i),
/*bidir*/ 0))) RC_FAIL(model, rc);
if ((rc = add_switch(model, y, x,
pf("CMT_PLL_HCLK%i", i),
pf("CMT_PLL_HCLK%i_E", i),
/*bidir*/ 0))) RC_FAIL(model, rc);
if (y < model->center_y) {
if ((rc = add_switch(model, y, x,
pf("CMT_PLL_HCLK%i_E", i),
pf("CLK_PLLCASC_OUT%i", i),
/*bidir*/ 0))) RC_FAIL(model, rc);
if ((rc = add_switch(model, y, x,
pf("PLL_CLK_CASC_IN%i", i),
pf("CLK_PLLCASC_OUT%i", i),
/*bidir*/ 0))) RC_FAIL(model, rc);
} else {
if ((rc = add_switch(model, y, x,
pf("CMT_PLL_HCLK%i_E", i),
pf("PLL_CLK_CASC_IN%i", i),
/*bidir*/ 0))) RC_FAIL(model, rc);
}
}
for (i = 0; i <= 7; i++) {
if ((rc = add_switch(model, y, x,
pf("CMT_PLL_CLK_FEEDBACK_LRBOT%i", i),
"CMT_CLKMUX_CLKFB",
/*bidir*/ 0))) RC_FAIL(model, rc);
if ((rc = add_switch(model, y, x,
pf("PLL_CLK_FEEDBACK_TB%i", i),
"CMT_CLKMUX_CLKFB",
/*bidir*/ 0))) RC_FAIL(model, rc);
}
for (i = 0; i <= 7; i++) {
const char *to = i < 4 ? "CMT_CLKMUX_CLKREF" : "CMT_CLKMUX_CLKIN2";
if ((rc = add_switch(model, y, x,
pf("CMT_PLL_CLK_INDIRECT_LRBOT%i", i), to,
/*bidir*/ 0))) RC_FAIL(model, rc);
if ((rc = add_switch(model, y, x,
pf("PLL_CLK_INDIRECT_TB%i", i), to,
/*bidir*/ 0))) RC_FAIL(model, rc);
}
for (i = 0; i <= 5; i++) {
if ((rc = add_switch(model, y, x,
pf("CMT_PLL_CLKOUTDCM%i", i),
"CMT_CLK_TO_DCM1",
/*bidir*/ 0))) RC_FAIL(model, rc);
if ((rc = add_switch(model, y, x,
pf("CMT_PLL_CLKOUTDCM%i", i),
"CMT_CLK_TO_DCM2",
/*bidir*/ 0))) RC_FAIL(model, rc);
}
{ const char *s[] = {
"CMT_CLKFB", "CMT_CLKMUX_CLKFB",
"CMT_CLK_FROM_BUFG0", "CMT_CLKMUX_CLKREF",
"CMT_CLK_FROM_BUFG1", "CMT_CLKMUX_CLKIN2",
"CMT_CLK_FROM_BUFG2", "CMT_CLKMUX_CLKFB",
"CMT_CLK_FROM_DCM1", "CMT_CLKMUX_CLKIN2",
"CMT_CLK_FROM_DCM2", "CMT_CLKMUX_CLKIN2",
"CMT_CLKMUX_CLKFB", "CMT_CLKMUX_CLKFB_TEST",
"CMT_CLKMUX_CLKFB", "CMT_PLL_CLKFBIN",
"CMT_CLKMUX_CLKIN2", "CMT_PLL_CLKIN2",
"CMT_CLKMUX_CLKREF", "CMT_CLKMUX_CLKREF_TEST",
"CMT_CLKMUX_CLKREF", "CMT_PLL_CLKIN1",
"CMT_CLK_TO_DCM1", "CMT_PLL_SKEWCLKIN1",
"CMT_CLK_TO_DCM2", "CMT_PLL_SKEWCLKIN2",
"CMT_PLL_CLKFB", "CMT_CLKFB",
"CMT_PLL_CLKFBDCM", "CMT_CLKMUX_CLKFB",
"CMT_PLL_CLKFBDCM", "CMT_PLL_CLKFBDCM_TEST",
"CMT_PLL_CLKOUT0", "CMT_CLKMUX_CLKFB",
"CMT_PLL_CLKOUT0", "PLLCASC_CLKOUT0",
"CMT_PLL_CLKOUT1", "PLLCASC_CLKOUT1",
"CMT_PLL_LOCKED", "CMT_PLL_LOCK_DN1",
"CMT_PLL_LOCKED", "CMT_PLL_LOCK_UP1",
"CMT_SE_CLKIN0", "CMT_CLKMUX_CLKIN2",
"CMT_SE_CLKIN1", "CMT_CLKMUX_CLKFB",
"CMT_TEST_CLK", "CMT_SE_CLK_OUT",
"PLLCASC_CLKOUT0", "PLL_IOCLK_DN2",
"PLLCASC_CLKOUT0", "PLL_IOCLK_UP2",
"PLLCASC_CLKOUT1", "PLL_IOCLK_DN3",
"PLLCASC_CLKOUT1", "PLL_IOCLK_UP3",
"PLL_LOCKED", "CMT_PLL_LOCKED",
"PLL_LOCKED", "PLL_CLB1_LOGICOUT18",
"PLL_VCC", "PLL_REL",
"PLL_CLB1_CLK0", "CMT_CLK_FROM_BUFG0",
"PLL_CLB1_CLK1", "CMT_CLK_FROM_BUFG1",
"PLL_CLB2_CLK0", "CMT_CLK_FROM_BUFG2",
"PLL_CLB2_GFAN1", "PLL_DCLK" };
for (i = 0; i < sizeof(s)/sizeof(*s)/2; i++) {
if ((rc = add_switch(model, y, x,
s[i*2], s[i*2+1], /*bidir*/ 0))) RC_FAIL(model, rc);
}}
// logicin
{ const char *clb1_in0_to_62[] = {
/* 0*/ 0, 0, "13", "6", "1", 0, 0, 0,
/* 8*/ "15", 0, 0, 0, 0, 0, 0, 0,
/*16*/ 0, 0, 0, "7", 0, 0, 0, 0,
/*24*/ 0, 0, "3", 0, "8", "9", "4", 0,
/*32*/ "10", 0, 0, 0, 0, 0, 0, "14",
/*40*/ 0, "5", 0, 0, "0", 0, 0, 0,
/*48*/ 0, 0, 0, 0, "12", 0, 0, "2",
/*56*/ 0, 0, 0, "11", 0, 0, 0 };
const char *clb2_in0_to_62[] = {
/* 0*/ 0, "PLL_DI14", 0, 0, 0, "PLL_DADDR3", 0, "PLL_DADDR1",
/* 8*/ 0, 0, 0, 0, "PLL_DI0", 0, 0, "PLL_DADDR0",
/*16*/ 0, "PLL_DI4", 0, "PLL_DI12", 0, 0, 0, 0,
/*24*/ "PLL_DEN", "PLL_DI2", "PLL_DI8", "PLL_DI13", "CMT_SE_CLKIN0", 0, "PLL_DI10", 0,
/*32*/ "PLL_DI15", 0, "PLL_DI1", 0, "PLL_DADDR4", "PLL_CLKINSEL", "PLL_DI3", 0,
/*40*/ 0, "PLL_DI11", "PLL_DADDR2", 0, "PLL_DI5", 0, 0, 0,
/*48*/ "PLL_DI9", 0, 0, 0, "PLL_RST", 0, 0, "PLL_DI6",
/*56*/ 0, "PLL_DI7", "PLL_DWE", "CMT_SE_CLKIN1", 0, 0, 0 };
for (i = 0; i < 63; i++) {
if (clb1_in0_to_62[i])
if ((rc = add_switch(model, y, x,
pf("PLL_CLB1_LOGICINB%i", i),
pf("CMT_FABRIC_CLK%s", clb1_in0_to_62[i]),
/*bidir*/ 0))) RC_FAIL(model, rc);
if (clb2_in0_to_62[i])
if ((rc = add_switch(model, y, x,
pf("PLL_CLB2_LOGICINB%i", i), clb2_in0_to_62[i],
/*bidir*/ 0))) RC_FAIL(model, rc);
}}
// logicout
for (i = 0; i <= 15; i++) {
if ((rc = add_switch(model, y, x,
pf("PLL_DO%i", i),
pf("PLL_CLB1_LOGICOUT%i", i),
/*bidir*/ 0))) RC_FAIL(model, rc);
}
if ((rc = add_switch(model, y, x, "PLL_DRDY",
"PLL_CLB1_LOGICOUT16", /*bidir*/ 0))) RC_FAIL(model, rc);
}
RC_RETURN(model);
}
static int init_center_hclk(struct fpga_model *model)
{
int y, x, i, rc;
RC_CHECK(model);
x = model->center_x;
for (y = TOP_IO_TILES; y < model->y_height-BOT_IO_TILES; y++) {
if (!is_aty(Y_ROW_HORIZ_AXSYMM, model, y))
continue;
for (i = 0; i <= 15; i++) {
if ((rc = add_switch(model, y, x,
pf("CLKV_GCLKH_L%i", i),
pf("I_BUFH_LEFT_SITE%i", i),
/*bidir*/ 0))) RC_FAIL(model, rc);
if ((rc = add_switch(model, y, x,
pf("CLKV_GCLKH_R%i", i),
pf("I_BUFH_RIGHT_SITE%i", i),
/*bidir*/ 0))) RC_FAIL(model, rc);
if ((rc = add_switch(model, y, x,
pf("CLKV_GCLKH_MAIN%i_FOLD", i),
pf("CLKV_GCLKH_L%i", i),
/*bidir*/ 0))) RC_FAIL(model, rc);
if ((rc = add_switch(model, y, x,
pf("CLKV_GCLKH_MAIN%i_FOLD", i),
pf("CLKV_GCLKH_R%i", i),
/*bidir*/ 0))) RC_FAIL(model, rc);
if ((rc = add_switch(model, y, x,
pf("I_BUFH_LEFT_SITE%i", i),
pf("O_BUFH_LEFT_SITE%i", i),
/*bidir*/ 0))) RC_FAIL(model, rc);
if ((rc = add_switch(model, y, x,
pf("I_BUFH_RIGHT_SITE%i", i),
pf("O_BUFH_RIGHT_SITE%i", i),
/*bidir*/ 0))) RC_FAIL(model, rc);
if ((rc = add_switch(model, y, x,
pf("O_BUFH_LEFT_SITE%i", i),
pf("CLKV_BUFH_LEFT_L%i", i),
/*bidir*/ 0))) RC_FAIL(model, rc);
if ((rc = add_switch(model, y, x,
pf("O_BUFH_RIGHT_SITE%i", i),
pf("CLKV_BUFH_RIGHT_R%i", i),
/*bidir*/ 0))) RC_FAIL(model, rc);
if ((rc = add_switch(model, y, x,
pf("REGV_PLL_HCLK%i", i),
pf("CLKV_GCLKH_L%i", i),
/*bidir*/ 0))) RC_FAIL(model, rc);
if ((rc = add_switch(model, y, x,
pf("REGV_PLL_HCLK%i", i),
pf("CLKV_GCLKH_R%i", i),
/*bidir*/ 0))) RC_FAIL(model, rc);
}
}
RC_RETURN(model);
}
static int init_center_midbuf(struct fpga_model *model)
{
int y, x, i, rc;
RC_CHECK(model);
x = model->center_x;
for (y = TOP_IO_TILES; y < model->y_height-BOT_IO_TILES; y++) {
if (!is_atyx(YX_CENTER_MIDBUF, model, y, x))
continue;
if (y < model->center_y) {
for (i = 0; i <= 7; i++) {
if ((rc = add_switch(model, y-1, x,
pf("CLKV_CKPIN_BUF%i", i),
pf("CLKV_MIDBUF_TOP_CKPIN%i", i),
/*bidir*/ 0))) RC_FAIL(model, rc);
}
} else {
for (i = 0; i <= 7; i++) {
if ((rc = add_switch(model, y+1, x,
pf("CLKV_MIDBUF_BOT_CKPIN%i", i),
pf("CLKV_CKPIN_BOT_BUF%i", i),
/*bidir*/ 0))) RC_FAIL(model, rc);
}
}
for (i = 0; i <= 15; i++) {
if ((rc = add_switch(model, y, x,
pf("CLKV_GCLK_MAIN%i", i),
pf("CLKV_MIDBUF_GCLK%i", i),
/*bidir*/ 0))) RC_FAIL(model, rc);
if ((rc = add_switch(model, y, x,
pf("CLKV_MIDBUF_GCLK%i", i),
pf("CLKV_GCLK_MAIN%i_BUF", i),
/*bidir*/ 0))) RC_FAIL(model, rc);
}
}
RC_RETURN(model);
}
static int init_center_reg_tile(struct fpga_model *model, int y, int x, const char *s1, const char *s2)
{
int i, j, rc;
RC_CHECK(model);
{ static const char *s[] = {
"%s_CKPIN_OUT%i", "%s_CKPIN%i",
"%s_CKPIN_OUT%i", "%s_CLK_INDIRECT%i",
"%s_GND", "%s_IOCLKOUT%i",
"%s_VCC", "%s_CKPIN%i",
"%s_VCC", "%s_CLK_FEEDBACK%i",
"%s_VCC", "%s_CLK_INDIRECT%i" };
for (i = 0; i < sizeof(s)/sizeof(*s)/2; i++) {
for (j = 0; j <= 7; j++) {
if ((rc = add_switch(model, y, x, pf(s[i*2], s1, j),
pf(s[i*2+1], s1, j), /*bidir*/ 0))) RC_FAIL(model, rc);
}
}}
RC_RETURN(model);
}
static int init_center_reg_tblr(struct fpga_model *model)
{
int y, x, i, j, rc;
const char *s1, *s2;
RC_CHECK(model);
//
// top
//
y = TOP_OUTER_ROW;
x = model->center_x-CENTER_CMTPLL_O;
s1 = "REGT";
s2 = "TOP";
rc = init_center_reg_tile(model, y, x, s1, s2);
if (rc) RC_FAIL(model, rc);
for (i = 0; i <= 5; i++) {
for (j = 0; j <= 1; j++) {
if ((rc = add_switch(model, y, x, pf("REGT_PLL_IOCLK_UP%i", i),
pf("PLLIN_BUFPLL%i_TOP_SITE", j), /*bidir*/ 0))) RC_FAIL(model, rc);
if (i < 3) {
if ((rc = add_switch(model, y, x, pf("REGT_LOCKIN%i", i),
pf("LOCKED_BUFPLL%i_TOP_SITE", j), /*bidir*/ 0))) RC_FAIL(model, rc);
}
}
}
{ const char *s[] = {
"REGT_VCC", "REGT_PLLCLK0",
"REGT_VCC", "REGT_PLLCLK1",
"IOCLK_BUFPLL0_TOP_SITE", "REGT_PLLCLK0",
"IOCLK_BUFPLL1_TOP_SITE", "REGT_PLLCLK1",
"LOCK_BUFPLL0_TOP_SITE", "REGT_LOCK0",
"LOCK_BUFPLL1_TOP_SITE", "REGT_LOCK1",
"REGT_GCLK0", "GCLK_BUFPLL0_TOP_SITE",
"REGT_GCLK1", "GCLK_BUFPLL1_TOP_SITE",
"SERDESSTROBE_BUFPLL0_TOP_SITE", "REGT_CEOUT0",
"SERDESSTROBE_BUFPLL1_TOP_SITE", "REGT_CEOUT1" };
for (i = 0; i < sizeof(s)/sizeof(*s)/2; i++) {
if ((rc = add_switch(model, y, x, pf(s[i*2]),
pf(s[i*2+1]), /*bidir*/ 0))) RC_FAIL(model, rc);
}}
// y+1
for (i = 0; i <= 7; i++) {
if ((rc = add_switch(model, y+1, x, pf("REGT_TTERM_CLKPIN%i", i),
pf("REGT_TTERM_CKPIN%i", i), /*bidir*/ 0))) RC_FAIL(model, rc);
}
{ const char *s[] = {
"REGT_TTERM_PLL_CEOUT0_N", "REGT_TTERM_PLL_CEOUT0",
"REGT_TTERM_PLL_CEOUT1_N", "REGT_TTERM_PLL_CEOUT1",
"REGT_TTERM_PLL_CLKOUT0_N", "REGT_TTERM_PLL_CLKOUT0",
"REGT_TTERM_PLL_CLKOUT1_N", "REGT_TTERM_PLL_CLKOUT1" };
for (i = 0; i < sizeof(s)/sizeof(*s)/2; i++) {
if ((rc = add_switch(model, y+1, x, pf(s[i*2]),
pf(s[i*2+1]), /*bidir*/ 0))) RC_FAIL(model, rc);
}}
//
// left
//
y = model->center_y;
x = LEFT_OUTER_COL;
s1 = "REGL";
s2 = "LEFT";
rc = init_center_reg_tile(model, y, x, s1, s2);
if (rc) RC_FAIL(model, rc);
{ const char *s[] = {
"REGL_VCC", "REGL_PLL_CLKOUT0_LEFT",
"REGL_VCC", "REGL_PLL_CLKOUT1_LEFT",
"IOCLK_BUFPLL0_LEFT_SITE", "REGL_PLL_CLKOUT0_LEFT",
"IOCLK_BUFPLL1_LEFT_SITE", "REGL_PLL_CLKOUT1_LEFT",
"LOCK_BUFPLL0_LEFT_SITE", "REGL_LOCK0",
"LOCK_BUFPLL1_LEFT_SITE", "REGL_LOCK1",
"REGL_CLKPLL0", "PLLIN_BUFPLL0_LEFT_SITE",
"REGL_CLKPLL1", "PLLIN_BUFPLL1_LEFT_SITE",
"REGL_GCLK0", "GCLK_BUFPLL0_LEFT_SITE",
"REGL_GCLK1", "GCLK_BUFPLL1_LEFT_SITE",
"REGL_GCLK2", "PLLIN_BUFPLL0_LEFT_SITE",
"REGL_GCLK3", "PLLIN_BUFPLL1_LEFT_SITE",
"REGL_LOCKED0", "LOCKED_BUFPLL0_LEFT_SITE",
"REGL_LOCKED1", "LOCKED_BUFPLL1_LEFT_SITE",
"REGL_PCI_IRDY_IOB", "REGL_PCI_IRDY_PINW",
"REGL_PCI_TRDY_IOB", "REGL_PCI_TRDY_PINW",
"SERDESSTROBE_BUFPLL0_LEFT_SITE", "REGL_PLL_CEOUT0_LEFT",
"SERDESSTROBE_BUFPLL1_LEFT_SITE", "REGL_PLL_CEOUT1_LEFT" };
for (i = 0; i < sizeof(s)/sizeof(*s)/2; i++) {
if ((rc = add_switch(model, y, x, pf(s[i*2]),
pf(s[i*2+1]), /*bidir*/ 0))) RC_FAIL(model, rc);
}}
// x+1
for (i = 0; i <= 7; i++) {
if ((rc = add_switch(model, y, x+1, pf("REGH_LTERM_CLKPIN%i", i),
pf("REGH_LTERM_CKPIN%i", i), /*bidir*/ 0))) RC_FAIL(model, rc);
}
{ const char *s[] = {
"REGH_LTERM_PLL_CEOUT0_W", "REGH_LTERM_PLL_CEOUT0",
"REGH_LTERM_PLL_CEOUT1_W", "REGH_LTERM_PLL_CEOUT1",
"REGH_LTERM_PLL_CLKOUT0_W", "REGH_LTERM_PLL_CLKOUT0",
"REGH_LTERM_PLL_CLKOUT1_W", "REGH_LTERM_PLL_CLKOUT1" };
for (i = 0; i < sizeof(s)/sizeof(*s)/2; i++) {
if ((rc = add_switch(model, y, x+1, pf(s[i*2]),
pf(s[i*2+1]), /*bidir*/ 0))) RC_FAIL(model, rc);
}}
//
// right
//
y = model->center_y;
x = model->x_width-RIGHT_OUTER_O;
s1 = "REGR";
s2 = "RIGHT";
rc = init_center_reg_tile(model, y, x, s1, s2);
if (rc) RC_FAIL(model, rc);
{ const char *s[] = {
"REGR_VCC", "REGR_PLLCLK0",
"REGR_VCC", "REGR_PLLCLK1",
"IOCLK_BUFPLL0_RIGHT_SITE", "REGR_PLLCLK0",
"IOCLK_BUFPLL1_RIGHT_SITE", "REGR_PLLCLK1",
"LOCK_BUFPLL0_RIGHT_SITE", "REGR_LOCK0",
"LOCK_BUFPLL1_RIGHT_SITE", "REGR_LOCK1",
"REGR_CLKPLL0", "PLLIN_BUFPLL0_RIGHT_SITE",
"REGR_CLKPLL1", "PLLIN_BUFPLL1_RIGHT_SITE",
"REGR_GCLK0", "GCLK_BUFPLL0_RIGHT_SITE",
"REGR_GCLK1", "GCLK_BUFPLL1_RIGHT_SITE",
"REGR_GCLK2", "PLLIN_BUFPLL0_RIGHT_SITE",
"REGR_GCLK3", "PLLIN_BUFPLL1_RIGHT_SITE",
"REGR_LOCKED0", "LOCKED_BUFPLL0_RIGHT_SITE",
"REGR_LOCKED1", "LOCKED_BUFPLL1_RIGHT_SITE",
"REGR_PCI_IRDY_IOB", "REGR_PCI_IRDY_PINW",
"REGR_PCI_TRDY_IOB", "REGR_PCI_TRDY_PINW",
"SERDESSTROBE_BUFPLL0_RIGHT_SITE", "REGR_CEOUT0",
"SERDESSTROBE_BUFPLL1_RIGHT_SITE", "REGR_CEOUT1" };
for (i = 0; i < sizeof(s)/sizeof(*s)/2; i++) {
if ((rc = add_switch(model, y, x, pf(s[i*2]),
pf(s[i*2+1]), /*bidir*/ 0))) RC_FAIL(model, rc);
}}
// x-1
for (i = 0; i <= 7; i++) {
if ((rc = add_switch(model, y, x-1, pf("REGH_RTERM_CLKPIN%i", i),
pf("REGH_RTERM_CKPIN%i", i), /*bidir*/ 0))) RC_FAIL(model, rc);
}
{ const char *s[] = {
"REGH_RTERM_PLL_CEOUT0_E", "REGH_RTERM_PLL_CEOUT0",
"REGH_RTERM_PLL_CEOUT1_E", "REGH_RTERM_PLL_CEOUT1",
"REGH_RTERM_PLL_CLKOUT0_E", "REGH_RTERM_PLL_CLKOUT0",
"REGH_RTERM_PLL_CLKOUT1_E", "REGH_RTERM_PLL_CLKOUT1" };
for (i = 0; i < sizeof(s)/sizeof(*s)/2; i++) {
if ((rc = add_switch(model, y, x-1, pf(s[i*2]),
pf(s[i*2+1]), /*bidir*/ 0))) RC_FAIL(model, rc);
}}
//
// bottom
//
y = model->y_height-BOT_OUTER_ROW;
x = model->center_x-CENTER_CMTPLL_O;
s1 = "REGB";
s2 = "BOT";
rc = init_center_reg_tile(model, y, x, s1, s2);
if (rc) RC_FAIL(model, rc);
for (i = 0; i <= 5; i++) {
for (j = 0; j <= 1; j++) {
if ((rc = add_switch(model, y, x, pf("REGB_PLL_IOCLK_DOWN%i", i),
pf("PLLIN_BUFPLL%i_BOT_SITE", j), /*bidir*/ 0))) RC_FAIL(model, rc);
if (i < 3) {
if ((rc = add_switch(model, y, x, pf("REGB_LOCKIN%i", i),
pf("LOCKED_BUFPLL%i_BOT_SITE", j), /*bidir*/ 0))) RC_FAIL(model, rc);
}
}
}
{ const char *s[] = {
"REGB_VCC", "REGB_PLLCLK0",
"REGB_VCC", "REGB_PLLCLK1",
"IOCLK_BUFPLL0_BOT_SITE", "REGB_PLLCLK0",
"IOCLK_BUFPLL1_BOT_SITE", "REGB_PLLCLK1",
"LOCK_BUFPLL0_BOT_SITE", "REGB_LOCK0",
"LOCK_BUFPLL1_BOT_SITE", "REGB_LOCK1",
"REGB_GCLK0", "GCLK_BUFPLL0_BOT_SITE",
"REGB_GCLK1", "GCLK_BUFPLL1_BOT_SITE",
"SERDESSTROBE_BUFPLL0_BOT_SITE", "REGB_CEOUT0",
"SERDESSTROBE_BUFPLL1_BOT_SITE", "REGB_CEOUT1" };
for (i = 0; i < sizeof(s)/sizeof(*s)/2; i++) {
if ((rc = add_switch(model, y, x, pf(s[i*2]),
pf(s[i*2+1]), /*bidir*/ 0))) RC_FAIL(model, rc);
}}
// y-1
for (i = 0; i <= 7; i++) {
if ((rc = add_switch(model, y-1, x, pf("REGB_BTERM_CLKPIN%i", i),
pf("REGB_BTERM_CKPIN%i", i), /*bidir*/ 0))) RC_FAIL(model, rc);
}
{ const char *s[] = {
"REGB_BTERM_PLL_CEOUT0_S", "REGB_BTERM_PLL_CEOUT0",
"REGB_BTERM_PLL_CEOUT1_S", "REGB_BTERM_PLL_CEOUT1",
"REGB_BTERM_PLL_CLKOUT0_S", "REGB_BTERM_PLL_CLKOUT0",
"REGB_BTERM_PLL_CLKOUT1_S", "REGB_BTERM_PLL_CLKOUT1" };
for (i = 0; i < sizeof(s)/sizeof(*s)/2; i++) {
if ((rc = add_switch(model, y-1, x, pf(s[i*2]),
pf(s[i*2+1]), /*bidir*/ 0))) RC_FAIL(model, rc);
}}
RC_RETURN(model);
}
static int init_center_topbot_cfb_dfb(struct fpga_model *model)
{
const int x_enum[] = { model->center_x-CENTER_LOGIC_O,
model->center_x+CENTER_X_PLUS_2 };
int y, i, x_i, rc;
RC_CHECK(model);
y = TOP_INNER_ROW;
for (x_i = 0; x_i < sizeof(x_enum)/sizeof(*x_enum); x_i++) {
for (i = 0; i <= 1; i++) {
if ((rc = add_switch(model, y, x_enum[x_i], pf("IOI_REGT_CFB1_M%i_S", i+1),
pf("IOI_REGT_CFB1_M%i", i+1), /*bidir*/ 0))) RC_FAIL(model, rc);
if ((rc = add_switch(model, y, x_enum[x_i], pf("IOI_REGT_CFB1_S%i_S", i+1),
pf("IOI_REGT_CFB1_S%i", i+1), /*bidir*/ 0))) RC_FAIL(model, rc);
if ((rc = add_switch(model, y, x_enum[x_i], pf("IOI_REGT_CFB_M%i_S", i+1),
pf("IOI_REGT_CFB_M%i", i+1), /*bidir*/ 0))) RC_FAIL(model, rc);
if ((rc = add_switch(model, y, x_enum[x_i], pf("IOI_REGT_CFB_S%i_S", i+1),
pf("IOI_REGT_CFB_S%i", i+1), /*bidir*/ 0))) RC_FAIL(model, rc);
if ((rc = add_switch(model, y, x_enum[x_i], pf("IOI_REGT_DFB_M%i_S", i+1),
pf("IOI_REGT_DFB_M%i", i+1), /*bidir*/ 0))) RC_FAIL(model, rc);
if ((rc = add_switch(model, y, x_enum[x_i], pf("IOI_REGT_DFB_S%i_S", i+1),
pf("IOI_REGT_DFB_S%i", i+1), /*bidir*/ 0))) RC_FAIL(model, rc);
if ((rc = add_switch(model, y, x_enum[x_i], pf("IOI_REGT_DQSN%i_S", i),
pf("IOI_REGT_DQSN%i", i), /*bidir*/ 0))) RC_FAIL(model, rc);
if ((rc = add_switch(model, y, x_enum[x_i], pf("IOI_REGT_DQSP%i_S", i),
pf("IOI_REGT_DQSP%i", i), /*bidir*/ 0))) RC_FAIL(model, rc);
if ((rc = add_switch(model, y, x_enum[x_i], pf("TTERM_IOIBOT_IBUF%i", i),
pf("IOI_REGT_CLKPIN%i", i+2), /*bidir*/ 0))) RC_FAIL(model, rc);
if ((rc = add_switch(model, y, x_enum[x_i], pf("TTERM_IOIUP_IBUF%i", i),
pf("IOI_REGT_CLKPIN%i", i), /*bidir*/ 0))) RC_FAIL(model, rc);
}
}
y = model->y_height-BOT_INNER_ROW;
for (x_i = 0; x_i < sizeof(x_enum)/sizeof(*x_enum); x_i++) {
for (i = 0; i <= 3; i++) {
if ((rc = add_switch(model, y, x_enum[x_i], pf("BTERM_CLB_CFB1_%i_N", i+4),
pf("BTERM_CLB_CFB1_%i", i+4), /*bidir*/ 0))) RC_FAIL(model, rc);
if ((rc = add_switch(model, y, x_enum[x_i], pf("BTERM_CLB_CFB%i_N", i+4),
pf("BTERM_CLB_CFB%i", i+4), /*bidir*/ 0))) RC_FAIL(model, rc);
if ((rc = add_switch(model, y, x_enum[x_i], pf("BTERM_CLB_DFB%i_N", i+4),
pf("BTERM_CLB_DFB%i", i+4), /*bidir*/ 0))) RC_FAIL(model, rc);
}
for (i = 0; i <= 1; i++) {
if ((rc = add_switch(model, y, x_enum[x_i], pf("BTERM_CLB_DQSN%i_N", i+2),
pf("BTERM_CLB_DQSN%i", i+2), /*bidir*/ 0))) RC_FAIL(model, rc);
if ((rc = add_switch(model, y, x_enum[x_i], pf("BTERM_CLB_DQSP%i_N", i+2),
pf("BTERM_CLB_DQSP%i", i+2), /*bidir*/ 0))) RC_FAIL(model, rc);
if ((rc = add_switch(model, y, x_enum[x_i], pf("BTERM_IOIBOT_IBUF%i", i),
pf("BTERM_CLB_CLKPIN%i", i+4), /*bidir*/ 0))) RC_FAIL(model, rc);
if ((rc = add_switch(model, y, x_enum[x_i], pf("BTERM_IOIUP_IBUF%i", i),
pf("BTERM_CLB_CLKPIN%i", i+6), /*bidir*/ 0))) RC_FAIL(model, rc);
}
}
RC_RETURN(model);
}
fpgatools-201212/libs/model_tiles.c 0000664 0000000 0000000 00000062142 12065743015 0017206 0 ustar 00root root 0000000 0000000 //
// Author: Wolfgang Spraul
//
// This is free and unencumbered software released into the public domain.
// For details see the UNLICENSE file at the root of the source tree.
//
#include
#include "model.h"
int init_tiles(struct fpga_model* model)
{
int tile_rows, tile_columns, i, j, k, l, row_top_y, left_side;
int start, end, no_io, cur_major;
char cur_cfgcol, last_col;
struct fpga_tile* tile_i0;
RC_CHECK(model);
tile_rows = 1 /* middle */ + (8+1+8)*model->die->num_rows + 2+2 /* two extra tiles at top and bottom */;
tile_columns = LEFT_SIDE_WIDTH + RIGHT_SIDE_WIDTH;
for (i = 0; model->die->major_str[i] != 0; i++) {
if (model->die->major_str[i] == 'L' || model->die->major_str[i] == 'M')
tile_columns += 2; // 2 for logic blocks L/M
else if (model->die->major_str[i] == 'B' || model->die->major_str[i] == 'D')
tile_columns += 3; // 3 for bram or macc
else if (model->die->major_str[i] == 'R')
tile_columns += 2+2; // 2+2 for middle IO+logic+PLL/DCM
}
model->tmp_str = malloc((tile_columns > tile_rows ? tile_columns : tile_rows) * sizeof(*model->tmp_str));
if (!model->tmp_str) {
fprintf(stderr, "%i: Out of memory.\n", __LINE__);
return -1;
}
model->x_width = tile_columns;
model->y_height = tile_rows;
model->center_x = -1;
model->tiles = calloc(tile_columns * tile_rows, sizeof(struct fpga_tile));
if (!model->tiles) {
fprintf(stderr, "%i: Out of memory.\n", __LINE__);
return -1;
}
for (i = 0; i < tile_rows * tile_columns; i++)
model->tiles[i].type = NA;
if (!(tile_rows % 2))
fprintf(stderr, "Unexpected even number of tile rows (%i).\n", tile_rows);
model->center_y = 2 /* top IO files */ + (model->die->num_rows/2)*(8+1/*middle of row clock*/+8);
//
// top, bottom, center:
// go through columns from left to right, rows from top to bottom
//
left_side = 1; // turn off (=right side) when reaching the 'R' middle column
for (i = 0; i < LEFT_SIDE_WIDTH; i++)
model->x_major[i] = LEFT_SIDE_MAJOR;
cur_major = LEFT_SIDE_MAJOR+1;
// i is now LEFT_SIDE_WIDTH (5)
for (j = 0; model->die->major_str[j]; j++) {
cur_cfgcol = model->die->major_str[j];
switch (cur_cfgcol) {
case 'L':
case 'l':
case 'M':
case 'm':
no_io = (next_non_whitespace(&model->die->major_str[j+1]) == 'n');
last_col = last_major(model->die->major_str, j);
model->tiles[i].flags |= TF_FABRIC_ROUTING_COL;
if (no_io) model->tiles[i].flags |= TF_ROUTING_NO_IO;
model->tiles[i+1].flags |=
(cur_cfgcol == 'L' || cur_cfgcol == 'l')
? TF_FABRIC_LOGIC_XL_COL
: TF_FABRIC_LOGIC_XM_COL;
for (k = model->die->num_rows-1; k >= 0; k--) {
row_top_y = 2 /* top IO tiles */ + (model->die->num_rows-1-k)*(8+1/*middle of row clock*/+8);
if (k<(model->die->num_rows/2)) row_top_y++; // middle system tiles (center row)
start = ((k == model->die->num_rows-1 && !no_io) ? 2 : 0);
end = ((k == 0 && !no_io) ? 14 : 16);
for (l = start; l < end; l++) {
tile_i0 = &model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + i];
if (l < 15 || (!k && no_io))
tile_i0->type = ROUTING;
else
tile_i0->type = ROUTING_BRK;
if (cur_cfgcol == 'L') {
tile_i0[1].flags |= TF_LOGIC_XL_DEV;
tile_i0[1].type = LOGIC_XL;
} else {
tile_i0[1].flags |= TF_LOGIC_XM_DEV;
tile_i0[1].type = LOGIC_XM;
}
}
if (cur_cfgcol == 'L') {
model->tiles[(row_top_y+8)*tile_columns + i].type = HCLK_ROUTING_XL;
model->tiles[(row_top_y+8)*tile_columns + i + 1].type = HCLK_LOGIC_XL;
} else {
model->tiles[(row_top_y+8)*tile_columns + i].type = HCLK_ROUTING_XM;
model->tiles[(row_top_y+8)*tile_columns + i + 1].type = HCLK_LOGIC_XM;
}
}
if (last_col == 'R') {
model->tiles[tile_columns + i].type = IO_BUFPLL_TERM_T;
model->tiles[(tile_rows-2)*tile_columns + i].type = IO_BUFPLL_TERM_B;
} else {
model->tiles[tile_columns + i].type = IO_TERM_T;
if (!no_io)
model->tiles[(tile_rows-2)*tile_columns + i].type = IO_TERM_B;
else
model->tiles[(tile_rows-2)*tile_columns + i].type = LOGIC_ROUTING_TERM_B;
}
if (!no_io) {
model->tiles[i].type = IO_T;
model->tiles[(tile_rows-1)*tile_columns + i].type = IO_B;
model->tiles[2*tile_columns + i].type = IO_ROUTING;
model->tiles[3*tile_columns + i].type = IO_ROUTING;
model->tiles[(tile_rows-4)*tile_columns + i].type = IO_ROUTING;
model->tiles[(tile_rows-3)*tile_columns + i].type = IO_ROUTING;
}
if (last_col == 'R') {
model->tiles[tile_columns + i + 1].type = IO_LOGIC_REG_TERM_T;
model->tiles[(tile_rows-2)*tile_columns + i + 1].type = IO_LOGIC_REG_TERM_B;
} else {
model->tiles[tile_columns + i + 1].type = IO_LOGIC_TERM_T;
if (!no_io)
model->tiles[(tile_rows-2)*tile_columns + i + 1].type = IO_LOGIC_TERM_B;
else
model->tiles[(tile_rows-2)*tile_columns + i + 1].type = LOGIC_NOIO_TERM_B;
}
if (!no_io) {
model->tiles[2*tile_columns + i + 1].type = IO_OUTER_T;
model->tiles[2*tile_columns + i + 1].flags |= TF_IOLOGIC_DELAY_DEV;
model->tiles[3*tile_columns + i + 1].type = IO_INNER_T;
model->tiles[3*tile_columns + i + 1].flags |= TF_IOLOGIC_DELAY_DEV;
model->tiles[(tile_rows-4)*tile_columns + i + 1].type = IO_INNER_B;
model->tiles[(tile_rows-4)*tile_columns + i + 1].flags |= TF_IOLOGIC_DELAY_DEV;
model->tiles[(tile_rows-3)*tile_columns + i + 1].type = IO_OUTER_B;
model->tiles[(tile_rows-3)*tile_columns + i + 1].flags |= TF_IOLOGIC_DELAY_DEV;
}
if (cur_cfgcol == 'L') {
model->tiles[model->center_y*tile_columns + i].type = REGH_ROUTING_XL;
model->tiles[model->center_y*tile_columns + i + 1].type = REGH_LOGIC_XL;
} else {
model->tiles[model->center_y*tile_columns + i].type = REGH_ROUTING_XM;
model->tiles[model->center_y*tile_columns + i + 1].type = REGH_LOGIC_XM;
}
for (k = 0; k < 2; k++)
model->x_major[i++] = cur_major;
cur_major++;
break;
case 'B':
if (next_non_whitespace(&model->die->major_str[j+1]) == 'g') {
if (left_side)
model->left_gclk_sep_x = i+2;
else
model->right_gclk_sep_x = i+2;
}
model->tiles[i].flags |= TF_FABRIC_ROUTING_COL;
model->tiles[i].flags |= TF_ROUTING_NO_IO; // no_io always on for BRAM
model->tiles[i+1].flags |= TF_FABRIC_BRAM_VIA_COL;
model->tiles[i+2].flags |= TF_FABRIC_BRAM_COL;
for (k = model->die->num_rows-1; k >= 0; k--) {
row_top_y = 2 /* top IO tiles */ + (model->die->num_rows-1-k)*(8+1/*middle of row clock*/+8);
if (k<(model->die->num_rows/2)) row_top_y++; // middle system tiles
for (l = 0; l < 16; l++) {
tile_i0 = &model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + i];
if (l < 15)
tile_i0->type = BRAM_ROUTING;
else
tile_i0->type = BRAM_ROUTING_BRK;
model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + i + 1].type = ROUTING_VIA;
if (!(l%4)) {
model->tiles[(row_top_y+3+(l<8?l:l+1))*tile_columns + i + 2].type = BRAM;
model->tiles[(row_top_y+3+(l<8?l:l+1))*tile_columns + i + 2].flags |= TF_BRAM_DEV;
}
}
model->tiles[(row_top_y+8)*tile_columns + i].type = HCLK_BRAM_ROUTING;
model->tiles[(row_top_y+8)*tile_columns + i + 1].type = HCLK_BRAM_ROUTING_VIA;
model->tiles[(row_top_y+8)*tile_columns + i + 2].type = HCLK_BRAM;
}
model->tiles[tile_columns + i].type = BRAM_ROUTING_TERM_T;
model->tiles[(tile_rows-2)*tile_columns + i].type = BRAM_ROUTING_TERM_B;
model->tiles[tile_columns + i + 1].type = BRAM_ROUTING_VIA_TERM_T;
model->tiles[(tile_rows-2)*tile_columns + i + 1].type = BRAM_ROUTING_VIA_TERM_B;
model->tiles[tile_columns + i + 2].type = left_side ? BRAM_TERM_LT : BRAM_TERM_RT;
model->tiles[(tile_rows-2)*tile_columns + i + 2].type = left_side ? BRAM_TERM_LB : BRAM_TERM_RB;
model->tiles[model->center_y*tile_columns + i].type = REGH_BRAM_ROUTING;
model->tiles[model->center_y*tile_columns + i + 1].type = REGH_BRAM_ROUTING_VIA;
model->tiles[model->center_y*tile_columns + i + 2].type = left_side ? REGH_BRAM_L : REGH_BRAM_R;
for (k = 0; k < 3; k++)
model->x_major[i++] = cur_major;
cur_major++;
break;
case 'D':
model->tiles[i].flags |= TF_FABRIC_ROUTING_COL;
model->tiles[i].flags |= TF_ROUTING_NO_IO; // no_io always on for MACC
model->tiles[i+1].flags |= TF_FABRIC_MACC_VIA_COL;
model->tiles[i+2].flags |= TF_FABRIC_MACC_COL;
for (k = model->die->num_rows-1; k >= 0; k--) {
row_top_y = 2 /* top IO tiles */ + (model->die->num_rows-1-k)*(8+1/*middle of row clock*/+8);
if (k<(model->die->num_rows/2)) row_top_y++; // middle system tiles
for (l = 0; l < 16; l++) {
tile_i0 = &model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + i];
if (l < 15)
tile_i0->type = ROUTING;
else
tile_i0->type = ROUTING_BRK;
tile_i0[1].type = ROUTING_VIA;
if (!(l%4)) {
model->tiles[(row_top_y+3+(l<8?l:l+1))*tile_columns + i + 2].type = MACC;
model->tiles[(row_top_y+3+(l<8?l:l+1))*tile_columns + i + 2].flags |= TF_MACC_DEV;
}
}
model->tiles[(row_top_y+8)*tile_columns + i].type = HCLK_MACC_ROUTING;
model->tiles[(row_top_y+8)*tile_columns + i + 1].type = HCLK_MACC_ROUTING_VIA;
model->tiles[(row_top_y+8)*tile_columns + i + 2].type = HCLK_MACC;
}
model->tiles[tile_columns + i].type = MACC_ROUTING_TERM_T;
model->tiles[(tile_rows-2)*tile_columns + i].type = MACC_ROUTING_TERM_B;
model->tiles[tile_columns + i + 1].type = MACC_VIA_TERM_T;
model->tiles[(tile_rows-2)*tile_columns + i + 1].type = IO_LOGIC_TERM_B;
model->tiles[tile_columns + i + 2].type = left_side ? MACC_TERM_TL : MACC_TERM_TR;
model->tiles[(tile_rows-2)*tile_columns + i + 2].type = left_side ? MACC_TERM_BL : MACC_TERM_BR;
model->tiles[model->center_y*tile_columns + i].type = REGH_MACC_ROUTING;
model->tiles[model->center_y*tile_columns + i + 1].type = REGH_MACC_ROUTING_VIA;
model->tiles[model->center_y*tile_columns + i + 2].type = REGH_MACC_L;
for (k = 0; k < 3; k++)
model->x_major[i++] = cur_major;
cur_major++;
break;
case 'R':
if (next_non_whitespace(&model->die->major_str[j+1]) != 'M') {
// We expect a LOGIC_XM column to follow the center for
// the top and bottom bufpll and reg routing.
fprintf(stderr, "Expecting LOGIC_XM after center but found '%c'\n", model->die->major_str[j+1]);
}
model->center_x = i+3;
left_side = 0;
for (k = model->die->num_rows-1; k >= 0; k--) {
row_top_y = 2 /* top IO tiles */ + (model->die->num_rows-1-k)*(8+1/*middle of row clock*/+8);
if (k<(model->die->num_rows/2)) row_top_y++; // middle system tiles
for (l = 0; l < 16; l++) {
tile_i0 = &model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + i];
if ((k < model->die->num_rows-1 || l >= 2) && (k || l<14)) {
if (l < 15)
tile_i0->type = ROUTING;
else
tile_i0->type = ROUTING_BRK;
if (l == 7)
tile_i0[1].type = ROUTING_VIA_IO;
else if (l == 8)
tile_i0[1].type = (k%2) ? ROUTING_VIA_CARRY : ROUTING_VIA_IO_DCM;
else if (l == 15 && k==model->die->num_rows/2)
tile_i0[1].type = ROUTING_VIA_REGC;
else {
tile_i0[1].type = LOGIC_XL;
tile_i0[1].flags |= TF_LOGIC_XL_DEV;
}
}
if (l == 7
|| (l == 8 && !(k%2))) { // even row, together with DCM
tile_i0->type = IO_ROUTING;
}
if (l == 7) {
if (k%2) { // odd
model->tiles[(row_top_y+l)*tile_columns + i + 2].flags |= TF_PLL_DEV;
model->tiles[(row_top_y+l)*tile_columns + i + 2].type = (k<(model->die->num_rows/2)) ? PLL_B : PLL_T;
} else { // even
model->tiles[(row_top_y+l)*tile_columns + i + 2].flags |= TF_DCM_DEV;
model->tiles[(row_top_y+l)*tile_columns + i + 2].type = (k<(model->die->num_rows/2)) ? DCM_B : DCM_T;
}
}
// four midbuf tiles, in the middle of the top and bottom halves
if (l == 15) {
if (k == model->die->num_rows*3/4)
model->tiles[(row_top_y+l+1)*tile_columns + i + 3].type = REGV_MIDBUF_T;
else if (k == model->die->num_rows/4) {
model->tiles[(row_top_y+l+1)*tile_columns + i + 3].flags |= TF_CENTER_MIDBUF;
model->tiles[(row_top_y+l+1)*tile_columns + i + 3].type = REGV_HCLKBUF_B;
} else
model->tiles[(row_top_y+l+1)*tile_columns + i + 3].type = REGV_BRK;
} else if (l == 0 && k == model->die->num_rows*3/4-1) {
model->tiles[(row_top_y+l)*tile_columns + i + 3].flags |= TF_CENTER_MIDBUF;
model->tiles[(row_top_y+l)*tile_columns + i + 3].type = REGV_HCLKBUF_T;
} else if (l == 0 && k == model->die->num_rows/4-1)
model->tiles[(row_top_y+l)*tile_columns + i + 3].type = REGV_MIDBUF_B;
else if (l == 8)
model->tiles[(row_top_y+l+1)*tile_columns + i + 3].type = (kdie->num_rows/2) ? REGV_B : REGV_T;
else
model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + i + 3].type = REGV;
}
model->tiles[(row_top_y+8)*tile_columns + i].type = HCLK_ROUTING_XL;
model->tiles[(row_top_y+8)*tile_columns + i + 1].type = HCLK_LOGIC_XL;
model->tiles[(row_top_y+8)*tile_columns + i + 3].type = HCLK_REGV;
}
model->tiles[i].type = IO_T;
model->tiles[(tile_rows-1)*tile_columns + i].type = IO_B;
model->tiles[tile_columns + i].type = IO_TERM_T;
model->tiles[(tile_rows-2)*tile_columns + i].type = IO_TERM_B;
model->tiles[2*tile_columns + i].type = IO_ROUTING;
model->tiles[3*tile_columns + i].type = IO_ROUTING;
model->tiles[(tile_rows-4)*tile_columns + i].type = IO_ROUTING;
model->tiles[(tile_rows-3)*tile_columns + i].type = IO_ROUTING;
model->tiles[tile_columns + i + 1].type = IO_LOGIC_REG_TERM_T;
model->tiles[(tile_rows-2)*tile_columns + i + 1].type = IO_LOGIC_REG_TERM_B;
model->tiles[2*tile_columns + i + 1].type = IO_OUTER_T;
model->tiles[2*tile_columns + i + 1].flags |= TF_IOLOGIC_DELAY_DEV;
model->tiles[3*tile_columns + i + 1].type = IO_INNER_T;
model->tiles[3*tile_columns + i + 1].flags |= TF_IOLOGIC_DELAY_DEV;
model->tiles[(tile_rows-4)*tile_columns + i + 1].type = IO_INNER_B;
model->tiles[(tile_rows-4)*tile_columns + i + 1].flags |= TF_IOLOGIC_DELAY_DEV;
model->tiles[(tile_rows-3)*tile_columns + i + 1].type = IO_OUTER_B;
model->tiles[(tile_rows-3)*tile_columns + i + 1].flags |= TF_IOLOGIC_DELAY_DEV;
model->tiles[i + 2].type = REG_T;
model->tiles[tile_columns + i + 2].type = REG_TERM_T;
model->tiles[(tile_rows-2)*tile_columns + i + 2].type = REG_TERM_B;
model->tiles[(tile_rows-1)*tile_columns + i + 2].type = REG_B;
model->tiles[tile_columns + i + 3].type = REGV_TERM_T;
model->tiles[(tile_rows-2)*tile_columns + i + 3].type = REGV_TERM_B;
model->tiles[model->center_y*tile_columns + i].type = REGC_ROUTING;
model->tiles[model->center_y*tile_columns + i + 1].type = REGC_LOGIC;
model->tiles[model->center_y*tile_columns + i + 2].type = REGC_CMT;
model->tiles[model->center_y*tile_columns + i + 3].type = CENTER;
for (k = 0; k < 4; k++)
model->x_major[i++] = cur_major;
cur_major++;
break;
case ' ': // space used to make string more readable only
case 'g': // global clock separator
case 'n': // noio for logic blocks
break;
default:
fprintf(stderr, "Ignoring unexpected column "
"identifier '%c'\n", cur_cfgcol);
break;
}
}
for (k = 0; k < RIGHT_SIDE_WIDTH; k++)
model->x_major[i++] = cur_major;
//
// left IO
//
for (k = model->die->num_rows-1; k >= 0; k--) {
row_top_y = 2 /* top IO tiles */ + (model->die->num_rows-1-k)*(8+1/*middle of row clock*/+8);
if (k<(model->die->num_rows/2)) row_top_y++; // middle system tiles
for (l = 0; l < 16; l++) {
//
// +0
//
if (model->die->left_wiring[(model->die->num_rows-1-k)*16+l] == 'W') {
model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns].flags |= TF_WIRED;
model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns].type = IO_L;
}
//
// +1
//
if ((k == model->die->num_rows-1 && !l) || (!k && l==15))
model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + 1].type = CORNER_TERM_L;
else if (k == model->die->num_rows/2 && l == 12)
model->tiles[(row_top_y+l+1)*tile_columns + 1].type = IO_TERM_L_UPPER_TOP;
else if (k == model->die->num_rows/2 && l == 13)
model->tiles[(row_top_y+l+1)*tile_columns + 1].type = IO_TERM_L_UPPER_BOT;
else if (k == (model->die->num_rows/2)-1 && !l)
model->tiles[(row_top_y+l)*tile_columns + 1].type = IO_TERM_L_LOWER_TOP;
else if (k == (model->die->num_rows/2)-1 && l == 1)
model->tiles[(row_top_y+l)*tile_columns + 1].type = IO_TERM_L_LOWER_BOT;
else
model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + 1].type = IO_TERM_L;
//
// +2
//
if (model->die->left_wiring[(model->die->num_rows-1-k)*16+l] == 'W') {
if (l == 15 && k && k != model->die->num_rows/2)
model->tiles[(row_top_y+l+1)*tile_columns + 2].type = ROUTING_IO_L_BRK;
else
model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + 2].type = ROUTING_IO_L;
} else { // unwired
if (k && k != model->die->num_rows/2 && l == 15)
model->tiles[(row_top_y+l+1)*tile_columns + 2].type = ROUTING_BRK;
else if (k == model->die->num_rows/2 && l == 14)
model->tiles[(row_top_y+l+1)*tile_columns + 2].type = ROUTING_GCLK;
else
model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + 2].type = ROUTING;
}
//
// +3
//
if (model->die->left_wiring[(model->die->num_rows-1-k)*16+l] == 'W') {
model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + 3].flags |= TF_IOLOGIC_DELAY_DEV;
model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + 3].type = ROUTING_IO_VIA_L;
} else { // unwired
if (k == model->die->num_rows-1 && !l) {
model->tiles[(row_top_y+l)*tile_columns + 3].type = CORNER_TL;
} else if (!k && l == 15) {
model->tiles[(row_top_y+l+1)*tile_columns + 3].type = CORNER_BL;
} else {
if (k && k != model->die->num_rows/2 && l == 15)
model->tiles[(row_top_y+l+1)*tile_columns + 3].type = ROUTING_VIA_CARRY;
else
model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + 3].type = ROUTING_VIA;
}
}
}
model->tiles[(row_top_y+8)*tile_columns + 1].type = HCLK_TERM_L;
model->tiles[(row_top_y+8)*tile_columns + 2].type = HCLK_ROUTING_IO_L;
if (k >= model->die->num_rows/2) { // top half
if (k > (model->die->num_rows*3)/4)
model->tiles[(row_top_y+8)*tile_columns + 3].type = HCLK_IO_TOP_UP_L;
else if (k == (model->die->num_rows*3)/4)
model->tiles[(row_top_y+8)*tile_columns + 3].type = HCLK_IO_TOP_SPLIT_L;
else
model->tiles[(row_top_y+8)*tile_columns + 3].type = HCLK_IO_TOP_DN_L;
} else { // bottom half
if (k < model->die->num_rows/4 - 1)
model->tiles[(row_top_y+8)*tile_columns + 3].type = HCLK_IO_BOT_DN_L;
else if (k == model->die->num_rows/4 - 1)
model->tiles[(row_top_y+8)*tile_columns + 3].type = HCLK_IO_BOT_SPLIT_L;
else
model->tiles[(row_top_y+8)*tile_columns + 3].type = HCLK_IO_BOT_UP_L;
}
model->tiles[(row_top_y+8)*tile_columns + 4].type = HCLK_MCB;
}
model->tiles[(model->center_y-3)*tile_columns].type = IO_PCI_L;
model->tiles[(model->center_y-2)*tile_columns].type = IO_PCI_CONN_L;
model->tiles[(model->center_y-1)*tile_columns].type = IO_PCI_CONN_L;
model->tiles[model->center_y*tile_columns].type = REG_L;
model->tiles[(model->center_y+1)*tile_columns].type = IO_RDY_L;
model->tiles[model->center_y*tile_columns + 1].type = REGH_IO_TERM_L;
model->tiles[tile_columns + 2].type = CORNER_TERM_T;
model->tiles[(tile_rows-2)*tile_columns + 2].type = CORNER_TERM_B;
model->tiles[model->center_y*tile_columns + 2].type = REGH_ROUTING_IO_L;
model->tiles[tile_columns + 3].type = ROUTING_IO_PCI_CE_L;
model->tiles[(tile_rows-2)*tile_columns + 3].type = ROUTING_IO_PCI_CE_L;
model->tiles[model->center_y*tile_columns + 3].type = REGH_IO_L;
model->tiles[model->center_y*tile_columns + 4].type = REGH_MCB;
//
// right IO
//
for (k = model->die->num_rows-1; k >= 0; k--) {
row_top_y = 2 /* top IO tiles */ + (model->die->num_rows-1-k)*(8+1/*middle of row clock*/+8);
if (k<(model->die->num_rows/2)) row_top_y++; // middle system tiles
for (l = 0; l < 16; l++) {
//
// -1
//
if (model->die->right_wiring[(model->die->num_rows-1-k)*16+l] == 'W')
model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + tile_columns - 1].flags |= TF_WIRED;
if (k == model->die->num_rows/2 && l == 13)
model->tiles[(row_top_y+l+1)*tile_columns + tile_columns - 1].type = IO_RDY_R;
else if (k == model->die->num_rows/2 && l == 14)
model->tiles[(row_top_y+l+1)*tile_columns + tile_columns - 1].type = IO_PCI_CONN_R;
else if (k == model->die->num_rows/2 && l == 15)
model->tiles[(row_top_y+l+1)*tile_columns + tile_columns - 1].type = IO_PCI_CONN_R;
else if (k == model->die->num_rows/2-1 && !l)
model->tiles[(row_top_y+l)*tile_columns + tile_columns - 1].type = IO_PCI_R;
else {
if (model->die->right_wiring[(model->die->num_rows-1-k)*16+l] == 'W')
model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + tile_columns - 1].type = IO_R;
}
//
// -2
//
if ((k == model->die->num_rows-1 && (!l || l == 1)) || (!k && (l==15 || l==14)))
model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + tile_columns - 2].type = CORNER_TERM_R;
else if (k == model->die->num_rows/2 && l == 12)
model->tiles[(row_top_y+l+1)*tile_columns + tile_columns - 2].type = IO_TERM_R_UPPER_TOP;
else if (k == model->die->num_rows/2 && l == 13)
model->tiles[(row_top_y+l+1)*tile_columns + tile_columns - 2].type = IO_TERM_R_UPPER_BOT;
else if (k == (model->die->num_rows/2)-1 && !l)
model->tiles[(row_top_y+l)*tile_columns + tile_columns - 2].type = IO_TERM_R_LOWER_TOP;
else if (k == (model->die->num_rows/2)-1 && l == 1)
model->tiles[(row_top_y+l)*tile_columns + tile_columns - 2].type = IO_TERM_R_LOWER_BOT;
else
model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + tile_columns - 2].type = IO_TERM_R;
//
// -3
//
//
// -4
//
if (model->die->right_wiring[(model->die->num_rows-1-k)*16+l] == 'W') {
model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + tile_columns - 4].flags |= TF_IOLOGIC_DELAY_DEV;
model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + tile_columns - 4].type = ROUTING_IO_VIA_R;
} else {
if (k == model->die->num_rows-1 && l == 0)
model->tiles[(row_top_y+l)*tile_columns + tile_columns - 4].type = CORNER_TR_UPPER;
else if (k == model->die->num_rows-1 && l == 1)
model->tiles[(row_top_y+l)*tile_columns + tile_columns - 4].type = CORNER_TR_LOWER;
else if (k && k != model->die->num_rows/2 && l == 15)
model->tiles[(row_top_y+l+1)*tile_columns + tile_columns - 4].type = ROUTING_VIA_CARRY;
else if (!k && l == 14)
model->tiles[(row_top_y+l+1)*tile_columns + tile_columns - 4].type = CORNER_BR_UPPER;
else if (!k && l == 15)
model->tiles[(row_top_y+l+1)*tile_columns + tile_columns - 4].type = CORNER_BR_LOWER;
else
model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + tile_columns - 4].type = ROUTING_VIA;
}
//
// -5
//
if (model->die->right_wiring[(model->die->num_rows-1-k)*16+l] == 'W')
model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + tile_columns - 5].type = IO_ROUTING;
else {
if (k && k != model->die->num_rows/2 && l == 15)
model->tiles[(row_top_y+l+1)*tile_columns + tile_columns - 5].type = ROUTING_BRK;
else if (k == model->die->num_rows/2 && l == 14)
model->tiles[(row_top_y+l+1)*tile_columns + tile_columns - 5].type = ROUTING_GCLK;
else
model->tiles[(row_top_y+(l<8?l:l+1))*tile_columns + tile_columns - 5].type = ROUTING;
}
}
model->tiles[(row_top_y+8)*tile_columns + tile_columns - 2].type = HCLK_TERM_R;
model->tiles[(row_top_y+8)*tile_columns + tile_columns - 3].type = HCLK_MCB;
model->tiles[(row_top_y+8)*tile_columns + tile_columns - 5].type = HCLK_ROUTING_IO_R;
if (k >= model->die->num_rows/2) { // top half
if (k > (model->die->num_rows*3)/4)
model->tiles[(row_top_y+8)*tile_columns + tile_columns - 4].type = HCLK_IO_TOP_UP_R;
else if (k == (model->die->num_rows*3)/4)
model->tiles[(row_top_y+8)*tile_columns + tile_columns - 4].type = HCLK_IO_TOP_SPLIT_R;
else
model->tiles[(row_top_y+8)*tile_columns + tile_columns - 4].type = HCLK_IO_TOP_DN_R;
} else { // bottom half
if (k < model->die->num_rows/4 - 1)
model->tiles[(row_top_y+8)*tile_columns + tile_columns - 4].type = HCLK_IO_BOT_DN_R;
else if (k == model->die->num_rows/4 - 1)
model->tiles[(row_top_y+8)*tile_columns + tile_columns - 4].type = HCLK_IO_BOT_SPLIT_R;
else
model->tiles[(row_top_y+8)*tile_columns + tile_columns - 4].type = HCLK_IO_BOT_UP_R;
}
}
model->tiles[tile_columns + tile_columns - 5].type = CORNER_TERM_T;
model->tiles[(tile_rows-2)*tile_columns + tile_columns - 5].type = CORNER_TERM_B;
model->tiles[tile_columns + tile_columns - 4].type = ROUTING_IO_PCI_CE_R;
model->tiles[(tile_rows-2)*tile_columns + tile_columns - 4].type = ROUTING_IO_PCI_CE_R;
model->tiles[model->center_y*tile_columns + tile_columns - 1].type = REG_R;
model->tiles[model->center_y*tile_columns + tile_columns - 2].type = REGH_IO_TERM_R;
model->tiles[model->center_y*tile_columns + tile_columns - 3].type = REGH_MCB;
model->tiles[model->center_y*tile_columns + tile_columns - 4].type = REGH_IO_R;
model->tiles[model->center_y*tile_columns + tile_columns - 5].type = REGH_ROUTING_IO_R;
return 0;
}
fpgatools-201212/libs/parts.c 0000664 0000000 0000000 00000121156 12065743015 0016040 0 ustar 00root root 0000000 0000000 //
// Author: Wolfgang Spraul
//
// This is free and unencumbered software released into the public domain.
// For details see the UNLICENSE file at the root of the source tree.
//
#include "model.h"
#include "control.h"
const char* iob_xc6slx9_sitenames[IOB_WORDS*2/8] =
{
// Note that the configuration space for 4*6 IOBs
// that are marked with 0 is used for clocks etc,
// just not IOBs.
[0]
"P70", "P69", "P67", "P66", "P65", "P64", "P62", "P61",
"P60", "P59", "P58", "P57", "UNB113", "UNB114", "UNB115", "UNB116",
[16]
"UNB117", "UNB118", "P56", "P55", 0, 0, 0, 0,
0, 0, "P51", "P50", "UNB123", "UNB124", "UNB125", "UNB126",
[32]
"UNB127", "UNB128", "UNB129", "UNB130", "UNB131", "UNB132", "P48", "P47",
"P46", "P45", "P44", "P43", "UNB139", "UNB140", "P41", "P40",
[48]
"P39", "P38", "P35", "P34", "P33", "P32", "UNB149", "UNB150",
"UNB151", "UNB152", "UNB153", "UNB154", "UNB155", "UNB156", "UNB157", "UNB158",
[64]
"P30", "P29", "P27", "P26", "UNB163", "UNB164", "UNB165", "UNB166",
"UNB167", "UNB168", "P24", "P23", "P22", "P21", 0, 0,
[80]
0, 0, 0, 0, "P17", "P16", "P15", "P14",
"UNB177", "UNB178", "UNB179", "UNB180", "UNB181", "UNB182", "UNB183", "UNB184",
[96]
"P12", "P11", "P10", "P9", "P8", "P7", "P6", "P5",
"UNB193", "UNB194", "UNB195", "UNB196", "UNB197", "UNB198", "P2", "P1",
[112]
"P144", "P143", "P142", "P141", "P140", "P139", "P138", "P137",
"UNB9", "UNB10", "UNB11", "UNB12", "UNB13", "UNB14", "UNB15", "UNB16",
[128]
"UNB17", "UNB18", "UNB19", "UNB20", "P134", "P133", "P132", "P131",
0, 0, 0, 0, 0, 0, "P127", "P126",
[144]
"P124", "P123", "UNB29", "UNB30", "UNB31", "UNB32", "UNB33", "UNB34",
"P121", "P120", "P119", "P118", "P117", "P116", "P115", "P114",
[160]
"P112", "P111", "P105", "P104", "UNB47", "UNB48", "UNB49", "UNB50",
"UNB51", "UNB52", "P102", "P101", "P100", "P99", "P98", "P97",
[176]
"UNB59", "UNB60", "UNB61", "UNB62", "UNB63", "UNB64", "UNB65", "UNB66",
"UNB67", "UNB68", "P95", "P94", "P93", "P92", 0, 0,
[192]
0, 0, 0, 0, "P88", "P87", "P85", "P84",
"UNB77", "UNB78", "P83", "P82", "P81", "P80", "P79", "P78",
[208]
"UNB85", "UNB86", "UNB87", "UNB88", "UNB89", "UNB90", "UNB91", "UNB92",
"UNB93", "UNB94", "UNB95", "UNB96", "UNB97", "UNB98", "P75", "P74"
};
int get_num_iobs(int idcode)
{
if ((idcode & IDCODE_MASK) != XC6SLX9)
EXIT(1);
return sizeof(iob_xc6slx9_sitenames)/sizeof(iob_xc6slx9_sitenames[0]);
}
const char* get_iob_sitename(int idcode, int idx)
{
if ((idcode & IDCODE_MASK) != XC6SLX9)
EXIT(1);
if (idx < 0 || idx > sizeof(iob_xc6slx9_sitenames)/sizeof(iob_xc6slx9_sitenames[0]))
EXIT(1);
return iob_xc6slx9_sitenames[idx];
}
int find_iob_sitename(int idcode, const char* name)
{
int i;
if ((idcode & IDCODE_MASK) != XC6SLX9) {
HERE();
return -1;
}
for (i = 0; i < sizeof(iob_xc6slx9_sitenames)
/sizeof(iob_xc6slx9_sitenames[0]); i++) {
if (iob_xc6slx9_sitenames[i]
&& !strcmp(iob_xc6slx9_sitenames[i], name))
return i;
}
return -1;
}
int xc_num_rows(int idcode)
{
if ((idcode & IDCODE_MASK) != XC6SLX9) {
HERE();
return -1;
}
return NUM_ROWS;
}
const struct xc_die *xc_die_info(int idcode)
{
static const struct xc_die xc6slx9_info = {
.idcode = XC6SLX9,
.num_rows = 4,
.left_wiring =
/* row 3 */ "UWUWUWUW" "WWWWUUUU" \
/* row 2 */ "UUUUUUUU" "WWWWWWUU" \
/* row 1 */ "WWWUUWUU" "WUUWUUWU" \
/* row 0 */ "UWUUWUUW" "UUWWWWUU",
.right_wiring =
/* row 3 */ "UUWWUWUW" "WWWWUUUU" \
/* row 2 */ "UUUUUUUU" "WWWWWWUU" \
/* row 1 */ "WWWUUWUU" "WUUWUUWU" \
/* row 0 */ "UWUUWUUW" "UUWWWWUU",
.major_str = "M L Bg M L D M R M Ln M L Bg M L",
.num_majors = 18,
.majors = {
// maj_zero: 505 bytes = extra 8-bit for each minor?
[0] = { XC_MAJ_ZERO, 4 },
[1] = { XC_MAJ_LEFT, 30 },
[2] = { XC_MAJ_XM | XC_MAJ_TOP_BOT_IO, 31 },
[3] = { XC_MAJ_XL | XC_MAJ_TOP_BOT_IO, 30 },
[4] = { XC_MAJ_BRAM | XC_MAJ_GCLK_SEP, 25 },
[5] = { XC_MAJ_XM | XC_MAJ_TOP_BOT_IO, 31 },
[6] = { XC_MAJ_XL | XC_MAJ_TOP_BOT_IO, 30 },
[7] = { XC_MAJ_MACC, 24 },
[8] = { XC_MAJ_XM | XC_MAJ_TOP_BOT_IO, 31 },
[9] = { XC_MAJ_CENTER | XC_MAJ_TOP_BOT_IO, 31 },
[10] = { XC_MAJ_XM | XC_MAJ_TOP_BOT_IO, 31 },
[11] = { XC_MAJ_XL, 30 },
[12] = { XC_MAJ_XM | XC_MAJ_TOP_BOT_IO, 31 },
[13] = { XC_MAJ_XL | XC_MAJ_TOP_BOT_IO, 30 },
[14] = { XC_MAJ_BRAM | XC_MAJ_GCLK_SEP, 25 },
[15] = { XC_MAJ_XM | XC_MAJ_TOP_BOT_IO, 31 },
[16] = { XC_MAJ_XL | XC_MAJ_TOP_BOT_IO, 30 },
[17] = { XC_MAJ_RIGHT, 30 }},
.num_type2 = 224,
.type2 = {
[0] = { XC_T2_IOB_PAD, 70 },
[1] = { XC_T2_IOB_PAD, 69 },
[2] = { XC_T2_IOB_PAD, 67 },
[3] = { XC_T2_IOB_PAD, 66 },
[4] = { XC_T2_IOB_PAD, 65 },
[5] = { XC_T2_IOB_PAD, 64 },
[6] = { XC_T2_IOB_PAD, 62 },
[7] = { XC_T2_IOB_PAD, 61 },
[8] = { XC_T2_IOB_PAD, 60 },
[9] = { XC_T2_IOB_PAD, 59 },
[10] = { XC_T2_IOB_PAD, 58 },
[11] = { XC_T2_IOB_PAD, 57 },
[12] = { XC_T2_IOB_UNBONDED, 113 },
[13] = { XC_T2_IOB_UNBONDED, 114 },
[14] = { XC_T2_IOB_UNBONDED, 115 },
[15] = { XC_T2_IOB_UNBONDED, 116 },
[16] = { XC_T2_IOB_UNBONDED, 117 },
[17] = { XC_T2_IOB_UNBONDED, 118 },
[18] = { XC_T2_IOB_PAD, 56 },
[19] = { XC_T2_IOB_PAD, 55 },
[20] = { XC_T2_CENTER },
[21] = { XC_T2_CENTER },
[22] = { XC_T2_CENTER },
[23] = { XC_T2_CENTER },
[24] = { XC_T2_CENTER },
[25] = { XC_T2_CENTER },
[26] = { XC_T2_IOB_PAD, 51 },
[27] = { XC_T2_IOB_PAD, 50 },
[28] = { XC_T2_IOB_UNBONDED, 123 },
[29] = { XC_T2_IOB_UNBONDED, 124 },
[30] = { XC_T2_IOB_UNBONDED, 125 },
[31] = { XC_T2_IOB_UNBONDED, 126 },
[32] = { XC_T2_IOB_UNBONDED, 127 },
[33] = { XC_T2_IOB_UNBONDED, 128 },
[34] = { XC_T2_IOB_UNBONDED, 129 },
[35] = { XC_T2_IOB_UNBONDED, 130 },
[36] = { XC_T2_IOB_UNBONDED, 131 },
[37] = { XC_T2_IOB_UNBONDED, 132 },
[38] = { XC_T2_IOB_PAD, 48 },
[39] = { XC_T2_IOB_PAD, 47 },
[40] = { XC_T2_IOB_PAD, 46 },
[41] = { XC_T2_IOB_PAD, 45 },
[42] = { XC_T2_IOB_PAD, 44 },
[43] = { XC_T2_IOB_PAD, 43 },
[44] = { XC_T2_IOB_UNBONDED, 139 },
[45] = { XC_T2_IOB_UNBONDED, 140 },
[46] = { XC_T2_IOB_PAD, 41 },
[47] = { XC_T2_IOB_PAD, 40 },
[48] = { XC_T2_IOB_PAD, 39 },
[49] = { XC_T2_IOB_PAD, 38 },
[50] = { XC_T2_IOB_PAD, 35 },
[51] = { XC_T2_IOB_PAD, 34 },
[52] = { XC_T2_IOB_PAD, 33 },
[53] = { XC_T2_IOB_PAD, 32 },
[54] = { XC_T2_IOB_UNBONDED, 149 },
[55] = { XC_T2_IOB_UNBONDED, 150 },
[56] = { XC_T2_IOB_UNBONDED, 151 },
[57] = { XC_T2_IOB_UNBONDED, 152 },
[58] = { XC_T2_IOB_UNBONDED, 153 },
[59] = { XC_T2_IOB_UNBONDED, 154 },
[60] = { XC_T2_IOB_UNBONDED, 155 },
[61] = { XC_T2_IOB_UNBONDED, 156 },
[62] = { XC_T2_IOB_UNBONDED, 157 },
[63] = { XC_T2_IOB_UNBONDED, 158 },
[64] = { XC_T2_IOB_PAD, 30 },
[65] = { XC_T2_IOB_PAD, 29 },
[66] = { XC_T2_IOB_PAD, 27 },
[67] = { XC_T2_IOB_PAD, 26 },
[68] = { XC_T2_IOB_UNBONDED, 163 },
[69] = { XC_T2_IOB_UNBONDED, 164 },
[70] = { XC_T2_IOB_UNBONDED, 165 },
[71] = { XC_T2_IOB_UNBONDED, 166 },
[72] = { XC_T2_IOB_UNBONDED, 167 },
[73] = { XC_T2_IOB_UNBONDED, 168 },
[74] = { XC_T2_IOB_PAD, 24 },
[75] = { XC_T2_IOB_PAD, 23 },
[76] = { XC_T2_IOB_PAD, 22 },
[77] = { XC_T2_IOB_PAD, 21 },
[78] = { XC_T2_CENTER },
[79] = { XC_T2_CENTER },
[80] = { XC_T2_CENTER },
[81] = { XC_T2_CENTER },
[82] = { XC_T2_CENTER },
[83] = { XC_T2_CENTER },
[84] = { XC_T2_IOB_PAD, 17 },
[85] = { XC_T2_IOB_PAD, 16 },
[86] = { XC_T2_IOB_PAD, 15 },
[87] = { XC_T2_IOB_PAD, 14 },
[88] = { XC_T2_IOB_UNBONDED, 177 },
[89] = { XC_T2_IOB_UNBONDED, 178 },
[90] = { XC_T2_IOB_UNBONDED, 179 },
[91] = { XC_T2_IOB_UNBONDED, 180 },
[92] = { XC_T2_IOB_UNBONDED, 181 },
[93] = { XC_T2_IOB_UNBONDED, 182 },
[94] = { XC_T2_IOB_UNBONDED, 183 },
[95] = { XC_T2_IOB_UNBONDED, 184 },
[96] = { XC_T2_IOB_PAD, 12 },
[97] = { XC_T2_IOB_PAD, 11 },
[98] = { XC_T2_IOB_PAD, 10 },
[99] = { XC_T2_IOB_PAD, 9 },
[100] = { XC_T2_IOB_PAD, 8 },
[101] = { XC_T2_IOB_PAD, 7 },
[102] = { XC_T2_IOB_PAD, 6 },
[103] = { XC_T2_IOB_PAD, 5 },
[104] = { XC_T2_IOB_UNBONDED, 193 },
[105] = { XC_T2_IOB_UNBONDED, 194 },
[106] = { XC_T2_IOB_UNBONDED, 195 },
[107] = { XC_T2_IOB_UNBONDED, 196 },
[108] = { XC_T2_IOB_UNBONDED, 197 },
[109] = { XC_T2_IOB_UNBONDED, 198 },
[110] = { XC_T2_IOB_PAD, 2 },
[111] = { XC_T2_IOB_PAD, 1 },
[112] = { XC_T2_IOB_PAD, 144 },
[113] = { XC_T2_IOB_PAD, 143 },
[114] = { XC_T2_IOB_PAD, 142 },
[115] = { XC_T2_IOB_PAD, 141 },
[116] = { XC_T2_IOB_PAD, 140 },
[117] = { XC_T2_IOB_PAD, 139 },
[118] = { XC_T2_IOB_PAD, 138 },
[119] = { XC_T2_IOB_PAD, 137 },
[120] = { XC_T2_IOB_UNBONDED, 9 },
[121] = { XC_T2_IOB_UNBONDED, 10 },
[122] = { XC_T2_IOB_UNBONDED, 11 },
[123] = { XC_T2_IOB_UNBONDED, 12 },
[124] = { XC_T2_IOB_UNBONDED, 13 },
[125] = { XC_T2_IOB_UNBONDED, 14 },
[126] = { XC_T2_IOB_UNBONDED, 15 },
[127] = { XC_T2_IOB_UNBONDED, 16 },
[128] = { XC_T2_IOB_UNBONDED, 17 },
[129] = { XC_T2_IOB_UNBONDED, 18 },
[130] = { XC_T2_IOB_UNBONDED, 19 },
[131] = { XC_T2_IOB_UNBONDED, 20 },
[132] = { XC_T2_IOB_PAD, 134 },
[133] = { XC_T2_IOB_PAD, 133 },
[134] = { XC_T2_IOB_PAD, 132 },
[135] = { XC_T2_IOB_PAD, 131 },
[136] = { XC_T2_CENTER },
[137] = { XC_T2_CENTER },
[138] = { XC_T2_CENTER },
[139] = { XC_T2_CENTER },
[140] = { XC_T2_CENTER },
[141] = { XC_T2_CENTER },
[142] = { XC_T2_IOB_PAD, 127 },
[143] = { XC_T2_IOB_PAD, 126 },
[144] = { XC_T2_IOB_PAD, 124 },
[145] = { XC_T2_IOB_PAD, 123 },
[146] = { XC_T2_IOB_UNBONDED, 29 },
[147] = { XC_T2_IOB_UNBONDED, 30 },
[148] = { XC_T2_IOB_UNBONDED, 31 },
[149] = { XC_T2_IOB_UNBONDED, 32 },
[150] = { XC_T2_IOB_UNBONDED, 33 },
[151] = { XC_T2_IOB_UNBONDED, 34 },
[152] = { XC_T2_IOB_PAD, 121 },
[153] = { XC_T2_IOB_PAD, 120 },
[154] = { XC_T2_IOB_PAD, 119 },
[155] = { XC_T2_IOB_PAD, 118 },
[156] = { XC_T2_IOB_PAD, 117 },
[157] = { XC_T2_IOB_PAD, 116 },
[158] = { XC_T2_IOB_PAD, 115 },
[159] = { XC_T2_IOB_PAD, 114 },
[160] = { XC_T2_IOB_PAD, 112 },
[161] = { XC_T2_IOB_PAD, 111 },
[162] = { XC_T2_IOB_PAD, 105 },
[163] = { XC_T2_IOB_PAD, 104 },
[164] = { XC_T2_IOB_UNBONDED, 47 },
[165] = { XC_T2_IOB_UNBONDED, 48 },
[166] = { XC_T2_IOB_UNBONDED, 49 },
[167] = { XC_T2_IOB_UNBONDED, 50 },
[168] = { XC_T2_IOB_UNBONDED, 51 },
[169] = { XC_T2_IOB_UNBONDED, 52 },
[170] = { XC_T2_IOB_PAD, 102 },
[171] = { XC_T2_IOB_PAD, 101 },
[172] = { XC_T2_IOB_PAD, 100 },
[173] = { XC_T2_IOB_PAD, 99 },
[174] = { XC_T2_IOB_PAD, 98 },
[175] = { XC_T2_IOB_PAD, 97 },
[176] = { XC_T2_IOB_UNBONDED, 59 },
[177] = { XC_T2_IOB_UNBONDED, 60 },
[178] = { XC_T2_IOB_UNBONDED, 61 },
[179] = { XC_T2_IOB_UNBONDED, 62 },
[180] = { XC_T2_IOB_UNBONDED, 63 },
[181] = { XC_T2_IOB_UNBONDED, 64 },
[182] = { XC_T2_IOB_UNBONDED, 65 },
[183] = { XC_T2_IOB_UNBONDED, 66 },
[184] = { XC_T2_IOB_UNBONDED, 67 },
[185] = { XC_T2_IOB_UNBONDED, 68 },
[186] = { XC_T2_IOB_PAD, 95 },
[187] = { XC_T2_IOB_PAD, 94 },
[188] = { XC_T2_IOB_PAD, 93 },
[189] = { XC_T2_IOB_PAD, 92 },
[190] = { XC_T2_CENTER },
[191] = { XC_T2_CENTER },
[192] = { XC_T2_CENTER },
[193] = { XC_T2_CENTER },
[194] = { XC_T2_CENTER },
[195] = { XC_T2_CENTER },
[196] = { XC_T2_IOB_PAD, 88 },
[197] = { XC_T2_IOB_PAD, 87 },
[198] = { XC_T2_IOB_PAD, 85 },
[199] = { XC_T2_IOB_PAD, 84 },
[200] = { XC_T2_IOB_UNBONDED, 77 },
[201] = { XC_T2_IOB_UNBONDED, 78 },
[202] = { XC_T2_IOB_PAD, 83 },
[203] = { XC_T2_IOB_PAD, 82 },
[204] = { XC_T2_IOB_PAD, 81 },
[205] = { XC_T2_IOB_PAD, 80 },
[206] = { XC_T2_IOB_PAD, 79 },
[207] = { XC_T2_IOB_PAD, 78 },
[208] = { XC_T2_IOB_UNBONDED, 85 },
[209] = { XC_T2_IOB_UNBONDED, 86 },
[210] = { XC_T2_IOB_UNBONDED, 87 },
[211] = { XC_T2_IOB_UNBONDED, 88 },
[212] = { XC_T2_IOB_UNBONDED, 89 },
[213] = { XC_T2_IOB_UNBONDED, 90 },
[214] = { XC_T2_IOB_UNBONDED, 91 },
[215] = { XC_T2_IOB_UNBONDED, 92 },
[216] = { XC_T2_IOB_UNBONDED, 93 },
[217] = { XC_T2_IOB_UNBONDED, 94 },
[218] = { XC_T2_IOB_UNBONDED, 95 },
[219] = { XC_T2_IOB_UNBONDED, 96 },
[220] = { XC_T2_IOB_UNBONDED, 97 },
[221] = { XC_T2_IOB_UNBONDED, 98 },
[222] = { XC_T2_IOB_PAD, 75 },
[223] = { XC_T2_IOB_PAD, 74 }},
.mcb_ypos = 20,
.num_mui = 8,
.mui_pos = { 40, 43, 47, 50, 53, 56, 59, 63 },
.sel_logicin = {
24, 15, 7, 42, 5, 12, 62, 16,
47, 20, 38, 23, 48, 57, 44, 4 }};
switch (idcode & IDCODE_MASK) {
case XC6SLX9: return &xc6slx9_info;
}
HERE();
return 0;
}
int xc_die_center_major(const struct xc_die *die)
{
int i;
for (i = 0; i < die->num_majors; i++) {
if (die->majors[i].flags & XC_MAJ_CENTER)
return i;
}
HERE();
return -1;
}
const struct xc6_pkg_info *xc6_pkg_info(enum xc6_pkg pkg)
{
// ug382 table 1-6 page 25
static const struct xc6_pkg_info pkg_tqg144 = {
.pkg = TQG144,
.num_gclk_pins = XC6_NUM_GCLK_PINS,
.gclk_pin = {
/* 0 */ "P55", "P56", 0, 0,
/* 4 */ "P84", "P85", "P87", "P88",
/* 8 */ "P92", "P93", "P94", "P95",
/* 12 */ "P123", "P124", "P126", "P127",
/* 16 */ "P131", "P132", "P133", "P134",
/* 20 */ "P14", "P15", "P16", "P17",
/* 24 */ "P21", "P22", "P23", "P24",
/* 28 */ 0, 0, "P50", "P51" },
.gclk_type2_o = {
/* 0 */ 20*4+ 6, 20*4+ 9, -1, -1,
/* 4 */ 190*4+18, 190*4+21, 190*4+12, 190*4+15,
/* 8 */ 190*4+ 6, 190*4+ 9, 190*4+ 0, 190*4+ 3,
/* 12 */ 136*4+18, 136*4+21, 136*4+12, 136*4+15,
/* 16 */ 136*4+ 6, 136*4+ 9, 136*4+ 0, 136*4+ 3,
/* 20 */ 78*4+21, 78*4+18, 78*4+15, 78*4+12,
/* 24 */ 78*4+ 9, 78*4+ 6, 78*4+ 3, 78*4+ 0,
/* 28 */ -1, -1, 20*4+12, 20*4+15 }};
switch (pkg) {
case TQG144: return &pkg_tqg144;
default: ;
}
HERE();
return 0;
}
int get_major_minors(int idcode, int major)
{
static const int minors_per_major[] = // for slx9
{
/* 0 */ 4, // 505 bytes = middle 8-bit for each minor?
/* 1 */ 30, // left
/* 2 */ 31, // logic M
/* 3 */ 30, // logic L
/* 4 */ 25, // bram
/* 5 */ 31, // logic M
/* 6 */ 30, // logic L
/* 7 */ 24, // macc
/* 8 */ 31, // logic M
/* 9 */ 31, // center
/* 10 */ 31, // logic M
/* 11 */ 30, // logic L
/* 12 */ 31, // logic M
/* 13 */ 30, // logic L
/* 14 */ 25, // bram
/* 15 */ 31, // logic M
/* 16 */ 30, // logic L
/* 17 */ 30, // right
};
if ((idcode & IDCODE_MASK) != XC6SLX9)
EXIT(1);
if (major < 0 || major
> sizeof(minors_per_major)/sizeof(minors_per_major[0]))
EXIT(1);
return minors_per_major[major];
}
enum major_type get_major_type(int idcode, int major)
{
static const int major_types[] = // for slx9
{
/* 0 */ MAJ_ZERO,
/* 1 */ MAJ_LEFT,
/* 2 */ MAJ_LOGIC_XM,
/* 3 */ MAJ_LOGIC_XL,
/* 4 */ MAJ_BRAM,
/* 5 */ MAJ_LOGIC_XM,
/* 6 */ MAJ_LOGIC_XL,
/* 7 */ MAJ_MACC,
/* 8 */ MAJ_LOGIC_XM,
/* 9 */ MAJ_CENTER,
/* 10 */ MAJ_LOGIC_XM,
/* 11 */ MAJ_LOGIC_XL,
/* 12 */ MAJ_LOGIC_XM,
/* 13 */ MAJ_LOGIC_XL,
/* 14 */ MAJ_BRAM,
/* 15 */ MAJ_LOGIC_XM,
/* 16 */ MAJ_LOGIC_XL,
/* 17 */ MAJ_RIGHT
};
if ((idcode & IDCODE_MASK) != XC6SLX9)
EXIT(1);
if (major < 0 || major
> sizeof(major_types)/sizeof(major_types[0]))
EXIT(1);
return major_types[major];
}
int get_rightside_major(int idcode)
{
if ((idcode & IDCODE_MASK) != XC6SLX9) {
HERE();
return -1;
}
return XC6_SLX9_RIGHTMOST_MAJOR;
}
int get_major_framestart(int idcode, int major)
{
int i, frame_count;
frame_count = 0;
for (i = 0; i < major; i++)
frame_count += get_major_minors(idcode, i);
return frame_count;
}
int get_frames_per_row(int idcode)
{
return get_major_framestart(idcode, get_rightside_major(idcode)+1);
}
//
// routing switches
//
struct sw_mip_src
{
int minor;
int m0_sw_to;
int m0_two_bits_o;
int m0_two_bits_val;
int m0_one_bit_start;
int m1_sw_to;
int m1_two_bits_o;
int m1_two_bits_val;
int m1_one_bit_start;
int from_w[6];
};
// returns:
// 1 for the active side of a bidir switch, where the bits reside
// 0 for a unidirectional switch
// -1 for the passive side of a bidir switch, where no bits reside
static int bidir_check(int sw_to, int sw_from)
{
// the first member of bidir switch pairs is where the bits reside
static const int bidir[] = {
LW + (LI_BX|LD1), FAN_B,
LW + (LI_AX|LD1), GFAN0,
LW + LI_AX, GFAN0,
LW + (LI_CE|LD1), GFAN1,
LW + (LI_CI|LD1), GFAN1,
LW + LI_BX, LW + (LI_CI|LD1),
LW + LI_BX, LW + (LI_DI|LD1),
LW + (LI_AX|LD1), LW + (LI_CI|LD1),
LW + (LI_BX|LD1), LW + (LI_CE|LD1),
LW + LI_AX, LW + (LI_CE|LD1) };
int i;
// bidirectional switches are ignored on one side, and
// marked as bidir on the other side
for (i = 0; i < sizeof(bidir)/sizeof(*bidir)/2; i++) {
if (sw_from == bidir[i*2] && sw_to == bidir[i*2+1])
// nothing to do where no bits reside
return -1;
if (sw_from == bidir[i*2+1] && sw_to == bidir[i*2])
return 1;
}
return 0;
}
static int wire_decrement(int wire)
{
int _wire, flags;
if (wire >= DW && wire <= DW_LAST) {
_wire = wire - DW;
flags = _wire & DIR_FLAGS;
_wire &= ~DIR_FLAGS;
if (_wire%4 == 0)
return DW + ((_wire + 3) | flags);
return DW + ((_wire - 1) | flags);
}
if (wire >= LW && wire <= LW_LAST) {
_wire = wire - LW;
flags = _wire & LD1;
_wire &= ~LD1;
if (_wire == LO_A)
return LW + (LO_D|flags);
if (_wire == LO_AMUX)
return LW + (LO_DMUX|flags);
if (_wire == LO_AQ)
return LW + (LO_DQ|flags);
if ((_wire >= LO_B && _wire <= LO_D)
|| (_wire >= LO_BMUX && _wire <= LO_DMUX)
|| (_wire >= LO_BQ && _wire <= LO_DQ))
return LW + ((_wire-1)|flags);
}
if (wire == NO_WIRE) return wire;
HERE();
return wire;
}
static enum extra_wires clean_S0N3(enum extra_wires wire)
{
int flags;
if (wire < DW || wire > DW_LAST) return wire;
wire -= DW;
flags = wire & DIR_FLAGS;
wire &= ~DIR_FLAGS;
if (flags & DIR_S0 && wire%4 != 0)
flags &= ~DIR_S0;
if (flags & DIR_N3 && wire%4 != 3)
flags &= ~DIR_N3;
return DW + (wire | flags);
}
static int src_to_bitpos(struct xc6_routing_bitpos* bitpos, int* cur_el, int max_el,
const struct sw_mip_src* src, int src_len)
{
int i, j, bidir, rc;
for (i = 0; i < src_len; i++) {
for (j = 0; j < sizeof(src->from_w)/sizeof(src->from_w[0]); j++) {
if (src[i].from_w[j] == NO_WIRE) continue;
bidir = bidir_check(src[i].m0_sw_to, src[i].from_w[j]);
if (bidir != -1) {
if (*cur_el >= max_el) FAIL(EINVAL);
bitpos[*cur_el].from = clean_S0N3(src[i].from_w[j]);
bitpos[*cur_el].to = clean_S0N3(src[i].m0_sw_to);
bitpos[*cur_el].bidir = bidir;
bitpos[*cur_el].minor = src[i].minor;
bitpos[*cur_el].two_bits_o = src[i].m0_two_bits_o;
bitpos[*cur_el].two_bits_val = src[i].m0_two_bits_val;
bitpos[*cur_el].one_bit_o = src[i].m0_one_bit_start + j*2;
(*cur_el)++;
}
bidir = bidir_check(src[i].m1_sw_to, src[i].from_w[j]);
if (bidir != -1) {
if (*cur_el >= max_el) FAIL(EINVAL);
bitpos[*cur_el].from = clean_S0N3(src[i].from_w[j]);
bitpos[*cur_el].to = clean_S0N3(src[i].m1_sw_to);
bitpos[*cur_el].bidir = bidir;
bitpos[*cur_el].minor = src[i].minor;
bitpos[*cur_el].two_bits_o = src[i].m1_two_bits_o;
bitpos[*cur_el].two_bits_val = src[i].m1_two_bits_val;
bitpos[*cur_el].one_bit_o = src[i].m1_one_bit_start + j*2;
(*cur_el)++;
}
}
}
return 0;
fail:
return rc;
}
#define LOGIN_ROW 2
#define LOGIN_MIP_ROWS 8
static const int logicin_matrix[] =
{
/*mip 12*/
/* 000 */ LW + (LI_C6|LD1), LW + LI_D6,
/* 016 */ LW + (LI_B1|LD1), LW + (LI_DI|LD1),
/* 032 */ LW + (LI_C5|LD1), LW + LI_D5,
/* 048 */ LW + (LI_CI|LD1), LW + LI_A2,
/* 064 */ LW + (LI_C4|LD1), LW + LI_D4,
/* 080 */ LW + LI_A1, LW + LI_CE,
/* 096 */ LW + (LI_C3|LD1), LW + LI_D3,
/* 112 */ LW + (LI_B2|LD1), LW + (LI_WE|LD1),
/*mip 14*/
/* 000 */ LW + LI_C1, LW + LI_DX,
/* 016 */ LW + (LI_A3|LD1), LW + LI_B3,
/* 032 */ LW + (LI_CX|LD1), LW + (LI_D2|LD1),
/* 048 */ LW + (LI_A4|LD1), LW + LI_B4,
/* 064 */ LW + (LI_D1|LD1), LW + LI_BX,
/* 080 */ LW + (LI_A5|LD1), LW + LI_B5,
/* 096 */ LW + (LI_AX|LD1), LW + LI_C2,
/* 112 */ LW + (LI_A6|LD1), LW + LI_B6,
/*mip 16*/
/* 000 */ LW + (LI_B3|LD1), LW + LI_A3,
/* 016 */ LW + (LI_C2|LD1), LW + (LI_DX|LD1),
/* 032 */ LW + (LI_B4|LD1), LW + LI_A4,
/* 048 */ LW + LI_CX, LW + LI_D1,
/* 064 */ LW + (LI_B5|LD1), LW + LI_A5,
/* 080 */ LW + (LI_BX|LD1), LW + LI_D2,
/* 096 */ LW + (LI_B6|LD1), LW + LI_A6,
/* 112 */ LW + (LI_C1|LD1), LW + LI_AX,
/*mip 18*/
/* 000 */ LW + LI_B2, FAN_B,
/* 016 */ LW + (LI_D6|LD1), LW + LI_C6,
/* 032 */ LW + (LI_A1|LD1), LW + (LI_CE|LD1),
/* 048 */ LW + (LI_D5|LD1), LW + LI_C5,
/* 064 */ LW + (LI_A2|LD1), LW + (LI_BI|LD1),
/* 080 */ LW + (LI_D4|LD1), LW + LI_C4,
/* 096 */ LW + (LI_AI|LD1), LW + LI_B1,
/* 112 */ LW + (LI_D3|LD1), LW + LI_C3
};
static int mip_to_bitpos(struct xc6_routing_bitpos* bitpos, int* cur_el,
int max_el, int minor, int m0_two_bits_val, int m0_one_bit_start,
int m1_two_bits_val, int m1_one_bit_start, int (*from_ws)[8][6])
{
struct sw_mip_src src;
int i, j, rc;
src.minor = minor;
src.m0_two_bits_o = 0;
src.m0_two_bits_val = m0_two_bits_val;
src.m0_one_bit_start = m0_one_bit_start;
src.m1_two_bits_o = 14;
src.m1_two_bits_val = m1_two_bits_val;
src.m1_one_bit_start = m1_one_bit_start;
for (i = 0; i < 8; i++) {
int logicin_o = ((src.minor-12)/2)*LOGIN_MIP_ROWS*LOGIN_ROW;
logicin_o += i*LOGIN_ROW;
src.m0_sw_to = logicin_matrix[logicin_o+0];
src.m1_sw_to = logicin_matrix[logicin_o+1];
if (i) {
src.m0_two_bits_o += 16;
src.m0_one_bit_start += 16;
src.m1_two_bits_o += 16;
src.m1_one_bit_start += 16;
}
for (j = 0; j < sizeof(src.from_w)/sizeof(src.from_w[0]); j++)
src.from_w[j] = (*from_ws)[i][j];
rc = src_to_bitpos(bitpos, cur_el, max_el, &src, /*src_len*/ 1);
if (rc) FAIL(rc);
}
return 0;
fail:
return rc;
}
int get_xc6_routing_bitpos(struct xc6_routing_bitpos** bitpos, int* num_bitpos)
{
int i, j, k, rc;
*num_bitpos = 0;
*bitpos = malloc(MAX_SWITCHBOX_SIZE * sizeof(**bitpos));
if (!(*bitpos)) FAIL(ENOMEM);
// mip 0-10 (6*288=1728 switches)
{ struct sw_mip_src src[] = {
{0, DW + ((W_WW4*4+3) | DIR_BEG), 0, 2, 3,
DW + ((W_NW4*4+3) | DIR_BEG), 14, 1, 2,
{LW + (LO_BMUX|LD1), LW + (LO_DQ|LD1), LW + (LO_D|LD1),
LW + LO_BMUX, LW + LO_DQ, LW + LO_D}},
{0, DW + ((W_WW4*4+3) | DIR_BEG), 0, 1, 3,
DW + ((W_NW4*4+3) | DIR_BEG), 14, 2, 2,
{DW + ((W_SW2*4+2)|DIR_N3), DW + ((W_SS2*4+2)|DIR_N3), DW + ((W_WW2*4+2)|DIR_N3),
DW + W_NE2*4+3, DW + W_NN2*4+3, DW + W_NW2*4+3}},
{0, DW + ((W_WW4*4+3) | DIR_BEG), 0, 0, 3,
DW + ((W_NW4*4+3) | DIR_BEG), 14, 0, 2,
{DW + ((W_SW4*4+2)|DIR_N3), DW + ((W_SS4*4+2)|DIR_N3), DW + W_NE4*4+3,
DW + W_NN4*4+3, DW + W_NW4*4+3, DW + W_WW4*4+3}},
{0, DW + ((W_SS4*4+3) | DIR_BEG), 16, 2, 18,
DW + ((W_SW4*4+3) | DIR_BEG), 30, 1, 19,
{DW + W_SW2*4+3, DW + W_WW2*4+3, DW + ((W_NW2*4+0)|DIR_S0),
DW + W_SS2*4+3, DW + W_SE2*4+3, DW + W_EE2*4+3}},
{0, DW + ((W_SS4*4+3) | DIR_BEG), 16, 1, 18,
DW + ((W_SW4*4+3) | DIR_BEG), 30, 2, 19,
{LW + LO_D, LW + LO_DQ, LW + LO_BMUX,
LW + (LO_D|LD1), LW + (LO_DQ|LD1), LW + (LO_BMUX|LD1)}},
{0, DW + ((W_SS4*4+3) | DIR_BEG), 16, 0, 18,
DW + ((W_SW4*4+3) | DIR_BEG), 30, 0, 19,
{DW + W_SW4*4+3, DW + W_SS4*4+3, DW + ((W_WW4*4+0)|DIR_S0),
DW + ((W_NW4*4+0)|DIR_S0), DW + W_SE4*4+3, DW + W_EE4*4+3}},
{2, DW + ((W_NN4*4+3) | DIR_BEG), 0, 2, 3,
DW + ((W_NE4*4+3) | DIR_BEG), 14, 1, 2,
{LW + (LO_BMUX|LD1), LW + (LO_DQ|LD1), LW + (LO_D|LD1),
LW + LO_BMUX, LW + LO_DQ, LW + LO_D}},
{2, DW + ((W_NN4*4+3) | DIR_BEG), 0, 1, 3,
DW + ((W_NE4*4+3) | DIR_BEG), 14, 2, 2,
{DW + W_EE2*4+3, DW + W_SE2*4+3, DW + ((W_WW2*4+2)|DIR_N3),
DW + W_NE2*4+3, DW + W_NN2*4+3, DW + W_NW2*4+3}},
{2, DW + ((W_NN4*4+3) | DIR_BEG), 0, 0, 3,
DW + ((W_NE4*4+3) | DIR_BEG), 14, 0, 2,
{DW + W_EE4*4+3, DW + W_SE4*4+3, DW + W_NE4*4+3,
DW + W_NN4*4+3, DW + W_NW4*4+3, DW + W_WW4*4+3}},
{2, DW + ((W_EE4*4+3) | DIR_BEG), 16, 2, 18,
DW + ((W_SE4*4+3) | DIR_BEG), 30, 1, 19,
{DW + W_SW2*4+3, DW + W_NN2*4+3, DW + W_NE2*4+3,
DW + W_SS2*4+3, DW + W_SE2*4+3, DW + W_EE2*4+3}},
{2, DW + ((W_EE4*4+3) | DIR_BEG), 16, 1, 18,
DW + ((W_SE4*4+3) | DIR_BEG), 30, 2, 19,
{LW + LO_D, LW + LO_DQ, LW + LO_BMUX,
LW + (LO_D|LD1), LW + (LO_DQ|LD1), LW + (LO_BMUX|LD1)}},
{2, DW + ((W_EE4*4+3) | DIR_BEG), 16, 0, 18,
DW + ((W_SE4*4+3) | DIR_BEG), 30, 0, 19,
{DW + W_SW4*4+3, DW + W_SS4*4+3, DW + W_NN4*4+3,
DW + W_NE4*4+3, DW + W_SE4*4+3, DW + W_EE4*4+3}},
{4, DW + ((W_NW2*4+3) | DIR_BEG), 0, 2, 3,
DW + ((W_NN2*4+3) | DIR_BEG), 14, 1, 2,
{LW + (LO_BMUX|LD1), LW + (LO_DQ|LD1), LW + (LO_D|LD1),
LW + LO_BMUX, LW + LO_DQ, LW + LO_D}},
{4, DW + ((W_NW2*4+3) | DIR_BEG), 0, 1, 3,
DW + ((W_NN2*4+3) | DIR_BEG), 14, 2, 2,
{DW + W_NE2*4+3, DW + W_NN2*4+3, DW + ((W_WL1*4+2)|DIR_N3),
DW + W_WR1*4+3, DW + W_NR1*4+3, DW + W_NL1*4+3}},
{4, DW + ((W_NW2*4+3) | DIR_BEG), 0, 0, 3,
DW + ((W_NN2*4+3) | DIR_BEG), 14, 0, 2,
{DW + W_NW4*4+3, DW + W_WW4*4+3, DW + W_NE4*4+3,
DW + W_NN4*4+3, DW + ((W_WW2*4+2)|DIR_N3), DW + W_NW2*4+3}},
{4, DW + ((W_WW2*4+3) | DIR_BEG), 16, 2, 18,
DW + ((W_SW2*4+3) | DIR_BEG), 30, 1, 19,
{DW + W_SR1*4+3, DW + W_SL1*4+3, DW + ((W_WR1*4+0)|DIR_S0),
DW + W_WL1*4+3, DW + W_SW2*4+3, DW + W_SS2*4+3}},
{4, DW + ((W_WW2*4+3) | DIR_BEG), 16, 1, 18,
DW + ((W_SW2*4+3) | DIR_BEG), 30, 2, 19,
{LW + LO_D, LW + LO_DQ, LW + LO_BMUX,
LW + (LO_D|LD1), LW + (LO_DQ|LD1), LW + (LO_BMUX|LD1)}},
{4, DW + ((W_WW2*4+3) | DIR_BEG), 16, 0, 18,
DW + ((W_SW2*4+3) | DIR_BEG), 30, 0, 19,
{DW + W_WW2*4+3, DW + ((W_NW2*4+0)|DIR_S0), DW + W_SW4*4+3,
DW + W_SS4*4+3, DW + ((W_WW4*4+0)|DIR_S0), DW + ((W_NW4*4+0)|DIR_S0)}},
{6, DW + ((W_NE2*4+3) | DIR_BEG), 0, 2, 3,
DW + ((W_EE2*4+3) | DIR_BEG), 14, 1, 2,
{LW + (LO_BMUX|LD1), LW + (LO_DQ|LD1), LW + (LO_D|LD1),
LW + LO_BMUX, LW + LO_DQ, LW + LO_D}},
{6, DW + ((W_NE2*4+3) | DIR_BEG), 0, 1, 3,
DW + ((W_EE2*4+3) | DIR_BEG), 14, 2, 2,
{DW + W_NE2*4+3, DW + W_NN2*4+3, DW + W_EL1*4+3,
DW + W_ER1*4+3, DW + W_NR1*4+3, DW + W_NL1*4+3}},
{6, DW + ((W_NE2*4+3) | DIR_BEG), 0, 0, 3,
DW + ((W_EE2*4+3) | DIR_BEG), 14, 0, 2,
{DW + W_EE4*4+3, DW + W_SE4*4+3, DW + W_NE4*4+3,
DW + W_NN4*4+3, DW + W_EE2*4+3, DW + W_SE2*4+3}},
{6, DW + ((W_SS2*4+3) | DIR_BEG), 16, 2, 18,
DW + ((W_SE2*4+3) | DIR_BEG), 30, 1, 19,
{DW + W_SR1*4+3, DW + W_SL1*4+3, DW + W_ER1*4+3,
DW + W_EL1*4+3, DW + W_SW2*4+3, DW + W_SS2*4+3}},
{6, DW + ((W_SS2*4+3) | DIR_BEG), 16, 1, 18,
DW + ((W_SE2*4+3) | DIR_BEG), 30, 2, 19,
{LW + LO_D, LW + LO_DQ, LW + LO_BMUX,
LW + (LO_D|LD1), LW + (LO_DQ|LD1), LW + (LO_BMUX|LD1)}},
{6, DW + ((W_SS2*4+3) | DIR_BEG), 16, 0, 18,
DW + ((W_SE2*4+3) | DIR_BEG), 30, 0, 19,
{DW + W_SE2*4+3, DW + W_EE2*4+3, DW + W_SW4*4+3,
DW + W_SS4*4+3, DW + W_SE4*4+3, DW + W_EE4*4+3}},
{8, DW + ((W_WR1*4+0) | DIR_BEG), 0, 2, 3,
DW + ((W_NL1*4+2) | DIR_BEG), 14, 1, 2,
{LW + (LO_BMUX|LD1), LW + (LO_DQ|LD1), LW + (LO_D|LD1),
LW + LO_BMUX, LW + LO_DQ, LW + LO_D}},
{8, DW + ((W_WR1*4+0) | DIR_BEG), 0, 1, 3,
DW + ((W_NL1*4+2) | DIR_BEG), 14, 2, 2,
{DW + W_NE2*4+3, DW + W_NN2*4+3, DW + ((W_WL1*4+2)|DIR_N3),
DW + W_WR1*4+3, DW + W_NR1*4+3, DW + W_NL1*4+3}},
{8, DW + ((W_WR1*4+0) | DIR_BEG), 0, 0, 3,
DW + ((W_NL1*4+2) | DIR_BEG), 14, 0, 2,
{DW + W_NW4*4+3, DW + W_WW4*4+3, DW + W_NE4*4+3,
DW + W_NN4*4+3, DW + ((W_WW2*4+2)|DIR_N3), DW + W_NW2*4+3}},
{8, DW + ((W_SR1*4+0) | DIR_BEG), 16, 2, 18,
DW + ((W_WL1*4+2) | DIR_BEG), 30, 1, 19,
{DW + W_SR1*4+3, DW + W_SL1*4+3, DW + ((W_WR1*4+0)|DIR_S0),
DW + W_WL1*4+3, DW + W_SW2*4+3, DW + W_SS2*4+3}},
{8, DW + ((W_SR1*4+0) | DIR_BEG), 16, 1, 18,
DW + ((W_WL1*4+2) | DIR_BEG), 30, 2, 19,
{LW + LO_D, LW + LO_DQ, LW + LO_BMUX,
LW + (LO_D|LD1), LW + (LO_DQ|LD1), LW + (LO_BMUX|LD1)}},
{8, DW + ((W_SR1*4+0) | DIR_BEG), 16, 0, 18,
DW + ((W_WL1*4+2) | DIR_BEG), 30, 0, 19,
{DW + W_WW2*4+3, DW + ((W_NW2*4+0)|DIR_S0), DW + W_SW4*4+3,
DW + W_SS4*4+3, DW + ((W_WW4*4+0)|DIR_S0), DW + ((W_NW4*4+0)|DIR_S0)}},
{10, DW + ((W_EL1*4+2) | DIR_BEG), 0, 2, 3,
DW + ((W_NR1*4+3) | DIR_BEG), 14, 1, 2,
{LW + (LO_BMUX|LD1), LW + (LO_DQ|LD1), LW + (LO_D|LD1),
LW + LO_BMUX, LW + LO_DQ, LW + LO_D}},
{10, DW + ((W_EL1*4+2) | DIR_BEG), 0, 1, 3,
DW + ((W_NR1*4+3) | DIR_BEG), 14, 2, 2,
{DW + W_NE2*4+3, DW + W_NN2*4+3, DW + W_EL1*4+3,
DW + W_ER1*4+3, DW + W_NR1*4+3, DW + W_NL1*4+3}},
{10, DW + ((W_EL1*4+2) | DIR_BEG), 0, 0, 3,
DW + ((W_NR1*4+3) | DIR_BEG), 14, 0, 2,
{DW + W_EE4*4+3, DW + W_SE4*4+3, DW + W_NE4*4+3,
DW + W_NN4*4+3, DW + W_EE2*4+3, DW + W_SE2*4+3}},
{10, DW + ((W_SL1*4+3) | DIR_BEG), 16, 2, 18,
DW + ((W_ER1*4+0) | DIR_BEG), 30, 1, 19,
{DW + W_SR1*4+3, DW + W_SL1*4+3, DW + W_ER1*4+3,
DW + W_EL1*4+3, DW + W_SW2*4+3, DW + W_SS2*4+3}},
{10, DW + ((W_SL1*4+3) | DIR_BEG), 16, 1, 18,
DW + ((W_ER1*4+0) | DIR_BEG), 30, 2, 19,
{LW + LO_D, LW + LO_DQ, LW + LO_BMUX,
LW + (LO_D|LD1), LW + (LO_DQ|LD1), LW + (LO_BMUX|LD1)}},
{10, DW + ((W_SL1*4+3) | DIR_BEG), 16, 0, 18,
DW + ((W_ER1*4+0) | DIR_BEG), 30, 0, 19,
{DW + W_SE2*4+3, DW + W_EE2*4+3, DW + W_SW4*4+3,
DW + W_SS4*4+3, DW + W_SE4*4+3, DW + W_EE4*4+3}}};
for (i = 0;; i++) {
rc = src_to_bitpos(*bitpos, num_bitpos, MAX_SWITCHBOX_SIZE,
src, sizeof(src)/sizeof(*src));
if (rc) FAIL(rc);
if (i >= 3) break;
for (j = 0; j < sizeof(src)/sizeof(*src); j++) {
src[j].m0_sw_to = wire_decrement(src[j].m0_sw_to);
src[j].m0_two_bits_o += 32;
src[j].m0_one_bit_start += 32;
src[j].m1_sw_to = wire_decrement(src[j].m1_sw_to);
src[j].m1_two_bits_o += 32;
src[j].m1_one_bit_start += 32;
for (k = 0; k < sizeof(src[0].from_w)/sizeof(src[0].from_w[0]); k++)
src[j].from_w[k] = wire_decrement(src[j].from_w[k]);
}
}
}
// mip 12-18, decrementing directional wires (1024 switches)
{ struct sw_mip_src src[] = {
{12, NO_WIRE, 0, 2, 2,
NO_WIRE, 14, 2, 3,
{DW + W_EL1*4+3, DW + W_ER1*4+3, DW + W_WL1*4+3,
DW + W_WR1*4+3, DW + W_EE2*4+3, DW + W_SE2*4+3}},
{12, NO_WIRE, 0, 0, 2,
NO_WIRE, 14, 0, 3,
{DW + W_SS2*4+3, DW + W_SW2*4+3, DW + ((W_NW2*4+0)|DIR_S0),
DW + W_WW2*4+3, DW + W_NE2*4+3, DW + W_NN2*4+3}},
{12, NO_WIRE, 0, 1, 2,
NO_WIRE, 14, 1, 3,
{NO_WIRE, NO_WIRE, DW + ((W_NL1*4+0)|DIR_S0),
DW + W_NR1*4+3, DW + W_SL1*4+3, DW + W_SR1*4+3}},
{14, NO_WIRE, 0, 1, 3,
NO_WIRE, 14, 1, 2,
{DW + ((W_EL1*4+0)|DIR_S0), DW + W_ER1*4+3, DW + W_WL1*4+3,
DW + ((W_WR1*4+0)|DIR_S0), DW + W_EE2*4+3, DW + W_SE2*4+3}},
{14, NO_WIRE, 0, 0, 3,
NO_WIRE, 14, 0, 2,
{DW + W_SS2*4+3, DW + W_SW2*4+3, DW + ((W_NW2*4+0)|DIR_S0),
DW + W_WW2*4+3, DW + ((W_NE2*4+0)|DIR_S0), DW + ((W_NN2*4+0)|DIR_S0)}},
{14, NO_WIRE, 0, 2, 3,
NO_WIRE, 14, 2, 2,
{NO_WIRE, NO_WIRE, DW + ((W_NL1*4+0)|DIR_S0),
DW + W_NR1*4+3, DW + W_SL1*4+3, DW + W_SR1*4+3}},
{16, NO_WIRE, 0, 2, 2,
NO_WIRE, 14, 2, 3,
{DW + W_EL1*4+3, DW + W_ER1*4+3, DW + W_WL1*4+3,
DW + W_WR1*4+3, DW + W_EE2*4+3, DW + W_SE2*4+3}},
{16, NO_WIRE, 0, 0, 2,
NO_WIRE, 14, 0, 3,
{DW + W_SS2*4+3, DW + W_SW2*4+3, DW + W_NW2*4+3,
DW + ((W_WW2*4+2)|DIR_N3), DW + W_NE2*4+3, DW + W_NN2*4+3}},
{16, NO_WIRE, 0, 1, 2,
NO_WIRE, 14, 1, 3,
{NO_WIRE, NO_WIRE, DW + W_NL1*4+3,
DW + W_NR1*4+3, DW + W_SL1*4+3, DW + ((W_SR1*4+2)|DIR_N3)}},
{18, NO_WIRE, 0, 1, 3,
NO_WIRE, 14, 1, 2,
{DW + W_EL1*4+3, DW + ((W_ER1*4+2)|DIR_N3), DW + ((W_WL1*4+2)|DIR_N3),
DW + W_WR1*4+3, DW + W_EE2*4+3, DW + W_SE2*4+3}},
{18, NO_WIRE, 0, 0, 3,
NO_WIRE, 14, 0, 2,
{DW + ((W_SS2*4+2)|DIR_N3), DW + ((W_SW2*4+2)|DIR_N3), DW + W_NW2*4+3,
DW + ((W_WW2*4+2)|DIR_N3), DW + W_NE2*4+3, DW + W_NN2*4+3}},
{18, NO_WIRE, 0, 2, 3,
NO_WIRE, 14, 2, 2,
{NO_WIRE, NO_WIRE, DW + W_NL1*4+3,
DW + W_NR1*4+3, DW + W_SL1*4+3, DW + ((W_SR1*4+2)|DIR_N3)}}};
for (i = 0; i < 8; i++) {
for (j = 0; j < sizeof(src)/sizeof(*src); j++) {
int logicin_o = ((src[j].minor-12)/2)*LOGIN_MIP_ROWS*LOGIN_ROW;
logicin_o += i*LOGIN_ROW;
src[j].m0_sw_to = logicin_matrix[logicin_o+0];
src[j].m1_sw_to = logicin_matrix[logicin_o+1];
if (i) {
src[j].m0_two_bits_o += 16;
src[j].m0_one_bit_start += 16;
src[j].m1_two_bits_o += 16;
src[j].m1_one_bit_start += 16;
if (!(i%2)) // at 2, 4 and 6 we decrement the wires
for (k = 0; k < sizeof(src[0].from_w)/sizeof(src[0].from_w[0]); k++)
src[j].from_w[k] = wire_decrement(src[j].from_w[k]);
}
}
rc = src_to_bitpos(*bitpos, num_bitpos, MAX_SWITCHBOX_SIZE,
src, sizeof(src)/sizeof(*src));
if (rc) FAIL(rc);
}
}
// VCC/GND/GFAN, logicin and logicout sources
// mip12-14
{ int logicin_src[8][6] = {
{VCC_WIRE, LW + (LO_D|LD1), LW + LO_DQ, LW + (LO_BMUX|LD1), LOGICIN_S62, LOGICIN_S20},
{GFAN1, LW + (LO_D|LD1), LW + LO_DQ, LW + (LO_BMUX|LD1), LOGICIN_S62, LOGICIN_S20},
{VCC_WIRE, LW + LO_C, LW + (LO_CQ|LD1), LW + LO_AMUX, LOGICIN_S62, LW + (LI_AX|LD1)},
{GFAN1, LW + LO_C, LW + (LO_CQ|LD1), LW + LO_AMUX, LOGICIN_S62, LW + (LI_AX|LD1)},
{VCC_WIRE, LW + (LO_B|LD1), LW + LO_BQ, LW + (LO_DMUX|LD1), LW + (LI_AX|LD1), LW + (LI_CI|LD1)},
{GFAN0, LW + (LO_B|LD1), LW + LO_BQ, LW + (LO_DMUX|LD1), LW + (LI_AX|LD1), LW + (LI_CI|LD1)},
{VCC_WIRE, LW + LO_A, LW + (LO_AQ|LD1), LW + LO_CMUX, LOGICIN20, LW + (LI_CI|LD1)},
{GFAN0, LW + LO_A, LW + (LO_AQ|LD1), LW + LO_CMUX, LOGICIN20, LW + (LI_CI|LD1)},
};
rc = mip_to_bitpos(*bitpos, num_bitpos, MAX_SWITCHBOX_SIZE,
12, 3, 2, 3, 3, &logicin_src);
if (rc) FAIL(rc);
logicin_src[1][0] = logicin_src[3][0] = logicin_src[5][0] = logicin_src[7][0] = VCC_WIRE;
logicin_src[0][0] = logicin_src[2][0] = GFAN1;
logicin_src[4][0] = logicin_src[6][0] = GFAN0;
rc = mip_to_bitpos(*bitpos, num_bitpos, MAX_SWITCHBOX_SIZE,
14, 3, 3, 3, 2, &logicin_src);
if (rc) FAIL(rc);
}
{ int logicin_src[8][6] = {
{ LW + LI_BX, LOGICIN52 },
{ LW + LI_BX, LOGICIN52 },
{ LW + LI_BX, LW + (LI_DI|LD1) },
{ LW + LI_BX, LW + (LI_DI|LD1) },
{ LW + (LI_DI|LD1), LOGICIN_N28 },
{ LW + (LI_DI|LD1), LOGICIN_N28 },
{ LOGICIN_N52, LOGICIN_N28 },
{ LOGICIN_N52, LOGICIN_N28 }};
rc = mip_to_bitpos(*bitpos, num_bitpos, MAX_SWITCHBOX_SIZE,
12, 1, 2, 1, 3, &logicin_src);
if (rc) FAIL(rc);
rc = mip_to_bitpos(*bitpos, num_bitpos, MAX_SWITCHBOX_SIZE,
14, 2, 3, 2, 2, &logicin_src);
if (rc) FAIL(rc);
}
// mip16-18
{ int logicin_src[8][6] = {
{VCC_WIRE, LW + LO_D, LW + (LO_DQ|LD1), LW + LO_BMUX, LOGICIN_S36, LOGICIN_S44},
{GFAN1, LW + LO_D, LW + (LO_DQ|LD1), LW + LO_BMUX, LOGICIN_S36, LOGICIN_S44},
{VCC_WIRE, LW + (LO_C|LD1), LW + LO_CQ, LW + (LO_AMUX|LD1), LOGICIN_S36, LW + LI_AX},
{GFAN1, LW + (LO_C|LD1), LW + LO_CQ, LW + (LO_AMUX|LD1), LOGICIN_S36, LW + LI_AX},
{VCC_WIRE, LW + LO_B, LW + (LO_BQ|LD1), LW + LO_DMUX, LW + LI_AX, LW + (LI_CE|LD1)},
{GFAN0, LW + LO_B, LW + (LO_BQ|LD1), LW + LO_DMUX, LW + LI_AX, LW + (LI_CE|LD1)},
{VCC_WIRE, LW + (LO_A|LD1), LW + LO_AQ, LW + (LO_CMUX|LD1), LOGICIN44, LW + (LI_CE|LD1)},
{GFAN0, LW + (LO_A|LD1), LW + LO_AQ, LW + (LO_CMUX|LD1), LOGICIN44, LW + (LI_CE|LD1)},
};
rc = mip_to_bitpos(*bitpos, num_bitpos, MAX_SWITCHBOX_SIZE,
16, 3, 2, 3, 3, &logicin_src);
if (rc) FAIL(rc);
logicin_src[1][0] = logicin_src[3][0] = logicin_src[5][0] = logicin_src[7][0] = VCC_WIRE;
logicin_src[0][0] = logicin_src[2][0] = GFAN1;
logicin_src[4][0] = logicin_src[6][0] = GFAN0;
rc = mip_to_bitpos(*bitpos, num_bitpos, MAX_SWITCHBOX_SIZE,
18, 3, 3, 3, 2, &logicin_src);
if (rc) FAIL(rc);
}
{ int logicin_src[8][6] = {
{ LW + (LI_BX|LD1), LOGICIN21 },
{ LW + (LI_BX|LD1), LOGICIN21 },
{ LW + (LI_BX|LD1), FAN_B },
{ LW + (LI_BX|LD1), FAN_B },
{ FAN_B, LOGICIN_N60 },
{ FAN_B, LOGICIN_N60 },
{ LOGICIN_N21, LOGICIN_N60 },
{ LOGICIN_N21, LOGICIN_N60 }};
rc = mip_to_bitpos(*bitpos, num_bitpos, MAX_SWITCHBOX_SIZE,
16, 1, 2, 1, 3, &logicin_src);
if (rc) FAIL(rc);
rc = mip_to_bitpos(*bitpos, num_bitpos, MAX_SWITCHBOX_SIZE,
18, 2, 3, 2, 2, &logicin_src);
if (rc) FAIL(rc);
}
// minor 20 switches (SR, CLK, GFAN = 113 switches (4 bidir added on other side))
{ const struct sw_mip_src src[] = {
{20, SR1, 6, 3, 0, .from_w =
{GCLK11, GCLK10, GCLK13, GCLK12, GCLK9, GCLK8}},
{20, SR1, 6, 2, 0, .from_w =
{DW+W_WR1*4+2, DW+W_NR1*4+2, VCC_WIRE, GND_WIRE, DW+W_ER1*4+2, DW+W_SR1*4+2}},
{20, SR1, 6, 1, 0, .from_w =
{FAN_B, LW+(LI_DI|LD1), LW+(LI_BX|LD1), LW+LI_BX, GCLK15, GCLK14}},
{20, SR0, 8, 3, 10, .from_w =
{GCLK8, GCLK9, GCLK10, GCLK13, GCLK12, GCLK11}},
{20, SR0, 8, 2, 10, .from_w =
{GCLK14, GCLK15, LW+(LI_DI|LD1), LW+(LI_BX|LD1), LW+LI_BX, FAN_B}},
{20, SR0, 8, 1, 10, .from_w = {DW+W_SR1*4+2, DW+W_ER1*4+2, DW+W_NR1*4+2,
VCC_WIRE, NO_WIRE, DW+W_WR1*4+2}},
{20, CLK0, 16, 3, 18, .from_w =
{GCLK0, GCLK1, GCLK2, GCLK5, GCLK4, GCLK3}},
{20, CLK0, 16, 2, 18, .from_w =
{GCLK6, GCLK7, GCLK8, GCLK11, GCLK10, GCLK9}},
{20, CLK0, 16, 1, 18, .from_w =
{GCLK12, GCLK13, GCLK14, LW+(LI_BX|LD1), LW+(LI_CI|LD1), GCLK15}},
{20, CLK0, 16, 0, 18, .from_w =
{DW+W_NR1*4+2, DW+W_WR1*4+2, DW+W_SR1*4+1, VCC_WIRE, NO_WIRE, DW+W_ER1*4+1}},
{20, CLK1, 46, 3, 40, .from_w =
{GCLK3, GCLK2, GCLK5, GCLK4, GCLK1, GCLK0}},
{20, CLK1, 46, 2, 40, .from_w =
{GCLK15, GCLK14, LW+(LI_BX|LD1), LW+(LI_CI|LD1), GCLK13, GCLK12}},
{20, CLK1, 46, 1, 40, .from_w =
{GCLK9, GCLK8, GCLK11, GCLK10, GCLK7, GCLK6}},
{20, CLK1, 46, 0, 40, .from_w =
{DW+W_ER1*4+1, DW+W_SR1*4+1, VCC_WIRE, NO_WIRE, DW+W_WR1*4+2, DW+W_NR1*4+2}},
{20, GFAN0, 54, 3, 48, .from_w =
{GCLK3, GCLK4, GCLK5, GCLK2, GCLK1, GCLK0}},
{20, GFAN0, 54, 2, 48, .from_w =
{DW+W_WR1*4+1, GND_WIRE, VCC_WIRE, DW+W_NR1*4+1, DW+W_ER1*4+1, DW+W_SR1*4+1}},
{20, GFAN0, 54, 1, 48, .from_w =
{LW+(LI_CE|LD1), NO_WIRE, NO_WIRE, LW+(LI_CI|LD1), GCLK7, GCLK6}},
{20, GFAN1, 56, 3, 58, .from_w =
{GCLK0, GCLK1, GCLK4, GCLK5, GCLK2, GCLK3}},
{20, GFAN1, 56, 2, 58, .from_w =
{GCLK6, GCLK7, LW+(LI_AX|LD1), LW+LI_AX, NO_WIRE, NO_WIRE}},
{20, GFAN1, 56, 1, 58, .from_w =
{DW+W_SR1*4+1, DW+W_ER1*4+1, GND_WIRE, VCC_WIRE, DW+W_NR1*4+1, DW+W_WR1*4+1}}};
for (i = 0; i < sizeof(src)/sizeof(*src); i++) {
for (j = 0; j < sizeof(src[0].from_w)/sizeof(src[0].from_w[0]); j++) {
if (src[i].from_w[j] == NO_WIRE) continue;
if (*num_bitpos >= MAX_SWITCHBOX_SIZE) FAIL(EINVAL);
(*bitpos)[*num_bitpos].from = src[i].from_w[j];
(*bitpos)[*num_bitpos].to = src[i].m0_sw_to;
(*bitpos)[*num_bitpos].bidir = 0;
(*bitpos)[*num_bitpos].minor = 20;
(*bitpos)[*num_bitpos].two_bits_o = src[i].m0_two_bits_o;
(*bitpos)[*num_bitpos].two_bits_val = src[i].m0_two_bits_val;
(*bitpos)[*num_bitpos].one_bit_o = src[i].m0_one_bit_start + j;
(*num_bitpos)++;
}
}}
return 0;
fail:
return rc;
}
void free_xc6_routing_bitpos(struct xc6_routing_bitpos* bitpos)
{
free(bitpos);
}
void xc6_lut_bitmap(int lut_pos, int (*map)[64], int num_bits)
{
static const int xc6_lut_wiring[4][16] = {
// xm-m a; xm-m c;
{ 17, 19, 16, 18, 23, 21, 22, 20, 31, 29, 30, 28, 25, 27, 24, 26 },
// xm-m b; xm-m d;
{ 47, 45, 46, 44, 41, 43, 40, 42, 33, 35, 32, 34, 39, 37, 38, 36 },
// xm-x a; xm-x b; xl-l b; xl-l d; xl-x a; xl-x b;
{ 31, 29, 30, 28, 27, 25, 26, 24, 19, 17, 18, 16, 23, 21, 22, 20 },
// xm-x c; xm-x d; xl-l a; xl-l c; xl-x c; xl-x d;
{ 33, 35, 32, 34, 37, 39, 36, 38, 45, 47, 44, 46, 41, 43, 40, 42 }};
int map32[32];
int i;
// expand from 16 to 32 bit positions
for (i = 0; i < 16; i++) {
map32[i] = xc6_lut_wiring[lut_pos][i];
if (map32[i] < 32) {
if (map32[i] < 16) HERE();
map32[16+i] = map32[i]-16;
} else {
if (map32[i] > 47) HERE();
map32[16+i] = map32[i]+16;
}
}
// expand from 32 to 64 for either lut6 only or lut5/lut6 pair.
for (i = 0; i < 32; i++) {
if (num_bits == 32) {
if (lut_pos == XC6_LMAP_XM_M_A
|| lut_pos == XC6_LMAP_XM_M_C
|| lut_pos == XC6_LMAP_XM_X_A
|| lut_pos == XC6_LMAP_XM_X_B
|| lut_pos == XC6_LMAP_XL_L_B
|| lut_pos == XC6_LMAP_XL_L_D
|| lut_pos == XC6_LMAP_XL_X_A
|| lut_pos == XC6_LMAP_XL_X_B) {
(*map)[i] = map32[i]%32;
(*map)[32+i] = 32+(map32[i]%32);
} else {
(*map)[i] = 32+(map32[i]%32);
(*map)[32+i] = map32[i]%32;
}
} else {
if (num_bits != 64) HERE();
(*map)[i] = map32[i];
(*map)[32+i] = ((*map)[i]+32)%64;
}
}
}
fpgatools-201212/libs/parts.h 0000664 0000000 0000000 00000034617 12065743015 0016052 0 ustar 00root root 0000000 0000000 //
// Author: Wolfgang Spraul
//
// This is free and unencumbered software released into the public domain.
// For details see the UNLICENSE file at the root of the source tree.
//
// The highest 4 bits are the binary revision and not
// used when performing IDCODE verification.
// ug380, Configuration Sequence, page 78
#define IDCODE_MASK 0x0FFFFFFF
#define XC6SLX4 0x04000093
#define XC6SLX9 0x04001093
#define XC6SLX16 0x04002093
#define XC6SLX25 0x04004093
#define XC6SLX25T 0x04024093
#define XC6SLX45 0x04008093
#define XC6SLX45T 0x04028093
#define XC6SLX75 0x0400E093
#define XC6SLX75T 0x0402E093
#define XC6SLX100 0x04011093
#define XC6SLX100T 0x04031093
#define XC6SLX150 0x0401D093
#define XC_MAX_MAJORS 400
#define XC_MAX_TYPE2_ENTRIES 2000
#define XC_MAX_MUI_POS 32
#define XC_MAJ_ZERO 0x00000001
#define XC_MAJ_LEFT 0x00000002
#define XC_MAJ_CENTER 0x00000004
#define XC_MAJ_RIGHT 0x00000008
#define XC_MAJ_XM 0x00000010
#define XC_MAJ_XL 0x00000020
#define XC_MAJ_BRAM 0x00000040
#define XC_MAJ_MACC 0x00000080
#define XC_MAJ_TOP_BOT_IO 0x00000100
#define XC_MAJ_GCLK_SEP 0x00000200
struct xc_major_info
{
int flags;
int minors;
};
#define XC_T2_IOB_PAD 0x00000001
#define XC_T2_IOB_UNBONDED 0x00000002
#define XC_T2_CENTER 0x00000004
struct xc_type2_info
{
int flags;
int val;
};
//
// major_str
// 'L' = X+L logic block
// 'M' = X+M logic block
// 'B' = block ram
// 'D' = dsp (macc)
// 'R' = registers and center IO/logic column
//
// 'n' = noio - can follow L or M to designate a logic
// column without IO at top or bottom
// 'g' = gclk - can follow LlMmBD to designate exactly one
// place on the left and right side of the chip where
// the global clock is separated into left and right
// half (on each side of the chip, for a total of 4
// vertical clock separations).
// left_wiring and right_wiring are described with 16
// characters for each row, order is top-down
// 'W' = wired
// 'U' = unwired
//
struct xc_die
{
int idcode;
int num_rows;
const char* left_wiring;
const char* right_wiring;
const char* major_str;
int num_majors;
struct xc_major_info majors[XC_MAX_MAJORS];
int num_type2;
struct xc_type2_info type2[XC_MAX_TYPE2_ENTRIES];
int mcb_ypos;
int num_mui;
int mui_pos[XC_MAX_MUI_POS];
int sel_logicin[16];
};
const struct xc_die* xc_die_info(int idcode);
int xc_die_center_major(const struct xc_die *die);
enum xc6_pkg { TQG144, FTG256, CSG324, FGG484 };
#define XC6_NUM_GCLK_PINS 32
struct xc6_pkg_info
{
enum xc6_pkg pkg;
int num_gclk_pins;
// negative side of differential pairs: even numbers
// positive side of differential pairs: odd numbers
const char* gclk_pin[XC6_NUM_GCLK_PINS];
int gclk_type2_o[XC6_NUM_GCLK_PINS]; // in words
};
const struct xc6_pkg_info *xc6_pkg_info(enum xc6_pkg pkg);
#define FRAME_SIZE 130
#define FRAMES_PER_ROW 505 // for slx4 and slx9
#define PADDING_FRAMES_PER_ROW 2
#define NUM_ROWS 4 // for slx9 and slx9
#define FRAMES_DATA_START 0
#define FRAMES_DATA_LEN (NUM_ROWS*FRAMES_PER_ROW*FRAME_SIZE)
#define BRAM_DATA_START FRAMES_DATA_LEN
#define BRAM_DATA_LEN (4*144*FRAME_SIZE)
#define IOB_DATA_START (BRAM_DATA_START + BRAM_DATA_LEN)
#define IOB_WORDS 896 // 16-bit words, for slx4 and slx9
#define IOB_DATA_LEN (IOB_WORDS*2)
#define IOB_ENTRY_LEN 8
#define BITS_LEN (IOB_DATA_START+IOB_DATA_LEN)
#define XC6_WORD_BYTES 2
#define XC6_WORD_BITS (XC6_WORD_BYTES*8)
#define XC6_HCLK_POS 64
#define XC6_HCLK_BYTES 2
#define XC6_HCLK_BITS (XC6_HCLK_BYTES*8)
#define XC6_HCLK_GCLK_UP_PIN 0
#define XC6_HCLK_GCLK_DOWN_PIN 1
#define XC6_NULL_MAJOR 0
#define XC6_IOB_MASK_IO 0x00FF00FFFF000000
#define XC6_IOB_MASK_IN_TYPE 0x000000000000F000
#define XC6_IOB_MASK_SLEW 0x0000000000FF0000
#define XC6_IOB_MASK_SUSPEND 0x000000000000001F
#define XC6_IOB_INSTANTIATED 0x0000000000000080
#define XC6_IOB_INPUT 0x00D0002400000000
#define XC6_IOB_INPUT_LVCMOS33_25_LVTTL 0x000000000000E000
#define XC6_IOB_INPUT_LVCMOS18_15_12 0x000000000000C000
#define XC6_IOB_INPUT_LVCMOS18_15_12_JEDEC 0x0000000000002000
#define XC6_IOB_INPUT_SSTL2_I 0x000000000000B000
#define XC6_IOB_OUTPUT_LVCMOS33_25_DRIVE_2 0x001000B400000000
#define XC6_IOB_OUTPUT_LVCMOS33_DRIVE_4 0x0070006C00000000
#define XC6_IOB_OUTPUT_LVCMOS33_DRIVE_6 0x003000FC00000000
#define XC6_IOB_OUTPUT_LVCMOS33_DRIVE_8 0x0040000000000000
#define XC6_IOB_OUTPUT_LVCMOS33_DRIVE_12 0x0060008800000000
#define XC6_IOB_OUTPUT_LVCMOS33_DRIVE_16 0x009800C600000000
#define XC6_IOB_OUTPUT_LVCMOS33_DRIVE_24 0x0088007200000000
#define XC6_IOB_OUTPUT_LVCMOS25_DRIVE_4 0x00B0006C00000000
#define XC6_IOB_OUTPUT_LVCMOS25_DRIVE_6 0x004000FC00000000
#define XC6_IOB_OUTPUT_LVCMOS25_DRIVE_8 0x0000000000000000
#define XC6_IOB_OUTPUT_LVCMOS25_DRIVE_12 0x0058008800000000
#define XC6_IOB_OUTPUT_LVCMOS25_DRIVE_16 0x00B800C600000000
#define XC6_IOB_OUTPUT_LVCMOS25_DRIVE_24 0x0054007200000000
#define XC6_IOB_OUTPUT_LVTTL_DRIVE_2 0x009000B400000000
#define XC6_IOB_OUTPUT_LVTTL_DRIVE_4 0x00F0006C00000000
#define XC6_IOB_OUTPUT_LVTTL_DRIVE_6 0x007000FC00000000
#define XC6_IOB_OUTPUT_LVTTL_DRIVE_8 0x0030000000000000
#define XC6_IOB_OUTPUT_LVTTL_DRIVE_12 0x0080008800000000
#define XC6_IOB_OUTPUT_LVTTL_DRIVE_16 0x006000C600000000
#define XC6_IOB_OUTPUT_LVTTL_DRIVE_24 0x0018007200000000
#define XC6_IOB_OUTPUT_LVCMOS18_DRIVE_2 0x00F000B402000000
#define XC6_IOB_OUTPUT_LVCMOS18_DRIVE_4 0x00C000AC02000000
#define XC6_IOB_OUTPUT_LVCMOS18_DRIVE_6 0x00E000BC02000000
#define XC6_IOB_OUTPUT_LVCMOS18_DRIVE_8 0x00D800A002000000
#define XC6_IOB_OUTPUT_LVCMOS18_DRIVE_12 0x003800A802000000
#define XC6_IOB_OUTPUT_LVCMOS18_DRIVE_16 0x002800A602000000
#define XC6_IOB_OUTPUT_LVCMOS18_DRIVE_24 0x00A400A202000000
#define XC6_IOB_OUTPUT_LVCMOS15_DRIVE_2 0x00B0007402000000
#define XC6_IOB_OUTPUT_LVCMOS15_DRIVE_4 0x00E0000C02000000
#define XC6_IOB_OUTPUT_LVCMOS15_DRIVE_6 0x0098005C02000000
#define XC6_IOB_OUTPUT_LVCMOS15_DRIVE_8 0x00C8003002000000
#define XC6_IOB_OUTPUT_LVCMOS15_DRIVE_12 0x00F4001802000000
#define XC6_IOB_OUTPUT_LVCMOS15_DRIVE_16 0x002400D602000000
#define XC6_IOB_OUTPUT_LVCMOS12_DRIVE_2 0x004000B402000000
#define XC6_IOB_OUTPUT_LVCMOS12_DRIVE_4 0x0098006C02000000
#define XC6_IOB_OUTPUT_LVCMOS12_DRIVE_6 0x008800FC02000000
#define XC6_IOB_OUTPUT_LVCMOS12_DRIVE_8 0x0014000002000000
#define XC6_IOB_OUTPUT_LVCMOS12_DRIVE_12 0x00FC008802000000
#define XC6_IOB_OUTPUT_SSTL2_I 0x0040001C00000000
#define XC6_IOB_IMUX_I_B 0x0000000000000400
#define XC6_IOB_O_PINW 0x0000000000000100
#define XC6_IOB_SLEW_SLOW 0x0000000000000000
#define XC6_IOB_SLEW_FAST 0x0000000000330000
#define XC6_IOB_SLEW_QUIETIO 0x0000000000660000
#define XC6_IOB_SUSP_3STATE 0x0000000000000000
#define XC6_IOB_SUSP_3STATE_OCT_ON 0x0000000000000001
#define XC6_IOB_SUSP_3STATE_KEEPER 0x0000000000000002
#define XC6_IOB_SUSP_3STATE_PULLUP 0x0000000000000004
#define XC6_IOB_SUSP_3STATE_PULLDOWN 0x0000000000000008
#define XC6_IOB_SUSP_LAST_VAL 0x0000000000000010
int get_major_minors(int idcode, int major);
enum major_type { MAJ_ZERO, MAJ_LEFT, MAJ_RIGHT, MAJ_CENTER,
MAJ_LOGIC_XM, MAJ_LOGIC_XL, MAJ_BRAM, MAJ_MACC };
enum major_type get_major_type(int idcode, int major);
#define XC6_ZERO_MAJOR 0
#define XC6_LEFTSIDE_MAJOR 1
#define XC6_SLX9_RIGHTMOST_MAJOR 17
int get_rightside_major(int idcode);
int get_major_framestart(int idcode, int major);
int get_frames_per_row(int idcode);
int get_num_iobs(int idcode);
const char* get_iob_sitename(int idcode, int idx);
// returns -1 if sitename not found
int find_iob_sitename(int idcode, const char* name);
int xc_num_rows(int idcode);
// The routing bitpos is relative to a tile, i.e. major (x)
// and row/v64_i (y) are defined outside.
struct xc6_routing_bitpos
{
// from and to are enum extra_wires values from model.h
int from;
int to;
int bidir;
// minors 0-19 are minor pairs, minor will be set
// to the even beginning of the pair, two_bits_o and
// one_bit_o are within 2*64 bits of the two minors.
// Even bit offsets are from the first minor, odd bit
// offsets from the second minor.
// minor 20 is a regular single 64-bit minor.
int minor; // 0,2,4,..18 for pairs, 20 for single-minor
int two_bits_o; // 0-126 for pairs (even only), 0-62 for single-minor
int two_bits_val; // 0-3
int one_bit_o; // 1-6 positions up or down from two-bit pos
};
int get_xc6_routing_bitpos(struct xc6_routing_bitpos** bitpos, int* num_bitpos);
void free_xc6_routing_bitpos(struct xc6_routing_bitpos* bitpos);
#define XC6_LMAP_XM_M_A 0
#define XC6_LMAP_XM_M_B 1
#define XC6_LMAP_XM_M_C 0
#define XC6_LMAP_XM_M_D 1
#define XC6_LMAP_XM_X_A 2
#define XC6_LMAP_XM_X_B 2
#define XC6_LMAP_XM_X_C 3
#define XC6_LMAP_XM_X_D 3
#define XC6_LMAP_XL_L_A 3
#define XC6_LMAP_XL_L_B 2
#define XC6_LMAP_XL_L_C 3
#define XC6_LMAP_XL_L_D 2
#define XC6_LMAP_XL_X_A 2
#define XC6_LMAP_XL_X_B 2
#define XC6_LMAP_XL_X_C 3
#define XC6_LMAP_XL_X_D 3
// num_bits must be 32 or 64. If it is 32, the lower
// 32 entries of map contain the bit positions for lut5,
// the upper 32 entries of map the ones for lut6.
// In either case 64 entries are written to map.
void xc6_lut_bitmap(int lut_pos, int (*map)[64], int num_bits);
//
// logic configuration
//
//
// Some things noteworthy for *not* having bits set:
// cout_used, a_used-d_used, srinit=0, non-inverted clock,
// async attribute, precyinit=0, ffmux=O6, cy0=X, enabling
// 5Q-ff in X devices
//
// All offsets into vertical range of 64 bits per logic row.
//
// minor 20 (only bits 24-39 for logic config, 0-23 and 40-63
// are for routing switches):
#define XC6_MI20_LOGIC_MASK 0x000000FFFF000000ULL
#define XC6_ML_D5_FFSRINIT_1 24
#define XC6_X_D5_FFSRINIT_1 25
#define XC6_ML_C5_FFSRINIT_1 29
#define XC6_X_C_FFSRINIT_1 30
#define XC6_X_C5_FFSRINIT_1 31
#define XC6_ML_B5_FFSRINIT_1 32
#define XC6_X_B5_FFSRINIT_1 34
#define XC6_M_A_FFSRINIT_1 37 // M-device only
#define XC6_X_A5_FFSRINIT_1 38
#define XC6_ML_A5_FFSRINIT_1 39
// minor 26 in XM, 25 in XL columns:
// ML_D_CY0=DX -
#define XC6_ML_D_CY0_O5 0 // implies lut5 on ML-D
// X_D_OUTMUX=5Q - // implies lut5 on X-D
#define XC6_X_D_OUTMUX_O5 1 // default-set, does not imply lut5
// X_C_OUTMUX=5Q - // implies lut5 on X-C
#define XC6_X_C_OUTMUX_O5 2 // default-set, does not imply lut5
#define XC6_ML_D_FFSRINIT_1 3
#define XC6_ML_C_FFSRINIT_1 4
#define XC6_X_D_FFSRINIT_1 5
// ML_C_CY0=CX -
#define XC6_ML_C_CY0_O5 6 // implies lut5 on ML-C
// X_B_OUTMUX=5Q - // implies lut5 on X-B
#define XC6_X_B_OUTMUX_O5 7 // default-set, does not imply lut5
#define XC6_ML_D_OUTMUX_MASK 0x0000000000000F00ULL
#define XC6_ML_D_OUTMUX_O 8
#define XC6_ML_D_OUTMUX_O6 1ULL // 0001
#define XC6_ML_D_OUTMUX_XOR 2ULL // 0010
#define XC6_ML_D_OUTMUX_O5 5ULL // 0101, implies lut5 on ML-D
#define XC6_ML_D_OUTMUX_CY 6ULL // 0110
#define XC6_ML_D_OUTMUX_5Q 8ULL // 1000, implies lut5 on ML-D
#define XC6_ML_D_FFMUX_MASK 0x000000000000F000ULL
#define XC6_ML_D_FFMUX_O 12
#define XC6_ML_D_FFMUX_O6 0ULL // 0000
#define XC6_ML_D_FFMUX_O5 1ULL // 0001, implies lut5 on ML-D
#define XC6_ML_D_FFMUX_X 10ULL // 1010
#define XC6_ML_D_FFMUX_XOR 12ULL // 1100
#define XC6_ML_D_FFMUX_CY 13ULL // 1101
#define XC6_X_CLK_B 16
#define XC6_ML_ALL_LATCH 17
#define XC6_ML_SR_USED 18
#define XC6_ML_SYNC 19
#define XC6_ML_CE_USED 20
// X_D_FFMUX=O6 -
#define XC6_X_D_FFMUX_X 21 // default-set, does not imply lut5
// X_C_FFMUX=O6 -
#define XC6_X_C_FFMUX_X 22 // default-set, does not imply lut5
#define XC6_X_CE_USED 23
#define XC6_ML_C_OUTMUX_MASK 0x000000000F000000ULL
#define XC6_ML_C_OUTMUX_O 24
#define XC6_ML_C_OUTMUX_XOR 1ULL // 0001
#define XC6_ML_C_OUTMUX_O6 2ULL // 0010
#define XC6_ML_C_OUTMUX_5Q 4ULL // 0100, implies lut5 on ML-C
#define XC6_ML_C_OUTMUX_CY 9ULL // 1001
#define XC6_ML_C_OUTMUX_O5 10ULL // 1010, implies lut5 on ML-C
#define XC6_ML_C_OUTMUX_F7 12ULL // 1100
#define XC6_ML_C_FFMUX_MASK 0x00000000F0000000ULL
#define XC6_ML_C_FFMUX_O 28
#define XC6_ML_C_FFMUX_O6 0ULL // 0000
#define XC6_ML_C_FFMUX_O5 2ULL // 0010, implies lut5 on ML-C
#define XC6_ML_C_FFMUX_X 5ULL // 0101
#define XC6_ML_C_FFMUX_F7 7ULL // 0111
#define XC6_ML_C_FFMUX_XOR 12ULL // 1100
#define XC6_ML_C_FFMUX_CY 14ULL // 1110
#define XC6_ML_B_OUTMUX_MASK 0x0000000F00000000ULL
#define XC6_ML_B_OUTMUX_O 32
#define XC6_ML_B_OUTMUX_5Q 2ULL // 0010, implies lut5 on ML-B
#define XC6_ML_B_OUTMUX_F8 3ULL // 0011
#define XC6_ML_B_OUTMUX_XOR 4ULL // 0100
#define XC6_ML_B_OUTMUX_CY 5ULL // 0101
#define XC6_ML_B_OUTMUX_O6 8ULL // 1000
#define XC6_ML_B_OUTMUX_O5 9ULL // 1001, implies lut5 on ML-B
// X_B_FFMUX=O6 -
#define XC6_X_B_FFMUX_X 36 // default-set, does not imply lut5
// X_A_FFMUX=O6 -
#define XC6_X_A_FFMUX_X 37 // default-set, does not imply lut5
#define XC6_X_B_FFSRINIT_1 38
// X_A_OUTMUX=5Q - // implies lut5 on X-A
#define XC6_X_A_OUTMUX_O5 39 // default-set, does not imply lut5
#define XC6_X_SR_USED 40
#define XC6_X_SYNC 41
#define XC6_X_ALL_LATCH 42
#define XC6_ML_CLK_B 43
#define XC6_ML_B_FFMUX_MASK 0x0000F00000000000ULL
#define XC6_ML_B_FFMUX_O 44
#define XC6_ML_B_FFMUX_O6 0ULL // 0000
#define XC6_ML_B_FFMUX_XOR 3ULL // 0011
#define XC6_ML_B_FFMUX_O5 4ULL // 0100, implies lut5 on ML-B
#define XC6_ML_B_FFMUX_CY 7ULL // 0111
#define XC6_ML_B_FFMUX_X 10ULL // 1010
#define XC6_ML_B_FFMUX_F8 14ULL // 1110
#define XC6_ML_A_FFMUX_MASK 0x000F000000000000ULL
#define XC6_ML_A_FFMUX_O 48
#define XC6_ML_A_FFMUX_O6 0ULL // 0000
#define XC6_ML_A_FFMUX_XOR 3ULL // 0011
#define XC6_ML_A_FFMUX_X 5ULL // 0101
#define XC6_ML_A_FFMUX_O5 8ULL // 1000, implies lut5 on ML-A
#define XC6_ML_A_FFMUX_CY 11ULL // 1011
#define XC6_ML_A_FFMUX_F7 13ULL // 1101
#define XC6_ML_A_OUTMUX_MASK 0x00F0000000000000ULL
#define XC6_ML_A_OUTMUX_O 52
#define XC6_ML_A_OUTMUX_5Q 1ULL // 0001, implies lut5 on ML-A
#define XC6_ML_A_OUTMUX_F7 3ULL // 0011
#define XC6_ML_A_OUTMUX_XOR 4ULL // 0100
#define XC6_ML_A_OUTMUX_CY 6ULL // 0110
#define XC6_ML_A_OUTMUX_O6 8ULL // 1000
#define XC6_ML_A_OUTMUX_O5 10ULL // 1010, implies lut5 on ML-A
// ML_B_CY0=BX -
#define XC6_ML_B_CY0_O5 56 // implies lut5 on ML-B
#define XC6_ML_PRECYINIT_AX 57
#define XC6_X_A_FFSRINIT_1 58
// CIN_USED best corresponds to the cout->cout_n switch in the
// next lower logic device (y+1).
#define XC6_ML_CIN_USED 59
// ML_PRECYINIT=0 -
#define XC6_ML_PRECYINIT_1 60
#define XC6_ML_B_FFSRINIT_1 61
// ML_A_CY0=AX -
#define XC6_ML_A_CY0_O5 62 // implies lut5 on ML-A
#define XC6_L_A_FFSRINIT_1 63 // L-device only
#define XC6_TYPE2_GCLK_REG_SW 2 // bit 2 in 1st word
#define XC6_CENTER_GCLK_MINOR 25
fpgatools-201212/lut.svg 0000664 0000000 0000000 00000024730 12065743015 0015137 0 ustar 00root root 0000000 0000000
A5
A6
A4
A3
A2
A1
MAJ
MAJ+1
A1
A1
A2
A2
A3
A3
A4
A4
b0
b1
b2
b3
b4
b5
b6
b7
b8
b9
b10
b11
b12
b13
b14
b15
b16
b17
b18
b19
b20
b21
b22
b23
b24
b25
b26
b27
b28
b29
b30
b31
b0
b1
b2
b3
b4
b5
b6
b7
b8
b9
b10
b11
b12
b13
b14
b15
b16
b17
b18
b19
b20
b21
b22
b23
b24
b25
b26
b27
b28
b29
b30
b31
A5
A5
A5
A5
A6
A6
fpgatools-201212/merge_log.sh 0000775 0000000 0000000 00000000164 12065743015 0016104 0 ustar 00root root 0000000 0000000 #!/usr/bin/env bash
grep '^+net\|^+r0.*v64_'|awk '/^+r0.*v64_/{if (x~/^+net/) printf "%s %s\n",$0,x};{x=$0};'|sort
fpgatools-201212/merge_seq.c 0000664 0000000 0000000 00000025760 12065743015 0015731 0 ustar 00root root 0000000 0000000 //
// Author: Wolfgang Spraul
//
// This is free and unencumbered software released into the public domain.
// For details see the UNLICENSE file at the root of the source tree.
//
#include
#include
#include
#include "helper.h"
#define LINE_LENGTH 1024
struct line_buf
{
// buf[0] == 0 signals 'no line'
char buf[LINE_LENGTH];
// left_digit_start_o and right_digit_start_o will be -1
// if left/right is not initialized.
int left_digit_start_o, left_digit_end_o, left_digit_base;
int right_digit_start_o, right_digit_end_o, right_digit_base;
// sequence_size == 0 means no sequence detected, 1 means
// two members in sequence (e.g. 0:1), etc.
int sequence_size;
};
static int print_line(const struct line_buf* line)
{
char buf[LINE_LENGTH];
if (!line->buf[0]) return 0;
if (!line->sequence_size || line->left_digit_start_o < 0) {
printf(line->buf);
return 0;
}
if (line->right_digit_start_o < 0)
snprintf(buf, sizeof(buf), "%.*s%i:%i%s",
line->left_digit_start_o,
line->buf,
line->left_digit_base,
line->left_digit_base+line->sequence_size,
&line->buf[line->left_digit_end_o]);
else
snprintf(buf, sizeof(buf), "%.*s%i:%i%.*s%i:%i%s",
line->left_digit_start_o,
line->buf,
line->left_digit_base,
line->left_digit_base+line->sequence_size,
line->right_digit_start_o-line->left_digit_end_o,
&line->buf[line->left_digit_end_o],
line->right_digit_base,
line->right_digit_base+line->sequence_size,
&line->buf[line->right_digit_end_o]);
printf(buf);
return 0;
}
// Finds the positions of two non-equal numbers that must meet
// the following two criteria:
// - prefixed by at least one capital 'A'-'Z' or '_'
// - suffixed by matching or empty strings
static void find_non_matching_number(const char* a, int a_len,
const char* b, int b_len, int* ab_start, int* a_end, int* b_end)
{
int a_o, b_o, digit_start, a_num, b_num;
*ab_start = -1;
a_o = 0;
// from the left side, search for the first non-matching
// character
while (a[a_o] == b[a_o] && a_o < a_len && a_o < b_len)
a_o++;
// if the strings match entirely, return
if (a_o >= a_len && a_o >= b_len) return;
// If neither of the non-matching characters is a digit, return
if ((a[a_o] < '0' || a[a_o] > '9')
&& (b[a_o] < '0' || b[a_o] > '9'))
return;
// go back to beginning of numeric section
// (first and second must be identical going backwards)
while (a_o && a[a_o-1] >= '0' && a[a_o-1] <= '9')
a_o--;
// If there is not at least one capital 'A'-'Z' or '_'
// before the number, return
if (!a_o
|| ((a[a_o-1] < 'A' || a[a_o-1] > 'Z')
&& a[a_o-1] != '_')) return;
// now skip over all digits in left and right string
digit_start = a_o;
while (a[a_o] >= '0' && a[a_o] <= '9' && a_o < a_len)
a_o++;
b_o = digit_start;
while (b[b_o] >= '0' && b[b_o] <= '9' && b_o < b_len)
b_o++;
// there must be at least one digit on each side
if (a_o <= digit_start || b_o <= digit_start) return;
a_num = to_i(&a[digit_start], a_o-digit_start);
b_num = to_i(&b[digit_start], b_o-digit_start);
if (a_num == b_num) {
fprintf(stderr, "Strange parsing issue with '%.*s' and '%.*s'\n", a_len, a, b_len, b);
return;
}
// the trailing part after the two numbers must match
if (a_len - a_o != b_len - b_o) return;
if ((a_len - a_o) && strncmp(&a[a_o], &b[b_o], a_len-a_o)) return;
// some known suffixes include numbers and must never be
// part of merging
if (a_len - a_o == 0) {
// _S0 _N3
if (a_o > 3
&& ((a[a_o-3] == '_' && a[a_o-2] == 'S' && a[a_o-1] == '0')
|| (a[a_o-3] == '_' && a[a_o-2] == 'N' && a[a_o-1] == '3')))
return;
// _INT0 _INT1 _INT2 _INT3
if (a_o > 5
&& a[a_o-5] == '_' && a[a_o-4] == 'I' && a[a_o-3] == 'N'
&& a[a_o-2] == 'T'
&& a[a_o-1] >= '0' && a[a_o-1] <= '3')
return;
}
*ab_start = digit_start;
*a_end = a_o;
*b_end = b_o;
}
static int merge_line(struct line_buf* first_l, struct line_buf* second_l)
{
int first_o, second_o, fs_start, f_end, s_end, first_num, second_num;
int first_eow, second_eow, f_start, s_start;
int left_start, left_end, left_num;
if (!first_l->buf[0] || !second_l->buf[0]) return 0;
// go through word by word, find first non-equal word
first_o = 0;
second_o = 0;
while (1) {
next_word(first_l->buf, first_o, &first_o, &first_eow);
next_word(second_l->buf, second_o, &second_o, &second_eow);
if (first_eow <= first_o || second_eow <= second_o) return 0;
if (first_eow-first_o != second_eow-second_o
|| strncmp(&first_l->buf[first_o], &second_l->buf[second_o], first_eow-first_o))
break;
first_o = first_eow;
second_o = second_eow;
}
// non-matching number inside?
fs_start = -1;
find_non_matching_number(&first_l->buf[first_o], first_eow-first_o,
&second_l->buf[second_o], second_eow-second_o,
&fs_start, &f_end, &s_end);
if (fs_start == -1) return 0; // no: cannot merge
f_start = first_o+fs_start;
f_end += first_o;
s_start = second_o+fs_start;
s_end += second_o;
first_o = first_eow;
second_o = second_eow;
// in sequence? if not, cannot merge
second_num = to_i(&second_l->buf[s_start], s_end-s_start);
if (first_l->sequence_size) {
if (first_l->left_digit_start_o < 0) {
fprintf(stderr, "Internal error in %s:%i\n", __FILE__, __LINE__);
return -1;
}
// We must be looking at the same digit, for example
// if we have a sequence SW2M0:3, and now the second
// line is SW4M0 - the '4' must not be seen as a
// continuation of the '3'.
if (s_start != first_l->left_digit_start_o)
return 0;
if (second_num != first_l->left_digit_base
+ first_l->sequence_size + 1)
return 0;
first_num = -1; // to suppress compiler warning
} else {
first_num = to_i(&first_l->buf[f_start], f_end-f_start);
if (second_num != first_num + 1)
return 0;
}
// find next non-equal word
while (1) {
next_word(first_l->buf, first_o, &first_o, &first_eow);
next_word(second_l->buf, second_o, &second_o, &second_eow);
if (first_eow <= first_o && second_eow <= second_o) {
// reached end of line
if (first_l->sequence_size) {
if (first_l->right_digit_start_o != -1) return 0;
first_l->sequence_size++;
} else {
first_l->left_digit_start_o = f_start;
first_l->left_digit_end_o = f_end;
first_l->left_digit_base = first_num;
first_l->right_digit_start_o = -1;
first_l->sequence_size = 1;
}
second_l->buf[0] = 0;
return 0;
}
if (first_eow <= first_o || second_eow <= second_o) return 0;
if (first_eow-first_o != second_eow-second_o
|| strncmp(&first_l->buf[first_o], &second_l->buf[second_o], first_eow-first_o))
break;
first_o = first_eow;
second_o = second_eow;
}
// now we must find a second number matching the sequence
left_start = f_start;
left_end = f_end;
left_num = first_num;
// non-matching number inside?
fs_start = -1;
find_non_matching_number(&first_l->buf[first_o], first_eow-first_o,
&second_l->buf[second_o], second_eow-second_o,
&fs_start, &f_end, &s_end);
if (fs_start == -1) return 0; // no: cannot merge
f_start = first_o+fs_start;
f_end += first_o;
s_start = second_o+fs_start;
s_end += second_o;
first_o = first_eow;
second_o = second_eow;
// in sequence? if not, cannot merge
second_num = to_i(&second_l->buf[s_start], s_end-s_start);
if (first_l->sequence_size) {
if (first_l->right_digit_start_o < 0
|| second_num != first_l->right_digit_base + first_l->sequence_size + 1)
return 0;
} else {
first_num = to_i(&first_l->buf[f_start], f_end-f_start);
if (second_num != first_num + 1)
return 0;
}
// find next non-equal word
while (1) {
next_word(first_l->buf, first_o, &first_o, &first_eow);
next_word(second_l->buf, second_o, &second_o, &second_eow);
if (first_eow <= first_o && second_eow <= second_o) {
// reached end of line
if (first_l->sequence_size)
first_l->sequence_size++;
else {
first_l->left_digit_start_o = left_start;
first_l->left_digit_end_o = left_end;
first_l->left_digit_base = left_num;
first_l->right_digit_start_o = f_start;
first_l->right_digit_end_o = f_end;
first_l->right_digit_base = first_num;
first_l->sequence_size = 1;
}
second_l->buf[0] = 0;
return 0;
}
if (first_eow <= first_o || second_eow <= second_o) return 0;
if (first_eow-first_o != second_eow-second_o
|| strncmp(&first_l->buf[first_o], &second_l->buf[second_o], first_eow-first_o))
break;
first_o = first_eow;
second_o = second_eow;
}
// found another non-matching word, cannot merge
return 0;
}
static void read_line(FILE* fp, struct line_buf* line)
{
*line->buf = 0;
line->left_digit_start_o = -1;
line->right_digit_start_o = -1;
line->sequence_size = 0;
if (!fgets(line->buf, sizeof(line->buf), fp))
*line->buf = 0;
}
static void increment(int *off, struct line_buf* lines, int num_lines, int end_of_ringbuf)
{
if (++(*off) >= num_lines)
*off = 0;
while (!lines[*off].buf[0] && *off != end_of_ringbuf) {
if (++(*off) >= num_lines)
*off = 0;
}
}
#define READ_AHEAD_SIZE 100
int main(int argc, char** argv)
{
struct line_buf read_ahead[READ_AHEAD_SIZE];
int read_ahead_get, read_ahead_put, second_line, eof_reached, try_count;
FILE* fp = 0;
int last_merge_try, rc = -1;
if (argc < 2) {
fprintf(stderr,
"merge_seq - merge sequence (needs presorted file)\n"
"Usage: %s | - for stdin [--try 2]\n", argv[0]);
goto xout;
}
if (!strcmp(argv[1], "-"))
fp = stdin;
else {
fp = fopen(argv[1], "r");
if (!fp) {
fprintf(stderr, "Error opening %s.\n", argv[1]);
goto xout;
}
}
// how far to look ahead for mergable sequences
if (argc >= 4 && !strcmp(argv[2], "--try"))
last_merge_try = atoi(argv[3]);
else
last_merge_try = 2;
read_line(fp, &read_ahead[0]);
if (!read_ahead[0].buf[0]) goto out;
read_ahead_get = 0;
read_ahead_put = 1;
eof_reached = 0;
while (1) {
// fill up read ahead buffer
while (!eof_reached
&& read_ahead_put != read_ahead_get) {
read_line(fp, &read_ahead[read_ahead_put]);
if (!read_ahead[read_ahead_put].buf[0]) {
eof_reached = 1;
break;
}
if (++read_ahead_put >= READ_AHEAD_SIZE)
read_ahead_put = 0;
}
// find second line in read ahead buffer
second_line = read_ahead_get;
increment(&second_line, read_ahead, READ_AHEAD_SIZE, read_ahead_put);
if (!read_ahead[second_line].buf[0]) {
// if no more lines, print first one and exit
rc = print_line(&read_ahead[read_ahead_get]);
if (rc) goto xout;
break;
}
try_count = 0;
while (1) {
// try to merge
rc = merge_line(&read_ahead[read_ahead_get], &read_ahead[second_line]);
if (rc) goto xout;
if (!read_ahead[second_line].buf[0]) // merge successful
break;
// try next one
increment(&second_line, read_ahead,
READ_AHEAD_SIZE, read_ahead_put);
if (second_line == read_ahead_put
|| ++try_count >= last_merge_try) {
// read-ahead empty or stop trying
rc = print_line(&read_ahead[read_ahead_get]);
if (rc) goto xout;
read_ahead[read_ahead_get].buf[0] = 0;
increment(&read_ahead_get, read_ahead,
READ_AHEAD_SIZE, read_ahead_put);
break;
}
}
}
out:
return EXIT_SUCCESS;
xout:
return rc;
}
fpgatools-201212/mini-jtag/ 0000775 0000000 0000000 00000000000 12065743015 0015463 5 ustar 00root root 0000000 0000000 fpgatools-201212/mini-jtag/Makefile 0000664 0000000 0000000 00000003773 12065743015 0017135 0 ustar 00root root 0000000 0000000 #
# Author: Xiangfu Liu
#
# This is free and unencumbered software released into the public domain.
# For details see the UNLICENSE file at the root of the source tree.
#
LDLIBS += `pkg-config libftdi --libs`
OBJS := mini-jtag.o load-bits.o jtag.o
.PHONY: all clean
.PHONY: install uninstall
.PHONY: test test-counter test-blinking test-hello_world
all: mini-jtag
include ../Makefile.common
mini-jtag: $(OBJS)
$(CC) $(LDFLAGS) -o $@ $(OBJS) $(LDLIBS)
%.o: %.c
$(CC) $(CPPFLAGS) $(CFLAGS) -o $@ -c $<
$(MKDEP)
install: all
mkdir -p $(DESTDIR)/$(PREFIX)/bin/
install -m 755 mini-jtag $(DESTDIR)/$(PREFIX)/bin/
uninstall:
rm -f $(DESTDIR)/$(PREFIX)/bin/mini-jtag
clean:
rm -f $(OBJS)
rm -f $(OBJS:.o=.d)
rm -f mini-jtag
%.bit:
@echo ""
@echo "Move the config bits file: <$@> here."
@echo ""
@exit 1
test: test-hello_world test-blinking test-counter
hello_world.bit:
make -C .. hello_world fp2bit
../hello_world | ../fp2bit - $@
test-hello_world: hello_world.bit mini-jtag
./mini-jtag load $<
sleep 2
blinking.bit:
make -C .. blinking_led fp2bit
../blinking_led | ../fp2bit - $@
test-blinking: blinking.bit mini-jtag
./mini-jtag load $<
sleep 2
test-counter: counter.bit mini-jtag
@./mini-jtag load $<
@echo "Read counter registers (1 ~ 5)"
@./mini-jtag read 0 # read version
@./mini-jtag read 1 # read counter EN
@./mini-jtag read 2 # read counter WE
@./mini-jtag read 3 # read counter_set
@./mini-jtag read 4 # read counter
@echo "Read counter"
@./mini-jtag write 1 1 # enable counter
@./mini-jtag read 4 # read counter
@./mini-jtag write 1 0 # disable counter
@echo "Set counter to 50000000"
@./mini-jtag write 2 1 # set counter WE
@./mini-jtag write 3 50000000 # set counter
@./mini-jtag read 3 # read counter_set
@./mini-jtag write 2 0 # set counter WE
@echo "Read counter"
@./mini-jtag write 1 1 # enable counter
@./mini-jtag read 4 # read counter
@echo "Sleep 1 second for count"
@sleep 1
@./mini-jtag read 4 # read counter
@./mini-jtag write 1 0 # disable counter
fpgatools-201212/mini-jtag/jtag.c 0000664 0000000 0000000 00000007352 12065743015 0016563 0 ustar 00root root 0000000 0000000 //
// Author: Xiangfu Liu
//
// This is free and unencumbered software released into the public domain.
// For details see the UNLICENSE file at the root of the source tree.
//
#include
#include
#include
#include
#include
#include
#include "jtag.h"
int tap_tms(struct ftdi_context *ftdi, int tms, uint8_t bit7)
{
uint8_t buf[3];
buf[0] = MPSSE_WRITE_TMS|MPSSE_LSB|MPSSE_BITMODE|MPSSE_WRITE_NEG;
buf[1] = 0; /* value = length - 1 */
buf[2] = (tms ? 0x01 : 0x00) | ((bit7 & 0x01) << 7);
if (ftdi_write_data(ftdi, buf, 3) != 3)
return -1;
return 0;
}
void tap_reset_rti(struct ftdi_context *ftdi)
{
int i;
for(i = 0; i < 5; i++)
tap_tms(ftdi, 1, 0);
tap_tms(ftdi, 0, 0); /* Goto RTI */
}
int tap_shift_ir_only(struct ftdi_context *ftdi, uint8_t ir)
{
int ret = 0;
uint8_t buf[3] = {0, 0, 0};
buf[0] = MPSSE_DO_WRITE|MPSSE_LSB|
MPSSE_BITMODE|MPSSE_WRITE_NEG;
buf[1] = 4;
buf[2] = ir;
if (ftdi_write_data(ftdi,buf, 3) != 3) {
fprintf(stderr, "Write loop failed\n");
ret = -1;
}
tap_tms(ftdi, 1, (ir >> 5));
return ret;
}
int tap_shift_ir(struct ftdi_context *ftdi, uint8_t ir)
{
int ret;
tap_tms(ftdi, 1, 0); /* RTI status */
tap_tms(ftdi, 1, 0);
tap_tms(ftdi, 0, 0);
tap_tms(ftdi, 0, 0); /* Goto shift IR */
ret = tap_shift_ir_only(ftdi, ir);
tap_tms(ftdi, 1, 0);
tap_tms(ftdi, 0, 0); /* Goto RTI */
return ret;
}
static int shift_last_bits(struct ftdi_context *ftdi,
uint8_t *in, uint8_t len, uint8_t *out)
{
uint8_t buf[3];
if (!len)
return -1;
buf[0] = MPSSE_LSB|MPSSE_BITMODE|MPSSE_WRITE_NEG;
if (in)
buf[0] |= MPSSE_DO_WRITE;
if (out)
buf[0] |= MPSSE_DO_READ;
buf[1] = len - 1;
if (in)
buf[2] = *in;
if (ftdi_write_data(ftdi, buf, 3) != 3) {
fprintf(stderr,
"Ftdi write failed\n");
return -1;
}
if (out)
ftdi_read_data(ftdi, out, 1);
return 0;
}
int tap_shift_dr_bits_only(struct ftdi_context *ftdi,
uint8_t *in, uint32_t in_bits,
uint8_t *out)
{
/* Have to be at RTI status before call this function */
uint8_t buf_bytes[FTDI_MAX_RW_SIZE + 3];
uint32_t in_bytes = 0;
uint32_t last_bits = 0;
uint16_t last_bytes, len;
int i, t;
in_bytes = in_bits / 8;
last_bits = in_bits % 8;
/* If last_bits == 0, the last bit of last byte should send out with TMS */
if (in_bytes) {
t = in_bytes / FTDI_MAX_RW_SIZE;
last_bytes = in_bytes % FTDI_MAX_RW_SIZE;
for (i = 0; i <= t; i++) {
len = (i == t) ? last_bytes : FTDI_MAX_RW_SIZE;
buf_bytes[0] = MPSSE_LSB|MPSSE_WRITE_NEG;
if (in)
buf_bytes[0] |= MPSSE_DO_WRITE;
if (out)
buf_bytes[0] |= MPSSE_DO_READ;
buf_bytes[1] = (len - 1) & 0xff;
buf_bytes[2] = ((len - 1) >> 8) & 0xff;
if (in)
memcpy(&buf_bytes[3], (in + i * FTDI_MAX_RW_SIZE), len);
if (ftdi_write_data(ftdi, buf_bytes, len + 3) != len + 3) {
fprintf(stderr,
"Ftdi write failed\n");
return -1;
}
if (out)
ftdi_read_data(ftdi, (out + i * FTDI_MAX_RW_SIZE), len);
}
}
if (last_bits) {
/* Send last few bits */
shift_last_bits(ftdi, &in[in_bytes], last_bits - 1, out);
tap_tms(ftdi, 1, (in[in_bytes] >> (last_bits - 1)));
} else
tap_tms(ftdi, 1, 0);
return 0;
}
int tap_shift_dr_bits(struct ftdi_context *ftdi,
uint8_t *in, uint32_t in_bits,
uint8_t *out)
{
int ret;
/* Send 3 Clocks with TMS = 1 0 0 to reach SHIFTDR*/
tap_tms(ftdi, 1, 0);
tap_tms(ftdi, 0, 0);
tap_tms(ftdi, 0, 0);
ret = tap_shift_dr_bits_only(ftdi, in, in_bits, out);
tap_tms(ftdi, 1, 0);
tap_tms(ftdi, 0, 0); /* Goto RTI */
return ret;
}
int ft232_flush(struct ftdi_context *ftdi)
{
uint8_t buf[1] = { SEND_IMMEDIATE };
if (ftdi_write_data(ftdi, buf, 1) != 1) {
fprintf(stderr,
"Can't SEND_IMMEDIATE\n");
return -1;
}
return 0;
}
fpgatools-201212/mini-jtag/jtag.h 0000664 0000000 0000000 00000002177 12065743015 0016570 0 ustar 00root root 0000000 0000000 //
// Author: Xiangfu Liu
//
// This is free and unencumbered software released into the public domain.
// For details see the UNLICENSE file at the root of the source tree.
//
#ifndef JTAG_H
#define JTAG_H
/* FPGA Boundary-Scan Instructions */
#define EXTEST 0x0F
#define SAMPLE 0x01
#define USER1 0x02
#define USER2 0x03
#define USER3 0x1A
#define USER4 0x1B
#define CFG_OUT 0x04
#define CFG_IN 0x05
#define INTEST 0x07
#define USERCODE 0x08
#define IDCODE 0x09
#define JPROGRAM 0x0B
#define JSTART 0x0C
#define JSHUTDOWN 0x0D
#define BYPASS 0x3F
/* The max read/write size is 65536, we use 65532 here */
#define FTDI_MAX_RW_SIZE 65532
int tap_tms(struct ftdi_context *ftdi, int tms, uint8_t bit7);
void tap_reset_rti(struct ftdi_context *ftdi);
int tap_shift_ir_only(struct ftdi_context *ftdi, uint8_t ir);
int tap_shift_dr_bits_only(struct ftdi_context *ftdi,
uint8_t *in, uint32_t in_bits,
uint8_t *out);
int tap_shift_ir(struct ftdi_context *ftdi, uint8_t ir);
int tap_shift_dr_bits(struct ftdi_context *ftdi,
uint8_t *in, uint32_t in_bits,
uint8_t *out);
int ft232_flush(struct ftdi_context *ftdi);
#endif
fpgatools-201212/mini-jtag/load-bits.c 0000664 0000000 0000000 00000004025 12065743015 0017506 0 ustar 00root root 0000000 0000000 //
// Author: Xiangfu Liu
//
// This is free and unencumbered software released into the public domain.
// For details see the UNLICENSE file at the root of the source tree.
//
#include
#include
#include
#include
#include "load-bits.h"
int read_section(FILE *bit_file, char *id, uint8_t **data, uint32_t *len)
{
uint8_t buf[4];
int lenbytes;
/* first read 1 bytes, the section key */
if (fread(buf, 1, 1, bit_file) != 1)
return -1;
*id = buf[0];
/* section 'e' has 4 bytes indicating section length */
if (*id == 'e')
lenbytes = 4;
else
lenbytes = 2;
/* first read 1 bytes */
if (fread(buf, 1, lenbytes, bit_file) != lenbytes)
return -1;
/* second and third is section length */
if (*id != 'e')
*len = buf[0] << 8 | buf[1];
else
*len = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3];
/* now allocate memory for data */
*data = malloc(*len);
if (fread(*data, 1, *len, bit_file) != *len)
return -1;
return 0;
}
int load_bits(FILE *bit_file, struct load_bits *bs)
{
char sid = 0;
uint8_t *sdata;
uint32_t slen;
uint8_t buf[128];
uint8_t header[] = {
0x00, 0x09, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0,
0x0f, 0xf0, 0x00, 0x00, 0x01,
};
if (fread(buf, 1, sizeof (header), bit_file) != sizeof (header))
return -1;
if (memcmp(buf, header, sizeof (header)) != 0)
return -1;
while (sid != 'e') {
if (read_section(bit_file, &sid, &sdata, &slen) != 0)
return -1;
/* make sure that strings are terminated */
if (sid != 'e')
sdata[slen-1] = '\0';
switch (sid) {
case 'a': bs->design = (char *)sdata; break;
case 'b': bs->part_name = (char *)sdata; break;
case 'c': bs->date = (char *)sdata; break;
case 'd': bs->time = (char *)sdata; break;
case 'e': bs->data = sdata; bs->length = slen; break;
}
}
return 0;
}
void bits_free(struct load_bits *bs)
{
if (bs->design)
free(bs->design);
if (bs->part_name)
free(bs->part_name);
if (bs->date)
free(bs->date);
if (bs->time)
free(bs->time);
if (bs->data)
free(bs->data);
free (bs);
}
fpgatools-201212/mini-jtag/load-bits.h 0000664 0000000 0000000 00000001046 12065743015 0017513 0 ustar 00root root 0000000 0000000 //
// Author: Xiangfu Liu
//
// This is free and unencumbered software released into the public domain.
// For details see the UNLICENSE file at the root of the source tree.
//
#ifndef LOAD_BITS_H
#define LOAD_BITS_H
struct load_bits {
char *design;
char *part_name;
char *date;
char *time;
uint32_t length;
uint8_t *data;
};
int read_section(FILE *bit_file, char *id, uint8_t **data, uint32_t *len);
int load_bits(FILE *bit_file, struct load_bits *bs);
void bits_free(struct load_bits *bs);
#endif /* LOAD_BITS_H */
fpgatools-201212/mini-jtag/mini-jtag.c 0000664 0000000 0000000 00000017755 12065743015 0017525 0 ustar 00root root 0000000 0000000 //
// Author: Xiangfu Liu
//
// This is free and unencumbered software released into the public domain.
// For details see the UNLICENSE file at the root of the source tree.
//
#include
#include
#include
#include
#include
#include
#include "load-bits.h"
#include "jtag.h"
/* JTAG/Serial board ID */
#define VENDOR 0x20b7
#define PRODUCT 0x0713
static inline uint8_t rev8(uint8_t d)
{
int i;
uint8_t out = 0;
/* (from left to right) */
for (i = 0; i < 8; i++)
if (d & (1 << i))
out |= (1 << (7 - i));
return out;
}
static uint8_t jtagcomm_checksum(uint8_t *d, uint16_t len)
{
int i, j;
uint16_t bytes, bits;
uint8_t checksum = 0x01;
bytes = len / 8;
bits = len % 8;
j = 0;
if (bytes)
for (j = 0; j < bytes; j++)
for (i = 0; i < 8; i++)
checksum ^= ((d[j] >> i) & 0x01) ? 1 : 0;
if (bits)
for (i = 0; i < bits; i++)
checksum ^= ((d[j] >> i) & 0x01) ? 1 : 0;
return checksum;
}
static void rev_dump(uint8_t *buf, uint16_t len)
{
int i;
for (i = len - 1; i >= 0 ; i--)
printf("%02x ", buf[i]);
}
static void brd_reset(struct ftdi_context *ftdi)
{
tap_reset_rti(ftdi);
tap_shift_ir(ftdi, JPROGRAM);
tap_reset_rti(ftdi);
}
static void usage(char *name)
{
fprintf(stderr,
"\n"
"%s - A small JTAG program talk to FPGA chip\n"
"Usage:\n"
" idcode\n"
" reset\n"
" load \n"
" readreg \tRead configure register status\n"
" read|write reg \n"
"Report bugs to xiangfu@openmobilefree.net\n"
"\n", name);
}
int main(int argc, char **argv)
{
struct ftdi_context ftdi;
uint8_t buf[4];
uint8_t conf_buf[] = {SET_BITS_LOW, 0x08, 0x0b,
SET_BITS_HIGH, 0x00, 0x00,
TCK_DIVISOR, 0x00, 0x00,
LOOPBACK_END};
if (argc < 2) {
usage(argv[0]);
return 1;
}
if (strcmp (argv[1], "idcode") && strcmp (argv[1], "reset") &&
strcmp (argv[1], "load") && strcmp (argv[1], "readreg") &&
strcmp (argv[1], "read") && strcmp (argv[1], "write")
) {
usage(argv[0]);
return 1;
}
/* Init */
ftdi_init(&ftdi);
if (ftdi_usb_open_desc(&ftdi, VENDOR, PRODUCT, 0, 0) < 0) {
fprintf(stderr,
"Can't open device %04x:%04x\n", VENDOR, PRODUCT);
return 1;
}
ftdi_usb_reset(&ftdi);
ftdi_set_interface(&ftdi, INTERFACE_A);
ftdi_set_latency_timer(&ftdi, 1);
ftdi_set_bitmode(&ftdi, 0xfb, BITMODE_MPSSE);
if (ftdi_write_data(&ftdi, conf_buf, 10) != 10) {
fprintf(stderr,
"Can't configure device %04x:%04x\n", VENDOR, PRODUCT);
return 1;
}
buf[0] = GET_BITS_LOW;
buf[1] = SEND_IMMEDIATE;
if (ftdi_write_data(&ftdi, buf, 2) != 2) {
fprintf(stderr,
"Can't send command to device\n");
return 1;
}
ftdi_read_data(&ftdi, &buf[2], 1);
if (!(buf[2] & 0x10)) {
fprintf(stderr,
"Vref not detected. Please power on target board\n");
return 1;
}
if (!strcmp(argv[1], "idcode")) {
uint8_t out[4];
tap_reset_rti(&ftdi);
tap_shift_dr_bits(&ftdi, NULL, 32, out);
rev_dump(out, 4);
printf("\n");
}
if (!strcmp (argv[1], "reset"))
brd_reset(&ftdi);
if (!strcmp (argv[1], "load")) {
int i;
struct load_bits *bs;
FILE *fp;
uint8_t *dr_data;
uint32_t u;
if(argc < 3) {
usage(argv[0]);
goto exit;
}
if (!strcmp(argv[2], "-"))
fp = stdin;
else {
fp = fopen(argv[2], "r");
if (!fp) {
perror("Unable to open file");
goto exit;
}
}
bs = calloc(1, sizeof(*bs));
if (!bs) {
perror("memory allocation failed");
goto exit;
}
if (load_bits(fp, bs) != 0) {
fprintf(stderr, "%s not supported\n", argv[2]);
goto free_bs;
}
printf("Bitstream information:\n");
printf("\tDesign: %s\n", bs->design);
printf("\tPart name: %s\n", bs->part_name);
printf("\tDate: %s\n", bs->date);
printf("\tTime: %s\n", bs->time);
printf("\tBitstream length: %d\n", bs->length);
/* copy data into shift register */
dr_data = calloc(1, bs->length);
if (!dr_data) {
perror("memory allocation failed");
goto free_bs;
}
for (u = 0; u < bs->length; u++)
dr_data[u] = rev8(bs->data[u]);
brd_reset(&ftdi);
tap_shift_ir(&ftdi, CFG_IN);
tap_shift_dr_bits(&ftdi, dr_data, bs->length * 8, NULL);
/* ug380.pdf
* P161: a minimum of 16 clock cycles to the TCK */
tap_shift_ir(&ftdi, JSTART);
for (i = 0; i < 32; i++)
tap_tms(&ftdi, 0, 0);
tap_reset_rti(&ftdi);
free(dr_data);
free_bs:
bits_free(bs);
fclose(fp);
}
if (!strcmp(argv[1], "readreg") && argc == 3) {
int i;
char *err;
uint8_t reg;
uint8_t out[2];
uint8_t dr_in[14];
uint8_t in[14] = {
0xaa, 0x99, 0x55, 0x66,
0x00, 0x00, 0x20, 0x00,
0x20, 0x00, 0x20, 0x00,
0x20, 0x00
};
uint16_t cmd = 0x2801; /* type 1 packet (word count = 1) */
reg = strtol(argv[2], &err, 0);
if((*err != 0x00) || (reg < 0) || (reg > 0x22)) {
fprintf(stderr,
"Invalid register, use a decimal or hexadecimal(0x...) number between 0x0 and 0x22\n");
goto exit;
}
cmd |= ((reg & 0x3f) << 5);
in[4] = (cmd & 0xff00) >> 8;
in[5] = cmd & 0xff;
tap_reset_rti(&ftdi);
tap_tms(&ftdi, 1, 0);
tap_tms(&ftdi, 1, 0);
tap_tms(&ftdi, 0, 0);
tap_tms(&ftdi, 0, 0); /* Goto shift IR */
tap_shift_ir_only(&ftdi, CFG_IN);
tap_tms(&ftdi, 1, 0);
tap_tms(&ftdi, 1, 0);
tap_tms(&ftdi, 0, 0);
tap_tms(&ftdi, 0, 0); /* Goto SHIFT-DR */
for (i = 0; i < 14; i++)
dr_in[i] = rev8(in[i]);
tap_shift_dr_bits_only(&ftdi, dr_in, 14 * 8, NULL);
tap_tms(&ftdi, 1, 0);
tap_tms(&ftdi, 1, 0);
tap_tms(&ftdi, 1, 0); /* Goto SELECT-IR */
tap_tms(&ftdi, 0, 0);
tap_tms(&ftdi, 0, 0); /* Goto SHIFT-IR */
tap_shift_ir_only(&ftdi, CFG_OUT);
tap_tms(&ftdi, 1, 0);
tap_tms(&ftdi, 1, 0);
tap_tms(&ftdi, 0, 0);
tap_tms(&ftdi, 0, 0); /* Goto SHIFT-IR */
tap_shift_dr_bits_only(&ftdi, NULL, 2 * 8, out);
tap_tms(&ftdi, 1, 0);
tap_tms(&ftdi, 1, 0);
tap_tms(&ftdi, 1, 0); /* Goto SELECT-IR */
tap_tms(&ftdi, 0, 0);
tap_tms(&ftdi, 0, 0); /* Goto SHIFT-IR */
tap_reset_rti(&ftdi);
out[0] = rev8(out[0]);
out[1] = rev8(out[1]);
printf("REG[%d]: 0x%02x%02x\n", reg, out[0], out[1]);
}
/* TODO:
* Configuration Memory Read Procedure (IEEE Std 1149.1 JTAG) */
if (!strcmp (argv[1], "read") && argc == 3) {
char *err;
uint8_t addr, checksum;
uint8_t in[5];
uint8_t out[4];
/* Tell the FPGA what address we would like to read */
addr = strtol(argv[2], &err, 0);
if((*err != 0x00) || (addr < 0) || (addr > 4)) {
fprintf(stderr,
"Invalid address, use a decimal or hexadecimal(0x...) number between 0 and 4\n");
goto exit;
}
addr &= 0xf;
in[0] = addr;
checksum = jtagcomm_checksum(in, 4);
in[0] = (checksum << 5) | (0 << 4) | addr;
tap_reset_rti(&ftdi);
tap_shift_ir(&ftdi, USER1);
tap_shift_dr_bits(&ftdi, in, 6, NULL);
/* Now read back the register */
tap_shift_dr_bits(&ftdi, NULL, 32, out);
printf("Read: ");
rev_dump(out, 4);
printf("\t[%d]\n",(uint32_t) (out[3] << 24 | out[2] << 16 |
out[1] << 8 | out[0]));
tap_reset_rti(&ftdi);
}
if (!strcmp(argv[1], "write") && argc == 4) {
char *err;
uint8_t addr, checksum;
uint8_t in[5];
uint32_t value;
value = strtol(argv[3], &err, 0);
if (*err != 0x00) {
fprintf(stderr,
"Invalid value, use a decimal or hexadecimal(0x...) number\n");
goto exit;
}
in[0] = value & 0x000000ff;
in[1] = (value & 0x0000ff00) >> 8;
in[2] = (value & 0x00ff0000) >> 16;
in[3] = (value & 0xff000000) >> 24;
/* Tell the FPGA what address we would like to read */
addr = strtol(argv[2], &err, 0);
if((*err != 0x00) || (addr < 0) || (addr > 4)) {
fprintf(stderr,
"Invalid address, use a decimal or hexadecimal(0x...) number between 0 and 4\n");
goto exit;
}
addr &= 0xf;
in[4] = (1 << 4) | addr;
checksum = jtagcomm_checksum(in, 37);
in[4] |= (checksum << 5);
printf("Write: ");
rev_dump(in, 5);
printf("\n");
tap_reset_rti(&ftdi);
tap_shift_ir(&ftdi, USER1);
tap_shift_dr_bits(&ftdi, in, 38, NULL);
tap_reset_rti(&ftdi);
}
exit:
/* Clean up */
ftdi_usb_reset(&ftdi);
ftdi_usb_close(&ftdi);
ftdi_deinit(&ftdi);
return 0;
}
fpgatools-201212/new_fp.c 0000664 0000000 0000000 00000001527 12065743015 0015233 0 ustar 00root root 0000000 0000000 //
// Author: Wolfgang Spraul
//
// This is free and unencumbered software released into the public domain.
// For details see the UNLICENSE file at the root of the source tree.
//
#include "model.h"
#include "floorplan.h"
int main(int argc, char** argv)
{
struct fpga_model model;
int no_conns, rc;
if ((rc = fpga_build_model(&model, XC6SLX9, TQG144)))
goto fail;
no_conns = 0;
if (argc > 1 && !strcmp(argv[1], "--no-conns"))
no_conns = 1;
printf_version(stdout);
rc = printf_tiles(stdout, &model);
if (rc) goto fail;
rc = printf_devices(stdout, &model, /*config_only*/ 0);
if (rc) goto fail;
rc = printf_ports(stdout, &model);
if (rc) goto fail;
if (!no_conns) {
rc = printf_conns(stdout, &model);
if (rc) goto fail;
}
rc = printf_switches(stdout, &model);
if (rc) goto fail;
return EXIT_SUCCESS;
fail:
return rc;
}
fpgatools-201212/pair2net.c 0000664 0000000 0000000 00000011677 12065743015 0015510 0 ustar 00root root 0000000 0000000 //
// Author: Wolfgang Spraul
//
// This is free and unencumbered software released into the public domain.
// For details see the UNLICENSE file at the root of the source tree.
//
#include
#include
#include
#include
#include
#include
#include "helper.h"
#define ALLOC_INCREMENT 16
static int add_entry(uint32_t** net, uint32_t new_idx)
{
if (!*net) {
*net = malloc(ALLOC_INCREMENT*sizeof(**net));
if (!(*net)) {
fprintf(stderr, "Out of memory in %s:%i\n",
__FILE__, __LINE__);
return -1;
}
**net = 1;
} else {
uint32_t num_entries = **net;
if (!(num_entries % ALLOC_INCREMENT)) {
void* new_ptr = realloc(*net,
(num_entries + ALLOC_INCREMENT)*sizeof(**net));
if (!new_ptr) {
fprintf(stderr, "Out of memory in %s:%i\n",
__FILE__, __LINE__);
return -1;
}
*net = new_ptr;
}
}
(*net)[**net] = new_idx;
(**net)++;
return 0;
}
static int print_nets(uint32_t** nets, struct hashed_strarray* connpt_names)
{
int i, j, num_connpoints, num_nets, largest_net, total_net_connpoints;
const char* str;
num_connpoints = 0;
num_nets = 0;
largest_net = 0;
total_net_connpoints = 0;
for (i = 0; i < STRIDX_1M; i++) {
if (nets[i]) {
num_connpoints++;
if (!((uint64_t)nets[i] & 1)) {
num_nets++;
if (!(*nets[i]))
fprintf(stderr, "Internal error - 0 entries in net %i\n", i);
total_net_connpoints += *nets[i] - 1;
if (*nets[i] - 1 > largest_net)
largest_net = *nets[i] - 1;
for (j = 1; j < *nets[i]; j++) {
str = strarray_lookup(connpt_names, nets[i][j]);
if (!str) {
fprintf(stderr, "Internal error - cannot find str %i\n", nets[i][j]);
continue;
}
if (j > 1) fputc(' ', stdout);
fputs(str, stdout);
}
fputc('\n', stdout);
}
}
}
return 0;
}
struct hashed_strarray* g_sort_connpt_names;
static int sort_net(const void* a, const void* b)
{
const uint32_t* _a, *_b;
const char* a_str, *b_str;
_a = a;
_b = b;
a_str = strarray_lookup(g_sort_connpt_names, *_a);
b_str = strarray_lookup(g_sort_connpt_names, *_b);
if (!a_str || !b_str) {
fprintf(stderr, "Internal error in %s:%i - cannot find str %i or %i\n",
__FILE__, __LINE__, *_a, *_b);
return 0;
}
return strcmp(a_str, b_str);
}
static int sort_nets(uint32_t** nets, struct hashed_strarray* connpt_names)
{
int i;
g_sort_connpt_names = connpt_names;
for (i = 0; i < STRIDX_1M; i++) {
if (nets[i] && !((uint64_t)nets[i] & 1)) {
qsort(&nets[i][1], *nets[i]-1, sizeof(nets[i][1]), sort_net);
}
}
return 0;
}
int main(int argc, char** argv)
{
char line[1024], point_a[1024], point_b[1024];
struct hashed_strarray connpt_names;
FILE* fp = 0;
int i, rc, point_a_idx, point_b_idx, existing_net_idx, new_net_idx;
int net_data_idx;
uint32_t** nets;
if (argc < 2) {
fprintf(stderr,
"\n"
"pair2net - finds all pairs connected to the same net\n"
"Usage: %s | '-' for stdin\n", argv[0]);
goto xout;
}
if (strarray_init(&connpt_names, STRIDX_1M)) {
fprintf(stderr, "Out of memory in %s:%i\n", __FILE__, __LINE__);
goto xout;
}
nets = calloc(STRIDX_1M, sizeof(*nets));
if (!nets) {
fprintf(stderr, "Out of memory in %s:%i\n", __FILE__, __LINE__);
goto xout;
}
if (!strcmp(argv[1], "-"))
fp = stdin;
else {
fp = fopen(argv[1], "r");
if (!fp) {
fprintf(stderr, "Error opening %s.\n", argv[1]);
goto xout;
}
}
while (fgets(line, sizeof(line), fp)) {
i = sscanf(line, "%s%s", point_a, point_b);
if (i != 2) continue;
i = strlen(point_b);
if (i && point_b[i-1] == '\n')
point_b[i-1] = 0;
rc = strarray_add(&connpt_names, point_a, &point_a_idx);
if (rc) {
fprintf(stderr, "Out of memory in %s:%i\n",
__FILE__, __LINE__);
goto xout;
}
rc = strarray_add(&connpt_names, point_b, &point_b_idx);
if (rc) {
fprintf(stderr, "Out of memory in %s:%i\n",
__FILE__, __LINE__);
goto xout;
}
if (nets[point_a_idx] && nets[point_b_idx]) {
continue;}
if (nets[point_a_idx] || nets[point_b_idx]) {
if (nets[point_a_idx]) {
existing_net_idx = point_a_idx;
new_net_idx = point_b_idx;
} else { // point_b_idx exists
existing_net_idx = point_b_idx;
new_net_idx = point_a_idx;
}
if ((uint64_t) nets[existing_net_idx] & 1)
net_data_idx = (uint64_t) nets[existing_net_idx] >> 32;
else
net_data_idx = existing_net_idx;
// add new_net_idx to net data
rc = add_entry(&nets[net_data_idx], new_net_idx);
if (rc) goto xout;
// point to net data from new_net_idx
nets[new_net_idx] = (uint32_t*) (((uint64_t) net_data_idx << 32) | 1);
} else {
rc = add_entry(&nets[point_a_idx], point_a_idx);
if (rc) goto xout;
rc = add_entry(&nets[point_a_idx], point_b_idx);
if (rc) goto xout;
nets[point_b_idx] = (uint32_t*) (((uint64_t) point_a_idx << 32) | 1);
}
}
rc = sort_nets(nets, &connpt_names);
if (rc) goto xout;
rc = print_nets(nets, &connpt_names);
if (rc) goto xout;
return EXIT_SUCCESS;
xout:
return EXIT_FAILURE;
}
fpgatools-201212/sort_seq.c 0000664 0000000 0000000 00000027322 12065743015 0015615 0 ustar 00root root 0000000 0000000 //
// Author: Wolfgang Spraul
//
// This is free and unencumbered software released into the public domain.
// For details see the UNLICENSE file at the root of the source tree.
//
#include
#include
#include
#include "helper.h"
#define LINE_LENGTH 1024
static int s_numlines;
static char s_lines[1000][LINE_LENGTH];
// returns 0 if no number found
static int find_rightmost_num(const char* s, int s_len,
int* dig_start, int* dig_end)
{
int i;
if (s_len < 2) return 0;
i = s_len;
while (i > 0 && (s[i-1] < '0' || s[i-1] > '9'))
i--;
if (!i) return 0;
*dig_end = i;
while (i > 0 && s[i-1] >= '0' && s[i-1] <= '9')
i--;
if (!i) return 0;
if ((s[i-1] < 'A' || s[i-1] > 'Z') && s[i-1] != '_')
return 0;
*dig_start = i;
return 1;
}
// Finds the position of a number in a string, searching from
// the right, meeting:
// - not part of a known suffix if there is another number to
// the left of it
// - prefixed by at least one capital 'A'-'Z' or '_'
// If none is found, both *num_start and *num_end will be returned as 0.
static void find_number(const char* s, int s_len, int* num_start, int* num_end)
{
int result, dig_start, dig_end, found_num, search_more;
int next_dig_start, next_dig_end;
*num_start = 0;
*num_end = 0;
if (s_len >= 13 && !strncmp("_DSP48A1_SITE", &s[s_len-13], 13))
s_len -= 13;
else if (s_len >= 15 && !strncmp("_DSP48A1_B_SITE", &s[s_len-15], 15))
s_len -= 15;
result = find_rightmost_num(s, s_len, &dig_start, &dig_end);
if (!result) return;
// If the found number is not part of a potential
// suffix, we can take it.
found_num = to_i(&s[dig_start], dig_end-dig_start);
// The remaining suffixes all reach the right end of
// the string, so if our digits don't, we can take them.
if (dig_end < s_len) {
*num_start = dig_start;
*num_end = dig_end;
return;
}
search_more = 0;
// _
if (dig_start >= 2
&& s[dig_start-1] == '_'
&& ((s[dig_start-2] >= 'A' && s[dig_start-2] <= 'Z')
|| (s[dig_start-2] >= '0' && s[dig_start-2] <= '9')))
search_more = 1;
// _S0
else if (found_num == 0 && dig_start >= 3
&& s[dig_start-1] == 'S' && s[dig_start-2] == '_'
&& ((s[dig_start-3] >= 'A' && s[dig_start-3] <= 'Z')
|| (s[dig_start-3] >= '0' && s[dig_start-3] <= '9')))
search_more = 1;
// _N3
else if (found_num == 3 && dig_start >= 3
&& s[dig_start-1] == 'N' && s[dig_start-2] == '_'
&& ((s[dig_start-3] >= 'A' && s[dig_start-3] <= 'Z')
|| (s[dig_start-3] >= '0' && s[dig_start-3] <= '9')))
search_more = 1;
// _INT0 _INT1 _INT2 _INT3
else if ((found_num >= 0 && found_num <= 3) && dig_start >= 5
&& s[dig_start-1] == 'T' && s[dig_start-2] == 'N'
&& s[dig_start-3] == 'I' && s[dig_start-4] == '_'
&& ((s[dig_start-5] >= 'A' && s[dig_start-5] <= 'Z')
|| (s[dig_start-5] >= '0' && s[dig_start-5] <= '9')))
search_more = 1;
if (!search_more
|| !find_rightmost_num(s, dig_start, &next_dig_start, &next_dig_end)) {
*num_start = dig_start;
*num_end = dig_end;
} else {
*num_start = next_dig_start;
*num_end = next_dig_end;
}
}
static int is_known_suffix(const char* str, int str_len)
{
int i;
if (str_len < 1) return 0;
if (str[0] != '_') return 0;
if (str_len < 2) return 0;
// Special case _ - we detect this as a
// known suffix here because our number finding
// function already found a better match to the
// left of it, so we can assume the _ to
// be a suffix.
i = 1;
while (i < str_len) {
if (str[i] < '0' || str[i] > '9')
break;
i++;
}
if (i >= str_len)
return 1;
if (str_len == 2) {
// _E _W _S _N _M
if (str[1] == 'E' || str[1] == 'W' || str[2] == 'S'
|| str[1] == 'N' || str[1] == 'M')
return 1;
}
if (str_len < 3) return 0;
if (str_len == 3) {
// _S0 _N3 _UP
if ((str[1] == 'S' && str[2] == '0')
|| (str[1] == 'N' && str[2] == '3')
|| (str[1] == 'U' && str[2] == 'P'))
return 1;
}
if (str_len < 4) return 0;
if (str_len == 4) {
// _CLB _DSP _EXT _INT _MCP _BRK _BUF
if ((str[1] == 'C' && str[2] == 'L' && str[3] == 'B')
|| (str[1] == 'D' && str[2] == 'S' && str[3] == 'P')
|| (str[1] == 'E' && str[2] == 'X' && str[3] == 'T')
|| (str[1] == 'I' && str[2] == 'N' && str[3] == 'T')
|| (str[1] == 'M' && str[2] == 'C' && str[3] == 'B')
|| (str[1] == 'B' && str[2] == 'R' && str[3] == 'K')
|| (str[1] == 'B' && str[2] == 'U' && str[3] == 'F'))
return 1;
}
if (str_len < 5) return 0;
if (str_len == 5) {
// _INT0 _INT1 _INT2 _INT3 _TEST _FOLD _BRAM _DOWN _PINW
if ((str[1] == 'I' && str[2] == 'N' && str[3] == 'T'
&& str[4] >= '0' && str[4] <= '3')
|| (str[1] == 'T' && str[2] == 'E' && str[3] == 'S'
&& str[4] == 'T')
|| (str[1] == 'F' && str[2] == 'O' && str[3] == 'L'
&& str[4] == 'D')
|| (str[1] == 'B' && str[2] == 'R' && str[3] == 'A'
&& str[4] == 'M')
|| (str[1] == 'D' && str[2] == 'O' && str[3] == 'W'
&& str[4] == 'N')
|| (str[1] == 'P' && str[2] == 'I' && str[3] == 'N'
&& str[4] == 'W'))
return 1;
}
if (str_len < 11) return 0;
if (str_len == 11) {
// _BRAM_INTER
if (str[1] == 'B' && str[2] == 'R' && str[3] == 'A'
&& str[4] == 'M' && str[5] == '_' && str[6] == 'I'
&& str[7] == 'N' && str[8] == 'T' && str[9] == 'E'
&& str[10] == 'R')
return 1;
}
return 0;
}
static void next_unequal_word(
const char* a, int a_start, int* a_beg, int* a_end,
const char* b, int b_start, int* b_beg, int* b_end)
{
*a_beg = a_start;
*a_end = a_start;
*b_beg = b_start;
*b_end = b_start;
// find the first non-matching word
while (1) {
next_word(a, *a_beg, a_beg, a_end);
next_word(b, *b_beg, b_beg, b_end);
if (*a_end-*a_beg <= 0
|| *b_end-*b_beg <= 0)
return;
if (str_cmp(&a[*a_beg], *a_end-*a_beg, &b[*b_beg], *b_end-*b_beg))
return;
*a_beg = *a_end;
*b_beg = *b_end;
}
}
static int sort_lines(const void* a, const void* b)
{
const char* _a, *_b;
int a_word_beg, a_word_end, b_word_beg, b_word_end;
int a_num, b_num, a_num_start, b_num_start, a_num_end, b_num_end;
int num_result, result, suffix_result;
_a = a;
_b = b;
// find the first non-matching word
a_word_beg = 0;
b_word_beg = 0;
next_unequal_word(_a, a_word_beg, &a_word_beg, &a_word_end,
_b, b_word_beg, &b_word_beg, &b_word_end);
if (a_word_end-a_word_beg <= 0) {
if (b_word_end-b_word_beg <= 0)
return 0;
return -1;
}
if (b_word_end-b_word_beg <= 0) {
if (a_word_end-a_word_beg <= 0)
return 0;
return 1;
}
// first try to find 2 numbers
find_number(&_a[a_word_beg], a_word_end-a_word_beg,
&a_num_start, &a_num_end);
find_number(&_b[b_word_beg], b_word_end-b_word_beg,
&b_num_start, &b_num_end);
// if we cannot find both numbers, return a regular
// string comparison over the entire word
if (a_num_end <= a_num_start
|| b_num_end <= b_num_start) {
result = str_cmp(&_a[a_word_beg], a_word_end-a_word_beg,
&_b[b_word_beg], b_word_end-b_word_beg);
if (!result) {
fprintf(stderr, "Internal error in %s:%i\n",
__FILE__, __LINE__);
exit(0);
}
return result;
}
// A number must always be prefixed by at least one character.
if (!a_num_start || !b_num_start) {
fprintf(stderr, "Internal error in %s:%i\n",
__FILE__, __LINE__);
exit(0);
}
// otherwise compare the string up to the 2 numbers,
// if it does not match return that result
result = str_cmp(&_a[a_word_beg], a_num_start,
&_b[b_word_beg], b_num_start);
if (result)
return result;
a_num_start += a_word_beg;
a_num_end += a_word_beg;
b_num_start += b_word_beg;
b_num_end += b_word_beg;
if (a_num_end > a_word_end
|| b_num_end > b_word_end) {
fprintf(stderr, "Internal error in %s:%i\n",
__FILE__, __LINE__);
fprintf(stderr, "sort_line_a: %s", _a);
fprintf(stderr, "sort_line_b: %s", _b);
exit(1);
}
if ((a_word_end-a_num_end == 0
|| is_known_suffix(&_a[a_num_end],
a_word_end-a_num_end))
&& (b_word_end-b_num_end == 0
|| is_known_suffix(&_b[b_num_end],
b_word_end-b_num_end))) {
// known suffix comes before number
suffix_result = str_cmp(&_a[a_num_end],
a_word_end-a_num_end,
&_b[b_num_end], b_word_end-b_num_end);
if (suffix_result)
return suffix_result;
}
a_num = to_i(&_a[a_num_start], a_num_end-a_num_start);
b_num = to_i(&_b[b_num_start], b_num_end-b_num_start);
num_result = a_num-b_num;
// if the non-known suffixes don't match, return numeric result
// if numbers are not equal, otherwise suffix result
suffix_result = str_cmp(&_a[a_num_end], a_word_end-a_num_end,
&_b[b_num_end], b_word_end-b_num_end);
if (suffix_result) {
if (num_result) return num_result;
return suffix_result;
}
// Should be impossible that both the number result and
// suffix result are equal. How can the entire word then
// be unequal?
if (!num_result) {
fprintf(stderr, "Internal error in %s:%i\n",
__FILE__, __LINE__);
fprintf(stderr, "sort_line_a: %s", _a);
fprintf(stderr, "sort_line_b: %s", _b);
exit(1);
}
// find second non-equal word
next_unequal_word(_a, a_word_end, &a_word_beg, &a_word_end,
_b, b_word_end, &b_word_beg, &b_word_end);
if (a_word_end <= a_word_beg
|| b_word_end <= b_word_beg)
return num_result;
// if no numbers in second non-equal words, fall back
// to numeric result of first word
find_number(&_a[a_word_beg], a_word_end-a_word_beg,
&a_num_start, &a_num_end);
find_number(&_b[b_word_beg], b_word_end-b_word_beg,
&b_num_start, &b_num_end);
if (a_num_end <= a_num_start
|| b_num_end <= b_num_start)
return num_result;
// A number must always be prefixed by at least one character.
if (!a_num_start || !b_num_start) {
fprintf(stderr, "Internal error in %s:%i\n",
__FILE__, __LINE__);
exit(0);
}
// If the prefix string of the second word does not
// match, fall back to numeric result of first word.
result = str_cmp(&_a[a_word_beg], a_num_start,
&_b[b_word_beg], b_num_start);
if (result)
return num_result;
a_num_start += a_word_beg;
a_num_end += a_word_beg;
b_num_start += b_word_beg;
b_num_end += b_word_beg;
if (a_num_end > a_word_end
|| b_num_end > b_word_end) {
fprintf(stderr, "Internal error in %s:%i\n",
__FILE__, __LINE__);
exit(0);
}
// if there are known suffixes in second non-equal
// words, compare those first
if ((a_word_end-a_num_end == 0
|| is_known_suffix(&_a[a_num_end],
a_word_end-a_num_end))
&& (b_word_end-b_num_end == 0
|| is_known_suffix(&_b[b_num_end],
b_word_end-b_num_end))) {
// known suffix comes before number
suffix_result = str_cmp(&_a[a_num_end],
a_word_end-a_num_end,
&_b[b_num_end], b_word_end-b_num_end);
if (suffix_result)
return suffix_result;
}
// otherwise fall back to numeric result of first word
return num_result;
}
int main(int argc, char** argv)
{
FILE* fp = 0;
int i;
if (argc < 2) {
fprintf(stderr,
"sort_seq - sort by sequence\n"
"Usage: %s | - for stdin\n", argv[0]);
goto xout;
}
if (!strcmp(argv[1], "-"))
fp = stdin;
else {
fp = fopen(argv[1], "r");
if (!fp) {
fprintf(stderr, "Error opening %s.\n", argv[1]);
goto xout;
}
}
s_numlines = 0;
// read 200 lines to beginning of buffer
while (s_numlines < 200
&& fgets(s_lines[s_numlines], sizeof(s_lines[0]), fp))
s_numlines++;
while (1) {
// read another 800 lines
while (s_numlines < 1000
&& fgets(s_lines[s_numlines], sizeof(s_lines[0]), fp))
s_numlines++;
if (!s_numlines) break;
// sort 1000 lines
qsort(s_lines, s_numlines, sizeof(s_lines[0]), sort_lines);
// print first 800 lines
for (i = 0; i < 800; i++) {
if (i >= s_numlines) break;
printf(s_lines[i]);
}
// move up last 200 lines to beginning of buffer
if (s_numlines > i) {
memmove(s_lines[0], s_lines[i],
(s_numlines-i)*sizeof(s_lines[0]));
s_numlines -= i;
} else
s_numlines = 0;
}
return EXIT_SUCCESS;
xout:
return EXIT_FAILURE;
}