Merge pull request #55 from kc8apf/xc7patch

FASM and xc7patch proof of concept using partial reconfig flow
This commit is contained in:
Rick Altherr 2018-01-22 16:10:49 -08:00 committed by GitHub
commit 79fa80c737
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 886 additions and 11 deletions

View File

@ -8,6 +8,6 @@ go:
cd build; cmake ..; make -j$(JOBS)
format:
find . -name \*.cc -and -not -path './third_party/*' -exec $(CLANG_FORMAT) -style=file -i {} \;
find . -name \*.h -and -not -path './third_party/*' -exec $(CLANG_FORMAT) -style=file -i {} \;
find . -name \*.py -and -not -path './third_party/*' -exec yapf -p -i {} \;
find . -name \*.cc -and -not -path './third_party/*' -and -not -path './.git/*' -exec $(CLANG_FORMAT) -style=file -i {} \;
find . -name \*.h -and -not -path './third_party/*' -and -not -path './.git/*' -exec $(CLANG_FORMAT) -style=file -i {} \;
find . -name \*.py -and -not -path './third_party/*' -and -not -path './.git/*' -exec yapf -p -i {} \;

View File

@ -25,8 +25,8 @@ class BitstreamWriter {
typedef std::array<uint32_t, 6> header_t;
typedef std::vector<ConfigurationPacket> packets_t;
// Only defined if a packet exists
typedef absl::optional<absl::Span<uint32_t>> op_data_t;
typedef absl::Span<uint32_t>::iterator data_iterator_t;
typedef absl::optional<absl::Span<const uint32_t>> op_data_t;
typedef absl::Span<const uint32_t>::iterator data_iterator_t;
using itr_value_type = uint32_t;
class packet_iterator

View File

@ -16,7 +16,7 @@ namespace xc7series {
class Configuration {
public:
using FrameMap = std::map<FrameAddress, absl::Span<uint32_t>>;
using FrameMap = std::map<FrameAddress, absl::Span<const uint32_t>>;
template <typename Collection>
static absl::optional<Configuration> InitWithPackets(
@ -28,7 +28,7 @@ class Configuration {
: part_(part) {
for (auto& frame : *frames) {
frames_[frame.first] =
absl::Span<uint32_t>(frame.second);
absl::Span<const uint32_t>(frame.second);
}
}

View File

@ -27,7 +27,7 @@ class ConfigurationPacket {
ConfigurationPacket(unsigned int header_type,
Opcode opcode,
ConfigurationRegister address,
const absl::Span<uint32_t>& data)
const absl::Span<const uint32_t>& data)
: header_type_(header_type),
opcode_(opcode),
address_(address),
@ -47,13 +47,13 @@ class ConfigurationPacket {
unsigned int header_type() const { return header_type_; }
const Opcode opcode() const { return opcode_; }
const ConfigurationRegister address() const { return address_; }
const absl::Span<uint32_t>& data() const { return data_; }
const absl::Span<const uint32_t>& data() const { return data_; }
private:
unsigned int header_type_;
Opcode opcode_;
ConfigurationRegister address_;
absl::Span<uint32_t> data_;
absl::Span<const uint32_t> data_;
};
std::ostream& operator<<(std::ostream& o, const ConfigurationPacket& packet);

View File

@ -25,7 +25,11 @@ ConfigurationPacket::InitWithWords(absl::Span<uint32_t> words,
// NOPs. Since Type 0 packets don't exist according to
// UG470 and they seem to be zero-filled, just consume
// the bytes without generating a packet.
return {words.subspan(1), {}};
return {words.subspan(1),
{{header_type,
Opcode::NOP,
ConfigurationRegister::CRC,
{}}}};
case 0x1: {
Opcode opcode = static_cast<Opcode>(
bit_field_get(words[0], 28, 27));
@ -73,6 +77,10 @@ ConfigurationPacket::InitWithWords(absl::Span<uint32_t> words,
}
std::ostream& operator<<(std::ostream& o, const ConfigurationPacket& packet) {
if (packet.header_type() == 0x0) {
return o << "[Zero-pad]" << std::endl;
}
switch (packet.opcode()) {
case ConfigurationPacket::Opcode::NOP:
o << "[NOP]" << std::endl;

View File

@ -0,0 +1,95 @@
# Top-level target for generating a programmable bitstream. Given a .fasm
# file, calling make with the .fasm extension replaced with .hand_crafted.bit
# will generate a bitstream that includes both the harness and the .fasm design
# ready for programming to a board. For example, 'make
# roi_noninv.hand_crafted.bit' will generate a bitstream that includes the
# design from roi_noninv.fasm.
%.hand_crafted.bit: init_sequence.bit %.no_headers.bin final_sequence.bin
cat $^ > $@
%.no_headers.bin: %.patched.bin
# WARNING: these values need to be tweaked if anything about the
# Vivado-generated design changes.
xxd -p -s 0x18 $< | xxd -r -p - $@
%.patched.bin: %.frm harness_routed.bit
${XRAY_TOOLS_DIR}/xc7patch \
--part_file ${XRAY_PART_YAML} \
--bitstream_file harness_routed.bit \
--frm_file $< \
--output_file $@
# xc7patch currently only generates the actual frame writes which is
# insufficient to program a device. Grab the initialization and finalization
# sequences from the harness bitstream so they can be tacked on to the
# xc7patch-generated bitstream to create a programmable bitstream.
#
# The offsets used below were determined by manually inspecting
# harness_routed.bit with a hex editor. init_sequence.bit is the beginning of
# the file until just before the actual frame data is sent via a write to FDRI.
# final_sequence.bin is from just after the frame data write to the end of the
# file. Note that final_sequence.bin normally includes at least one CRC check.
# The sed command replaces any CRC checks with a Reset CRC command which is the
# same behavior as setting BITSTREAM.GENERAL.CRC to Disabled. These offset
# should not change unless you alter the bitstream format used (i.e. setting
# BITSTREAM.GENERAL.DEBUGBITSTREAM or BITSTREAM.GENERAL.PERFRAMECRC to YES).
init_sequence.bit: harness_routed.bit
# WARNING: these values need to be tweaked if anything about the
# Vivado-generated design changes.
xxd -p -l 0x147 $< | xxd -r -p - $@
final_sequence.bin: harness_routed.bit
# WARNING: these values need to be tweaked if anything about the
# Vivado-generated design changes.
xxd -p -s 0x216abf $< | \
tr -d '\n' | \
sed -e 's/30000001.\{8\}/3000800100000007/g' | \
fold -w 40 | \
xxd -r -p - $@
# Generate a suitable harness by using Vivado's partial reconfiguration
# feature. roi_inv is used as a sample reconfiguration design as one is
# required to generate a partial reconfiguration design.
harness.dcp: harness.tcl top.v roi_base.v
vivado -mode batch -source harness.tcl
roi_inv.dcp: roi_inv.tcl roi_inv.v
vivado -mode batch -source roi_inv.tcl
roi_inv_routed.dcp roi_inv_w_harness_routed.dcp harness_routed.dcp: harness.dcp roi_inv.dcp roi_inv_routed.tcl
vivado -mode batch -source roi_inv_routed.tcl
# Conversions between various formats.
%.bit: %.dcp write_bitstream.tcl
vivado -mode batch -source write_bitstream.tcl -tclargs $< $@
%.bits: %.bit
${XRAY_BITREAD} -y -o $@ $<
# Extract only bits that are within the ROI.
%.roi.bits: %.bit
${XRAY_BITREAD} -F ${XRAY_ROI_FRAMES} -z -y -o $@ $<
%.segp: %.roi.bits
${XRAY_SEGPRINT} -zd $< > $@
%.fasm: %.segp
${XRAY_DIR}/tools/segprint2fasm.py $< $@
%.frm: %.fasm
${XRAY_DIR}/tools/fasm2frame.py $< $@
# This format is a human-readable representation of the configuration packets
# used to interact with 7-series chips over JTAG.
%.packets: %.bit
${XRAY_TOOLS_DIR}/bittool list_config_packets $< > $@
clean:
rm -rf specimen_[0-9][0-9][0-9]/ seg_clblx.segbits vivado*.log vivado_*.str vivado*.jou design *.bits *.dcp *.bit design.txt .Xil
rm -rf out_* *~
rm -rf *.frm *.segp *.packets *.bin
rm -rf harness_routed.fasm roi_inv_w_harness_routed.fasm
rm -rf hd_visual
.PHONY: clean

View File

@ -0,0 +1,53 @@
# FASM Proof of Concept using Vivado Partial Reconfig flow
top.v is a top-level design that routes a variety of signal into a black-box
region of interest (ROI). Vivado's Partial Reconfiguration flow (see UG909
and UG947) is used to implement that design and obtain a bitstream that
configures portions of the chip that are currently undocumented.
Designs that fit within the ROI are written in FASM and merged with the above
harness into a bitstream with fasm2frame and xc7patch.
# Usage
make rules are provided for generating each step of the process so that
intermediate forms can be analyzed. Assuming you have a .fasm file, invoking
the %.hand\_crafted.bit rule will generate a merged bitstream:
```
make foo.hand\_crafted.bit # reads foo.fasm
```
# Using Vivado to generate .fasm
Vivado's Partial Reconfiguration flow can be used to synthesize and implement a
design that is then converted to .fasm. The basic process is to write a module
that _exactly_ matches the roi blackbox in the top-level design. Note that
even the name of the module must match exactly. Once you have a design, the
first step is to synthesize the design with -mode out\_of\_context:
```
read_verilog <design>.v
synth_design -mode out_of_context -top roi -part $::env(XRAY_PART)
write_checkpoint -force <design>.dcp
```
Next, implement that design within the harness. Run 'make harness\_routed.dcp'
if it doesn't already exist. The following TCL will load the fully-routed
harness, load your synthesized design, and generate a bitstream containing
both:
```
open_checkpoint -force harness_routed.dcp
read_checkpoint -cell <design>.dcp
opt_design
place_design
route_design
write_checkpoint -force <design>_routed.dcp
write_bitstream -force <design>_routed.bit
```
'make <design>\_routed.fasm' will run a sequence of tools to extract the bits
that are inside the ROI and convert them to FASM. The resulting .fasm can be
used to generate a marged bitstream using
'make <design>\_routed.hand\_crafted.bit'. The resulting bitstream should be
equivalent to <design>\_routed.bit.

View File

@ -0,0 +1,8 @@
`ifndef DIN_N
`define DIN_N 8
`endif
`ifndef DOUT_N
`define DOUT_N 8
`endif

View File

@ -0,0 +1,5 @@
read_verilog top.v
read_verilog roi_base.v
synth_design -top top -part $::env(XRAY_PART)
write_checkpoint -force harness.dcp

View File

@ -0,0 +1,9 @@
//See README and tcl for more info
`include "defines.v"
module roi(input clk,
input [DIN_N-1:0] din, output [DOUT_N-1:0] dout);
parameter DIN_N = `DIN_N;
parameter DOUT_N = `DOUT_N;
endmodule

View File

@ -0,0 +1,3 @@
read_verilog roi_inv.v
synth_design -mode out_of_context -top roi -part $::env(XRAY_PART)
write_checkpoint -force roi_inv.dcp

View File

@ -0,0 +1,53 @@
//Connect the switches to the LEDs, inverting the signal in the ROI
//Assumes # inputs = # outputs
`include "defines.v"
module roi(input clk,
input [DIN_N-1:0] din, output [DOUT_N-1:0] dout);
parameter DIN_N = `DIN_N;
parameter DOUT_N = `DOUT_N;
wire [DIN_N-1:0] internal;
genvar i;
generate
//CLK
(* KEEP, DONT_TOUCH *)
reg clk_reg;
always @(posedge clk) begin
clk_reg <= clk_reg;
end
//DIN
for (i = 0; i < DIN_N; i = i+1) begin:ins
//Very expensive inverter
(* KEEP, DONT_TOUCH *)
LUT6 #(
.INIT(64'b01)
) lut (
.I0(din[i]),
.I1(1'b0),
.I2(1'b0),
.I3(1'b0),
.I4(1'b0),
.I5(1'b0),
.O(internal[i]));
end
//DOUT
for (i = 0; i < DOUT_N; i = i+1) begin:outs
//Very expensive buffer
(* KEEP, DONT_TOUCH *)
LUT6 #(
.INIT(64'b010)
) lut (
.I0(internal[i]),
.I1(1'b0),
.I2(1'b0),
.I3(1'b0),
.I4(1'b0),
.I5(1'b0),
.O(dout[i]));
end
endgenerate
endmodule

View File

@ -0,0 +1,149 @@
open_checkpoint harness.dcp
create_pblock roi
add_cells_to_pblock [get_pblocks roi] [get_cells roi]
resize_pblock [get_pblocks roi] -add "$::env(XRAY_ROI)"
set_property CFGBVS VCCO [current_design]
set_property CONFIG_VOLTAGE 3.3 [current_design]
# Number of package inputs going to ROI
set DIN_N 8
# Number of ROI outputs going to package
set DOUT_N 8
set part $::env(XRAY_PART)
set pincfg $::env(XRAY_PINCFG)
# Map of top level net names to IOB pin names
array set net2pin [list]
# Create pin assignments based on what we are targetting
# A50T I/O Bank 16 sequential layout
if {$part eq "xc7a50tfgg484-1"} {
# Partial list, expand as needed
set bank_16 "F21 G22 G21 D21 E21 D22 E22 A21 B21 B22 C22 C20 D20 F20 F19 A19 A18"
set banki 0
# CLK
set pin [lindex $bank_16 $banki]
incr banki
set net2pin(clk) $pin
# DIN
for {set i 0} {$i < $DIN_N} {incr i} {
set pin [lindex $bank_16 $banki]
incr banki
set net2pin(din[$i]) $pin
}
# DOUT
for {set i 0} {$i < $DOUT_N} {incr i} {
set pin [lindex $bank_16 $banki]
incr banki
set net2pin(dout[$i]) $pin
}
} elseif {$part eq "xc7a35tcsg324-1"} {
# Arty A7 switch, button, and LED
if {$pincfg eq "ARTY-A7-SWBUT"} {
# https://reference.digilentinc.com/reference/programmable-logic/arty/reference-manual?redirect=1
# 4 switches then 4 buttons
set sw_but "A8 C11 C10 A10 D9 C9 B9 B8"
# 4 LEDs then 4 RGB LEDs (green only)
set leds "H5 J5 T9 T10 F6 J4 J2 H6"
# 100 MHz CLK onboard
set pin "E3"
set net2pin(clk) $pin
# DIN
for {set i 0} {$i < $DIN_N} {incr i} {
set pin [lindex $sw_but $i]
set net2pin(din[$i]) $pin
}
# DOUT
for {set i 0} {$i < $DOUT_N} {incr i} {
set pin [lindex $leds $i]
set net2pin(dout[$i]) $pin
}
# Arty A7 pmod
# Disabled per above
} elseif {$pincfg eq "ARTY-A7-PMOD"} {
# https://reference.digilentinc.com/reference/programmable-logic/arty/reference-manual?redirect=1
set pmod_ja "G13 B11 A11 D12 D13 B18 A18 K16"
set pmod_jb "E15 E16 D15 C15 J17 J18 K15 J15"
set pmod_jc "U12 V12 V10 V11 U14 V14 T13 U13"
# CLK on Pmod JA
set pin [lindex $pmod_ja 0]
set net2pin(clk) $pin
# DIN on Pmod JB
for {set i 0} {$i < $DIN_N} {incr i} {
set pin [lindex $pmod_jb $i]
set net2pin(din[$i]) $pin
}
# DOUT on Pmod JC
for {set i 0} {$i < $DOUT_N} {incr i} {
set pin [lindex $pmod_jc $i]
set net2pin(dout[$i]) $pin
}
} else {
error "Unsupported config $pincfg"
}
} elseif {$part eq "xc7a35tcpg236-1"} {
if {$pincfg eq "BASYS3-SWBUT"} {
# https://raw.githubusercontent.com/Digilent/digilent-xdc/master/Basys-3-Master.xdc
# Slide switches
set sws "V17 V16 W16 W17 W15 V15 W14 W13 V2 T3 T2 R3 W2 U1 T1 R2"
set leds "U16 E19 U19 V19 W18 U15 U14 V14 V13 V3 W3 U3 P3 N3 P1 L1"
# 100 MHz CLK onboard
set pin "W5"
set net2pin(clk) $pin
# DIN
for {set i 0} {$i < $DIN_N} {incr i} {
set pin [lindex $sws $i]
set net2pin(din[$i]) $pin
}
# DOUT
for {set i 0} {$i < $DOUT_N} {incr i} {
set pin [lindex $leds $i]
set net2pin(dout[$i]) $pin
}
} else {
error "Unsupported config $pincfg"
}
} else {
error "Pins: unsupported part $part"
}
# Now actually apply the pin definitions
puts "Applying pin definitions"
foreach {net pin} [array get net2pin] {
puts " Net $net to pin $pin"
set_property -dict "PACKAGE_PIN $pin IOSTANDARD LVCMOS33" [get_ports $net]
}
set_property HD.RECONFIGURABLE TRUE [get_cells roi]
read_checkpoint -cell roi roi_inv.dcp
opt_design
place_design
route_design
write_checkpoint -force roi_inv_w_harness_routed.dcp
# Routed design of roi cell only
write_checkpoint -force -cell roi roi_inv_routed.dcp
# Replace roi cell with a black box and write the rest of the design
update_design -cell roi -black_box
lock_design -level routing
write_checkpoint -force harness_routed.dcp

View File

@ -0,0 +1,228 @@
INT_L_X10Y107.CENTER_INTER_L.SE6BEG0 NN6END0
INT_L_X10Y104.CENTER_INTER_L.WL1BEG0 NW2END2
INT_L_X10Y103.CENTER_INTER_L.EL1BEG0 NR1END1
INT_L_X10Y103.CENTER_INTER_L.EL1BEG_N3 NW2END0
INT_L_X10Y103.CENTER_INTER_L.FAN_ALT4 NR1END0
INT_L_X10Y103.CENTER_INTER_L.NE2BEG3 NL1BEG_N3
INT_L_X10Y103.CENTER_INTER_L.NL1BEG_N3 NL1END0
INT_L_X10Y103.CENTER_INTER_L.SE2BEG2 EL1END2
INT_L_X10Y103.CENTER_INTER_L.WW2BEG2 WL1END2
CLBLM_L_X10Y102.SLICE_X13Y102.ALUT.INIT[01] 1
CLBLM_L_X10Y102.SLICE_X13Y102.BLUT.INIT[01] 1
CLBLM_L_X10Y102.SLICE_X12Y102.ALUT.INIT[01] 1
CLBLM_L_X10Y102.SLICE_X12Y102.BLUT.INIT[01] 1
INT_L_X10Y102.CENTER_INTER_L.BYP_ALT5 NN2END2
INT_L_X10Y102.CENTER_INTER_L.EE2BEG2 NL1END2
INT_L_X10Y102.CENTER_INTER_L.EL1BEG_N3 NL1END0
INT_L_X10Y102.CENTER_INTER_L.GFAN0 GND_WIRE
INT_L_X10Y102.CENTER_INTER_L.GFAN1 GND_WIRE
INT_L_X10Y102.CENTER_INTER_L.IMUX_L0 GFAN0
INT_L_X10Y102.CENTER_INTER_L.IMUX_L1 GFAN0
INT_L_X10Y102.CENTER_INTER_L.IMUX_L10 GFAN0
INT_L_X10Y102.CENTER_INTER_L.IMUX_L11 GFAN0
INT_L_X10Y102.CENTER_INTER_L.IMUX_L12 GFAN1
INT_L_X10Y102.CENTER_INTER_L.IMUX_L13 GFAN1
INT_L_X10Y102.CENTER_INTER_L.IMUX_L14 NL1BEG_N3
INT_L_X10Y102.CENTER_INTER_L.IMUX_L15 FAN_BOUNCE_S3_4
INT_L_X10Y102.CENTER_INTER_L.IMUX_L16 GFAN0
INT_L_X10Y102.CENTER_INTER_L.IMUX_L17 GFAN0
INT_L_X10Y102.CENTER_INTER_L.IMUX_L18 GFAN0
INT_L_X10Y102.CENTER_INTER_L.IMUX_L19 GFAN0
INT_L_X10Y102.CENTER_INTER_L.IMUX_L2 GFAN0
INT_L_X10Y102.CENTER_INTER_L.IMUX_L24 GFAN0
INT_L_X10Y102.CENTER_INTER_L.IMUX_L25 GFAN0
INT_L_X10Y102.CENTER_INTER_L.IMUX_L26 GFAN0
INT_L_X10Y102.CENTER_INTER_L.IMUX_L27 GFAN0
INT_L_X10Y102.CENTER_INTER_L.IMUX_L3 GFAN0
INT_L_X10Y102.CENTER_INTER_L.IMUX_L4 GFAN1
INT_L_X10Y102.CENTER_INTER_L.IMUX_L5 GFAN1
INT_L_X10Y102.CENTER_INTER_L.IMUX_L6 WR1END3
INT_L_X10Y102.CENTER_INTER_L.IMUX_L7 BYP_BOUNCE5
INT_L_X10Y102.CENTER_INTER_L.IMUX_L8 GFAN0
INT_L_X10Y102.CENTER_INTER_L.IMUX_L9 GFAN0
INT_L_X10Y102.CENTER_INTER_L.NL1BEG0 LOGIC_OUTS_L9
INT_L_X10Y102.CENTER_INTER_L.NL1BEG_N3 LOGIC_OUTS_L8
INT_L_X10Y102.CENTER_INTER_L.NR1BEG0 LOGIC_OUTS_L12
INT_L_X10Y102.CENTER_INTER_L.NR1BEG1 LOGIC_OUTS_L13
INT_L_X10Y102.CENTER_INTER_L.SE2BEG2 EL1END2
INT_L_X10Y102.CENTER_INTER_L.SR1BEG2 WL1END1
INT_L_X10Y102.CENTER_INTER_L.SW2BEG3 WL1END3
INT_L_X10Y102.CENTER_INTER_L.WW2BEG2 WL1END2
CLBLM_L_X10Y101.SLICE_X13Y101.ALUT.INIT[01] 1
CLBLM_L_X10Y101.SLICE_X13Y101.BLUT.INIT[01] 1
CLBLM_L_X10Y101.SLICE_X12Y101.ALUT.INIT[01] 1
CLBLM_L_X10Y101.SLICE_X12Y101.BLUT.INIT[01] 1
INT_L_X10Y101.CENTER_INTER_L.BYP_ALT3 NL1BEG_N3
INT_L_X10Y101.CENTER_INTER_L.BYP_ALT4 NW2END1
INT_L_X10Y101.CENTER_INTER_L.ER1BEG2 LOGIC_OUTS_L13
INT_L_X10Y101.CENTER_INTER_L.GFAN0 GND_WIRE
INT_L_X10Y101.CENTER_INTER_L.GFAN1 GND_WIRE
INT_L_X10Y101.CENTER_INTER_L.IMUX_L0 GFAN0
INT_L_X10Y101.CENTER_INTER_L.IMUX_L1 GFAN0
INT_L_X10Y101.CENTER_INTER_L.IMUX_L10 GFAN0
INT_L_X10Y101.CENTER_INTER_L.IMUX_L11 GFAN0
INT_L_X10Y101.CENTER_INTER_L.IMUX_L12 GFAN1
INT_L_X10Y101.CENTER_INTER_L.IMUX_L13 GFAN1
INT_L_X10Y101.CENTER_INTER_L.IMUX_L14 SR1END2
INT_L_X10Y101.CENTER_INTER_L.IMUX_L15 BYP_BOUNCE3
INT_L_X10Y101.CENTER_INTER_L.IMUX_L16 GFAN0
INT_L_X10Y101.CENTER_INTER_L.IMUX_L17 GFAN0
INT_L_X10Y101.CENTER_INTER_L.IMUX_L18 GFAN0
INT_L_X10Y101.CENTER_INTER_L.IMUX_L19 GFAN0
INT_L_X10Y101.CENTER_INTER_L.IMUX_L2 GFAN0
INT_L_X10Y101.CENTER_INTER_L.IMUX_L24 GFAN0
INT_L_X10Y101.CENTER_INTER_L.IMUX_L25 GFAN0
INT_L_X10Y101.CENTER_INTER_L.IMUX_L26 GFAN0
INT_L_X10Y101.CENTER_INTER_L.IMUX_L27 GFAN0
INT_L_X10Y101.CENTER_INTER_L.IMUX_L3 GFAN0
INT_L_X10Y101.CENTER_INTER_L.IMUX_L4 GFAN1
INT_L_X10Y101.CENTER_INTER_L.IMUX_L5 GFAN1
INT_L_X10Y101.CENTER_INTER_L.IMUX_L6 BYP_BOUNCE4
INT_L_X10Y101.CENTER_INTER_L.IMUX_L7 NW2END_S0_0
INT_L_X10Y101.CENTER_INTER_L.IMUX_L8 GFAN0
INT_L_X10Y101.CENTER_INTER_L.IMUX_L9 GFAN0
INT_L_X10Y101.CENTER_INTER_L.LV_L18 SR1BEG_S0
INT_L_X10Y101.CENTER_INTER_L.NE2BEG1 NR1END1
INT_L_X10Y101.CENTER_INTER_L.NE2BEG3 NN6END3
INT_L_X10Y101.CENTER_INTER_L.NL1BEG0 LOGIC_OUTS_L9
INT_L_X10Y101.CENTER_INTER_L.NL1BEG2 WL1END2
INT_L_X10Y101.CENTER_INTER_L.NL1BEG_N3 LOGIC_OUTS_L8
INT_L_X10Y101.CENTER_INTER_L.NN6BEG0 LOGIC_OUTS_L12
INT_L_X10Y101.CENTER_INTER_L.SE2BEG2 EE2END2
INT_L_X10Y101.CENTER_INTER_L.SR1BEG_S0 WL1END3
CLBLM_L_X10Y100.SLICE_X13Y100.ALUT.INIT[01] 1
CLBLM_L_X10Y100.SLICE_X13Y100.BLUT.INIT[01] 1
CLBLM_L_X10Y100.SLICE_X12Y100.ALUT.INIT[01] 1
INT_L_X10Y100.CENTER_INTER_L.BYP_ALT1 LOGIC_OUTS_L8
INT_L_X10Y100.CENTER_INTER_L.BYP_ALT2 BYP_BOUNCE1
INT_L_X10Y100.CENTER_INTER_L.BYP_ALT3 NL1BEG_N3
INT_L_X10Y100.CENTER_INTER_L.EE2BEG3 NN6END3
INT_L_X10Y100.CENTER_INTER_L.ER1BEG1 SR1BEG_S0
INT_L_X10Y100.CENTER_INTER_L.GFAN0 GND_WIRE
INT_L_X10Y100.CENTER_INTER_L.GFAN1 GND_WIRE
INT_L_X10Y100.CENTER_INTER_L.IMUX_L0 GFAN0
INT_L_X10Y100.CENTER_INTER_L.IMUX_L1 GFAN0
INT_L_X10Y100.CENTER_INTER_L.IMUX_L10 GFAN0
INT_L_X10Y100.CENTER_INTER_L.IMUX_L11 GFAN0
INT_L_X10Y100.CENTER_INTER_L.IMUX_L13 GFAN1
INT_L_X10Y100.CENTER_INTER_L.IMUX_L14 BYP_BOUNCE2
INT_L_X10Y100.CENTER_INTER_L.IMUX_L16 GFAN0
INT_L_X10Y100.CENTER_INTER_L.IMUX_L19 GFAN0
INT_L_X10Y100.CENTER_INTER_L.IMUX_L2 GFAN0
INT_L_X10Y100.CENTER_INTER_L.IMUX_L25 GFAN0
INT_L_X10Y100.CENTER_INTER_L.IMUX_L26 GFAN0
INT_L_X10Y100.CENTER_INTER_L.IMUX_L3 GFAN0
INT_L_X10Y100.CENTER_INTER_L.IMUX_L4 GFAN1
INT_L_X10Y100.CENTER_INTER_L.IMUX_L5 GFAN1
INT_L_X10Y100.CENTER_INTER_L.IMUX_L6 SW2END2
INT_L_X10Y100.CENTER_INTER_L.IMUX_L7 BYP_BOUNCE3
INT_L_X10Y100.CENTER_INTER_L.IMUX_L8 GFAN0
INT_L_X10Y100.CENTER_INTER_L.IMUX_L9 GFAN0
INT_L_X10Y100.CENTER_INTER_L.NE2BEG0 LOGIC_OUTS_L12
INT_L_X10Y100.CENTER_INTER_L.NE2BEG3 NE6END3
INT_L_X10Y100.CENTER_INTER_L.NL1BEG_N3 WL1END_N1_3
INT_L_X10Y100.CENTER_INTER_L.NN2BEG2 WL1END1
INT_L_X10Y100.CENTER_INTER_L.NR1BEG1 LOGIC_OUTS_L9
INT_L_X10Y100.CENTER_INTER_L.SR1BEG_S0 WL1END3
INT_R_X11Y104.CENTER_INTER_R.SL1BEG3 NE2END3
INT_R_X11Y103.CENTER_INTER_R.NW2BEG2 NN2END2
INT_R_X11Y103.CENTER_INTER_R.SL1BEG0 EL1END0
INT_R_X11Y103.CENTER_INTER_R.WL1BEG2 SL1END3
INT_R_X11Y103.CENTER_INTER_R.WL1BEG_N3 WR1END1
CLBLM_R_X11Y102.SLICE_X14Y102.ALUT.INIT[01] 1
CLBLM_R_X11Y102.SLICE_X14Y102.BLUT.INIT[01] 1
INT_R_X11Y102.CENTER_INTER_R.EL1BEG0 LOGIC_OUTS13
INT_R_X11Y102.CENTER_INTER_R.GFAN0 GND_WIRE
INT_R_X11Y102.CENTER_INTER_R.GFAN1 GND_WIRE
INT_R_X11Y102.CENTER_INTER_R.IMUX1 GFAN0
INT_R_X11Y102.CENTER_INTER_R.IMUX11 GFAN0
INT_R_X11Y102.CENTER_INTER_R.IMUX12 GFAN1
INT_R_X11Y102.CENTER_INTER_R.IMUX15 EL1END3
INT_R_X11Y102.CENTER_INTER_R.IMUX17 GFAN0
INT_R_X11Y102.CENTER_INTER_R.IMUX18 GFAN0
INT_R_X11Y102.CENTER_INTER_R.IMUX2 GFAN0
INT_R_X11Y102.CENTER_INTER_R.IMUX24 GFAN0
INT_R_X11Y102.CENTER_INTER_R.IMUX27 GFAN0
INT_R_X11Y102.CENTER_INTER_R.IMUX4 GFAN1
INT_R_X11Y102.CENTER_INTER_R.IMUX7 WR1END3
INT_R_X11Y102.CENTER_INTER_R.IMUX8 GFAN0
INT_R_X11Y102.CENTER_INTER_R.NW2BEG0 LOGIC_OUTS12
INT_R_X11Y102.CENTER_INTER_R.SE2BEG1 NE2END1
INT_R_X11Y102.CENTER_INTER_R.SL1BEG2 SE2END2
INT_R_X11Y102.CENTER_INTER_R.SL1BEG3 NE2END3
INT_R_X11Y102.CENTER_INTER_R.WL1BEG1 NW2END3
INT_R_X11Y102.CENTER_INTER_R.WL1BEG2 WL1END3
INT_R_X11Y102.CENTER_INTER_R.WL1BEG_N3 SL1END0
INT_R_X11Y102.CENTER_INTER_R.WR1BEG3 NR1END2
CLBLM_R_X11Y101.SLICE_X14Y101.ALUT.INIT[01] 1
CLBLM_R_X11Y101.SLICE_X14Y101.AMUX.O6 1
CLBLM_R_X11Y101.SLICE_X14Y101.BLUT.INIT[01] 1
INT_R_X11Y101.CENTER_INTER_R.EE2BEG2 ER1END2
INT_R_X11Y101.CENTER_INTER_R.EL1BEG0 LOGIC_OUTS13
INT_R_X11Y101.CENTER_INTER_R.GFAN0 GND_WIRE
INT_R_X11Y101.CENTER_INTER_R.GFAN1 GND_WIRE
INT_R_X11Y101.CENTER_INTER_R.IMUX1 GFAN0
INT_R_X11Y101.CENTER_INTER_R.IMUX11 GFAN0
INT_R_X11Y101.CENTER_INTER_R.IMUX12 GFAN1
INT_R_X11Y101.CENTER_INTER_R.IMUX15 EL1END3
INT_R_X11Y101.CENTER_INTER_R.IMUX17 GFAN0
INT_R_X11Y101.CENTER_INTER_R.IMUX18 GFAN0
INT_R_X11Y101.CENTER_INTER_R.IMUX2 GFAN0
INT_R_X11Y101.CENTER_INTER_R.IMUX24 GFAN0
INT_R_X11Y101.CENTER_INTER_R.IMUX27 GFAN0
INT_R_X11Y101.CENTER_INTER_R.IMUX4 GFAN1
INT_R_X11Y101.CENTER_INTER_R.IMUX7 NR1END3
INT_R_X11Y101.CENTER_INTER_R.IMUX8 GFAN0
INT_R_X11Y101.CENTER_INTER_R.NN2BEG2 LOGIC_OUTS20
INT_R_X11Y101.CENTER_INTER_R.NR1BEG2 SE2END2
INT_R_X11Y101.CENTER_INTER_R.NW2BEG0 NE2END0
INT_R_X11Y101.CENTER_INTER_R.SL1BEG3 NE2END3
INT_R_X11Y101.CENTER_INTER_R.SR1BEG_S0 SL1END3
INT_R_X11Y101.CENTER_INTER_R.SW2BEG2 SL1END2
INT_R_X11Y101.CENTER_INTER_R.WL1BEG2 WR1END_S1_0
INT_R_X11Y101.CENTER_INTER_R.WL1BEG_N3 SR1BEG_S0
INT_R_X11Y101.CENTER_INTER_R.WW2BEG0 WL1END0
INT_R_X11Y101.CENTER_INTER_R.WW2BEG1 WL1END1
CLBLM_R_X11Y100.SLICE_X14Y100.ALUT.INIT[01] 1
INT_R_X11Y100.CENTER_INTER_R.BYP_ALT5 ER1END1
INT_R_X11Y100.CENTER_INTER_R.GFAN0 GND_WIRE
INT_R_X11Y100.CENTER_INTER_R.GFAN1 GND_WIRE
INT_R_X11Y100.CENTER_INTER_R.IMUX1 GFAN0
INT_R_X11Y100.CENTER_INTER_R.IMUX11 GFAN0
INT_R_X11Y100.CENTER_INTER_R.IMUX2 GFAN0
INT_R_X11Y100.CENTER_INTER_R.IMUX4 GFAN1
INT_R_X11Y100.CENTER_INTER_R.IMUX7 BYP_BOUNCE5
INT_R_X11Y100.CENTER_INTER_R.IMUX8 GFAN0
INT_R_X11Y100.CENTER_INTER_R.NL1BEG_N3 LOGIC_OUTS12
INT_R_X11Y100.CENTER_INTER_R.NR1BEG3 NL1BEG_N3
INT_R_X11Y100.CENTER_INTER_R.NW2BEG1 WL1END0
INT_R_X11Y100.CENTER_INTER_R.SR1BEG_S0 SL1END3
INT_R_X11Y100.CENTER_INTER_R.WL1BEG1 SE2END2
INT_R_X11Y100.CENTER_INTER_R.WL1BEG_N3 SR1BEG_S0
INT_L_X12Y103.CENTER_INTER_L.WL1BEG_N3 SE6END0
INT_L_X12Y103.CENTER_INTER_L.WR1BEG1 NR1END0
INT_L_X12Y102.CENTER_INTER_L.NR1BEG0 EL1END0
INT_L_X12Y102.CENTER_INTER_L.WR1BEG3 EE2END2
INT_L_X12Y101.CENTER_INTER_L.NW2BEG3 NR1END3
INT_L_X12Y101.CENTER_INTER_L.SE2BEG0 EL1END0
INT_L_X12Y101.CENTER_INTER_L.WL1BEG0 SE2END1
INT_L_X12Y101.CENTER_INTER_L.WL1BEG1 WR1END3
INT_L_X12Y101.CENTER_INTER_L.WR1BEG_S0 NE6END3
INT_L_X12Y100.CENTER_INTER_L.EL1BEG2 NE6END3
INT_L_X12Y100.CENTER_INTER_L.LV_L18 WR1END0
INT_L_X12Y100.CENTER_INTER_L.NR1BEG3 EE2END3
INT_L_X12Y100.CENTER_INTER_L.SW6BEG3 LV_L18
INT_L_X12Y100.CENTER_INTER_L.WL1BEG0 WR1END2
INT_R_X13Y101.CENTER_INTER_R.WR1BEG3 EE2END2
INT_R_X13Y100.CENTER_INTER_R.SL1BEG2 EL1END2
INT_R_X13Y100.CENTER_INTER_R.WL1BEG_N3 SE2END0
INT_R_X13Y100.CENTER_INTER_R.WR1BEG2 NR1END1
INT_L_X16Y100.CENTER_INTER_L.ER1BEG1 SR1BEG_S0
INT_L_X16Y100.CENTER_INTER_L.SR1BEG_S0 WL1END3
INT_R_X17Y101.CENTER_INTER_R.WL1BEG_N3 WW2END0
CLBLL_R_X17Y100.SLICE_X27Y100.AFF.DMUX.AX 1
CLBLL_R_X17Y100.SLICE_X27Y100.AFF.ZINI 1
CLBLL_R_X17Y100.SLICE_X27Y100.AFF.ZRST 1
CLBLL_R_X17Y100.SLICE_X27Y100.FFSYNC 1
INT_R_X17Y100.CENTER_INTER_R.BYP_ALT0 LOGIC_OUTS0
INT_R_X17Y100.CENTER_INTER_R.CLK0 ER1END1

View File

@ -0,0 +1,14 @@
//See README and tcl for more info
`include "defines.v"
module top(input wire clk,
input [DIN_N-1:0] din, output [DOUT_N-1:0] dout);
parameter DIN_N = `DIN_N;
parameter DOUT_N = `DOUT_N;
roi #(.DIN_N(DIN_N), .DOUT_N(DOUT_N)) roi (
.clk(clk),
.din(din), .dout(dout));
endmodule

View File

@ -0,0 +1,27 @@
open_checkpoint [lindex $argv 0]
# Disabling CRC just replaces the CRC register writes with Reset CRC commands.
# This seems to work via JTAG as it works in combination with PERFRAMECRC
# either when applied via Vivado (this setting) or by manually patching the
# bitstream later.
#
set_property BITSTREAM.GENERAL.CRC Disable [current_design]
# Debug bitstreams write to LOUT which is only valid on serial master/slave
# programming methods. If those are replaced with NOPs, Reset CRC commands, or
# removed entirely, the bitstream will program (DONE light goes active) but the
# configuration doesn't start. The JTAG status register shows BAD_PACKET_ERROR
# when this happens. I'm guessing that the individual frame writes require the
# PERFRAMECRC approach to work at all via JTAG.
#
#set_property BITSTREAM.GENERAL.DEBUGBITSTREAM YES [current_design]
# PERFRAMECRC bitstreams can be directly loaded via JTAG. They also use an
# undocumented bit to disable autoincrement which seems to be required if doing
# individual frame writes instead of a bulk write. The CRC chceks after each
# frame are _required_ for this bitstream to program.
#
#set_property BITSTREAM.GENERAL.PERFRAMECRC YES [current_design]
write_bitstream -force [lindex $argv 1]

View File

@ -17,3 +17,10 @@ target_link_libraries(gen_part_base_yaml
libprjxray
yaml-cpp
)
add_executable(xc7patch xc7patch.cc)
target_link_libraries(xc7patch
absl::strings
gflags
libprjxray
)

View File

@ -178,6 +178,8 @@ def run(f_in, f_out, sparse=False, debug=False):
return '%s.%s.%s' % (tilej['type'], suffix, value)
tile2dbkey = {
'CLBLL_L': clb2dbkey,
'CLBLL_R': clb2dbkey,
'CLBLM_L': clb2dbkey,
'CLBLM_R': clb2dbkey,
'INT_L': int2dbkey,

View File

@ -37,6 +37,8 @@ def tag2fasm(grid, seg, tag):
which = m.group(1)
value = m.group(2)
site = {
'clbll_l': 'CENTER_INTER_L',
'clbll_r': 'CENTER_INTER_R',
'clblm_l': 'CENTER_INTER_L',
'clblm_r': 'CENTER_INTER_R',
'hclk_l': 'HCLK_L',
@ -56,6 +58,8 @@ def tag2fasm(grid, seg, tag):
raise Exception("Couldn't find tile type %s" % tile_type)
tag2asm = {
'CLBLL_L': clbf,
'CLBLL_R': clbf,
'CLBLM_L': clbf,
'CLBLM_R': clbf,
'INT_L': intf,

210
tools/xc7patch.cc Normal file
View File

@ -0,0 +1,210 @@
#include <algorithm>
#include <fstream>
#include <iostream>
#include <iterator>
#include <string>
#include <vector>
#include <absl/strings/str_split.h>
#include <gflags/gflags.h>
#include <prjxray/memory_mapped_file.h>
#include <prjxray/xilinx/xc7series/bitstream_reader.h>
#include <prjxray/xilinx/xc7series/bitstream_writer.h>
#include <prjxray/xilinx/xc7series/configuration.h>
#include <prjxray/xilinx/xc7series/part.h>
DEFINE_string(part_file, "", "Definition file for target 7-series part");
DEFINE_string(bitstream_file,
"",
"Initial bitstream to which the deltas are applied.");
DEFINE_string(
frm_file,
"",
"File containing a list of frame deltas to be applied to the base "
"bitstream. Each line in the file is of the form: "
"<frame_address> <word1>,...,<word101>.");
DEFINE_string(output_file, "", "Write patched bitsteam to file");
namespace xc7series = prjxray::xilinx::xc7series;
int main(int argc, char* argv[]) {
gflags::SetUsageMessage(argv[0]);
gflags::ParseCommandLineFlags(&argc, &argv, true);
auto part = xc7series::Part::FromFile(FLAGS_part_file);
if (!part) {
std::cerr << "Part file not found or invalid" << std::endl;
return 1;
}
auto bitstream_file =
prjxray::MemoryMappedFile::InitWithFile(FLAGS_bitstream_file);
if (!bitstream_file) {
std::cerr << "Can't open base bitstream file: "
<< FLAGS_bitstream_file << std::endl;
return 1;
}
auto bitstream_reader = xc7series::BitstreamReader::InitWithBytes(
bitstream_file->as_bytes());
if (!bitstream_reader) {
std::cout
<< "Bitstream does not appear to be a 7-series bitstream!"
<< std::endl;
return 1;
}
auto bitstream_config =
xc7series::Configuration::InitWithPackets(*part, *bitstream_reader);
if (!bitstream_config) {
std::cerr << "Bitstream does not appear to be for this part"
<< std::endl;
return 1;
}
// Copy the base frames to a mutable collection
std::map<xc7series::FrameAddress, std::vector<uint32_t>> frames;
for (auto& frame_val : bitstream_config->frames()) {
auto& cur_frame = frames[frame_val.first];
std::copy(frame_val.second.begin(), frame_val.second.end(),
std::back_inserter(cur_frame));
}
// Apply the deltas.
std::ifstream frm_file(FLAGS_frm_file);
if (!frm_file) {
std::cerr << "Unable to open frm file: " << FLAGS_frm_file
<< std::endl;
return 1;
}
std::string frm_line;
while (std::getline(frm_file, frm_line)) {
if (frm_line[0] == '#')
continue;
std::pair<std::string, std::string> frame_delta =
absl::StrSplit(frm_line, ' ');
uint32_t frame_address =
std::stoul(frame_delta.first, nullptr, 16);
auto& frame_data = frames[frame_address];
frame_data.resize(101);
std::vector<std::string> frame_data_strings =
absl::StrSplit(frame_delta.second, ',');
if (frame_data_strings.size() != 101) {
std::cerr << "Frame " << std::hex << frame_address
<< ": found " << std::dec
<< frame_data_strings.size()
<< "words instead of 101";
continue;
};
std::transform(frame_data_strings.begin(),
frame_data_strings.end(), frame_data.begin(),
[](const std::string& val) -> uint32_t {
return std::stoul(val, nullptr, 16);
});
uint32_t ecc = 0;
for (size_t ii = 0; ii < frame_data.size(); ++ii) {
uint32_t word = frame_data[ii];
uint32_t offset = ii * 32;
if (ii > 0x25) {
offset += 0x1360;
} else if (ii > 0x6) {
offset += 0x1340;
} else {
offset += 0x1320;
}
// Mask out where the ECC should be.
if (ii == 0x32) {
word &= 0xFFFFE000;
}
for (int jj = 0; jj < 32; ++jj) {
if ((word & 1) == 1) {
ecc ^= offset + jj;
}
word >>= 1;
}
}
uint32_t v = ecc & 0xFFF;
v ^= v >> 8;
v ^= v >> 4;
v ^= v >> 2;
v ^= v >> 1;
ecc ^= (v & 1) << 12;
// Replace the old ECC with the new.
frame_data[0x32] &= 0xFFFFE000;
frame_data[0x32] |= (ecc & 0x1FFF);
}
#if 0
for (auto& frame : frames) {
std::cout << "0x" << std::hex
<< static_cast<uint32_t>(frame.first) << " ";
for (auto& word : frame.second) {
std::cout << "0x" << std::hex << word << ",";
}
std::cout << std::endl;
}
#endif
std::vector<xc7series::ConfigurationPacket> out_packets;
// Generate a single type 2 packet that writes everything at once.
std::vector<uint32_t> packet_data;
for (auto& frame : frames) {
std::copy(frame.second.begin(), frame.second.end(),
std::back_inserter(packet_data));
auto next_address = part->GetNextFrameAddress(frame.first);
if (next_address &&
(next_address->block_type() != frame.first.block_type() ||
next_address->is_bottom_half_rows() !=
frame.first.is_bottom_half_rows() ||
next_address->row() != frame.first.row())) {
packet_data.insert(packet_data.end(), 202, 0);
}
}
packet_data.insert(packet_data.end(), 202, 0);
out_packets.push_back(xc7series::ConfigurationPacket(
1, xc7series::ConfigurationPacket::Opcode::Write,
xc7series::ConfigurationRegister::FDRI, {}));
out_packets.push_back(xc7series::ConfigurationPacket(
2, xc7series::ConfigurationPacket::Opcode::Write,
xc7series::ConfigurationRegister::FDRI, packet_data));
#if 0
for (auto& packet : out_packets) {
std::cout << packet << std::endl;
}
#endif
// Write bitstream.
xc7series::BitstreamWriter out_bitstream_writer(out_packets);
std::ofstream out_file(FLAGS_output_file);
if (!out_file) {
std::cerr << "Unable to open file for writting: "
<< FLAGS_output_file << std::endl;
return 1;
}
for (uint32_t word : out_bitstream_writer) {
out_file.put((word >> 24) & 0xFF);
out_file.put((word >> 16) & 0xFF);
out_file.put((word >> 8) & 0xFF);
out_file.put((word)&0xFF);
}
return 0;
}