WIP adding xdc create_clock -- nextpnr-xilinx currently ignores it
All checks were successful
/ test (pull_request) Successful in 4m35s

This commit is contained in:
Jacob Lifshay 2025-10-19 23:10:38 -07:00
parent 477a1f2d29
commit 2bdc8a7c72
Signed by: programmerjake
SSH key fingerprint: SHA256:HnFTLGpSm4Q4Fj502oCFisjZSoakwEuTsJJMSke63RQ
6 changed files with 53 additions and 10 deletions

View file

@ -1907,7 +1907,8 @@ impl<'a> Exporter<'a> {
additional_fields: (*additional_fields).into(),
},
Annotation::Xilinx(XilinxAnnotation::XdcLocation(_))
| Annotation::Xilinx(XilinxAnnotation::XdcIOStandard(_)) => return,
| Annotation::Xilinx(XilinxAnnotation::XdcIOStandard(_))
| Annotation::Xilinx(XilinxAnnotation::XdcCreateClock(_)) => return,
};
self.annotations.push(FirrtlAnnotation {
data,

View file

@ -33,7 +33,9 @@ use crate::{
sim::{ExternModuleSimulation, value::DynSimOnly},
source_location::SourceLocation,
ty::{CanonicalType, Type},
vendor::xilinx::{XdcIOStandardAnnotation, XdcLocationAnnotation, XilinxAnnotation},
vendor::xilinx::{
XdcCreateClockAnnotation, XdcIOStandardAnnotation, XdcLocationAnnotation, XilinxAnnotation,
},
wire::Wire,
};
use num_bigint::{BigInt, BigUint};

View file

@ -8,6 +8,7 @@ use crate::{
prelude::{DynPlatform, Platform},
};
use clap::ValueEnum;
use ordered_float::NotNan;
use serde::{Deserialize, Serialize};
use std::fmt;
@ -25,11 +26,18 @@ pub struct XdcLocationAnnotation {
pub location: Interned<str>,
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct XdcCreateClockAnnotation {
/// clock period in nanoseconds
pub period: NotNan<f64>,
}
make_annotation_enum! {
#[non_exhaustive]
pub enum XilinxAnnotation {
XdcIOStandard(XdcIOStandardAnnotation),
XdcLocation(XdcLocationAnnotation),
XdcCreateClock(XdcCreateClockAnnotation),
}
}

View file

@ -3,7 +3,10 @@
use std::sync::OnceLock;
use ordered_float::NotNan;
use crate::{
annotations::Annotation,
intern::{Intern, Interned},
module::{instance_with_loc, reg_builder_with_loc, wire_with_loc},
platform::{
@ -13,7 +16,7 @@ use crate::{
},
prelude::*,
vendor::xilinx::{
Device, XdcIOStandardAnnotation, XdcLocationAnnotation,
Device, XdcCreateClockAnnotation, XdcIOStandardAnnotation, XdcLocationAnnotation,
primitives::{self, BUFGCE, STARTUPE2_default_inputs},
},
};
@ -165,7 +168,11 @@ impl Platform for ArtyA7Platform {
ld6,
ld7,
} = peripherals;
let make_buffered_input = |name: &str, location: &str, io_standard: &str, invert: bool| {
let make_buffered_input = |name: &str,
location: &str,
io_standard: &str,
additional_annotations: &[Annotation],
invert: bool| {
let pin = m.input_with_loc(name, SourceLocation::builtin(), Bool);
annotate(
pin,
@ -179,6 +186,7 @@ impl Platform for ArtyA7Platform {
value: io_standard.intern(),
},
);
annotate(pin, additional_annotations);
let buf = instance_with_loc(
&format!("{name}_buf"),
primitives::IBUF(),
@ -210,7 +218,16 @@ impl Platform for ArtyA7Platform {
connect(buf.T, false);
buf.I
};
let clk100_buf = make_buffered_input("clk100", "E3", "LVCMOS33", false);
let clock_annotation = XdcCreateClockAnnotation {
period: NotNan::new(1e9 / clk100.ty().frequency()).expect("known to be valid"),
};
let clk100_buf = make_buffered_input(
"clk100",
"E3",
"LVCMOS33",
&[clock_annotation.into()],
false,
);
let startup = instance_with_loc(
"startup",
STARTUPE2_default_inputs(),
@ -222,12 +239,13 @@ impl Platform for ArtyA7Platform {
if let Some(clk100) = clk100.into_used() {
connect(clk100.instance_io_field().clk, clk100_sync.O);
}
let rst_buf = make_buffered_input("rst", "C2", "LVCMOS33", true);
let rst_buf = make_buffered_input("rst", "C2", "LVCMOS33", &[], true);
let rst_sync_cd = wire_with_loc(
"rst_sync_cd",
SourceLocation::builtin(),
ClockDomain[AsyncReset],
);
annotate(clk100_sync.O, clock_annotation);
connect(rst_sync_cd.clk, clk100_sync.O);
connect(rst_sync_cd.rst, rst_buf.to_async_reset());
let [rst_sync_0, rst_sync_1] = std::array::from_fn(|index| {

View file

@ -19,7 +19,8 @@ use crate::{
prelude::JobParams,
util::job_server::AcquiredJob,
vendor::xilinx::{
Device, XdcIOStandardAnnotation, XdcLocationAnnotation, XilinxAnnotation, XilinxArgs,
Device, XdcCreateClockAnnotation, XdcIOStandardAnnotation, XdcLocationAnnotation,
XilinxAnnotation, XilinxArgs,
},
};
use eyre::Context;
@ -390,7 +391,7 @@ impl YosysNextpnrXrayWriteXdcFile {
output,
"set_property LOC {} [get_ports {}]",
tcl_escape(location),
tcl_escape(port.scalarized_name())
tcl_escape(port.scalarized_name()),
)?,
Annotation::Xilinx(XilinxAnnotation::XdcIOStandard(XdcIOStandardAnnotation {
value,
@ -398,7 +399,14 @@ impl YosysNextpnrXrayWriteXdcFile {
output,
"set_property IOSTANDARD {} [get_ports {}]",
tcl_escape(value),
tcl_escape(port.scalarized_name())
tcl_escape(port.scalarized_name()),
)?,
Annotation::Xilinx(XilinxAnnotation::XdcCreateClock(
XdcCreateClockAnnotation { period },
)) => writeln!(
output,
"create_clock -period {period} [get_ports {}]",
tcl_escape(port.scalarized_name()),
)?,
}
}

View file

@ -1219,7 +1219,8 @@
"data": {
"$kind": "Enum",
"XdcLocation": "Visible",
"XdcIOStandard": "Visible"
"XdcIOStandard": "Visible",
"XdcCreateClock": "Visible"
}
},
"XdcLocationAnnotation": {
@ -1232,6 +1233,11 @@
"$kind": "Opaque"
}
},
"XdcCreateClockAnnotation": {
"data": {
"$kind": "Opaque"
}
},
"Target": {
"data": {
"$kind": "Enum",