Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: azonenberg/openfpga
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 06feeed2484d
Choose a base ref
...
head repository: azonenberg/openfpga
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: c52f45cb9376
Choose a head ref
  • 8 commits
  • 7 files changed
  • 1 contributor

Commits on Jun 10, 2017

  1. Copy the full SHA
    5e78cbe View commit details
  2. Copy the full SHA
    cb3e1fb View commit details
  3. Copy the full SHA
    fdf3e1b View commit details
  4. Copy the full SHA
    4fd447d View commit details
  5. Copy the full SHA
    75223b8 View commit details
  6. Copy the full SHA
    c714173 View commit details
  7. xc2bit: Use the ? operator in a few more places

    Still needs a future improvement with a custom error type rather than a
    string
    ArcaneNibble committed Jun 10, 2017
    Copy the full SHA
    14cb561 View commit details
  8. Copy the full SHA
    c52f45c View commit details
Showing with 752 additions and 896 deletions.
  1. +242 −822 src/xc2bit/src/bitstream.rs
  2. +95 −63 src/xc2bit/src/fb.rs
  3. +110 −0 src/xc2bit/src/fusemap_logical.rs
  4. +11 −11 src/xc2bit/src/iob.rs
  5. +2 −0 src/xc2bit/src/lib.rs
  6. +266 −0 src/xc2bit/src/mc.rs
  7. +26 −0 src/xc2bit/src/partdb.rs
1,064 changes: 242 additions & 822 deletions src/xc2bit/src/bitstream.rs

Large diffs are not rendered by default.

158 changes: 95 additions & 63 deletions src/xc2bit/src/fb.rs
Original file line number Diff line number Diff line change
@@ -31,7 +31,8 @@ use std::io::Write;
use *;
use pla::{read_and_term_logical, read_or_term_logical};
use mc::{read_small_ff_logical, read_large_ff_logical, read_large_buried_ff_logical};
use zia::{read_32_zia_fb_row_logical, read_64_zia_fb_row_logical, read_128_zia_fb_row_logical, zia_get_row_width};
use zia::{encode_32_zia_choice, encode_64_zia_choice, encode_128_zia_choice,
read_32_zia_fb_row_logical, read_64_zia_fb_row_logical, read_128_zia_fb_row_logical, zia_get_row_width};

/// Represents a collection of all the parts that make up one function block
#[derive(Copy)]
@@ -62,14 +63,14 @@ impl Default for XC2BitstreamFB {
}

impl XC2BitstreamFB {
/// Dump a human-readable explanation of the settings for this pin to the given `writer` object.
/// Dump a human-readable explanation of the settings for this FB to the given `writer` object.
/// `device` must be the device type this FB was extracted from and is needed to decode I/O pin numbers.
/// `fb` must be the index of this function block.
pub fn dump_human_readable(&self, device: XC2Device, fb: u32, writer: &mut Write) -> Result<(), io::Error> {
for i in 0..MCS_PER_FB {
self.ffs[i].dump_human_readable(fb, i as u32, writer)?;
}

// FIXME: Move this somewhere else?
write!(writer, "\n")?;
write!(writer, "ZIA inputs for FB{}\n", fb + 1)?;
for i in 0..INPUTS_PER_ANDTERM {
@@ -87,7 +88,6 @@ impl XC2BitstreamFB {
}
}

// FIXME: Move this somewhere else?
write!(writer, "\n")?;
write!(writer, "AND terms for FB{}\n", fb + 1)?;
write!(writer, " | 0| ~0| 1| ~1| 2| ~2| 3| ~3| 4| ~4| 5| ~5| 6| ~6| 7| ~7| 8| ~8| 9| ~9| 10|~10| \
@@ -113,7 +113,6 @@ impl XC2BitstreamFB {
write!(writer, "\n")?;
}

// FIXME: Move this somewhere else?
write!(writer, "\n")?;
write!(writer, "OR terms for FB{}\n", fb + 1)?;
write!(writer, " | 0| 1| 2| 3| 4| 5| 6| 7| 8| 9|10|11|12|13|14|15|16|17|18|19|20|\
@@ -133,72 +132,103 @@ impl XC2BitstreamFB {

Ok(())
}
}

/// Internal function that reads a function block for "small" (32/64-macrocell) devices
pub fn read_small_fb_logical(device: XC2Device, fuses: &[bool], block_idx: usize)
-> Result<XC2BitstreamFB, &'static str> {

let zia_row_width = zia_get_row_width(device);
let size_of_zia = zia_row_width * INPUTS_PER_ANDTERM;
let size_of_and = INPUTS_PER_ANDTERM * 2 * ANDTERMS_PER_FB;
let size_of_or = ANDTERMS_PER_FB * MCS_PER_FB;
let size_of_mc = MCS_PER_FB * 27;
let size_of_each_fb = size_of_zia + size_of_and + size_of_or + size_of_mc;

let zia_row_read_function = match device {
XC2Device::XC2C32 | XC2Device::XC2C32A => read_32_zia_fb_row_logical,
XC2Device::XC2C64 | XC2Device::XC2C64A => read_64_zia_fb_row_logical,
_ => unreachable!(),
};

let mut and_terms = [XC2PLAAndTerm::default(); ANDTERMS_PER_FB];
let and_block_idx = block_idx * size_of_each_fb + size_of_zia;
for i in 0..and_terms.len() {
and_terms[i] = read_and_term_logical(fuses, and_block_idx, i);
}
/// Write the .JED representation of the settings for this FB to the given `writer` object.
/// `device` must be the device type this FB was extracted from and is needed to encode the ZIA.
/// `fuse_base` must be the starting fuse number of this function block.
pub fn write_to_jed(&self, device: XC2Device, fuse_base: usize, writer: &mut Write) -> Result<(), io::Error> {
// ZIA
let zia_row_width = zia_get_row_width(device);
for i in 0..INPUTS_PER_ANDTERM {
write!(writer, "L{:06} ", fuse_base + i * zia_row_width)?;
match device {
XC2Device::XC2C32 | XC2Device::XC2C32A => {
let zia_choice_bits = encode_32_zia_choice(i as u32, self.zia_bits[i].selected)
// FIXME: Fold this into the error system??
.expect("invalid ZIA input");
for j in 0..zia_choice_bits.len() {
write!(writer, "{}", if zia_choice_bits[zia_choice_bits.len() - 1 - j] {"1"} else {"0"})?;
}
},
XC2Device::XC2C64 | XC2Device::XC2C64A => {
let zia_choice_bits = encode_64_zia_choice(i as u32, self.zia_bits[i].selected)
// FIXME: Fold this into the error system??
.expect("invalid ZIA input");
for j in 0..zia_choice_bits.len() {
write!(writer, "{}", if zia_choice_bits[zia_choice_bits.len() - 1 - j] {"1"} else {"0"})?;
}
},
XC2Device::XC2C128 => {
let zia_choice_bits = encode_128_zia_choice(i as u32, self.zia_bits[i].selected)
// FIXME: Fold this into the error system??
.expect("invalid ZIA input");
for j in 0..zia_choice_bits.len() {
write!(writer, "{}", if zia_choice_bits[zia_choice_bits.len() - 1 - j] {"1"} else {"0"})?;
}
},
_ => unreachable!(),
}
write!(writer, "*\n")?;
}
write!(writer, "\n")?;

let mut or_terms = [XC2PLAOrTerm::default(); MCS_PER_FB];
let or_block_idx = block_idx * size_of_each_fb + size_of_zia + size_of_and;
for i in 0..or_terms.len() {
or_terms[i] = read_or_term_logical(fuses, or_block_idx, i);
}
// AND terms
for i in 0..ANDTERMS_PER_FB {
write!(writer, "L{:06} ",
fuse_base + zia_row_width * INPUTS_PER_ANDTERM + i * INPUTS_PER_ANDTERM * 2)?;
for j in 0..INPUTS_PER_ANDTERM {
if self.and_terms[i].input[j] {
write!(writer, "0")?;
} else {
write!(writer, "1")?;
}
if self.and_terms[i].input_b[j] {
write!(writer, "0")?;
} else {
write!(writer, "1")?;
}
}
write!(writer, "*\n")?;
}
write!(writer, "\n")?;

let mut zia_bits = [XC2ZIARowPiece::default(); INPUTS_PER_ANDTERM];
let zia_block_idx = block_idx * size_of_each_fb;
for i in 0..zia_bits.len() {
let result = zia_row_read_function(fuses, zia_block_idx, i);
if let Err(err) = result {
return Err(err);
// OR terms
for i in 0..ANDTERMS_PER_FB {
write!(writer, "L{:06} ",
fuse_base + zia_row_width * INPUTS_PER_ANDTERM +
ANDTERMS_PER_FB * INPUTS_PER_ANDTERM * 2 + i * MCS_PER_FB)?;
for j in 0..MCS_PER_FB {
if self.or_terms[j].input[i] {
write!(writer, "0")?;
} else {
write!(writer, "1")?;
}
}
write!(writer, "*\n")?;
}
zia_bits[i] = result.unwrap();
}
write!(writer, "\n")?;

let mut ff_bits = [XC2Macrocell::default(); MCS_PER_FB];
let ff_block_idx = block_idx * size_of_each_fb + size_of_zia + size_of_and + size_of_or;
for i in 0..ff_bits.len() {
ff_bits[i] = read_small_ff_logical(fuses, ff_block_idx, i);
Ok(())
}


Ok(XC2BitstreamFB {
and_terms: and_terms,
or_terms: or_terms,
zia_bits: zia_bits,
ffs: ff_bits,
})
}

/// Internal function that reads a function block for "large" (>=128-macrocell) devices
pub fn read_large_fb_logical(device: XC2Device, fuses: &[bool], fb: u32, fuse_base: usize)
/// Internal function that reads a function block
pub fn read_fb_logical(device: XC2Device, fuses: &[bool], fb: u32, fuse_base: usize)
-> Result<XC2BitstreamFB, &'static str> {

let zia_row_width = zia_get_row_width(device);
let size_of_zia = zia_row_width * INPUTS_PER_ANDTERM;
let size_of_and = INPUTS_PER_ANDTERM * 2 * ANDTERMS_PER_FB;
let size_of_or = ANDTERMS_PER_FB * MCS_PER_FB;

let device_is_large = match device {
XC2Device::XC2C32 | XC2Device::XC2C32A | XC2Device::XC2C64 | XC2Device::XC2C64A => false,
_ => true,
};

let zia_row_read_function = match device {
XC2Device::XC2C32 | XC2Device::XC2C32A => read_32_zia_fb_row_logical,
XC2Device::XC2C64 | XC2Device::XC2C64A => read_64_zia_fb_row_logical,
XC2Device::XC2C128 => read_128_zia_fb_row_logical,
_ => unreachable!(),
};
@@ -218,25 +248,27 @@ pub fn read_large_fb_logical(device: XC2Device, fuses: &[bool], fb: u32, fuse_ba
let mut zia_bits = [XC2ZIARowPiece::default(); INPUTS_PER_ANDTERM];
let zia_block_idx = fuse_base;
for i in 0..zia_bits.len() {
let result = zia_row_read_function(fuses, zia_block_idx, i);
if let Err(err) = result {
return Err(err);
}
zia_bits[i] = result.unwrap();
let result = zia_row_read_function(fuses, zia_block_idx, i)?;
zia_bits[i] = result;
}

let mut ff_bits = [XC2Macrocell::default(); MCS_PER_FB];
let ff_block_idx = fuse_base + size_of_zia + size_of_and + size_of_or;
let mut cur_ff_idx = ff_block_idx;
for i in 0..ff_bits.len() {
if fb_ff_num_to_iob_num(device, fb, i as u32).is_none() {
// Buried
// Buried (must be large)
ff_bits[i] = read_large_buried_ff_logical(fuses, cur_ff_idx);
cur_ff_idx += 16;
} else {
// Not buried
ff_bits[i] = read_large_ff_logical(fuses, cur_ff_idx);
cur_ff_idx += 29;
if device_is_large {
ff_bits[i] = read_large_ff_logical(fuses, cur_ff_idx);
cur_ff_idx += 29;
} else {
ff_bits[i] = read_small_ff_logical(fuses, ff_block_idx, i);
cur_ff_idx += 27;
}
}
}

110 changes: 110 additions & 0 deletions src/xc2bit/src/fusemap_logical.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
/*
Copyright (c) 2016-2017, Robert Ou <rqou@robertou.com> and contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

use *;

/// Helper function that returns the first fuse for a given function block. This is made more complicated by buried
/// macrocells in the larger devices
pub fn fb_fuse_idx(device: XC2Device, fb: u32) -> usize {
match device {
XC2Device::XC2C32 | XC2Device::XC2C32A => {
match fb {
0 => 0,
1 => 6128,
_ => unreachable!(),
}
},
XC2Device::XC2C64 | XC2Device::XC2C64A => {
match fb {
0 => 0,
1 => 6448,
2 => 12896,
3 => 19344,
_ => unreachable!(),
}
},
XC2Device::XC2C128 => {
match fb {
0 => 0,
1 => 6908,
2 => 13816,
3 => 20737,
4 => 27658,
5 => 34579,
6 => 41487,
7 => 48408,
_ => unreachable!(),
}
}
_ => unreachable!(),
}
}

pub fn gck_fuse_idx(device: XC2Device) -> usize {
match device {
XC2Device::XC2C32 | XC2Device::XC2C32A => 12256,
XC2Device::XC2C64 | XC2Device::XC2C64A => 25792,
XC2Device::XC2C128 => 55316,
_ => unreachable!(),
}
}

pub fn gsr_fuse_idx(device: XC2Device) -> usize {
match device {
XC2Device::XC2C32 | XC2Device::XC2C32A => 12259,
XC2Device::XC2C64 | XC2Device::XC2C64A => 25795,
XC2Device::XC2C128 => 55324,
_ => unreachable!(),
}
}

pub fn gts_fuse_idx(device: XC2Device) -> usize {
match device {
XC2Device::XC2C32 | XC2Device::XC2C32A => 12261,
XC2Device::XC2C64 | XC2Device::XC2C64A => 25797,
XC2Device::XC2C128 => 55326,
_ => unreachable!(),
}
}

pub fn global_term_fuse_idx(device: XC2Device) -> usize {
match device {
XC2Device::XC2C32 | XC2Device::XC2C32A => 12269,
XC2Device::XC2C64 | XC2Device::XC2C64A => 25805,
XC2Device::XC2C128 => 55334,
_ => unreachable!(),
}
}

pub fn total_logical_fuse_count(device: XC2Device) -> usize {
match device {
XC2Device::XC2C32 => 12274,
XC2Device::XC2C32A => 12278,
XC2Device::XC2C64 => 25808,
XC2Device::XC2C64A => 25812,
XC2Device::XC2C128 => 55341,
_ => unreachable!(),
}
}
22 changes: 11 additions & 11 deletions src/xc2bit/src/iob.rs
Original file line number Diff line number Diff line change
@@ -364,22 +364,22 @@ pub fn fb_ff_num_to_iob_num(device: XC2Device, fb: u32, ff: u32) -> Option<u32>
}

/// Internal function that reads only the IO-related bits from the macrocell configuration
pub fn read_small_iob_logical(fuses: &[bool], block_idx: usize, io_idx: usize) -> Result<XC2MCSmallIOB, &'static str> {
let inz = (fuses[block_idx + io_idx * 27 + 11],
fuses[block_idx + io_idx * 27 + 12]);
pub fn read_small_iob_logical(fuses: &[bool], fuse_idx: usize) -> Result<XC2MCSmallIOB, &'static str> {
let inz = (fuses[fuse_idx + 11],
fuses[fuse_idx + 12]);
let input_to_zia = match inz {
(false, false) => XC2IOBZIAMode::PAD,
(true, false) => XC2IOBZIAMode::REG,
(_, true) => XC2IOBZIAMode::Disabled,
};

let st = fuses[block_idx + io_idx * 27 + 16];
let regcom = fuses[block_idx + io_idx * 27 + 19];
let st = fuses[fuse_idx + 16];
let regcom = fuses[fuse_idx + 19];

let oe = (fuses[block_idx + io_idx * 27 + 20],
fuses[block_idx + io_idx * 27 + 21],
fuses[block_idx + io_idx * 27 + 22],
fuses[block_idx + io_idx * 27 + 23]);
let oe = (fuses[fuse_idx + 20],
fuses[fuse_idx + 21],
fuses[fuse_idx + 22],
fuses[fuse_idx + 23]);
let output_mode = match oe {
(false, false, false, false) => XC2IOBOBufMode::PushPull,
(false, false, false, true) => XC2IOBOBufMode::OpenDrain,
@@ -394,8 +394,8 @@ pub fn read_small_iob_logical(fuses: &[bool], block_idx: usize, io_idx: usize) -
_ => return Err("unknown Oe mode used"),
};

let tm = fuses[block_idx + io_idx * 27 + 24];
let slw = fuses[block_idx + io_idx * 27 + 25];
let tm = fuses[fuse_idx + 24];
let slw = fuses[fuse_idx + 25];

Ok(XC2MCSmallIOB {
zia_mode: input_to_zia,
2 changes: 2 additions & 0 deletions src/xc2bit/src/lib.rs
Original file line number Diff line number Diff line change
@@ -58,6 +58,8 @@ pub use bitstream::{XC2Bitstream, XC2BitstreamBits, XC2GlobalNets, XC2ClockDivRa
mod fb;
pub use fb::{XC2BitstreamFB, CTC, CTR, CTS, CTE, get_pta, get_ptb, get_ptc};

mod fusemap_logical;

mod iob;
pub use iob::{XC2MCSmallIOB, XC2IOBZIAMode, XC2IOBOBufMode, XC2ExtraIBuf, XC2IOBIbufMode, XC2MCLargeIOB,
iob_num_to_fb_ff_num, fb_ff_num_to_iob_num};
266 changes: 266 additions & 0 deletions src/xc2bit/src/mc.rs
Original file line number Diff line number Diff line change
@@ -28,6 +28,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
use std::io;
use std::io::Write;

use *;
use zia::{zia_get_row_width};

/// Clock source for the register in a macrocell
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum XC2MCRegClkSrc {
@@ -439,3 +442,266 @@ pub fn read_large_buried_ff_logical(fuses: &[bool], fuse_idx: usize) -> XC2Macro
xor_mode: xormode,
}
}

/// Helper that prints the IOB and macrocell configuration on the "small" parts
pub fn write_small_mc_to_jed(writer: &mut Write, device: XC2Device, fb: &XC2BitstreamFB, iobs: &[XC2MCSmallIOB],
fb_i: usize, fuse_base: usize) -> Result<(), io::Error> {

let zia_row_width = zia_get_row_width(device);

for i in 0..MCS_PER_FB {
write!(writer, "L{:06} ",
fuse_base + zia_row_width * INPUTS_PER_ANDTERM +
ANDTERMS_PER_FB * INPUTS_PER_ANDTERM * 2 + ANDTERMS_PER_FB * MCS_PER_FB + i * 27)?;

let iob = fb_ff_num_to_iob_num(device, fb_i as u32, i as u32).unwrap() as usize;

// aclk
write!(writer, "{}", match fb.ffs[i].clk_src {
XC2MCRegClkSrc::CTC => "1",
_ => "0",
})?;

// clkop
write!(writer, "{}", if fb.ffs[i].clk_invert_pol {"1"} else {"0"})?;

// clk
write!(writer, "{}", match fb.ffs[i].clk_src {
XC2MCRegClkSrc::GCK0 => "00",
XC2MCRegClkSrc::GCK1 => "01",
XC2MCRegClkSrc::GCK2 => "10",
XC2MCRegClkSrc::PTC | XC2MCRegClkSrc::CTC => "11",
})?;

// clkfreq
write!(writer, "{}", if fb.ffs[i].is_ddr {"1"} else {"0"})?;

// r
write!(writer, "{}", match fb.ffs[i].r_src {
XC2MCRegResetSrc::PTA => "00",
XC2MCRegResetSrc::GSR => "01",
XC2MCRegResetSrc::CTR => "10",
XC2MCRegResetSrc::Disabled => "11",
})?;

// p
write!(writer, "{}", match fb.ffs[i].s_src {
XC2MCRegSetSrc::PTA => "00",
XC2MCRegSetSrc::GSR => "01",
XC2MCRegSetSrc::CTS => "10",
XC2MCRegSetSrc::Disabled => "11",
})?;

// regmod
write!(writer, "{}", match fb.ffs[i].reg_mode {
XC2MCRegMode::DFF => "00",
XC2MCRegMode::LATCH => "01",
XC2MCRegMode::TFF => "10",
XC2MCRegMode::DFFCE => "11",
})?;

// inz
write!(writer, "{}", match iobs[iob].zia_mode {
XC2IOBZIAMode::PAD => "00",
XC2IOBZIAMode::REG => "10",
XC2IOBZIAMode::Disabled => "11",
})?;

// fb
write!(writer, "{}", match fb.ffs[i].fb_mode {
XC2MCFeedbackMode::COMB => "00",
XC2MCFeedbackMode::REG => "10",
XC2MCFeedbackMode::Disabled => "11",
})?;

// inreg
write!(writer, "{}", if fb.ffs[i].ff_in_ibuf {"0"} else {"1"})?;

// st
write!(writer, "{}", if iobs[iob].schmitt_trigger {"1"} else {"0"})?;

// xorin
write!(writer, "{}", match fb.ffs[i].xor_mode {
XC2MCXorMode::ZERO => "00",
XC2MCXorMode::PTCB => "01",
XC2MCXorMode::PTC => "10",
XC2MCXorMode::ONE => "11",
})?;

// regcom
write!(writer, "{}", if iobs[iob].obuf_uses_ff {"0"} else {"1"})?;

// oe
write!(writer, "{}", match iobs[iob].obuf_mode {
XC2IOBOBufMode::PushPull => "0000",
XC2IOBOBufMode::OpenDrain => "0001",
XC2IOBOBufMode::TriStateGTS1 => "0010",
XC2IOBOBufMode::TriStatePTB => "0100",
XC2IOBOBufMode::TriStateGTS3 => "0110",
XC2IOBOBufMode::TriStateCTE => "1000",
XC2IOBOBufMode::TriStateGTS2 => "1010",
XC2IOBOBufMode::TriStateGTS0 => "1100",
XC2IOBOBufMode::CGND => "1110",
XC2IOBOBufMode::Disabled => "1111",
})?;

// tm
write!(writer, "{}", if iobs[iob].termination_enabled {"1"} else {"0"})?;

// slw
write!(writer, "{}", if iobs[iob].slew_is_fast {"0"} else {"1"})?;

// pu
write!(writer, "{}", if fb.ffs[i].init_state {"0"} else {"1"})?;

write!(writer, "*\n")?;
}
write!(writer, "\n")?;

Ok(())
}

/// Helper that prints the IOB and macrocell configuration on the "large" parts
pub fn write_large_mc_to_jed(writer: &mut Write, device: XC2Device, fb: &XC2BitstreamFB, iobs: &[XC2MCLargeIOB],
fb_i: usize, fuse_base: usize) -> Result<(), io::Error> {

let zia_row_width = zia_get_row_width(device);

let mut current_fuse_offset = fuse_base + zia_row_width * INPUTS_PER_ANDTERM +
ANDTERMS_PER_FB * INPUTS_PER_ANDTERM * 2 + ANDTERMS_PER_FB * MCS_PER_FB;

for i in 0..MCS_PER_FB {
write!(writer, "L{:06} ", current_fuse_offset)?;

let iob = fb_ff_num_to_iob_num(device, fb_i as u32, i as u32);

// aclk
write!(writer, "{}", match fb.ffs[i].clk_src {
XC2MCRegClkSrc::CTC => "1",
_ => "0",
})?;

// clk
write!(writer, "{}", match fb.ffs[i].clk_src {
XC2MCRegClkSrc::GCK0 => "00",
XC2MCRegClkSrc::GCK1 => "01",
XC2MCRegClkSrc::GCK2 => "10",
XC2MCRegClkSrc::PTC | XC2MCRegClkSrc::CTC => "11",
})?;

// clkfreq
write!(writer, "{}", if fb.ffs[i].is_ddr {"1"} else {"0"})?;

// clkop
write!(writer, "{}", if fb.ffs[i].clk_invert_pol {"1"} else {"0"})?;

// dg
if iob.is_some() {
write!(writer, "{}", if iobs[iob.unwrap() as usize].uses_data_gate {"1"} else {"0"})?;
}

// fb
write!(writer, "{}", match fb.ffs[i].fb_mode {
XC2MCFeedbackMode::COMB => "00",
XC2MCFeedbackMode::REG => "10",
XC2MCFeedbackMode::Disabled => "11",
})?;

if iob.is_some() {
let iob = iob.unwrap() as usize;

// inmod
write!(writer, "{}", match iobs[iob].ibuf_mode {
XC2IOBIbufMode::NoVrefNoSt => "00",
XC2IOBIbufMode::IsVref => "01",
XC2IOBIbufMode::UsesVref => "10",
XC2IOBIbufMode::NoVrefSt => "11",
})?;

// inreg
write!(writer, "{}", if fb.ffs[i].ff_in_ibuf {"0"} else {"1"})?;

// inz
write!(writer, "{}", match iobs[iob].zia_mode {
XC2IOBZIAMode::PAD => "00",
XC2IOBZIAMode::REG => "10",
XC2IOBZIAMode::Disabled => "11",
})?;

// oe
write!(writer, "{}", match iobs[iob].obuf_mode {
XC2IOBOBufMode::PushPull => "0000",
XC2IOBOBufMode::OpenDrain => "0001",
XC2IOBOBufMode::TriStateGTS1 => "0010",
XC2IOBOBufMode::TriStatePTB => "0100",
XC2IOBOBufMode::TriStateGTS3 => "0110",
XC2IOBOBufMode::TriStateCTE => "1000",
XC2IOBOBufMode::TriStateGTS2 => "1010",
XC2IOBOBufMode::TriStateGTS0 => "1100",
XC2IOBOBufMode::CGND => "1110",
XC2IOBOBufMode::Disabled => "1111",
})?;
}

// p
write!(writer, "{}", match fb.ffs[i].s_src {
XC2MCRegSetSrc::PTA => "00",
XC2MCRegSetSrc::GSR => "01",
XC2MCRegSetSrc::CTS => "10",
XC2MCRegSetSrc::Disabled => "11",
})?;

// pu
write!(writer, "{}", if fb.ffs[i].init_state {"0"} else {"1"})?;

if iob.is_some() {
// regcom
write!(writer, "{}", if iobs[iob.unwrap() as usize].obuf_uses_ff {"0"} else {"1"})?;
}

// regmod
write!(writer, "{}", match fb.ffs[i].reg_mode {
XC2MCRegMode::DFF => "00",
XC2MCRegMode::LATCH => "01",
XC2MCRegMode::TFF => "10",
XC2MCRegMode::DFFCE => "11",
})?;

// r
write!(writer, "{}", match fb.ffs[i].r_src {
XC2MCRegResetSrc::PTA => "00",
XC2MCRegResetSrc::GSR => "01",
XC2MCRegResetSrc::CTR => "10",
XC2MCRegResetSrc::Disabled => "11",
})?;

if iob.is_some() {
let iob = iob.unwrap() as usize;

// slw
write!(writer, "{}", if iobs[iob].slew_is_fast {"0"} else {"1"})?;

// tm
write!(writer, "{}", if iobs[iob].termination_enabled {"1"} else {"0"})?;
}

// xorin
write!(writer, "{}", match fb.ffs[i].xor_mode {
XC2MCXorMode::ZERO => "00",
XC2MCXorMode::PTCB => "01",
XC2MCXorMode::PTC => "10",
XC2MCXorMode::ONE => "11",
})?;

write!(writer, "*\n")?;

if iob.is_some() {
current_fuse_offset += 29;
} else {
current_fuse_offset += 16;
}
}
write!(writer, "\n")?;

Ok(())
}
26 changes: 26 additions & 0 deletions src/xc2bit/src/partdb.rs
Original file line number Diff line number Diff line change
@@ -47,6 +47,32 @@ impl fmt::Display for XC2Device {
}
}

impl XC2Device {
/// Returns the number of function blocks for the device type
pub fn num_fbs(&self) -> usize {
match *self {
XC2Device::XC2C32 | XC2Device::XC2C32A => 2,
XC2Device::XC2C64 | XC2Device::XC2C64A => 4,
XC2Device::XC2C128 => 8,
XC2Device::XC2C256 => 16,
XC2Device::XC2C384 => 24,
XC2Device::XC2C512 => 32,
}
}

/// Returns the number of I/O pins for the device type
pub fn num_iobs(&self) -> usize {
match *self {
XC2Device::XC2C32 | XC2Device::XC2C32A => 32,
XC2Device::XC2C64 | XC2Device::XC2C64A => 64,
XC2Device::XC2C128 => 100,
XC2Device::XC2C256 => 184,
XC2Device::XC2C384 => 240,
XC2Device::XC2C512 => 270,
}
}
}

/// Possible speed grades
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum XC2Speed {