xc2bit/
globalbits.rs

1/*
2Copyright (c) 2016-2017, Robert Ou <rqou@robertou.com> and contributors
3All rights reserved.
4
5Redistribution and use in source and binary forms, with or without
6modification, are permitted provided that the following conditions are met:
7
81. Redistributions of source code must retain the above copyright notice,
9   this list of conditions and the following disclaimer.
102. Redistributions in binary form must reproduce the above copyright notice,
11   this list of conditions and the following disclaimer in the documentation
12   and/or other materials provided with the distribution.
13
14THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
15ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
18FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24*/
25
26//! Contains functions pertaining to global control bits (e.g. clocks)
27
28use std::io;
29use std::io::Write;
30
31use crate::*;
32use crate::fusemap_logical::{gck_fuse_idx, gsr_fuse_idx, gts_fuse_idx, global_term_fuse_idx, clock_div_fuse_idx};
33use crate::fusemap_physical::{gck_fuse_coords, gsr_fuse_coords, gts_fuse_coords, global_term_fuse_coord,
34                              clock_div_fuse_coord};
35
36/// Represents the configuration of the global nets. Coolrunner-II parts have various global control signals that have
37/// dedicated low-skew paths.
38#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Serialize, Deserialize)]
39pub struct XC2GlobalNets {
40    /// Controls whether the three global clock nets are enabled or not
41    pub gck_enable: [bool; 3],
42    /// Controls whether the global set/reset net is enabled or not
43    pub gsr_enable: bool,
44    /// Controls the polarity of the global set/reset signal
45    ///
46    /// `false` = active low, `true` = active high
47    pub gsr_invert: bool,
48    /// Controls whether the four global tristate nets are enabled or not
49    pub gts_enable: [bool; 4],
50    /// Controls the polarity of the global tristate signal
51    ///
52    /// `false` = used as T, `true` = used as !T
53    pub gts_invert: [bool; 4],
54    /// Controls the mode of the global termination
55    ///
56    /// `false` = keeper, `true` = pull-up
57    pub global_pu: bool,
58}
59
60impl Default for XC2GlobalNets {
61    /// Returns a "default" global net configuration which has everything disabled.
62    fn default() -> Self {
63        XC2GlobalNets {
64            gck_enable: [false; 3],
65            gsr_enable: false,
66            gsr_invert: false,
67            gts_enable: [false; 4],
68            gts_invert: [true; 4],
69            global_pu: true,
70        }
71    }
72}
73
74impl XC2GlobalNets {
75    /// Dump a human-readable explanation of the global net configuration to the given `writer` object.
76    pub fn dump_human_readable<W: Write>(&self, mut writer: W) -> Result<(), io::Error> {
77        write!(writer, "\n")?;
78        write!(writer, "GCK0 {}\n", if self.gck_enable[0] {"enabled"} else {"disabled"})?;
79        write!(writer, "GCK1 {}\n", if self.gck_enable[1] {"enabled"} else {"disabled"})?;
80        write!(writer, "GCK2 {}\n", if self.gck_enable[2] {"enabled"} else {"disabled"})?;
81
82        write!(writer, "GSR {}, active {}\n",
83            if self.gsr_enable {"enabled"} else {"disabled"},
84            if self.gsr_invert {"high"} else {"low"})?;
85
86        write!(writer, "GTS0 {}, acts as {}\n",
87            if self.gts_enable[0] {"enabled"} else {"disabled"},
88            if self.gts_invert[0] {"!T"} else {"T"})?;
89        write!(writer, "GTS1 {}, acts as {}\n",
90            if self.gts_enable[1] {"enabled"} else {"disabled"},
91            if self.gts_invert[1] {"!T"} else {"T"})?;
92        write!(writer, "GTS2 {}, acts as {}\n",
93            if self.gts_enable[2] {"enabled"} else {"disabled"},
94            if self.gts_invert[2] {"!T"} else {"T"})?;
95        write!(writer, "GTS3 {}, acts as {}\n",
96            if self.gts_enable[3] {"enabled"} else {"disabled"},
97            if self.gts_invert[3] {"!T"} else {"T"})?;
98
99        write!(writer, "global termination is {}\n", if self.global_pu {"pull-up"} else {"bus hold"})?;
100
101        Ok(())
102    }
103
104    /// Write the crbit representation of the global net settings to the given `fuse_array`.
105    pub fn to_crbit(&self, device: XC2Device, fuse_array: &mut FuseArray) {
106        let ((gck0x, gck0y), (gck1x, gck1y), (gck2x, gck2y)) = gck_fuse_coords(device);
107        fuse_array.set(gck0x, gck0y, self.gck_enable[0]);
108        fuse_array.set(gck1x, gck1y, self.gck_enable[1]);
109        fuse_array.set(gck2x, gck2y, self.gck_enable[2]);
110
111        let ((gsren_x, gsren_y), (gsrinv_x, gsrinv_y)) = gsr_fuse_coords(device);
112        fuse_array.set(gsren_x, gsren_y, self.gsr_enable);
113        fuse_array.set(gsrinv_x, gsrinv_y, self.gsr_invert);
114
115        let (((gts0en_x, gts0en_y), (gts0inv_x, gts0inv_y)), ((gts1en_x, gts1en_y), (gts1inv_x, gts1inv_y)),
116             ((gts2en_x, gts2en_y), (gts2inv_x, gts2inv_y)), ((gts3en_x, gts3en_y), (gts3inv_x, gts3inv_y))) =
117                gts_fuse_coords(device);
118        fuse_array.set(gts0en_x, gts0en_y, !self.gts_enable[0]);
119        fuse_array.set(gts0inv_x, gts0inv_y, self.gts_invert[0]);
120        fuse_array.set(gts1en_x, gts1en_y, !self.gts_enable[1]);
121        fuse_array.set(gts1inv_x, gts1inv_y, self.gts_invert[1]);
122        fuse_array.set(gts2en_x, gts2en_y, !self.gts_enable[2]);
123        fuse_array.set(gts2inv_x, gts2inv_y, self.gts_invert[2]);
124        fuse_array.set(gts3en_x, gts3en_y, !self.gts_enable[3]);
125        fuse_array.set(gts3inv_x, gts3inv_y, self.gts_invert[3]);
126
127        let (term_x, term_y) = global_term_fuse_coord(device);
128        fuse_array.set(term_x, term_y, self.global_pu);
129    }
130
131    /// Internal function to read the global nets
132    pub fn from_jed(device: XC2Device, fuses: &[bool]) -> Self {
133        XC2GlobalNets {
134            gck_enable: [
135                fuses[gck_fuse_idx(device) + 0],
136                fuses[gck_fuse_idx(device) + 1],
137                fuses[gck_fuse_idx(device) + 2],
138            ],
139            gsr_enable: fuses[gsr_fuse_idx(device) + 1],
140            gsr_invert: fuses[gsr_fuse_idx(device) + 0],
141            gts_enable: [
142                !fuses[gts_fuse_idx(device) + 1],
143                !fuses[gts_fuse_idx(device) + 3],
144                !fuses[gts_fuse_idx(device) + 5],
145                !fuses[gts_fuse_idx(device) + 7],
146            ],
147            gts_invert: [
148                fuses[gts_fuse_idx(device) + 0],
149                fuses[gts_fuse_idx(device) + 2],
150                fuses[gts_fuse_idx(device) + 4],
151                fuses[gts_fuse_idx(device) + 6],
152            ],
153            global_pu: fuses[global_term_fuse_idx(device)],
154        }
155    }
156
157    /// Internal function to read the global nets
158    pub fn from_crbit(device: XC2Device, fuse_array: &FuseArray) -> Self {
159        let ((gck0x, gck0y), (gck1x, gck1y), (gck2x, gck2y)) = gck_fuse_coords(device);
160
161        let ((gsren_x, gsren_y), (gsrinv_x, gsrinv_y)) = gsr_fuse_coords(device);
162
163        let (((gts0en_x, gts0en_y), (gts0inv_x, gts0inv_y)), ((gts1en_x, gts1en_y), (gts1inv_x, gts1inv_y)),
164             ((gts2en_x, gts2en_y), (gts2inv_x, gts2inv_y)), ((gts3en_x, gts3en_y), (gts3inv_x, gts3inv_y))) =
165                gts_fuse_coords(device);
166
167        let (term_x, term_y) = global_term_fuse_coord(device);
168
169        XC2GlobalNets {
170            gck_enable: [
171                fuse_array.get(gck0x, gck0y),
172                fuse_array.get(gck1x, gck1y),
173                fuse_array.get(gck2x, gck2y),
174            ],
175            gsr_enable: fuse_array.get(gsren_x, gsren_y),
176            gsr_invert: fuse_array.get(gsrinv_x, gsrinv_y),
177            gts_enable: [
178                !fuse_array.get(gts0en_x, gts0en_y),
179                !fuse_array.get(gts1en_x, gts1en_y),
180                !fuse_array.get(gts2en_x, gts2en_y),
181                !fuse_array.get(gts3en_x, gts3en_y),
182            ],
183            gts_invert: [
184                fuse_array.get(gts0inv_x, gts0inv_y),
185                fuse_array.get(gts1inv_x, gts1inv_y),
186                fuse_array.get(gts2inv_x, gts2inv_y),
187                fuse_array.get(gts3inv_x, gts3inv_y),
188            ],
189            global_pu: fuse_array.get(term_x, term_y),
190        }
191    }
192}
193
194/// Possible clock divide ratios for the programmable clock divider
195#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Serialize, Deserialize)]
196#[derive(BitPattern)]
197pub enum XC2ClockDivRatio {
198    #[bits = "000"]
199    Div2,
200    #[bits = "001"]
201    Div4,
202    #[bits = "010"]
203    Div6,
204    #[bits = "011"]
205    Div8,
206    #[bits = "100"]
207    Div10,
208    #[bits = "101"]
209    Div12,
210    #[bits = "110"]
211    Div14,
212    #[bits = "111"]
213    Div16,
214}
215
216/// Represents the configuration of the programmable clock divider in devices with 128 macrocells or more. This is
217/// hard-wired onto the GCK2 clock pin.
218#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Serialize, Deserialize)]
219pub struct XC2ClockDiv {
220    /// Ratio that input clock is divided by
221    pub div_ratio: XC2ClockDivRatio,
222    /// Whether the "delay" feature is enabled
223    pub delay: bool,
224    /// Whether the clock divider is enabled (other settings are ignored if not)
225    pub enabled: bool,
226}
227
228impl XC2ClockDiv {
229    /// Dump a human-readable explanation of the clock divider to the given `writer` object.
230    pub fn dump_human_readable<W: Write>(&self, mut writer: W) -> Result<(), io::Error> {
231        write!(writer, "\n")?;
232        write!(writer, "GCK2 clock divider {}\n", if self.enabled {"enabled"} else {"disabled"})?;
233        write!(writer, "clock divider delay {}\n", if self.delay {"enabled"} else {"disabled"})?;
234
235        write!(writer, "clock division ratio: {}\n", match self.div_ratio {
236            XC2ClockDivRatio::Div2 => "2",
237            XC2ClockDivRatio::Div4 => "4",
238            XC2ClockDivRatio::Div6 => "6",
239            XC2ClockDivRatio::Div8 => "8",
240            XC2ClockDivRatio::Div10 => "10",
241            XC2ClockDivRatio::Div12 => "12",
242            XC2ClockDivRatio::Div14 => "14",
243            XC2ClockDivRatio::Div16 => "16",
244        })?;
245
246        Ok(())
247    }
248}
249
250impl Default for XC2ClockDiv {
251    /// Returns a "default" clock divider configuration, which is one that is not used
252    fn default() -> Self {
253        XC2ClockDiv {
254            div_ratio: XC2ClockDivRatio::Div16,
255            delay: false,
256            enabled: false,
257        }
258    }
259}
260
261impl XC2ClockDiv {
262    /// Internal function to read the clock divider configuration from a 128-macrocell part
263    pub fn from_jed(device: XC2Device, fuses: &[bool]) -> Self {
264        let clock_fuse_block = clock_div_fuse_idx(device);
265
266        XC2ClockDiv {
267            delay: !fuses[clock_fuse_block + 4],
268            enabled: !fuses[clock_fuse_block],
269            div_ratio: XC2ClockDivRatio::decode((fuses[clock_fuse_block + 1], fuses[clock_fuse_block + 2], fuses[clock_fuse_block + 3])),
270        }
271    }
272
273    /// Internal function to read the clock divider configuration from a 128-macrocell part
274    pub fn from_crbit(device: XC2Device, fuse_array: &FuseArray) -> Self {
275        let ((clken_x, clken_y), (clkdiv0_x, clkdiv0_y), (clkdiv1_x, clkdiv1_y), (clkdiv2_x, clkdiv2_y),
276            (clkdelay_x, clkdelay_y)) = clock_div_fuse_coord(device);
277
278        let div_ratio_bits = (fuse_array.get(clkdiv0_x, clkdiv0_y),
279                              fuse_array.get(clkdiv1_x, clkdiv1_y),
280                              fuse_array.get(clkdiv2_x, clkdiv2_y));
281
282        XC2ClockDiv {
283            delay: !fuse_array.get(clkdelay_x, clkdelay_y),
284            enabled: !fuse_array.get(clken_x, clken_y),
285            div_ratio: XC2ClockDivRatio::decode(div_ratio_bits),
286        }
287    }
288}