use std::io;
use std::io::Write;
use jedec::*;
use crate::*;
use crate::fusemap_physical::{mc_block_loc};
use crate::util::{LinebreakSet};
use crate::zia::{zia_get_row_width};
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Serialize, Deserialize)]
#[derive(BitPattern)]
pub enum XC2MCRegClkSrc {
#[bits = "x00"]
GCK0,
#[bits = "x10"]
GCK1,
#[bits = "x01"]
GCK2,
#[bits = "011"]
PTC,
#[bits = "111"]
CTC,
}
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Serialize, Deserialize)]
#[derive(BitPattern)]
pub enum XC2MCRegResetSrc {
#[bits = "11"]
Disabled,
#[bits = "00"]
PTA,
#[bits = "01"]
GSR,
#[bits = "10"]
CTR,
}
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Serialize, Deserialize)]
#[derive(BitPattern)]
pub enum XC2MCRegSetSrc {
#[bits = "11"]
Disabled,
#[bits = "00"]
PTA,
#[bits = "01"]
GSR,
#[bits = "10"]
CTS,
}
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Serialize, Deserialize)]
#[derive(BitPattern)]
pub enum XC2MCRegMode {
#[bits = "00"]
DFF,
#[bits = "01"]
LATCH,
#[bits = "10"]
TFF,
#[bits = "11"]
DFFCE,
}
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Serialize, Deserialize)]
#[derive(BitPattern)]
pub enum XC2MCFeedbackMode {
#[bits = "X1"]
Disabled,
#[bits = "00"]
COMB,
#[bits = "10"]
REG,
}
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Serialize, Deserialize)]
#[derive(BitPattern)]
pub enum XC2MCXorMode {
#[bits = "00"]
ZERO,
#[bits = "11"]
ONE,
#[bits = "10"]
PTC,
#[bits = "01"]
PTCB,
}
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Serialize, Deserialize)]
#[derive(BitTwiddler)]
#[bittwiddler = "jed_internal_small"]
#[bittwiddler = "jed_internal_large"]
#[bittwiddler = "jed_internal_large_buried"]
#[bittwiddler = "crbit32 mirror0"]
#[bittwiddler = "crbit64 mirror0"]
#[bittwiddler = "crbit256 mirror0"]
#[bittwiddler = "crbit_large mirror0"]
pub struct XC2Macrocell {
#[bittwiddler_field = "jed_internal_small 0 2 3"]
#[bittwiddler_field = "jed_internal_large 0 1 2"]
#[bittwiddler_field = "jed_internal_large_buried 0 1 2"]
#[bittwiddler_field = "crbit32 0|0 2|0 3|0"]
#[bittwiddler_field = "crbit64 8|0 5|0 6|0"]
#[bittwiddler_field = "crbit256 9|0 7|0 8|0"]
#[bittwiddler_field = "crbit_large 8|0 9|0 10|0"]
pub clk_src: XC2MCRegClkSrc,
#[bittwiddler_field = "jed_internal_small 1"]
#[bittwiddler_field = "jed_internal_large 4"]
#[bittwiddler_field = "jed_internal_large_buried 4"]
#[bittwiddler_field = "crbit32 1|0"]
#[bittwiddler_field = "crbit64 7|0"]
#[bittwiddler_field = "crbit256 5|0"]
#[bittwiddler_field = "crbit_large 12|0"]
pub clk_invert_pol: bool,
#[bittwiddler_field = "jed_internal_small 4"]
#[bittwiddler_field = "jed_internal_large 3"]
#[bittwiddler_field = "jed_internal_large_buried 3"]
#[bittwiddler_field = "crbit32 4|0"]
#[bittwiddler_field = "crbit64 4|0"]
#[bittwiddler_field = "crbit256 6|0"]
#[bittwiddler_field = "crbit_large 11|0"]
pub is_ddr: bool,
#[bittwiddler_field = "jed_internal_small 5 6"]
#[bittwiddler_field = "jed_internal_large 23 24"]
#[bittwiddler_field = "jed_internal_large_buried 12 13"]
#[bittwiddler_field = "crbit32 5|0 6|0"]
#[bittwiddler_field = "crbit64 2|0 3|0"]
#[bittwiddler_field = "crbit256 4|2 5|2"]
#[bittwiddler_field = "crbit_large 11|1 12|1"]
pub r_src: XC2MCRegResetSrc,
#[bittwiddler_field = "jed_internal_small 7 8"]
#[bittwiddler_field = "jed_internal_large 17 18"]
#[bittwiddler_field = "jed_internal_large_buried 7 8"]
#[bittwiddler_field = "crbit32 7|0 8|0"]
#[bittwiddler_field = "crbit64 0|0 1|0"]
#[bittwiddler_field = "crbit256 1|1 2|1"]
#[bittwiddler_field = "crbit_large 13|1 14|1"]
pub s_src: XC2MCRegSetSrc,
#[bittwiddler_field = "jed_internal_small !26"]
#[bittwiddler_field = "jed_internal_large !19"]
#[bittwiddler_field = "jed_internal_large_buried !9"]
#[bittwiddler_field = "crbit32 !8|2"]
#[bittwiddler_field = "crbit64 !0|2"]
#[bittwiddler_field = "crbit256 !0|1"]
#[bittwiddler_field = "crbit_large !14|0"]
pub init_state: bool,
#[bittwiddler_field = "jed_internal_small 9 10"]
#[bittwiddler_field = "jed_internal_large 21 22"]
#[bittwiddler_field = "jed_internal_large_buried 10 11"]
#[bittwiddler_field = "crbit32 0|1 1|1"]
#[bittwiddler_field = "crbit64 7|1 8|1"]
#[bittwiddler_field = "crbit256 6|2 7|2"]
#[bittwiddler_field = "crbit_large 9|1 10|1"]
pub reg_mode: XC2MCRegMode,
#[bittwiddler_field = "jed_internal_small 13 14"]
#[bittwiddler_field = "jed_internal_large 6 7"]
#[bittwiddler_field = "jed_internal_large_buried 5 6"]
#[bittwiddler_field = "crbit32 4|1 5|1"]
#[bittwiddler_field = "crbit64 3|1 4|1"]
#[bittwiddler_field = "crbit256 2|0 3|0"]
#[bittwiddler_field = "crbit_large 2|0 3|0"]
pub fb_mode: XC2MCFeedbackMode,
#[bittwiddler_field = "jed_internal_small !15"]
#[bittwiddler_field = "jed_internal_large !10"]
#[bittwiddler_field = "jed_internal_large_buried F"]
#[bittwiddler_field = "crbit32 !6|1"]
#[bittwiddler_field = "crbit64 !2|1"]
#[bittwiddler_field = "crbit256 !9|1"]
#[bittwiddler_field = "crbit_large !13|0"]
pub ff_in_ibuf: bool,
#[bittwiddler_field = "jed_internal_small 17 18"]
#[bittwiddler_field = "jed_internal_large 27 28"]
#[bittwiddler_field = "jed_internal_large_buried 14 15"]
#[bittwiddler_field = "crbit32 8|1 0|2"]
#[bittwiddler_field = "crbit64 7|2 8|2"]
#[bittwiddler_field = "crbit256 0|2 1|2"]
#[bittwiddler_field = "crbit_large 0|1 1|1"]
pub xor_mode: XC2MCXorMode,
}
impl Default for XC2Macrocell {
fn default() -> Self {
XC2Macrocell {
clk_src: XC2MCRegClkSrc::GCK0,
clk_invert_pol: false,
is_ddr: false,
r_src: XC2MCRegResetSrc::Disabled,
s_src: XC2MCRegSetSrc::Disabled,
init_state: true,
reg_mode: XC2MCRegMode::DFF,
fb_mode: XC2MCFeedbackMode::Disabled,
ff_in_ibuf: false,
xor_mode: XC2MCXorMode::ZERO,
}
}
}
pub static MC_TO_ROW_MAP_LARGE: [usize; MCS_PER_FB] =
[0, 3, 5, 8, 10, 13, 15, 18, 20, 23, 25, 28, 30, 33, 35, 38];
impl XC2Macrocell {
pub fn dump_human_readable<W: Write>(&self, fb: u32, mc: u32, mut writer: W) -> Result<(), io::Error> {
write!(writer, "\n")?;
write!(writer, "FF configuration for FB{}_{}\n", fb + 1, mc + 1)?;
write!(writer, "FF mode: {}\n", match self.reg_mode {
XC2MCRegMode::DFF => "D flip-flop",
XC2MCRegMode::LATCH => "transparent latch",
XC2MCRegMode::TFF => "T flip-flop",
XC2MCRegMode::DFFCE => "D flip-flop with clock-enable",
})?;
write!(writer, "initial state: {}\n", if self.init_state {1} else {0})?;
write!(writer, "{}-edge triggered\n", if self.clk_invert_pol {"falling"} else {"rising"})?;
write!(writer, "DDR: {}\n", if self.is_ddr {"yes"} else {"no"})?;
write!(writer, "clock source: {}\n", match self.clk_src {
XC2MCRegClkSrc::GCK0 => "GCK0",
XC2MCRegClkSrc::GCK1 => "GCK1",
XC2MCRegClkSrc::GCK2 => "GCK2",
XC2MCRegClkSrc::PTC => "PTC",
XC2MCRegClkSrc::CTC => "CTC",
})?;
write!(writer, "set source: {}\n", match self.s_src {
XC2MCRegSetSrc::Disabled => "disabled",
XC2MCRegSetSrc::PTA => "PTA",
XC2MCRegSetSrc::GSR => "GSR",
XC2MCRegSetSrc::CTS => "CTS",
})?;
write!(writer, "reset source: {}\n", match self.r_src {
XC2MCRegResetSrc::Disabled => "disabled",
XC2MCRegResetSrc::PTA => "PTA",
XC2MCRegResetSrc::GSR => "GSR",
XC2MCRegResetSrc::CTR => "CTR",
})?;
write!(writer, "using ibuf direct path: {}\n", if self.ff_in_ibuf {"yes"} else {"no"})?;
write!(writer, "XOR gate input: {}\n", match self.xor_mode {
XC2MCXorMode::ZERO => "0",
XC2MCXorMode::ONE => "1",
XC2MCXorMode::PTC => "PTC",
XC2MCXorMode::PTCB => "~PTC",
})?;
write!(writer, "ZIA feedback: {}\n", match self.fb_mode {
XC2MCFeedbackMode::Disabled => "disabled",
XC2MCFeedbackMode::COMB => "combinatorial",
XC2MCFeedbackMode::REG => "registered",
})?;
Ok(())
}
pub fn to_crbit(&self, device: XC2Device, fb: u32, mc: u32, fuse_array: &mut FuseArray) {
let (x, y, mirror) = mc_block_loc(device, fb);
match device {
XC2Device::XC2C32 | XC2Device::XC2C32A => {
let y = y + (mc as usize) * 3;
self.encode_crbit32(fuse_array, (x, y), mirror);
},
XC2Device::XC2C64 | XC2Device::XC2C64A => {
let y = y + (mc as usize) * 3;
self.encode_crbit64(fuse_array, (x, y), mirror);
},
XC2Device::XC2C256 => {
let y = y + (mc as usize) * 3;
self.encode_crbit256(fuse_array, (x, y), mirror);
},
XC2Device::XC2C128 | XC2Device::XC2C384 | XC2Device::XC2C512 => {
let y = y + MC_TO_ROW_MAP_LARGE[mc as usize];
self.encode_crbit_large(fuse_array, (x, y), mirror);
}
}
}
pub fn from_crbit(device: XC2Device, fb: u32, mc: u32, fuse_array: &FuseArray) -> Self {
let (x, y, mirror) = mc_block_loc(device, fb);
match device {
XC2Device::XC2C32 | XC2Device::XC2C32A => {
let y = y + (mc as usize) * 3;
Self::decode_crbit32(fuse_array, (x, y), mirror)
},
XC2Device::XC2C64 | XC2Device::XC2C64A => {
let y = y + (mc as usize) * 3;
Self::decode_crbit64(fuse_array, (x, y), mirror)
},
XC2Device::XC2C256 => {
let y = y + (mc as usize) * 3;
Self::decode_crbit256(fuse_array, (x, y), mirror)
},
XC2Device::XC2C128 | XC2Device::XC2C384 | XC2Device::XC2C512 => {
let y = y + MC_TO_ROW_MAP_LARGE[mc as usize];
Self::decode_crbit_large(fuse_array, (x, y), mirror)
}
}
}
pub fn from_jed_small(fuses: &[bool], block_idx: usize, mc_idx: usize) -> Self {
Self::decode_jed_internal_small(fuses, block_idx + mc_idx * 27)
}
pub fn from_jed_large(fuses: &[bool], fuse_idx: usize) -> Self {
Self::decode_jed_internal_large(fuses, fuse_idx)
}
pub fn from_jed_large_buried(fuses: &[bool], fuse_idx: usize) -> Self {
Self::decode_jed_internal_large_buried(fuses, fuse_idx)
}
pub fn to_jed_small(jed: &mut JEDECFile, linebreaks: &mut LinebreakSet,
device: XC2Device, fb: &XC2BitstreamFB, fuse_base: usize) {
let zia_row_width = zia_get_row_width(device);
for i in 0..MCS_PER_FB {
let mc_fuse_base = fuse_base + zia_row_width * INPUTS_PER_ANDTERM +
ANDTERMS_PER_FB * INPUTS_PER_ANDTERM * 2 + ANDTERMS_PER_FB * MCS_PER_FB + i * 27;
linebreaks.add(mc_fuse_base);
if i == 0 {
linebreaks.add(mc_fuse_base);
}
fb.mcs[i].encode_jed_internal_small(&mut jed.f, mc_fuse_base);
}
}
pub fn to_jed_large(jed: &mut JEDECFile, linebreaks: &mut LinebreakSet,
device: XC2Device, fb: &XC2BitstreamFB, fb_i: usize, fuse_base: usize) {
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;
linebreaks.add(current_fuse_offset);
for i in 0..MCS_PER_FB {
linebreaks.add(current_fuse_offset);
let iob = fb_mc_num_to_iob_num(device, fb_i as u32, i as u32);
if iob.is_some() {
fb.mcs[i].encode_jed_internal_large(&mut jed.f, current_fuse_offset);
current_fuse_offset += 29;
} else {
fb.mcs[i].encode_jed_internal_large_buried(&mut jed.f, current_fuse_offset);
current_fuse_offset += 16;
}
}
}
}