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: 8a4cc7048640
Choose a base ref
...
head repository: azonenberg/openfpga
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 85c1d9a4158f
Choose a head ref

Commits on Jun 6, 2017

  1. xc2bit: Initial commit

    ArcaneNibble committed Jun 6, 2017
    Copy the full SHA
    eac55c8 View commit details
  2. Copy the full SHA
    7ab293d View commit details
  3. Copy the full SHA
    7a12381 View commit details
  4. Copy the full SHA
    fcf4820 View commit details
  5. Copy the full SHA
    69190f7 View commit details
  6. Copy the full SHA
    7333ae8 View commit details
  7. Copy the full SHA
    257c8ca View commit details
  8. Copy the full SHA
    83fd2b4 View commit details
  9. Copy the full SHA
    17b0d0c View commit details
  10. Copy the full SHA
    3a9242e View commit details
  11. Copy the full SHA
    f91b84a View commit details
  12. Copy the full SHA
    3619ea2 View commit details
  13. Copy the full SHA
    d39ad24 View commit details
  14. Copy the full SHA
    7d634cc View commit details
  15. Copy the full SHA
    955d1e6 View commit details
  16. Copy the full SHA
    7649887 View commit details
  17. Copy the full SHA
    4575838 View commit details
  18. Copy the full SHA
    e65ec71 View commit details
  19. xc2bit: Expose ZIA map

    ArcaneNibble committed Jun 6, 2017
    Copy the full SHA
    d02f09d View commit details
  20. Copy the full SHA
    c67b94a View commit details
  21. Copy the full SHA
    076e2c3 View commit details
  22. Copy the full SHA
    476582b View commit details

Commits on Jun 7, 2017

  1. Merge pull request #92 from rqou/xc2bit_only

    Merged xc2bit from rqou
    azonenberg authored Jun 7, 2017
    Copy the full SHA
    85c1d9a View commit details
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -8,3 +8,6 @@
/debian/gp4par-dbg/
/debian/gp4par-doc/
/obj-*/

# Because these are library crates, do not check in their Cargo.lock files
/src/xc2bit/Cargo.lock
18 changes: 18 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -9,6 +9,7 @@ include(GNUInstallDirs)
# Project configuration
set(YOSYS_COMMAND "yosys" CACHE STRING "Command used to run yosys")
set(IVERILOG_COMMAND "iverilog" CACHE STRING "Command used to run Icarus Verilog")
set(CARGO_COMMAND "cargo" CACHE STRING "Command used to run cargo")

set(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}/bin)
set(LIBRARY_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}/bin)
@@ -88,6 +89,23 @@ endif()
# FORCE is required for the "asked for but missing tool" case
set(BUILD_TESTS ${BUILD_TESTS} CACHE BOOL "Build and run tests" FORCE)

find_program(CARGO ${CARGO_COMMAND})
if(DEFINED BUILD_RUST AND NOT BUILD_RUST)
message(STATUS "BUILD_RUST turned off, Rust code will not be built nor run")
elseif(DEFINED BUILD_RUST AND BUILD_RUST AND NOT CARGO)
message(WARNING "BUILD_RUST turned on but no cargo found, Rust code will not be built nor run")
set(BUILD_RUST OFF)
elseif(NOT DEFINED BUILD_RUST AND NOT CARGO)
message(WARNING "cargo not found, Rust code will not be built nor run")
set(BUILD_RUST OFF)
else()
message(STATUS "Rust enabled")
set(BUILD_RUST ON)
endif()

# FORCE is required for the "asked for but missing tool" case
set(BUILD_RUST ${BUILD_RUST} CACHE BOOL "Build and run Rust code" FORCE)

# Subdirectories
add_subdirectory(src)
if(BUILD_TESTS)
6 changes: 6 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -7,3 +7,9 @@ add_subdirectory(xbpar)
add_subdirectory(log)
add_subdirectory(gpcosim)
add_subdirectory(xptools)

if(BUILD_RUST)
add_custom_target(xc2bit ALL
${CMAKE_COMMAND} -E env CARGO_TARGET_DIR=${CMAKE_CURRENT_BINARY_DIR}/xc2bit ${CARGO} build
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/src/xc2bit)
endif()
10 changes: 10 additions & 0 deletions src/xc2bit/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[package]
name = "xc2bit"
version = "0.0.1"

[profile.release]
lto = true

[lib]
name = "xc2bit"
crate-type = ["rlib"]
33 changes: 33 additions & 0 deletions src/xc2bit/src/bin/xc2jedblank.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
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.
*/

extern crate xc2bit;
use xc2bit::*;

fn main() {
let bitstream = XC2Bitstream::blank_bitstream("XC2C32A", "6", "VQ44").expect("failed to create bitstream");

bitstream.write_jed(&mut ::std::io::stdout());
}
53 changes: 53 additions & 0 deletions src/xc2bit/src/bin/xc2jeddump.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
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 std::fs::File;
use std::io::Read;

extern crate xc2bit;
use xc2bit::*;

fn main() {
let args = ::std::env::args().collect::<Vec<_>>();

if args.len() != 2 {
println!("Usage: {} file.jed", args[0]);
::std::process::exit(1);
}

// Read the entire file
let mut f = File::open(&args[1]).expect("failed to open file");
let mut data = Vec::new();
f.read_to_end(&mut data).expect("failed to read data");

let bits_result = read_jed(&data);
let (bits, device_name_option) = bits_result.expect("failed to read jed");
let device_name = device_name_option.expect("missing device name in jed");

let bitstream_result = process_jed(&bits, &device_name);
let bitstream = bitstream_result.expect("failed to process jed");

bitstream.dump_human_readable(&mut ::std::io::stdout());
}
53 changes: 53 additions & 0 deletions src/xc2bit/src/bin/xc2jedroundtrip.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
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 std::fs::File;
use std::io::Read;

extern crate xc2bit;
use xc2bit::*;

fn main() {
let args = ::std::env::args().collect::<Vec<_>>();

if args.len() != 2 {
println!("Usage: {} file.jed", args[0]);
::std::process::exit(1);
}

// Read the entire file
let mut f = File::open(&args[1]).expect("failed to open file");
let mut data = Vec::new();
f.read_to_end(&mut data).expect("failed to read data");

let bits_result = read_jed(&data);
let (bits, device_name_option) = bits_result.expect("failed to read jed");
let device_name = device_name_option.expect("missing device name in jed");

let bitstream_result = process_jed(&bits, &device_name);
let bitstream = bitstream_result.expect("failed to process jed");

bitstream.write_jed(&mut ::std::io::stdout());
}
556 changes: 556 additions & 0 deletions src/xc2bit/src/bitstream.rs

Large diffs are not rendered by default.

210 changes: 210 additions & 0 deletions src/xc2bit/src/fb.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
/*
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.
*/

// Function block

use std::io::Write;

use *;
use pla::{read_and_term_logical, read_or_term_logical};
use mc::{read_32_ff_logical, iob_num_to_fb_ff_num_32};
use zia::{read_32_zia_fb_row_logical};

#[derive(Copy)]
pub struct XC2BistreamFB {
pub and_terms: [XC2PLAAndTerm; 56],
pub or_terms: [XC2PLAOrTerm; 16],
pub zia_bits: [XC2ZIARowPiece; 40],
pub ffs: [XC2MCFF; 16],
}

impl Clone for XC2BistreamFB {
fn clone(&self) -> XC2BistreamFB {*self}
}

impl Default for XC2BistreamFB {
fn default() -> XC2BistreamFB {
XC2BistreamFB {
and_terms: [XC2PLAAndTerm::default(); 56],
or_terms: [XC2PLAOrTerm::default(); 16],
zia_bits: [XC2ZIARowPiece::default(); 40],
ffs: [XC2MCFF::default(); 16],
}
}
}

impl XC2BistreamFB {
pub fn dump_human_readable(&self, fb: u32, writer: &mut Write) {
for i in 0..16 {
self.ffs[i].dump_human_readable(fb, i as u32, writer);
}

// FIXME: Move this somewhere else?
write!(writer, "\n").unwrap();
write!(writer, "ZIA inputs for FB{}\n", fb + 1).unwrap();
for i in 0..40 {
write!(writer, "{:2}: ", i).unwrap();
match self.zia_bits[i].selected {
XC2ZIAInput::Zero => write!(writer, "0\n").unwrap(),
XC2ZIAInput::One => write!(writer, "1\n").unwrap(),
XC2ZIAInput::Macrocell{fb, ff} =>
write!(writer, "FB{}_{} FF\n", fb + 1, ff + 1).unwrap(),
XC2ZIAInput::IBuf{ibuf} => {
let (fb, ff) = iob_num_to_fb_ff_num_32(ibuf).unwrap();
write!(writer, "FB{}_{} pad\n", fb + 1, ff + 1).unwrap();
},
XC2ZIAInput::DedicatedInput => write!(writer, "dedicated input\n").unwrap(),
}
}

// FIXME: Move this somewhere else?
write!(writer, "\n").unwrap();
write!(writer, "AND terms for FB{}\n", fb + 1).unwrap();
write!(writer, " | 0| ~0| 1| ~1| 2| ~2| 3| ~3| 4| ~4| 5| ~5| 6| ~6| 7| ~7| 8| ~8| 9| ~9| 10|~10| \
11|~11| 12|~12| 13|~13| 14|~14| 15|~15| 16|~16| 17|~17| 18|~18| 19|~19| 20|~20| \
21|~21| 22|~22| 23|~23| 24|~24| 25|~25| 26|~26| 27|~27| 28|~28| 29|~29| 30|~30| \
31|~31| 32|~32| 33|~33| 34|~34| 35|~35| 36|~36| 37|~37| 38|~38| 39|~39\
\n").unwrap();
for i in 0..56 {
write!(writer, "{:2}:", i).unwrap();
for j in 0..40 {
if self.and_terms[i].input[j] {
write!(writer, "|XXX").unwrap();
} else {
write!(writer, "| ").unwrap();
}

if self.and_terms[i].input_b[j] {
write!(writer, "|XXX").unwrap();
} else {
write!(writer, "| ").unwrap();
}
}
write!(writer, "\n").unwrap();
}

// FIXME: Move this somewhere else?
write!(writer, "\n").unwrap();
write!(writer, "OR terms for FB{}\n", fb + 1).unwrap();
write!(writer, " | 0| 1| 2| 3| 4| 5| 6| 7| 8| 9|10|11|12|13|14|15|16|17|18|19|20|\
21|22|23|24|25|26|27|28|29|30|31|32|33|34|35|36|37|38|39|40|\
41|42|43|44|45|46|47|48|49|50|51|52|53|54|55\n").unwrap();
for i in 0..16 {
write!(writer, "{:2}:", i).unwrap();
for j in 0..56 {
if self.or_terms[i].input[j] {
write!(writer, "|XX").unwrap();
} else {
write!(writer, "| ").unwrap();
}
}
write!(writer, "\n").unwrap();
}
}
}


pub fn read_32_fb_logical(fuses: &[bool], block_idx: usize) -> Result<XC2BistreamFB, &'static str> {
let mut and_terms = [XC2PLAAndTerm::default(); 56];
let and_block_idx = match block_idx {
0 => 320,
1 => 6448,
_ => return Err("invalid block_idx"),
};
for i in 0..and_terms.len() {
and_terms[i] = read_and_term_logical(fuses, and_block_idx, i);
}

let mut or_terms = [XC2PLAOrTerm::default(); 16];
let or_block_idx = match block_idx {
0 => 4800,
1 => 10928,
_ => return Err("invalid block_idx"),
};
for i in 0..or_terms.len() {
or_terms[i] = read_or_term_logical(fuses, or_block_idx, i);
}

let mut zia_bits = [XC2ZIARowPiece::default(); 40];
let zia_block_idx = match block_idx {
0 => 0,
1 => 6128,
_ => return Err("invalid block_idx"),
};
for i in 0..zia_bits.len() {
let result = read_32_zia_fb_row_logical(fuses, zia_block_idx, i);
if let Err(err) = result {
return Err(err);
}
zia_bits[i] = result.unwrap();
}

let mut ff_bits = [XC2MCFF::default(); 16];
let ff_block_idx = match block_idx {
0 => 5696,
1 => 11824,
_ => return Err("invalid block_idx"),
};
for i in 0..ff_bits.len() {
ff_bits[i] = read_32_ff_logical(fuses, ff_block_idx, i);
}


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

// TODO: This is the same across all sizes, right?
pub fn get_ctc() -> u32 {
4
}

pub fn get_ctr() -> u32 {
5
}

pub fn get_cts() -> u32 {
6
}

pub fn get_cte() -> u32 {
7
}

pub fn get_pta(mc: u32) -> u32 {
3 * mc + 8
}

pub fn get_ptb(mc: u32) -> u32 {
3 * mc + 9
}

pub fn get_ptc(mc: u32) -> u32 {
3 * mc + 10
}
386 changes: 386 additions & 0 deletions src/xc2bit/src/jed.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,386 @@
/*
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.
*/

// Xilinx JED file I/O

use std::num::Wrapping;
use std::str;

use *;
use bitstream::{read_32_bitstream_logical, read_32a_bitstream_logical};

#[derive(Eq, PartialEq, Copy, Clone)]
enum Ternary {
Zero,
One,
Undef,
}

const STX: u8 = 0x02;
const ETX: u8 = 0x03;

// Reads .jed file and outputs the fuses as an array of booleans and optional device name
pub fn read_jed(in_bytes: &[u8]) -> Result<(Vec<bool>, Option<String>), &'static str> {
let mut fuse_csum = Wrapping(0u16);
let mut fuse_expected_csum = None;
let mut file_csum = Wrapping(0u16);
let mut num_fuses: u32 = 0;
let mut device = None;
let mut jed_stx: usize = 0;
let mut jed_etx: usize;
let mut fuses_ternary = vec![];
let mut default_fuse = Ternary::Undef;

// Find STX
while in_bytes[jed_stx] != STX {
jed_stx += 1;
if jed_stx >= in_bytes.len() {
return Err("STX not found");
}
}

// Checksum and find ETX
jed_etx = jed_stx;
while in_bytes[jed_etx] != ETX {
file_csum += Wrapping(in_bytes[jed_etx] as u16);
jed_etx += 1;
if jed_etx >= in_bytes.len() {
return Err("ETX not found");
}
}
// Add the ETX to the checksum too
file_csum += Wrapping(ETX as u16);

// Check the checksum
if jed_etx + 4 >= in_bytes.len() {
return Err("unexpected end of file - checksum");
}
let csum_expected = &in_bytes[jed_etx + 1..jed_etx + 5];
let csum_expected = str::from_utf8(csum_expected);
if csum_expected.is_err() {
return Err("invalid character encountered - file checksum");
}
let csum_expected = u16::from_str_radix(csum_expected.unwrap(), 16);
if csum_expected.is_err() {
return Err("invalid character encountered - file checksum");
}
let csum_expected = csum_expected.unwrap();
if csum_expected != 0 && csum_expected != file_csum.0 {
return Err("invalid file checksum");
}

// Make a str object out of the body
let jed_body = str::from_utf8(&in_bytes[jed_stx + 1..jed_etx]);
if jed_body.is_err() {
return Err("invalid character encountered - non-ASCII");
}
let jed_body = jed_body.unwrap();

// Ready to parse each line
for l in jed_body.split('*') {
let l = l.trim_matches(|c| c == ' ' || c == '\r' || c == '\n');
if l.len() == 0 {
// FIXME: Should we do something else here?
// ignore empty fields
continue;
}

// Now we can look at the first byte to figure out what we have
match l.chars().next().unwrap() {
'X' | 'J' => {}, // Do nothing, don't care about these
'F' => {
// Default state
let (_, default_state_str) = l.split_at(1);
default_fuse = match default_state_str {
"0" => Ternary::Zero,
"1" => Ternary::One,
_ => return Err("invalid character encountered - F field")
}
},
'N' => {
// Notes; we want to extract N DEVICE but otherwise ignore it
let note_pieces = l.split(|c| c == ' ' || c == '\r' || c == '\n').collect::<Vec<_>>();
if note_pieces.len() == 3 && note_pieces[1] == "DEVICE" {
device = Some(note_pieces[2].to_owned());
}
},
'Q' => {
// Look for QF
if l.starts_with("QF") {
let (_, num_fuses_str) = l.split_at(2);
let num_fuses_maybe = u32::from_str_radix(num_fuses_str, 10);
if num_fuses_maybe.is_err() {
return Err("invalid character encountered - QF field");
}
num_fuses = num_fuses_maybe.unwrap();
fuses_ternary.reserve(num_fuses as usize);
for _ in 0..num_fuses {
fuses_ternary.push(Ternary::Undef);
}
}
},
'L' => {
// A set of fuses
if num_fuses == 0 {
return Err("missing QF field");
}

let mut fuse_field_splitter = l.splitn(2, |c| c == ' ' || c == '\r' || c == '\n');
let fuse_idx_str = fuse_field_splitter.next();
let (_, fuse_idx_str) = fuse_idx_str.unwrap().split_at(1);
let fuse_idx_maybe = u32::from_str_radix(fuse_idx_str, 10);
if fuse_idx_maybe.is_err() {
return Err("invalid character encountered - fuse number");
}
let mut fuse_idx = fuse_idx_maybe.unwrap();

let fuse_bits_part = fuse_field_splitter.next();
if fuse_bits_part.is_none() {
return Err("malformed L field");
}
let fuse_bits_part = fuse_bits_part.unwrap();
for fuse in fuse_bits_part.chars() {
match fuse {
'0' => {
if fuse_idx >= num_fuses {
return Err("invalid fuse index out of range");
}
fuses_ternary[fuse_idx as usize] = Ternary::Zero;
fuse_idx += 1;
},
'1' => {
if fuse_idx >= num_fuses {
return Err("invalid fuse index out of range");
}
fuses_ternary[fuse_idx as usize] = Ternary::One;
fuse_idx += 1;
},
' ' | '\r' | '\n' => {}, // Do nothing
_ => return Err("invalid character encountered - fuse value"),
}
}
},
'C' => {
// Checksum
let (_, csum_str) = l.split_at(1);
if csum_str.len() != 4 {
return Err("malformed fuse checksum");
}
let csum_maybe = u16::from_str_radix(csum_str, 16);
if csum_maybe.is_err() {
return Err("invalid character encountered - C");
}
fuse_expected_csum = Some(csum_maybe.unwrap());
}
_ => return Err("unrecognized field"),
}
}

// Fill in the default values
for x in &mut fuses_ternary {
if *x == Ternary::Undef {
// There cannot be undefined fuses if there isn't an F field
if default_fuse == Ternary::Undef {
return Err("missing F field")
}

*x = default_fuse;
}
}

// Un-ternary it
let fuses = fuses_ternary.iter().map(|&x| match x {
Ternary::Zero => false,
Ternary::One => true,
_ => unreachable!(),
}).collect::<Vec<_>>();

// Fuse checksum
if let Some(fuse_expected_csum) = fuse_expected_csum {
for i in 0..num_fuses {
if fuses[i as usize] {
// Fuse is a 1 and contributes to the sum
fuse_csum += Wrapping(1u16 << (i % 8));
}
}

if fuse_expected_csum != fuse_csum.0 {
return Err("invalid fuse checksum");
}
}

Ok((fuses, device))
}

// Processes a fuse array into a bitstream object
pub fn process_jed(fuses: &[bool], device: &str) -> Result<XC2Bitstream, &'static str> {
let device_split = device.split('-').collect::<Vec<_>>();

if device_split.len() != 3 {
return Err("malformed device name");
}

// TODO: Validate these
let device_speed = device_split[1];
let device_package = device_split[2];

// Part name
match device_split[0] {
"XC2C32" => {
if fuses.len() != 12274 {
return Err("wrong number of fuses");
}
let bits = read_32_bitstream_logical(fuses);
if let Err(err) = bits {
return Err(err);
}
Ok(XC2Bitstream {
speed_grade: device_speed.to_owned(),
package: device_package.to_owned(),
bits: bits.unwrap(),
})
},
"XC2C32A" => {
if fuses.len() != 12278 {
return Err("wrong number of fuses");
}
let bits = read_32a_bitstream_logical(fuses);
if let Err(err) = bits {
return Err(err);
}
Ok(XC2Bitstream {
speed_grade: device_speed.to_owned(),
package: device_package.to_owned(),
bits: bits.unwrap(),
})
},
_ => Err("unsupported part"),
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn read_no_stx() {
let ret = read_jed(b"asdf");

assert_eq!(ret, Err("STX not found"));
}

#[test]
fn read_no_etx() {
let ret = read_jed(b"asdf\x02fdsa");

assert_eq!(ret, Err("ETX not found"));
}

#[test]
fn read_no_csum() {
let ret = read_jed(b"asdf\x02fdsa\x03");
assert_eq!(ret, Err("unexpected end of file - checksum"));

let ret = read_jed(b"asdf\x02fdsa\x03AAA");
assert_eq!(ret, Err("unexpected end of file - checksum"));
}

#[test]
fn read_bad_csum() {
let ret = read_jed(b"asdf\x02fdsa\x03AAAA");

assert_eq!(ret, Err("invalid file checksum"));
}

#[test]
fn read_malformed_csum() {
let ret = read_jed(b"asdf\x02fdsa\x03AAAZ");

assert_eq!(ret, Err("invalid character encountered - file checksum"));
}

#[test]
fn read_no_f() {
let ret = read_jed(b"\x02QF1*\x030000");

assert_eq!(ret, Err("missing F field"));
}

#[test]
fn read_empty_no_fuses() {
let ret = read_jed(b"\x02F0*\x030000");

assert_eq!(ret, Ok((vec![], None)));
}

#[test]
fn read_bogus_f_command() {
let ret = read_jed(b"\x02F2*\x030000");

assert_eq!(ret, Err("invalid character encountered - F field"));
}

#[test]
fn read_empty_with_device() {
let ret = read_jed(b"\x02F0*N DEVICE asdf*\x030000");

assert_eq!(ret, Ok((vec![], Some(String::from("asdf")))));
}

#[test]
fn read_l_without_qf() {
let ret = read_jed(b"\x02F0*L0 0*\x030000");

assert_eq!(ret, Err("missing QF field"));
}

#[test]
fn read_one_fuse() {
let ret = read_jed(b"\x02F0*QF1*L0 1*\x030000");

assert_eq!(ret, Ok((vec![true], None)));
}

#[test]
fn read_one_fuse_csum_good() {
let ret = read_jed(b"\x02F0*QF1*L0 1*C0001*\x030000");

assert_eq!(ret, Ok((vec![true], None)));
}

#[test]
fn read_one_fuse_csum_bad() {
let ret = read_jed(b"\x02F0*QF1*L0 1*C0002*\x030000");

assert_eq!(ret, Err("invalid fuse checksum"));
}

#[test]
fn read_two_fuses_space() {
let ret = read_jed(b"\x02F0*QF2*L0 0 1*\x030000");

assert_eq!(ret, Ok((vec![false, true], None)));
}
}
46 changes: 46 additions & 0 deletions src/xc2bit/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
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.
*/

// Public interface

mod bitstream;
pub use bitstream::{XC2Bitstream, XC2BitstreamBits, XC2GlobalNets};

mod fb;
pub use fb::{XC2BistreamFB, get_ctc, get_ctr, get_cts, get_cte, get_pta, get_ptb, get_ptc};

mod mc;
pub use mc::{XC2MCFF, XC2MCSmallIOB, XC2MCFFClkSrc, XC2MCFFResetSrc, XC2MCFFSetSrc, XC2MCFFMode, XC2MCFeedbackMode,
XC2IOBZIAMode, XC2MCXorMode, XC2MCOBufMode, XC2ExtraIBuf, iob_num_to_fb_ff_num_32,
fb_ff_num_to_iob_num_32};

mod pla;
pub use pla::{XC2PLAAndTerm, XC2PLAOrTerm};

mod zia;
pub use zia::{XC2ZIARowPiece, XC2ZIAInput, ZIA_BIT_TO_CHOICE_32};

mod jed;
pub use jed::{read_jed, process_jed};
408 changes: 408 additions & 0 deletions src/xc2bit/src/mc.rs

Large diffs are not rendered by default.

91 changes: 91 additions & 0 deletions src/xc2bit/src/pla.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/*
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.
*/

// PLA stuff

#[derive(Copy)]
pub struct XC2PLAAndTerm {
// true = part of and, false = not part of and
pub input: [bool; 40],
pub input_b: [bool; 40],
}

impl Clone for XC2PLAAndTerm {
fn clone(&self) -> XC2PLAAndTerm {*self}
}

impl Default for XC2PLAAndTerm {
fn default() -> XC2PLAAndTerm {
XC2PLAAndTerm {
input: [false; 40],
input_b: [false; 40],
}
}
}

#[derive(Copy)]
pub struct XC2PLAOrTerm {
// true = part of or, false = not part of or
pub input: [bool; 56],
}

impl Clone for XC2PLAOrTerm {
fn clone(&self) -> XC2PLAOrTerm {*self}
}

impl Default for XC2PLAOrTerm {
fn default() -> XC2PLAOrTerm {
XC2PLAOrTerm {
input: [false; 56],
}
}
}

pub fn read_and_term_logical(fuses: &[bool], block_idx: usize, term_idx: usize) -> XC2PLAAndTerm {
let mut input = [false; 40];
let mut input_b = [false; 40];

for i in 0..40 {
input[i] = !fuses[block_idx + term_idx * 80 + i * 2 + 0];
input_b[i] = !fuses[block_idx + term_idx * 80 + i * 2 + 1];
}

XC2PLAAndTerm {
input: input,
input_b: input_b,
}
}

pub fn read_or_term_logical(fuses: &[bool], block_idx: usize, term_idx: usize) -> XC2PLAOrTerm {
let mut input = [false; 56];

for i in 0..56 {
input[i] = !fuses[block_idx + term_idx +i * 16];
}

XC2PLAOrTerm {
input: input,
}
}
400 changes: 400 additions & 0 deletions src/xc2bit/src/zia.rs

Large diffs are not rendered by default.