Skip to content

Commit

Permalink
xc9500: more docs
Browse files Browse the repository at this point in the history
  • Loading branch information
wanda-phi committed Dec 2, 2023
1 parent 3e13e7a commit 5162a31
Show file tree
Hide file tree
Showing 6 changed files with 206 additions and 64 deletions.
157 changes: 157 additions & 0 deletions docs/xc9500/database.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
Database schema
###############

The device database is provided in machine-readable form as three JSON files:

- ``xc9500.json``, describing all XC9500 devices
- ``xc9500xl.json``, describing all XC9500XL devices
- ``xc9500xv.json``, describing all XC9500XV devices

All three files have the same schema.


Top level
=========

The top level of the database is an object, with the following fields:

- ``devices`` (list of object): list of :ref:`device <xc9500-db-device>`
- ``bonds`` (list of object): list of :ref:`bond <xc9500-db-bond>`
- ``speeds`` (list of object): list of :ref:`speed <xc9500-db-speed>`
- ``parts`` (list of object): list of :ref:`part <xc9500-db-part>`
- ``mc_bits`` (object): a :ref:`tile <xc9500-db-tile>` describing per-MC bits
- ``fb_bits`` (object): a :ref:`tile <xc9500-db-tile>` describing per-FB bits
- ``global_bits`` (object): a :ref:`tile <xc9500-db-tile>` describing global bits


.. _xc9500-db-device:

Device
======

A device is a structure describing a particular device die. A device is referenced
from a :ref:`part <xc9500-db-part>`. A device is an object with the following fields:

- ``kind`` (string): the kind of the device, one of:

- ``"xc9500"``
- ``"xc9500xl"``
- ``"xc9500xv"``

All devices within a single file will have the same kind.

- ``idcode`` (number): the JTAG IDCODE of the device
- ``fbs`` (number): the number of FBs in the device
- ``ios`` (map from string to number): describes the I/O pads available on the device.
The keys are of the form ``"<fb_idx>.<mc_idx>"`` and identify the MC that owns the IOB.
The value corresponding to the key is the bank index that the IOB belongs to.
- ``banks`` (number): the number of I/O banks in the device
- ``tdo_bank`` (number): the I/O bank index that is used to drive the TDO special pin
- ``io_special`` (map from string to pair of numbers): describes the I/O pads with special functions on the device.
The keys can be:

- ``"GCLK[0-2]"``
- ``"GSR"``
- ``"GOE[0-3]"``

The values are two-element lists of numbers. The first number is FB index, and the second
is MC index. Note that sometimes items in this map are overriden by the bond.

- ``imux_bits`` (object) : a :ref:`tile <xc9500-db-tile>` describing per-FB bits corresponding to IMUX
- ``uim_ibuf_bits`` (object or null): for XC95288 device, a :ref:`tile <xc9500-db-tile>` describing the UIM IBUF bits; for every other device, ``null``
- ``program_time`` (number): number of TCK cycles to wait after a program operation
- ``erase_time`` (number): number of TCK cycles to wait after an erase operation


.. _xc9500-db-bond:

Bond
====

A bond is a structure describing the mapping of device pads to package pins.
Bonds are referenced from :ref:`part <xc9500-db-part>` packages. A bond is an object
with the following fields:

- ``io_special_override`` (map from string to pair of numbers): a map like the device's ``io_special`` map, containing per-bond overrides
to the defaults (usually empty)
- ``pins`` (map from string to string): the pins of the package; they keys are package pin names, and the values are:

- ``NC``: unconnected pin
- ``GND``, ``VCCINT``, ``VCCIO{bank}``: power and ground pins
- ``MC_{fb}_{mc}``: an I/O pin
- ``TMS``, ``TCK``, ``TDI``, ``TDO``: JTAG pins

.. _xc9500-db-speed:

Speed
=====

A speed is a structure describing the timings of a device. They are referenced from
:ref:`part <xc9500-db-part>` speed grades. A speed is an object with one field:

- ``timing`` (map of string to number): a map from timing parameter name to timing data.
All timing data is given in picoseconds, and is always an integer number.


.. _xc9500-db-part:

Part
====

A part is a structure describing a particular commercially available part number.
Several parts may correspond to the same device. A part is an object with the following fields:

- ``name`` (string): the base name of the part, in lowercase
- ``device`` (number): the index of the corresponding device in the ``devices`` field
of the database
- ``packages`` (map from string to int): the packages in which this part is available;
the key is package name, and the value is the index of the corresponding bond in the ``bonds`` database field
- ``speeds`` (map from string to int): the speed grades in which this part is available;
the key is speed grade name (including the leading ``-``), and the value is the index of the corresponding speed in the ``speeds`` database field


.. _xc9500-db-part:

Tile
====

A tile is a structure describing a set of device fuses. There are multiple kinds
of tiles used to describe the bitstream. The base structure of a tile is the same
for all of these kinds.

A tile is an object where the keys are fuse set names, and the values are objects
with the following keys:

- ``bits`` (list of coordinate): the list of fuse coordinates in this fuse set
- one of:
- ``values`` (map of string to list of bool): used for an enumerated fuse set;
the list of possible values for this fuse set; the value is a list of fuse values, corresponding one
to one to the coordinates in ``bits``
- ``invert`` (bool): used for a plain bool / bitvec fuse set; if true, it means
that the value of this bitvec or bool is stored inverted in the datastream
(0 means true, 1 means false); if false, the value is stored directly without
inversion

The type and interpretation of coordinate depends on the tile kind.

The following tile kinds exist:

- per-MC bits tile: identical for all devices in the database, the coordinate
is a single number and corresponds to the row coordinate of the fuse
- per-FB bits tile: identical for all devices in the database, the coordinate
is a list of 3 numbers, in order:

- row
- bit
- column

- IMUX bits tile: device-specific, the coordinate is the same as for per-FB bits tile
- global bits tile: identical for all devices in the database, the coordinate
is a list of 4 numbers, in order:

- fb
- row
- bit
- column

- UIM IBUF bits tile: device-specific, only for XC995288, the coordinate is the same as for global bits tile
1 change: 1 addition & 0 deletions docs/xc9500/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ Xilinx XC9500, XC9500XL, XC9500XV CPLDs
structure
bitstream-xc9500
bitstream-xc9500xl
database
jtag
16 changes: 16 additions & 0 deletions docs/xc9500/jtag.rst
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,22 @@ The IR status is:
.. todo:: verify


IDCODE
======

The IDCODE for XC9500* devices can be determined as follows:

- bits 0-11: vendor code, ``0x093``
- bits 12-19: number of FBs in the device
- bits 20-27: device kind

- ``0x95``: XC9500
- ``0x96``: XC9500XL
- ``0x97``: XC9500XV

- bits 28-31: device revision (varies)


Boundary scan register
======================

Expand Down
12 changes: 8 additions & 4 deletions docs/xc9500/structure.rst
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,8 @@ Each FB has 36 inputs, which we call ``FB[i].IM[j]``. Each FB input is controll
depends only on the ``j`` coordinate, but not on ``i``.

- wire-AND fuses (``FB[i].IM[j].UIM.FB[k].MC[l]``) select which MC outputs participate in the
wire-AND. If a given fuse is programmed, it means that ``FB[k].MC[l].OUT_UIM`` is included
in the product. These fuses are only relevant when the mux fuse set is set to ``UIM``.
wire-AND. If a given fuse is set to 1 (ie. *not* programmed), it means that ``FB[k].MC[l].OUT_UIM``
is included in the product. These fuses are only relevant when the mux fuse set is set to ``UIM``.

.. todo:: check ``NONE`` semantics

Expand Down Expand Up @@ -166,8 +166,8 @@ Each product term can be routed to at most one of three destinations:

The fuses controlling a product term are:

- ``FB[i].MC[j].PT[k].IM[l].P``: if programmed, ``FB[i].IM[l]`` is included in the product term (true polarity)
- ``FB[i].MC[j].PT[k].IM[l].N``: if programmed, ``~FB[i].IM[l]`` is included in the product term (inverted polarity)
- ``FB[i].MC[j].PT[k].IM[l].P``: if set to 1, ``FB[i].IM[l]`` is included in the product term (true polarity)
- ``FB[i].MC[j].PT[k].IM[l].N``: if set to 1, ``~FB[i].IM[l]`` is included in the product term (inverted polarity)
- ``FB[i].MC[j].PT[k].HP``: if programmed, the product term is in high performance mode; otherwise, it is in low power mode
- ``FB[i].MC[j].PT[k].ALLOC``: has one of four values:

Expand All @@ -179,6 +179,10 @@ The fuses controlling a product term are:
The product term's corresponding dedicated function is called ``FB[i].MC[j].PT[k].SPECIAL``.
It is equal to ``FB[i].MC[j].PT[k]`` if the dedicated function is enabled in ``ALLOC``, 0 otherwise.

Note that the main product term control fuses are active-high on both XC9500 and XC9500XL/XV. This effectively
means that an unprogrammed XC9500 chip has all product term inputs enabled, while an unprogrammed XC9500XL device
has all product term inputs disabled.

PT import/export
----------------

Expand Down
6 changes: 4 additions & 2 deletions prjcombine_xc9500/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ pub struct Device {
pub io_special: BTreeMap<String, (FbId, FbMcId)>,
pub imux_bits: Tile<FbBitCoord>,
pub uim_ibuf_bits: Option<Tile<GlobalBitCoord>>,
pub program_time: u32,
pub erase_time: u32,
}

#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
Expand Down Expand Up @@ -91,16 +93,16 @@ pub struct Part {
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)]
pub struct FbBitCoord {
pub row: u32,
pub column: u32,
pub bit: u32,
pub column: u32,
}

#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)]
pub struct GlobalBitCoord {
pub fb: u32,
pub row: u32,
pub column: u32,
pub bit: u32,
pub column: u32,
}

#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
Expand Down
78 changes: 20 additions & 58 deletions prjcombine_xilinx_recpld/src/bin/xcpld_finish_xc9500.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,40 +35,6 @@ struct Args {
json: PathBuf,
}

// fn print_tile<T>(prefix: &str, tile: &Tile<T>, print_coord: impl Fn(&T)) {
// for (name, item) in &tile.items {
// print!("{prefix}");
// let bits = match item {
// TileItem::Enum(it) => &it.bits,
// TileItem::BitVec(it) => &it.bits,
// };
// for bit in bits {
// print!(" ");
// print_coord(bit);
// }
// print!(": {name}");
// match item {
// TileItem::Enum(it) => {
// println!(" ENUM");
// for (k, v) in &it.values {
// print!(" ");
// for bit in v {
// print!("{}", u8::from(*bit));
// }
// println!(": {k}");
// }
// }
// TileItem::BitVec(it) => {
// if it.invert {
// println!(" INVERT");
// } else {
// println!(" TRUE");
// }
// }
// }
// }
// }

fn merge_enum<T: Copy + Eq + Ord + Debug>(
a: &mut TileItemEnum<T>,
b: &TileItemEnum<T>,
Expand Down Expand Up @@ -971,8 +937,8 @@ fn validate_imux_uim(device: &Device, fpart: &FuzzDbPart) {
for im in device.fb_imuxes() {
for sfb in device.fbs() {
for smc in device.fb_mcs() {
let (fuse, inv) = fpart.bits.fbs[fb].uim_mc[im][sfb][smc];
assert!(inv);
let (fuse, pol) = fpart.bits.fbs[fb].uim_mc[im][sfb][smc];
assert!(pol);
let (r_addr, r_bit) = fpart.map.main[fuse];
let r_addr = r_addr as usize;
let bit = im.to_idx() / 5;
Expand Down Expand Up @@ -1001,10 +967,10 @@ fn validate_pterm(device: &Device, fpart: &FuzzDbPart) {
.enumerate()
{
for im in device.fb_imuxes() {
let ((fuse_t, inv_t), (fuse_f, inv_f)) =
let ((fuse_t, pol_t), (fuse_f, pol_f)) =
fpart.bits.fbs[fb].mcs[mc].pt.as_ref().unwrap()[pt].and[im];
assert!(inv_t);
assert!(inv_f);
assert!(pol_t);
assert!(pol_f);
for (neg, fuse) in [(0, fuse_t), (1, fuse_f)] {
let (r_addr, r_bit) = fpart.map.main[fuse];
let r_addr = r_addr as usize;
Expand Down Expand Up @@ -1054,11 +1020,11 @@ fn tile_to_json<T: Copy>(
}

fn fb_bit_to_json(crd: FbBitCoord) -> serde_json::Value {
json!([crd.row, crd.column, crd.bit])
json!([crd.row, crd.bit, crd.column])
}

fn global_bit_to_json(crd: GlobalBitCoord) -> serde_json::Value {
json!([crd.fb, crd.row, crd.column, crd.bit])
json!([crd.fb, crd.row, crd.bit, crd.column])
}

fn convert_io(io: IoId) -> (xc9500::FbId, xc9500::FbMcId) {
Expand Down Expand Up @@ -1153,23 +1119,6 @@ pub fn main() -> Result<(), Box<dyn Error>> {
let mc_bits = mc_bits.unwrap();
let fb_bits = fb_bits.unwrap();
let global_bits = global_bits.unwrap();
// print_tile("MC", &mc_bits, |x| print!("{x}"));
// print_tile("FB", &fb_bits, |x| {
// print!("{}.{}.{}", x.row, x.column, x.bit)
// });
// print_tile("GLOBAL", &global_bits, |x| {
// print!("{}.{}.{}.{}", x.fb, x.row, x.column, x.bit)
// });
// for (k, v) in &imux_bits {
// print_tile(&format!("IMUX {k}"), v, |x| {
// print!("{}.{}.{}", x.row, x.column, x.bit)
// })
// }
// if let Some(ref bits) = ibuf_uim_bits {
// print_tile("IBUF_UIM.16", bits, |x| {
// print!("{}.{}.{}.{}", x.fb, x.row, x.column, x.bit)
// });
// }

let devices: EntityVec<_, _> = db
.devices
Expand Down Expand Up @@ -1213,6 +1162,17 @@ pub fn main() -> Result<(), Box<dyn Error>> {
} else {
None
},
program_time: match (device.kind, device.fbs) {
(DeviceKind::Xc9500, 2) => 640,
(DeviceKind::Xc9500, 4) => 320,
(DeviceKind::Xc9500, _) => 160,
_ => 20000,
},
erase_time: if device.kind == DeviceKind::Xc9500 {
1300000
} else {
200000
},
}
})
.collect();
Expand Down Expand Up @@ -1339,6 +1299,8 @@ pub fn main() -> Result<(), Box<dyn Error>> {
} else {
serde_json::Value::Null
},
"program_time": device.program_time,
"erase_time": device.erase_time,
}))),
"bonds": Vec::from_iter(
database.bonds.values().map(|bond| json!({
Expand Down

0 comments on commit 5162a31

Please sign in to comment.