aboutsummaryrefslogtreecommitdiffstats
path: root/src-riscv
diff options
context:
space:
mode:
Diffstat (limited to 'src-riscv')
l---------src-riscv/.#main.rs1
-rw-r--r--src-riscv/blink.rs70
-rw-r--r--src-riscv/boot.S11
-rw-r--r--src-riscv/led.rs42
-rw-r--r--src-riscv/log.rs36
-rwxr-xr-xsrc-riscv/main.rs215
-rwxr-xr-xsrc-riscv/usb.rs42
7 files changed, 417 insertions, 0 deletions
diff --git a/src-riscv/.#main.rs b/src-riscv/.#main.rs
new file mode 120000
index 0000000..988fc15
--- /dev/null
+++ b/src-riscv/.#main.rs
@@ -0,0 +1 @@
+bjc@ditto.691749627316654132 \ No newline at end of file
diff --git a/src-riscv/blink.rs b/src-riscv/blink.rs
new file mode 100644
index 0000000..967cde6
--- /dev/null
+++ b/src-riscv/blink.rs
@@ -0,0 +1,70 @@
+use core::convert::Infallible;
+
+// use gd32vf103xx_hal as hal;
+use stm32f30x_hal as hal;
+
+use hal::{
+ //eclic::{self, EclicExt},
+ pac::{self, Interrupt},
+ prelude::*,
+ time::Hertz,
+ timer::{Event, Timer},
+};
+use nb;
+use riscv::interrupt;
+
+use crate::led::LED;
+
+pub struct Task {
+ timer: Timer<pac::TIMER6>,
+ frequency: Hertz,
+ led: LED,
+}
+
+static mut TIMER_FIRED: bool = false;
+
+impl Task {
+ pub fn new(mut timer: Timer<pac::TIMER6>, frequency: Hertz, led: LED) -> Self {
+ // pac::ECLIC::setup(Interrupt::TIMER6, eclic::TriggerType::RisingEdge, eclic::Level::L0, eclic::Priority::P3);
+ // unsafe { pac::ECLIC::unmask(Interrupt::TIMER6); }
+ // assert!(pac::ECLIC::is_enabled(Interrupt::TIMER6));
+ timer.listen(Event::Update);
+
+ Self { timer, frequency, led }
+ }
+
+ pub fn poll(&mut self) -> nb::Result<(), Infallible> {
+ interrupt::free(|_cs| {
+ if unsafe { TIMER_FIRED } {
+ unsafe { TIMER_FIRED = false };
+ self.led.toggle();
+ self.timer.start(self.frequency);
+ }
+ });
+ Err(nb::Error::WouldBlock)
+ }
+}
+
+/*
+ * because i'm using ‘wfi’ to sleep as much as possible, i need to
+ * actually schedule the timer to fire an interrupt. that, in turn,
+ * requires a handler.
+ *
+ * why? because, for efficiency reasons, ‘_irq_handler’ uses the
+ * bumblebee core ‘jalmnxti’ csr, and the default entry in the irq
+ * vector is ‘0’. so the core jumps to 0, which is the ‘_start’ entry
+ * point. but it does this *from the interrupt*, which masks the
+ * interrupt (because it's currently being serviced), so any
+ * subsequent firings are never triggered, nor any interrupts at lower
+ * priority.
+ *
+ * so it looks like the core resets every other time it's
+ * started. adding a real isr avoids these problems.
+ */
+#[export_name="TIMER6"]
+fn timer6() {
+ // logln!("I timer6 I");
+ let regs = unsafe { &*pac::TIMER6::ptr() };
+ regs.intf.write(|w| w.upif().clear_bit());
+ unsafe { TIMER_FIRED = true };
+}
diff --git a/src-riscv/boot.S b/src-riscv/boot.S
new file mode 100644
index 0000000..d31e5fe
--- /dev/null
+++ b/src-riscv/boot.S
@@ -0,0 +1,11 @@
+ .global _start
+ .section .text.init
+_start:
+ .option push
+ .option norelax
+ la gp, __global_pointer$
+ .option pop
+ la sp, _stack_top
+
+ csrr a0, mhartid
+ tail main
diff --git a/src-riscv/led.rs b/src-riscv/led.rs
new file mode 100644
index 0000000..536121b
--- /dev/null
+++ b/src-riscv/led.rs
@@ -0,0 +1,42 @@
+use gd32vf103xx_hal::{
+ gpio::{Floating, Input, Output, PushPull, Pxx, State, gpioa::PA7},
+};
+use embedded_hal::digital::v2::OutputPin;
+
+pub struct LED {
+ pin: Pxx<Output<PushPull>>,
+ state: State,
+}
+
+impl LED {
+ pub fn new(pin: PA7<Input<Floating>>) -> Self {
+ let mut p = pin.into_push_pull_output().downgrade();
+ p.set_low().ok();
+ Self { pin: p, state: State::Low }
+ }
+
+ pub fn is_on(&self) -> bool {
+ match self.state {
+ State::High => true,
+ State::Low => false,
+ }
+ }
+
+ pub fn on(&mut self) {
+ self.state = State::High;
+ self.pin.set_high().ok();
+ }
+
+ pub fn off(&mut self) {
+ self.state = State::Low;
+ self.pin.set_low().ok();
+ }
+
+ pub fn toggle(&mut self) {
+ if self.is_on() {
+ self.off();
+ } else {
+ self.on();
+ }
+ }
+}
diff --git a/src-riscv/log.rs b/src-riscv/log.rs
new file mode 100644
index 0000000..ddb6792
--- /dev/null
+++ b/src-riscv/log.rs
@@ -0,0 +1,36 @@
+use core::fmt::{write, Arguments};
+
+use gd32vf103xx_hal::{
+ serial::Tx,
+ pac::USART1,
+};
+use riscv::interrupt::{self, Mutex};
+
+#[macro_export]
+macro_rules! log {
+ ($($args:tt)+) => {
+ $crate::log::log_args(core::format_args!($($args)+))
+ }
+}
+
+#[macro_export]
+macro_rules! logln {
+ () => ({ kprint!("\r\n") });
+ ($fmt: literal $(, $($arg: tt)+)?) => {
+ log!(concat!($fmt, "\n") $(, $($arg)+)?)
+ }
+}
+
+static mut TX: Mutex<Option<Tx<USART1>>> = Mutex::new(None);
+
+pub fn init(tx: Tx<USART1>) {
+ interrupt::free(|_cs| {
+ unsafe { TX.get_mut().insert(tx) };
+ });
+}
+
+pub fn log_args(args: Arguments) {
+ interrupt::free(|_cs| {
+ unsafe { TX.get_mut().as_mut().map(|tx| write(tx, args)) };
+ });
+}
diff --git a/src-riscv/main.rs b/src-riscv/main.rs
new file mode 100755
index 0000000..68fa8da
--- /dev/null
+++ b/src-riscv/main.rs
@@ -0,0 +1,215 @@
+#![no_std]
+#![no_main]
+
+mod blink;
+mod led;
+mod log;
+mod usb;
+
+// use gd32vf103xx_hal as hal;
+use stm32f30x_hal as hal;
+
+use hal::{
+ afio::AfioExt,
+ eclic::{self, EclicExt},
+ gpio::GpioExt,
+ pac::{self, Peripherals},
+ rcu::RcuExt,
+ serial::Serial,
+ time::{Hertz, MegaHertz},
+ timer::Timer,
+};
+use riscv::{
+ asm::wfi,
+ interrupt,
+};
+use riscv_rt::entry;
+use usb_device::prelude::*;
+
+use led::LED;
+use usb::{USB, UsbBus};
+
+static mut EP_MEMORY: [u32; 1024] = [0; 1024];
+
+#[entry]
+fn main(_hartid: usize) -> ! {
+ let p = Peripherals::take().expect("couldn't take peripherals");
+
+ pac::ECLIC::reset();
+ pac::ECLIC::set_threshold_level(eclic::Level::L0);
+ pac::ECLIC::set_level_priority_bits(eclic::LevelPriorityBits::L3P1);
+
+ let mut rcu = p.RCU
+ .configure()
+ .ext_hf_clock(MegaHertz(8))
+ .sysclk(MegaHertz(96))
+ .freeze();
+ let mut afio = p.AFIO.constrain(&mut rcu);
+ let gpioa = p.GPIOA.split(&mut rcu);
+
+ // TODO: figure out how to use the usb serial on the start board.
+ //
+ // this version has to be wired up physically.
+ let serial = Serial::new(
+ p.USART1,
+ (gpioa.pa2, gpioa.pa3),
+ Default::default(),
+ &mut afio,
+ &mut rcu,
+ );
+ let (tx, _rx) = serial.split();
+ log::init(tx);
+ logln!("luchie starting");
+
+ let timer = Timer::<pac::TIMER6>::timer6(p.TIMER6, Hertz(5), &mut rcu);
+ let led = LED::new(gpioa.pa7);
+ let mut blink = blink::Task::new(timer, Hertz(5), led);
+
+ let usb = USB {
+ usb_global: p.USBFS_GLOBAL,
+ usb_device: p.USBFS_DEVICE,
+ usb_pwrclk: p.USBFS_PWRCLK,
+ pin_dm: gpioa.pa11,
+ pin_dp: gpioa.pa12,
+ hclk: rcu.clocks.hclk()
+ };
+ logln!("hclk: {:?}", rcu.clocks.hclk().0);
+
+ let usb_bus = UsbBus::new(usb, unsafe { &mut EP_MEMORY });
+
+ let mut usb_dev = UsbDeviceBuilder::new(&usb_bus, UsbVidPid(0x16c0, 0x27dd))
+ .manufacturer("Fake company")
+ .product("Enumeration test")
+ .serial_number("TEST")
+ .device_class(0)
+ .build();
+
+ //let mut serial = SerialPort::new(&bus_alloc);
+
+ unsafe { interrupt::enable() };
+
+ loop {
+ let mut can_sleep = true;
+
+ if let Ok(_) = blink.poll() {
+ can_sleep = false;
+ }
+ if usb_dev.poll(&mut []) {
+ logln!("usb");
+ can_sleep = false;
+ }
+
+ if can_sleep && false {
+ log!("!");
+ unsafe { wfi() };
+ }
+ }
+}
+#[export_name="ExceptionHandler"]
+fn exception_handler(_frame: &riscv_rt::TrapFrame) -> ! {
+ spin();
+}
+
+#[export_name="DefaultHandler"]
+fn default_handler() -> ! {
+ spin();
+}
+
+#[export_name="MachineTimer"]
+fn machine_timer() {
+ spin();
+}
+
+#[panic_handler]
+fn panic(info: &core::panic::PanicInfo) -> ! {
+ interrupt::free(|_cs| {
+ log!("!!! panic ");
+ if let Some(loc) = info.location() {
+ log!("in {}:{} ", loc.file(), loc.line());
+ }
+ if let Some(msg) = info.payload().downcast_ref::<&str>() {
+ log!("⇒ {} ", msg);
+ }
+ logln!("!!!");
+ });
+ spin();
+}
+
+fn spin() -> ! {
+ loop { unsafe { wfi() } };
+}
+
+/*
+#![no_std]
+#![no_main]
+
+mod usb;
+
+use riscv::asm::wfi;
+use riscv_rt::entry;
+use gd32vf103xx_hal::prelude::*;
+use gd32vf103xx_hal::pac;
+
+use usb::{USB, UsbBus};
+use usb_device::prelude::*;
+use usbd_serial::SerialPort;
+
+static mut EP_MEMORY: [u32; 1024] = [0; 1024];
+
+#[entry]
+fn main() -> ! {
+ let dp = pac::Peripherals::take().unwrap();
+
+ // Configure clocks
+ let mut rcu = dp.RCU.configure()
+ .ext_hf_clock(8.mhz())
+ .sysclk(96.mhz())
+ .freeze();
+
+ assert!(rcu.clocks.usbclk_valid());
+
+ let gpioa = dp.GPIOA.split(&mut rcu);
+ let usb = USB {
+ usb_global: dp.USBFS_GLOBAL,
+ usb_device: dp.USBFS_DEVICE,
+ usb_pwrclk: dp.USBFS_PWRCLK,
+ pin_dm: gpioa.pa11,
+ pin_dp: gpioa.pa12,
+ hclk: rcu.clocks.hclk()
+ };
+
+ let usb_bus = UsbBus::new(usb, unsafe { &mut EP_MEMORY });
+
+ let mut serial = SerialPort::new(&usb_bus);
+ let mut usb_dev = UsbDeviceBuilder::new(&usb_bus, UsbVidPid(0x16c0, 0x27dd))
+ .manufacturer("Fake company")
+ .product("Enumeration test")
+ .serial_number("TEST")
+ .device_class(0)
+ .build();
+
+ loop {
+ if usb_dev.poll(&mut [&mut serial]) {
+ }
+ }
+}
+
+#[panic_handler]
+fn panic(info: &core::panic::PanicInfo) -> ! {
+// interrupt::free(|_cs| {
+// log!("!!! panic ");
+ if let Some(loc) = info.location() {
+// log!("in {}:{} ", loc.file(), loc.line());
+ }
+ if let Some(msg) = info.payload().downcast_ref::<&str>() {
+// log!("⇒ {} ", msg);
+ }
+// logln!("!!!");
+// });
+ spin();
+}
+
+fn spin() -> ! {
+ loop { unsafe { wfi() } };
+}
+*/
diff --git a/src-riscv/usb.rs b/src-riscv/usb.rs
new file mode 100755
index 0000000..1ec36af
--- /dev/null
+++ b/src-riscv/usb.rs
@@ -0,0 +1,42 @@
+use gd32vf103xx_hal::pac;
+use gd32vf103xx_hal::gpio::{Input, Floating, gpioa::{PA11, PA12}};
+use gd32vf103xx_hal::time::Hertz;
+pub use synopsys_usb_otg::UsbBus;
+use synopsys_usb_otg::UsbPeripheral;
+
+#[allow(dead_code)]
+pub struct USB {
+ pub usb_global: pac::USBFS_GLOBAL,
+ pub usb_device: pac::USBFS_DEVICE,
+ pub usb_pwrclk: pac::USBFS_PWRCLK,
+ pub pin_dm: PA11<Input<Floating>>,
+ pub pin_dp: PA12<Input<Floating>>,
+ pub hclk: Hertz,
+}
+
+unsafe impl Sync for USB {}
+
+unsafe impl UsbPeripheral for USB {
+ const REGISTERS: *const () = pac::USBFS_GLOBAL::ptr() as *const ();
+
+ const HIGH_SPEED: bool = false;
+ const FIFO_DEPTH_WORDS: usize = 320;
+ const ENDPOINT_COUNT: usize = 4;
+
+ fn enable() {
+ let rcu = unsafe { &*pac::RCU::ptr() };
+
+ riscv::interrupt::free(|_| {
+ // Enable USB peripheral
+ rcu.ahben.modify(|_, w| w.usbfsen().set_bit());
+
+ // Reset USB peripheral
+ rcu.ahbrst.modify(|_, w| w.usbfsrst().set_bit());
+ rcu.ahbrst.modify(|_, w| w.usbfsrst().clear_bit());
+ });
+ }
+
+ fn ahb_frequency_hz(&self) -> u32 {
+ self.hclk.0
+ }
+}