Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[feature request] add Rust support #837

Open
Chris44442 opened this issue Mar 1, 2024 · 4 comments
Open

[feature request] add Rust support #837

Chris44442 opened this issue Mar 1, 2024 · 4 comments
Labels
enhancement New feature or request help wanted Extra attention is needed SW software-related

Comments

@Chris44442
Copy link

Recently I have tried converting a Rust elf binary to the neorv32_application_image.vhd, by making a minor hack to the common.mk file. To my surprise it worked pretty much right away. My Rust program was very simple, essentially I only wrote to a couple of physical addresses (GPIOs) in order to toggle the LEDs on my board. But even calculating some trigonometric floating point stuff worked! But as soon as I added things like loops and more complex stuff, it didn't work anymore. My guess is that the instructions in the neorv32_application_image.vhd were not valid for some reason. I haven't tried using the bootloader yet due to my hardware setup.

Anyway this got my hopes up, that we may have Rust support in the future in some way?

@Chris44442 Chris44442 changed the title add Rust support [Feature Request] Add Rust support Mar 1, 2024
@Chris44442 Chris44442 changed the title [Feature Request] Add Rust support [feature request] add Rust support Mar 1, 2024
@stnolting stnolting added enhancement New feature or request help wanted Extra attention is needed SW software-related labels Mar 4, 2024
@stnolting
Copy link
Owner

Hey @Chris44442!

That's an interesting idea! I've never worked with Rust before, but I see it being adopted more and more - even in tiny embedded systems (which have a focus on security).

So, yes, I would love to see this project support Rust. Unfortunately, I'm far too inexperienced to tackle it.

To my surprise it worked pretty much right away. My Rust program was very simple, essentially I only wrote to a couple of physical addresses (GPIOs) in order to toggle the LEDs on my board.

That sounds great! Could you make the sources available some where? Maybe that would be a good starting point.

@umarcor
Copy link
Collaborator

umarcor commented Mar 4, 2024

My guess is that the instructions in the neorv32_application_image.vhd were not valid for some reason.

Several CPU extensions are disabled by default: https://github.com/stnolting/neorv32/blob/main/rtl/core/neorv32_top.vhd#L59-L71. You might try enabling them all.

Alternatively, when compiling your Rust program, you might try checking how to specify -march to avoid the compiler generating instructions which are not supported by the hardware.

@Chris44442
Copy link
Author

This is my main.rs

#![no_std]
#![no_main]

use core::panic::PanicInfo;
const GPIO_BASE: usize = 0xffff_fc08;

#[no_mangle]
pub extern "C" fn _start() -> ! {
    let gpio_output_val = GPIO_BASE as *mut u32;
    let mut result: u32 = 0;
    unsafe {gpio_output_val.write_volatile(result);}
    result = result + 5;
    unsafe {gpio_output_val.write_volatile(result);}
    result = 3 * result;
    unsafe {gpio_output_val.write_volatile(result);}
    result = result - 2;
    unsafe {gpio_output_val.write_volatile(result);}
    if result == 1 {
        unsafe {gpio_output_val.write_volatile(0x0000_0001);}
    }
    else if result == 13 {
        unsafe {gpio_output_val.write_volatile(0x0000_3333);}
    }
    else {
        unsafe {gpio_output_val.write_volatile(0x0000_0010);}
    }
    loop {}
}

#[panic_handler]
fn panic (_info: &PanicInfo) -> ! {
    loop {}
}

and my Cargo.toml

[package]
name = "neorv32_rusty"
version = "0.1.0"
edition = "2021"

[dependencies]

[[bin]]
name = "neorv32_rusty"
test = false
bench = false

and my config.toml

[build]
target = "riscv32imc-unknown-none-elf"

*I have also tried riscv32i-unknown-none-elf as the target, but I haven't noticed a difference. So my guess is that the problem is not the rust compiler generating unsupported instructions, but something else.

my vhdl instantiation

neorv32_top_inst: entity work.neorv32_top
  generic map (
    -- General --
    CLOCK_FREQUENCY              => 50000000,   -- clock frequency of clk_i in Hz
    INT_BOOTLOADER_EN            => false,             -- boot configuration: true = boot explicit bootloader; false = boot from int/ext (I)MEM
    -- RISC-V CPU Extensions --
    CPU_EXTENSION_RISCV_C        => true,              -- implement compressed extension?
    CPU_EXTENSION_RISCV_M        => true,              -- implement mul/div extension?
    CPU_EXTENSION_RISCV_Zicntr   => true,              -- implement base counters?
    -- Internal Instruction memory --
    MEM_INT_IMEM_EN              => true,              -- implement processor-internal instruction memory
    MEM_INT_IMEM_SIZE            => 17*1024, -- size of processor-internal instruction memory in bytes
    -- Internal Data memory --
    MEM_INT_DMEM_EN              => true,              -- implement processor-internal data memory
    MEM_INT_DMEM_SIZE            => 8*1024, -- size of processor-internal data memory in bytes
    -- Processor peripherals --
    IO_GPIO_NUM                  => 8,                 -- number of GPIO input/output pairs (0..64)
    IO_MTIME_EN                  => true               -- implement machine system timer (MTIME)?
  )
  port map (
    -- Global control --
    clk_i  => FPGA_CLK1_50,     -- global clock, rising edge
    rstn_i => hps_fpga_reset_n,    -- global reset, low-active, async
    -- GPIO (available if IO_GPIO_NUM > 0) --
    gpio_o(0) => LED(0), -- parallel output
    gpio_o(1) => LED(1), -- parallel output
    gpio_o(2) => LED(2), -- parallel output
    gpio_o(3) => LED(3), -- parallel output
    gpio_o(4) => LED(4), -- parallel output
    gpio_o(5) => LED(5), -- parallel output
    gpio_o(6) => LED(6) -- parallel output
  );

To get it working I simply replace one of the main.elf files from the software examples with my compiled rust elf binary, comment out $(APP_ELF): $(OBJ) in the common.mk and run make image to get the neorv32_application_image.vhd

I have made a few more tests and right now my suspicion is that any loops results in jumps to the wrong address. One thing to note is that Rust elf files seem to look a bit different, if you inspect them with a hex editor compared to C elf files.

If statements seem to work, and I have also tested some u32 and f64 calulations which did seem to work. But, even the infinite loop at the end of the program can result in unexpected behavior. Maybe I will try to dig deeper in the next few days. But I have just started learning risc-v so my experience is limited.

@stnolting
Copy link
Owner

Unfortunately, I still haven't found the time to try it out myself. Anyway, thanks for sharing your code! Rust is definitely on my want-to-learn list 😉

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request help wanted Extra attention is needed SW software-related
Projects
None yet
Development

No branches or pull requests

3 participants