Skip to content

Commit

Permalink
Merge pull request #48 from Neotron-Compute/release/0.4.0
Browse files Browse the repository at this point in the history
Release 0.4.0
  • Loading branch information
thejpster committed Jun 25, 2023
2 parents 8bd0638 + 45c5f5a commit 362db34
Show file tree
Hide file tree
Showing 18 changed files with 782 additions and 171 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/rust.yml
Expand Up @@ -22,7 +22,7 @@ jobs:
rustup component add llvm-tools-preview
cargo install cargo-binutils
- name: Build
run: ./build.sh
run: ./build.sh --verbose
- name: Upload files to Release
if: github.event_name == 'push' && startswith(github.ref, 'refs/tags/')
uses: softprops/action-gh-release@v1
Expand Down
5 changes: 5 additions & 0 deletions CHANGELOG.md
Expand Up @@ -2,6 +2,11 @@

## Unreleased changes

## v0.4.0

* The `load` command now takes ELF binaries, not raw binaries.
* Neotron OS can now be used as a dependency within an application, if desired.

## v0.3.3

* Add `dir` command
Expand Down
32 changes: 31 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 10 additions & 2 deletions Cargo.toml
@@ -1,7 +1,10 @@
[package]
name = "neotron-os"
version = "0.3.3"
authors = ["Jonathan 'theJPster' Pallant <github@thejpster.org.uk>", "The Neotron Developers"]
version = "0.4.0"
authors = [
"Jonathan 'theJPster' Pallant <github@thejpster.org.uk>",
"The Neotron Developers"
]
edition = "2018"
description = "The Neotron Operating System"
license = "GPL-3.0-or-later"
Expand Down Expand Up @@ -46,3 +49,8 @@ serde = { version = "1.0", default-features = false }
menu = "0.3"
chrono = { version = "0.4", default-features = false }
embedded-sdmmc = { version = "0.5", default-features = false }
neotron-api = "0.1"
neotron-loader = "0.1"

[features]
lib-mode = []
4 changes: 2 additions & 2 deletions build.sh
Expand Up @@ -11,9 +11,9 @@ for TARGET_ARCH in thumbv6m-none-eabi thumbv7m-none-eabi thumbv7em-none-eabi; do
echo "TARGET is ${TARGET_ARCH}"
for BINARY in flash0002 flash0802 flash1002; do
echo "BINARY is ${BINARY}"
cargo build --verbose --release --target=${TARGET_ARCH} --bin ${BINARY}
cargo build $* --release --target=${TARGET_ARCH} --bin ${BINARY}
# objcopy would do the build for us first, but it doesn't have good build output
cargo objcopy --verbose --release --target=${TARGET_ARCH} --bin ${BINARY} -- -O binary ${RELEASE_DIR}/${TARGET_ARCH}-${BINARY}-libneotron_os.bin
cargo objcopy $* --release --target=${TARGET_ARCH} --bin ${BINARY} -- -O binary ${RELEASE_DIR}/${TARGET_ARCH}-${BINARY}-libneotron_os.bin
# Keep the ELF file too (for debugging)
cp ./target/${TARGET_ARCH}/release/${BINARY} ${RELEASE_DIR}/${TARGET_ARCH}-${BINARY}-libneotron_os.elf
done
Expand Down
6 changes: 5 additions & 1 deletion neotron-flash-0002.ld
Expand Up @@ -32,7 +32,11 @@ MEMORY

/* # Entry point = what the BIOS calls to start the OS */
ENTRY(main);
EXTERN(__RESET_VECTOR);

/*
Where the Transient Program Area starts.
*/
_tpa_start = ORIGIN(RAM) + LENGTH(RAM);

/* # Sections */
SECTIONS
Expand Down
6 changes: 5 additions & 1 deletion neotron-flash-0802.ld
Expand Up @@ -32,7 +32,11 @@ MEMORY

/* # Entry point = what the BIOS calls to start the OS */
ENTRY(main);
EXTERN(__RESET_VECTOR);

/*
Where the Transient Program Area starts.
*/
_tpa_start = ORIGIN(RAM) + LENGTH(RAM);

/* # Sections */
SECTIONS
Expand Down
14 changes: 11 additions & 3 deletions neotron-flash-1002.ld
Expand Up @@ -23,16 +23,24 @@ MEMORY
{
/* The first 128 KiB is for the BIOS. We get the rest. */
FLASH (rx) : ORIGIN = 0x10020000, LENGTH = 128K

/*
* We get the bottom 4KB of RAM. Anything above that is for applications
* (up to wherever the BIOS tells us we can use.)
* The RAM reserved for the OS. Above this is the Transient Program Area.
*
* This is defined by the Neotron specification for a given platform. On this
* Cortex-M based platform, it's the start of Cortex-M SRAM, plus 4 KiB, or
* 0x2000_1000.
*/
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 4K
}

/* # Entry point = what the BIOS calls to start the OS */
ENTRY(main);
EXTERN(__RESET_VECTOR);

/*
Where the Transient Program Area starts.
*/
_tpa_start = ORIGIN(RAM) + LENGTH(RAM);

/* # Sections */
SECTIONS
Expand Down
2 changes: 1 addition & 1 deletion src/bin/flash0002.rs
Expand Up @@ -13,4 +13,4 @@
/// of our portion of Flash.
#[link_section = ".entry_point"]
#[used]
pub static ENTRY_POINT_ADDR: extern "C" fn(*const neotron_common_bios::Api) -> ! = neotron_os::main;
pub static ENTRY_POINT_ADDR: extern "C" fn(&neotron_common_bios::Api) -> ! = neotron_os::os_main;
2 changes: 1 addition & 1 deletion src/bin/flash0802.rs
Expand Up @@ -13,4 +13,4 @@
/// of our portion of Flash.
#[link_section = ".entry_point"]
#[used]
pub static ENTRY_POINT_ADDR: extern "C" fn(*const neotron_common_bios::Api) -> ! = neotron_os::main;
pub static ENTRY_POINT_ADDR: extern "C" fn(&neotron_common_bios::Api) -> ! = neotron_os::os_main;
2 changes: 1 addition & 1 deletion src/bin/flash1002.rs
Expand Up @@ -13,4 +13,4 @@
/// of our portion of Flash.
#[link_section = ".entry_point"]
#[used]
pub static ENTRY_POINT_ADDR: extern "C" fn(*const neotron_common_bios::Api) -> ! = neotron_os::main;
pub static ENTRY_POINT_ADDR: extern "C" fn(&neotron_common_bios::Api) -> ! = neotron_os::os_main;
2 changes: 1 addition & 1 deletion src/commands/config.rs
Expand Up @@ -22,7 +22,7 @@ pub static COMMAND_ITEM: menu::Item<Ctx> = menu::Item {

/// Called when the "config" command is executed.
fn command(_menu: &menu::Menu<Ctx>, _item: &menu::Item<Ctx>, args: &[&str], ctx: &mut Ctx) {
let command = args.get(0).cloned().unwrap_or("print");
let command = args.first().cloned().unwrap_or("print");
match command {
"reset" => match config::Config::load() {
Ok(new_config) => {
Expand Down
118 changes: 9 additions & 109 deletions src/commands/fs.rs
@@ -1,9 +1,8 @@
//! File Systems related commands for Neotron OS

use chrono::{Datelike, Timelike};
use embedded_sdmmc::VolumeIdx;

use crate::{bios, print, println, Ctx, API};
use crate::{bios, print, println, Ctx};

pub static DIR_ITEM: menu::Item<Ctx> = menu::Item {
item_type: menu::ItemType::Callback {
Expand All @@ -14,7 +13,6 @@ pub static DIR_ITEM: menu::Item<Ctx> = menu::Item {
help: Some("Dir the root directory on block device 0"),
};

#[cfg(target_os = "none")]
pub static LOAD_ITEM: menu::Item<Ctx> = menu::Item {
item_type: menu::ItemType::Callback {
function: load,
Expand All @@ -27,89 +25,12 @@ pub static LOAD_ITEM: menu::Item<Ctx> = menu::Item {
help: Some("Load a file into the application area"),
};

struct BiosBlock();

impl embedded_sdmmc::BlockDevice for BiosBlock {
type Error = bios::Error;

fn read(
&self,
blocks: &mut [embedded_sdmmc::Block],
start_block_idx: embedded_sdmmc::BlockIdx,
_reason: &str,
) -> Result<(), Self::Error> {
let api = API.get();
let byte_slice = unsafe {
core::slice::from_raw_parts_mut(
blocks.as_mut_ptr() as *mut u8,
blocks.len() * embedded_sdmmc::Block::LEN,
)
};
match (api.block_read)(
0,
bios::block_dev::BlockIdx(u64::from(start_block_idx.0)),
blocks.len() as u8,
bios::ApiBuffer::new(byte_slice),
) {
bios::Result::Ok(_) => Ok(()),
bios::Result::Err(e) => Err(e),
}
}

fn write(
&self,
blocks: &[embedded_sdmmc::Block],
start_block_idx: embedded_sdmmc::BlockIdx,
) -> Result<(), Self::Error> {
let api = API.get();
let byte_slice = unsafe {
core::slice::from_raw_parts(
blocks.as_ptr() as *const u8,
blocks.len() * embedded_sdmmc::Block::LEN,
)
};
match (api.block_write)(
0,
bios::block_dev::BlockIdx(u64::from(start_block_idx.0)),
blocks.len() as u8,
bios::ApiByteSlice::new(byte_slice),
) {
bios::Result::Ok(_) => Ok(()),
bios::Result::Err(e) => Err(e),
}
}

fn num_blocks(&self) -> Result<embedded_sdmmc::BlockCount, Self::Error> {
let api = API.get();
match (api.block_dev_get_info)(0) {
bios::Option::Some(info) => Ok(embedded_sdmmc::BlockCount(info.num_blocks as u32)),
bios::Option::None => Err(bios::Error::InvalidDevice),
}
}
}

struct BiosTime();

impl embedded_sdmmc::TimeSource for BiosTime {
fn get_timestamp(&self) -> embedded_sdmmc::Timestamp {
let time = API.get_time();
embedded_sdmmc::Timestamp {
year_since_1970: (time.year() - 1970) as u8,
zero_indexed_month: time.month0() as u8,
zero_indexed_day: time.day0() as u8,
hours: time.hour() as u8,
minutes: time.minute() as u8,
seconds: time.second() as u8,
}
}
}

/// Called when the "dir" command is executed.
fn dir(_menu: &menu::Menu<Ctx>, _item: &menu::Item<Ctx>, _args: &[&str], _ctx: &mut Ctx) {
fn work() -> Result<(), embedded_sdmmc::Error<bios::Error>> {
println!("Listing files on Block Device 0, /");
let bios_block = BiosBlock();
let time = BiosTime();
let bios_block = crate::fs::BiosBlock();
let time = crate::fs::BiosTime();
let mut mgr = embedded_sdmmc::VolumeManager::new(bios_block, time);
// Open the first partition
let volume = mgr.get_volume(VolumeIdx(0))?;
Expand Down Expand Up @@ -165,33 +86,12 @@ fn dir(_menu: &menu::Menu<Ctx>, _item: &menu::Item<Ctx>, _args: &[&str], _ctx: &
}

/// Called when the "load" command is executed.
#[cfg(target_os = "none")]
fn load(_menu: &menu::Menu<Ctx>, _item: &menu::Item<Ctx>, args: &[&str], _ctx: &mut Ctx) {
fn work(args: &[&str]) -> Result<(), embedded_sdmmc::Error<bios::Error>> {
println!("Loading /{} from Block Device 0", args[0]);
let bios_block = BiosBlock();
let time = BiosTime();
let mut mgr = embedded_sdmmc::VolumeManager::new(bios_block, time);
// Open the first partition
let mut volume = mgr.get_volume(VolumeIdx(0))?;
let root_dir = mgr.open_root_dir(&volume)?;
let mut file = mgr.open_file_in_dir(
&mut volume,
&root_dir,
args[0],
embedded_sdmmc::Mode::ReadOnly,
)?;
let file_length = file.length();
// Application space starts 4K into Cortex-M SRAM
const APPLICATION_START_ADDR: usize = 0x2000_1000;
let application_ram: &'static mut [u8] = unsafe {
core::slice::from_raw_parts_mut(APPLICATION_START_ADDR as *mut u8, file_length as usize)
};
mgr.read(&mut volume, &mut file, application_ram)?;
Ok(())
}

match work(args) {
fn load(_menu: &menu::Menu<Ctx>, _item: &menu::Item<Ctx>, args: &[&str], ctx: &mut Ctx) {
let Some(filename) = args.first() else {
println!("Need a filename");
return;
};
match ctx.tpa.load_program(filename) {
Ok(_) => {}
Err(e) => {
println!("Error: {:?}", e);
Expand Down
3 changes: 1 addition & 2 deletions src/commands/mod.rs
Expand Up @@ -23,9 +23,8 @@ pub static OS_MENU: menu::Menu<Ctx> = menu::Menu {
&fs::DIR_ITEM,
&hardware::LSHW_ITEM,
&ram::HEXDUMP_ITEM,
#[cfg(target_os = "none")]
&ram::RUN_ITEM,
#[cfg(target_os = "none")]
&ram::LOAD_ITEM,
&fs::LOAD_ITEM,
&screen::CLEAR_ITEM,
&screen::BENCH_ITEM,
Expand Down

0 comments on commit 362db34

Please sign in to comment.