forked from libre-chip/fayalite
Compare commits
1 commit
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
34b4a57507 |
8 changed files with 480 additions and 394 deletions
21
Makefile
Normal file
21
Makefile
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
DIRU=/home/alex/Desktop/Hacking/libre-chip/fayalite-wip/target/blinky-out
|
||||||
|
NEXTPNR_DENSITY:=--25k
|
||||||
|
|
||||||
|
all:
|
||||||
|
cp $(DIRU)/*.pcf /tmp
|
||||||
|
RUST_BACKTRACE=full cargo run --example blinky yosys-nextpnr-ecp5 \
|
||||||
|
--nextpnr /home/alex/.guix-profile/bin/nextpnr-ecp5 \
|
||||||
|
--platform orangecrab-85k -o target/blinky-out \
|
||||||
|
--ecppack /home/alex/.guix-profile/bin/ecppack \
|
||||||
|
--placeholder-dir /tmp/anyPathBuf/orangecrab_r0.2.1.pcf
|
||||||
|
ls -1 $(DIRU)/*.bit
|
||||||
|
ls:
|
||||||
|
ls -1 $(DIRU)
|
||||||
|
clean:
|
||||||
|
rm $(DIRU)/*
|
||||||
|
nextpnr:
|
||||||
|
cd $(DIRU) && nextpnr-ecp5 --json blinky.json --textcfg blinky.nextpnr.out $(NEXTPNR_DENSITY) \
|
||||||
|
--package CSFBGA285 --lpf orangecrab_r0.2.1.pcf --lpf-allow-unconstrained
|
||||||
|
pack:
|
||||||
|
cd $(DIRU) && ecppack --compress --freq 38.8 --input blinky.nextpnr.out --bit blinky.nextpnr.bit
|
||||||
|
cd $(DIRU) && file *.bit
|
||||||
|
|
@ -2,11 +2,14 @@
|
||||||
// See Notices.txt for copyright information
|
// See Notices.txt for copyright information
|
||||||
|
|
||||||
pub mod xilinx;
|
pub mod xilinx;
|
||||||
|
pub mod lattice;
|
||||||
|
|
||||||
pub(crate) fn built_in_job_kinds() -> impl IntoIterator<Item = crate::build::DynJobKind> {
|
pub(crate) fn built_in_job_kinds() -> impl IntoIterator<Item = crate::build::DynJobKind> {
|
||||||
xilinx::built_in_job_kinds()
|
xilinx::built_in_job_kinds();
|
||||||
|
lattice::built_in_job_kinds()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn built_in_platforms() -> impl IntoIterator<Item = crate::platform::DynPlatform> {
|
pub(crate) fn built_in_platforms() -> impl IntoIterator<Item = crate::platform::DynPlatform> {
|
||||||
xilinx::built_in_platforms()
|
xilinx::built_in_platforms();
|
||||||
|
lattice::built_in_platforms()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
174
crates/fayalite/src/vendor/lattice.rs
vendored
174
crates/fayalite/src/vendor/lattice.rs
vendored
|
|
@ -12,4 +12,176 @@ use ordered_float::NotNan;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
// copy of xilinx.rs with same header
|
pub mod orangecrab;
|
||||||
|
pub mod primitives;
|
||||||
|
pub mod yosys_nextpnr;
|
||||||
|
|
||||||
|
#[derive(Clone, PartialEq, Eq, Hash, Debug, clap::Args)]
|
||||||
|
pub struct LatticeArgs {
|
||||||
|
#[arg(long)]
|
||||||
|
pub device: Option<Device>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LatticeArgs {
|
||||||
|
pub fn require_device(
|
||||||
|
&self,
|
||||||
|
platform: Option<&DynPlatform>,
|
||||||
|
global_params: &GlobalParams,
|
||||||
|
) -> clap::error::Result<Device> {
|
||||||
|
if let Some(device) = self.device {
|
||||||
|
return Ok(device);
|
||||||
|
}
|
||||||
|
if let Some(device) =
|
||||||
|
platform.and_then(|platform| platform.aspects().get_single_by_type::<Device>().copied())
|
||||||
|
{
|
||||||
|
return Ok(device);
|
||||||
|
}
|
||||||
|
Err(global_params.clap_error(
|
||||||
|
clap::error::ErrorKind::MissingRequiredArgument,
|
||||||
|
"missing --device option",
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToArgs for LatticeArgs {
|
||||||
|
fn to_args(&self, args: &mut (impl WriteArgs + ?Sized)) {
|
||||||
|
if let Some(device) = self.device {
|
||||||
|
args.write_long_option_eq("device", device.as_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! make_device_enum {
|
||||||
|
($vis:vis enum $Device:ident {
|
||||||
|
$(
|
||||||
|
#[
|
||||||
|
name = $name:literal,
|
||||||
|
lattice_part = $lattice_part:literal,
|
||||||
|
lattice_device = $lattice_device:literal,
|
||||||
|
lattice_family = $lattice_family:literal,
|
||||||
|
]
|
||||||
|
$variant:ident,
|
||||||
|
)*
|
||||||
|
}) => {
|
||||||
|
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, ValueEnum)]
|
||||||
|
$vis enum $Device {
|
||||||
|
$(
|
||||||
|
#[value(name = $name, alias = $lattice_part)]
|
||||||
|
$variant,
|
||||||
|
)*
|
||||||
|
}
|
||||||
|
|
||||||
|
impl $Device {
|
||||||
|
$vis fn as_str(self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
$(Self::$variant => $name,)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$vis fn lattice_part(self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
$(Self::$variant => $lattice_part,)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$vis fn lattice_device(self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
$(Self::$variant => $lattice_device,)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$vis fn lattice_family(self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
$(Self::$variant => $lattice_family,)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct DeviceVisitor;
|
||||||
|
|
||||||
|
impl<'de> serde::de::Visitor<'de> for DeviceVisitor {
|
||||||
|
type Value = $Device;
|
||||||
|
|
||||||
|
fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.write_str("a Lattice device string")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
|
||||||
|
where
|
||||||
|
E: serde::de::Error,
|
||||||
|
{
|
||||||
|
match $Device::from_str(v, false) {
|
||||||
|
Ok(v) => Ok(v),
|
||||||
|
Err(_) => Err(E::invalid_value(serde::de::Unexpected::Str(v), &self)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
|
||||||
|
where
|
||||||
|
E: serde::de::Error,
|
||||||
|
{
|
||||||
|
match str::from_utf8(v).ok().and_then(|v| $Device::from_str(v, false).ok()) {
|
||||||
|
Some(v) => Ok(v),
|
||||||
|
None => Err(E::invalid_value(serde::de::Unexpected::Bytes(v), &self)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> Deserialize<'de> for $Device {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: serde::Deserializer<'de>,
|
||||||
|
{
|
||||||
|
deserializer.deserialize_string(DeviceVisitor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Serialize for $Device {
|
||||||
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: serde::Serializer,
|
||||||
|
{
|
||||||
|
self.as_str().serialize(serializer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
//ECP5 variants
|
||||||
|
make_device_enum! {
|
||||||
|
pub enum Device {
|
||||||
|
#[
|
||||||
|
name = "placeholder25k",
|
||||||
|
lattice_part = "fixme",
|
||||||
|
lattice_device = "fixme",
|
||||||
|
lattice_family = "fixme",
|
||||||
|
]
|
||||||
|
Placeholder25k,
|
||||||
|
#[
|
||||||
|
name = "placeholder85k",
|
||||||
|
lattice_part = "fixme",
|
||||||
|
lattice_device = "fimxe",
|
||||||
|
lattice_family = "fixme",
|
||||||
|
]
|
||||||
|
Placeholder85k,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//rest looks good
|
||||||
|
|
||||||
|
impl fmt::Display for Device {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.write_str(self.as_str())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn built_in_job_kinds() -> impl IntoIterator<Item = crate::build::DynJobKind> {
|
||||||
|
orangecrab::built_in_job_kinds()
|
||||||
|
.into_iter()
|
||||||
|
.chain(yosys_nextpnr::built_in_job_kinds())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn built_in_platforms() -> impl IntoIterator<Item = crate::platform::DynPlatform> {
|
||||||
|
orangecrab::built_in_platforms()
|
||||||
|
.into_iter()
|
||||||
|
.chain(yosys_nextpnr::built_in_platforms())
|
||||||
|
}
|
||||||
|
|
||||||
|
//first step yosys -p "read_verilog $<; synth_ecp5 -json $@"
|
||||||
|
|
|
||||||
146
crates/fayalite/src/vendor/lattice/orangecrab.rs
vendored
146
crates/fayalite/src/vendor/lattice/orangecrab.rs
vendored
|
|
@ -10,28 +10,29 @@ use crate::{
|
||||||
peripherals::{ClockInput, Led, RgbLed, Uart},
|
peripherals::{ClockInput, Led, RgbLed, Uart},
|
||||||
},
|
},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
vendor::xilinx::{
|
vendor::lattice::{
|
||||||
Device, XdcCreateClockAnnotation, XdcIOStandardAnnotation, XdcLocationAnnotation,
|
Device,
|
||||||
primitives,
|
primitives,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use ordered_float::NotNan;
|
use ordered_float::NotNan;
|
||||||
use std::sync::OnceLock;
|
use std::sync::OnceLock;
|
||||||
|
|
||||||
macro_rules! arty_a7_platform {
|
//keep unchanged
|
||||||
|
macro_rules! orangecrab_platform {
|
||||||
(
|
(
|
||||||
$vis:vis enum $ArtyA7Platform:ident {
|
$vis:vis enum $OrangeCrabPlatform:ident {
|
||||||
$(#[name = $name:literal, device = $device:ident]
|
$(#[name = $name:literal, device = $device:ident]
|
||||||
$Variant:ident,)*
|
$Variant:ident,)*
|
||||||
}
|
}
|
||||||
) => {
|
) => {
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
|
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
$vis enum $ArtyA7Platform {
|
$vis enum $OrangeCrabPlatform {
|
||||||
$($Variant,)*
|
$($Variant,)*
|
||||||
}
|
}
|
||||||
|
|
||||||
impl $ArtyA7Platform {
|
impl $OrangeCrabPlatform {
|
||||||
$vis const VARIANTS: &'static [Self] = &[$(Self::$Variant,)*];
|
$vis const VARIANTS: &'static [Self] = &[$(Self::$Variant,)*];
|
||||||
$vis fn device(self) -> Device {
|
$vis fn device(self) -> Device {
|
||||||
match self {
|
match self {
|
||||||
|
|
@ -55,15 +56,17 @@ macro_rules! arty_a7_platform {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
arty_a7_platform! {
|
//untested
|
||||||
pub enum ArtyA7Platform {
|
orangecrab_platform! {
|
||||||
#[name = "arty-a7-35t", device = Xc7a35ticsg324_1l]
|
pub enum OrangeCrabPlatform {
|
||||||
ArtyA7_35T,
|
#[name = "orangecrab-25k", device = Placeholder25k]
|
||||||
#[name = "arty-a7-100t", device = Xc7a100ticsg324_1l]
|
OrangeCrab_25k,
|
||||||
ArtyA7_100T,
|
#[name = "orangecrab-85k", device = Placeholder85k]
|
||||||
|
OrangeCrab_85k,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//FIXME
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ArtyA7Peripherals {
|
pub struct ArtyA7Peripherals {
|
||||||
clk100_div_pow2: [Peripheral<ClockInput>; 4],
|
clk100_div_pow2: [Peripheral<ClockInput>; 4],
|
||||||
|
|
@ -112,7 +115,7 @@ impl Peripherals for ArtyA7Peripherals {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ArtyA7Platform {
|
impl OrangeCrabPlatform {
|
||||||
fn make_aspects(self) -> PlatformAspectSet {
|
fn make_aspects(self) -> PlatformAspectSet {
|
||||||
let mut retval = PlatformAspectSet::new();
|
let mut retval = PlatformAspectSet::new();
|
||||||
retval.insert_new(self.device());
|
retval.insert_new(self.device());
|
||||||
|
|
@ -129,37 +132,21 @@ fn reset_sync() {
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let out: SyncReset = m.output();
|
let out: SyncReset = m.output();
|
||||||
m.annotate_module(BlackBoxInlineAnnotation {
|
m.annotate_module(BlackBoxInlineAnnotation {
|
||||||
path: "fayalite_arty_a7_reset_sync.v".intern(),
|
path: "fayalite_orangecrab_reset_sync.v".intern(),
|
||||||
text: r#"module __fayalite_arty_a7_reset_sync(input clk, input inp, output out);
|
text: r#"module __fayalite_orangecrab_reset_sync(input clk, input inp, output out);
|
||||||
wire reset_0_out;
|
wire reset_0_out;
|
||||||
(* ASYNC_REG = "TRUE" *)
|
always @(posedge clk) begin
|
||||||
FDPE #(
|
reset_0_out <= inp;
|
||||||
.INIT(1'b1)
|
outp <= reset_0_out;
|
||||||
) reset_0 (
|
end
|
||||||
.Q(reset_0_out),
|
|
||||||
.C(clk),
|
|
||||||
.CE(1'b1),
|
|
||||||
.PRE(inp),
|
|
||||||
.D(1'b0)
|
|
||||||
);
|
|
||||||
(* ASYNC_REG = "TRUE" *)
|
|
||||||
FDPE #(
|
|
||||||
.INIT(1'b1)
|
|
||||||
) reset_1 (
|
|
||||||
.Q(out),
|
|
||||||
.C(clk),
|
|
||||||
.CE(1'b1),
|
|
||||||
.PRE(inp),
|
|
||||||
.D(reset_0_out)
|
|
||||||
);
|
|
||||||
endmodule
|
endmodule
|
||||||
"#
|
"#
|
||||||
.intern(),
|
.intern(),
|
||||||
});
|
});
|
||||||
m.verilog_name("__fayalite_arty_a7_reset_sync");
|
m.verilog_name("__fayalite_orangecrab_reset_sync");
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Platform for ArtyA7Platform {
|
impl Platform for OrangeCrabPlatform {
|
||||||
type Peripherals = ArtyA7Peripherals;
|
type Peripherals = ArtyA7Peripherals;
|
||||||
|
|
||||||
fn name(&self) -> Interned<str> {
|
fn name(&self) -> Interned<str> {
|
||||||
|
|
@ -222,29 +209,30 @@ impl Platform for ArtyA7Platform {
|
||||||
} = 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, invert: bool| {
|
||||||
let pin = m.input_with_loc(name, SourceLocation::builtin(), Bool);
|
let pin = m.input_with_loc(name, SourceLocation::builtin(), Bool);
|
||||||
annotate(
|
/* fixme annotate(
|
||||||
pin,
|
pin,
|
||||||
XdcLocationAnnotation {
|
XdcLocationAnnotation {
|
||||||
location: location.intern(),
|
location: location.intern(),
|
||||||
},
|
},
|
||||||
);
|
); */
|
||||||
annotate(
|
/* fixme annotate(
|
||||||
pin,
|
pin,
|
||||||
XdcIOStandardAnnotation {
|
XdcIOStandardAnnotation {
|
||||||
value: io_standard.intern(),
|
value: io_standard.intern(),
|
||||||
},
|
},
|
||||||
);
|
); */
|
||||||
let buf = instance_with_loc(
|
//let buf = instance_with_loc(
|
||||||
&format!("{name}_buf"),
|
// &format!("{name}_buf"),
|
||||||
primitives::IBUF(),
|
// //primitives::IBUF(),
|
||||||
SourceLocation::builtin(),
|
// SourceLocation::builtin(),
|
||||||
);
|
//);
|
||||||
connect(buf.I, pin);
|
//connect(buf.I, pin);
|
||||||
if invert { !buf.O } else { buf.O }
|
//if invert { !buf.O } else { buf.O }
|
||||||
|
if invert { !pin } else { pin }
|
||||||
};
|
};
|
||||||
let make_buffered_output = |name: &str, location: &str, io_standard: &str| {
|
let make_buffered_output = |name: &str, location: &str, io_standard: &str| {
|
||||||
let pin = m.output_with_loc(name, SourceLocation::builtin(), Bool);
|
let pin = m.output_with_loc(name, SourceLocation::builtin(), Bool);
|
||||||
annotate(
|
/* fixme annotate(
|
||||||
pin,
|
pin,
|
||||||
XdcLocationAnnotation {
|
XdcLocationAnnotation {
|
||||||
location: location.intern(),
|
location: location.intern(),
|
||||||
|
|
@ -255,15 +243,16 @@ impl Platform for ArtyA7Platform {
|
||||||
XdcIOStandardAnnotation {
|
XdcIOStandardAnnotation {
|
||||||
value: io_standard.intern(),
|
value: io_standard.intern(),
|
||||||
},
|
},
|
||||||
);
|
); */
|
||||||
let buf = instance_with_loc(
|
//let buf = instance_with_loc(
|
||||||
&format!("{name}_buf"),
|
// &format!("{name}_buf"),
|
||||||
primitives::OBUFT(),
|
// primitives::OBUFT(),
|
||||||
SourceLocation::builtin(),
|
// SourceLocation::builtin(),
|
||||||
);
|
//);
|
||||||
connect(pin, buf.O);
|
//connect(pin, buf.O);
|
||||||
connect(buf.T, false);
|
//connect(buf.T, false);
|
||||||
buf.I
|
//buf.I
|
||||||
|
pin
|
||||||
};
|
};
|
||||||
let mut frequency = clk100_div_pow2[0].ty().frequency();
|
let mut frequency = clk100_div_pow2[0].ty().frequency();
|
||||||
let mut log2_divisor = 0;
|
let mut log2_divisor = 0;
|
||||||
|
|
@ -281,17 +270,17 @@ impl Platform for ArtyA7Platform {
|
||||||
log2_divisor = cur_log2_divisor;
|
log2_divisor = cur_log2_divisor;
|
||||||
}
|
}
|
||||||
let clk100_buf = make_buffered_input("clk100", "E3", "LVCMOS33", false);
|
let clk100_buf = make_buffered_input("clk100", "E3", "LVCMOS33", false);
|
||||||
let startup = instance_with_loc(
|
//let startup = instance_with_loc(
|
||||||
"startup",
|
// "startup",
|
||||||
primitives::STARTUPE2_default_inputs(),
|
// primitives::STARTUPE2_default_inputs(),
|
||||||
SourceLocation::builtin(),
|
// SourceLocation::builtin(),
|
||||||
);
|
//);
|
||||||
let clk_global_buf = instance_with_loc(
|
//let clk_global_buf = instance_with_loc(
|
||||||
"clk_global_buf",
|
// "clk_global_buf",
|
||||||
primitives::BUFGCE(),
|
// primitives::BUFGCE(),
|
||||||
SourceLocation::builtin(),
|
// SourceLocation::builtin(),
|
||||||
);
|
//);
|
||||||
connect(clk_global_buf.CE, startup.EOS);
|
//connect(clk_global_buf.CE, startup.EOS);
|
||||||
let mut clk_global_buf_in = clk100_buf.to_clock();
|
let mut clk_global_buf_in = clk100_buf.to_clock();
|
||||||
for prev_log2_divisor in 0..log2_divisor {
|
for prev_log2_divisor in 0..log2_divisor {
|
||||||
let prev_divisor = 1u64 << prev_log2_divisor;
|
let prev_divisor = 1u64 << prev_log2_divisor;
|
||||||
|
|
@ -301,13 +290,14 @@ impl Platform for ArtyA7Platform {
|
||||||
Clock,
|
Clock,
|
||||||
);
|
);
|
||||||
connect(clk_in, clk_global_buf_in);
|
connect(clk_in, clk_global_buf_in);
|
||||||
|
/* fixme
|
||||||
annotate(
|
annotate(
|
||||||
clk_in,
|
clk_in,
|
||||||
XdcCreateClockAnnotation {
|
XdcCreateClockAnnotation {
|
||||||
period: NotNan::new(1e9 / (100e6 / prev_divisor as f64))
|
period: NotNan::new(1e9 / (100e6 / prev_divisor as f64))
|
||||||
.expect("known to be valid"),
|
.expect("known to be valid"),
|
||||||
},
|
},
|
||||||
);
|
); */
|
||||||
annotate(clk_in, DontTouchAnnotation);
|
annotate(clk_in, DontTouchAnnotation);
|
||||||
let cd = wire_with_loc(
|
let cd = wire_with_loc(
|
||||||
&format!("clk_div_{prev_divisor}_in"),
|
&format!("clk_div_{prev_divisor}_in"),
|
||||||
|
|
@ -315,7 +305,7 @@ impl Platform for ArtyA7Platform {
|
||||||
ClockDomain[AsyncReset],
|
ClockDomain[AsyncReset],
|
||||||
);
|
);
|
||||||
connect(cd.clk, clk_in);
|
connect(cd.clk, clk_in);
|
||||||
connect(cd.rst, (!startup.EOS).to_async_reset());
|
//FIXME connect(cd.rst, (!startup.EOS).to_async_reset());
|
||||||
let divider = reg_builder_with_loc("divider", SourceLocation::builtin())
|
let divider = reg_builder_with_loc("divider", SourceLocation::builtin())
|
||||||
.clock_domain(cd)
|
.clock_domain(cd)
|
||||||
.reset(false)
|
.reset(false)
|
||||||
|
|
@ -323,24 +313,26 @@ impl Platform for ArtyA7Platform {
|
||||||
connect(divider, !divider);
|
connect(divider, !divider);
|
||||||
clk_global_buf_in = divider.to_clock();
|
clk_global_buf_in = divider.to_clock();
|
||||||
}
|
}
|
||||||
connect(clk_global_buf.I, clk_global_buf_in);
|
//connect(clk_global_buf.I, clk_global_buf_in);
|
||||||
let clk_out = wire_with_loc("clk_out", SourceLocation::builtin(), Clock);
|
let clk_out = wire_with_loc("clk_out", SourceLocation::builtin(), Clock);
|
||||||
connect(clk_out, clk_global_buf.O);
|
//connect(clk_out, clk_global_buf.O);
|
||||||
annotate(
|
connect(clk_out, clk_global_buf_in);
|
||||||
|
/* fixme annotate(
|
||||||
clk_out,
|
clk_out,
|
||||||
XdcCreateClockAnnotation {
|
XdcCreateClockAnnotation {
|
||||||
period: NotNan::new(1e9 / frequency).expect("known to be valid"),
|
period: NotNan::new(1e9 / frequency).expect("known to be valid"),
|
||||||
},
|
},
|
||||||
);
|
); */
|
||||||
annotate(clk_out, DontTouchAnnotation);
|
annotate(clk_out, DontTouchAnnotation);
|
||||||
if let Some(clk) = clk {
|
if let Some(clk) = clk {
|
||||||
connect(clk.instance_io_field().clk, clk_out);
|
connect(clk.instance_io_field().clk, clk_out);
|
||||||
}
|
}
|
||||||
|
//undo 1
|
||||||
let rst_value = {
|
let rst_value = {
|
||||||
let rst_buf = make_buffered_input("rst", "C2", "LVCMOS33", true);
|
let rst_buf = make_buffered_input("rst", "C2", "LVCMOS33", true);
|
||||||
let rst_sync = instance_with_loc("rst_sync", reset_sync(), SourceLocation::builtin());
|
let rst_sync = instance_with_loc("rst_sync", reset_sync(), SourceLocation::builtin());
|
||||||
connect(rst_sync.clk, clk_out);
|
connect(rst_sync.clk, clk_out);
|
||||||
connect(rst_sync.inp, rst_buf | !startup.EOS);
|
connect(rst_sync.inp, rst_buf/* | !startup.EOS*/); //FIXME
|
||||||
rst_sync.out
|
rst_sync.out
|
||||||
};
|
};
|
||||||
if let Some(rst) = rst.into_used() {
|
if let Some(rst) = rst.into_used() {
|
||||||
|
|
@ -398,7 +390,7 @@ pub(crate) fn built_in_job_kinds() -> impl IntoIterator<Item = crate::build::Dyn
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn built_in_platforms() -> impl IntoIterator<Item = DynPlatform> {
|
pub(crate) fn built_in_platforms() -> impl IntoIterator<Item = DynPlatform> {
|
||||||
ArtyA7Platform::VARIANTS
|
OrangeCrabPlatform::VARIANTS
|
||||||
.iter()
|
.iter()
|
||||||
.map(|&v| DynPlatform::new(v))
|
.map(|&v| DynPlatform::new(v))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
44
crates/fayalite/src/vendor/lattice/primitives.rs
vendored
44
crates/fayalite/src/vendor/lattice/primitives.rs
vendored
|
|
@ -6,5 +6,45 @@
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
//#[hdl_module(extern)]
|
//#[hdl_module(extern)]
|
||||||
//pub fn PLACEHOLDER() {
|
//pub fn IBUF() {
|
||||||
//do this first
|
// m.verilog_name("IBUF");
|
||||||
|
// #[hdl]
|
||||||
|
// let O: Bool = m.output();
|
||||||
|
// #[hdl]
|
||||||
|
// let I: Bool = m.input();
|
||||||
|
//}
|
||||||
|
|
||||||
|
//#[hdl_module(extern)]
|
||||||
|
//pub fn OBUFT() {
|
||||||
|
// m.verilog_name("OBUFT");
|
||||||
|
// #[hdl]
|
||||||
|
// let O: Bool = m.output();
|
||||||
|
// #[hdl]
|
||||||
|
// let I: Bool = m.input();
|
||||||
|
// #[hdl]
|
||||||
|
// let T: Bool = m.input();
|
||||||
|
//}
|
||||||
|
|
||||||
|
//#[hdl_module(extern)]
|
||||||
|
//pub fn BUFGCE() {
|
||||||
|
// m.verilog_name("BUFGCE");
|
||||||
|
// #[hdl]
|
||||||
|
// let O: Clock = m.output();
|
||||||
|
// #[hdl]
|
||||||
|
// let CE: Bool = m.input();
|
||||||
|
// #[hdl]
|
||||||
|
// let I: Clock = m.input();
|
||||||
|
//}
|
||||||
|
|
||||||
|
#[hdl_module(extern)]
|
||||||
|
pub fn FIXME_PLACEHOLDER() {
|
||||||
|
m.verilog_name("FIXME_PLACEHOLDER");
|
||||||
|
#[hdl]
|
||||||
|
let CFGCLK: Clock = m.output();
|
||||||
|
#[hdl]
|
||||||
|
let CFGMCLK: Clock = m.output();
|
||||||
|
#[hdl]
|
||||||
|
let EOS: Bool = m.output();
|
||||||
|
#[hdl]
|
||||||
|
let PREQ: Bool = m.output();
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,8 +24,8 @@ use crate::{
|
||||||
source_location::SourceLocation,
|
source_location::SourceLocation,
|
||||||
util::{HashSet, job_server::AcquiredJob},
|
util::{HashSet, job_server::AcquiredJob},
|
||||||
vendor::lattice::{
|
vendor::lattice::{
|
||||||
Device, XdcCreateClockAnnotation, XdcIOStandardAnnotation, XdcLocationAnnotation,
|
Device,
|
||||||
LatticeAnnotation, LatticeArgs,
|
/* fixme LatticeAnnotation,*/ LatticeArgs,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use eyre::Context;
|
use eyre::Context;
|
||||||
|
|
@ -39,26 +39,26 @@ use std::{
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash, Default)]
|
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash, Default)]
|
||||||
pub struct YosysNextpnrTrellisWriteYsFileJobKind;
|
pub struct YosysNextpnrWriteYsFileJobKind;
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, Hash, Debug, clap::Args)]
|
#[derive(Clone, PartialEq, Eq, Hash, Debug, clap::Args)]
|
||||||
pub struct YosysNextpnrTrellisWriteYsFileArgs {}
|
pub struct YosysNextpnrWriteYsFileArgs {}
|
||||||
|
|
||||||
impl ToArgs for YosysNextpnrTrellisWriteYsFileArgs {
|
impl ToArgs for YosysNextpnrWriteYsFileArgs {
|
||||||
fn to_args(&self, _args: &mut (impl WriteArgs + ?Sized)) {
|
fn to_args(&self, _args: &mut (impl WriteArgs + ?Sized)) {
|
||||||
let Self {} = self;
|
let Self {} = self;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)]
|
#[derive(Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)]
|
||||||
pub struct YosysNextpnrTrellisWriteYsFile {
|
pub struct YosysNextpnrWriteYsFile {
|
||||||
main_verilog_file: Interned<Path>,
|
main_verilog_file: Interned<Path>,
|
||||||
ys_file: Interned<Path>,
|
ys_file: Interned<Path>,
|
||||||
json_file: Interned<Path>,
|
json_file: Interned<Path>,
|
||||||
json_file_name: Interned<OsStr>,
|
json_file_name: Interned<OsStr>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl YosysNextpnrTrellisWriteYsFile {
|
impl YosysNextpnrWriteYsFile {
|
||||||
pub fn main_verilog_file(&self) -> Interned<Path> {
|
pub fn main_verilog_file(&self) -> Interned<Path> {
|
||||||
self.main_verilog_file
|
self.main_verilog_file
|
||||||
}
|
}
|
||||||
|
|
@ -91,7 +91,7 @@ impl YosysNextpnrTrellisWriteYsFile {
|
||||||
let circuit_name = crate::firrtl::get_circuit_name(main_module_name_id);
|
let circuit_name = crate::firrtl::get_circuit_name(main_module_name_id);
|
||||||
writeln!(
|
writeln!(
|
||||||
output,
|
output,
|
||||||
"synth_lattice -flatten -abc9 -nobram -arch xc7 -top {circuit_name}"
|
"synth_ecp5 -top {circuit_name}"
|
||||||
)
|
)
|
||||||
.expect("writing to OsString can't fail");
|
.expect("writing to OsString can't fail");
|
||||||
output.push("write_json \"");
|
output.push("write_json \"");
|
||||||
|
|
@ -101,9 +101,9 @@ impl YosysNextpnrTrellisWriteYsFile {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl JobKind for YosysNextpnrTrellisWriteYsFileJobKind {
|
impl JobKind for YosysNextpnrWriteYsFileJobKind {
|
||||||
type Args = YosysNextpnrTrellisWriteYsFileArgs;
|
type Args = YosysNextpnrWriteYsFileArgs;
|
||||||
type Job = YosysNextpnrTrellisWriteYsFile;
|
type Job = YosysNextpnrWriteYsFile;
|
||||||
type Dependencies = JobKindAndDependencies<VerilogJobKind>;
|
type Dependencies = JobKindAndDependencies<VerilogJobKind>;
|
||||||
|
|
||||||
fn dependencies(self) -> Self::Dependencies {
|
fn dependencies(self) -> Self::Dependencies {
|
||||||
|
|
@ -123,11 +123,11 @@ impl JobKind for YosysNextpnrTrellisWriteYsFileJobKind {
|
||||||
.verilog_dialect
|
.verilog_dialect
|
||||||
.get_or_insert(VerilogDialect::Yosys);
|
.get_or_insert(VerilogDialect::Yosys);
|
||||||
args.args_to_jobs_simple(params, global_params, |_kind, args, dependencies| {
|
args.args_to_jobs_simple(params, global_params, |_kind, args, dependencies| {
|
||||||
let YosysNextpnrTrellisWriteYsFileArgs {} = args;
|
let YosysNextpnrWriteYsFileArgs {} = args;
|
||||||
let base_job = dependencies.get_job::<BaseJob, _>();
|
let base_job = dependencies.get_job::<BaseJob, _>();
|
||||||
let verilog_job = dependencies.get_job::<VerilogJob, _>();
|
let verilog_job = dependencies.get_job::<VerilogJob, _>();
|
||||||
let json_file = base_job.file_with_ext("json");
|
let json_file = base_job.file_with_ext("json");
|
||||||
Ok(YosysNextpnrTrellisWriteYsFile {
|
Ok(YosysNextpnrWriteYsFile {
|
||||||
main_verilog_file: verilog_job.main_verilog_file(),
|
main_verilog_file: verilog_job.main_verilog_file(),
|
||||||
ys_file: base_job.file_with_ext("ys"),
|
ys_file: base_job.file_with_ext("ys"),
|
||||||
json_file,
|
json_file,
|
||||||
|
|
@ -150,7 +150,7 @@ impl JobKind for YosysNextpnrTrellisWriteYsFileJobKind {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn name(self) -> Interned<str> {
|
fn name(self) -> Interned<str> {
|
||||||
"yosys-nextpnr-trellis-write-ys-file".intern()
|
"yosys-nextpnr-ecp5-write-ys-file".intern()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn external_command_params(self, _job: &Self::Job) -> Option<CommandParams> {
|
fn external_command_params(self, _job: &Self::Job) -> Option<CommandParams> {
|
||||||
|
|
@ -188,26 +188,26 @@ impl JobKind for YosysNextpnrTrellisWriteYsFileJobKind {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, Hash, Debug, clap::Args)]
|
#[derive(Clone, PartialEq, Eq, Hash, Debug, clap::Args)]
|
||||||
pub struct YosysNextpnrTrellisSynthArgs {}
|
pub struct YosysNextpnrSynthArgs {}
|
||||||
|
|
||||||
impl ToArgs for YosysNextpnrTrellisSynthArgs {
|
impl ToArgs for YosysNextpnrSynthArgs {
|
||||||
fn to_args(&self, _args: &mut (impl WriteArgs + ?Sized)) {
|
fn to_args(&self, _args: &mut (impl WriteArgs + ?Sized)) {
|
||||||
let Self {} = self;
|
let Self {} = self;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, Hash, Deserialize, Serialize)]
|
#[derive(Clone, PartialEq, Eq, Hash, Deserialize, Serialize)]
|
||||||
pub struct YosysNextpnrTrellisSynth {
|
pub struct YosysNextpnrSynth {
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
write_ys_file: YosysNextpnrTrellisWriteYsFile,
|
write_ys_file: YosysNextpnrWriteYsFile,
|
||||||
ys_file_name: Interned<OsStr>,
|
ys_file_name: Interned<OsStr>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for YosysNextpnrTrellisSynth {
|
impl fmt::Debug for YosysNextpnrSynth {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
let Self {
|
let Self {
|
||||||
write_ys_file:
|
write_ys_file:
|
||||||
YosysNextpnrTrellisWriteYsFile {
|
YosysNextpnrWriteYsFile {
|
||||||
main_verilog_file,
|
main_verilog_file,
|
||||||
ys_file,
|
ys_file,
|
||||||
json_file,
|
json_file,
|
||||||
|
|
@ -215,7 +215,7 @@ impl fmt::Debug for YosysNextpnrTrellisSynth {
|
||||||
},
|
},
|
||||||
ys_file_name,
|
ys_file_name,
|
||||||
} = self;
|
} = self;
|
||||||
f.debug_struct("YosysNextpnrTrellisSynth")
|
f.debug_struct("YosysNextpnrSynth")
|
||||||
.field("main_verilog_file", main_verilog_file)
|
.field("main_verilog_file", main_verilog_file)
|
||||||
.field("ys_file", ys_file)
|
.field("ys_file", ys_file)
|
||||||
.field("ys_file_name", ys_file_name)
|
.field("ys_file_name", ys_file_name)
|
||||||
|
|
@ -225,7 +225,7 @@ impl fmt::Debug for YosysNextpnrTrellisSynth {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl YosysNextpnrTrellisSynth {
|
impl YosysNextpnrSynth {
|
||||||
pub fn main_verilog_file(&self) -> Interned<Path> {
|
pub fn main_verilog_file(&self) -> Interned<Path> {
|
||||||
self.write_ys_file.main_verilog_file()
|
self.write_ys_file.main_verilog_file()
|
||||||
}
|
}
|
||||||
|
|
@ -248,19 +248,19 @@ pub struct Yosys;
|
||||||
|
|
||||||
impl ExternalProgramTrait for Yosys {
|
impl ExternalProgramTrait for Yosys {
|
||||||
fn default_program_name() -> Interned<str> {
|
fn default_program_name() -> Interned<str> {
|
||||||
"yosys".intern()
|
"yosys".intern() //must be yosys
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ExternalCommand for YosysNextpnrTrellisSynth {
|
impl ExternalCommand for YosysNextpnrSynth {
|
||||||
type AdditionalArgs = YosysNextpnrTrellisSynthArgs;
|
type AdditionalArgs = YosysNextpnrSynthArgs;
|
||||||
type AdditionalJobData = Self;
|
type AdditionalJobData = Self;
|
||||||
type BaseJobPosition = GetJobPositionDependencies<
|
type BaseJobPosition = GetJobPositionDependencies<
|
||||||
GetJobPositionDependencies<
|
GetJobPositionDependencies<
|
||||||
GetJobPositionDependencies<<UnadjustedVerilog as ExternalCommand>::BaseJobPosition>,
|
GetJobPositionDependencies<<UnadjustedVerilog as ExternalCommand>::BaseJobPosition>,
|
||||||
>,
|
>,
|
||||||
>;
|
>;
|
||||||
type Dependencies = JobKindAndDependencies<YosysNextpnrTrellisWriteYsFileJobKind>;
|
type Dependencies = JobKindAndDependencies<YosysNextpnrWriteYsFileJobKind>;
|
||||||
type ExternalProgram = Yosys;
|
type ExternalProgram = Yosys;
|
||||||
|
|
||||||
fn dependencies() -> Self::Dependencies {
|
fn dependencies() -> Self::Dependencies {
|
||||||
|
|
@ -276,7 +276,7 @@ impl ExternalCommand for YosysNextpnrTrellisSynth {
|
||||||
<Self::Dependencies as JobDependencies>::JobsAndKinds,
|
<Self::Dependencies as JobDependencies>::JobsAndKinds,
|
||||||
)> {
|
)> {
|
||||||
args.args_to_jobs_external_simple(params, global_params, |args, dependencies| {
|
args.args_to_jobs_external_simple(params, global_params, |args, dependencies| {
|
||||||
let YosysNextpnrTrellisSynthArgs {} = args.additional_args;
|
let YosysNextpnrSynthArgs {} = args.additional_args;
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
write_ys_file: dependencies.job.job.clone(),
|
write_ys_file: dependencies.job.job.clone(),
|
||||||
ys_file_name: dependencies
|
ys_file_name: dependencies
|
||||||
|
|
@ -318,7 +318,7 @@ impl ExternalCommand for YosysNextpnrTrellisSynth {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn job_kind_name() -> Interned<str> {
|
fn job_kind_name() -> Interned<str> {
|
||||||
"yosys-nextpnr-trellis-synth".intern()
|
"yosys-nextpnr-ecp5-synth".intern()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn subcommand_hidden() -> bool {
|
fn subcommand_hidden() -> bool {
|
||||||
|
|
@ -327,33 +327,33 @@ impl ExternalCommand for YosysNextpnrTrellisSynth {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash, Default)]
|
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash, Default)]
|
||||||
pub struct YosysNextpnrTrellisWriteXdcFileJobKind;
|
pub struct YosysNextpnrWritePcfFileJobKind;
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, Hash, Debug, clap::Args)]
|
#[derive(Clone, PartialEq, Eq, Hash, Debug, clap::Args)]
|
||||||
pub struct YosysNextpnrTrellisWriteXdcFileArgs {}
|
pub struct YosysNextpnrWritePcfFileArgs {}
|
||||||
|
|
||||||
impl ToArgs for YosysNextpnrTrellisWriteXdcFileArgs {
|
impl ToArgs for YosysNextpnrWritePcfFileArgs {
|
||||||
fn to_args(&self, _args: &mut (impl WriteArgs + ?Sized)) {
|
fn to_args(&self, _args: &mut (impl WriteArgs + ?Sized)) {
|
||||||
let Self {} = self;
|
let Self {} = self;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)]
|
#[derive(Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)]
|
||||||
pub struct YosysNextpnrTrellisWriteXdcFile {
|
pub struct YosysNextpnrWritePcfFile {
|
||||||
firrtl_export_options: crate::firrtl::ExportOptions,
|
firrtl_export_options: crate::firrtl::ExportOptions,
|
||||||
output_dir: Interned<Path>,
|
output_dir: Interned<Path>,
|
||||||
xdc_file: Interned<Path>,
|
pcf_file: Interned<Path>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct WriteXdcContentsError(eyre::Report);
|
struct WritePcfContentsError(eyre::Report);
|
||||||
|
|
||||||
impl From<eyre::Report> for WriteXdcContentsError {
|
impl From<eyre::Report> for WritePcfContentsError {
|
||||||
fn from(v: eyre::Report) -> Self {
|
fn from(v: eyre::Report) -> Self {
|
||||||
Self(v)
|
Self(v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<fmt::Error> for WriteXdcContentsError {
|
impl From<fmt::Error> for WritePcfContentsError {
|
||||||
fn from(_v: fmt::Error) -> Self {
|
fn from(_v: fmt::Error) -> Self {
|
||||||
unreachable!("String write can't fail")
|
unreachable!("String write can't fail")
|
||||||
}
|
}
|
||||||
|
|
@ -395,7 +395,7 @@ impl AnnotationTarget {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct XdcFileWriter<W: fmt::Write> {
|
struct PcfFileWriter<W: fmt::Write> { //TODO
|
||||||
output: W,
|
output: W,
|
||||||
module_depth: usize,
|
module_depth: usize,
|
||||||
annotation_target: AnnotationTarget,
|
annotation_target: AnnotationTarget,
|
||||||
|
|
@ -403,8 +403,8 @@ struct XdcFileWriter<W: fmt::Write> {
|
||||||
required_dont_touch_targets: HashSet<Interned<Target>>,
|
required_dont_touch_targets: HashSet<Interned<Target>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<W: fmt::Write> XdcFileWriter<W> {
|
impl<W: fmt::Write> PcfFileWriter<W> {
|
||||||
fn run(output: W, top_module: Module<Bundle>) -> Result<(), WriteXdcContentsError> {
|
fn run(output: W, top_module: Module<Bundle>) -> Result<(), WritePcfContentsError> {
|
||||||
let mut this = Self {
|
let mut this = Self {
|
||||||
output,
|
output,
|
||||||
module_depth: 0,
|
module_depth: 0,
|
||||||
|
|
@ -433,7 +433,7 @@ impl<W: fmt::Write> XdcFileWriter<W> {
|
||||||
module_depth: usize,
|
module_depth: usize,
|
||||||
annotation_target: AnnotationTarget,
|
annotation_target: AnnotationTarget,
|
||||||
v: &T,
|
v: &T,
|
||||||
) -> Result<(), WriteXdcContentsError> {
|
) -> Result<(), WritePcfContentsError> {
|
||||||
let Self {
|
let Self {
|
||||||
output: _,
|
output: _,
|
||||||
module_depth: old_module_depth,
|
module_depth: old_module_depth,
|
||||||
|
|
@ -450,8 +450,8 @@ impl<W: fmt::Write> XdcFileWriter<W> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<W: fmt::Write> Visitor for XdcFileWriter<W> {
|
impl<W: fmt::Write> Visitor for PcfFileWriter<W> {
|
||||||
type Error = WriteXdcContentsError;
|
type Error = WritePcfContentsError;
|
||||||
|
|
||||||
fn visit_targeted_annotation(&mut self, v: &TargetedAnnotation) -> Result<(), Self::Error> {
|
fn visit_targeted_annotation(&mut self, v: &TargetedAnnotation) -> Result<(), Self::Error> {
|
||||||
self.default_visit_with(self.module_depth, AnnotationTarget::Target(v.target()), v)
|
self.default_visit_with(self.module_depth, AnnotationTarget::Target(v.target()), v)
|
||||||
|
|
@ -486,161 +486,21 @@ impl<W: fmt::Write> Visitor for XdcFileWriter<W> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_lattice_annotation(&mut self, v: &LatticeAnnotation) -> Result<(), Self::Error> {
|
|
||||||
fn todo(
|
/* FIXME fn visit_lattice_annotation(&mut self, v: &LatticeAnnotation) -> Result<(), Self::Error> */
|
||||||
msg: &str,
|
|
||||||
annotation: &LatticeAnnotation,
|
|
||||||
source_location: SourceLocation,
|
|
||||||
) -> Result<Infallible, WriteXdcContentsError> {
|
|
||||||
Err(WriteXdcContentsError(eyre::eyre!(
|
|
||||||
"{msg}\nannotation: {annotation:?}\nat: {source_location}"
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
if self.module_depth != 1 {
|
|
||||||
match todo(
|
|
||||||
"annotations are not yet supported outside of the top module since the logic to figure out the correct name isn't implemented",
|
|
||||||
v,
|
|
||||||
self.annotation_target.source_location(),
|
|
||||||
)? {}
|
|
||||||
}
|
|
||||||
match self.annotation_target {
|
|
||||||
AnnotationTarget::None => unreachable!(),
|
|
||||||
AnnotationTarget::Module(module) => match v {
|
|
||||||
LatticeAnnotation::XdcIOStandard(_)
|
|
||||||
| LatticeAnnotation::XdcLocation(_)
|
|
||||||
| LatticeAnnotation::XdcCreateClock(_) => {
|
|
||||||
return Err(WriteXdcContentsError(eyre::eyre!(
|
|
||||||
"annotation not allowed on a module: {v:?}\nat: {}",
|
|
||||||
module.source_location(),
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
AnnotationTarget::Mem(mem) => match todo(
|
|
||||||
"lattice annotations are not yet supported on memories since the logic to figure out the correct name isn't implemented",
|
|
||||||
v,
|
|
||||||
mem.source_location(),
|
|
||||||
)? {},
|
|
||||||
AnnotationTarget::Target(target) => {
|
|
||||||
let base = target.base();
|
|
||||||
match *base {
|
|
||||||
TargetBase::ModuleIO(_) => {
|
|
||||||
// already handled by write_xdc_contents handling the main module's ScalarizedModuleABI
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
TargetBase::MemPort(mem_port) => {
|
|
||||||
match todo(
|
|
||||||
"lattice annotations are not yet supported on memory ports since the logic to figure out the correct name isn't implemented",
|
|
||||||
v,
|
|
||||||
mem_port.source_location(),
|
|
||||||
)? {}
|
|
||||||
}
|
|
||||||
TargetBase::Reg(_)
|
|
||||||
| TargetBase::RegSync(_)
|
|
||||||
| TargetBase::RegAsync(_)
|
|
||||||
| TargetBase::Wire(_) => {
|
|
||||||
match *target {
|
|
||||||
Target::Base(_) => {}
|
|
||||||
Target::Child(_) => match todo(
|
|
||||||
"lattice annotations are not yet supported on parts of registers/wires since the logic to figure out the correct name isn't implemented",
|
|
||||||
v,
|
|
||||||
base.source_location(),
|
|
||||||
)? {},
|
|
||||||
}
|
|
||||||
match base.canonical_ty() {
|
|
||||||
CanonicalType::UInt(_)
|
|
||||||
| CanonicalType::SInt(_)
|
|
||||||
| CanonicalType::Bool(_)
|
|
||||||
| CanonicalType::AsyncReset(_)
|
|
||||||
| CanonicalType::SyncReset(_)
|
|
||||||
| CanonicalType::Reset(_)
|
|
||||||
| CanonicalType::Clock(_) => {}
|
|
||||||
CanonicalType::Enum(_)
|
|
||||||
| CanonicalType::Array(_)
|
|
||||||
| CanonicalType::Bundle(_)
|
|
||||||
| CanonicalType::PhantomConst(_)
|
|
||||||
| CanonicalType::DynSimOnly(_) => match todo(
|
|
||||||
"lattice annotations are not yet supported on types other than integers, Bool, resets, or Clock since the logic to figure out the correct name isn't implemented",
|
|
||||||
v,
|
|
||||||
base.source_location(),
|
|
||||||
)? {},
|
|
||||||
}
|
|
||||||
self.required_dont_touch_targets.insert(target);
|
|
||||||
match v {
|
|
||||||
LatticeAnnotation::XdcIOStandard(_)
|
|
||||||
| LatticeAnnotation::XdcLocation(_) => {
|
|
||||||
return Err(WriteXdcContentsError(eyre::eyre!(
|
|
||||||
"annotation must be on a ModuleIO: {v:?}\nat: {}",
|
|
||||||
base.source_location(),
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
LatticeAnnotation::XdcCreateClock(XdcCreateClockAnnotation {
|
|
||||||
period,
|
|
||||||
}) => {
|
|
||||||
let TargetName(ScopedNameId(_, NameId(name, _)), _) =
|
|
||||||
base.target_name();
|
|
||||||
writeln!(
|
|
||||||
self.output,
|
|
||||||
"create_clock -period {period} [get_nets {}]",
|
|
||||||
tcl_escape(name),
|
|
||||||
)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
TargetBase::Instance(instance) => match todo(
|
|
||||||
"lattice annotations are not yet supported on instances' IO since the logic to figure out the correct name isn't implemented",
|
|
||||||
v,
|
|
||||||
instance.source_location(),
|
|
||||||
)? {},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl YosysNextpnrTrellisWriteXdcFile {
|
impl YosysNextpnrWritePcfFile {
|
||||||
fn write_xdc_contents_for_port_and_annotations(
|
fn write_pcf_contents_for_port_and_annotations(
|
||||||
&self,
|
&self,
|
||||||
output: &mut impl fmt::Write,
|
output: &mut impl fmt::Write,
|
||||||
port: &ScalarizedModuleABIPort,
|
port: &ScalarizedModuleABIPort,
|
||||||
annotations: ScalarizedModuleABIAnnotations<'_>,
|
annotations: ScalarizedModuleABIAnnotations<'_>,
|
||||||
) -> Result<(), WriteXdcContentsError> {
|
) -> Result<(), WritePcfContentsError> {
|
||||||
for annotation in annotations {
|
/* fixme for annotation in annotations .. */
|
||||||
match annotation.annotation() {
|
|
||||||
Annotation::DontTouch(_)
|
|
||||||
| Annotation::SVAttribute(_)
|
|
||||||
| Annotation::BlackBoxInline(_)
|
|
||||||
| Annotation::BlackBoxPath(_)
|
|
||||||
| Annotation::DocString(_)
|
|
||||||
| Annotation::CustomFirrtl(_) => {}
|
|
||||||
Annotation::Lattice(LatticeAnnotation::XdcLocation(XdcLocationAnnotation {
|
|
||||||
location,
|
|
||||||
})) => writeln!(
|
|
||||||
output,
|
|
||||||
"set_property LOC {} [get_ports {}]",
|
|
||||||
tcl_escape(location),
|
|
||||||
tcl_escape(port.scalarized_name()),
|
|
||||||
)?,
|
|
||||||
Annotation::Lattice(LatticeAnnotation::XdcIOStandard(XdcIOStandardAnnotation {
|
|
||||||
value,
|
|
||||||
})) => writeln!(
|
|
||||||
output,
|
|
||||||
"set_property IOSTANDARD {} [get_ports {}]",
|
|
||||||
tcl_escape(value),
|
|
||||||
tcl_escape(port.scalarized_name()),
|
|
||||||
)?,
|
|
||||||
Annotation::Lattice(LatticeAnnotation::XdcCreateClock(
|
|
||||||
XdcCreateClockAnnotation { period },
|
|
||||||
)) => writeln!(
|
|
||||||
output,
|
|
||||||
"create_clock -period {period} [get_ports {}]",
|
|
||||||
tcl_escape(port.scalarized_name()),
|
|
||||||
)?,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
fn write_xdc_contents(
|
fn write_pcf_contents(
|
||||||
&self,
|
&self,
|
||||||
output: &mut String,
|
output: &mut String,
|
||||||
top_module: &Module<Bundle>,
|
top_module: &Module<Bundle>,
|
||||||
|
|
@ -649,7 +509,7 @@ impl YosysNextpnrTrellisWriteXdcFile {
|
||||||
ScalarizedModuleABI::new(top_module, self.firrtl_export_options)
|
ScalarizedModuleABI::new(top_module, self.firrtl_export_options)
|
||||||
.map_err(eyre::Report::from)?;
|
.map_err(eyre::Report::from)?;
|
||||||
match scalarized_module_abi.for_each_port_and_annotations(|port, annotations| {
|
match scalarized_module_abi.for_each_port_and_annotations(|port, annotations| {
|
||||||
match self.write_xdc_contents_for_port_and_annotations(output, port, annotations) {
|
match self.write_pcf_contents_for_port_and_annotations(output, port, annotations) {
|
||||||
Ok(()) => ControlFlow::Continue(()),
|
Ok(()) => ControlFlow::Continue(()),
|
||||||
Err(e) => ControlFlow::Break(e),
|
Err(e) => ControlFlow::Break(e),
|
||||||
}
|
}
|
||||||
|
|
@ -657,14 +517,14 @@ impl YosysNextpnrTrellisWriteXdcFile {
|
||||||
ControlFlow::Continue(()) => {}
|
ControlFlow::Continue(()) => {}
|
||||||
ControlFlow::Break(e) => return Err(e.0),
|
ControlFlow::Break(e) => return Err(e.0),
|
||||||
}
|
}
|
||||||
XdcFileWriter::run(output, *top_module).map_err(|e| e.0)
|
PcfFileWriter::run(output, *top_module).map_err(|e| e.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl JobKind for YosysNextpnrTrellisWriteXdcFileJobKind {
|
impl JobKind for YosysNextpnrWritePcfFileJobKind {
|
||||||
type Args = YosysNextpnrTrellisWriteXdcFileArgs;
|
type Args = YosysNextpnrWritePcfFileArgs;
|
||||||
type Job = YosysNextpnrTrellisWriteXdcFile;
|
type Job = YosysNextpnrWritePcfFile;
|
||||||
type Dependencies = JobKindAndDependencies<ExternalCommandJobKind<YosysNextpnrTrellisSynth>>;
|
type Dependencies = JobKindAndDependencies<ExternalCommandJobKind<YosysNextpnrSynth>>;
|
||||||
|
|
||||||
fn dependencies(self) -> Self::Dependencies {
|
fn dependencies(self) -> Self::Dependencies {
|
||||||
Default::default()
|
Default::default()
|
||||||
|
|
@ -685,12 +545,12 @@ impl JobKind for YosysNextpnrTrellisWriteXdcFileJobKind {
|
||||||
.args
|
.args
|
||||||
.export_options;
|
.export_options;
|
||||||
args.args_to_jobs_simple(params, global_params, |_kind, args, dependencies| {
|
args.args_to_jobs_simple(params, global_params, |_kind, args, dependencies| {
|
||||||
let YosysNextpnrTrellisWriteXdcFileArgs {} = args;
|
let YosysNextpnrWritePcfFileArgs {} = args;
|
||||||
let base_job = dependencies.get_job::<BaseJob, _>();
|
let base_job = dependencies.get_job::<BaseJob, _>();
|
||||||
Ok(YosysNextpnrTrellisWriteXdcFile {
|
Ok(YosysNextpnrWritePcfFile {
|
||||||
firrtl_export_options,
|
firrtl_export_options,
|
||||||
output_dir: base_job.output_dir(),
|
output_dir: base_job.output_dir(),
|
||||||
xdc_file: base_job.file_with_ext("xdc"),
|
pcf_file: base_job.file_with_ext("pcf"),
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -703,11 +563,11 @@ impl JobKind for YosysNextpnrTrellisWriteXdcFileJobKind {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn outputs(self, job: &Self::Job) -> Interned<[JobItemName]> {
|
fn outputs(self, job: &Self::Job) -> Interned<[JobItemName]> {
|
||||||
[JobItemName::Path { path: job.xdc_file }].intern_slice()
|
[JobItemName::Path { path: job.pcf_file }].intern_slice()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn name(self) -> Interned<str> {
|
fn name(self) -> Interned<str> {
|
||||||
"yosys-nextpnr-trellis-write-xdc-file".intern()
|
"yosys-nextpnr-ecp5-write-pcf-file".intern()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn external_command_params(self, _job: &Self::Job) -> Option<CommandParams> {
|
fn external_command_params(self, _job: &Self::Job) -> Option<CommandParams> {
|
||||||
|
|
@ -723,10 +583,10 @@ impl JobKind for YosysNextpnrTrellisWriteXdcFileJobKind {
|
||||||
_acquired_job: &mut AcquiredJob,
|
_acquired_job: &mut AcquiredJob,
|
||||||
) -> eyre::Result<Vec<JobItem>> {
|
) -> eyre::Result<Vec<JobItem>> {
|
||||||
assert!(inputs.iter().map(JobItem::name).eq(self.inputs(job)));
|
assert!(inputs.iter().map(JobItem::name).eq(self.inputs(job)));
|
||||||
let mut xdc = String::new();
|
let mut pcf = String::new();
|
||||||
job.write_xdc_contents(&mut xdc, params.main_module())?;
|
job.write_pcf_contents(&mut pcf, params.main_module())?;
|
||||||
std::fs::write(job.xdc_file, xdc)?;
|
std::fs::write(job.pcf_file, pcf)?;
|
||||||
Ok(vec![JobItem::Path { path: job.xdc_file }])
|
Ok(vec![JobItem::Path { path: job.pcf_file }])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn subcommand_hidden(self) -> bool {
|
fn subcommand_hidden(self) -> bool {
|
||||||
|
|
@ -739,65 +599,49 @@ pub struct NextpnrLattice;
|
||||||
|
|
||||||
impl ExternalProgramTrait for NextpnrLattice {
|
impl ExternalProgramTrait for NextpnrLattice {
|
||||||
fn default_program_name() -> Interned<str> {
|
fn default_program_name() -> Interned<str> {
|
||||||
"nextpnr-lattice".intern()
|
"nextpnr".intern()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, Hash, Debug, clap::Args)]
|
#[derive(Clone, PartialEq, Eq, Hash, Debug, clap::Args)]
|
||||||
pub struct YosysNextpnrTrellisRunNextpnrArgs {
|
pub struct YosysNextpnrRunNextpnrArgs {
|
||||||
#[command(flatten)]
|
#[command(flatten)]
|
||||||
pub common: LatticeArgs,
|
pub common: LatticeArgs,
|
||||||
#[arg(long, env = "CHIPDB_DIR", value_hint = clap::ValueHint::DirPath)]
|
|
||||||
pub nextpnr_lattice_chipdb_dir: PathBuf,
|
|
||||||
#[arg(long, default_value_t = 0)]
|
#[arg(long, default_value_t = 0)]
|
||||||
pub nextpnr_lattice_seed: i32,
|
pub nextpnr_lattice_seed: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToArgs for YosysNextpnrTrellisRunNextpnrArgs {
|
impl ToArgs for YosysNextpnrRunNextpnrArgs {
|
||||||
fn to_args(&self, args: &mut (impl WriteArgs + ?Sized)) {
|
fn to_args(&self, args: &mut (impl WriteArgs + ?Sized)) {
|
||||||
let Self {
|
let Self {
|
||||||
common,
|
common,
|
||||||
nextpnr_lattice_chipdb_dir,
|
|
||||||
nextpnr_lattice_seed,
|
nextpnr_lattice_seed,
|
||||||
} = self;
|
} = self;
|
||||||
common.to_args(args);
|
common.to_args(args);
|
||||||
args.write_long_option_eq("nextpnr-lattice-chipdb-dir", nextpnr_lattice_chipdb_dir);
|
|
||||||
args.write_display_arg(format_args!("--nextpnr-lattice-seed={nextpnr_lattice_seed}"));
|
args.write_display_arg(format_args!("--nextpnr-lattice-seed={nextpnr_lattice_seed}"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)]
|
#[derive(Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)]
|
||||||
pub struct YosysNextpnrTrellisRunNextpnr {
|
pub struct YosysNextpnrRunNextpnr {
|
||||||
nextpnr_lattice_chipdb_dir: Interned<Path>,
|
|
||||||
device: Device,
|
device: Device,
|
||||||
nextpnr_lattice_seed: i32,
|
nextpnr_lattice_seed: i32,
|
||||||
xdc_file: Interned<Path>,
|
pcf_file: Interned<Path>,
|
||||||
xdc_file_name: Interned<OsStr>,
|
|
||||||
json_file: Interned<Path>,
|
json_file: Interned<Path>,
|
||||||
json_file_name: Interned<OsStr>,
|
json_file_name: Interned<OsStr>,
|
||||||
routed_json_file: Interned<Path>,
|
routed_json_file: Interned<Path>,
|
||||||
routed_json_file_name: Interned<OsStr>,
|
routed_json_file_name: Interned<OsStr>,
|
||||||
fasm_file: Interned<Path>,
|
textcfg_file: Interned<Path>,
|
||||||
fasm_file_name: Interned<OsStr>,
|
textcfg_file_name: Interned<OsStr>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl YosysNextpnrTrellisRunNextpnr {
|
impl ExternalCommand for YosysNextpnrRunNextpnr {
|
||||||
fn chipdb_file(&self) -> Interned<Path> {
|
type AdditionalArgs = YosysNextpnrRunNextpnrArgs;
|
||||||
let mut retval = self
|
|
||||||
.nextpnr_lattice_chipdb_dir
|
|
||||||
.join(self.device.trellis_device());
|
|
||||||
retval.set_extension("bin");
|
|
||||||
retval.intern_deref()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ExternalCommand for YosysNextpnrTrellisRunNextpnr {
|
|
||||||
type AdditionalArgs = YosysNextpnrTrellisRunNextpnrArgs;
|
|
||||||
type AdditionalJobData = Self;
|
type AdditionalJobData = Self;
|
||||||
type BaseJobPosition = GetJobPositionDependencies<
|
type BaseJobPosition = GetJobPositionDependencies<
|
||||||
GetJobPositionDependencies<<YosysNextpnrTrellisSynth as ExternalCommand>::BaseJobPosition>,
|
GetJobPositionDependencies<<YosysNextpnrSynth as ExternalCommand>::BaseJobPosition>,
|
||||||
>;
|
>;
|
||||||
type Dependencies = JobKindAndDependencies<YosysNextpnrTrellisWriteXdcFileJobKind>;
|
type Dependencies = JobKindAndDependencies<YosysNextpnrWritePcfFileJobKind>;
|
||||||
type ExternalProgram = NextpnrLattice;
|
type ExternalProgram = NextpnrLattice;
|
||||||
|
|
||||||
fn dependencies() -> Self::Dependencies {
|
fn dependencies() -> Self::Dependencies {
|
||||||
|
|
@ -813,35 +657,29 @@ impl ExternalCommand for YosysNextpnrTrellisRunNextpnr {
|
||||||
<Self::Dependencies as JobDependencies>::JobsAndKinds,
|
<Self::Dependencies as JobDependencies>::JobsAndKinds,
|
||||||
)> {
|
)> {
|
||||||
args.args_to_jobs_external_simple(params, global_params, |args, dependencies| {
|
args.args_to_jobs_external_simple(params, global_params, |args, dependencies| {
|
||||||
let YosysNextpnrTrellisRunNextpnrArgs {
|
let YosysNextpnrRunNextpnrArgs {
|
||||||
common,
|
common,
|
||||||
nextpnr_lattice_chipdb_dir,
|
|
||||||
nextpnr_lattice_seed,
|
nextpnr_lattice_seed,
|
||||||
} = args.additional_args;
|
} = args.additional_args;
|
||||||
let base_job = dependencies.get_job::<BaseJob, _>();
|
let base_job = dependencies.get_job::<BaseJob, _>();
|
||||||
let write_xdc_file = dependencies.get_job::<YosysNextpnrTrellisWriteXdcFile, _>();
|
let write_pcf_file = dependencies.get_job::<YosysNextpnrWritePcfFile, _>();
|
||||||
let synth = dependencies.get_job::<ExternalCommandJob<YosysNextpnrTrellisSynth>, _>();
|
let synth = dependencies.get_job::<ExternalCommandJob<YosysNextpnrSynth>, _>();
|
||||||
let routed_json_file = base_job.file_with_ext("routed.json");
|
let routed_json_file = base_job.file_with_ext("routed.json");
|
||||||
let fasm_file = base_job.file_with_ext("fasm");
|
let textcfg_file = base_job.file_with_ext("config"); //file must exist
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
nextpnr_lattice_chipdb_dir: nextpnr_lattice_chipdb_dir.intern_deref(),
|
|
||||||
device: common.require_device(base_job.platform(), global_params)?,
|
device: common.require_device(base_job.platform(), global_params)?,
|
||||||
nextpnr_lattice_seed,
|
nextpnr_lattice_seed,
|
||||||
xdc_file: write_xdc_file.xdc_file,
|
pcf_file: write_pcf_file.pcf_file,
|
||||||
xdc_file_name: write_xdc_file
|
|
||||||
.xdc_file
|
|
||||||
.interned_file_name()
|
|
||||||
.expect("known to have file name"),
|
|
||||||
json_file: synth.additional_job_data().json_file(),
|
json_file: synth.additional_job_data().json_file(),
|
||||||
json_file_name: synth.additional_job_data().json_file_name(),
|
json_file_name: synth.additional_job_data().json_file_name(),
|
||||||
routed_json_file,
|
routed_json_file: routed_json_file,
|
||||||
routed_json_file_name: routed_json_file
|
routed_json_file_name: routed_json_file
|
||||||
.interned_file_name()
|
.interned_file_name()
|
||||||
.expect("known to have file name"),
|
.expect("known to have file name"),
|
||||||
fasm_file,
|
textcfg_file:textcfg_file,
|
||||||
fasm_file_name: fasm_file
|
textcfg_file_name: textcfg_file
|
||||||
.interned_file_name()
|
.interned_file_name()
|
||||||
.expect("known to have file name"),
|
.expect("known to have file name"),
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -852,7 +690,7 @@ impl ExternalCommand for YosysNextpnrTrellisRunNextpnr {
|
||||||
path: job.additional_job_data().json_file,
|
path: job.additional_job_data().json_file,
|
||||||
},
|
},
|
||||||
JobItemName::Path {
|
JobItemName::Path {
|
||||||
path: job.additional_job_data().xdc_file,
|
path: job.additional_job_data().pcf_file,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
.intern_slice()
|
.intern_slice()
|
||||||
|
|
@ -861,26 +699,26 @@ impl ExternalCommand for YosysNextpnrTrellisRunNextpnr {
|
||||||
fn output_paths(job: &ExternalCommandJob<Self>) -> Interned<[Interned<Path>]> {
|
fn output_paths(job: &ExternalCommandJob<Self>) -> Interned<[Interned<Path>]> {
|
||||||
[
|
[
|
||||||
job.additional_job_data().routed_json_file,
|
job.additional_job_data().routed_json_file,
|
||||||
job.additional_job_data().fasm_file,
|
|
||||||
]
|
]
|
||||||
.intern_slice()
|
.intern_slice()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn command_line_args<W: ?Sized + WriteArgs>(job: &ExternalCommandJob<Self>, args: &mut W) {
|
fn command_line_args<W: ?Sized + WriteArgs>(job: &ExternalCommandJob<Self>, args: &mut W) {
|
||||||
let job_data @ YosysNextpnrTrellisRunNextpnr {
|
let job_data @ YosysNextpnrRunNextpnr {
|
||||||
nextpnr_lattice_seed,
|
nextpnr_lattice_seed,
|
||||||
xdc_file_name,
|
|
||||||
json_file_name,
|
json_file_name,
|
||||||
routed_json_file_name,
|
routed_json_file_name,
|
||||||
fasm_file_name,
|
textcfg_file_name,
|
||||||
..
|
..
|
||||||
} = job.additional_job_data();
|
} = job.additional_job_data();
|
||||||
args.write_long_option_eq("chipdb", job_data.chipdb_file());
|
|
||||||
args.write_long_option_eq("xdc", xdc_file_name);
|
|
||||||
args.write_long_option_eq("json", json_file_name);
|
args.write_long_option_eq("json", json_file_name);
|
||||||
args.write_long_option_eq("write", routed_json_file_name);
|
args.write_long_option_eq("textcfg",textcfg_file_name);
|
||||||
args.write_long_option_eq("fasm", fasm_file_name);
|
args.write_arg("--25k");
|
||||||
args.write_display_arg(format_args!("--seed={nextpnr_lattice_seed}"));
|
args.write_long_option_eq("package","CSFBGA285");
|
||||||
|
args.write_long_option_eq("lpf","/tmp/orangecrab_r0.2.1.pcf");
|
||||||
|
args.write_arg("--lpf-allow-unconstrained");
|
||||||
|
//???args.write_display_arg(format_args!("--seed={nextpnr_lattice_seed}"));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn current_dir(job: &ExternalCommandJob<Self>) -> Option<Interned<Path>> {
|
fn current_dir(job: &ExternalCommandJob<Self>) -> Option<Interned<Path>> {
|
||||||
|
|
@ -888,7 +726,7 @@ impl ExternalCommand for YosysNextpnrTrellisRunNextpnr {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn job_kind_name() -> Interned<str> {
|
fn job_kind_name() -> Interned<str> {
|
||||||
"yosys-nextpnr-trellis-run-nextpnr".intern()
|
"yosys-nextpnr-ecp5-run-nextpnr".intern()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn subcommand_hidden() -> bool {
|
fn subcommand_hidden() -> bool {
|
||||||
|
|
@ -896,62 +734,75 @@ impl ExternalCommand for YosysNextpnrTrellisRunNextpnr {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Default)]
|
|
||||||
pub struct Xcfasm;
|
|
||||||
|
|
||||||
impl ExternalProgramTrait for Xcfasm {
|
|
||||||
fn default_program_name() -> Interned<str> {
|
|
||||||
"xcfasm".intern()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, Hash, Debug, clap::Args)]
|
#[derive(Clone, PartialEq, Eq, Hash, Debug, clap::Args)]
|
||||||
pub struct YosysNextpnrTrellisArgs {
|
pub struct YosysNextpnrArgs {
|
||||||
#[arg(long, env = "DB_DIR", value_hint = clap::ValueHint::DirPath)]
|
#[arg(long, env = "DB_DIR", value_hint = clap::ValueHint::DirPath)]
|
||||||
pub prjtrellis_db_dir: PathBuf,
|
pub pcf1: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToArgs for YosysNextpnrTrellisArgs {
|
impl ToArgs for YosysNextpnrArgs {
|
||||||
fn to_args(&self, args: &mut (impl WriteArgs + ?Sized)) {
|
fn to_args(&self, args: &mut (impl WriteArgs + ?Sized)) {
|
||||||
let Self { prjtrellis_db_dir } = self;
|
let Self { pcf1 } = self;
|
||||||
args.write_long_option_eq("prjtrellis-db-dir", prjtrellis_db_dir);
|
args.write_long_option_eq("pcf1", pcf1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)]
|
#[derive(Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)]
|
||||||
pub struct YosysNextpnrTrellis {
|
pub struct YosysNextpnr {
|
||||||
prjtrellis_db_dir: Interned<Path>,
|
pcf1: Interned<Path>,
|
||||||
device: Device,
|
device: Device,
|
||||||
fasm_file: Interned<Path>,
|
|
||||||
fasm_file_name: Interned<OsStr>,
|
|
||||||
frames_file: Interned<Path>,
|
frames_file: Interned<Path>,
|
||||||
frames_file_name: Interned<OsStr>,
|
frames_file_name: Interned<OsStr>,
|
||||||
bit_file: Interned<Path>,
|
bit_file: Interned<Path>,
|
||||||
bit_file_name: Interned<OsStr>,
|
bit_file_name: Interned<OsStr>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl YosysNextpnrTrellis {
|
|
||||||
fn db_root(&self) -> Interned<Path> {
|
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Default)]
|
||||||
self.prjtrellis_db_dir
|
pub struct Ecppack;
|
||||||
.join(self.device.trellis_family())
|
|
||||||
.intern_deref()
|
impl ExternalProgramTrait for Ecppack {
|
||||||
}
|
fn default_program_name() -> Interned<str> {
|
||||||
fn part_file(&self) -> Interned<Path> {
|
"ecppack".intern()
|
||||||
let mut retval = self.prjtrellis_db_dir.join(self.device.trellis_family());
|
|
||||||
retval.push(self.device.trellis_part());
|
|
||||||
retval.push("part.yaml");
|
|
||||||
retval.intern_deref()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ExternalCommand for YosysNextpnrTrellis {
|
//begin
|
||||||
type AdditionalArgs = YosysNextpnrTrellisArgs;
|
#[derive(Clone, PartialEq, Eq, Hash, Debug, clap::Args)]
|
||||||
|
pub struct YosysNextpnrRunEcpPackArgs {
|
||||||
|
#[arg(long, env = "DB_DIR", value_hint = clap::ValueHint::DirPath)]
|
||||||
|
pub placeholder_dir: PathBuf,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToArgs for YosysNextpnrRunEcpPackArgs {
|
||||||
|
fn to_args(&self, args: &mut (impl WriteArgs + ?Sized)) {
|
||||||
|
let Self { placeholder_dir } = self;
|
||||||
|
args.write_long_option_eq("placeholder-dir", placeholder_dir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)]
|
||||||
|
pub struct YosysNextpnrRunEcpPack {
|
||||||
|
placeholder_dir: Interned<Path>,
|
||||||
|
device: Device,
|
||||||
|
routed_json_file: Interned<Path>,
|
||||||
|
routed_json_file_name: Interned<OsStr>,
|
||||||
|
textcfg_file: Interned<Path>,
|
||||||
|
textcfg_file_name: Interned<OsStr>,
|
||||||
|
frames_file: Interned<Path>,
|
||||||
|
frames_file_name: Interned<OsStr>,
|
||||||
|
bit_file: Interned<Path>,
|
||||||
|
bit_file_name: Interned<OsStr>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ExternalCommand for YosysNextpnrRunEcpPack {
|
||||||
|
type AdditionalArgs = YosysNextpnrRunEcpPackArgs;
|
||||||
type AdditionalJobData = Self;
|
type AdditionalJobData = Self;
|
||||||
type BaseJobPosition = GetJobPositionDependencies<
|
type BaseJobPosition = GetJobPositionDependencies<
|
||||||
<YosysNextpnrTrellisRunNextpnr as ExternalCommand>::BaseJobPosition,
|
<YosysNextpnrRunNextpnr as ExternalCommand>::BaseJobPosition,
|
||||||
>;
|
>;
|
||||||
type Dependencies = JobKindAndDependencies<ExternalCommandJobKind<YosysNextpnrTrellisRunNextpnr>>;
|
type Dependencies = JobKindAndDependencies<ExternalCommandJobKind<YosysNextpnrRunNextpnr>>;
|
||||||
type ExternalProgram = Xcfasm;
|
type ExternalProgram = Ecppack;
|
||||||
|
|
||||||
fn dependencies() -> Self::Dependencies {
|
fn dependencies() -> Self::Dependencies {
|
||||||
Default::default()
|
Default::default()
|
||||||
|
|
@ -966,15 +817,18 @@ impl ExternalCommand for YosysNextpnrTrellis {
|
||||||
<Self::Dependencies as JobDependencies>::JobsAndKinds,
|
<Self::Dependencies as JobDependencies>::JobsAndKinds,
|
||||||
)> {
|
)> {
|
||||||
args.args_to_jobs_external_simple(params, global_params, |args, dependencies| {
|
args.args_to_jobs_external_simple(params, global_params, |args, dependencies| {
|
||||||
let YosysNextpnrTrellisArgs { prjtrellis_db_dir } = args.additional_args;
|
let YosysNextpnrRunEcpPackArgs { placeholder_dir } = args.additional_args;
|
||||||
let base_job = dependencies.get_job::<BaseJob, _>();
|
let base_job = dependencies.get_job::<BaseJob, _>();
|
||||||
let frames_file = base_job.file_with_ext("frames");
|
let frames_file = base_job.file_with_ext("frames");
|
||||||
let bit_file = base_job.file_with_ext("bit");
|
let bit_file = base_job.file_with_ext("bit");
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
prjtrellis_db_dir: prjtrellis_db_dir.intern_deref(),
|
placeholder_dir: placeholder_dir.intern_deref(),
|
||||||
device: dependencies.job.job.additional_job_data().device,
|
device: dependencies.job.job.additional_job_data().device,
|
||||||
fasm_file: dependencies.job.job.additional_job_data().fasm_file,
|
//fixme glue code
|
||||||
fasm_file_name: dependencies.job.job.additional_job_data().fasm_file_name,
|
routed_json_file: dependencies.job.job.additional_job_data().routed_json_file,
|
||||||
|
routed_json_file_name: dependencies.job.job.additional_job_data().routed_json_file_name,
|
||||||
|
textcfg_file: dependencies.job.job.additional_job_data().textcfg_file,
|
||||||
|
textcfg_file_name: dependencies.job.job.additional_job_data().textcfg_file_name,
|
||||||
frames_file,
|
frames_file,
|
||||||
frames_file_name: frames_file
|
frames_file_name: frames_file
|
||||||
.interned_file_name()
|
.interned_file_name()
|
||||||
|
|
@ -989,34 +843,32 @@ impl ExternalCommand for YosysNextpnrTrellis {
|
||||||
|
|
||||||
fn inputs(job: &ExternalCommandJob<Self>) -> Interned<[JobItemName]> {
|
fn inputs(job: &ExternalCommandJob<Self>) -> Interned<[JobItemName]> {
|
||||||
[JobItemName::Path {
|
[JobItemName::Path {
|
||||||
path: job.additional_job_data().fasm_file,
|
path: job.additional_job_data().routed_json_file,
|
||||||
}]
|
}]
|
||||||
.intern_slice()
|
.intern_slice()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn output_paths(job: &ExternalCommandJob<Self>) -> Interned<[Interned<Path>]> {
|
fn output_paths(job: &ExternalCommandJob<Self>) -> Interned<[Interned<Path>]> {
|
||||||
[
|
[
|
||||||
job.additional_job_data().frames_file,
|
|
||||||
job.additional_job_data().bit_file,
|
job.additional_job_data().bit_file,
|
||||||
]
|
]
|
||||||
.intern_slice()
|
.intern_slice()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn command_line_args<W: ?Sized + WriteArgs>(job: &ExternalCommandJob<Self>, args: &mut W) {
|
fn command_line_args<W: ?Sized + WriteArgs>(job: &ExternalCommandJob<Self>, args: &mut W) {
|
||||||
let job_data @ YosysNextpnrTrellis {
|
let job_data @ YosysNextpnrRunEcpPack {
|
||||||
|
placeholder_dir,
|
||||||
device,
|
device,
|
||||||
fasm_file_name,
|
routed_json_file_name,
|
||||||
|
textcfg_file_name,
|
||||||
frames_file_name,
|
frames_file_name,
|
||||||
bit_file_name,
|
bit_file_name,
|
||||||
..
|
..
|
||||||
} = job.additional_job_data();
|
} = job.additional_job_data();
|
||||||
args.write_arg("--sparse");
|
args.write_arg("--compress");
|
||||||
args.write_long_option_eq("db-root", job_data.db_root());
|
args.write_long_option_eq("freq", "38.8"); //FIXME do not hardcode
|
||||||
args.write_long_option_eq("part", device.trellis_part());
|
args.write_long_option_eq("input",textcfg_file_name);
|
||||||
args.write_long_option_eq("part_file", job_data.part_file());
|
args.write_long_option_eq("bit",bit_file_name);
|
||||||
args.write_long_option_eq("fn_in", fasm_file_name);
|
|
||||||
args.write_long_option_eq("frm_out", frames_file_name);
|
|
||||||
args.write_long_option_eq("bit_out", bit_file_name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn current_dir(job: &ExternalCommandJob<Self>) -> Option<Interned<Path>> {
|
fn current_dir(job: &ExternalCommandJob<Self>) -> Option<Interned<Path>> {
|
||||||
|
|
@ -1024,17 +876,18 @@ impl ExternalCommand for YosysNextpnrTrellis {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn job_kind_name() -> Interned<str> {
|
fn job_kind_name() -> Interned<str> {
|
||||||
"yosys-nextpnr-trellis".intern()
|
"yosys-nextpnr-ecp5".intern()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//end
|
||||||
|
|
||||||
pub(crate) fn built_in_job_kinds() -> impl IntoIterator<Item = DynJobKind> {
|
pub(crate) fn built_in_job_kinds() -> impl IntoIterator<Item = DynJobKind> {
|
||||||
[
|
[
|
||||||
DynJobKind::new(YosysNextpnrTrellisWriteYsFileJobKind),
|
DynJobKind::new(YosysNextpnrWriteYsFileJobKind), //working
|
||||||
DynJobKind::new(ExternalCommandJobKind::<YosysNextpnrTrellisSynth>::new()),
|
DynJobKind::new(ExternalCommandJobKind::<YosysNextpnrSynth>::new()), //working
|
||||||
DynJobKind::new(YosysNextpnrTrellisWriteXdcFileJobKind),
|
DynJobKind::new(YosysNextpnrWritePcfFileJobKind), //TODO
|
||||||
DynJobKind::new(ExternalCommandJobKind::<YosysNextpnrTrellisRunNextpnr>::new()),
|
DynJobKind::new(ExternalCommandJobKind::<YosysNextpnrRunNextpnr>::new()), //working
|
||||||
DynJobKind::new(ExternalCommandJobKind::<YosysNextpnrTrellis>::new()),
|
DynJobKind::new(ExternalCommandJobKind::<YosysNextpnrRunEcpPack>::new()), //working
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
5
nextpnr.txt
Normal file
5
nextpnr.txt
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
nextpnr-ecp5 for orangecrab
|
||||||
|
nextpnr-ice40 for other one*
|
||||||
|
|
||||||
|
modified: Makefile
|
||||||
|
modified: crates/fayalite/src/vendor/lattice/yosys_nextpnr.rs
|
||||||
BIN
tools/firrtl.tar.gz
Normal file
BIN
tools/firrtl.tar.gz
Normal file
Binary file not shown.
Loading…
Add table
Add a link
Reference in a new issue