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: b8dcb589dfdc
Choose a base ref
...
head repository: azonenberg/openfpga
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 6049fa6f3971
Choose a head ref
  • 16 commits
  • 9 files changed
  • 1 contributor

Commits on Jun 8, 2017

  1. Copy the full SHA
    ae2cf4f View commit details
  2. Copy the full SHA
    368ae67 View commit details
  3. Copy the full SHA
    ea22558 View commit details
  4. Copy the full SHA
    d5c27d1 View commit details
  5. Copy the full SHA
    b5dcbb7 View commit details
  6. xc2bit: Rename XC2MCOBufMode to XC2IOBOBufMode

    This is more related to the IO pin rather than the macrocell
    ArcaneNibble committed Jun 8, 2017
    Copy the full SHA
    01a51f5 View commit details
  7. xc2bit: Move special product terms back to FB again

    They belong with the function block, not a particular macrocell
    ArcaneNibble committed Jun 8, 2017
    Copy the full SHA
    f228f3d View commit details
  8. xc2bit: Start documenting macrocell stuff; rename XC2MCFF -> XC2MCReg

    A latch isn't a flip-flop, so this new name should be more appropriate
    ArcaneNibble committed Jun 8, 2017
    Copy the full SHA
    0ba5b51 View commit details
  9. Copy the full SHA
    990b1c3 View commit details
  10. xc2bit: More macrocell documentation and another rename

    This struct contains information about the entire macrocell, not just
    the register.
    ArcaneNibble committed Jun 8, 2017
    Copy the full SHA
    d94e125 View commit details
  11. Copy the full SHA
    3101eb9 View commit details
  12. Copy the full SHA
    227e526 View commit details
  13. Copy the full SHA
    034e57b View commit details
  14. Copy the full SHA
    362ff0b View commit details
  15. Copy the full SHA
    36d0d5e View commit details
  16. Copy the full SHA
    6049fa6 View commit details
Showing with 573 additions and 364 deletions.
  1. +6 −0 src/xc2bit/Cargo.toml
  2. +98 −55 src/xc2bit/src/bitstream.rs
  3. +49 −42 src/xc2bit/src/fb.rs
  4. +225 −0 src/xc2bit/src/iob.rs
  5. +3 −3 src/xc2bit/src/jed.rs
  6. +36 −6 src/xc2bit/src/lib.rs
  7. +104 −234 src/xc2bit/src/mc.rs
  8. +34 −17 src/xc2bit/src/pla.rs
  9. +18 −7 src/xc2bit/src/zia.rs
6 changes: 6 additions & 0 deletions src/xc2bit/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
[package]
name = "xc2bit"
version = "0.0.1"
authors = ["Robert Ou <rqou@robertou.com>"]
license = "BSD-2-Clause"
description = "A library for working with Xilinx Coolrunner-II bitstreams"
repository = "https://github.com/azonenberg/openfpga/tree/master/src/xc2bit"
keywords = ["coolrunner", "cpld", "xilinx", "bitstream", "eda"]
categories = ["command-line-utilities", "parser-implementations"]

[profile.release]
lto = true
153 changes: 98 additions & 55 deletions src/xc2bit/src/bitstream.rs
Original file line number Diff line number Diff line change
@@ -29,23 +29,26 @@ use std::io::Write;

use *;
use fb::{read_32_fb_logical};
use mc::{read_32_iob_logical, read_32_extra_ibuf_logical, fb_ff_num_to_iob_num_32};
use iob::{read_32_iob_logical, read_32_extra_ibuf_logical};
use zia::{encode_32_zia_choice};

/// Toplevel struct representing an entire Coolrunner-II bitstream
pub struct XC2Bitstream {
pub speed_grade: String,
pub package: String,
pub bits: XC2BitstreamBits,
}

impl XC2Bitstream {
/// Dump a human-readable explanation of the bitstream to the given `writer` object.
pub fn dump_human_readable(&self, writer: &mut Write) {
write!(writer, "xc2bit dump\n").unwrap();
write!(writer, "device speed grade: {}\n", self.speed_grade).unwrap();
write!(writer, "device package: {}\n", self.package).unwrap();
self.bits.dump_human_readable(writer);
}

/// Write a .jed representation of the bitstream to the given `writer` object.
pub fn write_jed(&self, writer: &mut Write) {
write!(writer, ".JED fuse map written by xc2bit\n").unwrap();
write!(writer, "https://github.com/azonenberg/openfpga\n\n").unwrap();
@@ -67,6 +70,7 @@ impl XC2Bitstream {
write!(writer, "\x030000\n").unwrap();
}

/// Construct a new blank bitstream of the given part
pub fn blank_bitstream(device: &str, speed_grade: &str, package: &str) -> Result<XC2Bitstream, &'static str> {
// TODO: Validate speed_grade and package

@@ -76,7 +80,7 @@ impl XC2Bitstream {
speed_grade: speed_grade.to_owned(),
package: package.to_owned(),
bits: XC2BitstreamBits::XC2C32 {
fb: [XC2BistreamFB::default(); 2],
fb: [XC2BitstreamFB::default(); 2],
iobs: [XC2MCSmallIOB::default(); 32],
inpin: XC2ExtraIBuf::default(),
global_nets: XC2GlobalNets::default(),
@@ -90,7 +94,7 @@ impl XC2Bitstream {
speed_grade: speed_grade.to_owned(),
package: package.to_owned(),
bits: XC2BitstreamBits::XC2C32A {
fb: [XC2BistreamFB::default(); 2],
fb: [XC2BitstreamFB::default(); 2],
iobs: [XC2MCSmallIOB::default(); 32],
inpin: XC2ExtraIBuf::default(),
global_nets: XC2GlobalNets::default(),
@@ -106,19 +110,31 @@ impl XC2Bitstream {
}
}

/// Represents the configuration of the global nets. Coolrunner-II parts have various global control signals that have
/// dedicated low-skew paths.
pub struct XC2GlobalNets {
/// Controls whether the three global clock nets are enabled or not
pub gck_enable: [bool; 3],
/// Controls whether the global set/reset net is enabled or not
pub gsr_enable: bool,
// false = active low, true = active high
/// Controls the polarity of the global set/reset signal
///
/// `false` = active low, `true` = active high
pub gsr_invert: bool,
/// Controls whether the four global tristate nets are enabled or not
pub gts_enable: [bool; 4],
// false = used as T, true = used as !T
/// Controls the polarity of the global tristate signal
///
/// `false` = used as T, `true` = used as !T
pub gts_invert: [bool; 4],
// false = keeper, true = pull-up
/// Controls the mode of the global termination
///
/// `false` = keeper, `true` = pull-up
pub global_pu: bool,
}

impl Default for XC2GlobalNets {
/// Returns a "default" global net configuration which has everything disabled.
fn default() -> XC2GlobalNets {
XC2GlobalNets {
gck_enable: [false; 3],
@@ -132,6 +148,7 @@ impl Default for XC2GlobalNets {
}

impl XC2GlobalNets {
/// Dump a human-readable explanation of the global net configuration to the given `writer` object.
pub fn dump_human_readable(&self, writer: &mut Write) {
write!(writer, "\n").unwrap();
write!(writer, "GCK0 {}\n", if self.gck_enable[0] {"enabled"} else {"disabled"}).unwrap();
@@ -159,6 +176,7 @@ impl XC2GlobalNets {
}
}

/// Internal function to read the global nets from a 32-macrocell part
fn read_32_global_nets_logical(fuses: &[bool]) -> XC2GlobalNets {
XC2GlobalNets {
gck_enable: [
@@ -184,30 +202,48 @@ fn read_32_global_nets_logical(fuses: &[bool]) -> XC2GlobalNets {
}
}

/// The actual bitstream bits for each possible Coolrunner-II part
pub enum XC2BitstreamBits {
XC2C32 {
fb: [XC2BistreamFB; 2],
fb: [XC2BitstreamFB; 2],
iobs: [XC2MCSmallIOB; 32],
inpin: XC2ExtraIBuf,
global_nets: XC2GlobalNets,
// false = low, true = high
/// Voltage level control
///
/// `false` = low, `true` = high
ivoltage: bool,
/// Voltage level control
///
/// `false` = low, `true` = high
ovoltage: bool,
},
XC2C32A {
fb: [XC2BistreamFB; 2],
fb: [XC2BitstreamFB; 2],
iobs: [XC2MCSmallIOB; 32],
inpin: XC2ExtraIBuf,
global_nets: XC2GlobalNets,
// false = low, true = high
/// Legacy voltage level control, should almost always be set to `false`
///
/// `false` = low, `true` = high
legacy_ivoltage: bool,
/// Legacy voltage level control, should almost always be set to `false`
///
/// `false` = low, `true` = high
legacy_ovoltage: bool,
/// Voltage level control for each I/O bank
///
/// `false` = low, `true` = high
ivoltage: [bool; 2],
/// Voltage level control for each I/O bank
///
/// `false` = low, `true` = high
ovoltage: [bool; 2],
},
}

impl XC2BitstreamBits {
/// Dump a human-readable explanation of the bitstream to the given `writer` object.
pub fn dump_human_readable(&self, writer: &mut Write) {
match self {
&XC2BitstreamBits::XC2C32 {
@@ -252,6 +288,7 @@ impl XC2BitstreamBits {
}
}

/// Write a .jed representation of the bitstream to the given `writer` object.
pub fn write_jed(&self, writer: &mut Write) {
match self {
&XC2BitstreamBits::XC2C32 {
@@ -266,7 +303,7 @@ impl XC2BitstreamBits {
let fuse_base = if fb_i == 0 {0} else {6128};

// ZIA
for i in 0..40 {
for i in 0..INPUTS_PER_ANDTERM {
write!(writer, "L{:06} ", fuse_base + i * 8).unwrap();
let zia_choice_bits =
encode_32_zia_choice(i as u32, fb[fb_i].zia_bits[i].selected)
@@ -285,9 +322,10 @@ impl XC2BitstreamBits {
write!(writer, "\n").unwrap();

// AND terms
for i in 0..56 {
write!(writer, "L{:06} ", fuse_base + 8 * 40 + i * 80).unwrap();
for j in 0..40 {
for i in 0..ANDTERMS_PER_FB {
write!(writer, "L{:06} ",
fuse_base + 8 * INPUTS_PER_ANDTERM + i * INPUTS_PER_ANDTERM * 2).unwrap();
for j in 0..INPUTS_PER_ANDTERM {
if fb[fb_i].and_terms[i].input[j] {
write!(writer, "0").unwrap();
} else {
@@ -304,9 +342,11 @@ impl XC2BitstreamBits {
write!(writer, "\n").unwrap();

// OR terms
for i in 0..56 {
write!(writer, "L{:06} ", fuse_base + 8 * 40 + 56 * 80 + i * 16).unwrap();
for j in 0..16 {
for i in 0..ANDTERMS_PER_FB {
write!(writer, "L{:06} ",
fuse_base + 8 * INPUTS_PER_ANDTERM +
ANDTERMS_PER_FB * INPUTS_PER_ANDTERM * 2 + i * MCS_PER_FB).unwrap();
for j in 0..MCS_PER_FB {
if fb[fb_i].or_terms[j].input[i] {
write!(writer, "0").unwrap();
} else {
@@ -318,53 +358,55 @@ impl XC2BitstreamBits {
write!(writer, "\n").unwrap();

// Macrocells
for i in 0..16 {
write!(writer, "L{:06} ", fuse_base + 8 * 40 + 56 * 80 + 56 * 16 + i * 27).unwrap();
for i in 0..MCS_PER_FB {
write!(writer, "L{:06} ",
fuse_base + 8 * INPUTS_PER_ANDTERM +
ANDTERMS_PER_FB * INPUTS_PER_ANDTERM * 2 + ANDTERMS_PER_FB * MCS_PER_FB + i * 27).unwrap();

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

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

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

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

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

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

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

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

// inz
@@ -400,16 +442,16 @@ impl XC2BitstreamBits {

// oe
write!(writer, "{}", match iobs[iob].obuf_mode {
XC2MCOBufMode::PushPull => "0000",
XC2MCOBufMode::OpenDrain => "0001",
XC2MCOBufMode::TriStateGTS1 => "0010",
XC2MCOBufMode::TriStatePTB => "0100",
XC2MCOBufMode::TriStateGTS3 => "0110",
XC2MCOBufMode::TriStateCTE => "1000",
XC2MCOBufMode::TriStateGTS2 => "1010",
XC2MCOBufMode::TriStateGTS0 => "1100",
XC2MCOBufMode::CGND => "1110",
XC2MCOBufMode::Disabled => "1111",
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",
}).unwrap();

// tm
@@ -470,8 +512,9 @@ impl XC2BitstreamBits {
}
}

/// Internal function for parsing an XC2C32 bitstream
pub fn read_32_bitstream_logical(fuses: &[bool]) -> Result<XC2BitstreamBits, &'static str> {
let mut fb = [XC2BistreamFB::default(); 2];
let mut fb = [XC2BitstreamFB::default(); 2];
for i in 0..fb.len() {
let res = read_32_fb_logical(fuses, i);
if let Err(err) = res {
@@ -482,12 +525,12 @@ pub fn read_32_bitstream_logical(fuses: &[bool]) -> Result<XC2BitstreamBits, &'s

let mut iobs = [XC2MCSmallIOB::default(); 32];
for i in 0..iobs.len() {
let base_fuse = if i < 16 {
let base_fuse = if i < MCS_PER_FB {
5696
} else {
11824
};
let res = read_32_iob_logical(fuses, base_fuse, i % 16);
let res = read_32_iob_logical(fuses, base_fuse, i % MCS_PER_FB);
if let Err(err) = res {
return Err(err);
}
@@ -508,9 +551,9 @@ pub fn read_32_bitstream_logical(fuses: &[bool]) -> Result<XC2BitstreamBits, &'s
})
}


/// Internal function for parsing an XC2C32A bitstream
pub fn read_32a_bitstream_logical(fuses: &[bool]) -> Result<XC2BitstreamBits, &'static str> {
let mut fb = [XC2BistreamFB::default(); 2];
let mut fb = [XC2BitstreamFB::default(); 2];
for i in 0..fb.len() {
let res = read_32_fb_logical(fuses, i);
if let Err(err) = res {
@@ -521,12 +564,12 @@ pub fn read_32a_bitstream_logical(fuses: &[bool]) -> Result<XC2BitstreamBits, &'

let mut iobs = [XC2MCSmallIOB::default(); 32];
for i in 0..iobs.len() {
let base_fuse = if i < 16 {
let base_fuse = if i < MCS_PER_FB {
5696
} else {
11824
};
let res = read_32_iob_logical(fuses, base_fuse, i % 16);
let res = read_32_iob_logical(fuses, base_fuse, i % MCS_PER_FB);
if let Err(err) = res {
return Err(err);
}
Loading