diff --git a/crates/fayalite/examples/tx_only_uart.rs b/crates/fayalite/examples/tx_only_uart.rs index 5c20b395..c50e987f 100644 --- a/crates/fayalite/examples/tx_only_uart.rs +++ b/crates/fayalite/examples/tx_only_uart.rs @@ -3,34 +3,10 @@ use clap::builder::TypedValueParser; use fayalite::{ build::{ToArgs, WriteArgs}, - platform::PeripheralRef, prelude::*, }; use ordered_float::NotNan; -fn pick_clock<'a>( - platform_io_builder: &PlatformIOBuilder<'a>, -) -> PeripheralRef<'a, peripherals::ClockInput> { - let mut clks = platform_io_builder.peripherals_with_type::(); - clks.sort_by_key(|clk| { - // sort clocks by preference, smaller return values means higher preference - let mut frequency = clk.ty().frequency(); - let priority; - if frequency < 10e6 { - frequency = -frequency; // prefer bigger frequencies - priority = 1; - } else if frequency > 50e6 { - // prefer smaller frequencies - priority = 2; // least preferred - } else { - priority = 0; // most preferred - frequency = (frequency - 25e6).abs(); // prefer closer to 25MHz - } - (priority, NotNan::new(frequency).expect("should be valid")) - }); - clks[0] -} - #[hdl_module] fn tx_only_uart( platform_io_builder: PlatformIOBuilder<'_>, @@ -38,7 +14,8 @@ fn tx_only_uart( message: impl AsRef<[u8]>, ) { let message = message.as_ref(); - let clk_input = pick_clock(&platform_io_builder).use_peripheral(); + let clk_input = + platform_io_builder.peripherals_with_type::()[0].use_peripheral(); let rst = platform_io_builder.peripherals_with_type::()[0].use_peripheral(); let cd = #[hdl] ClockDomain { @@ -79,12 +56,17 @@ fn tx_only_uart( connect_any(next_uart_state, uart_state_reg + 1u8); #[hdl] - let message_mem: Array> = wire(Array[UInt::new_static()][message.len()]); - for (message, message_mem) in message.iter().zip(message_mem) { - connect(message_mem, *message); - } + let mut message_mem = memory_with_init(message); + message_mem.read_latency(4); + #[hdl] + let startup_reg = reg_builder().clock_domain(cd).reset(0u128); + connect_any(startup_reg, (startup_reg << 1) | 1u8); + let message_read = message_mem.new_read_port(); + connect(message_read.clk, cd.clk); + connect(message_read.en, true); #[hdl] let addr_reg: UInt<32> = reg_builder().clock_domain(cd).reset(0u32); + connect_any(message_read.addr, addr_reg); #[hdl] let next_addr: UInt<32> = wire(); connect(next_addr, addr_reg); @@ -93,19 +75,18 @@ fn tx_only_uart( let tx = reg_builder().clock_domain(cd).reset(true); #[hdl] - let tx_bits: Array = wire(); - - connect(tx_bits[0], false); // start bit - connect(tx_bits[9], true); // stop bit - - for i in 0..8 { - connect(tx_bits[i + 1], message_mem[addr_reg][i]); // data bits - } - - connect(tx, tx_bits[uart_state_reg]); - - #[hdl] - if uart_state_reg.cmp_eq(Expr::ty(tx_bits).len() - 1) { + if !startup_reg[message_mem.get_read_latency()] { + connect(next_uart_state, 0_hdl_u4); + connect(tx, true); + } else if uart_state_reg.cmp_eq(0_hdl_u4) { + connect(tx, false); // start bit + } else if uart_state_reg.cmp_le(8_hdl_u4) { + connect( + tx, + (message_read.data >> (uart_state_reg - 1_hdl_u4))[0].cast_to_static(), + ); // data bit + } else { + connect(tx, true); // stop bit connect(next_uart_state, 0_hdl_u4); let next_addr_val = addr_reg + 1u8; #[hdl] @@ -166,7 +147,7 @@ fn main() { "tx_only_uart", |_, platform, ExtraArgs { baud_rate, message }| { Ok(JobParams::new(platform.try_wrap_main_module(|io| { - let clk = pick_clock(&io).ty(); + let clk = io.peripherals_with_type::()[0].ty(); let divisor = clk.frequency() / *baud_rate; let baud_rate_error = |msg| { ::command() diff --git a/crates/fayalite/src/vendor/xilinx/arty_a7.rs b/crates/fayalite/src/vendor/xilinx/arty_a7.rs index 552eb4aa..0ba214e0 100644 --- a/crates/fayalite/src/vendor/xilinx/arty_a7.rs +++ b/crates/fayalite/src/vendor/xilinx/arty_a7.rs @@ -3,7 +3,7 @@ use crate::{ intern::{Intern, Interned}, - module::{instance_with_loc, reg_builder_with_loc, wire_with_loc}, + module::{instance_with_loc, wire_with_loc}, platform::{ DynPlatform, Peripheral, PeripheralRef, Peripherals, PeripheralsBuilderFactory, PeripheralsBuilderFinished, Platform, PlatformAspectSet, @@ -12,7 +12,7 @@ use crate::{ prelude::*, vendor::xilinx::{ Device, XdcCreateClockAnnotation, XdcIOStandardAnnotation, XdcLocationAnnotation, - primitives, + primitives::{self, BUFGCE, STARTUPE2_default_inputs}, }, }; use ordered_float::NotNan; @@ -66,7 +66,7 @@ arty_a7_platform! { #[derive(Debug)] pub struct ArtyA7Peripherals { - clk100_div_pow2: [Peripheral; 4], + clk100: Peripheral, rst: Peripheral, rst_sync: Peripheral, ld0: Peripheral, @@ -84,7 +84,7 @@ pub struct ArtyA7Peripherals { impl Peripherals for ArtyA7Peripherals { fn append_peripherals<'a>(&'a self, peripherals: &mut Vec>) { let Self { - clk100_div_pow2, + clk100, rst, rst_sync, ld0, @@ -97,7 +97,7 @@ impl Peripherals for ArtyA7Peripherals { ld7, uart, } = self; - clk100_div_pow2.append_peripherals(peripherals); + clk100.append_peripherals(peripherals); rst.append_peripherals(peripherals); rst_sync.append_peripherals(peripherals); ld0.append_peripherals(peripherals); @@ -171,20 +171,9 @@ impl Platform for ArtyA7Platform { builder_factory: PeripheralsBuilderFactory<'builder>, ) -> (Self::Peripherals, PeripheralsBuilderFinished<'builder>) { let mut builder = builder_factory.builder(); - - let clk100_div_pow2 = std::array::from_fn(|log2_divisor| { - let divisor = 1u64 << log2_divisor; - let name = if divisor != 1 { - format!("clk100_div_{divisor}") - } else { - "clk100".into() - }; - builder.input_peripheral(name, ClockInput::new(100e6 / divisor as f64)) - }); - builder.add_conflicts(Vec::from_iter(clk100_div_pow2.iter().map(|v| v.id()))); ( ArtyA7Peripherals { - clk100_div_pow2, + clk100: builder.input_peripheral("clk100", ClockInput::new(100e6)), rst: builder.input_peripheral("rst", Reset), rst_sync: builder.input_peripheral("rst_sync", SyncReset), ld0: builder.output_peripheral("ld0", RgbLed), @@ -207,7 +196,7 @@ impl Platform for ArtyA7Platform { fn add_peripherals_in_wrapper_module(&self, m: &ModuleBuilder, peripherals: Self::Peripherals) { let ArtyA7Peripherals { - clk100_div_pow2, + clk100, rst, rst_sync, ld0, @@ -265,82 +254,30 @@ impl Platform for ArtyA7Platform { connect(buf.T, false); buf.I }; - let mut frequency = clk100_div_pow2[0].ty().frequency(); - let mut log2_divisor = 0; - let mut clk = None; - for (cur_log2_divisor, p) in clk100_div_pow2.into_iter().enumerate() { - let Some(p) = p.into_used() else { - continue; - }; - debug_assert!( - clk.is_none(), - "conflict-handling logic should ensure at most one clock is used", - ); - frequency = p.ty().frequency(); - clk = Some(p); - log2_divisor = cur_log2_divisor; - } + 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", false); let startup = instance_with_loc( "startup", - primitives::STARTUPE2_default_inputs(), + STARTUPE2_default_inputs(), SourceLocation::builtin(), ); - let clk_global_buf = instance_with_loc( - "clk_global_buf", - primitives::BUFGCE(), - SourceLocation::builtin(), - ); - connect(clk_global_buf.CE, startup.EOS); - let mut clk_global_buf_in = clk100_buf.to_clock(); - for prev_log2_divisor in 0..log2_divisor { - let prev_divisor = 1u64 << prev_log2_divisor; - let clk_in = wire_with_loc( - &format!("clk_div_{prev_divisor}"), - SourceLocation::builtin(), - Clock, - ); - connect(clk_in, clk_global_buf_in); - annotate( - clk_in, - XdcCreateClockAnnotation { - period: NotNan::new(1e9 / (100e6 / prev_divisor as f64)) - .expect("known to be valid"), - }, - ); - annotate(clk_in, DontTouchAnnotation); - let cd = wire_with_loc( - &format!("clk_div_{prev_divisor}_in"), - SourceLocation::builtin(), - ClockDomain[AsyncReset], - ); - connect(cd.clk, clk_in); - connect(cd.rst, (!startup.EOS).to_async_reset()); - let divider = reg_builder_with_loc("divider", SourceLocation::builtin()) - .clock_domain(cd) - .reset(false) - .build(); - connect(divider, !divider); - clk_global_buf_in = divider.to_clock(); - } - connect(clk_global_buf.I, clk_global_buf_in); - let clk_out = wire_with_loc("clk_out", SourceLocation::builtin(), Clock); - connect(clk_out, clk_global_buf.O); - annotate( - clk_out, - XdcCreateClockAnnotation { - period: NotNan::new(1e9 / frequency).expect("known to be valid"), - }, - ); - annotate(clk_out, DontTouchAnnotation); - if let Some(clk) = clk { - connect(clk.instance_io_field().clk, clk_out); + let clk100_sync = instance_with_loc("clk100_sync", BUFGCE(), SourceLocation::builtin()); + connect(clk100_sync.CE, startup.EOS); + connect(clk100_sync.I, clk100_buf); + let clk100_out = wire_with_loc("clk100_out", SourceLocation::builtin(), Clock); + connect(clk100_out, clk100_sync.O); + annotate(clk100_out, clock_annotation); + annotate(clk100_out, DontTouchAnnotation); + if let Some(clk100) = clk100.into_used() { + connect(clk100.instance_io_field().clk, clk100_out); } let rst_value = { let rst_buf = make_buffered_input("rst", "C2", "LVCMOS33", true); let rst_sync = instance_with_loc("rst_sync", reset_sync(), SourceLocation::builtin()); - connect(rst_sync.clk, clk_out); - connect(rst_sync.inp, rst_buf | !startup.EOS); + connect(rst_sync.clk, clk100_sync.O); + connect(rst_sync.inp, rst_buf); rst_sync.out }; if let Some(rst) = rst.into_used() { diff --git a/crates/fayalite/src/vendor/xilinx/primitives.rs b/crates/fayalite/src/vendor/xilinx/primitives.rs index 9e22d26f..5dc25672 100644 --- a/crates/fayalite/src/vendor/xilinx/primitives.rs +++ b/crates/fayalite/src/vendor/xilinx/primitives.rs @@ -33,7 +33,7 @@ pub fn BUFGCE() { #[hdl] let CE: Bool = m.input(); #[hdl] - let I: Clock = m.input(); + let I: Bool = m.input(); } #[hdl_module(extern)]