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(), additional_fields: (*additional_fields).into(),
}, },
Annotation::Xilinx(XilinxAnnotation::XdcLocation(_)) Annotation::Xilinx(XilinxAnnotation::XdcLocation(_))
| Annotation::Xilinx(XilinxAnnotation::XdcIOStandard(_)) => return, | Annotation::Xilinx(XilinxAnnotation::XdcIOStandard(_))
| Annotation::Xilinx(XilinxAnnotation::XdcCreateClock(_)) => return,
}; };
self.annotations.push(FirrtlAnnotation { self.annotations.push(FirrtlAnnotation {
data, data,

View file

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

View file

@ -8,6 +8,7 @@ use crate::{
prelude::{DynPlatform, Platform}, prelude::{DynPlatform, Platform},
}; };
use clap::ValueEnum; use clap::ValueEnum;
use ordered_float::NotNan;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::fmt; use std::fmt;
@ -25,11 +26,18 @@ pub struct XdcLocationAnnotation {
pub location: Interned<str>, 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! { make_annotation_enum! {
#[non_exhaustive] #[non_exhaustive]
pub enum XilinxAnnotation { pub enum XilinxAnnotation {
XdcIOStandard(XdcIOStandardAnnotation), XdcIOStandard(XdcIOStandardAnnotation),
XdcLocation(XdcLocationAnnotation), XdcLocation(XdcLocationAnnotation),
XdcCreateClock(XdcCreateClockAnnotation),
} }
} }

View file

@ -3,7 +3,10 @@
use std::sync::OnceLock; use std::sync::OnceLock;
use ordered_float::NotNan;
use crate::{ use crate::{
annotations::Annotation,
intern::{Intern, Interned}, intern::{Intern, Interned},
module::{instance_with_loc, reg_builder_with_loc, wire_with_loc}, module::{instance_with_loc, reg_builder_with_loc, wire_with_loc},
platform::{ platform::{
@ -13,7 +16,7 @@ use crate::{
}, },
prelude::*, prelude::*,
vendor::xilinx::{ vendor::xilinx::{
Device, XdcIOStandardAnnotation, XdcLocationAnnotation, Device, XdcCreateClockAnnotation, XdcIOStandardAnnotation, XdcLocationAnnotation,
primitives::{self, BUFGCE, STARTUPE2_default_inputs}, primitives::{self, BUFGCE, STARTUPE2_default_inputs},
}, },
}; };
@ -165,7 +168,11 @@ impl Platform for ArtyA7Platform {
ld6, ld6,
ld7, ld7,
} = peripherals; } = 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); let pin = m.input_with_loc(name, SourceLocation::builtin(), Bool);
annotate( annotate(
pin, pin,
@ -179,6 +186,7 @@ impl Platform for ArtyA7Platform {
value: io_standard.intern(), value: io_standard.intern(),
}, },
); );
annotate(pin, additional_annotations);
let buf = instance_with_loc( let buf = instance_with_loc(
&format!("{name}_buf"), &format!("{name}_buf"),
primitives::IBUF(), primitives::IBUF(),
@ -210,7 +218,16 @@ impl Platform for ArtyA7Platform {
connect(buf.T, false); connect(buf.T, false);
buf.I 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( let startup = instance_with_loc(
"startup", "startup",
STARTUPE2_default_inputs(), STARTUPE2_default_inputs(),
@ -222,12 +239,13 @@ impl Platform for ArtyA7Platform {
if let Some(clk100) = clk100.into_used() { if let Some(clk100) = clk100.into_used() {
connect(clk100.instance_io_field().clk, clk100_sync.O); 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( let rst_sync_cd = wire_with_loc(
"rst_sync_cd", "rst_sync_cd",
SourceLocation::builtin(), SourceLocation::builtin(),
ClockDomain[AsyncReset], ClockDomain[AsyncReset],
); );
annotate(clk100_sync.O, clock_annotation);
connect(rst_sync_cd.clk, clk100_sync.O); connect(rst_sync_cd.clk, clk100_sync.O);
connect(rst_sync_cd.rst, rst_buf.to_async_reset()); connect(rst_sync_cd.rst, rst_buf.to_async_reset());
let [rst_sync_0, rst_sync_1] = std::array::from_fn(|index| { let [rst_sync_0, rst_sync_1] = std::array::from_fn(|index| {

View file

@ -19,7 +19,8 @@ use crate::{
prelude::JobParams, prelude::JobParams,
util::job_server::AcquiredJob, util::job_server::AcquiredJob,
vendor::xilinx::{ vendor::xilinx::{
Device, XdcIOStandardAnnotation, XdcLocationAnnotation, XilinxAnnotation, XilinxArgs, Device, XdcCreateClockAnnotation, XdcIOStandardAnnotation, XdcLocationAnnotation,
XilinxAnnotation, XilinxArgs,
}, },
}; };
use eyre::Context; use eyre::Context;
@ -390,7 +391,7 @@ impl YosysNextpnrXrayWriteXdcFile {
output, output,
"set_property LOC {} [get_ports {}]", "set_property LOC {} [get_ports {}]",
tcl_escape(location), tcl_escape(location),
tcl_escape(port.scalarized_name()) tcl_escape(port.scalarized_name()),
)?, )?,
Annotation::Xilinx(XilinxAnnotation::XdcIOStandard(XdcIOStandardAnnotation { Annotation::Xilinx(XilinxAnnotation::XdcIOStandard(XdcIOStandardAnnotation {
value, value,
@ -398,7 +399,14 @@ impl YosysNextpnrXrayWriteXdcFile {
output, output,
"set_property IOSTANDARD {} [get_ports {}]", "set_property IOSTANDARD {} [get_ports {}]",
tcl_escape(value), 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": { "data": {
"$kind": "Enum", "$kind": "Enum",
"XdcLocation": "Visible", "XdcLocation": "Visible",
"XdcIOStandard": "Visible" "XdcIOStandard": "Visible",
"XdcCreateClock": "Visible"
} }
}, },
"XdcLocationAnnotation": { "XdcLocationAnnotation": {
@ -1232,6 +1233,11 @@
"$kind": "Opaque" "$kind": "Opaque"
} }
}, },
"XdcCreateClockAnnotation": {
"data": {
"$kind": "Opaque"
}
},
"Target": { "Target": {
"data": { "data": {
"$kind": "Enum", "$kind": "Enum",