diff --git a/crates/fayalite/examples/blinky.rs b/crates/fayalite/examples/blinky.rs index 7384e0d..8682a33 100644 --- a/crates/fayalite/examples/blinky.rs +++ b/crates/fayalite/examples/blinky.rs @@ -1,64 +1,55 @@ // SPDX-License-Identifier: LGPL-3.0-or-later // See Notices.txt for copyright information -use fayalite::prelude::*; +use fayalite::{ + build::{ToArgs, WriteArgs}, + prelude::*, +}; #[hdl_module] -fn blinky(platform_io_builder: PlatformIOBuilder<'_>) { - let clk_input = - platform_io_builder.peripherals_with_type::()[0].use_peripheral(); - let rst = platform_io_builder.peripherals_with_type::()[0].use_peripheral(); +fn blinky(clock_frequency: u64) { + #[hdl] + let clk: Clock = m.input(); + #[hdl] + let rst: SyncReset = m.input(); let cd = #[hdl] ClockDomain { - clk: clk_input.clk, - rst, + clk, + rst: rst.to_reset(), }; - let max_value = (Expr::ty(clk_input).frequency() / 2.0).round_ties_even() as u64 - 1; + let max_value = clock_frequency / 2 - 1; let int_ty = UInt::range_inclusive(0..=max_value); #[hdl] let counter_reg: UInt = reg_builder().clock_domain(cd).reset(0u8.cast_to(int_ty)); #[hdl] let output_reg: Bool = reg_builder().clock_domain(cd).reset(false); #[hdl] - let rgb_output_reg = reg_builder().clock_domain(cd).reset( - #[hdl] - peripherals::RgbLed { - r: false, - g: false, - b: false, - }, - ); - #[hdl] if counter_reg.cmp_eq(max_value) { connect_any(counter_reg, 0u8); connect(output_reg, !output_reg); - connect(rgb_output_reg.r, !rgb_output_reg.r); - #[hdl] - if rgb_output_reg.r { - connect(rgb_output_reg.g, !rgb_output_reg.g); - #[hdl] - if rgb_output_reg.g { - connect(rgb_output_reg.b, !rgb_output_reg.b); - } - } } else { connect_any(counter_reg, counter_reg + 1_hdl_u1); } - for led in platform_io_builder.peripherals_with_type::() { - if let Ok(led) = led.try_use_peripheral() { - connect(led.on, output_reg); - } - } - for rgb_led in platform_io_builder.peripherals_with_type::() { - if let Ok(rgb_led) = rgb_led.try_use_peripheral() { - connect(rgb_led, rgb_output_reg); - } - } #[hdl] - let io = m.add_platform_io(platform_io_builder); + let led: Bool = m.output(); + connect(led, output_reg); +} + +#[derive(clap::Args, Clone, PartialEq, Eq, Hash, Debug)] +struct ExtraArgs { + /// clock frequency in hertz + #[arg(long, default_value = "1000000", value_parser = clap::value_parser!(u64).range(2..))] + clock_frequency: u64, +} + +impl ToArgs for ExtraArgs { + fn to_args(&self, args: &mut (impl WriteArgs + ?Sized)) { + let Self { clock_frequency } = self; + args.write_arg(format!("--clock-frequency={clock_frequency}")); + } } fn main() { - BuildCli::main("blinky", |_, platform, _| { - Ok(JobParams::new(platform.wrap_main_module(blinky))) + BuildCli::main(|_cli, ExtraArgs { clock_frequency }| { + Ok(JobParams::new(blinky(clock_frequency), "blinky")) }); } diff --git a/crates/fayalite/src/platform.rs b/crates/fayalite/src/platform.rs index 1018055..be675b8 100644 --- a/crates/fayalite/src/platform.rs +++ b/crates/fayalite/src/platform.rs @@ -530,7 +530,6 @@ impl<'a, S: PeripheralsOnUseSharedState> PeripheralsBuilder<'a, S> { } } -#[must_use] pub struct Peripheral { ty: T, common: PeripheralCommon, @@ -541,27 +540,6 @@ impl Peripheral { let Self { ty, ref common } = *self; PeripheralRef { ty, common } } - pub fn ty(&self) -> T { - self.as_ref().ty() - } - pub fn id(&self) -> PeripheralId { - self.as_ref().id() - } - pub fn name(&self) -> Interned { - self.as_ref().name() - } - pub fn is_input(&self) -> bool { - self.as_ref().is_input() - } - pub fn is_output(&self) -> bool { - self.as_ref().is_output() - } - pub fn conflicts_with(&self) -> Interned> { - self.as_ref().conflicts_with() - } - pub fn availability(&self) -> PeripheralAvailability { - self.as_ref().availability() - } pub fn is_available(&self) -> bool { self.as_ref().is_available() } @@ -651,24 +629,6 @@ impl UsedPeripheral { pub fn instance_io_field(&self) -> Expr { self.instance_io_field } - pub fn ty(&self) -> T { - self.as_ref().ty() - } - pub fn id(&self) -> PeripheralId { - self.as_ref().id() - } - pub fn name(&self) -> Interned { - self.as_ref().name() - } - pub fn is_input(&self) -> bool { - self.as_ref().is_input() - } - pub fn is_output(&self) -> bool { - self.as_ref().is_output() - } - pub fn conflicts_with(&self) -> Interned> { - self.as_ref().conflicts_with() - } } #[derive(Copy, Clone)] diff --git a/crates/fayalite/src/platform/peripherals.rs b/crates/fayalite/src/platform/peripherals.rs index 3ff4d6c..68db8d2 100644 --- a/crates/fayalite/src/platform/peripherals.rs +++ b/crates/fayalite/src/platform/peripherals.rs @@ -1,7 +1,7 @@ // SPDX-License-Identifier: LGPL-3.0-or-later // See Notices.txt for copyright information -use crate::{intern::Intern, prelude::*}; +use crate::prelude::*; use ordered_float::NotNan; use serde::{Deserialize, Serialize}; @@ -11,42 +11,10 @@ pub struct ClockInputProperties { pub frequency: NotNan, } -#[hdl(no_runtime_generics, no_static)] +type PhantomConstClockInputProperties = PhantomConst; + +#[hdl(no_static)] pub struct ClockInput { pub clk: Clock, - pub properties: PhantomConst, -} - -impl ClockInput { - #[track_caller] - pub fn new(frequency: f64) -> Self { - assert!( - frequency > 0.0 && frequency.is_finite(), - "invalid clock frequency: {frequency}" - ); - Self { - clk: Clock, - properties: PhantomConst::new( - ClockInputProperties { - frequency: NotNan::new(frequency).expect("just checked"), - } - .intern_sized(), - ), - } - } - pub fn frequency(self) -> f64 { - self.properties.get().frequency.into_inner() - } -} - -#[hdl] -pub struct Led { - pub on: Bool, -} - -#[hdl] -pub struct RgbLed { - pub r: Bool, - pub g: Bool, - pub b: Bool, + pub properties: PhantomConstClockInputProperties, } diff --git a/crates/fayalite/src/prelude.rs b/crates/fayalite/src/prelude.rs index 216f94e..5ff3a64 100644 --- a/crates/fayalite/src/prelude.rs +++ b/crates/fayalite/src/prelude.rs @@ -28,7 +28,6 @@ pub use crate::{ memory, memory_array, memory_with_init, reg_builder, wire, }, phantom_const::PhantomConst, - platform::{DynPlatform, Platform, PlatformIOBuilder, peripherals}, reg::Reg, reset::{AsyncReset, Reset, SyncReset, ToAsyncReset, ToReset, ToSyncReset}, sim::{ diff --git a/crates/fayalite/src/testing.rs b/crates/fayalite/src/testing.rs index c7feb5e..30a8243 100644 --- a/crates/fayalite/src/testing.rs +++ b/crates/fayalite/src/testing.rs @@ -2,8 +2,8 @@ // See Notices.txt for copyright information use crate::{ build::{ - BaseJobArgs, BaseJobKind, GlobalParams, JobArgsAndDependencies, JobKindAndArgs, JobParams, - NoArgs, RunBuild, + BaseJobArgs, BaseJobKind, JobArgsAndDependencies, JobKindAndArgs, JobParams, NoArgs, + RunBuild, external::{ExternalCommandArgs, ExternalCommandJobKind}, firrtl::{FirrtlArgs, FirrtlJobKind}, formal::{Formal, FormalAdditionalArgs, FormalArgs, FormalMode, WriteSbyFileJobKind}, @@ -106,7 +106,7 @@ fn make_assert_formal_args( ) -> eyre::Result>> { let args = JobKindAndArgs { kind: BaseJobKind, - args: BaseJobArgs::from_output_dir_and_env(get_assert_formal_target_path(&test_name), None), + args: BaseJobArgs::from_output_dir_and_env(get_assert_formal_target_path(&test_name)), }; let dependencies = JobArgsAndDependencies { args, @@ -168,9 +168,9 @@ pub fn try_assert_formal>, T: BundleType>( solver, export_options, )? - .run_without_platform( - |NoArgs {}| Ok(JobParams::new(module)), - &GlobalParams::new(None, APP_NAME), + .run( + |NoArgs {}| Ok(JobParams::new(module, APP_NAME)), + clap::Command::new(APP_NAME), // not actually used, so we can use an arbitrary value ) } diff --git a/crates/fayalite/src/vendor/xilinx.rs b/crates/fayalite/src/vendor/xilinx.rs index 2298541..11b6048 100644 --- a/crates/fayalite/src/vendor/xilinx.rs +++ b/crates/fayalite/src/vendor/xilinx.rs @@ -11,7 +11,6 @@ use serde::{Deserialize, Serialize}; use std::fmt; pub mod arty_a7; -pub mod primitives; pub mod yosys_nextpnr_prjxray; #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] diff --git a/crates/fayalite/src/vendor/xilinx/arty_a7.rs b/crates/fayalite/src/vendor/xilinx/arty_a7.rs index 5a1123b..e8affa2 100644 --- a/crates/fayalite/src/vendor/xilinx/arty_a7.rs +++ b/crates/fayalite/src/vendor/xilinx/arty_a7.rs @@ -3,17 +3,9 @@ use crate::{ intern::{Intern, Interned}, - module::instance_with_loc, - platform::{ - DynPlatform, Peripheral, PeripheralRef, Peripherals, PeripheralsBuilderFactory, - PeripheralsBuilderFinished, Platform, - peripherals::{ClockInput, Led, RgbLed}, - }, - prelude::*, - vendor::xilinx::{ - Device, XdcIOStandardAnnotation, XdcLocationAnnotation, - primitives::{self, BUFGCE, FDPE, STARTUPE2_default_inputs}, - }, + platform::{DynPlatform, PeripheralsBuilderFactory, PeripheralsBuilderFinished, Platform}, + prelude::{ModuleBuilder, SourceLocation}, + vendor::xilinx::Device, }; macro_rules! arty_a7_platform { @@ -54,53 +46,8 @@ arty_a7_platform! { } } -#[derive(Debug)] -pub struct ArtyA7Peripherals { - clk100: Peripheral, - rst: Peripheral, - rst_sync: Peripheral, - ld0: Peripheral, - ld1: Peripheral, - ld2: Peripheral, - ld3: Peripheral, - ld4: Peripheral, - ld5: Peripheral, - ld6: Peripheral, - ld7: Peripheral, - // TODO: add rest of peripherals when we need them -} - -impl Peripherals for ArtyA7Peripherals { - fn append_peripherals<'a>(&'a self, peripherals: &mut Vec>) { - let Self { - clk100, - rst, - rst_sync, - ld0, - ld1, - ld2, - ld3, - ld4, - ld5, - ld6, - ld7, - } = self; - clk100.append_peripherals(peripherals); - rst.append_peripherals(peripherals); - rst_sync.append_peripherals(peripherals); - ld0.append_peripherals(peripherals); - ld1.append_peripherals(peripherals); - ld2.append_peripherals(peripherals); - ld3.append_peripherals(peripherals); - ld4.append_peripherals(peripherals); - ld5.append_peripherals(peripherals); - ld6.append_peripherals(peripherals); - ld7.append_peripherals(peripherals); - } -} - impl Platform for ArtyA7Platform { - type Peripherals = ArtyA7Peripherals; + type Peripherals = (); fn name(&self) -> Interned { self.as_str().intern() @@ -110,23 +57,8 @@ impl Platform for ArtyA7Platform { &self, builder_factory: PeripheralsBuilderFactory<'builder>, ) -> (Self::Peripherals, PeripheralsBuilderFinished<'builder>) { - let mut builder = builder_factory.builder(); - ( - ArtyA7Peripherals { - clk100: builder.input_peripheral("clk100", ClockInput::new(100e6)), - rst: builder.input_peripheral("rst", Reset), - rst_sync: builder.input_peripheral("rst_sync", SyncReset), - ld0: builder.input_peripheral("ld0", RgbLed), - ld1: builder.input_peripheral("ld1", RgbLed), - ld2: builder.input_peripheral("ld2", RgbLed), - ld3: builder.input_peripheral("ld3", RgbLed), - ld4: builder.input_peripheral("ld4", Led), - ld5: builder.input_peripheral("ld5", Led), - ld6: builder.input_peripheral("ld6", Led), - ld7: builder.input_peripheral("ld7", Led), - }, - builder.finish(), - ) + let builder = builder_factory.builder(); + (todo!(), builder.finish()) } fn source_location(&self) -> SourceLocation { @@ -134,132 +66,7 @@ impl Platform for ArtyA7Platform { } fn add_peripherals_in_wrapper_module(&self, m: &ModuleBuilder, peripherals: Self::Peripherals) { - let ArtyA7Peripherals { - clk100, - rst, - rst_sync, - ld0, - ld1, - ld2, - ld3, - ld4, - ld5, - ld6, - ld7, - } = peripherals; - let make_buffered_input = |name: &str, location: &str, io_standard: &str, invert: bool| { - let pin = m.input_with_loc(name, SourceLocation::builtin(), Bool); - annotate( - pin, - XdcLocationAnnotation { - location: location.intern(), - }, - ); - annotate( - pin, - XdcIOStandardAnnotation { - value: io_standard.intern(), - }, - ); - let buf = instance_with_loc( - &format!("{name}_buf"), - primitives::IBUF(), - SourceLocation::builtin(), - ); - connect(buf.I, pin); - if invert { !buf.O } else { buf.O } - }; - let make_buffered_output = |name: &str, location: &str, io_standard: &str| { - let pin = m.output_with_loc(name, SourceLocation::builtin(), Bool); - annotate( - pin, - XdcLocationAnnotation { - location: location.intern(), - }, - ); - annotate( - pin, - XdcIOStandardAnnotation { - value: io_standard.intern(), - }, - ); - let buf = instance_with_loc( - &format!("{name}_buf"), - primitives::OBUFT(), - SourceLocation::builtin(), - ); - connect(pin, buf.O); - connect(buf.T, false); - buf.I - }; - let clk100_buf = make_buffered_input("clk100", "E3", "LVCMOS33", false); - let startup = instance_with_loc( - "startup", - STARTUPE2_default_inputs(), - SourceLocation::builtin(), - ); - let clk100_sync = instance_with_loc("clk100_sync", BUFGCE(), SourceLocation::builtin()); - connect(clk100_sync.CE, startup.EOS); - connect(clk100_sync.I, clk100_buf); - 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_sync_0, rst_sync_1] = std::array::from_fn(|index| { - let rst_sync = instance_with_loc( - &format!("rst_sync_{index}"), - FDPE(true), - SourceLocation::builtin(), - ); - annotate( - rst_sync, - SVAttributeAnnotation { - text: "ASYNC_REG = \"TRUE\"".intern(), - }, - ); - connect(rst_sync.C, clk100_sync.O); - connect(rst_sync.CE, true); - connect(rst_sync.PRE, rst_buf.to_async_reset()); - rst_sync - }); - connect(rst_sync_0.D, false); - connect(rst_sync_1.D, rst_sync_0.Q); - let rst_value = rst_sync_1.Q.to_sync_reset(); - if let Some(rst) = rst.into_used() { - connect(rst.instance_io_field(), rst_value.to_reset()); - } - if let Some(rst_sync) = rst_sync.into_used() { - connect(rst_sync.instance_io_field(), rst_value); - } - let rgb_leds = [ - (ld0, ("G6", "F6", "E1")), - (ld1, ("G3", "J4", "G4")), - (ld2, ("J3", "J2", "H4")), - (ld3, ("K1", "H6", "K2")), - ]; - for (rgb_led, (r_loc, g_loc, b_loc)) in rgb_leds { - let r = make_buffered_output(&format!("{}_r", rgb_led.name()), r_loc, "LVCMOS33"); - let g = make_buffered_output(&format!("{}_g", rgb_led.name()), g_loc, "LVCMOS33"); - let b = make_buffered_output(&format!("{}_b", rgb_led.name()), b_loc, "LVCMOS33"); - if let Some(rgb_led) = rgb_led.into_used() { - connect(r, rgb_led.instance_io_field().r); - connect(g, rgb_led.instance_io_field().g); - connect(b, rgb_led.instance_io_field().b); - } else { - connect(r, false); - connect(g, false); - connect(b, false); - } - } - let leds = [(ld4, "H5"), (ld5, "J5"), (ld6, "T9"), (ld7, "T10")]; - for (led, loc) in leds { - let o = make_buffered_output(&led.name(), loc, "LVCMOS33"); - if let Some(led) = led.into_used() { - connect(o, led.instance_io_field().on); - } else { - connect(o, false); - } - } + let () = peripherals; } } diff --git a/crates/fayalite/src/vendor/xilinx/primitives.rs b/crates/fayalite/src/vendor/xilinx/primitives.rs deleted file mode 100644 index 6e2bfb9..0000000 --- a/crates/fayalite/src/vendor/xilinx/primitives.rs +++ /dev/null @@ -1,66 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// See Notices.txt for copyright information - -#![allow(non_snake_case)] - -use crate::prelude::*; - -#[hdl_module(extern)] -pub fn IBUF() { - 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: Bool = m.input(); -} - -#[hdl_module(extern)] -pub fn STARTUPE2_default_inputs() { - m.verilog_name("STARTUPE2"); - #[hdl] - let CFGCLK: Clock = m.output(); - #[hdl] - let CFGMCLK: Clock = m.output(); - #[hdl] - let EOS: Bool = m.output(); - #[hdl] - let PREQ: Bool = m.output(); -} - -#[hdl_module(extern)] -pub fn FDPE(init: bool) { - m.verilog_name("FDPE"); - m.parameter_raw_verilog("INIT", if init { "1'b1" } else { "1'b0" }); - #[hdl] - let Q: Bool = m.output(); - #[hdl] - let C: Clock = m.input(); - #[hdl] - let CE: Bool = m.input(); - #[hdl] - let PRE: AsyncReset = m.input(); - #[hdl] - let D: Bool = m.input(); -}