forked from M-Labs/zynq-rs
commit
9b414e2408
@ -0,0 +1,11 @@ |
||||
[target.armv7-unknown-linux-gnueabihf] |
||||
runner = "./runner.sh" |
||||
linker = "arm-none-eabihf-gcc" |
||||
rustflags = [ |
||||
"-C", "link-arg=-Wl,-Tlink.x", |
||||
"-C", "target-feature=a9,armv7-a,neon", |
||||
"-C", "target-cpu=cortex-a9", |
||||
] |
||||
|
||||
[build] |
||||
target = "armv7-unknown-linux-gnueabihf" |
@ -0,0 +1,46 @@ |
||||
# This file is automatically @generated by Cargo. |
||||
# It is not intended for manual editing. |
||||
[[package]] |
||||
name = "bit_field" |
||||
version = "0.10.0" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
|
||||
[[package]] |
||||
name = "panic-abort" |
||||
version = "0.3.1" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
|
||||
[[package]] |
||||
name = "r0" |
||||
version = "0.2.2" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
|
||||
[[package]] |
||||
name = "vcell" |
||||
version = "0.1.0" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
|
||||
[[package]] |
||||
name = "volatile-register" |
||||
version = "0.2.0" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
dependencies = [ |
||||
"vcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", |
||||
] |
||||
|
||||
[[package]] |
||||
name = "zc706" |
||||
version = "0.0.0" |
||||
dependencies = [ |
||||
"bit_field 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", |
||||
"panic-abort 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", |
||||
"r0 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", |
||||
"volatile-register 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", |
||||
] |
||||
|
||||
[metadata] |
||||
"checksum bit_field 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a165d606cf084741d4ac3a28fb6e9b1eb0bd31f6cd999098cfddb0b2ab381dc0" |
||||
"checksum panic-abort 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2c14a66511ed17b6a8b4256b868d7fd207836d891db15eea5195dbcaf87e630f" |
||||
"checksum r0 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2a38df5b15c8d5c7e8654189744d8e396bddc18ad48041a500ce52d6948941f" |
||||
"checksum vcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "45c297f0afb6928cd08ab1ff9d95e99392595ea25ae1b5ecf822ff8764e57a0d" |
||||
"checksum volatile-register 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0d67cb4616d99b940db1d6bd28844ff97108b498a6ca850e5b6191a532063286" |
@ -0,0 +1,19 @@ |
||||
[package] |
||||
name = "zc706" |
||||
version = "0.0.0" |
||||
authors = ["Astro <astro@spaceboyz.net>"] |
||||
edition = "2018" |
||||
|
||||
[profile.dev] |
||||
panic = "abort" |
||||
lto = false |
||||
[profile.release] |
||||
panic = "abort" |
||||
lto = false |
||||
debug = true |
||||
|
||||
[dependencies] |
||||
panic-abort = "0.3" |
||||
r0 = "0.2" |
||||
volatile-register = "0.2" |
||||
bit_field = "0.10" |
@ -0,0 +1,18 @@ |
||||
use std::env; |
||||
use std::fs::File; |
||||
use std::io::Write; |
||||
use std::path::PathBuf; |
||||
|
||||
fn main() { |
||||
// Put the linker script somewhere the linker can find it
|
||||
let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); |
||||
File::create(out.join("link.x")) |
||||
.unwrap() |
||||
.write_all(include_bytes!("link.x")) |
||||
.unwrap(); |
||||
println!("cargo:rustc-link-search={}", out.display()); |
||||
|
||||
// Only re-run the build script when memory.x is changed,
|
||||
// instead of when any part of the source code changes.
|
||||
println!("cargo:rerun-if-changed=link.x"); |
||||
} |
@ -0,0 +1,22 @@ |
||||
{ # Use master branch of the overlay by default |
||||
mozillaOverlay ? import (builtins.fetchTarball https://github.com/mozilla/nixpkgs-mozilla/archive/master.tar.gz), |
||||
rustSrc ? https://github.com/rustlang/rust/archive/master.tar.gz, |
||||
}: |
||||
|
||||
let |
||||
pkgs = import <nixpkgs> { overlays = [ mozillaOverlay ]; }; |
||||
in |
||||
with pkgs; |
||||
let |
||||
targets = [ |
||||
"armv7-unknown-linux-gnueabihf" |
||||
]; |
||||
rust = |
||||
rustChannelOfTargets "nightly" null targets; |
||||
rustPlatform = recurseIntoAttrs (makeRustPlatform { |
||||
rustc = rust // { src = rustSrc; }; |
||||
cargo = rust; |
||||
}); |
||||
in { |
||||
inherit pkgs rustPlatform; |
||||
} |
@ -0,0 +1,62 @@ |
||||
ENTRY(_boot_cores); |
||||
|
||||
/* SECTIONS */ |
||||
/* { */ |
||||
/* . = 0x8000; */ |
||||
|
||||
/* .text : */ |
||||
/* { */ |
||||
/* KEEP(*(.text.boot)) *(.text .text.*) */ |
||||
/* } */ |
||||
|
||||
/* /DISCARD/ : { *(.comment) *(.gnu*) *(.note*) *(.eh_frame*) } */ |
||||
/* } */ |
||||
|
||||
|
||||
SECTIONS |
||||
{ |
||||
/* Starts at LOADER_ADDR. */ |
||||
. = 0x8000; |
||||
__start = .; |
||||
__text_start = .; |
||||
.text : |
||||
{ |
||||
KEEP(*(.text.boot)) |
||||
*(.text) |
||||
} |
||||
. = ALIGN(4096); /* align to page size */ |
||||
__text_end = .; |
||||
|
||||
__rodata_start = .; |
||||
.rodata : |
||||
{ |
||||
*(.rodata) |
||||
} |
||||
. = ALIGN(4096); /* align to page size */ |
||||
__rodata_end = .; |
||||
|
||||
__data_start = .; |
||||
.data : |
||||
{ |
||||
*(.data) |
||||
} |
||||
. = ALIGN(4096); /* align to page size */ |
||||
__data_end = .; |
||||
|
||||
__bss_start = .; |
||||
.bss : |
||||
{ |
||||
bss = .; |
||||
*(.bss) |
||||
} |
||||
. = ALIGN(4096); /* align to page size */ |
||||
__bss_end = .; |
||||
__end = .; |
||||
|
||||
/DISCARD/ : |
||||
{ |
||||
/* Unused exception related info that only wastes space */ |
||||
*(.ARM.exidx.*); |
||||
*(.ARM.extab.*); |
||||
} |
||||
} |
@ -0,0 +1,6 @@ |
||||
target remote :1234 |
||||
|
||||
# print demangled symbols by default |
||||
set print asm-demangle on |
||||
|
||||
load |
@ -0,0 +1,11 @@ |
||||
#!/usr/bin/env bash |
||||
|
||||
set -e -m |
||||
|
||||
ELF=$1 |
||||
IMAGE=$ELF.bin |
||||
arm-none-eabihf-objcopy -O binary $ELF $IMAGE |
||||
qemu-system-arm -M xilinx-zynq-a9 -s -kernel $IMAGE -chardev file,id=uart0,path=/tmp/qemu.serial & |
||||
sleep 1 |
||||
gdb -x qemu.gdb $ELF |
||||
kill -KILL %1 |
@ -0,0 +1,24 @@ |
||||
let |
||||
mozillaOverlay = import (builtins.fetchTarball https://github.com/mozilla/nixpkgs-mozilla/archive/master.tar.gz); |
||||
pkgs = import <nixpkgs> { overlays = [ mozillaOverlay ]; }; |
||||
in |
||||
with pkgs; |
||||
let |
||||
project = callPackage ./default.nix {}; |
||||
in |
||||
with project; |
||||
stdenv.mkDerivation { |
||||
name = "adc2tcp-env"; |
||||
buildInputs = with rustPlatform.rust; [ |
||||
rustc cargo |
||||
pkgsCross.armhf-embedded.buildPackages.gcc |
||||
#pkgsCross.armv7l-hf-multiplatform.buildPackages.gcc |
||||
#pkgsCross.armhf-embedded.buildPackages.binutils |
||||
]; |
||||
|
||||
# Set Environment Variables |
||||
RUST_BACKTRACE = 1; |
||||
|
||||
shellHook = '' |
||||
''; |
||||
} |
@ -0,0 +1,11 @@ |
||||
/// The classic no-op
|
||||
#[inline] |
||||
pub fn nop() { |
||||
unsafe { asm!("nop" :::: "volatile") } |
||||
} |
||||
|
||||
/// Wait For Event
|
||||
#[inline] |
||||
pub fn wfe() { |
||||
unsafe { asm!("wfe" :::: "volatile") } |
||||
} |
@ -0,0 +1,2 @@ |
||||
pub mod asm; |
||||
pub mod regs; |
@ -0,0 +1,38 @@ |
||||
pub trait ReadableRegister<T> { |
||||
fn get(&self) -> T; |
||||
} |
||||
|
||||
macro_rules! def_reg_get { |
||||
($name:ty, $type:ty, $asm_instr:tt) => { |
||||
impl ReadableRegister<$type> for $name { |
||||
#[inline(always)] |
||||
fn get(&self) -> $type { |
||||
let mut value; |
||||
unsafe { asm!($asm_instr : "=r" (value) ::: "volatile") } |
||||
value |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
pub trait WritableRegister<T> { |
||||
fn set(&self, value: T); |
||||
} |
||||
|
||||
macro_rules! def_reg_set { |
||||
($name:ty, $type:ty, $asm_instr:tt) => { |
||||
impl WritableRegister<$type> for $name { |
||||
#[inline(always)] |
||||
fn set(&self, value: $type) { |
||||
unsafe { asm!($asm_instr :: "r" (value) :: "volatile") } |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
pub struct SP; |
||||
def_reg_get!(SP, u32, "mov $0, sp"); |
||||
def_reg_set!(SP, u32, "mov sp, $0"); |
||||
|
||||
pub struct MPIDR; |
||||
def_reg_get!(MPIDR, u32, "mrc p15, 0, $0, c0, c0, 5"); |
@ -0,0 +1,50 @@ |
||||
#![no_std] |
||||
#![no_main] |
||||
#![feature(asm)] |
||||
//[feature(global_asm)]
|
||||
#![feature(naked_functions)] |
||||
|
||||
use panic_abort as _; |
||||
use r0::zero_bss; |
||||
|
||||
mod cortex_a9; |
||||
mod slcr; |
||||
mod uart; |
||||
use uart::Uart; |
||||
|
||||
extern "C" { |
||||
static mut __bss_start: u32; |
||||
static mut __bss_end: u32; |
||||
static mut __end: u32; |
||||
} |
||||
|
||||
#[link_section = ".text.boot"] |
||||
#[no_mangle] |
||||
#[naked] |
||||
pub unsafe extern "C" fn _boot_cores() -> ! { |
||||
use cortex_a9::{asm, regs::*}; |
||||
|
||||
const CORE_MASK: u32 = 0x3; |
||||
// End of OCM RAM
|
||||
const STACK_START: u32 = 256 << 10; |
||||
|
||||
match MPIDR.get() & CORE_MASK { |
||||
0 => { |
||||
SP.set(STACK_START); |
||||
zero_bss(&mut __bss_start, &mut __bss_end); |
||||
main(); |
||||
panic!("return from main"); |
||||
} |
||||
_ => loop { |
||||
// if not core0, infinitely wait for events
|
||||
asm::wfe(); |
||||
}, |
||||
} |
||||
} |
||||
|
||||
fn main() { |
||||
let uart = Uart::uart0(); |
||||
for b in "Hello World\r\n".bytes() { |
||||
uart.write_byte(b); |
||||
} |
||||
} |
@ -0,0 +1,70 @@ |
||||
use core::ops::RangeInclusive; |
||||
use volatile_register::{RO, WO, RW}; |
||||
use bit_field::BitField; |
||||
|
||||
|
||||
#[repr(packed)] |
||||
pub struct UartClkCtrl { |
||||
pub reg: RW<u32>, |
||||
} |
||||
|
||||
impl UartClkCtrl { |
||||
const ADDR: *mut Self = 0xF8000154 as *mut _; |
||||
|
||||
pub fn new() -> &'static mut Self { |
||||
unsafe { &mut *Self::ADDR } |
||||
} |
||||
|
||||
const DIVISOR: RangeInclusive<usize> = 8..=13; |
||||
const CLKACT1: usize = 1; |
||||
const CLKACT0: usize = 0; |
||||
|
||||
pub fn enable_uart0(&self) { |
||||
unsafe { |
||||
self.reg.modify(|mut x| { |
||||
x.set_bits(Self::DIVISOR, 0x14); |
||||
x.set_bit(Self::CLKACT0, true); |
||||
x |
||||
}) |
||||
} |
||||
} |
||||
} |
||||
|
||||
#[repr(packed)] |
||||
pub struct UartRstCtrl { |
||||
pub reg: RW<u32>, |
||||
} |
||||
|
||||
impl UartRstCtrl { |
||||
const ADDR: *mut Self = 0xF8000228 as *mut _; |
||||
|
||||
pub fn new() -> &'static mut Self { |
||||
unsafe { &mut *Self::ADDR } |
||||
} |
||||
|
||||
const UART1_REF_RST: usize = 3; |
||||
const UART0_REF_RST: usize = 2; |
||||
const UART1_CPU1X_RST: usize = 1; |
||||
const UART0_CPU1X_RST: usize = 0; |
||||
|
||||
pub fn reset_uart0(&self) { |
||||
unsafe { toggle(&self.reg, Self::UART0_REF_RST); } |
||||
} |
||||
|
||||
pub fn reset_uart1(&self) { |
||||
unsafe { toggle(&self.reg, Self::UART1_REF_RST); } |
||||
} |
||||
} |
||||
|
||||
unsafe fn toggle<T: BitField + Copy>(reg: &RW<T>, bit: usize) { |
||||
reg.modify(|x| { |
||||
let mut x = x.clone(); |
||||
x.set_bit(bit, true); |
||||
x |
||||
}); |
||||
reg.modify(|x| { |
||||
let mut x = x.clone(); |
||||
x.set_bit(bit, false); |
||||
x |
||||
}); |
||||
} |
@ -0,0 +1,38 @@ |
||||
mod regs; |
||||
pub use regs::RegisterBlock; |
||||
|
||||
pub struct Uart { |
||||
regs: &'static mut RegisterBlock, |
||||
} |
||||
|
||||
impl Uart { |
||||
pub fn uart0() -> Self { |
||||
let uart_rst_ctrl = super::slcr::UartRstCtrl::new(); |
||||
uart_rst_ctrl.reset_uart0(); |
||||
// TODO: Route UART 0 RxD/TxD Signals to MIO Pins
|
||||
|
||||
// a. Clock divisor, slcr.UART_CLK_CTRL[DIVISOR] = 0x14.
|
||||
// b. Select the IO PLL, slcr.UART_CLK_CTRL[SRCSEL] = 0.
|
||||
// c. Enable the UART 0 Reference clock, slcr.UART_CLK_CTRL [CLKACT0] = 1.
|
||||
// d. Disable UART 1 Reference clock, slcr.UART_CLK_CTRL [CLKACT1] bit = 0.
|
||||
let uart_clk_ctrl = super::slcr::UartClkCtrl::new(); |
||||
uart_clk_ctrl.enable_uart0(); |
||||
|
||||
Uart { |
||||
regs: RegisterBlock::uart0(), |
||||
}.init() |
||||
} |
||||
|
||||
fn init(self) -> Self { |
||||
self.regs.configure(); |
||||
self |
||||
} |
||||
|
||||
pub fn write_byte(&self, v: u8) { |
||||
unsafe { |
||||
while self.regs.tx_fifo_full() {} |
||||
|
||||
self.regs.write_byte(v); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,125 @@ |
||||
use volatile_register::{RO, WO, RW}; |
||||
use bit_field::BitField; |
||||
|
||||
#[repr(packed)] |
||||
pub struct RegisterBlock { |
||||
pub control: RW<u32>, |
||||
pub mode: RW<u32>, |
||||
pub intrpt_en: RW<u32>, |
||||
pub intrpt_dis: RW<u32>, |
||||
pub intrpt_mask: RO<u32>, |
||||
pub chnl_int_sts: WO<u32>, |
||||
pub baud_rate_gen: RW<u32>, |
||||
pub rcvr_timeout: RW<u32>, |
||||
pub rcvr_fifo_trigger_level: RW<u32>, |
||||
pub modem_ctrl: RW<u32>, |
||||
pub modem_sts: RW<u32>, |
||||
pub channel_sts: RO<u32>, |
||||
pub tx_rx_fifo: RW<u32>, |
||||
pub baud_rate_divider: RW<u32>, |
||||
pub flow_delay: RW<u32>, |
||||
pub reserved0: RO<u32>, |
||||
pub reserved1: RO<u32>, |
||||
pub tx_fifo_trigger_level: RW<u32>, |
||||
} |
||||
|
||||
impl RegisterBlock { |
||||
const UART0: *mut Self = 0xE0000000 as *mut _; |
||||
const UART1: *mut Self = 0xE0001000 as *mut _; |
||||
|
||||
pub fn uart0() -> &'static mut Self { |
||||
unsafe { &mut *Self::UART0 } |
||||
} |
||||
|
||||
pub fn uart1() -> &'static mut Self { |
||||
unsafe { &mut *Self::UART1 } |
||||
} |
||||
|
||||
pub fn configure(&self) { |
||||
unsafe { |
||||
// Confiugre UART character frame
|
||||
// * Disable clock-divider
|
||||
// * 8-bit
|
||||
// * no parity
|
||||
// * 1 stop bit
|
||||
// * Normal channel mode
|
||||
self.mode.write(0x20); |
||||
|
||||
// Configure the Buad Rate
|
||||
self.disable_rx(); |
||||
self.disable_tx(); |
||||
|
||||
// 9,600 baud
|
||||
self.baud_rate_gen.write(651); |
||||
self.baud_rate_divider.write(7); |
||||
|
||||
self.reset_rx(); |
||||
self.reset_tx(); |
||||
self.enable_rx(); |
||||
self.enable_tx(); |
||||
} |
||||
} |
||||
|
||||
pub unsafe fn write_byte(&self, value: u8) { |
||||
self.tx_rx_fifo.write(value.into()); |
||||
} |
||||
|
||||
const CONTROL_RXEN: usize = 2; |
||||
const CONTROL_RXDIS: usize = 3; |
||||
const CONTROL_TXEN: usize = 4; |
||||
const CONTROL_TXDIS: usize = 5; |
||||
const CONTROL_TXRST: usize = 1; |
||||
const CONTROL_RXRST: usize = 0; |
||||
|
||||
unsafe fn disable_rx(&self) { |
||||
self.control.modify(|mut x| { |
||||
x.set_bit(Self::CONTROL_RXEN, false); |
||||
x.set_bit(Self::CONTROL_RXDIS, true); |
||||
x |
||||
}) |
||||
} |
||||
|
||||
unsafe fn disable_tx(&self) { |
||||
self.control.modify(|mut x| { |
||||
x.set_bit(Self::CONTROL_TXEN, false); |
||||
x.set_bit(Self::CONTROL_TXDIS, true); |
||||
x |
||||
}) |
||||
} |
||||
|
||||
unsafe fn enable_rx(&self) { |
||||
self.control.modify(|mut x| { |
||||
x.set_bit(Self::CONTROL_RXEN, true); |
||||
x.set_bit(Self::CONTROL_RXDIS, false); |
||||
x |
||||
}) |
||||
} |
||||
|
||||
unsafe fn enable_tx(&self) { |
||||
self.control.modify(|mut x| { |
||||
x.set_bit(Self::CONTROL_TXEN, true); |
||||
x.set_bit(Self::CONTROL_TXDIS, false); |
||||
x |
||||
}) |
||||
} |
||||
|
||||
unsafe fn reset_rx(&self) { |
||||
self.control.modify(|mut x| { |
||||
x.set_bit(Self::CONTROL_RXRST, true); |
||||
x |
||||
}) |
||||
} |
||||
|
||||
unsafe fn reset_tx(&self) { |
||||
self.control.modify(|mut x| { |
||||
x.set_bit(Self::CONTROL_TXRST, true); |
||||
x |
||||
}) |
||||
} |
||||
|
||||
const CHANNEL_STS_TXFULL: usize = 4; |
||||
|
||||
pub fn tx_fifo_full(&self) -> bool { |
||||
self.channel_sts.read().get_bit(Self::CHANNEL_STS_TXFULL) |
||||
} |
||||
} |
Loading…
Reference in new issue