diff --git a/.gitignore b/.gitignore index a0e7a17..3e6a154 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ /target *.bin +*.txt +**/*.orig diff --git a/src/dmac/descriptor.rs b/src/dmac/descriptor.rs new file mode 100644 index 0000000..21e7d85 --- /dev/null +++ b/src/dmac/descriptor.rs @@ -0,0 +1,299 @@ +#[derive(Clone, Debug)] +#[repr(C, align(4))] +pub struct Descriptor { + configuration: u32, + source_address: u32, + destination_address: u32, + byte_counter: u32, + parameter: u32, + link: u32, +} + +// TODO: THIS COULD PROBABLY BE A BITFIELD LIBRARY +pub struct DescriptorConfig { + pub source: *const (), + pub destination: *mut (), + + // NOTE: Max is < 2^25, or < 32MiB + pub byte_counter: usize, + pub link: Option<*const ()>, + pub wait_clock_cycles: u8, + + pub bmode: BModeSel, + + pub dest_width: DataWidth, + pub dest_addr_mode: AddressMode, + pub dest_block_size: BlockSize, + pub dest_drq_type: DestDrqType, + + pub src_data_width: DataWidth, + pub src_addr_mode: AddressMode, + pub src_block_size: BlockSize, + pub src_drq_type: SrcDrqType, +} + +#[derive(Eq, PartialEq, Clone, Copy)] +#[repr(u8)] +pub enum SrcDrqType { + Sram = 0, + Dram = 1, + OwaRx = 2, + I2sPcm0Rx = 3, + I2sPcm1Rx = 4, + I2sPcm2Rx = 5, + AudioCodec = 7, + Dmic = 8, + GpADC = 12, + TpADC = 13, + Uart0Rx = 14, + Uart1Rx = 15, + Uart2Rx = 16, + Uart3Rx = 17, + Uart4Rx = 18, + Uart5Rx = 19, + Spi0Rx = 22, + Spi1Rx = 23, + Usb0Ep1 = 30, + Usb0Ep2 = 31, + Usb0Ep3 = 32, + Usb0Ep4 = 33, + Usb0Ep5 = 34, + Twi0 = 43, + Twi1 = 44, + Twi2 = 45, + Twi3 = 46, +} + +#[derive(Eq, PartialEq, Clone, Copy)] +#[repr(u8)] +pub enum DestDrqType { + Sram = 0, + Dram = 1, + OwaTx = 2, + I2sPcm0Tx = 3, + I2sPcm1Tx = 4, + I2sPcm2Tx = 5, + AudioCodec = 7, + IrTx = 13, + Uart0Tx = 14, + Uart1Tx = 15, + Uart2Tx = 16, + Uart3Tx = 17, + Uart4Tx = 18, + Uart5Tx = 19, + Spi0Tx = 22, + Spi1Tx = 23, + Usb0Ep1 = 30, + Usb0Ep2 = 31, + Usb0Ep3 = 32, + Usb0Ep4 = 33, + Usb0Ep5 = 34, + Ledc = 42, + Twi0 = 43, + Twi1 = 44, + Twi2 = 45, + Twi3 = 46, +} + +// TODO: Verify bits or bytes? +#[derive(Eq, PartialEq, Clone, Copy)] +#[repr(u8)] +pub enum BlockSize { + Byte1 = 0b00, + Byte4 = 0b01, + Byte8 = 0b10, + Byte16 = 0b11, +} + +#[derive(Eq, PartialEq, Clone, Copy)] +#[repr(u8)] +pub enum AddressMode { + LinearMode = 0, + IoMode = 1, +} + +#[derive(Eq, PartialEq, Clone, Copy)] +#[repr(u8)] +pub enum DataWidth { + Bit8 = 0b00, + Bit16 = 0b01, + Bit32 = 0b10, + Bit64 = 0b11, +} + +#[derive(Eq, PartialEq, Clone, Copy)] +#[repr(u8)] +pub enum BModeSel { + Normal, + BMode, +} + +// Descriptor + +impl Descriptor { + pub fn set_source(&mut self, source: u64) { + assert!(source < (1 << 34)); + self.source_address = source as u32; + // 332222222222 11 11 11111100 00000000 + // 109876543210 98 76 54321098 76543210 + self.parameter &= 0b111111111111_11_00_11111111_11111111; + self.parameter |= (((source >> 32) & 0b11) << 16) as u32; + } + + pub fn set_dest(&mut self, dest: u64) { + assert!(dest < (1 << 34)); + self.destination_address = dest as u32; + // 332222222222 11 11 11111100 00000000 + // 109876543210 98 76 54321098 76543210 + self.parameter &= 0b111111111111_00_11_11111111_11111111; + self.parameter |= (((dest >> 32) & 0b11) << 18) as u32; + } + + pub fn end_link(&mut self) { + self.link = 0xFFFF_F800; + } +} + +impl TryFrom for Descriptor { + type Error = (); + + fn try_from(value: DescriptorConfig) -> Result { + let source = value.source as usize; + let destination = value.destination as usize; + + if source as usize >= (1 << 34) { + return Err(()); + } + if destination as usize >= (1 << 34) { + return Err(()); + } + if value.byte_counter >= (1 << 25) { + return Err(()); + } + if let Some(link) = value.link { + let link = link as usize; + if (link & 0b11) != 0 { + return Err(()); + } + } + + let mut descriptor = Descriptor { + configuration: 0, + source_address: 0, + destination_address: 0, + byte_counter: 0, + parameter: 0, + link: 0, + }; + + // Set source + descriptor.source_address = source as u32; + // 332222222222 11 11 11111100 00000000 + // 109876543210 98 76 54321098 76543210 + descriptor.parameter &= 0b111111111111_11_00_11111111_11111111; + descriptor.parameter |= (((source >> 32) & 0b11) << 16) as u32; + + // Set dest + descriptor.destination_address = destination as u32; + // 332222222222 11 11 11111100 00000000 + // 109876543210 98 76 54321098 76543210 + descriptor.parameter &= 0b111111111111_00_11_11111111_11111111; + descriptor.parameter |= (((destination >> 32) & 0b11) << 18) as u32; + + descriptor.byte_counter = value.byte_counter as u32; + + // Set configuration + descriptor.configuration |= value.bmode.to_desc_bits(); + descriptor.configuration |= value.dest_width.to_desc_bits_dest(); + descriptor.configuration |= value.dest_addr_mode.to_desc_bits_dest(); + descriptor.configuration |= value.dest_block_size.to_desc_bits_dest(); + descriptor.configuration |= value.dest_drq_type.to_desc_bits(); + descriptor.configuration |= value.src_data_width.to_desc_bits_src(); + descriptor.configuration |= value.src_addr_mode.to_desc_bits_src(); + descriptor.configuration |= value.src_block_size.to_desc_bits_src(); + descriptor.configuration |= value.src_drq_type.to_desc_bits(); + + if let Some(link) = value.link { + descriptor.link = link as u32; + // We already verified above the low bits of `value.link` are clear, + // no need to re-mask the current state of `descriptor.link`. + descriptor.link |= ((link as usize >> 32) as u32) & 0b11 + } else { + descriptor.end_link(); + } + + Ok(descriptor) + } +} + +// DescriptorConfig + +// SrcDrqType + +impl SrcDrqType { + #[inline(always)] + fn to_desc_bits(&self) -> u32 { + // 6 bits, no shift + ((*self as u8) & 0b11_1111) as u32 + } +} + +// DestDrqType + +impl DestDrqType { + #[inline(always)] + fn to_desc_bits(&self) -> u32 { + (((*self as u8) & 0b11_1111) as u32) << 16 + } +} + +// BlockSize + +impl BlockSize { + #[inline(always)] + fn to_desc_bits_dest(&self) -> u32 { + (((*self as u8) & 0b11) as u32) << 22 + } + + #[inline(always)] + fn to_desc_bits_src(&self) -> u32 { + (((*self as u8) & 0b11) as u32) << 6 + } +} + +// AddressMode + +impl AddressMode { + #[inline(always)] + fn to_desc_bits_src(&self) -> u32 { + (((*self as u8) & 0b1) as u32) << 8 + } + + #[inline(always)] + fn to_desc_bits_dest(&self) -> u32 { + (((*self as u8) & 0b1) as u32) << 24 + } +} + +// DataWidth + +impl DataWidth { + #[inline(always)] + fn to_desc_bits_dest(&self) -> u32 { + (((*self as u8) & 0b11) as u32) << 25 + } + + #[inline(always)] + fn to_desc_bits_src(&self) -> u32 { + (((*self as u8) & 0b11) as u32) << 9 + } +} + +// BModeSel + +impl BModeSel { + #[inline(always)] + fn to_desc_bits(&self) -> u32 { + (((*self as u8) & 0b1) as u32) << 30 + } +} diff --git a/src/dmac/mod.rs b/src/dmac/mod.rs new file mode 100644 index 0000000..8dfa103 --- /dev/null +++ b/src/dmac/mod.rs @@ -0,0 +1,163 @@ +use core::{ + ptr::NonNull, + sync::atomic::{fence, Ordering}, +}; + +use d1_pac::{ + dmac::{dmac_desc_addr_reg::DMAC_DESC_ADDR_REG_SPEC, dmac_en_reg::DMAC_EN_REG_SPEC, dmac_mode_reg::DMAC_MODE_REG_SPEC}, + generic::Reg, + CCU, DMAC, +}; + +use self::descriptor::Descriptor; + +pub mod descriptor; + +pub struct Dmac { + pub dmac: DMAC, // TODO: not this + pub channels: [Channel; 16], +} + +impl Dmac { + pub fn new(dmac: DMAC, ccu: &mut CCU) -> Self { + ccu.dma_bgr.write(|w| w.gating().pass().rst().deassert()); + Self { + dmac, + channels: [ + Channel { idx: 0 }, + Channel { idx: 1 }, + Channel { idx: 2 }, + Channel { idx: 3 }, + Channel { idx: 4 }, + Channel { idx: 5 }, + Channel { idx: 6 }, + Channel { idx: 7 }, + Channel { idx: 8 }, + Channel { idx: 9 }, + Channel { idx: 10 }, + Channel { idx: 11 }, + Channel { idx: 12 }, + Channel { idx: 13 }, + Channel { idx: 14 }, + Channel { idx: 15 }, + ], + } + } +} + +pub struct Channel { + idx: u8, +} + +impl Channel { + pub unsafe fn desc_addr_reg(&self) -> &Reg { + let dmac = &*DMAC::PTR; + match self.idx { + 0 => &dmac.dmac_desc_addr_reg0, + 1 => &dmac.dmac_desc_addr_reg1, + 2 => &dmac.dmac_desc_addr_reg2, + 3 => &dmac.dmac_desc_addr_reg3, + 4 => &dmac.dmac_desc_addr_reg4, + 5 => &dmac.dmac_desc_addr_reg5, + 6 => &dmac.dmac_desc_addr_reg6, + 7 => &dmac.dmac_desc_addr_reg7, + 8 => &dmac.dmac_desc_addr_reg8, + 9 => &dmac.dmac_desc_addr_reg9, + 10 => &dmac.dmac_desc_addr_reg10, + 11 => &dmac.dmac_desc_addr_reg11, + 12 => &dmac.dmac_desc_addr_reg12, + 13 => &dmac.dmac_desc_addr_reg13, + 14 => &dmac.dmac_desc_addr_reg14, + 15 => &dmac.dmac_desc_addr_reg15, + _ => panic!(), + } + } + + pub unsafe fn en_reg(&self) -> &Reg { + let dmac = &*DMAC::PTR; + match self.idx { + 0 => &dmac.dmac_en_reg0, + 1 => &dmac.dmac_en_reg1, + 2 => &dmac.dmac_en_reg2, + 3 => &dmac.dmac_en_reg3, + 4 => &dmac.dmac_en_reg4, + 5 => &dmac.dmac_en_reg5, + 6 => &dmac.dmac_en_reg6, + 7 => &dmac.dmac_en_reg7, + 8 => &dmac.dmac_en_reg8, + 9 => &dmac.dmac_en_reg9, + 10 => &dmac.dmac_en_reg10, + 11 => &dmac.dmac_en_reg11, + 12 => &dmac.dmac_en_reg12, + 13 => &dmac.dmac_en_reg13, + 14 => &dmac.dmac_en_reg14, + 15 => &dmac.dmac_en_reg15, + _ => panic!(), + } + } + + pub unsafe fn mode_reg(&self) -> &Reg { + let dmac = &*DMAC::PTR; + match self.idx { + 0 => &dmac.dmac_mode_reg0, + 1 => &dmac.dmac_mode_reg1, + 2 => &dmac.dmac_mode_reg2, + 3 => &dmac.dmac_mode_reg3, + 4 => &dmac.dmac_mode_reg4, + 5 => &dmac.dmac_mode_reg5, + 6 => &dmac.dmac_mode_reg6, + 7 => &dmac.dmac_mode_reg7, + 8 => &dmac.dmac_mode_reg8, + 9 => &dmac.dmac_mode_reg9, + 10 => &dmac.dmac_mode_reg10, + 11 => &dmac.dmac_mode_reg11, + 12 => &dmac.dmac_mode_reg12, + 13 => &dmac.dmac_mode_reg13, + 14 => &dmac.dmac_mode_reg14, + 15 => &dmac.dmac_mode_reg15, + _ => panic!(), + } + } + + pub unsafe fn set_channel_modes(&mut self, src: ChannelMode, dst: ChannelMode) { + self.mode_reg().write(|w| { + match src { + ChannelMode::Wait => w.dma_src_mode().waiting(), + ChannelMode::Handshake => w.dma_src_mode().handshake(), + }; + match dst { + ChannelMode::Wait => w.dma_dst_mode().waiting(), + ChannelMode::Handshake => w.dma_dst_mode().handshake(), + }; + w + }) + } + + pub unsafe fn start_descriptor(&mut self, desc: NonNull) { + // TODO: Check if channel is idle? + + fence(Ordering::SeqCst); ////// + + let desc_addr = desc.as_ptr() as usize; + self.desc_addr_reg().write(|w| { + w.dma_desc_addr().variant((desc_addr >> 2) as u32); + w.dma_desc_high_addr() + .variant(((desc_addr >> 32) as u8) & 0b11); + w + }); + self.en_reg().write(|w| w.dma_en().enabled()); + + fence(Ordering::SeqCst); ////// + } + + pub unsafe fn stop_dma(&mut self) { + self.en_reg().write(|w| w.dma_en().disabled()); + + fence(Ordering::SeqCst); ////// + } +} + +pub enum ChannelMode { + Wait, + Handshake, +} diff --git a/src/examples/timers.rs b/src/examples/timers.rs new file mode 100644 index 0000000..2115b0e --- /dev/null +++ b/src/examples/timers.rs @@ -0,0 +1,154 @@ +#![no_std] +#![no_main] + +use d1_pac::{PLIC, TIMER}; +use panic_halt as _; +use d1_playground::timer::{Timer, TimerMode, TimerPrescaler, TimerSource, Timers}; + +struct Uart(d1_pac::UART0); +static mut PRINTER: Option = None; +impl core::fmt::Write for Uart { + fn write_str(&mut self, s: &str) -> core::fmt::Result { + for byte in s.as_bytes() { + self.0.thr().write(|w| unsafe { w.thr().bits(*byte) }); + while self.0.usr.read().tfnf().bit_is_clear() {} + } + Ok(()) + } +} +pub fn _print(args: core::fmt::Arguments) { + use core::fmt::Write; + unsafe { + PRINTER.as_mut().unwrap().write_fmt(args).ok(); + } +} +#[macro_export] +macro_rules! print { + ($($arg:tt)*) => { + $crate::_print(core::format_args!($($arg)*)); + } +} +#[macro_export] +macro_rules! println { + ($($arg:tt)*) => { + $crate::_print(core::format_args!($($arg)*)); + $crate::print!("\r\n"); + } +} + +#[riscv_rt::entry] +fn main() -> ! { + let p = d1_pac::Peripherals::take().unwrap(); + + // Enable UART0 clock. + let ccu = &p.CCU; + ccu.uart_bgr + .write(|w| w.uart0_gating().pass().uart0_rst().deassert()); + + // Set PC1 LED to output. + let gpio = &p.GPIO; + gpio.pc_cfg0 + .write(|w| w.pc1_select().output().pc0_select().ledc_do()); + + // Set PB8 and PB9 to function 6, UART0, internal pullup. + gpio.pb_cfg1 + .write(|w| w.pb8_select().uart0_tx().pb9_select().uart0_rx()); + gpio.pb_pull0 + .write(|w| w.pc8_pull().pull_up().pc9_pull().pull_up()); + + // Configure UART0 for 115200 8n1. + // By default APB1 is 24MHz, use divisor 13 for 115200. + let uart0 = p.UART0; + uart0.mcr.write(|w| unsafe { w.bits(0) }); + uart0.fcr().write(|w| w.fifoe().set_bit()); + uart0.halt.write(|w| w.halt_tx().enabled()); + uart0.lcr.write(|w| w.dlab().divisor_latch()); + uart0.dll().write(|w| unsafe { w.dll().bits(13) }); + uart0.dlh().write(|w| unsafe { w.dlh().bits(0) }); + uart0.lcr.write(|w| w.dlab().rx_buffer().dls().eight()); + uart0.halt.write(|w| w.halt_tx().disabled()); + unsafe { PRINTER = Some(Uart(uart0)) }; + + // Set up timers + let Timers { + mut timer0, + mut timer1, + .. + } = Timers::new(p.TIMER); + + timer0.set_source(TimerSource::OSC24_M); + timer1.set_source(TimerSource::OSC24_M); + + timer0.set_prescaler(TimerPrescaler::P8); // 24M / 8: 3.00M ticks/s + timer1.set_prescaler(TimerPrescaler::P32); // 24M / 32: 0.75M ticks/s + + timer0.set_mode(TimerMode::SINGLE_COUNTING); + timer1.set_mode(TimerMode::SINGLE_COUNTING); + + let _ = timer0.get_and_clear_interrupt(); + let _ = timer1.get_and_clear_interrupt(); + + unsafe { + riscv::interrupt::enable(); + riscv::register::mie::set_mext(); + } + + // yolo + timer0.set_interrupt_en(true); + timer1.set_interrupt_en(true); + let plic = &p.PLIC; + + plic.prio[75].write(|w| w.priority().p1()); + plic.prio[76].write(|w| w.priority().p1()); + plic.mie[2].write(|w| unsafe { w.bits((1 << 11) | (1 << 12)) }); + + // Blink LED + loop { + // Start both counters for 3M ticks: that's 1s for timer 0 + // and 4s for timer 1, for a 25% duty cycle + timer0.start_counter(3_000_000); + timer1.start_counter(3_000_000); + gpio.pc_dat.write(|w| unsafe { w.bits(2) }); + + unsafe { riscv::asm::wfi() }; + // while !timer0.get_and_clear_interrupt() { } + println!("T0 DONE"); + + gpio.pc_dat.write(|w| unsafe { w.bits(0) }); + unsafe { riscv::asm::wfi() }; + println!("T1 DONE"); + } +} + +#[export_name = "MachineExternal"] +fn im_an_interrupt() { + let plic = unsafe { &*PLIC::PTR }; + let timer = unsafe { &*TIMER::PTR }; + + let claim = plic.mclaim.read().mclaim(); + println!("INTERRUPT! claim: {}", claim.bits()); + + match claim.bits() { + 75 => { + timer + .tmr_irq_sta + .modify(|_r, w| w.tmr0_irq_pend().set_bit()); + // Wait for the interrupt to clear to avoid repeat interrupts + while timer.tmr_irq_sta.read().tmr0_irq_pend().bit_is_set() {} + } + 76 => { + timer + .tmr_irq_sta + .modify(|_r, w| w.tmr1_irq_pend().set_bit()); + // Wait for the interrupt to clear to avoid repeat interrupts + while timer.tmr_irq_sta.read().tmr1_irq_pend().bit_is_set() {} + } + x => { + println!("Unexpected claim: {}", x); + panic!(); + } + } + + // Release claim + plic.mclaim.write(|w| w.mclaim().variant(claim.bits())); +} diff --git a/src/lib.rs b/src/lib.rs index ed5fe09..204ba7c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,6 @@ #![no_std] +pub mod de; +pub mod dmac; pub mod plic; pub mod timer; diff --git a/src/main.rs b/src/main.rs index 081fb4f..61e9bdc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,18 +1,27 @@ #![no_std] #![no_main] -use d1_pac::{Interrupt, TIMER}; +use core::cell::UnsafeCell; +use core::ptr::NonNull; +use core::sync::atomic::{compiler_fence, Ordering, fence}; + +use d1_pac::{Interrupt, TIMER, UART0}; +use d1_playground::dmac::descriptor::{ + AddressMode, BModeSel, BlockSize, DataWidth, DescriptorConfig, DestDrqType, SrcDrqType, Descriptor, +}; +use d1_playground::dmac::{Dmac, ChannelMode}; use panic_halt as _; -mod de; - use d1_playground::plic::{Plic, Priority}; use d1_playground::timer::{Timer, TimerMode, TimerPrescaler, TimerSource, Timers}; +static HOUND: &str = include_str!("../hound.txt"); + struct Uart(d1_pac::UART0); static mut PRINTER: Option = None; impl core::fmt::Write for Uart { fn write_str(&mut self, s: &str) -> core::fmt::Result { + while self.0.usr.read().tfnf().bit_is_clear() {} for byte in s.as_bytes() { self.0.thr().write(|w| unsafe { w.thr().bits(*byte) }); while self.0.usr.read().tfnf().bit_is_clear() {} @@ -20,6 +29,14 @@ impl core::fmt::Write for Uart { Ok(()) } } +fn print_raw(data: &[u8]) { + let uart = unsafe { PRINTER.as_mut().unwrap() }; + while uart.0.usr.read().tfnf().bit_is_clear() {} + for byte in data { + uart.0.thr().write(|w| unsafe { w.thr().bits(*byte) }); + while uart.0.usr.read().tfnf().bit_is_clear() {} + } +} pub fn _print(args: core::fmt::Arguments) { use core::fmt::Write; unsafe { @@ -42,13 +59,16 @@ macro_rules! println { #[riscv_rt::entry] fn main() -> ! { - let p = d1_pac::Peripherals::take().unwrap(); + let mut p = d1_pac::Peripherals::take().unwrap(); // Enable UART0 clock. - let ccu = &p.CCU; + let ccu = &mut p.CCU; ccu.uart_bgr .write(|w| w.uart0_gating().pass().uart0_rst().deassert()); + // DMAC enable + let mut dmac = Dmac::new(p.DMAC, ccu); + // Set PC1 LED to output. let gpio = &p.GPIO; gpio.pc_cfg0 @@ -63,14 +83,48 @@ fn main() -> ! { // Configure UART0 for 115200 8n1. // By default APB1 is 24MHz, use divisor 13 for 115200. let uart0 = p.UART0; + + // UART Mode + // No Auto Flow Control + // No Loop Back + // No RTS_N + // No DTR_N uart0.mcr.write(|w| unsafe { w.bits(0) }); - uart0.fcr().write(|w| w.fifoe().set_bit()); + + // RCVR INT Trigger: 1 char in FIFO + // TXMT INT Trigger: FIFO Empty + // DMA Mode 0 - (???) + // FIFOs Enabled + // uart0.hsk.write(|w| w.hsk().handshake()); + // uart0.dma_req_en.modify(|_r, w| w.timeout_enable().set_bit()); + // uart0.fcr().write(|w| w.fifoe().set_bit().dmam().mode_1()); + uart0.fcr().write(|w| { + w.fifoe().set_bit(); + w.rt().half_full(); + w + }); + uart0.ier().write(|w| { + w.erbfi().set_bit(); + w + }); + + // TX Halted + // Also has some DMA relevant things? Not set currently uart0.halt.write(|w| w.halt_tx().enabled()); + + // Enable control of baudrates uart0.lcr.write(|w| w.dlab().divisor_latch()); + + // Baudrates uart0.dll().write(|w| unsafe { w.dll().bits(13) }); uart0.dlh().write(|w| unsafe { w.dlh().bits(0) }); + + // Unlatch baud rate, set width uart0.lcr.write(|w| w.dlab().rx_buffer().dls().eight()); + + // Re-enable sending uart0.halt.write(|w| w.halt_tx().disabled()); + unsafe { PRINTER = Some(Uart(uart0)) }; // Set up timers @@ -101,38 +155,61 @@ fn main() -> ! { timer0.set_interrupt_en(true); timer1.set_interrupt_en(true); let plic = Plic::new(p.PLIC); + unsafe { + plic.set_priority(Interrupt::UART0, Priority::P1); plic.set_priority(Interrupt::TIMER0, Priority::P1); plic.set_priority(Interrupt::TIMER1, Priority::P1); + plic.unmask(Interrupt::UART0); plic.unmask(Interrupt::TIMER0); plic.unmask(Interrupt::TIMER1); } - // Blink LED - loop { - // Start both counters for 3M ticks: that's 1s for timer 0 - // and 4s for timer 1, for a 25% duty cycle - timer0.start_counter(3_000_000); - timer1.start_counter(3_000_000); - gpio.pc_dat.write(|w| unsafe { w.bits(2) }); + let thr_addr = unsafe { &*UART0::PTR }.thr() as *const _ as *mut (); + + for chunk in HOUND.lines() { + let d_cfg = DescriptorConfig { + source: chunk.as_ptr().cast(), + destination: thr_addr, + byte_counter: chunk.len(), + link: None, + wait_clock_cycles: 0, + bmode: BModeSel::Normal, + dest_width: DataWidth::Bit8, + dest_addr_mode: AddressMode::IoMode, + dest_block_size: BlockSize::Byte1, + dest_drq_type: DestDrqType::Uart0Tx, + src_data_width: DataWidth::Bit8, + src_addr_mode: AddressMode::LinearMode, + src_block_size: BlockSize::Byte1, + src_drq_type: SrcDrqType::Dram, + }; + let descriptor = d_cfg.try_into().unwrap(); + unsafe { + dmac.channels[0].set_channel_modes(ChannelMode::Wait, ChannelMode::Handshake); + dmac.channels[0].start_descriptor(NonNull::from(&descriptor)); + } + timer0.start_counter(1_500_000); unsafe { riscv::asm::wfi() }; - // while !timer0.get_and_clear_interrupt() { } - println!("T0 DONE"); - gpio.pc_dat.write(|w| unsafe { w.bits(0) }); - unsafe { riscv::asm::wfi() }; - println!("T1 DONE"); + println!(""); + + unsafe { + dmac.channels[0].stop_dma(); + } } + panic!(); } #[export_name = "MachineExternal"] fn im_an_interrupt() { let plic = unsafe { Plic::summon() }; let timer = unsafe { &*TIMER::PTR }; + let uart0 = unsafe { &*UART0::PTR }; let claim = plic.claim(); - println!("claim: {:?}", claim); + // println!("claim: {}", claim.bits()); match claim { Interrupt::TIMER0 => { @@ -149,6 +226,16 @@ fn im_an_interrupt() { // Wait for the interrupt to clear to avoid repeat interrupts while timer.tmr_irq_sta.read().tmr1_irq_pend().bit_is_set() {} } + Interrupt::UART0 => { + println!(""); + println!("UART SAYS: "); + while uart0.usr.read().rfne().bit_is_set() { + let byte = uart0.rbr().read().rbr().bits(); + uart0.thr().write(|w| unsafe { w.thr().bits(byte) }); + while uart0.usr.read().tfnf().bit_is_clear() {} + } + println!(""); + } x => { println!("Unexpected claim: {:?}", x); panic!(); @@ -158,3 +245,8 @@ fn im_an_interrupt() { // Release claim plic.complete(claim); } + +// Main config register: +// DMAC_CFG_REGN +// Mode: +// DMAC_MODE_REGN