use xc2bit::*;
use crate::*;
use crate::objpool::*;
pub fn produce_bitstream(device_type: XC2DeviceSpeedPackage, g: &InputGraph, go: &OutputGraph) -> XC2Bitstream {
let mut result = XC2Bitstream::blank_bitstream(device_type);
{
let fb_bits = result.bits.get_fb_mut();
for fb_i in 0..go.zia.len() {
for zia_i in 0..INPUTS_PER_ANDTERM {
*fb_bits[fb_i].get_mut_zia(zia_i) = go.zia[fb_i].get(zia_i);
}
}
for andterm_idx in g.pterms.iter_idx() {
let andterm_go = go.pterms.get(ObjPoolIndex::from(andterm_idx));
let fb_i = andterm_go.loc.unwrap().fb as usize;
let andterm_i = andterm_go.loc.unwrap().i as usize;
for &x in &andterm_go.inputs_true_zia {
fb_bits[fb_i].get_mut_andterm(andterm_i).set(x as usize, true);
}
for &x in &andterm_go.inputs_comp_zia {
fb_bits[fb_i].get_mut_andterm(andterm_i).set_b(x as usize, true);
}
}
}
for mc_idx in g.mcs.iter_idx() {
let mc = g.mcs.get(mc_idx);
let mc_go = go.mcs.get(ObjPoolIndex::from(mc_idx));
let fb_i = mc_go.loc.unwrap().fb;
let mc_i = mc_go.loc.unwrap().i;
if let Some(ref io_bits) = mc.io_bits {
if (device_type.dev == XC2Device::XC2C32 || device_type.dev == XC2Device::XC2C32A) && fb_i == 2 && mc_i == 0 {
match result.bits {
XC2BitstreamBits::XC2C32{inpin: ref mut extra_inpin, ..} |
XC2BitstreamBits::XC2C32A{inpin: ref mut extra_inpin, ..} => {
extra_inpin.schmitt_trigger = io_bits.schmitt_trigger;
extra_inpin.termination_enabled = io_bits.termination_enabled;
},
_ => unreachable!(),
}
} else {
let i_iob = fb_mc_num_to_iob_num(device_type.dev, fb_i as u32, mc_i as u32).unwrap();
macro_rules! output_iob_common {
($iob_bit:expr) => {{
$iob_bit.termination_enabled = io_bits.termination_enabled;
$iob_bit.slew_is_fast = io_bits.slew_is_fast;
if let Some(input) = io_bits.input {
$iob_bit.obuf_uses_ff = input == InputGraphIOInputType::Reg;
$iob_bit.obuf_mode = match io_bits.oe {
None => XC2IOBOBufMode::PushPull,
Some(InputGraphIOOEType::OpenDrain) => XC2IOBOBufMode::OpenDrain,
Some(InputGraphIOOEType::PTerm(pterm)) => {
let pterm = go.pterms.get(ObjPoolIndex::from(pterm));
let pt_loc = pterm.loc.unwrap();
assert!(pt_loc.fb == fb_i);
if pt_loc.i == CTE {
XC2IOBOBufMode::TriStateCTE
} else if pt_loc.i == get_ptb(mc_i as u32) {
XC2IOBOBufMode::TriStatePTB
} else {
panic!("Internal error - not CTE or PTB");
}
},
Some(InputGraphIOOEType::GTS(gts)) => {
let gts = go.bufg_gts.get(ObjPoolIndex::from(gts));
let which = gts.loc.unwrap().i;
match which {
0 => XC2IOBOBufMode::TriStateGTS0,
1 => XC2IOBOBufMode::TriStateGTS1,
2 => XC2IOBOBufMode::TriStateGTS2,
3 => XC2IOBOBufMode::TriStateGTS3,
_ => panic!("Internal error - bad GTS"),
}
},
}
}
}}
}
if device_type.dev.is_small_iob() {
let iob_bit = result.bits.get_mut_small_iob(i_iob as usize).unwrap();
iob_bit.schmitt_trigger = io_bits.schmitt_trigger;
output_iob_common!(iob_bit);
} else {
let iob_bit = result.bits.get_mut_large_iob(i_iob as usize).unwrap();
iob_bit.ibuf_mode = if io_bits.schmitt_trigger {
XC2IOBIbufMode::NoVrefSt
} else {
XC2IOBIbufMode::NoVrefNoSt
};
iob_bit.uses_data_gate = io_bits.uses_data_gate;
output_iob_common!(iob_bit);
}
}
}
if let Some(i_iob) = fb_mc_num_to_iob_num(device_type.dev, fb_i as u32, mc_i as u32) {
macro_rules! output_iob_common {
($iob_bit:expr) => {{
if mc.io_feedback_used {
$iob_bit.zia_mode = XC2IOBZIAMode::PAD;
} else if (mc.xor_feedback_used && mc.reg_feedback_used) ||
mc.get_type() == InputGraphMacrocellType::PinInputReg {
$iob_bit.zia_mode = XC2IOBZIAMode::REG;
}
}}
}
if device_type.dev.is_small_iob() {
let iob_bit = result.bits.get_mut_small_iob(i_iob as usize).unwrap();
output_iob_common!(iob_bit);
} else {
let iob_bit = result.bits.get_mut_large_iob(i_iob as usize).unwrap();
output_iob_common!(iob_bit);
}
}
}
{
let fb_bits = result.bits.get_fb_mut();
for mc_idx in g.mcs.iter_idx() {
let mc = g.mcs.get(mc_idx);
let mc_go = go.mcs.get(ObjPoolIndex::from(mc_idx));
let fb_i = mc_go.loc.unwrap().fb as usize;
let mc_i = mc_go.loc.unwrap().i as usize;
if let Some(ref xor_bits) = mc.xor_bits {
fb_bits[fb_i].mcs[mc_i].xor_mode = match (xor_bits.invert_out, xor_bits.andterm_input) {
(false, None) => XC2MCXorMode::ZERO,
(true, None) => XC2MCXorMode::ONE,
(false, Some(_)) => XC2MCXorMode::PTC,
(true, Some(_)) => XC2MCXorMode::PTCB,
};
for &and_to_or_idx in &xor_bits.orterm_inputs {
let pterm = go.pterms.get(ObjPoolIndex::from(and_to_or_idx));
let pt_loc = pterm.loc.unwrap();
assert!(pt_loc.fb as usize == fb_i);
fb_bits[fb_i].or_terms[mc_i].set(pt_loc.i as usize, true);
}
if mc.xor_feedback_used {
fb_bits[fb_i].mcs[mc_i].fb_mode = XC2MCFeedbackMode::COMB;
} else if mc.reg_feedback_used {
fb_bits[fb_i].mcs[mc_i].fb_mode = XC2MCFeedbackMode::REG;
}
}
}
for mc_idx in g.mcs.iter_idx() {
let mc = g.mcs.get(mc_idx);
let mc_go = go.mcs.get(ObjPoolIndex::from(mc_idx));
let fb_i = mc_go.loc.unwrap().fb as usize;
let mc_i = mc_go.loc.unwrap().i as usize;
if let Some(ref reg_bits) = mc.reg_bits {
fb_bits[fb_i].mcs[mc_i].reg_mode = reg_bits.mode;
fb_bits[fb_i].mcs[mc_i].clk_invert_pol = reg_bits.clkinv;
fb_bits[fb_i].mcs[mc_i].is_ddr = reg_bits.clkddr;
fb_bits[fb_i].mcs[mc_i].init_state = reg_bits.init_state;
fb_bits[fb_i].mcs[mc_i].s_src = match reg_bits.set_input {
None => XC2MCRegSetSrc::Disabled,
Some(InputGraphRegRSType::GSR(_)) => XC2MCRegSetSrc::GSR,
Some(InputGraphRegRSType::PTerm(pterm)) => {
let pterm = go.pterms.get(ObjPoolIndex::from(pterm));
let pt_loc = pterm.loc.unwrap();
assert!(pt_loc.fb as usize == fb_i);
if pt_loc.i == CTS {
XC2MCRegSetSrc::CTS
} else if pt_loc.i == get_pta(mc_i as u32) {
XC2MCRegSetSrc::PTA
} else {
panic!("Internal error - not CTS or PTA");
}
},
};
fb_bits[fb_i].mcs[mc_i].r_src = match reg_bits.reset_input {
None => XC2MCRegResetSrc::Disabled,
Some(InputGraphRegRSType::GSR(_)) => XC2MCRegResetSrc::GSR,
Some(InputGraphRegRSType::PTerm(pterm)) => {
let pterm = go.pterms.get(ObjPoolIndex::from(pterm));
let pt_loc = pterm.loc.unwrap();
assert!(pt_loc.fb as usize == fb_i);
if pt_loc.i == CTR {
XC2MCRegResetSrc::CTR
} else if pt_loc.i == get_pta(mc_i as u32) {
XC2MCRegResetSrc::PTA
} else {
panic!("Internal error - not CTR or PTA");
}
},
};
fb_bits[fb_i].mcs[mc_i].ff_in_ibuf = reg_bits.dt_input == InputGraphRegInputType::Pin;
fb_bits[fb_i].mcs[mc_i].clk_src = match reg_bits.clk_input {
InputGraphRegClockType::PTerm(pterm) => {
let pterm = go.pterms.get(ObjPoolIndex::from(pterm));
let pt_loc = pterm.loc.unwrap();
assert!(pt_loc.fb as usize == fb_i);
if pt_loc.i == CTC {
XC2MCRegClkSrc::CTC
} else if pt_loc.i == get_ptc(mc_i as u32) {
XC2MCRegClkSrc::PTC
} else {
panic!("Internal error - not CTC or PTC");
}
},
InputGraphRegClockType::GCK(gck) => {
let gck = go.bufg_clks.get(ObjPoolIndex::from(gck));
let which = gck.loc.unwrap().i;
match which {
0 => XC2MCRegClkSrc::GCK0,
1 => XC2MCRegClkSrc::GCK1,
2 => XC2MCRegClkSrc::GCK2,
_ => panic!("Internal error - bad GCK"),
}
},
}
}
}
}
{
let global_nets = result.bits.get_global_nets_mut();
for gck in go.bufg_clks.iter() {
let which = gck.loc.unwrap().i;
global_nets.gck_enable[which as usize] = true;
}
for gts_idx in g.bufg_gts.iter_idx() {
let gts = g.bufg_gts.get(gts_idx);
let gts_go = go.bufg_gts.get(ObjPoolIndex::from(gts_idx));
let which = gts_go.loc.unwrap().i;
global_nets.gts_enable[which as usize] = true;
global_nets.gts_invert[which as usize] = gts.invert;
}
for gsr in g.bufg_gsr.iter() {
global_nets.gsr_enable = true;
global_nets.gsr_invert = gsr.invert;
}
}
if let XC2BitstreamBits::XC2C32A{ref mut legacy_ivoltage, ref mut legacy_ovoltage,
ref mut ivoltage, ref mut ovoltage, ..} = result.bits {
*legacy_ivoltage = false;
*legacy_ovoltage = false;
*ivoltage = [false, false];
*ovoltage = [false, false];
}
result
}