initial commit

master
cjb 2018-10-04 22:19:23 +01:00
commit e139aa0ae9
46 changed files with 7880 additions and 0 deletions

10
.gitignore vendored Normal file
View File

@ -0,0 +1,10 @@
gateware/build
misoc_*
*.o
*.a
*.d
*.elf
*.bin
*.lock
*.vcd
__pycache__

70
experiments/dds_timing.py Executable file
View File

@ -0,0 +1,70 @@
from artiq.experiment import *
import numpy as np
class Benchmark(EnvExperiment):
def build(self):
self.setattr_device("core")
self.dds = self.get_device("urukul0_ch0")
@kernel
def bisect_underflow(self, f, t_max_mu=1000, t_min_mu=0):
t = 0
while (t_max_mu-t_min_mu) > 2:
t = np.int64( (t_max_mu+t_min_mu)/2 )
print(np.int32(t_min_mu), np.int32(t_max_mu))
try:
f(t)
except RTIOUnderflow:
print("Underflow")
if t == t_max_mu:
raise ValueError("Upper bound underflowed")
t_min_mu = t
else:
t_max_mu = t
return t
@kernel
def dds_update_rate(self):
t=0
def f(t):
self.core.reset()
for i in range(1000):
with parallel:
delay_mu(t)
self.dds.set(80*MHz, amplitude=0.1, phase=0.5)
t = self.bisect_underflow(lambda t: f(t), t_max_mu=50000)
print("Sustained DDS update time: ", np.int32(t), "mu")
@kernel
def dds_setmu_update_rate(self):
t=0
def f(t):
f_mu = self.dds.frequency_to_ftw(80*MHz)
amp_mu = self.dds.amplitude_to_asf(0.1)
phase_mu = self.dds.turns_to_pow(0.5)
self.core.reset()
for i in range(1000):
with parallel:
delay_mu(t)
self.dds.set_mu(f_mu, asf=amp_mu, pow=phase_mu)
t = self.bisect_underflow(lambda t: f(t), t_max_mu=50000)
print("Sustained DDS set_mu update time: ", np.int32(t), "mu")
@kernel
def measure_dds_timeline_advance(self):
self.core.break_realtime()
t0 = now_mu()
self.dds.set(80*MHz, amplitude=0.1, phase=0.5)
dt = now_mu()-t0
core_log("DDS timeline advance:", np.int32(dt), "mu")
@kernel
def run(self):
self.core.reset()
self.dds.cpld.init(blind=True)
self.dds.init(blind=True)
# self.measure_dds_timeline_advance()
self.dds_update_rate()
# self.dds_setmu_update_rate()

147
experiments/device_db.py Executable file
View File

@ -0,0 +1,147 @@
device_db = {
"core": {
"type": "local",
"module": "artiq.coredevice.core",
"class": "Core",
"arguments": {"host": "lalala", "ref_period": 1/(125e6), "ref_multiplier": 1}
},
"ttl0": {
"type": "local",
"module": "artiq.coredevice.ttl",
"class": "TTLInOut",
"arguments": {"channel": 0},
},
"spi_urukul0": {
"type": "local",
"module": "artiq.coredevice.spi2",
"class": "SPIMaster",
"arguments": {"channel": 12}
},
"ttl_urukul0_io_update": {
"type": "local",
"module": "artiq.coredevice.ttl",
"class": "TTLOut",
"arguments": {"channel": 13}
},
"urukul0_cpld": {
"type": "local",
"module": "artiq.coredevice.urukul",
"class": "CPLD",
"arguments": {
"spi_device": "spi_urukul0",
"io_update_device": "ttl_urukul0_io_update",
"refclk": 125e6,
"clk_sel": 1
}
},
"urukul0_ch0": {
"type": "local",
"module": "artiq.coredevice.ad9910",
"class": "AD9910",
"arguments": {
"pll_n": 32,
"chip_select": 4,
"cpld_device": "urukul0_cpld",
}
},
"urukul0_ch1": {
"type": "local",
"module": "artiq.coredevice.ad9910",
"class": "AD9910",
"arguments": {
"pll_n": 32,
"chip_select": 5,
"cpld_device": "urukul0_cpld",
}
},
"urukul0_ch2": {
"type": "local",
"module": "artiq.coredevice.ad9910",
"class": "AD9910",
"arguments": {
"pll_n": 32,
"chip_select": 6,
"cpld_device": "urukul0_cpld",
}
},
"urukul0_ch3": {
"type": "local",
"module": "artiq.coredevice.ad9910",
"class": "AD9910",
"arguments": {
"pll_n": 32,
"chip_select": 7,
"cpld_device": "urukul0_cpld",
}
},
"spi_urukul1": {
"type": "local",
"module": "artiq.coredevice.spi2",
"class": "SPIMaster",
"arguments": {"channel": 17}
},
"ttl_urukul1_io_update": {
"type": "local",
"module": "artiq.coredevice.ttl",
"class": "TTLOut",
"arguments": {"channel": 18}
},
"urukul1_cpld": {
"type": "local",
"module": "artiq.coredevice.urukul",
"class": "CPLD",
"arguments": {
"spi_device": "spi_urukul1",
"io_update_device": "ttl_urukul1_io_update",
"refclk": 125e6,
"clk_sel": 1
}
},
"urukul1_ch0": {
"type": "local",
"module": "artiq.coredevice.ad9910",
"class": "AD9910",
"arguments": {
"pll_n": 32,
"chip_select": 4,
"cpld_device": "urukul1_cpld",
}
},
"urukul1_ch1": {
"type": "local",
"module": "artiq.coredevice.ad9910",
"class": "AD9910",
"arguments": {
"pll_n": 32,
"chip_select": 5,
"cpld_device": "urukul1_cpld",
}
},
"urukul1_ch2": {
"type": "local",
"module": "artiq.coredevice.ad9910",
"class": "AD9910",
"arguments": {
"pll_n": 32,
"chip_select": 6,
"cpld_device": "urukul1_cpld",
}
},
"urukul1_ch3": {
"type": "local",
"module": "artiq.coredevice.ad9910",
"class": "AD9910",
"arguments": {
"pll_n": 32,
"chip_select": 7,
"cpld_device": "urukul1_cpld",
}
},
}

46
experiments/mandelbrot.py Executable file
View File

@ -0,0 +1,46 @@
from artiq.experiment import *
import numpy as np
class Mandelbrot(EnvExperiment):
def build(self):
self.setattr_device("core")
def col(self, i):
sys.stdout.write(" .,-:;i+hHM$*#@ "[i])
def row(self):
print("")
# based on: http://warp.povusers.org/MandScripts/python.html
@kernel
def run(self):
minX = -2.0
maxX = 1.0
width = 78
height = 36
aspectRatio = 2
yScale = (maxX-minX)*(height/width)*aspectRatio
accum = 0.
t0 = self.core.get_rtio_counter_mu()
for y in range(height):
for x in range(width):
c_r = minX+x*(maxX-minX)/width
c_i = y*yScale/height-yScale/2
z_r = c_r
z_i = c_i
i = 0
for i in range(16):
if z_r*z_r + z_i*z_i > 4:
break
new_z_r = (z_r*z_r)-(z_i*z_i) + c_r
z_i = 2*z_r*z_i + c_i
z_r = new_z_r
accum += i
dt = self.core.get_rtio_counter_mu() - t0
core_log("Execution time:", np.int32(dt), "mu")
# Takes 666763336 mu on Kasli

14
experiments/minimal.py Executable file
View File

@ -0,0 +1,14 @@
from artiq.experiment import *
class Minimal(EnvExperiment):
def build(self):
self.setattr_device("core")
@kernel
def run(self):
core_log(" :: Hello from kernel")
# try:
raise ValueError
# except ValueError as e:
# core_log(" :: Caught exception.")

93
experiments/ttl.py Executable file
View File

@ -0,0 +1,93 @@
from artiq.experiment import *
import numpy as np
class TtlTests(EnvExperiment):
def build(self):
self.setattr_device("core")
self.ttlio = self.get_device("ttl0")
@kernel
def bisect_underflow(self, f, t_max_mu=1000, t_min_mu=0):
t = 0
while (t_max_mu-t_min_mu) > 1:
t = np.int64( (t_max_mu+t_min_mu)/2 )
print(np.int32(t_min_mu), np.int32(t_max_mu))
try:
f(t)
except RTIOUnderflow:
print("Underflow")
if t == t_max_mu:
raise ValueError("Upper bound underflowed")
t_min_mu = t
else:
t_max_mu = t
return t
@kernel
def test_input_operation(self):
core_log("")
core_log("Test input operation ...")
self.core.reset()
self.ttlio.output()
delay(10*us)
with parallel:
self.ttlio.gate_rising(10*us)
with sequential:
delay(1*us)
t_out_mu = now_mu()
self.ttlio.pulse(1*us)
t_in_mu = self.ttlio.timestamp_mu()
dt = np.int32(t_in_mu-t_out_mu)
core_log("t_in-t_out:", dt, "mu")
@kernel
def event_response(self):
"""How soon after an input event can we reliably schedule an output event"""
core_log("")
core_log("Measuring minimum event response time")
t = 0
def f(t_delay):
self.core.reset()
self.ttlio.output()
delay(1*us)
for i in range(10):
# Make sure we have plenty of slack
delay(1000*us)
self.ttlio.off()
delay(1*us)
with parallel:
self.ttlio.gate_rising(4*us)
with sequential:
delay(100*ns)
self.ttlio.pulse(100*ns)
t_input = self.ttlio.timestamp_mu()
at_mu(t_input+t_delay)
self.ttlio.pulse(10*us)
t = self.bisect_underflow(lambda t: f(t), t_max_mu=10000)
core_log("Event response time: ", np.int32(t), "mu")
@kernel
def output_pulse_rate(self):
"""Sustained TTL output pulse rate"""
core_log("")
core_log("Measuring sustained output pulse rate")
t=0
def f(t):
self.core.break_realtime()
for i in range(20000):
delay_mu(t)
self.ttlio.pulse_mu(t)
t = self.bisect_underflow(lambda t: f(t), t_max_mu=1000)
core_log("Sustained pulse rate: ", np.int32(2*t), "mu")
@kernel
def run(self):
self.core.reset()
self.test_input_operation()
self.output_pulse_rate()
self.event_response()

18
experiments/wall_time.py Executable file
View File

@ -0,0 +1,18 @@
from artiq.experiment import *
class WallTime(EnvExperiment):
def build(self):
self.setattr_device("core")
@kernel
def run(self):
t0 = self.core.get_rtio_counter_mu()
i = 0
while True:
t = self.core.get_rtio_counter_mu()
dt_s = (t-t0)
if dt_s < 1e9:
continue
t0 = t
core_log(i)
i += 1

7
firmware/Cargo.toml Executable file
View File

@ -0,0 +1,7 @@
[workspace]
members = ["runtime"]
[profile.dev]
incremental = true
lto = false
opt-level = 2

View File

@ -0,0 +1,14 @@
[package]
name = "board_misoc"
version = "0.1.0"
authors = ["cjb <cjb>"]
[dependencies]
[lib]
path="lib.rs"
name = "board_misoc"

56
firmware/libboard_misoc/lib.rs Executable file
View File

@ -0,0 +1,56 @@
#![no_std]
#![feature(asm)]
include!(concat!(env!("BUILDINC_DIRECTORY"), "/generated/csr.rs"));
pub mod uart;
#[macro_use]
pub mod uart_console;
// Clean = expunge cache line with writeback
pub fn clean_data_cache(base: usize, len: usize) {
const CACHE_SYNC_OFFSET: isize = 0x0730/4; // Cache Sync
const CACHE_CLEAN_PA_OFFSET: isize = 0x7B0/4;
const L2CC_BASE: *mut u32 = 0xF8F02000 as *mut u32;
const CACHE_LINE_LENGTH: usize = 32;
let mut addr = base & !(CACHE_LINE_LENGTH-1);
loop {
if addr > base+len {break}
unsafe {
write_volatile(L2CC_BASE.offset(CACHE_CLEAN_PA_OFFSET), addr as u32);
write_volatile(L2CC_BASE.offset(CACHE_SYNC_OFFSET), 0);
// Clean data cache line by virtual address
asm!("mcr p15, 0, $0, c7, c10, 1"::"r"(addr))
}
addr += CACHE_LINE_LENGTH;
}
}
use core::ptr::write_volatile;
// Invalidate = expunge cache line without writeback
pub fn invalidate_data_cache(base: usize, len: usize) {
const CACHE_SYNC_OFFSET: isize = 0x0730/4; // Cache Sync
const CACHE_INVLD_PA_OFFSET: isize = 0x0770/4; // Cache Invalid by PA
const L2CC_BASE: *mut u32 = 0xF8F02000 as *mut u32;
const CACHE_LINE_LENGTH: usize = 32;
let mut addr = base & !(CACHE_LINE_LENGTH-1);
loop {
if addr > base+len {break}
unsafe {
write_volatile(L2CC_BASE.offset(CACHE_INVLD_PA_OFFSET), addr as u32);
write_volatile(L2CC_BASE.offset(CACHE_SYNC_OFFSET), 0);
// Invalidate data cache line by virtual address
asm!("mcr p15, 0, $0, c7, c6, 1"::"r"(addr))
}
addr += CACHE_LINE_LENGTH;
}
}

14
firmware/libboard_misoc/uart.rs Executable file
View File

@ -0,0 +1,14 @@
use core::ptr::{read_volatile, write_volatile};
pub const UART_BASE: *mut u32 = 0xE0001000 as *mut u32;
// pub const UART_BASE: *mut u32 = 0x101000 as *mut u32;
#[export_name="uart_write"]
pub extern fn write(c: u8) {
unsafe {
while read_volatile(UART_BASE.offset(0x2c/4)) & 0x10 != 0 {}
write_volatile(UART_BASE.offset(0x30/4), c as u32);
}
}

View File

@ -0,0 +1,30 @@
use core::fmt;
pub struct Console;
impl fmt::Write for Console {
fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> {
use uart;
for c in s.bytes() {
unsafe { uart::write(c) }
}
Ok(())
}
}
#[macro_export]
macro_rules! print {
($($arg:tt)*) => ({
use core::fmt::Write;
write!($crate::uart_console::Console, $($arg)*).unwrap()
})
}
#[macro_export]
macro_rules! println {
($fmt:expr) => (print!(concat!($fmt, "\n")));
($fmt:expr, $($arg:tt)*) => (print!(concat!($fmt, "\n"), $($arg)*));
}

View File

@ -0,0 +1,8 @@
[package]
authors = ["M-Labs"]
name = "dyld"
version = "0.0.0"
[lib]
name = "dyld"
path = "lib.rs"

2737
firmware/libdyld/elf.rs Normal file

File diff suppressed because it is too large Load Diff

339
firmware/libdyld/lib.rs Normal file
View File

@ -0,0 +1,339 @@
#![no_std]
use core::{mem, ptr, fmt, slice, str, convert};
use elf::*;
pub mod elf;
fn read_unaligned<T: Copy>(data: &[u8], offset: usize) -> Result<T, ()> {
if data.len() < offset + mem::size_of::<T>() {
Err(())
} else {
let ptr = data.as_ptr().wrapping_offset(offset as isize) as *const T;
Ok(unsafe { ptr::read_unaligned(ptr) })
}
}
fn get_ref<T: Copy>(data: &[u8], offset: usize) -> Result<&T, ()> {
if data.len() < offset + mem::size_of::<T>() {
Err(())
} else if (data.as_ptr() as usize + offset) & (mem::align_of::<T>() - 1) != 0 {
Err(())
} else {
let ptr = data.as_ptr().wrapping_offset(offset as isize) as *const T;
Ok(unsafe { &*ptr })
}
}
fn get_ref_slice<T: Copy>(data: &[u8], offset: usize, len: usize) -> Result<&[T], ()> {
if data.len() < offset + mem::size_of::<T>() * len {
Err(())
} else if (data.as_ptr() as usize + offset) & (mem::align_of::<T>() - 1) != 0 {
Err(())
} else {
let ptr = data.as_ptr().wrapping_offset(offset as isize) as *const T;
Ok(unsafe { slice::from_raw_parts(ptr, len) })
}
}
fn elf_hash(name: &[u8]) -> u32 {
let mut h: u32 = 0;
for c in name {
h = (h << 4) + *c as u32;
let g = h & 0xf0000000;
if g != 0 {
h ^= g >> 24;
h &= !g;
}
}
h
}
#[derive(Debug)]
pub enum Error<'a> {
Parsing(&'static str),
Lookup(&'a [u8])
}
impl<'a> convert::From<&'static str> for Error<'a> {
fn from(desc: &'static str) -> Error<'a> {
Error::Parsing(desc)
}
}
impl<'a> fmt::Display for Error<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&Error::Parsing(desc) =>
write!(f, "parse error: {}", desc),
&Error::Lookup(sym) =>
match str::from_utf8(sym) {
Ok(sym) => write!(f, "symbol lookup error: {}", sym),
Err(_) => write!(f, "symbol lookup error: {:?}", sym)
}
}
}
}
pub struct Library<'a> {
image_off: Elf32_Addr,
image_sz: usize,
strtab: &'a [u8],
symtab: &'a [Elf32_Sym],
pltrel: &'a [Elf32_Rela],
hash_bucket: &'a [Elf32_Word],
hash_chain: &'a [Elf32_Word],
}
impl<'a> Library<'a> {
pub fn lookup(&self, name: &[u8]) -> Option<Elf32_Word> {
let hash = elf_hash(name);
let mut index = self.hash_bucket[hash as usize % self.hash_bucket.len()] as usize;
loop {
if index == STN_UNDEF { return None }
let sym = &self.symtab[index];
let sym_name_off = sym.st_name as usize;
match self.strtab.get(sym_name_off..sym_name_off + name.len()) {
Some(sym_name) if sym_name == name => {
if ELF32_ST_BIND(sym.st_info) & STB_GLOBAL == 0 {
return None
}
match sym.st_shndx {
SHN_UNDEF => return None,
SHN_ABS => return Some(sym.st_value),
_ => return Some(self.image_off + sym.st_value)
}
}
_ => (),
}
index = self.hash_chain[index] as usize;
}
}
fn name_starting_at(&self, offset: usize) -> Result<&'a [u8], Error<'a>> {
let size = self.strtab.iter().skip(offset).position(|&x| x == 0)
.ok_or("symbol in symbol table not null-terminated")?;
Ok(self.strtab.get(offset..offset + size)
.ok_or("cannot read symbol name")?)
}
fn update_rela(&self, rela: &Elf32_Rela, value: Elf32_Word) -> Result<(), Error<'a>> {
if rela.r_offset as usize + mem::size_of::<Elf32_Addr>() > self.image_sz {
return Err("relocation out of image bounds")?
}
let ptr = (self.image_off + rela.r_offset) as *mut Elf32_Addr;
Ok(unsafe { *ptr = value })
}
// This is unsafe because it mutates global data (the PLT).
pub unsafe fn rebind(&self, name: &[u8], addr: Elf32_Word) -> Result<(), Error<'a>> {
for rela in self.pltrel.iter() {
match ELF32_R_TYPE(rela.r_info) {
R_OR1K_32 | R_OR1K_GLOB_DAT | R_OR1K_JMP_SLOT => {
let sym = self.symtab.get(ELF32_R_SYM(rela.r_info) as usize)
.ok_or("symbol out of bounds of symbol table")?;
let sym_name = self.name_starting_at(sym.st_name as usize)?;
if sym_name == name {
self.update_rela(rela, addr)?
}
}
// No associated symbols for other relocation types.
_ => ()
}
}
Ok(())
}
fn resolve_rela(&self, rela: &Elf32_Rela, resolve: &Fn(&[u8]) -> Option<Elf32_Word>)
-> Result<(), Error<'a>> {
let sym;
if ELF32_R_SYM(rela.r_info) == 0 {
sym = None;
} else {
sym = Some(self.symtab.get(ELF32_R_SYM(rela.r_info) as usize)
.ok_or("symbol out of bounds of symbol table")?)
}
let value;
match ELF32_R_TYPE(rela.r_info) {
R_OR1K_NONE =>
return Ok(()),
R_OR1K_RELATIVE =>
value = self.image_off + rela.r_addend as Elf32_Word,
R_OR1K_32 | R_OR1K_GLOB_DAT | R_OR1K_JMP_SLOT => {
let sym = sym.ok_or("relocation requires an associated symbol")?;
let sym_name = self.name_starting_at(sym.st_name as usize)?;
// First, try to resolve against itself.
match self.lookup(sym_name) {
Some(addr) => value = addr,
None => {
// Second, call the user-provided function.
match resolve(sym_name) {
Some(addr) => value = addr,
None => {
// We couldn't find it anywhere.
return Err(Error::Lookup(sym_name))
}
}
}
}
}
_ => return Err("unsupported relocation type")?
}
self.update_rela(rela, value)
}
pub fn load(data: &[u8], image: &'a mut [u8], resolve: &Fn(&[u8]) -> Option<Elf32_Word>)
-> Result<Library<'a>, Error<'a>> {
#![allow(unused_assignments)]
let ehdr = read_unaligned::<Elf32_Ehdr>(data, 0)
.map_err(|()| "cannot read ELF header")?;
const IDENT: [u8; EI_NIDENT] = [
ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3,
ELFCLASS32, ELFDATA2MSB, EV_CURRENT, ELFOSABI_NONE,
/* ABI version */ 0, /* padding */ 0, 0, 0, 0, 0, 0, 0
];
#[cfg(target_arch = "or1k")]
const ARCH: u16 = EM_OPENRISC;
#[cfg(not(target_arch = "or1k"))]
const ARCH: u16 = EM_NONE;
if ehdr.e_ident != IDENT || ehdr.e_type != ET_DYN || ehdr.e_machine != ARCH {
return Err("not a shared library for current architecture")?
}
let mut dyn_off = None;
for i in 0..ehdr.e_phnum {
let phdr_off = ehdr.e_phoff as usize + mem::size_of::<Elf32_Phdr>() * i as usize;
let phdr = read_unaligned::<Elf32_Phdr>(data, phdr_off)
.map_err(|()| "cannot read program header")?;
match phdr.p_type {
PT_LOAD => {
if (phdr.p_vaddr + phdr.p_filesz) as usize > image.len() ||
(phdr.p_offset + phdr.p_filesz) as usize > data.len() {
return Err("program header requests an out of bounds load")?
}
let dst = image.get_mut(phdr.p_vaddr as usize..
(phdr.p_vaddr + phdr.p_filesz) as usize)
.ok_or("cannot write to program header destination")?;
let src = data.get(phdr.p_offset as usize..
(phdr.p_offset + phdr.p_filesz) as usize)
.ok_or("cannot read from program header source")?;
dst.copy_from_slice(src);
}
PT_DYNAMIC =>
dyn_off = Some(phdr.p_vaddr),
_ => ()
}
}
let (mut strtab_off, mut strtab_sz) = (0, 0);
let (mut symtab_off, mut symtab_sz) = (0, 0);
let (mut rela_off, mut rela_sz) = (0, 0);
let (mut pltrel_off, mut pltrel_sz) = (0, 0);
let (mut hash_off, mut hash_sz) = (0, 0);
let mut sym_ent = 0;
let mut rela_ent = 0;
let mut nbucket = 0;
let mut nchain = 0;
let dyn_off = dyn_off.ok_or("cannot find a dynamic header")?;
for i in 0.. {
let dyn_off = dyn_off as usize + i * mem::size_of::<Elf32_Dyn>();
let dyn = get_ref::<Elf32_Dyn>(image, dyn_off)
.map_err(|()| "cannot read dynamic header")?;
let val = unsafe { dyn.d_un.d_val } as usize;
match dyn.d_tag {
DT_NULL => break,
DT_REL => return Err("relocations with implicit addend are not supported")?,
DT_STRTAB => strtab_off = val,
DT_STRSZ => strtab_sz = val,
DT_SYMTAB => symtab_off = val,
DT_SYMENT => sym_ent = val,
DT_RELA => rela_off = val,
DT_RELASZ => rela_sz = val / mem::size_of::<Elf32_Rela>(),
DT_RELAENT => rela_ent = val,
DT_JMPREL => pltrel_off = val,
DT_PLTRELSZ => pltrel_sz = val / mem::size_of::<Elf32_Rela>(),
DT_HASH => {
nbucket = *get_ref::<Elf32_Word>(image, val + 0)
.map_err(|()| "cannot read hash bucket count")? as usize;
nchain = *get_ref::<Elf32_Word>(image, val + 4)
.map_err(|()| "cannot read hash chain count")? as usize;
hash_off = val + 8;
hash_sz = nbucket + nchain;
}
_ => ()
}
}
if sym_ent != mem::size_of::<Elf32_Sym>() {
return Err("incorrect symbol entry size")?
}
if rela_ent != mem::size_of::<Elf32_Rela>() {
return Err("incorrect relocation entry size")?
}
// These are the same--there are as many chains as buckets, and the chains only contain
// the symbols that overflowed the bucket.
symtab_sz = nchain;
// Drop the mutability. See also the comment below.
let image = &*image;
let strtab = get_ref_slice::<u8>(image, strtab_off, strtab_sz)
.map_err(|()| "cannot read string table")?;
let symtab = get_ref_slice::<Elf32_Sym>(image, symtab_off, symtab_sz)
.map_err(|()| "cannot read symbol table")?;
let rela = get_ref_slice::<Elf32_Rela>(image, rela_off, rela_sz)
.map_err(|()| "cannot read rela entries")?;
let pltrel = get_ref_slice::<Elf32_Rela>(image, pltrel_off, pltrel_sz)
.map_err(|()| "cannot read pltrel entries")?;
let hash = get_ref_slice::<Elf32_Word>(image, hash_off, hash_sz)
.map_err(|()| "cannot read hash entries")?;
let library = Library {
image_off: image.as_ptr() as Elf32_Word,
image_sz: image.len(),
strtab: strtab,
symtab: symtab,
pltrel: pltrel,
hash_bucket: &hash[..nbucket],
hash_chain: &hash[nbucket..nbucket + nchain],
};
// If a borrow exists anywhere, the borrowed memory cannot be mutated except
// through that pointer or it's UB. However, we need to retain pointers
// to the symbol tables and relocations, and at the same time mutate the code
// to resolve the relocations.
//
// To avoid invoking UB, we drop the only pointer to the entire area (which is
// unique since it's a &mut); we retain pointers to the various tables, but
// we never write to the memory they refer to, so it's safe.
mem::drop(image);
for r in rela { library.resolve_rela(r, resolve)? }
for r in pltrel { library.resolve_rela(r, resolve)? }
Ok(library)
}
}

Binary file not shown.

20
firmware/libksupport/Cargo.toml Executable file
View File

@ -0,0 +1,20 @@
[package]
name = "ksupport"
version = "0.1.0"
authors = ["cjb <cjb>"]
[build-dependencies]
cc = "1.0"
[dependencies]
board_misoc = { path = "../libboard_misoc"}
cslice = { version = "0.3" }
unwind = { path = "../libunwind-rs" }
libc = { default-features = false }
volatile_cell = "1.0"
[lib]
path="lib.rs"
name = "ksupport"

89
firmware/libksupport/api.rs Executable file
View File

@ -0,0 +1,89 @@
macro_rules! api {
($i:ident) => ({
extern { static $i: u8; }
api!($i = &$i as *const _)
});
($i:ident, $d:item) => ({
$d
api!($i = $i)
});
($i:ident = $e:expr) => {
(stringify!($i), unsafe { $e as *const () })
}
}
#[allow(unused_unsafe)]
static mut API: &'static [(&'static str, *const ())] = &[
api!(__divsi3),
api!(__modsi3),
api!(__ledf2),
api!(__gedf2),
api!(__unorddf2),
api!(__eqdf2),
api!(__ltdf2),
api!(__nedf2),
api!(__gtdf2),
api!(__addsf3),
api!(__subsf3),
api!(__mulsf3),
api!(__divsf3),
api!(__lshrdi3),
api!(__muldi3),
api!(__divdi3),
api!(__ashldi3),
api!(__ashrdi3),
api!(__udivmoddi4),
api!(__floatsisf),
api!(__floatunsisf),
api!(__fixsfsi),
api!(__fixunssfsi),
api!(__adddf3),
api!(__subdf3),
api!(__muldf3),
api!(__divdf3),
api!(__floatsidf),
api!(__floatunsidf),
api!(__floatdidf),
api!(__fixdfsi),
api!(__fixdfdi),
api!(__fixunsdfsi),
api!(__udivdi3),
api!(__umoddi3),
api!(__moddi3),
api!(__powidf2),
/* libc */
// api!(abort = ::abort),
api!(memcmp, extern { fn memcmp(a: *const u8, b: *mut u8, size: usize); }),
/* libm */
api!(sqrt),
api!(round),
api!(floor),
/* exceptions */
api!(_Unwind_Resume = ::unwind::_Unwind_Resume),
api!(__artiq_personality = ::eh::personality),
api!(__artiq_raise = ::eh::raise),
api!(__artiq_reraise = ::eh::reraise),
/* proxified syscalls */
api!(core_log),
api!(now = &::NOW as *const _),
/* direct syscalls */
api!(rtio_init = ::rtio::init),
api!(rtio_get_counter = ::rtio::get_counter),
api!(rtio_log),
api!(rtio_output = ::rtio::output),
api!(rtio_output_wide = ::rtio::output_wide),
api!(rtio_input_timestamp = ::rtio::input_timestamp),
api!(rtio_input_data = ::rtio::input_data),
api!(rtio_input_data_timeout = ::rtio::input_data_timeout),
api!(rtio_input_timestamp_data = ::rtio::input_timestamp_data),
];

12
firmware/libksupport/build.rs Executable file
View File

@ -0,0 +1,12 @@
extern crate cc;
fn main() {
let glue_path = "glue.c";
println!("cargo:rerun-if-changed={}", glue_path);
cc::Build::new()
.file(glue_path)
.compile("glue");
}

602
firmware/libksupport/eh.rs Normal file
View File

@ -0,0 +1,602 @@
// Portions of the code in this file are derived from code by:
//
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![allow(non_upper_case_globals, non_camel_case_types, dead_code)]
use core::{ptr, mem};
use cslice::CSlice;
use unwind as uw;
use libc::{c_int, c_void};
#[cfg(not(target_arch = "arm"))]
type _Unwind_Stop_Fn = extern "C" fn(version: c_int,
actions: uw::_Unwind_Action,
exception_class: uw::_Unwind_Exception_Class,
exception_object: *mut uw::_Unwind_Exception,
context: *mut uw::_Unwind_Context,
stop_parameter: *mut c_void)
-> uw::_Unwind_Reason_Code;
#[cfg(target_arch = "arm")]
type _Unwind_Stop_Fn = extern "C" fn(state: uw::_Unwind_State,
exception_object: *mut uw::_Unwind_Exception,
context: *mut uw::_Unwind_Context)
-> uw::_Unwind_Reason_Code;
extern {
fn _Unwind_ForcedUnwind(exception: *mut uw::_Unwind_Exception,
stop_fn: _Unwind_Stop_Fn,
stop_parameter: *mut c_void) -> uw::_Unwind_Reason_Code;
}
const DW_EH_PE_omit: u8 = 0xFF;
const DW_EH_PE_absptr: u8 = 0x00;
const DW_EH_PE_uleb128: u8 = 0x01;
const DW_EH_PE_udata2: u8 = 0x02;
const DW_EH_PE_udata4: u8 = 0x03;
const DW_EH_PE_udata8: u8 = 0x04;
const DW_EH_PE_sleb128: u8 = 0x09;
const DW_EH_PE_sdata2: u8 = 0x0A;
const DW_EH_PE_sdata4: u8 = 0x0B;
const DW_EH_PE_sdata8: u8 = 0x0C;
const DW_EH_PE_pcrel: u8 = 0x10;
const DW_EH_PE_textrel: u8 = 0x20;
const DW_EH_PE_datarel: u8 = 0x30;
const DW_EH_PE_funcrel: u8 = 0x40;
const DW_EH_PE_aligned: u8 = 0x50;
const DW_EH_PE_indirect: u8 = 0x80;
#[derive(Clone)]
struct DwarfReader {
pub ptr: *const u8,
}
impl DwarfReader {
fn new(ptr: *const u8) -> DwarfReader {
DwarfReader { ptr: ptr }
}
// DWARF streams are packed, so e.g. a u32 would not necessarily be aligned
// on a 4-byte boundary. This may cause problems on platforms with strict
// alignment requirements. By wrapping data in a "packed" struct, we are
// telling the backend to generate "misalignment-safe" code.
unsafe fn read<T: Copy>(&mut self) -> T {
let result = ptr::read_unaligned(self.ptr as *const T);
self.ptr = self.ptr.offset(mem::size_of::<T>() as isize);
result
}
// ULEB128 and SLEB128 encodings are defined in Section 7.6 - "Variable
// Length Data".
unsafe fn read_uleb128(&mut self) -> u64 {
let mut shift: usize = 0;
let mut result: u64 = 0;
let mut byte: u8;
loop {
byte = self.read::<u8>();
result |= ((byte & 0x7F) as u64) << shift;
shift += 7;
if byte & 0x80 == 0 {
break;
}
}
result
}
unsafe fn read_sleb128(&mut self) -> i64 {
let mut shift: usize = 0;
let mut result: u64 = 0;
let mut byte: u8;
loop {
byte = self.read::<u8>();
result |= ((byte & 0x7F) as u64) << shift;
shift += 7;
if byte & 0x80 == 0 {
break;
}
}
// sign-extend
if shift < 8 * mem::size_of::<u64>() && (byte & 0x40) != 0 {
result |= (!0 as u64) << shift;
}
result as i64
}
unsafe fn read_encoded_pointer(&mut self, encoding: u8) -> usize {
fn round_up(unrounded: usize, align: usize) -> usize {
debug_assert!(align.is_power_of_two());
(unrounded + align - 1) & !(align - 1)
}
debug_assert!(encoding != DW_EH_PE_omit);
// DW_EH_PE_aligned implies it's an absolute pointer value
if encoding == DW_EH_PE_aligned {
self.ptr = round_up(self.ptr as usize, mem::size_of::<usize>()) as *const u8;
return self.read::<usize>()
}
let value_ptr = self.ptr;
let mut result = match encoding & 0x0F {
DW_EH_PE_absptr => self.read::<usize>(),
DW_EH_PE_uleb128 => self.read_uleb128() as usize,
DW_EH_PE_udata2 => self.read::<u16>() as usize,
DW_EH_PE_udata4 => self.read::<u32>() as usize,
DW_EH_PE_udata8 => self.read::<u64>() as usize,
DW_EH_PE_sleb128 => self.read_sleb128() as usize,
DW_EH_PE_sdata2 => self.read::<i16>() as usize,
DW_EH_PE_sdata4 => self.read::<i32>() as usize,
DW_EH_PE_sdata8 => self.read::<i64>() as usize,
_ => panic!(),
};
result += match encoding & 0x70 {
DW_EH_PE_absptr => 0,
// relative to address of the encoded value, despite the name
DW_EH_PE_pcrel => value_ptr as usize,
// DW_EH_PE_funcrel => {
// if context.func_start == 0 {
// return Err(())
// }
// context.func_start
// }
// DW_EH_PE_textrel => (*context.get_text_start)(),
// DW_EH_PE_datarel => (*context.get_data_start)(),
_ => panic!(),
};
if encoding & DW_EH_PE_indirect != 0 {
result = *(result as *const usize);
}
result
}
}
fn encoding_size(encoding: u8) -> usize {
if encoding == DW_EH_PE_omit {
return 0
}
match encoding & 0x0F {
DW_EH_PE_absptr => mem::size_of::<usize>(),
DW_EH_PE_udata2 => 2,
DW_EH_PE_udata4 => 4,
DW_EH_PE_udata8 => 8,
DW_EH_PE_sdata2 => 2,
DW_EH_PE_sdata4 => 4,
DW_EH_PE_sdata8 => 8,
_ => panic!()
}
}
pub enum EHAction {
None,
Cleanup(usize),
Catch(usize),
Terminate,
}
unsafe fn find_eh_action(uw_exception: *mut uw::_Unwind_Exception,
context: *mut uw::_Unwind_Context) -> EHAction {
let lsda = uw::_Unwind_GetLanguageSpecificData(context) as *const u8;
let func_start = uw::_Unwind_GetRegionStart(context);
if lsda.is_null() {
return EHAction::None
}
let mut reader = DwarfReader::new(lsda);
let start_encoding = reader.read::<u8>();
// base address for landing pad offsets
let lpad_base = if start_encoding != DW_EH_PE_omit {
reader.read_encoded_pointer(start_encoding)
} else {
func_start
};
let mut ttype_encoding = reader.read::<u8>();
let ttype_encoding_size = encoding_size(ttype_encoding) as isize;
let class_info;
if ttype_encoding != DW_EH_PE_omit {
// // FIXME: ARM-only override; refactor this into read_target2 or something.
// // Alternatively, pass --target2=rel.
// ttype_encoding = DW_EH_PE_pcrel | DW_EH_PE_indirect;
let class_info_offset = reader.read_uleb128();
class_info = reader.ptr.offset(class_info_offset as isize);
} else {
class_info = ptr::null();
}
assert!(!class_info.is_null());
let call_site_encoding = reader.read::<u8>();
let call_site_table_length = reader.read_uleb128();
let action_table = reader.ptr.offset(call_site_table_length as isize);
let ip = uw::_Unwind_GetIP(context) - 1;
let exception_info = &mut *(uw_exception as *mut ExceptionInfo);
let exn_name = &exception_info.exception.unwrap().name;
while reader.ptr < action_table {
let cs_start = reader.read_encoded_pointer(call_site_encoding);
let cs_len = reader.read_encoded_pointer(call_site_encoding);
let cs_lpad = reader.read_encoded_pointer(call_site_encoding);
let cs_action = reader.read_uleb128();
if ip < func_start + cs_start {
// Callsite table is sorted by cs_start, so if we've passed the ip, we
// may stop searching.
break
}
if ip > func_start + cs_start + cs_len {
continue
}
if cs_lpad == 0 {
return EHAction::None
}
let lpad = lpad_base + cs_lpad;
if cs_action == 0 {
return EHAction::Cleanup(lpad)
}
let action_entry = action_table.offset((cs_action - 1) as isize);
let mut action_reader = DwarfReader::new(action_entry);
loop {
let type_info_offset = action_reader.read_sleb128() as isize;
let action_offset = action_reader.clone().read_sleb128() as isize;
assert!(type_info_offset >= 0);
if type_info_offset > 0 {
let type_info_ptr_ptr = class_info.offset(-type_info_offset * ttype_encoding_size);
let type_info_ptr = DwarfReader::new(type_info_ptr_ptr)
.read_encoded_pointer(ttype_encoding);
let type_info = *(type_info_ptr as *const CSlice<u8>);
if type_info.as_ref() == exn_name.as_ref() {
return EHAction::Catch(lpad)
}
if type_info.len() == 0 {
// This is a catch-all clause. We don't compare type_info_ptr with null here
// because, in PIC mode, the OR1K LLVM backend emits a literal zero
// encoded with DW_EH_PE_pcrel, which of course doesn't result in
// a proper null pointer.
return EHAction::Catch(lpad)
}
}
if action_offset == 0 {
break
} else {
action_reader.ptr = action_reader.ptr.offset(action_offset)
}
}
return EHAction::None
}
// the function has a personality but no landing pads; this is fine
EHAction::None
}
#[repr(C)]
#[derive(Clone, Copy)]
pub struct Exception<'a> {
pub name: CSlice<'a, u8>,
pub file: CSlice<'a, u8>,
pub line: u32,
pub column: u32,
pub function: CSlice<'a, u8>,
pub message: CSlice<'a, u8>,
pub param: [i64; 3]
}
const EXCEPTION_CLASS: uw::_Unwind_Exception_Class = 0x4d_4c_42_53_41_52_54_51; /* 'MLBSARTQ' */
const MAX_BACKTRACE_SIZE: usize = 128;
#[repr(C)]
struct ExceptionInfo {
uw_exception: uw::_Unwind_Exception,
exception: Option<Exception<'static>>,
handled: bool,
backtrace: [usize; MAX_BACKTRACE_SIZE],
backtrace_size: usize
}
#[cfg(target_arch = "x86_64")]
const UNWIND_DATA_REG: (i32, i32) = (0, 1); // RAX, RDX
#[cfg(target_arch = "arm")]
const UNWIND_DATA_REG: (i32, i32) = (0, 1); // R0, R1
#[cfg(any(target_arch = "or1k"))]
const UNWIND_DATA_REG: (i32, i32) = (3, 4); // R3, R4
// Personality routine for non-ARM-EHABI (which uses a slightly different ABI).
#[cfg(not(target_arch = "arm"))]
#[export_name="__artiq_personality"]
pub extern fn personality(version: c_int,
actions: uw::_Unwind_Action,
uw_exception_class: uw::_Unwind_Exception_Class,
uw_exception: *mut uw::_Unwind_Exception,
context: *mut uw::_Unwind_Context)
-> uw::_Unwind_Reason_Code {
unsafe {
if version != 1 || uw_exception_class != EXCEPTION_CLASS {
return uw::_URC_FATAL_PHASE1_ERROR
}
let eh_action = find_eh_action(uw_exception, context);
if actions as u32 & uw::_UA_SEARCH_PHASE as u32 != 0 {
match eh_action {
EHAction::None |
EHAction::Cleanup(_) => return uw::_URC_CONTINUE_UNWIND,
EHAction::Catch(_) => return uw::_URC_HANDLER_FOUND,
EHAction::Terminate => return uw::_URC_FATAL_PHASE1_ERROR,
}
} else {
match eh_action {
EHAction::None => return uw::_URC_CONTINUE_UNWIND,
EHAction::Cleanup(lpad) |
EHAction::Catch(lpad) => {
if actions as u32 & uw::_UA_HANDLER_FRAME as u32 != 0 {
exception_info.handled = true
}
// Pass a pair of the unwinder exception and ARTIQ exception
// (which immediately follows).
uw::_Unwind_SetGR(context, UNWIND_DATA_REG.0,
uw_exception as uw::_Unwind_Word);
uw::_Unwind_SetGR(context, UNWIND_DATA_REG.1,
exception as *const _ as uw::_Unwind_Word);
uw::_Unwind_SetIP(context, lpad);
return uw::_URC_INSTALL_CONTEXT;
}
EHAction::Terminate => return uw::_URC_FATAL_PHASE2_ERROR,
}
}
}
}
// ARM EHABI personality routine.
// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0038b/IHI0038B_ehabi.pdf
#[cfg(target_arch = "arm")]
#[export_name="__artiq_personality"]
unsafe extern "C" fn personality(state: uw::_Unwind_State,
exception_object: *mut uw::_Unwind_Exception,
context: *mut uw::_Unwind_Context)
-> uw::_Unwind_Reason_Code {
let state = state as c_int;
let action = state & uw::_US_ACTION_MASK as c_int;
let search_phase = if action == uw::_US_VIRTUAL_UNWIND_FRAME as c_int {
// Backtraces on ARM will call the personality routine with
// state == _US_VIRTUAL_UNWIND_FRAME | _US_FORCE_UNWIND. In those cases
// we want to continue unwinding the stack.
if state & uw::_US_FORCE_UNWIND as c_int != 0 {
return continue_unwind(exception_object, context);
}
true
} else if action == uw::_US_UNWIND_FRAME_STARTING as c_int {
false
} else if action == uw::_US_UNWIND_FRAME_RESUME as c_int {
return continue_unwind(exception_object, context);
} else {
return uw::_URC_FAILURE;
};
// The DWARF unwinder assumes that _Unwind_Context holds things like the function
// and LSDA pointers, however ARM EHABI places them into the exception object.
// To preserve signatures of functions like _Unwind_GetLanguageSpecificData(), which
// take only the context pointer, GCC personality routines stash a pointer to exception_object
// in the context, using location reserved for ARM's "scratch register" (r12).
uw::_Unwind_SetGR(context,
uw::UNWIND_POINTER_REG,
exception_object as uw::_Unwind_Ptr);
// ...A more principled approach would be to provide the full definition of ARM's
// _Unwind_Context in our libunwind bindings and fetch the required data from there directly,
// bypassing DWARF compatibility functions.
let eh_action = find_eh_action(exception_object, context);
if search_phase {
match eh_action {
EHAction::None |
EHAction::Cleanup(_) => return continue_unwind(exception_object, context),
EHAction::Catch(_) => return uw::_URC_HANDLER_FOUND,
EHAction::Terminate => {
return uw::_URC_FAILURE
}
}
} else {
match eh_action {
EHAction::None => return continue_unwind(exception_object, context),
EHAction::Cleanup(lpad) |
EHAction::Catch(lpad) => {
let exception_info = &mut *(exception_object as *mut ExceptionInfo);
match eh_action {
EHAction::Catch(_) => exception_info.handled = true,
_ => (),
}
// Pass a pair of the unwinder exception and ARTIQ exception
// (which immediately follows).
let exception = &exception_info.exception.unwrap();
uw::_Unwind_SetGR(context, UNWIND_DATA_REG.0,
exception_object as uw::_Unwind_Word);
uw::_Unwind_SetGR(context, UNWIND_DATA_REG.1,
exception as *const _ as uw::_Unwind_Word);
uw::_Unwind_SetIP(context, lpad);
return uw::_URC_INSTALL_CONTEXT;
},
EHAction::Terminate => {
return uw::_URC_FAILURE
}
}
}
// On ARM EHABI the personality routine is responsible for actually
// unwinding a single stack frame before returning (ARM EHABI Sec. 6.1).
unsafe fn continue_unwind(exception_object: *mut uw::_Unwind_Exception,
context: *mut uw::_Unwind_Context)
-> uw::_Unwind_Reason_Code {
if __gnu_unwind_frame(exception_object, context) == uw::_URC_NO_REASON {
uw::_URC_CONTINUE_UNWIND
} else {
uw::_URC_FAILURE
}
}
// Defined in libunwind, matching the GNU implementation in libgcc.
extern "C" {
fn __gnu_unwind_frame(exception_object: *mut uw::_Unwind_Exception,
context: *mut uw::_Unwind_Context)
-> uw::_Unwind_Reason_Code;
}
}
extern fn cleanup(_unwind_code: uw::_Unwind_Reason_Code,
uw_exception: *mut uw::_Unwind_Exception) {
unsafe {
let exception_info = &mut *(uw_exception as *mut ExceptionInfo);
exception_info.exception = None;
}
}
#[cfg(not(target_arch = "arm"))]
extern fn uncaught_exception(_version: c_int,
actions: uw::_Unwind_Action,
_uw_exception_class: uw::_Unwind_Exception_Class,
uw_exception: *mut uw::_Unwind_Exception,
context: *mut uw::_Unwind_Context,
_stop_parameter: *mut c_void)
-> uw::_Unwind_Reason_Code {
unsafe {
let exception_info = &mut *(uw_exception as *mut ExceptionInfo);
if exception_info.backtrace_size < exception_info.backtrace.len() {
let ip = uw::_Unwind_GetIP(context);
exception_info.backtrace[exception_info.backtrace_size] = ip;
exception_info.backtrace_size += 1;
}
if actions as u32 & uw::_UA_END_OF_STACK as u32 != 0 {
::terminate(&exception_info.exception.unwrap(),
exception_info.backtrace[..exception_info.backtrace_size].as_mut())
} else {
uw::_URC_NO_REASON
}
}
}
#[cfg(target_arch = "arm")]
extern "C" fn uncaught_exception(state: uw::_Unwind_State,
exception_object: *mut uw::_Unwind_Exception,
context: *mut uw::_Unwind_Context)
-> uw::_Unwind_Reason_Code {
unsafe {
let exception_info = &mut *(exception_object as *mut ExceptionInfo);
if exception_info.backtrace_size < exception_info.backtrace.len() {
let ip = uw::_Unwind_GetIP(context);
exception_info.backtrace[exception_info.backtrace_size] = ip;
exception_info.backtrace_size += 1;
}
// if actions as u32 & uw::_UA_END_OF_STACK as u32 != 0 {
// ::terminate(&exception_info.exception.unwrap(),
// exception_info.backtrace[..exception_info.backtrace_size].as_mut())
// } else {
uw::_URC_NO_REASON
// }
}
}
// We can unfortunately not use mem::zeroed in a static, so Option<> is used as a workaround.
// See https://github.com/rust-lang/rust/issues/39498.
static mut INFLIGHT: ExceptionInfo = ExceptionInfo {
uw_exception: uw::_Unwind_Exception {
exception_class: EXCEPTION_CLASS,
exception_cleanup: cleanup,
private: [0; uw::unwinder_private_data_size],
},
exception: None,
handled: false,
backtrace: [0; MAX_BACKTRACE_SIZE],
backtrace_size: 0
};
#[export_name="__artiq_raise"]
#[unwind(allowed)]
pub unsafe extern fn raise(exception: *const Exception) -> ! {
// Zing! The Exception<'a> to Exception<'static> transmute is not really sound in case
// the exception is ever captured. Fortunately, they currently aren't, and we save
// on the hassle of having to allocate exceptions somewhere except on stack.
INFLIGHT.exception = Some(mem::transmute::<Exception, Exception<'static>>(*exception));
INFLIGHT.handled = false;
let result = uw::_Unwind_RaiseException(&mut INFLIGHT.uw_exception);
if result != uw::_URC_END_OF_STACK {
println!("Unwinding error: {}", result as u32);
}
assert!(result == uw::_URC_END_OF_STACK);
// INFLIGHT.backtrace_size = 0;
// let _result = _Unwind_ForcedUnwind(&mut INFLIGHT.uw_exception,
// uncaught_exception, ptr::null_mut());
print!("Uncaught exception");
loop {}
unreachable!()
}
#[export_name="__artiq_reraise"]
#[unwind(allowed)]
pub unsafe extern fn reraise() -> ! {
if INFLIGHT.handled {
raise(&INFLIGHT.exception.unwrap())
} else {
uw::_Unwind_Resume(&mut INFLIGHT.uw_exception)
}
}
// Stub implementations for the functions the panic_unwind crate expects to be provided.
// These all do nothing in libunwind, but aren't built for OR1K.
#[cfg(target_arch = "or1k")]
pub mod stubs {
#![allow(bad_style, unused_variables)]
use super::{uw, c_int};
#[export_name="_Unwind_GetIPInfo"]
pub unsafe extern fn _Unwind_GetIPInfo(ctx: *mut uw::_Unwind_Context,
ip_before_insn: *mut c_int) -> uw::_Unwind_Word {
*ip_before_insn = 0;
uw::_Unwind_GetIP(ctx)
}
#[export_name="_Unwind_GetTextRelBase"]
pub unsafe extern fn _Unwind_GetTextRelBase(ctx: *mut uw::_Unwind_Context) -> uw::_Unwind_Ptr {
unimplemented!()
}
#[export_name="_Unwind_GetDataRelBase"]
pub unsafe extern fn _Unwind_GetDataRelBase(ctx: *mut uw::_Unwind_Context) -> uw::_Unwind_Ptr {
unimplemented!()
}
}

68
firmware/libksupport/glue.c Executable file
View File

@ -0,0 +1,68 @@
#include <stdarg.h>
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <stdint.h>
struct slice {
void *ptr;
size_t len;
};
void send_to_core_log(struct slice str);
#define KERNELCPU_EXEC_ADDRESS 0x40800000
#define KERNELCPU_PAYLOAD_ADDRESS 0x40840000
#define KERNELCPU_LAST_ADDRESS 0x4fffffff
#define KSUPPORT_HEADER_SIZE 0x80
/* called by kernel */
double round(double x);
double round(double x)
{
union {double f; uint64_t i;} u = {x};
int e = u.i >> 52 & 0x7ff;
double y;
if (e >= 0x3ff+52)
return x;
if (u.i >> 63)
x = -x;
if (e < 0x3ff-1) {
/* we don't do it in ARTIQ */
/* raise inexact if x!=0 */
// FORCE_EVAL(x + 0x1p52);
return 0*u.f;
}
y = (double)(x + 0x1p52) - 0x1p52 - x;
if (y > 0.5)
y = y + x - 1;
else if (y <= -0.5)
y = y + x + 1;
else
y = y + x;
if (u.i >> 63)
y = -y;
return y;
}
/* called by kernel */
int core_log(const char *fmt, ...);
int core_log(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
size_t size = vsnprintf(NULL, 0, fmt, args);
char *buf = __builtin_alloca(size + 1);
va_end(args);
va_start(args, fmt);
vsnprintf(buf, size + 1, fmt, args);
va_end(args);
struct slice str = { buf, size };
send_to_core_log(str);
return 0;
}

59
firmware/libksupport/lib.rs Executable file
View File

@ -0,0 +1,59 @@
#![feature(lang_items, asm, libc, panic_unwind, unwind_attributes, global_allocator,
needs_panic_runtime)]
#![no_std]
extern crate unwind;
extern crate libc;
extern crate cslice;
#[macro_use]
extern crate board_misoc;
extern crate volatile_cell;
use cslice::CSlice;
use core::str;
#[no_mangle]
pub static mut now: u64 = 0;
pub mod eh;
#[no_mangle]
pub extern fn send_to_core_log(text: CSlice<u8>) {
match str::from_utf8(text.as_ref()) {
Ok(s) => print!("{}", s),
Err(_e) => println!("kernel send invalid utf8")
}
}
fn terminate(exception: &eh::Exception, backtrace: &mut [usize]) -> ! {
print!("Uncaught exception");
// at {}:{}: {}({})",
// str::from_utf8(exception.file.as_ref()).unwrap(),
// exception.line,
// str::from_utf8(exception.name.as_ref()).unwrap(),
// str::from_utf8(exception.message.as_ref()).unwrap());
loop {}
}
macro_rules! raise {
($name:expr, $message:expr, $param0:expr, $param1:expr, $param2:expr) => ({
use cslice::AsCSlice;
let exn = $crate::eh::Exception {
name: concat!("0:artiq.coredevice.exceptions.", $name).as_bytes().as_c_slice(),
file: file!().as_bytes().as_c_slice(),
line: line!(),
column: column!(),
// https://github.com/rust-lang/rfcs/pull/1719
function: "(Rust function)".as_bytes().as_c_slice(),
message: $message.as_bytes().as_c_slice(),
param: [$param0, $param1, $param2]
};
#[allow(unused_unsafe)]
unsafe { $crate::eh::raise(&exn) }
});
($name:expr, $message:expr) => ({
raise!($name, $message, 0, 0, 0)
});
}
pub mod rtio;

337
firmware/libksupport/rtio.rs Executable file
View File

@ -0,0 +1,337 @@
use core::ptr::{read_volatile, write_volatile};
use cslice::CSlice;
use board_misoc::csr;
use volatile_cell::VolatileCell;
pub const RTIO_O_STATUS_WAIT: u8 = 1;
pub const RTIO_O_STATUS_UNDERFLOW: u8 = 2;
pub const RTIO_O_STATUS_LINK_ERROR: u8 = 4;
pub const RTIO_I_STATUS_WAIT_EVENT: u8 = 1;
pub const RTIO_I_STATUS_OVERFLOW: u8 = 2;
pub const RTIO_I_STATUS_WAIT_STATUS: u8 = 4;
pub const RTIO_I_STATUS_LINK_ERROR: u8 = 8;
#[repr(C)]
struct RtioCmd {
cmd_channel: i32,
address: i32,
timestamp: i64,
data: i64
}
#[repr(C)]
struct RtioResponse {
status: VolatileCell<i32>,
data: VolatileCell<i32>,
timestamp: VolatileCell<u64>
}
pub const DMA_BASE: isize = 0x200000;
#[no_mangle]
pub extern fn rtio_init() {
unsafe {
csr::rtio_core::reset_write(1);
csr::rtio_core::reset_phy_write(1);
}
}
#[no_mangle]
pub extern fn rtio_get_counter() -> i64 {
unsafe {
csr::rtio::counter_update_write(1);
csr::rtio::counter_read() as i64
}
}
#[inline(always)]
pub unsafe fn rtio_o_data_write(offset: usize, data: u32) {
write_volatile(
csr::rtio::O_DATA_ADDR.offset((csr::rtio::O_DATA_SIZE - 1 - offset) as isize),
data);
}
#[inline(always)]
pub unsafe fn rtio_i_data_read(offset: usize) -> u32 {
read_volatile(
csr::rtio::I_DATA_ADDR.offset((csr::rtio::I_DATA_SIZE - 1 - offset) as isize))
}
#[inline(never)]
unsafe fn process_exceptional_status(timestamp: i64, channel: i32, status: u8) {
if status & RTIO_O_STATUS_WAIT != 0 {
while csr::rtio::o_status_read() & RTIO_O_STATUS_WAIT != 0 {}
}
if status & RTIO_O_STATUS_UNDERFLOW != 0 {
raise!("RTIOUnderflow",
"RTIO underflow at {0} mu, channel {1}, slack {2} mu",
timestamp, channel as i64, timestamp - rtio_get_counter());
}
if status & RTIO_O_STATUS_LINK_ERROR != 0 {
raise!("RTIOLinkError",
"RTIO output link error at {0} mu, channel {1}",
timestamp, channel as i64, 0);
}
}
#[no_mangle]
pub extern fn rtio_output_csr(timestamp: i64, channel: i32, addr: i32, data: i32) {
unsafe {
csr::rtio::chan_sel_write(channel as _);
// writing timestamp clears o_data
csr::rtio::timestamp_write(timestamp as u64);
csr::rtio::o_address_write(addr as _);
rtio_o_data_write(0, data as _);
csr::rtio::o_we_write(1);
let status = csr::rtio::o_status_read();
if status != 0 {
process_exceptional_status(timestamp, channel, status);
}
}
}
#[no_mangle]
pub extern fn rtio_output(timestamp: i64, channel: i32, address: i32, data: i32) {
unsafe {
let rtio_cmd: *mut RtioCmd = DMA_BASE as *mut _;
let rtio_response: *mut RtioResponse = (DMA_BASE+0x20) as *mut _;
// Clear status so we can observe response
(*rtio_response).status.set(0);
(*rtio_cmd).cmd_channel = (0<<24) | channel;
(*rtio_cmd).address = address;
(*rtio_cmd).timestamp = timestamp;
(*rtio_cmd).data = data as i64;
asm!("dmb");
asm!("sev");
let mut status;
loop {
status = (*rtio_response).status.get();
if status != 0 {break}
}
let status = status & !0x10000;
if status != 0 {process_exceptional_status(timestamp, channel, status as u8)}
}
}
#[no_mangle]
pub extern fn rtio_input_timestamp(timestamp: i64, channel: i32) -> u64 {
unsafe {
let rtio_cmd: *mut RtioCmd = DMA_BASE as *mut _;
let rtio_response: *mut RtioResponse = (DMA_BASE+0x20) as *mut _;
// Clear status so we can observe response
(*rtio_response).status.set(0);
(*rtio_cmd).cmd_channel = (1<<24) | channel;
(*rtio_cmd).timestamp = timestamp;
asm!("dmb");
asm!("sev");
let mut status;
loop {
status = (*rtio_response).status.get();
if status != 0 {break}
}
let status = status & !0x10000;
let status = status as u8;
if status & RTIO_I_STATUS_OVERFLOW != 0 {
csr::cri_con::selected_write(0);
csr::rtio::i_overflow_reset_write(1);
csr::cri_con::selected_write(1);
raise!("RTIOOverflow",
"RTIO input overflow on channel {0}",
channel as i64, 0, 0);
}
if status & RTIO_I_STATUS_WAIT_EVENT != 0 {
return !0
}
if status & RTIO_I_STATUS_LINK_ERROR != 0 {
raise!("RTIOLinkError",
"RTIO input link error on channel {0}",
channel as i64, 0, 0);
}
(*rtio_response).timestamp.get()
}
}
#[no_mangle]
pub extern fn output_wide(timestamp: i64, channel: i32, addr: i32, data: CSlice<i32>) {
unsafe {
csr::rtio::chan_sel_write(channel as _);
// writing timestamp clears o_data
csr::rtio::timestamp_write(timestamp as u64);
csr::rtio::o_address_write(addr as _);
for i in 0..data.len() {
rtio_o_data_write(i, data[i] as _)
}
csr::rtio::o_we_write(1);
let status = csr::rtio::o_status_read();
if status != 0 {
process_exceptional_status(timestamp, channel, status);
}
}
}
#[no_mangle]
pub extern fn rtio_input_timestamp_csr(timeout: i64, channel: i32) -> u64 {
unsafe {
csr::rtio::chan_sel_write(channel as _);
csr::rtio::timestamp_write(timeout as u64);
csr::rtio::i_request_write(1);
let mut status = RTIO_I_STATUS_WAIT_STATUS;
while status & RTIO_I_STATUS_WAIT_STATUS != 0 {
status = csr::rtio::i_status_read();
}
if status & RTIO_I_STATUS_OVERFLOW != 0 {
csr::rtio::i_overflow_reset_write(1);
raise!("RTIOOverflow",
"RTIO input overflow on channel {0}",
channel as i64, 0, 0);
}
if status & RTIO_I_STATUS_WAIT_EVENT != 0 {
return !0
}
if status & RTIO_I_STATUS_LINK_ERROR != 0 {
raise!("RTIOLinkError",
"RTIO input link error on channel {0}",
channel as i64, 0, 0);
}
csr::rtio::i_timestamp_read()
}
}
#[no_mangle]
pub extern fn rtio_input_data(channel: i32) -> i32 {
unsafe {
csr::rtio::chan_sel_write(channel as _);
csr::rtio::timestamp_write(0xffffffff_ffffffff);
csr::rtio::i_request_write(1);
let mut status = RTIO_I_STATUS_WAIT_STATUS;
while status & RTIO_I_STATUS_WAIT_STATUS != 0 {
status = csr::rtio::i_status_read();
}
if status & RTIO_I_STATUS_OVERFLOW != 0 {
csr::rtio::i_overflow_reset_write(1);
raise!("RTIOOverflow",
"RTIO input overflow on channel {0}",
channel as i64, 0, 0);
}
if status & RTIO_I_STATUS_LINK_ERROR != 0 {
raise!("RTIOLinkError",
"RTIO input link error on channel {0}",
channel as i64, 0, 0);
}
rtio_i_data_read(0) as i32
}
}
#[no_mangle]
pub extern fn rtio_input_data_timeout(timeout: i64, channel: i32) -> i32 {
unsafe {
csr::rtio::chan_sel_write(channel as _);
csr::rtio::timestamp_write(timeout as u64);
csr::rtio::i_request_write(1);
let mut status = RTIO_I_STATUS_WAIT_STATUS;
while status & RTIO_I_STATUS_WAIT_STATUS != 0 {
status = csr::rtio::i_status_read();
}
if status & RTIO_I_STATUS_OVERFLOW != 0 {
csr::rtio::i_overflow_reset_write(1);
raise!("RTIOOverflow",
"RTIO input overflow on channel {0}",
channel as i64, 0, 0);
}
if status & RTIO_I_STATUS_WAIT_EVENT != 0 {
return !0
}
rtio_i_data_read(0) as i32
}
}
#[repr(C)]
pub struct TimestampData {
timestamp: u64,
data: i32,
}
pub extern fn input_timestamp_data(channel: i32) -> TimestampData {
unsafe {
csr::rtio::chan_sel_write(channel as _);
csr::rtio::timestamp_write(0xffffffff_ffffffff);
csr::rtio::i_request_write(1);
let mut status = RTIO_I_STATUS_WAIT_STATUS;
while status & RTIO_I_STATUS_WAIT_STATUS != 0 {
status = csr::rtio::i_status_read();
}
if status & RTIO_I_STATUS_OVERFLOW != 0 {
csr::rtio::i_overflow_reset_write(1);
println!("RTIO input overflow on channel {0}",channel as i64);
}
TimestampData {
timestamp: csr::rtio::i_timestamp_read(),
data: rtio_i_data_read(0) as i32
}
}
}
#[cfg(has_rtio_log)]
pub fn log(timestamp: i64, data: &[u8]) {
unsafe {
csr::rtio::chan_sel_write(csr::CONFIG_RTIO_LOG_CHANNEL);
csr::rtio::timestamp_write(timestamp as u64);
let mut word: u32 = 0;
for i in 0..data.len() {
word <<= 8;
word |= data[i] as u32;
if i % 4 == 3 {
rtio_o_data_write(0, word);
csr::rtio::o_we_write(1);
word = 0;
}
}
if word != 0 {
rtio_o_data_write(0, word);
csr::rtio::o_we_write(1);
}
}
}
#[cfg(not(has_rtio_log))]
pub fn log(_timestamp: i64, _data: &[u8]) {
unimplemented!("not(has_rtio_log)")
}

View File

@ -0,0 +1,15 @@
[package]
authors = ["The Rust Project Developers"]
name = "unwind"
version = "0.0.0"
build = "build.rs"
[lib]
name = "unwind"
path = "lib.rs"
test = false
bench = false
doc = false
[dependencies]
libc = { default-features = false }

41
firmware/libunwind-rs/build.rs Executable file
View File

@ -0,0 +1,41 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::env;
fn main() {
println!("cargo:rustc-cfg=cargobuild");
let target = env::var("TARGET").expect("TARGET was not set");
if target.contains("linux") {
if target.contains("musl") && !target.contains("mips") {
println!("cargo:rustc-link-lib=static=unwind");
} else if !target.contains("android") {
println!("cargo:rustc-link-lib=gcc_s");
}
} else if target.contains("freebsd") {
println!("cargo:rustc-link-lib=gcc_s");
} else if target.contains("rumprun") {
println!("cargo:rustc-link-lib=unwind");
} else if target.contains("netbsd") {
println!("cargo:rustc-link-lib=gcc_s");
} else if target.contains("openbsd") {
println!("cargo:rustc-link-lib=gcc");
} else if target.contains("bitrig") {
println!("cargo:rustc-link-lib=c++abi");
} else if target.contains("dragonfly") {
println!("cargo:rustc-link-lib=gcc_pic");
} else if target.contains("windows-gnu") {
println!("cargo:rustc-link-lib=gcc_eh");
} else if target.contains("fuchsia") {
println!("cargo:rustc-link-lib=unwind");
}
}

29
firmware/libunwind-rs/lib.rs Executable file
View File

@ -0,0 +1,29 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![no_std]
#![crate_name = "unwind"]
#![crate_type = "rlib"]
#![unstable(feature = "panic_unwind", issue = "32837")]
#![deny(warnings)]
#![feature(cfg_target_vendor)]
#![feature(staged_api)]
#![feature(unwind_attributes)]
#![cfg_attr(not(target_env = "msvc"), feature(libc))]
#[cfg(not(target_env = "msvc"))]
extern crate libc;
#[cfg(not(target_env = "msvc"))]
mod libunwind;
#[cfg(not(target_env = "msvc"))]
pub use libunwind::*;

View File

@ -0,0 +1,273 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![allow(bad_style)]
macro_rules! cfg_if {
( $( if #[cfg( $meta:meta )] { $($it1:item)* } else { $($it2:item)* } )* ) =>
( $( $( #[cfg($meta)] $it1)* $( #[cfg(not($meta))] $it2)* )* )
}
use libc::{c_int, c_void, uintptr_t};
#[repr(C)]
#[derive(Copy, Clone, PartialEq)]
pub enum _Unwind_Reason_Code {
_URC_NO_REASON = 0,
_URC_FOREIGN_EXCEPTION_CAUGHT = 1,
_URC_FATAL_PHASE2_ERROR = 2,
_URC_FATAL_PHASE1_ERROR = 3,
_URC_NORMAL_STOP = 4,
_URC_END_OF_STACK = 5,
_URC_HANDLER_FOUND = 6,
_URC_INSTALL_CONTEXT = 7,
_URC_CONTINUE_UNWIND = 8,
_URC_FAILURE = 9, // used only by ARM EHABI
}
pub use self::_Unwind_Reason_Code::*;
pub type _Unwind_Exception_Class = u64;
pub type _Unwind_Word = uintptr_t;
pub type _Unwind_Ptr = uintptr_t;
pub type _Unwind_Trace_Fn = extern "C" fn(ctx: *mut _Unwind_Context, arg: *mut c_void)
-> _Unwind_Reason_Code;
#[cfg(target_arch = "x86")]
pub const unwinder_private_data_size: usize = 5;
#[cfg(target_arch = "x86_64")]
pub const unwinder_private_data_size: usize = 6;
#[cfg(all(target_arch = "arm", not(target_os = "ios")))]
pub const unwinder_private_data_size: usize = 20;
#[cfg(all(target_arch = "arm", target_os = "ios"))]
pub const unwinder_private_data_size: usize = 5;
#[cfg(target_arch = "aarch64")]
pub const unwinder_private_data_size: usize = 2;
#[cfg(target_arch = "mips")]
pub const unwinder_private_data_size: usize = 2;
#[cfg(target_arch = "mips64")]
pub const unwinder_private_data_size: usize = 2;
#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))]
pub const unwinder_private_data_size: usize = 2;
#[cfg(target_arch = "s390x")]
pub const unwinder_private_data_size: usize = 2;
#[cfg(target_arch = "sparc64")]
pub const unwinder_private_data_size: usize = 2;
#[cfg(target_os = "emscripten")]
pub const unwinder_private_data_size: usize = 20;
#[repr(C)]
pub struct _Unwind_Exception {
pub exception_class: _Unwind_Exception_Class,
pub exception_cleanup: _Unwind_Exception_Cleanup_Fn,
pub private: [_Unwind_Word; unwinder_private_data_size],
}
pub enum _Unwind_Context {}
pub type _Unwind_Exception_Cleanup_Fn = extern "C" fn(unwind_code: _Unwind_Reason_Code,
exception: *mut _Unwind_Exception);
extern "C" {
#[unwind]
pub fn _Unwind_Resume(exception: *mut _Unwind_Exception) -> !;
pub fn _Unwind_DeleteException(exception: *mut _Unwind_Exception);
pub fn _Unwind_GetLanguageSpecificData(ctx: *mut _Unwind_Context) -> *mut c_void;
pub fn _Unwind_GetRegionStart(ctx: *mut _Unwind_Context) -> _Unwind_Ptr;
pub fn _Unwind_GetTextRelBase(ctx: *mut _Unwind_Context) -> _Unwind_Ptr;
pub fn _Unwind_GetDataRelBase(ctx: *mut _Unwind_Context) -> _Unwind_Ptr;
}
cfg_if! {
if #[cfg(not(any(all(target_os = "android", target_arch = "arm"),
all(target_os = "linux", target_arch = "arm"))))] {
// Not ARM EHABI
#[repr(C)]
#[derive(Copy, Clone, PartialEq)]
pub enum _Unwind_Action {
_UA_SEARCH_PHASE = 1,
_UA_CLEANUP_PHASE = 2,
_UA_HANDLER_FRAME = 4,
_UA_FORCE_UNWIND = 8,
_UA_END_OF_STACK = 16,
}
pub use self::_Unwind_Action::*;
extern "C" {
pub fn _Unwind_GetGR(ctx: *mut _Unwind_Context, reg_index: c_int) -> _Unwind_Word;
pub fn _Unwind_SetGR(ctx: *mut _Unwind_Context, reg_index: c_int, value: _Unwind_Word);
pub fn _Unwind_GetIP(ctx: *mut _Unwind_Context) -> _Unwind_Word;
pub fn _Unwind_SetIP(ctx: *mut _Unwind_Context, value: _Unwind_Word);
pub fn _Unwind_GetIPInfo(ctx: *mut _Unwind_Context, ip_before_insn: *mut c_int)
-> _Unwind_Word;
pub fn _Unwind_FindEnclosingFunction(pc: *mut c_void) -> *mut c_void;
}
} else {
// ARM EHABI
#[repr(C)]
#[derive(Copy, Clone, PartialEq)]
pub enum _Unwind_State {
_US_VIRTUAL_UNWIND_FRAME = 0,
_US_UNWIND_FRAME_STARTING = 1,
_US_UNWIND_FRAME_RESUME = 2,
_US_ACTION_MASK = 3,
_US_FORCE_UNWIND = 8,
_US_END_OF_STACK = 16,
}
pub use self::_Unwind_State::*;
#[repr(C)]
enum _Unwind_VRS_Result {
_UVRSR_OK = 0,
_UVRSR_NOT_IMPLEMENTED = 1,
_UVRSR_FAILED = 2,
}
#[repr(C)]
enum _Unwind_VRS_RegClass {
_UVRSC_CORE = 0,
_UVRSC_VFP = 1,
_UVRSC_FPA = 2,
_UVRSC_WMMXD = 3,
_UVRSC_WMMXC = 4,
}
use self::_Unwind_VRS_RegClass::*;
#[repr(C)]
enum _Unwind_VRS_DataRepresentation {
_UVRSD_UINT32 = 0,
_UVRSD_VFPX = 1,
_UVRSD_FPAX = 2,
_UVRSD_UINT64 = 3,
_UVRSD_FLOAT = 4,
_UVRSD_DOUBLE = 5,
}
use self::_Unwind_VRS_DataRepresentation::*;
pub const UNWIND_POINTER_REG: c_int = 12;
pub const UNWIND_IP_REG: c_int = 15;
extern "C" {
fn _Unwind_VRS_Get(ctx: *mut _Unwind_Context,
regclass: _Unwind_VRS_RegClass,
regno: _Unwind_Word,
repr: _Unwind_VRS_DataRepresentation,
data: *mut c_void)
-> _Unwind_VRS_Result;
fn _Unwind_VRS_Set(ctx: *mut _Unwind_Context,
regclass: _Unwind_VRS_RegClass,
regno: _Unwind_Word,
repr: _Unwind_VRS_DataRepresentation,
data: *mut c_void)
-> _Unwind_VRS_Result;
}
// On Android or ARM/Linux, these are implemented as macros:
pub unsafe fn _Unwind_GetGR(ctx: *mut _Unwind_Context, reg_index: c_int) -> _Unwind_Word {
let mut val: _Unwind_Word = 0;
_Unwind_VRS_Get(ctx, _UVRSC_CORE, reg_index as _Unwind_Word, _UVRSD_UINT32,
&mut val as *mut _ as *mut c_void);
val
}
pub unsafe fn _Unwind_SetGR(ctx: *mut _Unwind_Context, reg_index: c_int, value: _Unwind_Word) {
let mut value = value;
_Unwind_VRS_Set(ctx, _UVRSC_CORE, reg_index as _Unwind_Word, _UVRSD_UINT32,
&mut value as *mut _ as *mut c_void);
}
pub unsafe fn _Unwind_GetIP(ctx: *mut _Unwind_Context)
-> _Unwind_Word {
let val = _Unwind_GetGR(ctx, UNWIND_IP_REG);
(val & !1) as _Unwind_Word
}
pub unsafe fn _Unwind_SetIP(ctx: *mut _Unwind_Context,
value: _Unwind_Word) {
// Propagate thumb bit to instruction pointer
let thumb_state = _Unwind_GetGR(ctx, UNWIND_IP_REG) & 1;
let value = value | thumb_state;
_Unwind_SetGR(ctx, UNWIND_IP_REG, value);
}
pub unsafe fn _Unwind_GetIPInfo(ctx: *mut _Unwind_Context,
ip_before_insn: *mut c_int)
-> _Unwind_Word {
*ip_before_insn = 0;
_Unwind_GetIP(ctx)
}
// This function also doesn't exist on Android or ARM/Linux, so make it a no-op
pub unsafe fn _Unwind_FindEnclosingFunction(pc: *mut c_void) -> *mut c_void {
pc
}
}
if #[cfg(not(all(target_os = "ios", target_arch = "arm")))] {
// Not 32-bit iOS
extern "C" {
#[unwind]
pub fn _Unwind_RaiseException(exception: *mut _Unwind_Exception) -> _Unwind_Reason_Code;
pub fn _Unwind_Backtrace(trace: _Unwind_Trace_Fn,
trace_argument: *mut c_void)
-> _Unwind_Reason_Code;
}
} else {
// 32-bit iOS uses SjLj and does not provide _Unwind_Backtrace()
extern "C" {
#[unwind]
pub fn _Unwind_SjLj_RaiseException(e: *mut _Unwind_Exception) -> _Unwind_Reason_Code;
}
#[inline]
pub unsafe fn _Unwind_RaiseException(exc: *mut _Unwind_Exception) -> _Unwind_Reason_Code {
_Unwind_SjLj_RaiseException(exc)
}
}
} // cfg_if!
#[cfg_attr(any(all(target_os = "linux", not(target_env = "musl")),
target_os = "freebsd",
target_os = "solaris",
target_os = "haiku",
all(target_os = "linux",
target_env = "musl",
not(target_arch = "x86"),
not(target_arch = "x86_64"))),
link(name = "gcc_s"))]
#[cfg_attr(all(target_os = "linux",
target_env = "musl",
any(target_arch = "x86", target_arch = "x86_64"),
not(test)),
link(name = "unwind", kind = "static"))]
#[cfg_attr(target_os = "fuchsia",
link(name = "unwind"))]
#[cfg_attr(any(target_os = "android", target_os = "openbsd"),
link(name = "gcc"))]
#[cfg_attr(all(target_os = "netbsd", not(target_vendor = "rumprun")),
link(name = "gcc"))]
#[cfg_attr(all(target_os = "netbsd", target_vendor = "rumprun"),
link(name = "unwind"))]
#[cfg_attr(target_os = "dragonfly",
link(name = "gcc_pic"))]
#[cfg_attr(target_os = "bitrig",
link(name = "c++abi"))]
#[cfg_attr(all(target_os = "windows", target_env = "gnu"),
link(name = "gcc_eh"))]
#[cfg(not(cargobuild))]
extern "C" {}

20
firmware/runtime/Cargo.toml Executable file
View File

@ -0,0 +1,20 @@
[package]
name = "runtime"
version = "0.1.0"
authors = ["cjb <cjb>"]
[build-dependencies]
cc = "1.0"
[dependencies]
board_misoc = { path = "../libboard_misoc"}
ksupport = { path = "../libksupport"}
volatile_cell = "*"
[lib]
path="main.rs"
name = "runtime"
crate-type = ["staticlib"]

27
firmware/runtime/Makefile Executable file
View File

@ -0,0 +1,27 @@
include ../include/generated/variables.mak
include $(MISOC_DIRECTORY)/software/common.mak
LDFLAGS += --eh-frame-hdr \
-L../libm \
-L../libprintf \
-L../libunwind \
--start-group
RUSTFLAGS += -Cpanic=unwind
all:: runtime.bin
.PHONY: $(RUSTOUT)/libruntime.a
$(RUSTOUT)/libruntime.a:
$(cargo) --manifest-path $(RUNTIME_DIRECTORY)/Cargo.toml
runtime.elf: $(RUSTOUT)/libruntime.a $(RUNTIME_DIRECTORY)/exp.a ../libunwind/libunwind-bare.a
$(link) -T $(RUNTIME_DIRECTORY)/lscript.ld -lprintf-float -lm $(BUILDINC_DIRECTORY)/../libbase/libbase.a -lunwind-bare --target2=abs
%.bin: %.elf
$(objcopy) -O binary -R .uncachable
%.o: $(RUNTIME_DIRECTORY)/%.c
$(compile)

17
firmware/runtime/build.rs Executable file
View File

@ -0,0 +1,17 @@
extern crate cc;
fn main() {
let startup_path = "startup.S";
let table_path = "translation_table.S";
println!("cargo:rerun-if-changed={}", startup_path);
println!("cargo:rerun-if-changed={}", table_path);
cc::Build::new()
.file(startup_path)
.compile("startup");
cc::Build::new()
.file(table_path)
.compile("translation_table");
}

68
firmware/runtime/glue.c Executable file
View File

@ -0,0 +1,68 @@
#include <stdarg.h>
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <stdint.h>
struct slice {
void *ptr;
size_t len;
};
void send_to_core_log(struct slice str);
#define KERNELCPU_EXEC_ADDRESS 0x40800000
#define KERNELCPU_PAYLOAD_ADDRESS 0x40840000
#define KERNELCPU_LAST_ADDRESS 0x4fffffff
#define KSUPPORT_HEADER_SIZE 0x80
/* called by kernel */
double round(double x);
double round(double x)
{
union {double f; uint64_t i;} u = {x};
int e = u.i >> 52 & 0x7ff;
double y;
if (e >= 0x3ff+52)
return x;
if (u.i >> 63)
x = -x;
if (e < 0x3ff-1) {
/* we don't do it in ARTIQ */
/* raise inexact if x!=0 */
// FORCE_EVAL(x + 0x1p52);
return 0*u.f;
}
y = (double)(x + 0x1p52) - 0x1p52 - x;
if (y > 0.5)
y = y + x - 1;
else if (y <= -0.5)
y = y + x + 1;
else
y = y + x;
if (u.i >> 63)
y = -y;
return y;
}
/* called by kernel */
int core_log(const char *fmt, ...);
int core_log(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
size_t size = vsnprintf(NULL, 0, fmt, args);
char *buf = __builtin_alloca(size + 1);
va_end(args);
va_start(args, fmt);
vsnprintf(buf, size + 1, fmt, args);
va_end(args);
struct slice str = { buf, size };
send_to_core_log(str);
return 0;
}

83
firmware/runtime/lscript.ld Executable file
View File

@ -0,0 +1,83 @@
ENTRY(_boot)
MEMORY {
runtime (RWX) : ORIGIN = 0x100000, LENGTH = 0x1FF00000
}
SECTIONS
{
.text :
{
*(.vectors)
*(.text .text.*)
} > runtime
.ARM.extab : {
*(.ARM.extab*)
*(.gnu.linkonce.armextab.*)
} > runtime
.ARM.exidx : {
__exidx_start = .;
*(.ARM.exidx*)
*(.gnu.linkonce.armexidix.*.*)
__exidx_end = .;
} > runtime
/* https://sourceware.org/bugzilla/show_bug.cgi?id=20475 */
.got :
{
_GLOBAL_OFFSET_TABLE_ = .;
*(.got)
} > runtime
.got.plt :
{
*(.got.plt)
} > runtime
.rodata ALIGN(4):
{
*(.rodata .rodata.*)
} > runtime
.data ALIGN(4):
{
*(.data .data.*)
} > runtime
.bss ALIGN(4) :
{
_fbss = .;
*(.bss .bss.*)
_ebss = .;
} > runtime
.stack ALIGN(0x1000) :
{
. += 0x4000;
_fstack = . - 4;
} > runtime
.stack2 ALIGN(0x1000) :
{
. += 0x4000;
_fstack2 = . - 4;
} > runtime
.mmu_tbl (ALIGN(16384)) :
{
__mmu_tbl_start = .;
*(.mmu_tbl)
__mmu_tbl_end = .;
} > runtime
.uncachable ALIGN(0x100000) :
{
__uncachable_start = .;
*(.uncachable)
__uncachable_end = .;
} > runtime
}

92
firmware/runtime/main.rs Executable file
View File

@ -0,0 +1,92 @@
#![no_std]
#![feature(panic_implementation, lang_items, asm)]
#[allow(unused_imports)]
#[macro_use]
extern crate board_misoc;
extern crate ksupport;
extern {
// Statically linked python module entry point
fn __modinit__();
}
#[inline(never)]
pub fn get_cycle_counter() -> u32 {
let n: u32;
unsafe{asm!("mrc p15, 0, $0, c9, c13, 0": "=r"(n) ::: "volatile");}
n
}
use board_misoc::csr;
unsafe fn crg_init() {
csr::rtio_crg::pll_reset_write(1);
csr::rtio_crg::pll_reset_write(0);
println!("Waiting on PLL lock ... ");
while csr::rtio_crg::pll_locked_read() == 0 {}
println!("PLL locked.\n");
}
#[no_mangle]
pub extern "C" fn main() -> ! {
println!("");
println!("");
println!("-----------------");
println!("Artiq-Zynq lashup");
unsafe{
csr::dma::addr_base_write(0x200000 as u32);
csr::cri_con::selected_write(1);
crg_init();
}
println!("Starting kernel...");
println!("--");
unsafe{ __modinit__() }
println!("--");
println!("Kernel finished");
loop {}
}
#[no_mangle]
pub extern "C" fn data_abort_handler(abort_addr: u32, access_addr: u32, data_fault_status: u32) -> ! {
println!("!!! Data abort");
println!("PC = {:08x}", abort_addr-0x8);
println!("Access addr = {:08x}", access_addr);
println!("DFSR = {:08x}", data_fault_status);
loop {}
}
#[no_mangle]
pub extern "C" fn undefined_instruction_handler(abort_addr: u32) -> ! {
println!("!!! Undefined instruction");
println!("PC = {:08x}", abort_addr-0x4);
loop {}
}
#[no_mangle]
pub extern "C" fn irq_handler() -> ! {
println!("!!! IRQ");
loop {}
}
#[no_mangle]
#[lang = "eh_personality"] pub extern fn eh_personality() {}
use core::panic::PanicInfo;
// This function is called on panic (including failed assertions, ...).
#[panic_implementation]
#[no_mangle]
pub fn panic(info: &PanicInfo) -> ! {
println!("kernel {}", info);
loop {}
}

320
firmware/runtime/startup.S Executable file
View File

@ -0,0 +1,320 @@
.global _boot
.global _start
.global data_abort_handler
.global _vector_table
.global MMUTable
.set vector_base, _vector_table
.set TblBase, MMUTable
.set UncachableStart, __uncachable_start
.set UncachableEnd, __uncachable_end
.set CRValMmuCac, 0b01000000000101 /* Enable IDC, and MMU */
.set PSS_SLCR_BASE_ADDR, 0xF8000000
.set PSS_L2CC_BASE_ADDR, 0xF8F02000
.set L2CCWay, (PSS_L2CC_BASE_ADDR + 0x077C) /*(PSS_L2CC_BASE_ADDR + PSS_L2CC_CACHE_INVLD_WAY_OFFSET)*/
.set L2CCSync, (PSS_L2CC_BASE_ADDR + 0x0730) /*(PSS_L2CC_BASE_ADDR + PSS_L2CC_CACHE_SYNC_OFFSET)*/
.set L2CCCrtl, (PSS_L2CC_BASE_ADDR + 0x0100) /*(PSS_L2CC_BASE_ADDR + PSS_L2CC_CNTRL_OFFSET)*/
.set L2CCAuxCrtl, (PSS_L2CC_BASE_ADDR + 0x0104) /*(PSS_L2CC_BASE_ADDR + XPSS_L2CC_AUX_CNTRL_OFFSET)*/
.set L2CCTAGLatReg, (PSS_L2CC_BASE_ADDR + 0x0108) /*(PSS_L2CC_BASE_ADDR + XPSS_L2CC_TAG_RAM_CNTRL_OFFSET)*/
.set L2CCDataLatReg, (PSS_L2CC_BASE_ADDR + 0x010C) /*(PSS_L2CC_BASE_ADDR + XPSS_L2CC_DATA_RAM_CNTRL_OFFSET)*/
.set L2CCIntClear, (PSS_L2CC_BASE_ADDR + 0x0220) /*(PSS_L2CC_BASE_ADDR + XPSS_L2CC_IAR_OFFSET)*/
.set L2CCIntRaw, (PSS_L2CC_BASE_ADDR + 0x021C) /*(PSS_L2CC_BASE_ADDR + XPSS_L2CC_ISR_OFFSET)*/
.set L2CCAuxControl, 0x72360000 /* Enable all prefetching, Cache replacement policy, Parity enable,
Event monitor bus enable and Way Size (64 KB) */
.set L2CCControl, 0x01 /* Enable L2CC */
.set L2CCTAGLatency, 0x0111 /* latency for TAG RAM */
.set L2CCDataLatency, 0x0121 /* latency for DATA RAM */
.set SLCRlockReg, (PSS_SLCR_BASE_ADDR + 0x04) /*(PSS_SLCR_BASE_ADDR + XPSS_SLCR_LOCK_OFFSET)*/
.set SLCRUnlockReg, (PSS_SLCR_BASE_ADDR + 0x08) /*(PSS_SLCR_BASE_ADDR + XPSS_SLCR_UNLOCK_OFFSET)*/
.set SLCRL2cRamReg, (PSS_SLCR_BASE_ADDR + 0xA1C) /*(PSS_SLCR_BASE_ADDR + XPSS_SLCR_L2C_RAM_OFFSET)*/
.set SLCRlockKey, 0x767B /* SLCR lock key */
.set SLCRUnlockKey, 0xDF0D /* SLCR unlock key */
.set SLCRL2cRamConfig, 0x00020202 /* SLCR L2C ram configuration */
.org 0
.text
.globl _vector_table
.section .vectors
_vector_table:
B _boot
B Undefined
B SVCHandler
B PrefetchAbortHandler
B DataAbortHandler
NOP /* Placeholder for address exception vector*/
B IRQHandler
B FIQHandler
.text
_boot:
// Read MPIDR to determine processor id
mrc p15,0,r0,c0,c0,5
and r0, r0, 0x3
cmp r0, 0
// processor 0 -> p0_boot
// processor 1 waits for interrupt, then goes via p1_boot
beq p0_start
ldr r13,.Lstack2 /* stack address */
p1_loop:
wfi
b p1_loop
p0_start:
/* set VBAR to the _vector_table address in linker script */
ldr r0, =vector_base
mcr p15, 0, r0, c12, c0, 0
/*invalidate scu*/
ldr r7, =0xf8f0000c
ldr r6, =0xffff
str r6, [r7]
/* Invalidate caches and TLBs */
mov r0,#0 /* r0 = 0 */
mcr p15, 0, r0, c8, c7, 0 /* invalidate TLBs */
mcr p15, 0, r0, c7, c5, 0 /* invalidate icache */
mcr p15, 0, r0, c7, c5, 6 /* Invalidate branch predictor array */
bl invalidate_dcache /* invalidate dcache */
/* Disable MMU, if enabled */
mrc p15, 0, r0, c1, c0, 0 /* read CP15 register 1 */
bic r0, r0, #0x1 /* clear bit 0 */
mcr p15, 0, r0, c1, c0, 0 /* write value back */
/* Mark the a section of DDR as uncacheable */
ldr r3, =UncachableStart
ldr r4, =UncachableEnd
ldr r0, =TblBase /* MMU Table address in memory */
ldr r2, =0x11de2 /* S=b1 TEX=b001 AP=b11, Domain=b1111, C=b0, B=b0 */
lsr r5, r3, #18 // Calculate table offset
add r0, r0, r5 // Address of first table entry to modify
uncacheable_loop:
add r5, r3, r2
str r5, [r0] // write the entry to MMU table
add r0, r0, #0x4 // next entry in the table
add r3, r3, #0x100000 // next section
cmp r3, r4
blt uncacheable_loop
/*set scu enable bit in scu*/
ldr r7, =0xf8f00000
ldr r0, [r7]
orr r0, r0, #0x1
str r0, [r7]
// enable MMU and cache
ldr r0,=TblBase /* Load MMU translation table base */
orr r0, r0, #0x5B /* Outer-cacheable, WB */
mcr p15, 0, r0, c2, c0, 0 /* TTB0 */
mvn r0,#0 /* Load MMU domains -- all ones=manager */
mcr p15,0,r0,c3,c0,0
// Enable mmu, icache and dcache
ldr r0,=CRValMmuCac
mcr p15,0,r0,c1,c0,0 /* Enable cache and MMU */
dsb /* dsb allow the MMU to start up */
isb /* isb flush prefetch buffer */
/* Write to ACTLR */
mrc p15, 0, r0, c1, c0, 1 /* Read ACTLR*/
orr r0, r0, #(0x01 << 6) /* set SMP bit */
orr r0, r0, #(0x01 ) /* Cache/TLB maintenance broadcast */
mcr p15, 0, r0, c1, c0, 1 /* Write ACTLR*/
/* Invalidate L2 Cache and enable L2 Cache*/
ldr r0,=L2CCCrtl /* Load L2CC base address base + control register */
mov r1, #0 /* force the disable bit */
str r1, [r0] /* disable the L2 Caches */
ldr r0,=L2CCAuxCrtl /* Load L2CC base address base + Aux control register */
ldr r1,[r0] /* read the register */
ldr r2,=L2CCAuxControl /* set the default bits */
orr r1,r1,r2
str r1, [r0] /* store the Aux Control Register */
ldr r0,=L2CCTAGLatReg /* Load L2CC base address base + TAG Latency address */
ldr r1,=L2CCTAGLatency /* set the latencies for the TAG*/
str r1, [r0] /* store the TAG Latency register Register */
ldr r0,=L2CCDataLatReg /* Load L2CC base address base + Data Latency address */
ldr r1,=L2CCDataLatency /* set the latencies for the Data*/
str r1, [r0] /* store the Data Latency register Register */
ldr r0,=L2CCWay /* Load L2CC base address base + way register*/
ldr r2, =0xFFFF
str r2, [r0] /* force invalidate */
ldr r0,=L2CCSync /* need to poll 0x730, PSS_L2CC_CACHE_SYNC_OFFSET */
/* Load L2CC base address base + sync register*/
/* poll for completion */
Sync: ldr r1, [r0]
cmp r1, #0
bne Sync
ldr r0,=L2CCIntRaw /* clear pending interrupts */
ldr r1,[r0]
ldr r0,=L2CCIntClear
str r1,[r0]
ldr r0,=SLCRUnlockReg /* Load SLCR base address base + unlock register */
ldr r1,=SLCRUnlockKey /* set unlock key */
str r1, [r0] /* Unlock SLCR */
ldr r0,=SLCRL2cRamReg /* Load SLCR base address base + l2c Ram Control register */
ldr r1,=SLCRL2cRamConfig /* set the configuration value */
str r1, [r0] /* store the L2c Ram Control Register */
ldr r0,=SLCRlockReg /* Load SLCR base address base + lock register */
ldr r1,=SLCRlockKey /* set lock key */
str r1, [r0] /* lock SLCR */
ldr r0,=L2CCCrtl /* Load L2CC base address base + control register */
ldr r1,[r0] /* read the register */
mov r2, #L2CCControl /* set the enable bit */
orr r1,r1,r2
str r1, [r0] /* enable the L2 Caches */
mov r0,r0
// Enable CP11 and CP10 access from all processor modes
mrc p15, 0, r0, c1, c0, 2 // Read CPACR
orr r0, r0, (0b1111<<20)
mcr p15, 0, r0, c1, c0, 2
/* enable vfp */
vmrs r1, fpexc
orr r1,r1, (1<<30)
vmsr fpexc, r1
mrc p15,0,r0,c1,c0,0 /* flow prediction enable */
orr r0, r0, #(0x01 << 11) /* #0x8000 */
mcr p15,0,r0,c1,c0,0
mrc p15,0,r0,c1,c0,1 /* read Auxiliary Control Register */
orr r0, r0, #(0x1 << 2) /* enable Dside prefetch */
orr r0, r0, #(0x1 << 1) /* enable L2 Prefetch hint */
mcr p15,0,r0,c1,c0,1 /* write Auxiliary Control Register */
mrs r0, cpsr /* get the current PSR */
bic r0, r0, #0x100 /* enable asynchronous abort exception */
msr cpsr_xsf, r0
// Enable and reset cycle counter
mov r0, 0b101
mcr p15, 0, r0, c9, c12, 0
.Lenclsbss:
/* clear bss */
ldr r1,.Lbss_start /* calculate beginning of the BSS */
ldr r2,.Lbss_end /* calculate end of the BSS */
.Lloop_bss:
cmp r1,r2
bge .Lenclbss /* If no BSS, no clearing required */
str r0, [r1], #4
b .Lloop_bss
.Lenclbss:
/* set stack pointer */
ldr r13,.Lstack /* stack address */
bl main
loop:
b loop
Undefined:
ldr r13, .Lstack
mov r0, lr // address of undefined instruction +8
b undefined_instruction_handler
SVCHandler:
b SVCHandler
PrefetchAbortHandler:
b PrefetchAbortHandler
DataAbortHandler:
ldr r13, .Lstack
mov r0, lr // address of aborted instruction +8
mrc p15, 0, r1, c6, c0, 0 // Read DFAR
mrc p15, 0, r2, c5, c0, 0 // Read DFSR
b data_abort_handler
IRQHandler:
ldr r13, .Lstack
b irq_handler
FIQHandler:
b FIQHandler
invalidate_dcache:
mrc p15, 1, r0, c0, c0, 1 /* read CLIDR */
ands r3, r0, #0x7000000
mov r3, r3, lsr #23 /* cache level value (naturally aligned) */
beq finished
mov r10, #0 /* start with level 0 */
loop1:
add r2, r10, r10, lsr #1 /* work out 3xcachelevel */
mov r1, r0, lsr r2 /* bottom 3 bits are the Cache type for this level */
and r1, r1, #7 /* get those 3 bits alone */
cmp r1, #2
blt skip /* no cache or only instruction cache at this level */
mcr p15, 2, r10, c0, c0, 0 /* write the Cache Size selection register */
isb /* isb to sync the change to the CacheSizeID reg */
mrc p15, 1, r1, c0, c0, 0 /* reads current Cache Size ID register */
and r2, r1, #7 /* extract the line length field */
add r2, r2, #4 /* add 4 for the line length offset (log2 16 bytes) */
ldr r4, =0x3ff
ands r4, r4, r1, lsr #3 /* r4 is the max number on the way size (right aligned) */
clz r5, r4 /* r5 is the bit position of the way size increment */
ldr r7, =0x7fff
ands r7, r7, r1, lsr #13 /* r7 is the max number of the index size (right aligned) */
loop2:
mov r9, r4 /* r9 working copy of the max way size (right aligned) */
loop3:
orr r11, r10, r9, lsl r5 /* factor in the way number and cache number into r11 */
orr r11, r11, r7, lsl r2 /* factor in the index number */
mcr p15, 0, r11, c7, c6, 2 /* invalidate by set/way */
subs r9, r9, #1 /* decrement the way number */
bge loop3
subs r7, r7, #1 /* decrement the index */
bge loop2
skip:
add r10, r10, #2 /* increment the cache number */
cmp r3, r10
bgt loop1
finished:
mov r10, #0 /* swith back to cache level 0 */
mcr p15, 2, r10, c0, c0, 0 /* select current cache level in cssr */
dsb
isb
bx lr
.Lbss_start:
.long _fbss
.Lbss_end:
.long _ebss
.Lstack:
.long _fstack
.Lstack2:
.long _fstack2

View File

@ -0,0 +1,185 @@
/*****************************************************************************/
/**
* @file translation_table.s
*
* @addtogroup a9_boot_code
* @{
* <h2> translation_table.S </h2>
* translation_table.S contains a static page table required by MMU for
* cortex-A9. This translation table is flat mapped (input address = output
* address) with default memory attributes defined for zynq architecture. It
* utilizes short descriptor translation table format with each section defining
* 1MB of memory.
*
* The overview of translation table memory attributes is described below.
*
*| | Memory Range | Definition in Translation Table |
*|-----------------------|-------------------------|-----------------------------------|
*| DDR | 0x00000000 - 0x3FFFFFFF | Normal write-back Cacheable |
*| PL | 0x40000000 - 0xBFFFFFFF | Strongly Ordered |
*| Reserved | 0xC0000000 - 0xDFFFFFFF | Unassigned |
*| Memory mapped devices | 0xE0000000 - 0xE02FFFFF | Device Memory |
*| Reserved | 0xE0300000 - 0xE0FFFFFF | Unassigned |
*| NAND, NOR | 0xE1000000 - 0xE3FFFFFF | Device memory |
*| SRAM | 0xE4000000 - 0xE5FFFFFF | Normal write-back Cacheable |
*| Reserved | 0xE6000000 - 0xF7FFFFFF | Unassigned |
*| AMBA APB Peripherals | 0xF8000000 - 0xF8FFFFFF | Device Memory |
*| Reserved | 0xF9000000 - 0xFBFFFFFF | Unassigned |
*| Linear QSPI - XIP | 0xFC000000 - 0xFDFFFFFF | Normal write-through cacheable |
*| Reserved | 0xFE000000 - 0xFFEFFFFF | Unassigned |
*| OCM | 0xFFF00000 - 0xFFFFFFFF | Normal inner write-back cacheable |
*
* @note
*
* For region 0x00000000 - 0x3FFFFFFF, a system where DDR is less than 1GB,
* region after DDR and before PL is marked as undefined/reserved in translation
* table. In 0xF8000000 - 0xF8FFFFFF, 0xF8000C00 - 0xF8000FFF, 0xF8010000 -
* 0xF88FFFFF and 0xF8F03000 to 0xF8FFFFFF are reserved but due to granual size
* of 1MB, it is not possible to define separate regions for them. For region
* 0xFFF00000 - 0xFFFFFFFF, 0xFFF00000 to 0xFFFB0000 is reserved but due to 1MB
* granual size, it is not possible to define separate region for it
*
* <pre>
* MODIFICATION HISTORY:
*
* Ver Who Date Changes
* ----- ---- -------- ---------------------------------------------------
* 1.00a ecm 10/20/09 Initial version
* 3.04a sdm 01/13/12 Updated MMU table to mark DDR memory as Shareable
* 3.07a sgd 07/05/2012 Configuring device address spaces as shareable device
* instead of strongly-ordered.
* 3.07a asa 07/17/2012 Changed the property of the ".mmu_tbl" section.
* 4.2 pkp 09/02/2014 added entries for 0xfe000000 to 0xffefffff as reserved
* and 0xe0000000 - 0xe1ffffff is broken down into
* 0xe0000000 - 0xe02fffff (memory mapped devides)
* 0xe0300000 - 0xe0ffffff (reserved) and
* 0xe1000000 - 0xe1ffffff (NAND)
* 5.2 pkp 06/08/2015 put a check for XPAR_PS7_DDR_0_S_AXI_BASEADDR to confirm
* if DDR is present or not and accordingly generate the
* translation table
* 6.1 pkp 07/11/2016 Corrected comments for memory attributes
* </pre>
*
*
******************************************************************************/
.globl MMUTable
.section .mmu_tbl,"a"
MMUTable:
/* Each table entry occupies one 32-bit word and there are
* 4096 entries, so the entire table takes up 16KB.
* Each entry covers a 1MB section.
*/
.set SECT, 0
.set DDR_START, 0x00100000
.set DDR_END, 0x1FFFFFFF
.set DDR_SIZE, (DDR_END - DDR_START)+1
.set DDR_REG, DDR_SIZE/0x100000
.set UNDEF_REG, 0x3FF - DDR_REG
/*0x00000000 - 0x00100000 (cacheable )*/
.word SECT + 0x15de6 /* S=b1 TEX=b101 AP=b11, Domain=b1111, C=b0, B=b1 */
.set SECT, SECT+0x100000
.rept DDR_REG /* (DDR Cacheable) */
.word SECT + 0x15de6 /* S=b1 TEX=b101 AP=b11, Domain=b1111, C=b0, B=b1 */
.set SECT, SECT+0x100000
.endr
.rept UNDEF_REG /* (unassigned/reserved).
* Generates a translation fault if accessed */
.word SECT + 0x0 /* S=b0 TEX=b000 AP=b00, Domain=b0, C=b0, B=b0 */
.set SECT, SECT+0x100000
.endr
.rept 0x0400 /* 0x40000000 - 0x7fffffff (FPGA slave0) */
.word SECT + 0xc02 /* S=b0 TEX=b000 AP=b11, Domain=b0, C=b0, B=b0 */
.set SECT, SECT+0x100000
.endr
.rept 0x0400 /* 0x80000000 - 0xbfffffff (FPGA slave1) */
.word SECT + 0xc02 /* S=b0 TEX=b000 AP=b11, Domain=b0, C=b0, B=b0 */
.set SECT, SECT+0x100000
.endr
.rept 0x0200 /* 0xc0000000 - 0xdfffffff (unassigned/reserved).
* Generates a translation fault if accessed */
.word SECT + 0x0 /* S=b0 TEX=b000 AP=b00, Domain=b0, C=b0, B=b0 */
.set SECT, SECT+0x100000
.endr
.rept 0x003 /* 0xe0000000 - 0xe02fffff (Memory mapped devices)
* UART/USB/IIC/SPI/CAN/GEM/GPIO/QSPI/SD/NAND */
.word SECT + 0xc06 /* S=b0 TEX=b000 AP=b11, Domain=b0, C=b0, B=b1 */
.set SECT, SECT+0x100000
.endr
.rept 0x0D /* 0xe0300000 - 0xe0ffffff (unassigned/reserved).
* Generates a translation fault if accessed */
.word SECT + 0x0 /* S=b0 TEX=b000 AP=b00, Domain=b0, C=b0, B=b0 */
.set SECT, SECT+0x100000
.endr
.rept 0x0010 /* 0xe1000000 - 0xe1ffffff (NAND) */
.word SECT + 0xc06 /* S=b0 TEX=b000 AP=b11, Domain=b0, C=b0, B=b1 */
.set SECT, SECT+0x100000
.endr
.rept 0x0020 /* 0xe2000000 - 0xe3ffffff (NOR) */
.word SECT + 0xc06 /* S=b0 TEX=b000 AP=b11, Domain=b0, C=b0, B=b1 */
.set SECT, SECT+0x100000
.endr
.rept 0x0020 /* 0xe4000000 - 0xe5ffffff (SRAM) */
.word SECT + 0xc0e /* S=b0 TEX=b000 AP=b11, Domain=b0, C=b1, B=b1 */
.set SECT, SECT+0x100000
.endr
.rept 0x0120 /* 0xe6000000 - 0xf7ffffff (unassigned/reserved).
* Generates a translation fault if accessed */
.word SECT + 0x0 /* S=b0 TEX=b000 AP=b00, Domain=b0, C=b0, B=b0 */
.set SECT, SECT+0x100000
.endr
/* 0xf8000c00 to 0xf8000fff, 0xf8010000 to 0xf88fffff and
0xf8f03000 to 0xf8ffffff are reserved but due to granual size of
1MB, it is not possible to define separate regions for them */
.rept 0x0010 /* 0xf8000000 - 0xf8ffffff (AMBA APB Peripherals) */
.word SECT + 0xc06 /* S=b0 TEX=b000 AP=b11, Domain=b0, C=b0, B=b1 */
.set SECT, SECT+0x100000
.endr
.rept 0x0030 /* 0xf9000000 - 0xfbffffff (unassigned/reserved).
* Generates a translation fault if accessed */
.word SECT + 0x0 /* S=b0 TEX=b000 AP=b00, Domain=b0, C=b0, B=b0 */
.set SECT, SECT+0x100000
.endr
.rept 0x0020 /* 0xfc000000 - 0xfdffffff (Linear QSPI - XIP) */
.word SECT + 0xc0a /* S=b0 TEX=b000 AP=b11, Domain=b0, C=b1, B=b0 */
.set SECT, SECT+0x100000
.endr
.rept 0x001F /* 0xfe000000 - 0xffefffff (unassigned/reserved).
* Generates a translation fault if accessed */
.word SECT + 0x0 /* S=b0 TEX=b000 AP=b00, Domain=b0, C=b0, B=b0 */
.set SECT, SECT+0x100000
.endr
/* 0xfff00000 to 0xfffb0000 is reserved but due to granual size of
1MB, it is not possible to define separate region for it
0xfff00000 - 0xffffffff
256K OCM when mapped to high address space
inner-cacheable */
.word SECT + 0x4c0e /* S=b0 TEX=b100 AP=b11, Domain=b0, C=b1, B=b1 */
.set SECT, SECT+0x100000
.end

106
hp_dma.py Executable file
View File

@ -0,0 +1,106 @@
from migen import *
from migen_axi.interconnect import axi
from misoc.interconnect.csr import *
from operator import attrgetter
class HP_DMA_READ(Module, AutoCSR):
def __init__(self, bus=None):
self.bus = bus or axi.Interface(data_width=64)
self.addr_base = CSRStorage(32)
self.n_bursts = CSRStorage(32) # Number of bursts to do -1
self.trigger = CSR(1)
self.n_cycles = CSRStatus(32)
self.status = CSRStatus(1)
self.n_read = CSRStatus(32)
self.dout = Signal(32)
self.dout_stb = Signal()
###
ar, aw, w, r, b = attrgetter("ar", "aw", "w", "r", "b")(self.bus)
BURST_LEN = 16
trigger_stb = self.trigger.re
addr = Signal(32)
read_request_accepted = Signal() # Asserted when the read request has been accepted
read_request = Signal()
n_done = Signal(32)
self.submodules.fsm = fsm = FSM(reset_state="IDLE")
fsm.act("IDLE",
If(trigger_stb,
NextValue(addr, self.addr_base.storage),
NextValue(read_request, 1),
NextState("RUNNING")
)
)
fsm.act("RUNNING",
If(read_request_accepted,
NextValue(addr, addr+BURST_LEN),
NextValue(n_done, n_done+1),
If(n_done == self.n_bursts.storage,
NextState("IDLE"),
NextValue(read_request, 0)
)
)
)
### Read
self.comb += [
ar.addr.eq(self.addr_base.storage),
self.dout.eq(r.data),
r.ready.eq(1),
ar.burst.eq(axi.Burst.incr.value),
ar.len.eq(BURST_LEN-1), # Number of transfers in burst (0->1 transfer, 1->2 transfers...)
ar.size.eq(3), # Width of burst: 3 = 8 bytes = 64 bits
ar.cache.eq(0xf),
]
# read control
self.comb += read_request_accepted.eq(ar.ready & ar.valid)
self.submodules.read_fsm = read_fsm = FSM(reset_state="IDLE")
read_fsm.act("IDLE",
If(read_request,
ar.valid.eq(1),
If(ar.ready,
NextState("WAIT")
).Else(
NextState("READ_START")
)
)
)
read_fsm.act("READ_START",
ar.valid.eq(1),
If(ar.ready,
NextState("WAIT"),
)
)
read_fsm.act("WAIT",
NextState("IDLE")
)
self.comb += self.dout_stb.eq(r.valid & r.ready)
n_bursts_received = Signal(32)
self.sync += [
If(trigger_stb, n_bursts_received.eq(0)),
If(self.dout_stb & r.last, n_bursts_received.eq(n_bursts_received+1))
]
self.sync += [
If(trigger_stb, self.status.status.eq(1)),
If(n_bursts_received==self.n_bursts.storage+1, self.status.status.eq(0))
]
self.sync += [
If(self.status.status, self.n_cycles.status.eq(self.n_cycles.status+1)),
If(trigger_stb, self.n_cycles.status.eq(0))
]
self.sync += [
If(self.dout_stb, self.n_read.status.eq(self.n_read.status+1)),
If(trigger_stb, self.n_read.status.eq(0))
]

90
load.py Executable file
View File

@ -0,0 +1,90 @@
#!/usr/bin/env python
import argparse
import tempfile
import os
import subprocess
header_template = \
"""
source [find interface/ftdi/digilent_jtag_smt2.cfg]
adapter_khz 10000
set PL_TAPID 0x03727093
set SMP 1
source {cfg_dir}/zynq-7000.cfg
source {cfg_dir}/xilinx-tcl.cfg
source {cfg_dir}/ps7_init.tcl
reset_config srst_only srst_push_pull
set XC7_JSHUTDOWN 0x0d
set XC7_JPROGRAM 0x0b
set XC7_JSTART 0x0c
set XC7_BYPASS 0x3f
proc xc7_program {{tap}} {{
global XC7_JSHUTDOWN XC7_JPROGRAM XC7_JSTART XC7_BYPASS
irscan $tap $XC7_JSHUTDOWN
irscan $tap $XC7_JPROGRAM
runtest 60000
#JSTART prevents this from working...
#irscan $tap $XC7_JSTART
runtest 2000
irscan $tap $XC7_BYPASS
runtest 2000
}}
pld device virtex2 zynq.tap 1
init
xc7_program zynq.tap
xilinx_ps7_init
# Disable MMU
targets $_TARGETNAME_1
arm mcr 15 0 1 0 0 [expr [arm mrc 15 0 1 0 0] & ~0xd]
targets $_TARGETNAME_0
arm mcr 15 0 1 0 0 [expr [arm mrc 15 0 1 0 0] & ~0xd]
"""
def get_argparser():
parser = argparse.ArgumentParser()
parser.add_argument("action", nargs="*",
default="gateware firmware run stop".split())
return parser
def main():
args = get_argparser().parse_args()
with tempfile.NamedTemporaryFile(delete=False) as f:
cfg_file = f.name
cfg_dir = os.path.dirname(os.path.realpath(__file__))
header = header_template.format(cfg_dir=cfg_dir)
f.write(header.encode())
if "firmware" in args.action:
f.write(b"load_image misoc_zedboard_zedboard/software/runtime/runtime.bin 0x100000 bin\n")
if "gateware" in args.action:
f.write(b"pld load 0 misoc_zedboard_zedboard/gateware/top.bit\n")
if "run" in args.action:
f.write(b"targets $_TARGETNAME_1\nreg pc 0x100000\n")
f.write(b"targets $_TARGETNAME_0\nresume 0x100000\n")
if "stop" in args.action:
f.write(b"sleep 2000\n")
f.write(b"targets $_TARGETNAME_0\nhalt\nreg\n")
# f.write(b"targets $_TARGETNAME_1\nhalt\nreg\n")
if not ("noexit" in args.action):
f.write(b"exit\n")
subprocess.run(["openocd", "-f", cfg_file])
if __name__=="__main__":
main()

284
maxi_dma.py Executable file
View File

@ -0,0 +1,284 @@
from migen import *
from migen_axi.interconnect import axi
from misoc.interconnect.csr import *
from artiq.gateware import rtio
from operator import attrgetter
class MAXI_DMA(Module, AutoCSR):
def __init__(self, bus=None, user=None, trigger_stb=None):
self.bus = bus or axi.Interface(data_width=64)
self.addr_base = CSRStorage(32)
self.trig_count = CSRStatus(32)
self.write_count = CSRStatus(32)
# Dout : Data received from CPU, output by DMA module
# Din : Data driven into DMA module, written into CPU
# When stb assert, index shows word being read/written, dout/din holds
# data
#
# Cycle:
# trigger_stb pulsed at start
# Then out_burst_len words are strobed out of dout
# Then, when din_ready is high, in_burst_len words are strobed in to din
self.dout_stb = Signal()
self.din_stb = Signal()
self.dout_index = Signal(max=16)
self.din_index = Signal(max=16)
self.din_ready = Signal()
self.dout = Signal(64)
self.din = Signal(64)
self.out_burst_len = Signal(max=16)
self.in_burst_len = Signal(max=16)
###
self.trigger_stb = trigger_stb
self.sync += If(trigger_stb, self.trig_count.status.eq(self.trig_count.status+1))
if user:
self.comb += user.aruser.eq(0x1f)
self.comb += user.awuser.eq(0x1f)
ar, aw, w, r, b = attrgetter("ar", "aw", "w", "r", "b")(self.bus)
### Read
self.comb += [
ar.addr.eq(self.addr_base.storage),
self.dout.eq(r.data),
r.ready.eq(1),
ar.burst.eq(axi.Burst.incr.value),
ar.len.eq(self.out_burst_len-1), # Number of transfers in burst (0->1 transfer, 1->2 transfers...)
ar.size.eq(3), # Width of burst: 3 = 8 bytes = 64 bits
ar.cache.eq(0xf),
]
# read control
self.submodules.read_fsm = read_fsm = FSM(reset_state="IDLE")
read_fsm.act("IDLE",
If(trigger_stb,
ar.valid.eq(1),
If(ar.ready,
NextState("READ")
).Else(
NextState("READ_START")
)
)
)
read_fsm.act("READ_START",
ar.valid.eq(1),
If(ar.ready,
NextState("READ"),
)
)
read_fsm.act("READ",
ar.valid.eq(0),
If(r.last & r.valid,
NextState("IDLE")
)
)
self.sync += [
If(read_fsm.ongoing("IDLE"),
self.dout_index.eq(0)
).Else(If(r.valid & read_fsm.ongoing("READ"),
self.dout_index.eq(self.dout_index+1)
)
)
]
self.comb += self.dout_stb.eq(r.valid & r.ready)
### Write
self.comb += [
w.data.eq(self.din),
aw.addr.eq(self.addr_base.storage+32), # Write to next cache line
w.strb.eq(0xff),
aw.burst.eq(axi.Burst.incr.value),
aw.len.eq(self.in_burst_len-1), # Number of transfers in burst minus 1
aw.size.eq(3), # Width of burst: 3 = 8 bytes = 64 bits
aw.cache.eq(0xf),
b.ready.eq(1),
]
# write control
self.submodules.write_fsm = write_fsm = FSM(reset_state="IDLE")
write_fsm.act("IDLE",
w.valid.eq(0),
aw.valid.eq(0),
If(trigger_stb,
aw.valid.eq(1),
If(aw.ready, # assumes aw.ready is not randomly deasserted
NextState("DATA_WAIT")
).Else(
NextState("AW_READY_WAIT")
)
)
)
write_fsm.act("AW_READY_WAIT",
aw.valid.eq(1),
If(aw.ready,
NextState("DATA_WAIT"),
)
)
write_fsm.act("DATA_WAIT",
aw.valid.eq(0),
If(self.din_ready,
w.valid.eq(1),
NextState("WRITE")
)
)
write_fsm.act("WRITE",
w.valid.eq(1),
If(w.ready & w.last,
NextState("IDLE")
)
)
self.sync += If(w.ready & w.valid, self.write_count.status.eq(self.write_count.status+1))
self.sync += [
If(write_fsm.ongoing("IDLE"),
self.din_index.eq(0)
),
If(w.ready & w.valid, self.din_index.eq(self.din_index+1))
]
self.comb += [
w.last.eq(0),
If(self.din_index==aw.len, w.last.eq(1))
]
self.comb += self.din_stb.eq(w.valid & w.ready)
class DMA_Test(Module):
def __init__(self, engine=None):
if engine is None:
engine = MAXI_DMA()
N = 4
regs = [Signal(64) for _ in range(N)]
self.comb += [
engine.out_burst_len.eq(N),
engine.in_burst_len.eq(N),
]
self.sync += [
If(engine.trigger_stb, engine.din_ready.eq(0)),
If(engine.dout_stb & (engine.dout_index==3), engine.din_ready.eq(1))
]
dout_cases = {}
for i in range(N):
dout_cases[i] = regs[i].eq(engine.dout)
din_cases = {}
for i in range(N):
din_cases[i] = engine.din.eq(regs[i])
self.sync += [
If(engine.dout_stb,
Case(engine.dout_index, dout_cases)
),
]
self.comb += [
If(engine.din_stb,
Case(engine.din_index, din_cases)
)
]
class DMA_KernelInitiator(Module):
def __init__(self, engine=None, cri=None):
self.engine = engine or MAXI_DMA()
self.cri = cri or rtio.cri.Interface()
###
cri = self.cri
self.comb += [
engine.out_burst_len.eq(4),
engine.in_burst_len.eq(4),
]
cmd = Signal(8)
cmd_write = Signal()
cmd_read = Signal()
self.comb += [
cmd_write.eq(cmd==0),
cmd_read.eq(cmd==1)
]
dout_cases = {}
dout_lw = Signal(32)
dout_hw = Signal(32)
self.comb += [
dout_lw.eq(engine.dout[:32]),
dout_hw.eq(engine.dout[32:])
]
dout_cases[0] = [
cmd.eq(dout_lw[24:]),
cri.chan_sel.eq(dout_lw[:24]),
cri.o_address.eq(dout_hw[:16])
]
dout_cases[1] = [
cri.timestamp.eq(engine.dout)
]
dout_cases[2] = [cri.o_data.eq(engine.dout)] # only lowest 64 bits
self.sync += [
cri.cmd.eq(rtio.cri.commands["nop"]),
If(engine.dout_stb,
Case(engine.dout_index, dout_cases),
If(engine.dout_index==2,
If(cmd_write, cri.cmd.eq(rtio.cri.commands["write"])),
If(cmd_read, cri.cmd.eq(rtio.cri.commands["read"]))
)
)
]
# If input event, wait for response before allow input data to be
# sampled
# TODO: If output, wait for wait flag clear
RTIO_I_STATUS_WAIT_STATUS = 4
RTIO_O_STATUS_WAIT = 1
self.submodules.fsm = fsm = FSM(reset_state="IDLE")
fsm.act("IDLE",
If(engine.trigger_stb, NextState("WAIT_OUT_CYCLE"))
)
fsm.act("WAIT_OUT_CYCLE",
engine.din_ready.eq(0),
If(engine.dout_stb & (engine.dout_index==3),
NextState("WAIT_READY")
)
)
fsm.act("WAIT_READY",
If(cmd_read & (cri.i_status & RTIO_I_STATUS_WAIT_STATUS == 0) \
| cmd_write & ~(cri.o_status & RTIO_O_STATUS_WAIT),
engine.din_ready.eq(1),
NextState("IDLE")
)
)
din_cases_cmdwrite = {
0: [engine.din.eq((1<<16) | cri.o_status)],
1: [engine.din.eq(0)],
}
din_cases_cmdread = {
0: [engine.din[:32].eq((1<<16) | cri.i_status), engine.din[32:].eq(cri.i_data)],
1: [engine.din.eq(cri.i_timestamp)]
}
self.comb += [
If(cmd_read, Case(engine.din_index, din_cases_cmdread)),
If(cmd_write, Case(engine.din_index, din_cases_cmdwrite)),
]

771
ps7_init.tcl Executable file
View File

@ -0,0 +1,771 @@
proc ps7_pll_init_data_3_0 {} {
mwr -force 0XF8000008 0x0000DF0D
mask_write 0XF8000110 0x003FFFF0 0x000FA220
mask_write 0XF8000100 0x0007F000 0x00028000
mask_write 0XF8000100 0x00000010 0x00000010
mask_write 0XF8000100 0x00000001 0x00000001
mask_write 0XF8000100 0x00000001 0x00000000
mask_poll 0XF800010C 0x00000001
mask_write 0XF8000100 0x00000010 0x00000000
mask_write 0XF8000120 0x1F003F30 0x1F000200
mask_write 0XF8000114 0x003FFFF0 0x0012C220
mask_write 0XF8000104 0x0007F000 0x00020000
mask_write 0XF8000104 0x00000010 0x00000010
mask_write 0XF8000104 0x00000001 0x00000001
mask_write 0XF8000104 0x00000001 0x00000000
mask_poll 0XF800010C 0x00000002
mask_write 0XF8000104 0x00000010 0x00000000
mask_write 0XF8000124 0xFFF00003 0x0C200003
mask_write 0XF8000118 0x003FFFF0 0x001452C0
mask_write 0XF8000108 0x0007F000 0x0001E000
mask_write 0XF8000108 0x00000010 0x00000010
mask_write 0XF8000108 0x00000001 0x00000001
mask_write 0XF8000108 0x00000001 0x00000000
mask_poll 0XF800010C 0x00000004
mask_write 0XF8000108 0x00000010 0x00000000
mwr -force 0XF8000004 0x0000767B
}
proc ps7_clock_init_data_3_0 {} {
mwr -force 0XF8000008 0x0000DF0D
mask_write 0XF8000128 0x03F03F01 0x00700F01
mask_write 0XF8000138 0x00000011 0x00000001
mask_write 0XF8000140 0x03F03F71 0x00100801
mask_write 0XF800014C 0x00003F31 0x00000501
mask_write 0XF8000150 0x00003F33 0x00001401
mask_write 0XF8000154 0x00003F33 0x00001402
mask_write 0XF8000168 0x00003F31 0x00000501
mask_write 0XF8000170 0x03F03F30 0x00200500
mask_write 0XF80001C4 0x00000001 0x00000001
mask_write 0XF800012C 0x01FFCCCD 0x01EC044D
mwr -force 0XF8000004 0x0000767B
}
proc ps7_ddr_init_data_3_0 {} {
mask_write 0XF8006000 0x0001FFFF 0x00000080
mask_write 0XF8006004 0x0007FFFF 0x00001081
mask_write 0XF8006008 0x03FFFFFF 0x03C0780F
mask_write 0XF800600C 0x03FFFFFF 0x02001001
mask_write 0XF8006010 0x03FFFFFF 0x00014001
mask_write 0XF8006014 0x001FFFFF 0x0004159B
mask_write 0XF8006018 0xF7FFFFFF 0x452460D2
mask_write 0XF800601C 0xFFFFFFFF 0x720238E5
mask_write 0XF8006020 0x7FDFFFFC 0x270872D0
mask_write 0XF8006024 0x0FFFFFC3 0x00000000
mask_write 0XF8006028 0x00003FFF 0x00002007
mask_write 0XF800602C 0xFFFFFFFF 0x00000008
mask_write 0XF8006030 0xFFFFFFFF 0x00040930
mask_write 0XF8006034 0x13FF3FFF 0x000116D4
mask_write 0XF8006038 0x00000003 0x00000000
mask_write 0XF800603C 0x000FFFFF 0x00000777
mask_write 0XF8006040 0xFFFFFFFF 0xFFF00000
mask_write 0XF8006044 0x0FFFFFFF 0x0FF66666
mask_write 0XF8006048 0x0003F03F 0x0003C008
mask_write 0XF8006050 0xFF0F8FFF 0x77010800
mask_write 0XF8006058 0x00010000 0x00000000
mask_write 0XF800605C 0x0000FFFF 0x00005003
mask_write 0XF8006060 0x000017FF 0x0000003E
mask_write 0XF8006064 0x00021FE0 0x00020000
mask_write 0XF8006068 0x03FFFFFF 0x00284141
mask_write 0XF800606C 0x0000FFFF 0x00001610
mask_write 0XF8006078 0x03FFFFFF 0x00466111
mask_write 0XF800607C 0x000FFFFF 0x00032222
mask_write 0XF80060A4 0xFFFFFFFF 0x10200802
mask_write 0XF80060A8 0x0FFFFFFF 0x0690CB73
mask_write 0XF80060AC 0x000001FF 0x000001FE
mask_write 0XF80060B0 0x1FFFFFFF 0x1CFFFFFF
mask_write 0XF80060B4 0x00000200 0x00000200
mask_write 0XF80060B8 0x01FFFFFF 0x00200066
mask_write 0XF80060C4 0x00000003 0x00000000
mask_write 0XF80060C8 0x000000FF 0x00000000
mask_write 0XF80060DC 0x00000001 0x00000000
mask_write 0XF80060F0 0x0000FFFF 0x00000000
mask_write 0XF80060F4 0x0000000F 0x00000008
mask_write 0XF8006114 0x000000FF 0x00000000
mask_write 0XF8006118 0x7FFFFFCF 0x40000001
mask_write 0XF800611C 0x7FFFFFCF 0x40000001
mask_write 0XF8006120 0x7FFFFFCF 0x40000001
mask_write 0XF8006124 0x7FFFFFCF 0x40000001
mask_write 0XF800612C 0x000FFFFF 0x00033C03
mask_write 0XF8006130 0x000FFFFF 0x00034003
mask_write 0XF8006134 0x000FFFFF 0x0002F400
mask_write 0XF8006138 0x000FFFFF 0x00030400
mask_write 0XF8006140 0x000FFFFF 0x00000035
mask_write 0XF8006144 0x000FFFFF 0x00000035
mask_write 0XF8006148 0x000FFFFF 0x00000035
mask_write 0XF800614C 0x000FFFFF 0x00000035
mask_write 0XF8006154 0x000FFFFF 0x00000083
mask_write 0XF8006158 0x000FFFFF 0x00000083
mask_write 0XF800615C 0x000FFFFF 0x00000080
mask_write 0XF8006160 0x000FFFFF 0x00000080
mask_write 0XF8006168 0x001FFFFF 0x00000124
mask_write 0XF800616C 0x001FFFFF 0x00000125
mask_write 0XF8006170 0x001FFFFF 0x00000112
mask_write 0XF8006174 0x001FFFFF 0x00000116
mask_write 0XF800617C 0x000FFFFF 0x000000C3
mask_write 0XF8006180 0x000FFFFF 0x000000C3
mask_write 0XF8006184 0x000FFFFF 0x000000C0
mask_write 0XF8006188 0x000FFFFF 0x000000C0
mask_write 0XF8006190 0x6FFFFEFE 0x00040080
mask_write 0XF8006194 0x000FFFFF 0x0001FC82
mask_write 0XF8006204 0xFFFFFFFF 0x00000000
mask_write 0XF8006208 0x000703FF 0x000003FF
mask_write 0XF800620C 0x000703FF 0x000003FF
mask_write 0XF8006210 0x000703FF 0x000003FF
mask_write 0XF8006214 0x000703FF 0x000003FF
mask_write 0XF8006218 0x000F03FF 0x000003FF
mask_write 0XF800621C 0x000F03FF 0x000003FF
mask_write 0XF8006220 0x000F03FF 0x000003FF
mask_write 0XF8006224 0x000F03FF 0x000003FF
mask_write 0XF80062A8 0x00000FF5 0x00000000
mask_write 0XF80062AC 0xFFFFFFFF 0x00000000
mask_write 0XF80062B0 0x003FFFFF 0x00005125
mask_write 0XF80062B4 0x0003FFFF 0x000012A8
mask_poll 0XF8000B74 0x00002000
mask_write 0XF8006000 0x0001FFFF 0x00000081
mask_poll 0XF8006054 0x00000007
}
proc ps7_mio_init_data_3_0 {} {
mwr -force 0XF8000008 0x0000DF0D
mask_write 0XF8000B40 0x00000FFF 0x00000600
mask_write 0XF8000B44 0x00000FFF 0x00000600
mask_write 0XF8000B48 0x00000FFF 0x00000672
mask_write 0XF8000B4C 0x00000FFF 0x00000672
mask_write 0XF8000B50 0x00000FFF 0x00000674
mask_write 0XF8000B54 0x00000FFF 0x00000674
mask_write 0XF8000B58 0x00000FFF 0x00000600
mask_write 0XF8000B5C 0xFFFFFFFF 0x0018C61C
mask_write 0XF8000B60 0xFFFFFFFF 0x00F9861C
mask_write 0XF8000B64 0xFFFFFFFF 0x00F9861C
mask_write 0XF8000B68 0xFFFFFFFF 0x00F9861C
mask_write 0XF8000B6C 0x00007FFF 0x00000209
mask_write 0XF8000B70 0x00000001 0x00000001
mask_write 0XF8000B70 0x00000021 0x00000020
mask_write 0XF8000B70 0x07FEFFFF 0x00000823
mask_write 0XF8000700 0x00003FFF 0x00000600
mask_write 0XF8000704 0x00003FFF 0x00000702
mask_write 0XF8000708 0x00003FFF 0x00000702
mask_write 0XF800070C 0x00003FFF 0x00000702
mask_write 0XF8000710 0x00003FFF 0x00000702
mask_write 0XF8000714 0x00003FFF 0x00000702
mask_write 0XF8000718 0x00003FFF 0x00000702
mask_write 0XF800071C 0x00003FFF 0x00000600
mask_write 0XF8000720 0x00003FFF 0x00000700
mask_write 0XF8000724 0x00003FFF 0x00000600
mask_write 0XF8000728 0x00003FFF 0x00000600
mask_write 0XF800072C 0x00003FFF 0x00000600
mask_write 0XF8000730 0x00003FFF 0x00000600
mask_write 0XF8000734 0x00003FFF 0x00000600
mask_write 0XF8000738 0x00003FFF 0x00000600
mask_write 0XF800073C 0x00003FFF 0x00000600
mask_write 0XF8000740 0x00003FFF 0x00000302
mask_write 0XF8000744 0x00003FFF 0x00000302
mask_write 0XF8000748 0x00003FFF 0x00000302
mask_write 0XF800074C 0x00003FFF 0x00000302
mask_write 0XF8000750 0x00003FFF 0x00000302
mask_write 0XF8000754 0x00003FFF 0x00000302
mask_write 0XF8000758 0x00003FFF 0x00000303
mask_write 0XF800075C 0x00003FFF 0x00000303
mask_write 0XF8000760 0x00003FFF 0x00000303
mask_write 0XF8000764 0x00003FFF 0x00000303
mask_write 0XF8000768 0x00003FFF 0x00000303
mask_write 0XF800076C 0x00003FFF 0x00000303
mask_write 0XF8000770 0x00003FFF 0x00000304
mask_write 0XF8000774 0x00003FFF 0x00000305
mask_write 0XF8000778 0x00003FFF 0x00000304
mask_write 0XF800077C 0x00003FFF 0x00000305
mask_write 0XF8000780 0x00003FFF 0x00000304
mask_write 0XF8000784 0x00003FFF 0x00000304
mask_write 0XF8000788 0x00003FFF 0x00000304
mask_write 0XF800078C 0x00003FFF 0x00000304
mask_write 0XF8000790 0x00003FFF 0x00000305
mask_write 0XF8000794 0x00003FFF 0x00000304
mask_write 0XF8000798 0x00003FFF 0x00000304
mask_write 0XF800079C 0x00003FFF 0x00000304
mask_write 0XF80007A0 0x00003FFF 0x00000380
mask_write 0XF80007A4 0x00003FFF 0x00000380
mask_write 0XF80007A8 0x00003FFF 0x00000380
mask_write 0XF80007AC 0x00003FFF 0x00000380
mask_write 0XF80007B0 0x00003FFF 0x00000380
mask_write 0XF80007B4 0x00003FFF 0x00000380
mask_write 0XF80007B8 0x00003F01 0x00000201
mask_write 0XF80007BC 0x00003F01 0x00000201
mask_write 0XF80007C0 0x00003FFF 0x000002E0
mask_write 0XF80007C4 0x00003FFF 0x000002E1
mask_write 0XF80007C8 0x00003FFF 0x00000200
mask_write 0XF80007CC 0x00003FFF 0x00000200
mask_write 0XF80007D0 0x00003FFF 0x00000280
mask_write 0XF80007D4 0x00003FFF 0x00000280
mask_write 0XF8000830 0x003F003F 0x002F002E
mwr -force 0XF8000004 0x0000767B
}
proc ps7_peripherals_init_data_3_0 {} {
mwr -force 0XF8000008 0x0000DF0D
mask_write 0XF8000B48 0x00000180 0x00000180
mask_write 0XF8000B4C 0x00000180 0x00000180
mask_write 0XF8000B50 0x00000180 0x00000180
mask_write 0XF8000B54 0x00000180 0x00000180
mwr -force 0XF8000004 0x0000767B
mask_write 0XE0001034 0x000000FF 0x00000006
mask_write 0XE0001018 0x0000FFFF 0x0000003E
mask_write 0XE0001000 0x000001FF 0x00000017
mask_write 0XE0001004 0x000003FF 0x00000020
mask_write 0XE000D000 0x00080000 0x00080000
mask_write 0XF8007000 0x20000000 0x00000000
}
proc ps7_post_config_3_0 {} {
mwr -force 0XF8000008 0x0000DF0D
mask_write 0XF8000900 0x0000000F 0x0000000F
mask_write 0XF8000240 0xFFFFFFFF 0x00000000
mwr -force 0XF8000004 0x0000767B
}
proc ps7_debug_3_0 {} {
mwr -force 0XF8898FB0 0xC5ACCE55
mwr -force 0XF8899FB0 0xC5ACCE55
mwr -force 0XF8809FB0 0xC5ACCE55
}
proc ps7_pll_init_data_2_0 {} {
mwr -force 0XF8000008 0x0000DF0D
mask_write 0XF8000110 0x003FFFF0 0x000FA220
mask_write 0XF8000100 0x0007F000 0x00028000
mask_write 0XF8000100 0x00000010 0x00000010
mask_write 0XF8000100 0x00000001 0x00000001
mask_write 0XF8000100 0x00000001 0x00000000
mask_poll 0XF800010C 0x00000001
mask_write 0XF8000100 0x00000010 0x00000000
mask_write 0XF8000120 0x1F003F30 0x1F000200
mask_write 0XF8000114 0x003FFFF0 0x0012C220
mask_write 0XF8000104 0x0007F000 0x00020000
mask_write 0XF8000104 0x00000010 0x00000010
mask_write 0XF8000104 0x00000001 0x00000001
mask_write 0XF8000104 0x00000001 0x00000000
mask_poll 0XF800010C 0x00000002
mask_write 0XF8000104 0x00000010 0x00000000
mask_write 0XF8000124 0xFFF00003 0x0C200003
mask_write 0XF8000118 0x003FFFF0 0x001452C0
mask_write 0XF8000108 0x0007F000 0x0001E000
mask_write 0XF8000108 0x00000010 0x00000010
mask_write 0XF8000108 0x00000001 0x00000001
mask_write 0XF8000108 0x00000001 0x00000000
mask_poll 0XF800010C 0x00000004
mask_write 0XF8000108 0x00000010 0x00000000
mwr -force 0XF8000004 0x0000767B
}
proc ps7_clock_init_data_2_0 {} {
mwr -force 0XF8000008 0x0000DF0D
mask_write 0XF8000128 0x03F03F01 0x00700F01
mask_write 0XF8000138 0x00000011 0x00000001
mask_write 0XF8000140 0x03F03F71 0x00100801
mask_write 0XF800014C 0x00003F31 0x00000501
mask_write 0XF8000150 0x00003F33 0x00001401
mask_write 0XF8000154 0x00003F33 0x00001402
mask_write 0XF8000168 0x00003F31 0x00000501
mask_write 0XF8000170 0x03F03F30 0x00200500
mask_write 0XF80001C4 0x00000001 0x00000001
mask_write 0XF800012C 0x01FFCCCD 0x01EC044D
mwr -force 0XF8000004 0x0000767B
}
proc ps7_ddr_init_data_2_0 {} {
mask_write 0XF8006000 0x0001FFFF 0x00000080
mask_write 0XF8006004 0x1FFFFFFF 0x00081081
mask_write 0XF8006008 0x03FFFFFF 0x03C0780F
mask_write 0XF800600C 0x03FFFFFF 0x02001001
mask_write 0XF8006010 0x03FFFFFF 0x00014001
mask_write 0XF8006014 0x001FFFFF 0x0004159B
mask_write 0XF8006018 0xF7FFFFFF 0x452460D2
mask_write 0XF800601C 0xFFFFFFFF 0x720238E5
mask_write 0XF8006020 0xFFFFFFFC 0x272872D0
mask_write 0XF8006024 0x0FFFFFFF 0x0000003C
mask_write 0XF8006028 0x00003FFF 0x00002007
mask_write 0XF800602C 0xFFFFFFFF 0x00000008
mask_write 0XF8006030 0xFFFFFFFF 0x00040930
mask_write 0XF8006034 0x13FF3FFF 0x000116D4
mask_write 0XF8006038 0x00001FC3 0x00000000
mask_write 0XF800603C 0x000FFFFF 0x00000777
mask_write 0XF8006040 0xFFFFFFFF 0xFFF00000
mask_write 0XF8006044 0x0FFFFFFF 0x0FF66666
mask_write 0XF8006048 0x3FFFFFFF 0x0003C248
mask_write 0XF8006050 0xFF0F8FFF 0x77010800
mask_write 0XF8006058 0x0001FFFF 0x00000101
mask_write 0XF800605C 0x0000FFFF 0x00005003
mask_write 0XF8006060 0x000017FF 0x0000003E
mask_write 0XF8006064 0x00021FE0 0x00020000
mask_write 0XF8006068 0x03FFFFFF 0x00284141
mask_write 0XF800606C 0x0000FFFF 0x00001610
mask_write 0XF8006078 0x03FFFFFF 0x00466111
mask_write 0XF800607C 0x000FFFFF 0x00032222
mask_write 0XF80060A0 0x00FFFFFF 0x00008000
mask_write 0XF80060A4 0xFFFFFFFF 0x10200802
mask_write 0XF80060A8 0x0FFFFFFF 0x0690CB73
mask_write 0XF80060AC 0x000001FF 0x000001FE
mask_write 0XF80060B0 0x1FFFFFFF 0x1CFFFFFF
mask_write 0XF80060B4 0x000007FF 0x00000200
mask_write 0XF80060B8 0x01FFFFFF 0x00200066
mask_write 0XF80060C4 0x00000003 0x00000000
mask_write 0XF80060C8 0x000000FF 0x00000000
mask_write 0XF80060DC 0x00000001 0x00000000
mask_write 0XF80060F0 0x0000FFFF 0x00000000
mask_write 0XF80060F4 0x0000000F 0x00000008
mask_write 0XF8006114 0x000000FF 0x00000000
mask_write 0XF8006118 0x7FFFFFFF 0x40000001
mask_write 0XF800611C 0x7FFFFFFF 0x40000001
mask_write 0XF8006120 0x7FFFFFFF 0x40000001
mask_write 0XF8006124 0x7FFFFFFF 0x40000001
mask_write 0XF800612C 0x000FFFFF 0x00033C03
mask_write 0XF8006130 0x000FFFFF 0x00034003
mask_write 0XF8006134 0x000FFFFF 0x0002F400
mask_write 0XF8006138 0x000FFFFF 0x00030400
mask_write 0XF8006140 0x000FFFFF 0x00000035
mask_write 0XF8006144 0x000FFFFF 0x00000035
mask_write 0XF8006148 0x000FFFFF 0x00000035
mask_write 0XF800614C 0x000FFFFF 0x00000035
mask_write 0XF8006154 0x000FFFFF 0x00000083
mask_write 0XF8006158 0x000FFFFF 0x00000083
mask_write 0XF800615C 0x000FFFFF 0x00000080
mask_write 0XF8006160 0x000FFFFF 0x00000080
mask_write 0XF8006168 0x001FFFFF 0x00000124
mask_write 0XF800616C 0x001FFFFF 0x00000125
mask_write 0XF8006170 0x001FFFFF 0x00000112
mask_write 0XF8006174 0x001FFFFF 0x00000116
mask_write 0XF800617C 0x000FFFFF 0x000000C3
mask_write 0XF8006180 0x000FFFFF 0x000000C3
mask_write 0XF8006184 0x000FFFFF 0x000000C0
mask_write 0XF8006188 0x000FFFFF 0x000000C0
mask_write 0XF8006190 0xFFFFFFFF 0x10040080
mask_write 0XF8006194 0x000FFFFF 0x0001FC82
mask_write 0XF8006204 0xFFFFFFFF 0x00000000
mask_write 0XF8006208 0x000F03FF 0x000803FF
mask_write 0XF800620C 0x000F03FF 0x000803FF
mask_write 0XF8006210 0x000F03FF 0x000803FF
mask_write 0XF8006214 0x000F03FF 0x000803FF
mask_write 0XF8006218 0x000F03FF 0x000003FF
mask_write 0XF800621C 0x000F03FF 0x000003FF
mask_write 0XF8006220 0x000F03FF 0x000003FF
mask_write 0XF8006224 0x000F03FF 0x000003FF
mask_write 0XF80062A8 0x00000FF7 0x00000000
mask_write 0XF80062AC 0xFFFFFFFF 0x00000000
mask_write 0XF80062B0 0x003FFFFF 0x00005125
mask_write 0XF80062B4 0x0003FFFF 0x000012A8
mask_poll 0XF8000B74 0x00002000
mask_write 0XF8006000 0x0001FFFF 0x00000081
mask_poll 0XF8006054 0x00000007
}
proc ps7_mio_init_data_2_0 {} {
mwr -force 0XF8000008 0x0000DF0D
mask_write 0XF8000B40 0x00000FFF 0x00000600
mask_write 0XF8000B44 0x00000FFF 0x00000600
mask_write 0XF8000B48 0x00000FFF 0x00000672
mask_write 0XF8000B4C 0x00000FFF 0x00000672
mask_write 0XF8000B50 0x00000FFF 0x00000674
mask_write 0XF8000B54 0x00000FFF 0x00000674
mask_write 0XF8000B58 0x00000FFF 0x00000600
mask_write 0XF8000B5C 0xFFFFFFFF 0x0018C61C
mask_write 0XF8000B60 0xFFFFFFFF 0x00F9861C
mask_write 0XF8000B64 0xFFFFFFFF 0x00F9861C
mask_write 0XF8000B68 0xFFFFFFFF 0x00F9861C
mask_write 0XF8000B6C 0x00007FFF 0x00000209
mask_write 0XF8000B70 0x00000021 0x00000021
mask_write 0XF8000B70 0x00000021 0x00000020
mask_write 0XF8000B70 0x07FFFFFF 0x00000823
mask_write 0XF8000700 0x00003FFF 0x00000600
mask_write 0XF8000704 0x00003FFF 0x00000702
mask_write 0XF8000708 0x00003FFF 0x00000702
mask_write 0XF800070C 0x00003FFF 0x00000702
mask_write 0XF8000710 0x00003FFF 0x00000702
mask_write 0XF8000714 0x00003FFF 0x00000702
mask_write 0XF8000718 0x00003FFF 0x00000702
mask_write 0XF800071C 0x00003FFF 0x00000600
mask_write 0XF8000720 0x00003FFF 0x00000700
mask_write 0XF8000724 0x00003FFF 0x00000600
mask_write 0XF8000728 0x00003FFF 0x00000600
mask_write 0XF800072C 0x00003FFF 0x00000600
mask_write 0XF8000730 0x00003FFF 0x00000600
mask_write 0XF8000734 0x00003FFF 0x00000600
mask_write 0XF8000738 0x00003FFF 0x00000600
mask_write 0XF800073C 0x00003FFF 0x00000600
mask_write 0XF8000740 0x00003FFF 0x00000302
mask_write 0XF8000744 0x00003FFF 0x00000302
mask_write 0XF8000748 0x00003FFF 0x00000302
mask_write 0XF800074C 0x00003FFF 0x00000302
mask_write 0XF8000750 0x00003FFF 0x00000302
mask_write 0XF8000754 0x00003FFF 0x00000302
mask_write 0XF8000758 0x00003FFF 0x00000303
mask_write 0XF800075C 0x00003FFF 0x00000303
mask_write 0XF8000760 0x00003FFF 0x00000303
mask_write 0XF8000764 0x00003FFF 0x00000303
mask_write 0XF8000768 0x00003FFF 0x00000303
mask_write 0XF800076C 0x00003FFF 0x00000303
mask_write 0XF8000770 0x00003FFF 0x00000304
mask_write 0XF8000774 0x00003FFF 0x00000305
mask_write 0XF8000778 0x00003FFF 0x00000304
mask_write 0XF800077C 0x00003FFF 0x00000305
mask_write 0XF8000780 0x00003FFF 0x00000304
mask_write 0XF8000784 0x00003FFF 0x00000304
mask_write 0XF8000788 0x00003FFF 0x00000304
mask_write 0XF800078C 0x00003FFF 0x00000304
mask_write 0XF8000790 0x00003FFF 0x00000305
mask_write 0XF8000794 0x00003FFF 0x00000304
mask_write 0XF8000798 0x00003FFF 0x00000304
mask_write 0XF800079C 0x00003FFF 0x00000304
mask_write 0XF80007A0 0x00003FFF 0x00000380
mask_write 0XF80007A4 0x00003FFF 0x00000380
mask_write 0XF80007A8 0x00003FFF 0x00000380
mask_write 0XF80007AC 0x00003FFF 0x00000380
mask_write 0XF80007B0 0x00003FFF 0x00000380
mask_write 0XF80007B4 0x00003FFF 0x00000380
mask_write 0XF80007B8 0x00003F01 0x00000201
mask_write 0XF80007BC 0x00003F01 0x00000201
mask_write 0XF80007C0 0x00003FFF 0x000002E0
mask_write 0XF80007C4 0x00003FFF 0x000002E1
mask_write 0XF80007C8 0x00003FFF 0x00000200
mask_write 0XF80007CC 0x00003FFF 0x00000200
mask_write 0XF80007D0 0x00003FFF 0x00000280
mask_write 0XF80007D4 0x00003FFF 0x00000280
mask_write 0XF8000830 0x003F003F 0x002F002E
mwr -force 0XF8000004 0x0000767B
}
proc ps7_peripherals_init_data_2_0 {} {
mwr -force 0XF8000008 0x0000DF0D
mask_write 0XF8000B48 0x00000180 0x00000180
mask_write 0XF8000B4C 0x00000180 0x00000180
mask_write 0XF8000B50 0x00000180 0x00000180
mask_write 0XF8000B54 0x00000180 0x00000180
mwr -force 0XF8000004 0x0000767B
mask_write 0XE0001034 0x000000FF 0x00000006
mask_write 0XE0001018 0x0000FFFF 0x0000003E
mask_write 0XE0001000 0x000001FF 0x00000017
mask_write 0XE0001004 0x00000FFF 0x00000020
mask_write 0XE000D000 0x00080000 0x00080000
mask_write 0XF8007000 0x20000000 0x00000000
}
proc ps7_post_config_2_0 {} {
mwr -force 0XF8000008 0x0000DF0D
mask_write 0XF8000900 0x0000000F 0x0000000F
mask_write 0XF8000240 0xFFFFFFFF 0x00000000
mwr -force 0XF8000004 0x0000767B
}
proc ps7_debug_2_0 {} {
mwr -force 0XF8898FB0 0xC5ACCE55
mwr -force 0XF8899FB0 0xC5ACCE55
mwr -force 0XF8809FB0 0xC5ACCE55
}
proc ps7_pll_init_data_1_0 {} {
mwr -force 0XF8000008 0x0000DF0D
mask_write 0XF8000110 0x003FFFF0 0x000FA220
mask_write 0XF8000100 0x0007F000 0x00028000
mask_write 0XF8000100 0x00000010 0x00000010
mask_write 0XF8000100 0x00000001 0x00000001
mask_write 0XF8000100 0x00000001 0x00000000
mask_poll 0XF800010C 0x00000001
mask_write 0XF8000100 0x00000010 0x00000000
mask_write 0XF8000120 0x1F003F30 0x1F000200
mask_write 0XF8000114 0x003FFFF0 0x0012C220
mask_write 0XF8000104 0x0007F000 0x00020000
mask_write 0XF8000104 0x00000010 0x00000010
mask_write 0XF8000104 0x00000001 0x00000001
mask_write 0XF8000104 0x00000001 0x00000000
mask_poll 0XF800010C 0x00000002
mask_write 0XF8000104 0x00000010 0x00000000
mask_write 0XF8000124 0xFFF00003 0x0C200003
mask_write 0XF8000118 0x003FFFF0 0x001452C0
mask_write 0XF8000108 0x0007F000 0x0001E000
mask_write 0XF8000108 0x00000010 0x00000010
mask_write 0XF8000108 0x00000001 0x00000001
mask_write 0XF8000108 0x00000001 0x00000000
mask_poll 0XF800010C 0x00000004
mask_write 0XF8000108 0x00000010 0x00000000
mwr -force 0XF8000004 0x0000767B
}
proc ps7_clock_init_data_1_0 {} {
mwr -force 0XF8000008 0x0000DF0D
mask_write 0XF8000128 0x03F03F01 0x00700F01
mask_write 0XF8000138 0x00000011 0x00000001
mask_write 0XF8000140 0x03F03F71 0x00100801
mask_write 0XF800014C 0x00003F31 0x00000501
mask_write 0XF8000150 0x00003F33 0x00001401
mask_write 0XF8000154 0x00003F33 0x00001402
mask_write 0XF8000168 0x00003F31 0x00000501
mask_write 0XF8000170 0x03F03F30 0x00200400
mask_write 0XF80001C4 0x00000001 0x00000001
mask_write 0XF800012C 0x01FFCCCD 0x01EC044D
mwr -force 0XF8000004 0x0000767B
}
proc ps7_ddr_init_data_1_0 {} {
mask_write 0XF8006000 0x0001FFFF 0x00000080
mask_write 0XF8006004 0x1FFFFFFF 0x00081081
mask_write 0XF8006008 0x03FFFFFF 0x03C0780F
mask_write 0XF800600C 0x03FFFFFF 0x02001001
mask_write 0XF8006010 0x03FFFFFF 0x00014001
mask_write 0XF8006014 0x001FFFFF 0x0004159B
mask_write 0XF8006018 0xF7FFFFFF 0x452460D2
mask_write 0XF800601C 0xFFFFFFFF 0x720238E5
mask_write 0XF8006020 0xFFFFFFFC 0x272872D0
mask_write 0XF8006024 0x0FFFFFFF 0x0000003C
mask_write 0XF8006028 0x00003FFF 0x00002007
mask_write 0XF800602C 0xFFFFFFFF 0x00000008
mask_write 0XF8006030 0xFFFFFFFF 0x00040930
mask_write 0XF8006034 0x13FF3FFF 0x000116D4
mask_write 0XF8006038 0x00001FC3 0x00000000
mask_write 0XF800603C 0x000FFFFF 0x00000777
mask_write 0XF8006040 0xFFFFFFFF 0xFFF00000
mask_write 0XF8006044 0x0FFFFFFF 0x0FF66666
mask_write 0XF8006048 0x3FFFFFFF 0x0003C248
mask_write 0XF8006050 0xFF0F8FFF 0x77010800
mask_write 0XF8006058 0x0001FFFF 0x00000101
mask_write 0XF800605C 0x0000FFFF 0x00005003
mask_write 0XF8006060 0x000017FF 0x0000003E
mask_write 0XF8006064 0x00021FE0 0x00020000
mask_write 0XF8006068 0x03FFFFFF 0x00284141
mask_write 0XF800606C 0x0000FFFF 0x00001610
mask_write 0XF80060A0 0x00FFFFFF 0x00008000
mask_write 0XF80060A4 0xFFFFFFFF 0x10200802
mask_write 0XF80060A8 0x0FFFFFFF 0x0690CB73
mask_write 0XF80060AC 0x000001FF 0x000001FE
mask_write 0XF80060B0 0x1FFFFFFF 0x1CFFFFFF
mask_write 0XF80060B4 0x000007FF 0x00000200
mask_write 0XF80060B8 0x01FFFFFF 0x00200066
mask_write 0XF80060C4 0x00000003 0x00000000
mask_write 0XF80060C8 0x000000FF 0x00000000
mask_write 0XF80060DC 0x00000001 0x00000000
mask_write 0XF80060F0 0x0000FFFF 0x00000000
mask_write 0XF80060F4 0x0000000F 0x00000008
mask_write 0XF8006114 0x000000FF 0x00000000
mask_write 0XF8006118 0x7FFFFFFF 0x40000001
mask_write 0XF800611C 0x7FFFFFFF 0x40000001
mask_write 0XF8006120 0x7FFFFFFF 0x40000001
mask_write 0XF8006124 0x7FFFFFFF 0x40000001
mask_write 0XF800612C 0x000FFFFF 0x00033C03
mask_write 0XF8006130 0x000FFFFF 0x00034003
mask_write 0XF8006134 0x000FFFFF 0x0002F400
mask_write 0XF8006138 0x000FFFFF 0x00030400
mask_write 0XF8006140 0x000FFFFF 0x00000035
mask_write 0XF8006144 0x000FFFFF 0x00000035
mask_write 0XF8006148 0x000FFFFF 0x00000035
mask_write 0XF800614C 0x000FFFFF 0x00000035
mask_write 0XF8006154 0x000FFFFF 0x00000083
mask_write 0XF8006158 0x000FFFFF 0x00000083
mask_write 0XF800615C 0x000FFFFF 0x00000080
mask_write 0XF8006160 0x000FFFFF 0x00000080
mask_write 0XF8006168 0x001FFFFF 0x00000124
mask_write 0XF800616C 0x001FFFFF 0x00000125
mask_write 0XF8006170 0x001FFFFF 0x00000112
mask_write 0XF8006174 0x001FFFFF 0x00000116
mask_write 0XF800617C 0x000FFFFF 0x000000C3
mask_write 0XF8006180 0x000FFFFF 0x000000C3
mask_write 0XF8006184 0x000FFFFF 0x000000C0
mask_write 0XF8006188 0x000FFFFF 0x000000C0
mask_write 0XF8006190 0xFFFFFFFF 0x10040080
mask_write 0XF8006194 0x000FFFFF 0x0001FC82
mask_write 0XF8006204 0xFFFFFFFF 0x00000000
mask_write 0XF8006208 0x000F03FF 0x000803FF
mask_write 0XF800620C 0x000F03FF 0x000803FF
mask_write 0XF8006210 0x000F03FF 0x000803FF
mask_write 0XF8006214 0x000F03FF 0x000803FF
mask_write 0XF8006218 0x000F03FF 0x000003FF
mask_write 0XF800621C 0x000F03FF 0x000003FF
mask_write 0XF8006220 0x000F03FF 0x000003FF
mask_write 0XF8006224 0x000F03FF 0x000003FF
mask_write 0XF80062A8 0x00000FF7 0x00000000
mask_write 0XF80062AC 0xFFFFFFFF 0x00000000
mask_write 0XF80062B0 0x003FFFFF 0x00005125
mask_write 0XF80062B4 0x0003FFFF 0x000012A8
mask_poll 0XF8000B74 0x00002000
mask_write 0XF8006000 0x0001FFFF 0x00000081
mask_poll 0XF8006054 0x00000007
}
proc ps7_mio_init_data_1_0 {} {
mwr -force 0XF8000008 0x0000DF0D
mask_write 0XF8000B40 0x00000FFF 0x00000600
mask_write 0XF8000B44 0x00000FFF 0x00000600
mask_write 0XF8000B48 0x00000FFF 0x00000672
mask_write 0XF8000B4C 0x00000FFF 0x00000672
mask_write 0XF8000B50 0x00000FFF 0x00000674
mask_write 0XF8000B54 0x00000FFF 0x00000674
mask_write 0XF8000B58 0x00000FFF 0x00000600
mask_write 0XF8000B5C 0xFFFFFFFF 0x0018C61C
mask_write 0XF8000B60 0xFFFFFFFF 0x00F9861C
mask_write 0XF8000B64 0xFFFFFFFF 0x00F9861C
mask_write 0XF8000B68 0xFFFFFFFF 0x00F9861C
mask_write 0XF8000B6C 0x000073FF 0x00000209
mask_write 0XF8000B70 0x00000021 0x00000021
mask_write 0XF8000B70 0x00000021 0x00000020
mask_write 0XF8000B70 0x07FFFFFF 0x00000823
mask_write 0XF8000700 0x00003FFF 0x00000600
mask_write 0XF8000704 0x00003FFF 0x00000702
mask_write 0XF8000708 0x00003FFF 0x00000702
mask_write 0XF800070C 0x00003FFF 0x00000702
mask_write 0XF8000710 0x00003FFF 0x00000702
mask_write 0XF8000714 0x00003FFF 0x00000702
mask_write 0XF8000718 0x00003FFF 0x00000702
mask_write 0XF800071C 0x00003FFF 0x00000600
mask_write 0XF8000720 0x00003FFF 0x00000700
mask_write 0XF8000724 0x00003FFF 0x00000600
mask_write 0XF8000728 0x00003FFF 0x00000600
mask_write 0XF800072C 0x00003FFF 0x00000600
mask_write 0XF8000730 0x00003FFF 0x00000600
mask_write 0XF8000734 0x00003FFF 0x00000600
mask_write 0XF8000738 0x00003FFF 0x00000600
mask_write 0XF800073C 0x00003FFF 0x00000600
mask_write 0XF8000740 0x00003FFF 0x00000302
mask_write 0XF8000744 0x00003FFF 0x00000302
mask_write 0XF8000748 0x00003FFF 0x00000302
mask_write 0XF800074C 0x00003FFF 0x00000302
mask_write 0XF8000750 0x00003FFF 0x00000302
mask_write 0XF8000754 0x00003FFF 0x00000302
mask_write 0XF8000758 0x00003FFF 0x00000303
mask_write 0XF800075C 0x00003FFF 0x00000303
mask_write 0XF8000760 0x00003FFF 0x00000303
mask_write 0XF8000764 0x00003FFF 0x00000303
mask_write 0XF8000768 0x00003FFF 0x00000303
mask_write 0XF800076C 0x00003FFF 0x00000303
mask_write 0XF8000770 0x00003FFF 0x00000304
mask_write 0XF8000774 0x00003FFF 0x00000305
mask_write 0XF8000778 0x00003FFF 0x00000304
mask_write 0XF800077C 0x00003FFF 0x00000305
mask_write 0XF8000780 0x00003FFF 0x00000304
mask_write 0XF8000784 0x00003FFF 0x00000304
mask_write 0XF8000788 0x00003FFF 0x00000304
mask_write 0XF800078C 0x00003FFF 0x00000304
mask_write 0XF8000790 0x00003FFF 0x00000305
mask_write 0XF8000794 0x00003FFF 0x00000304
mask_write 0XF8000798 0x00003FFF 0x00000304
mask_write 0XF800079C 0x00003FFF 0x00000304
mask_write 0XF80007A0 0x00003FFF 0x00000380
mask_write 0XF80007A4 0x00003FFF 0x00000380
mask_write 0XF80007A8 0x00003FFF 0x00000380
mask_write 0XF80007AC 0x00003FFF 0x00000380
mask_write 0XF80007B0 0x00003FFF 0x00000380
mask_write 0XF80007B4 0x00003FFF 0x00000380
mask_write 0XF80007B8 0x00003F01 0x00000201
mask_write 0XF80007BC 0x00003F01 0x00000201
mask_write 0XF80007C0 0x00003FFF 0x000002E0
mask_write 0XF80007C4 0x00003FFF 0x000002E1
mask_write 0XF80007C8 0x00003FFF 0x00000200
mask_write 0XF80007CC 0x00003FFF 0x00000200
mask_write 0XF80007D0 0x00003FFF 0x00000280
mask_write 0XF80007D4 0x00003FFF 0x00000280
mask_write 0XF8000830 0x003F003F 0x002F002E
mwr -force 0XF8000004 0x0000767B
}
proc ps7_peripherals_init_data_1_0 {} {
mwr -force 0XF8000008 0x0000DF0D
mask_write 0XF8000B48 0x00000180 0x00000180
mask_write 0XF8000B4C 0x00000180 0x00000180
mask_write 0XF8000B50 0x00000180 0x00000180
mask_write 0XF8000B54 0x00000180 0x00000180
mwr -force 0XF8000004 0x0000767B
mask_write 0XE0001034 0x000000FF 0x00000006
mask_write 0XE0001018 0x0000FFFF 0x0000003E
mask_write 0XE0001000 0x000001FF 0x00000017
mask_write 0XE0001004 0x00000FFF 0x00000020
mask_write 0XE000D000 0x00080000 0x00080000
mask_write 0XF8007000 0x20000000 0x00000000
}
proc ps7_post_config_1_0 {} {
mwr -force 0XF8000008 0x0000DF0D
mask_write 0XF8000900 0x0000000F 0x0000000F
mask_write 0XF8000240 0xFFFFFFFF 0x00000000
mwr -force 0XF8000004 0x0000767B
}
proc ps7_debug_1_0 {} {
mwr -force 0XF8898FB0 0xC5ACCE55
mwr -force 0XF8899FB0 0xC5ACCE55
mwr -force 0XF8809FB0 0xC5ACCE55
}
set PCW_SILICON_VER_1_0 "0x0"
set PCW_SILICON_VER_2_0 "0x1"
set PCW_SILICON_VER_3_0 "0x2"
set APU_FREQ 666666667
proc mask_poll { addr mask } {
set count 1
set curval "0x[string range [mrd $addr] end-8 end]"
set maskedval [expr {$curval & $mask}]
while { $maskedval == 0 } {
set curval "0x[string range [mrd $addr] end-8 end]"
set maskedval [expr {$curval & $mask}]
set count [ expr { $count + 1 } ]
if { $count == 100000000 } {
puts "Timeout Reached. Mask poll failed at ADDRESS: $addr MASK: $mask"
break
}
}
}
proc mask_delay { addr val } {
set delay [ get_number_of_cycles_for_delay $val ]
perf_reset_and_start_timer
set curval "0x[string range [mrd $addr] end-8 end]"
set maskedval [expr {$curval < $delay}]
while { $maskedval == 1 } {
set curval "0x[string range [mrd $addr] end-8 end]"
set maskedval [expr {$curval < $delay}]
}
perf_reset_clock
}
proc ps_version { } {
set si_ver "0x[string range [mrd 0xF8007080] end-8 end]"
set mask_sil_ver "0x[expr {$si_ver >> 28}]"
return $mask_sil_ver;
}
proc ps7_post_config {} {
ps7_post_config_1_0
}
proc ps7_debug {} {
ps7_debug_1_0
}
proc ps7_init {} {
ps7_mio_init_data_1_0
ps7_pll_init_data_1_0
ps7_clock_init_data_1_0
ps7_ddr_init_data_1_0
ps7_peripherals_init_data_1_0
}
# For delay calculation using global timer
# start timer
proc perf_start_clock { } {
#writing SCU_GLOBAL_TIMER_CONTROL register
mask_write 0xF8F00208 0x00000109 0x00000009
}
# stop timer and reset timer count regs
proc perf_reset_clock { } {
perf_disable_clock
mask_write 0xF8F00200 0xFFFFFFFF 0x00000000
mask_write 0xF8F00204 0xFFFFFFFF 0x00000000
}
# Compute mask for given delay in miliseconds
proc get_number_of_cycles_for_delay { delay } {
# GTC is always clocked at 1/2 of the CPU frequency (CPU_3x2x)
variable APU_FREQ
return [ expr ($delay * $APU_FREQ /(2 * 1000))]
}
# stop timer
proc perf_disable_clock {} {
mask_write 0xF8F00208 0xFFFFFFFF 0x00000000
}
proc perf_reset_and_start_timer {} {
perf_reset_clock
perf_start_clock
}

24
run.py Executable file
View File

@ -0,0 +1,24 @@
#!/usr/bin/env python
import subprocess
import argparse
def build_experiment(exp, dev_db=None):
output = "firmware/runtime/exp.a"
if not dev_db:
dev_db = "experiments/device_db.py"
subprocess.run(["artiq_compile", "--target", "zynq", "--static", "-o", output, "--device-db", dev_db, exp])
def build_firmware():
subprocess.run(["python", "zedboard.py", "--no-compile-gateware"])
def load():
subprocess.run(["./load.py", "firmware", "run"])
parser = argparse.ArgumentParser()
parser.add_argument("path")
args = parser.parse_args()
build_experiment(args.path)
build_firmware()
load()

46
test_hp_dma.py Executable file
View File

@ -0,0 +1,46 @@
from migen import *
from hp_dma import *
def test(dut):
yield from dut.addr_base.write(0x12340)
yield from dut.n_bursts.write(3)
for _ in range(5):
yield
yield dut.bus.ar.ready.eq(1)
yield
yield from dut.trigger.write(1)
def deliver_read_word(w, last=False):
yield dut.bus.r.data.eq(w)
yield dut.bus.r.valid.eq(1)
if last:
yield dut.bus.r.last.eq(1)
for _ in range(100):
yield
if (yield dut.bus.r.ready):
yield dut.bus.r.valid.eq(0)
yield dut.bus.r.last.eq(0)
break
yield
N=(yield dut.bus.ar.len)+1
for _ in range( (yield dut.n_bursts.storage)+1 ):
for i in range(N):
yield from deliver_read_word(2*i | (2*i+1)<<32, last=i==N-1)
for _ in range(5):
yield
for _ in range(10):
yield
if __name__ == "__main__":
dut = HP_DMA_READ()
run_simulation(dut, test(dut), vcd_name="test.vcd", clocks={"sys": 8})

68
test_maxi_dma.py Executable file
View File

@ -0,0 +1,68 @@
from migen import *
from maxi_dma import *
def test_basic(dut):
yield from dut.engine.addr_base.write(0x12340)
for _ in range(5):
yield
yield dut.engine.bus.ar.ready.eq(1)
yield
yield dut.trigger.eq(1)
while True:
if (yield dut.engine.bus.ar.valid):
break
yield
yield dut.engine.bus.ar.ready.eq(0)
yield dut.trigger.eq(0)
def deliver_read_word(w, last=False):
yield dut.engine.bus.r.data.eq(w)
yield dut.engine.bus.r.valid.eq(1)
if last:
yield dut.engine.bus.r.last.eq(1)
for _ in range(100):
yield
if (yield dut.engine.bus.r.ready):
yield dut.engine.bus.r.valid.eq(0)
yield dut.engine.bus.r.last.eq(0)
break
yield
for i in range(4):
yield from deliver_read_word(2*i | (2*i+1)<<32, last=i==3)
for _ in range(5):
yield
while True:
if (yield dut.engine.bus.aw.valid):
break
yield
yield dut.engine.bus.aw.ready.eq(1)
yield
yield dut.engine.bus.aw.ready.eq(0)
yield dut.engine.bus.w.ready.eq(1)
for _ in range(10):
yield
class Wrapper(Module):
def __init__(self):
self.trigger = Signal()
self.submodules.engine = MAXI_DMA(trigger_stb=self.trigger)
self.submodules.dma_test = DMA_Test(self.engine)
if __name__ == "__main__":
dut = Wrapper()
run_simulation(dut, test_basic(dut), vcd_name="test.vcd", clocks={"sys": 8})

79
test_rtio_dma.py Executable file
View File

@ -0,0 +1,79 @@
from migen import *
from maxi_dma import *
def test(dut):
def delay_cycles(N):
for _ in range(N):
yield
yield from delay_cycles(4)
yield dut.trigger_stb.eq(1)
yield
yield dut.trigger_stb.eq(0)
yield from delay_cycles(2)
assert (yield dut.din_ready)==0
douts = [
(0x2<<32) | (1<< 24) | 1, # address, cmd, channel
0x55, # timestamp
0x111111, # Data
0x0
]
yield dut.dout_stb.eq(1)
for i in range( (yield dut.out_burst_len) ):
yield dut.dout_index.eq(i)
yield dut.dout.eq(douts[i])
yield
yield dut.dout_stb.eq(0)
# yield dut.h.cri.o_status.eq(0x3)
yield from delay_cycles(10)
yield dut.h.cri.i_data.eq(1)
yield dut.h.cri.i_timestamp.eq(2)
yield dut.h.cri.i_status.eq(4)
while True:
if (yield dut.din_ready):
break
yield
yield dut.din_stb.eq(1)
print("Got: ")
dins = []
for i in range( (yield dut.in_burst_len) ):
yield dut.din_index.eq(i)
yield
dins.append( (yield dut.din) )
yield dut.din_stb.eq(0)
print(dins)
class Wrapper(Module):
def __init__(self):
self.dout_stb = Signal()
self.din_stb = Signal()
self.dout_index = Signal(max=16)
self.din_index = Signal(max=16)
self.din_ready = Signal()
self.dout = Signal(64)
self.din = Signal(64)
self.out_burst_len = Signal(max=16)
self.in_burst_len = Signal(max=16)
self.trigger_stb = Signal()
self.submodules.h = DMA_KernelInitiator(self)
if __name__ == "__main__":
dut = Wrapper()
run_simulation(dut, test(dut), vcd_name="test_rtio_dma.vcd", clocks={"sys": 8})

61
xilinx-tcl.cfg Executable file
View File

@ -0,0 +1,61 @@
#
# TCL to allow the Xilinx PS7 Init TCL code to run in OpenOCD.
#
proc mrd { args } {
if {[llength $args] == 0} {
echo "mrd address \[count \[w|h|b\]\]"
echo " Read <count> memory locations starting at <address>. Defaults to one word."
return
}
set addr [lindex $args 0]
set count 1
set bits 32
if {[llength $args] > 1} {
set count [lindex $args 1]
if {[llength $args] > 2} {
switch [lindex $args 2] {
w { set bits 32 }
h { set bits 16 }
b { set bits 8 }
default { set bits 32 }
}
}
}
mem2array x $bits $addr $count
set nibbles [expr {$bits / 4}]
set bytes [expr {$bits / 8}]
set result {}
foreach {idx elmt} $x {
append result [format "%08x: %0*x\n" [expr {$addr + $idx * $bytes}] $nibbles $elmt]
}
return $result
}
proc mwr { args } {
set addr [lindex $args 1]
set data [lindex $args 2]
mww $addr $data
}
proc mask_write { addr mask value } {
set curval "0x[string range [mrd $addr] end-8 end]"
set maskedval [expr {$curval & ~$mask}]
#echo "curval = [format 0x%08x $curval] maskedval = [format 0x%08x $maskedval]"
set writeval(0) [expr {$maskedval | $value}]
#echo " $addr <= [format 0x%08x $writeval(0)] ([format 0x%08x $curval]: [format 0x%08x $mask]/[format 0x%08x $value])"
array2mem writeval 32 $addr 1
}
proc xilinx_ps7_init { } {
poll off
reset init
reset halt
targets zynq.cpu.0
sleep 100
halt
ps7_debug
ps7_init
ps7_post_config
poll on
}

180
zedboard.py Executable file
View File

@ -0,0 +1,180 @@
from migen_axi.integration.soc_core import SoCCore
from migen_axi.platforms import zedboard
from migen import *
from misoc.interconnect.csr import *
from migen.genlib.resetsync import AsyncResetSynchronizer
from migen.genlib.cdc import MultiReg
from misoc.integration.builder import *
from artiq.gateware import rtio
from artiq.gateware.rtio.phy import ttl_simple, ttl_serdes_7series, spi2
from artiq.gateware import eem
from artiq.gateware.rtio.phy import ttl_serdes_7series, ttl_simple
from artiq.gateware import fmcdio_vhdci_eem
from maxi_dma import MAXI_DMA, DMA_KernelInitiator, DMA_Test
from hp_dma import HP_DMA_READ
from operator import attrgetter
import argparse
import os
class _RTIOCRG(Module, AutoCSR):
def __init__(self):
self._pll_reset = CSRStorage(reset=1)
self._pll_locked = CSRStatus()
self.clock_domains.cd_sys = ClockDomain()
self.clock_domains.cd_rtio = ClockDomain()
# self.clock_domains.cd_rtiox4 = ClockDomain(reset_less=True)
pll_locked = Signal()
rtio_clk = Signal()
rtiox4_clk = Signal()
self.specials += [
Instance("PLLE2_ADV",
p_STARTUP_WAIT="FALSE", o_LOCKED=pll_locked,
p_REF_JITTER1=0.24,
p_CLKIN1_PERIOD=8.0, p_CLKIN2_PERIOD=8.0,
i_CLKIN2=self.cd_sys.clk,
# Warning: CLKINSEL=0 means CLKIN2 is selected
i_CLKINSEL=0,
# VCO @ 1GHz when using 125MHz input
p_CLKFBOUT_MULT=8, p_DIVCLK_DIVIDE=1,
i_CLKFBIN=self.cd_rtio.clk,
i_RST=self._pll_reset.storage,
o_CLKFBOUT=rtio_clk,
# p_CLKOUT0_DIVIDE=2, p_CLKOUT0_PHASE=0.0,
# o_CLKOUT0=rtiox4_clk
),
Instance("BUFG", i_I=rtio_clk, o_O=self.cd_rtio.clk),
# Instance("BUFG", i_I=rtiox4_clk, o_O=self.cd_rtiox4.clk),
AsyncResetSynchronizer(self.cd_rtio, ~pll_locked),
MultiReg(pll_locked, self._pll_locked.status)
]
def fix_serdes_timing_path(platform):
# ignore timing of path from OSERDESE2 through the pad to ISERDESE2
platform.add_platform_command(
"set_false_path -quiet "
"-through [get_pins -filter {{REF_PIN_NAME == OQ || REF_PIN_NAME == TQ}} "
"-of [get_cells -filter {{REF_NAME == OSERDESE2}}]] "
"-to [get_pins -filter {{REF_PIN_NAME == D}} "
"-of [get_cells -filter {{REF_NAME == ISERDESE2}}]]"
)
class Zedboard(SoCCore):
def __init__(self):
plat = zedboard.Platform()
super().__init__(platform=plat)
fclk0 = self.ps7.fclk.clk[0]
self.clock_domains.cd_sys = ClockDomain()
self.specials += Instance("BUFG", i_I=fclk0, o_O=self.cd_sys.clk),
plat.add_platform_command("create_clock -name clk_fpga_0 -period 8 [get_pins \"PS7/FCLKCLK[0]\"]")
plat.add_platform_command("set_input_jitter clk_fpga_0 0.24")
self.evento_stb = Signal()
evento_latched = Signal()
evento_latched_d = Signal()
self.sync += evento_latched.eq(self.ps7.event.o)
self.sync += evento_latched_d.eq(evento_latched)
self.comb += self.evento_stb.eq(evento_latched != evento_latched_d)
self.submodules.hp_dma = HP_DMA_READ(bus=self.ps7.s_axi_hp0)
self.csr_devices.append("hp_dma")
# Debug ports
# pads_b = plat.request("pmod",1)
# ar, aw, w, r, b = attrgetter("ar", "aw", "w", "r", "b")(self.dma.bus)
# self.comb += pads_b[0].eq(self.dma.trigger_stb)
plat.add_extension(fmcdio_vhdci_eem.io)
plat.add_connectors(fmcdio_vhdci_eem.connectors)
self.rtio_channels = []
for i in range(4):
pad = plat.request("user_led", i)
phy = ttl_simple.InOut(pad)
self.submodules += phy
self.rtio_channels.append(rtio.Channel.from_phy(phy))
for i in range(4):
led = plat.request("user_led", i+4)
s = Signal()
btn = plat.request("user_btn", i)
self.comb += led.eq(s | btn)
self.comb += s.eq(self.ps7.gpio.o[i])
pads = plat.request("pmod",0)
for i in range(8):
phy = ttl_simple.InOut(pads[i])
self.submodules += phy
self.rtio_channels.append(rtio.Channel.from_phy(phy))
ttl_phy = ttl_simple.Output
eem.Urukul.add_std(self, 0, 1, ttl_phy, iostandard="LVDS_25")
eem.Urukul.add_std(self, 2, 3, ttl_phy, iostandard="LVDS_25")
self.add_rtio(self.rtio_channels)
def add_rtio(self, rtio_channels):
self.submodules.rtio_crg = _RTIOCRG()
self.csr_devices.append("rtio_crg")
self.submodules.rtio_core = rtio.Core(rtio_channels)
self.csr_devices.append("rtio_core")
self.submodules.rtio = rtio.KernelInitiator()
self.csr_devices.append("rtio")
self.submodules.dma = MAXI_DMA(bus=self.ps7.s_axi_acp,
user=self.ps7.s_axi_acp_user,
trigger_stb=self.evento_stb)
self.csr_devices.append("dma")
self.submodules.rtio_dma = DMA_KernelInitiator(engine=self.dma)
self.submodules.cri_con = rtio.CRIInterconnectShared(
[self.rtio.cri, self.rtio_dma.cri],
[self.rtio_core.cri])
self.csr_devices.append("cri_con")
self.platform.add_false_path_constraints(
self.rtio_crg.cd_rtio.clk)
self.comb += self.rtio_crg.cd_sys.clk.eq(self.cd_sys.clk)
def main():
parser = argparse.ArgumentParser()
builder_args(parser)
args = parser.parse_args()
soc = Zedboard()
builder = Builder(soc, **builder_argdict(args))
builder.software_packages = []
root_path = os.path.dirname(os.path.abspath(__file__))
builder.add_software_package("libm")
builder.add_software_package("libprintf")
builder.add_software_package("libunwind")
builder.add_software_package("libbase")
builder.add_software_package("runtime", os.path.join(root_path, "firmware/runtime"))
builder.build()
if __name__ == "__main__":
main()

211
zynq-7000.cfg Normal file
View File

@ -0,0 +1,211 @@
#
# Xilinx Zynq 7000 SoC
#
# Chris Johns <chrisj@rtems.org>
#
# Setup
# -----
#
# Create a user configuration following the "Configuration Basics" in the user
# documentation. In the file have:
#
# source [find interface/ftdi/flyswatter2.cfg]
# source [find board/zynq-zc706-eval.cfg]
# adapter_khz 2000
# init
#
if { [info exists CHIPNAME] } {
global _CHIPNAME
set _CHIPNAME $CHIPNAME
} else {
global _CHIPNAME
set _CHIPNAME zynq
}
if { [info exists ENDIAN] } {
set _ENDIAN $ENDIAN
} else {
# this defaults to a bigendian
set _ENDIAN little
}
if { [info exists SMP] } {
global _SMP
set _SMP 1
} else {
global _SMP
set _SMP 0
}
#
# PL Tap.
#
# See ug585 ZYNQ-7000 TRM PSS_IDCODE for how this number is constructed.
# 0x03731093 - ZC706 Eval board 1.1
# 0x23731093 - ??
# 0x23727093 - Zedboard Rev. C and D
#
# Set in your configuration file or board specific file.
#
if { [info exists PL_TAPID] } {
set _PL_TAPID $PL_TAPID
} else {
set _PL_TAPID 0x03731093
}
jtag newtap $_CHIPNAME tap -irlen 6 -ircapture 0x001 -irmask 0x003 \
-expected-id $_PL_TAPID
#
# CoreSight Debug Access Port
#
if { [info exists DAP_TAPID] } {
set _DAP_TAPID $DAP_TAPID
} else {
set _DAP_TAPID 0x4ba00477
}
jtag newtap $_CHIPNAME dap -irlen 4 -ircapture 0x01 -irmask 0x03 \
-expected-id $_DAP_TAPID
#
# GDB target: Cortex-A9, using DAP, configuring only one core
# Base addresses of cores:
# core 0 - 0xF8890000
# core 1 - 0xF8892000
#
# Read from the ROM table with the patch to read the nested table.
#
set _TARGETNAME_0 $_CHIPNAME.cpu.0
set _TARGETNAME_1 $_CHIPNAME.cpu.1
target create $_TARGETNAME_0 cortex_a -coreid 0 \
-endian $_ENDIAN \
-chain-position $_CHIPNAME.dap \
-dbgbase 0x80090000
if { $_SMP } {
echo "Zynq CPU1."
target create $_TARGETNAME_1 cortex_a -coreid 1 \
-endian $_ENDIAN \
-chain-position $_CHIPNAME.dap \
-dbgbase 0x80092000
target smp $_TARGETNAME_0 $_TARGETNAME_1
}
#
# Hack to get the registers into a stable state when first booting a zynq in
# JTAG mode. If r11 is pointing to an invalid address and you use gdb to set a
# register the write will fail because gdb attempts to scan or unwind the
# current frame and the bad address seems to lock the bus up. This code puts
# the registers into the OCM and hopefull safe.
#
proc zynq_clear_registers { target } {
echo "Zynq-7000 Series setup: $target"
set _OCM_END 0x0003FFF0
mww phys 0xF8007000 0x4E00E07F
reg r0 0
reg r1 0
reg r2 0
reg r3 0
reg r4 0
reg r5 0
reg r6 0
reg r7 0
reg r8 0
reg r9 0
reg r10 0
reg r11 $_OCM_END
reg sp_svc $_OCM_END
reg lr_svc $_OCM_END
reg sp_abt $_OCM_END
reg lr_abt $_OCM_END
reg sp_und $_OCM_END
reg lr_und $_OCM_END
}
proc zynq_disable_mmu_and_caches { target } {
# arm mcr pX op1 CRn CRm op2 value
echo "Disable MMU and caches"
# Invalidate caches
catch {
$target arm mcr 15 0 7 5 0 0
$target arm mcr 15 0 7 7 0 0
# Invalidate all TLBs
$target arm mcr 15 0 8 5 0 0
$target arm mcr 15 0 8 6 0 0
$target arm mcr 15 0 8 7 0 0
$target arm mcr 15 4 8 3 0 0
$target arm mcr 15 4 8 7 0 0
set cp [$target arm mrc 15 0 1 0 0]
echo "SCTRL => [format 0x%x $cp]"
set mask [expr 1 << 29 | 1 << 12 | 1 << 11 | 1 << 2 | 1 << 1 | 1 << 0]
set cp [expr ($cp & ~$mask)]
$target arm mcr 15 0 1 0 0 $cp
echo "SCTRL <= [format 0x%x $cp]"
}
}
proc zynq_boot_ocm_setup { } {
#
# Enable the OCM
#
echo "Zynq Boot OCM setup"
catch {
mww phys 0xF8000008 0xDF0D
mww phys 0xF8000238 0
mww phys 0xF8000910 0xC
}
}
proc zynq_rtems_setup { } {
cache_config l2x 0xF8F02000 8
cortex_a maskisr on
}
proc zynq_restart { wait } {
global _SMP
global _TARGETNAME_0
global _TARGETNAME_1
set target0 $_TARGETNAME_0
set target1 $_TARGETNAME_1
echo "Zynq reset, resetting the board ... "
poll off
#
# Issue the reset via the SLCR
#
catch {
mww phys 0xF8000008 0xDF0D
mww phys 0xF8000200 1
}
echo "Zynq reset waiting for $wait msecs ... "
sleep $wait
#
# Reconnect the DAP etc due to the reset.
#
$target0 cortex_a dbginit
$target0 arm core_state arm
if { $_SMP } {
$target1 arm core_state arm
$target1 cortex_a dbginit
cortex_a smp_off
}
poll on
#
# We can now halt the core.
#
if { $_SMP } {
targets $target1
halt
}
targets $target0
halt
zynq_rtems_setup
}
proc zynq_gdb_attach { target } {
catch {
halt
}
}