diff --git a/firmware/src/eth.rs b/firmware/src/eth.rs index e972ccc..292eef1 100644 --- a/firmware/src/eth.rs +++ b/firmware/src/eth.rs @@ -14,30 +14,22 @@ // - Slots are sized to ethernet MTU (1530), and addressed by the closest log2 // thing, so 2048 bytes each -const LITEETH_BASE: u32 = 0x0300_0000; - -const CTRL_RESET: u32 = 0x000; -const CTRL_SCRATCH: u32 = 0x004; - // Writer, or RX register blocks -const ETHMAC_SRAM_WRITER_SLOT: u32 = 0x800; -const ETHMAC_SRAM_WRITER_LENGTH: u32 = 0x804; -const ETHMAC_SRAM_WRITER_EV_STATUS: u32 = 0x80c; -const ETHMAC_SRAM_WRITER_EV_PENDING: u32 = 0x810; -const ETHMAC_SRAM_WRITER_EV_ENABLE: u32 = 0x814; +const ETHMAC_SRAM_WRITER_SLOT: u32 = 0x000; +const ETHMAC_SRAM_WRITER_LENGTH: u32 = 0x004; +const ETHMAC_SRAM_WRITER_EV_STATUS: u32 = 0x00c; +const ETHMAC_SRAM_WRITER_EV_PENDING: u32 = 0x010; +const ETHMAC_SRAM_WRITER_EV_ENABLE: u32 = 0x014; // Reader, or TX register blocks -const ETHMAC_SRAM_READER_START: u32 = 0x818; -const ETHMAC_SRAM_READER_READY: u32 = 0x81c; -const ETHMAC_SRAM_READER_LEVEL: u32 = 0x820; -const ETHMAC_SRAM_READER_SLOT: u32 = 0x824; -const ETHMAC_SRAM_READER_LENGTH: u32 = 0x828; -const ETHMAC_SRAM_READER_EV_STATUS: u32 = 0x82c; -const ETHMAC_SRAM_READER_EV_PENDING: u32 = 0x830; -const ETHMAC_SRAM_READER_EV_ENABLE: u32 = 0x834; - -// Offset of ETHMAC SRAM from base -const ETHMAC_OFFSET: u32 = 0x0002_0000; +const ETHMAC_SRAM_READER_START: u32 = 0x018; +const ETHMAC_SRAM_READER_READY: u32 = 0x01c; +const ETHMAC_SRAM_READER_LEVEL: u32 = 0x020; +const ETHMAC_SRAM_READER_SLOT: u32 = 0x024; +const ETHMAC_SRAM_READER_LENGTH: u32 = 0x028; +const ETHMAC_SRAM_READER_EV_STATUS: u32 = 0x02c; +const ETHMAC_SRAM_READER_EV_PENDING: u32 = 0x030; +const ETHMAC_SRAM_READER_EV_ENABLE: u32 = 0x014; const NUM_RX_SLOTS: u32 = 2; const NUM_TX_SLOTS: u32 = 2; @@ -69,15 +61,6 @@ impl LiteEthDevice { /// Initialises the device and returns an instance. Unsafe because there are /// no checks for other users. pub unsafe fn try_init(csr_addr: u32, ethmac_addr: u32) -> Option { - if !LiteEthDevice::check_wishbone_access(csr_addr) { - return None; - } - // Reset liteeth - write_reg(csr_addr + CTRL_RESET, 1u32); - busy_wait(200); - write_reg(csr_addr + CTRL_RESET, 0u32); - busy_wait(200); - // Clear RX event to mark the slot as available write_reg(csr_addr + ETHMAC_SRAM_WRITER_EV_PENDING, 1u32); @@ -91,15 +74,6 @@ impl LiteEthDevice { // Return a new device Some(Self { csr_addr, ethmac_addr }) } - - /// Checks that wishbone memory access is correct for the given base address - unsafe fn check_wishbone_access(csr_addr: u32) -> bool { - // Read scratch register, which resets to 0x12345678 - let value: u32 = read_reg(csr_addr + CTRL_SCRATCH); - - // If this isn't true, we screwed. - return value == 0x12345678; - } } impl smoltcp::phy::Device for LiteEthDevice { diff --git a/firmware/src/litex_uart.rs b/firmware/src/litex_uart.rs new file mode 100644 index 0000000..6596454 --- /dev/null +++ b/firmware/src/litex_uart.rs @@ -0,0 +1,45 @@ +//! Quick and dirty LiteX uart drier + + +const REG_RXTX: u32 = 0; +const REG_TXFULL: u32 = 0x4; +//const REG_RXEMPTY: u32 = 0x8; + +use crate::{write_reg, read_reg}; +use core::fmt::Write; + +pub enum Error { + TxFull, + RxEmpty, +} + +pub struct LiteXUart { + base_addr: u32, +} + +impl LiteXUart { + pub fn new(base_addr: u32) -> Self{ Self {base_addr} } + + pub fn try_put_char(&mut self, c: u8) -> Result<(), Error> { + unsafe { + if read_reg::(self.base_addr + REG_TXFULL) != 0 { + return Err(Error::TxFull); + } + + write_reg::(self.base_addr + REG_RXTX, c as u32); + Ok(()) + } + } +} + +impl Write for LiteXUart { + fn write_str(&mut self, s: &str) -> core::fmt::Result { + for b in s.as_bytes() { + // It's okay to loop on this because we'll always clear the buffer + while let Err(Error::TxFull) = self.try_put_char(*b) {} + //self.try_put_char(*b); + } + + Ok(()) + } +} diff --git a/firmware/src/logging.rs b/firmware/src/logging.rs index 940fd4e..e7f33ec 100644 --- a/firmware/src/logging.rs +++ b/firmware/src/logging.rs @@ -22,17 +22,17 @@ unsafe impl defmt::Logger for DefmtLogger { } unsafe fn write(bytes: &[u8]) { - static mut UART: Option = None; - if UART.is_none() { - UART = Some(AmlibUart::new(0x0200_0040)); - } + //static mut UART: Option = None; + //if UART.is_none() { + // UART = Some(AmlibUart::new(0x0200_0040)); + //} - let mut dev = UART.unwrap(); - //writeln!(dev, "a").unwrap(); - //writeln!(dev, "length: {}", bytes.len()); - for byte in bytes { - while let Err(_) = dev.try_put_char(*byte) {} - } + //let mut dev = UART.unwrap(); + ////writeln!(dev, "a").unwrap(); + ////writeln!(dev, "length: {}", bytes.len()); + //for byte in bytes { + // while let Err(_) = dev.try_put_char(*byte) {} + //} } } diff --git a/firmware/src/main.rs b/firmware/src/main.rs index 3fd521a..e05cb28 100644 --- a/firmware/src/main.rs +++ b/firmware/src/main.rs @@ -26,10 +26,30 @@ mod eth; mod i2c; mod mcp4726; mod uart; +mod litex_uart; mod logging; const MAC: [u8; 6] = [0xA0, 0xBB, 0xCC, 0xDD, 0xEE, 0xF0]; +static mut SECONDS: u32 = 0; + +/// External interrupt handler +#[export_name = "MachineExternal"] +fn external_interrupt_handler() { + let cause = riscv::register::mcause::read(); + let mut uart = litex_uart::LiteXUart::new(0xf000_4000); + writeln!(uart, "mcause: {}", cause.bits()); + + if (cause.is_interrupt()) { + let mut uart = litex_uart::LiteXUart::new(0xf000_4000); + writeln!(uart, "mcause: {}", cause.code()); + + if cause.code() == 1 { + // TIMER0 event, we have reset so count another second + } + } +} + // use `main` as the entry point of this application // `main` is not allowed to return #[entry] @@ -44,9 +64,13 @@ fn main() -> ! { // } //}; let blink_period = 10_000_000u32; - let mut uart = uart::AmlibUart::new(0x0200_0040); + let mut uart = litex_uart::LiteXUart::new(0xf000_4000); + writeln!(uart, "uart init"); - let mut device = unsafe { eth::LiteEthDevice::try_init(0x0300_0000).unwrap() }; + // enable timer + + let mut device = unsafe { eth::LiteEthDevice::try_init(0xf000_0800, 0x8000_0000).unwrap() }; + writeln!(uart, "eth init"); use smoltcp::wire::{EthernetAddress, HardwareAddress}; let mut config = smoltcp::iface::Config::default(); @@ -74,7 +98,25 @@ fn main() -> ! { let mut last_blink: u32 = 0; let mut toggle = false; - defmt::info!("Done setup"); + //defmt::info!("Done setup"); + + unsafe { + //riscv::interrupt::enable(); + //riscv::register::mie::set_mext(); + //riscv::register::mie::set_msoft(); + + // Enable UART rx event for test + //write_reg(0xf000_4014, 1u32); + + // Timer stuff + write_reg(0xf000_3808, 0u32); // Disable timer + write_reg(0xf000_3800, 0u32); // Set LOAD value + write_reg(0xf000_3804, 60_000_000u32); // Set RELOAD value + write_reg(0xf000_3808, 1u32); // Enable timer + + // Enable timer event + //write_reg(0xf000_381c, 1u32); + } loop { let now = millis(); @@ -82,26 +124,47 @@ fn main() -> ! { last_blink = now; toggle = !toggle; write_led(if toggle { 1 } else { 0 }); + + let val: u32 = unsafe {read_reg(0x8000_2000)}; + writeln!(uart, "Sampler value: 0x{:08x}", val).unwrap(); } if iface.poll(Instant::from_millis(now), &mut device, &mut socket_set) { - //writeln!(uart, "iface did something"); } + + handle_timer_event(); } } -fn busy_wait(ms: u32) { - let start = millis(); - while millis() - start < ms { - unsafe { - asm!("nop"); +fn handle_timer_event() { + unsafe { + if read_reg::(0xf000_3818) == 0 { + return; } + + // Clear TIMER0 event status, and update time + write_reg(0xf000_3818, 1u32); + SECONDS += 1; + } + +} + +fn busy_wait(ms: u32) { + //let start = millis(); + //while millis() - start < ms { + // unsafe { + // asm!("nop"); + // } + //} + + for i in 0..ms*20_000 { + unsafe {asm!("nop");} } } fn write_led(val: u32) { unsafe { - write_reg(0x01200000, val); + write_reg(0xf000_2000, val); } } @@ -114,5 +177,14 @@ unsafe fn read_reg(addr: u32) -> T { } fn millis() -> u32 { - unsafe { read_reg(0x01300000) } + riscv::interrupt::free(|| { + unsafe { + // Latch timer value + write_reg(0xf000_380c, 1u32); + // Read timer value + let val: u32 = read_reg(0xf000_3810); + let val = 60_000_000 - val; + (SECONDS * 1000) + val / 60_000 + } + }) }