#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Constraint {
pub min_nck: u64,
pub min_ps: u64,
}
impl Constraint {
#[must_use]
pub const fn clocks(min_nck: u64) -> Self {
Self { min_nck, min_ps: 0 }
}
#[must_use]
pub const fn ps(min_ps: u64) -> Self {
Self { min_nck: 0, min_ps }
}
#[must_use]
pub const fn max(min_nck: u64, min_ps: u64) -> Self {
Self { min_nck, min_ps }
}
#[must_use]
pub const fn cycles(self, data_rate_mts: u64) -> u64 {
let from_ps = (self.min_ps * data_rate_mts).div_ceil(2_000_000);
if from_ps > self.min_nck { from_ps } else { self.min_nck }
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Ddr5SpeedBin {
pub data_rate_mts: u64,
pub cl: u64,
pub cwl: u64,
pub t_rcd: Constraint,
pub t_rp: Constraint,
pub t_ras: Constraint,
pub t_rc: Constraint,
pub t_rrd_s: Constraint,
pub t_rrd_l: Constraint,
pub t_ccd_s: Constraint,
pub t_ccd_l: Constraint,
pub t_ccd_l_wr: Constraint,
pub t_faw: Constraint,
pub t_wtr_s: Constraint,
pub t_wtr_l: Constraint,
pub t_wr: Constraint,
pub t_rtp: Constraint,
pub t_ppd: Constraint,
pub t_rfc1: Constraint,
pub t_rfc2: Constraint,
pub t_rfcsb: Constraint,
pub t_refi: Constraint,
pub t_xp: Constraint,
pub t_pd: Constraint,
}
impl Ddr5SpeedBin {
pub const DDR5_4800B: Self = Self {
data_rate_mts: 4800,
cl: 40,
cwl: 38,
t_rcd: Constraint::ps(16_250),
t_rp: Constraint::ps(16_250),
t_ras: Constraint::ps(32_000),
t_rc: Constraint::ps(48_250),
t_rrd_s: Constraint::max(8, 2_500),
t_rrd_l: Constraint::max(8, 5_000),
t_ccd_s: Constraint::clocks(8),
t_ccd_l: Constraint::max(8, 5_000),
t_ccd_l_wr: Constraint::max(32, 20_000),
t_faw: Constraint::max(32, 13_333),
t_wtr_s: Constraint::max(4, 2_500),
t_wtr_l: Constraint::max(16, 10_000),
t_wr: Constraint::ps(30_000),
t_rtp: Constraint::max(12, 7_500),
t_ppd: Constraint::clocks(2),
t_rfc1: Constraint::ps(295_000),
t_rfc2: Constraint::ps(160_000),
t_rfcsb: Constraint::ps(130_000),
t_refi: Constraint::ps(3_900_000),
t_xp: Constraint::max(8, 7_500),
t_pd: Constraint::max(8, 7_500),
};
pub const DDR5_5600B: Self = Self {
data_rate_mts: 5600,
cl: 46,
cwl: 44,
t_rcd: Constraint::ps(16_071),
t_rp: Constraint::ps(16_071),
t_ras: Constraint::ps(32_000),
t_rc: Constraint::ps(48_071),
..Self::DDR5_4800B
};
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Ddr5Timing {
pub data_rate_mts: u64,
pub t_cas: u64,
pub t_cwl: u64,
pub t_rcd: u64,
pub t_rp: u64,
pub t_ras: u64,
pub t_rc: u64,
pub t_rrd_s: u64,
pub t_rrd_l: u64,
pub t_ccd_s: u64,
pub t_ccd_l: u64,
pub t_ccd_l_wr: u64,
pub t_faw: u64,
pub t_wtr_s: u64,
pub t_wtr_l: u64,
pub t_rtw: u64,
pub t_wr: u64,
pub t_rtp: u64,
pub t_ppd: u64,
pub t_rtrs: u64,
pub t_rfc1: u64,
pub t_rfc2: u64,
pub t_rfcsb: u64,
pub t_refi: u64,
pub t_xp: u64,
pub t_pd: u64,
pub bl_half: u64,
}
impl Ddr5Timing {
#[must_use]
pub const fn from_bin(bin: &Ddr5SpeedBin) -> Self {
let rate = bin.data_rate_mts;
Self {
data_rate_mts: rate,
t_cas: bin.cl,
t_cwl: bin.cwl,
t_rcd: bin.t_rcd.cycles(rate),
t_rp: bin.t_rp.cycles(rate),
t_ras: bin.t_ras.cycles(rate),
t_rc: bin.t_rc.cycles(rate),
t_rrd_s: bin.t_rrd_s.cycles(rate),
t_rrd_l: bin.t_rrd_l.cycles(rate),
t_ccd_s: bin.t_ccd_s.cycles(rate),
t_ccd_l: bin.t_ccd_l.cycles(rate),
t_ccd_l_wr: bin.t_ccd_l_wr.cycles(rate),
t_faw: bin.t_faw.cycles(rate),
t_wtr_s: bin.t_wtr_s.cycles(rate),
t_wtr_l: bin.t_wtr_l.cycles(rate),
t_rtw: 2,
t_wr: bin.t_wr.cycles(rate),
t_rtp: bin.t_rtp.cycles(rate),
t_ppd: bin.t_ppd.cycles(rate),
t_rtrs: 2,
t_rfc1: bin.t_rfc1.cycles(rate),
t_rfc2: bin.t_rfc2.cycles(rate),
t_rfcsb: bin.t_rfcsb.cycles(rate),
t_refi: bin.t_refi.cycles(rate),
t_xp: bin.t_xp.cycles(rate),
t_pd: bin.t_pd.cycles(rate),
bl_half: 8,
}
}
#[must_use]
pub const fn ddr5_4800() -> Self {
Self::from_bin(&Ddr5SpeedBin::DDR5_4800B)
}
#[inline]
#[must_use]
pub const fn tck_ps(&self) -> u64 {
2_000_000 / self.data_rate_mts
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, serde::Deserialize)]
#[serde(rename_all = "snake_case")]
#[allow(missing_docs)]
pub enum Ddr5TimingField {
TCas,
TCwl,
TRcd,
TRp,
TRas,
TRc,
TRrdS,
TRrdL,
TCcdS,
TCcdL,
TCcdLWr,
TFaw,
TWtrS,
TWtrL,
TRtw,
TWr,
TRtp,
TPpd,
TRtrs,
TRfc1,
TRfc2,
TRfcsb,
TRefi,
TXp,
TPd,
BlHalf,
}
impl Ddr5Timing {
pub const fn set(&mut self, field: Ddr5TimingField, clocks: u64) {
match field {
Ddr5TimingField::TCas => self.t_cas = clocks,
Ddr5TimingField::TCwl => self.t_cwl = clocks,
Ddr5TimingField::TRcd => self.t_rcd = clocks,
Ddr5TimingField::TRp => self.t_rp = clocks,
Ddr5TimingField::TRas => self.t_ras = clocks,
Ddr5TimingField::TRc => self.t_rc = clocks,
Ddr5TimingField::TRrdS => self.t_rrd_s = clocks,
Ddr5TimingField::TRrdL => self.t_rrd_l = clocks,
Ddr5TimingField::TCcdS => self.t_ccd_s = clocks,
Ddr5TimingField::TCcdL => self.t_ccd_l = clocks,
Ddr5TimingField::TCcdLWr => self.t_ccd_l_wr = clocks,
Ddr5TimingField::TFaw => self.t_faw = clocks,
Ddr5TimingField::TWtrS => self.t_wtr_s = clocks,
Ddr5TimingField::TWtrL => self.t_wtr_l = clocks,
Ddr5TimingField::TRtw => self.t_rtw = clocks,
Ddr5TimingField::TWr => self.t_wr = clocks,
Ddr5TimingField::TRtp => self.t_rtp = clocks,
Ddr5TimingField::TPpd => self.t_ppd = clocks,
Ddr5TimingField::TRtrs => self.t_rtrs = clocks,
Ddr5TimingField::TRfc1 => self.t_rfc1 = clocks,
Ddr5TimingField::TRfc2 => self.t_rfc2 = clocks,
Ddr5TimingField::TRfcsb => self.t_rfcsb = clocks,
Ddr5TimingField::TRefi => self.t_refi = clocks,
Ddr5TimingField::TXp => self.t_xp = clocks,
Ddr5TimingField::TPd => self.t_pd = clocks,
Ddr5TimingField::BlHalf => self.bl_half = clocks,
}
}
}
impl Default for Ddr5Timing {
fn default() -> Self {
Self::ddr5_4800()
}
}