initial commit
This commit is contained in:
commit
e139aa0ae9
10
.gitignore
vendored
Normal file
10
.gitignore
vendored
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
gateware/build
|
||||||
|
misoc_*
|
||||||
|
*.o
|
||||||
|
*.a
|
||||||
|
*.d
|
||||||
|
*.elf
|
||||||
|
*.bin
|
||||||
|
*.lock
|
||||||
|
*.vcd
|
||||||
|
__pycache__
|
70
experiments/dds_timing.py
Executable file
70
experiments/dds_timing.py
Executable 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
147
experiments/device_db.py
Executable 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
46
experiments/mandelbrot.py
Executable 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
14
experiments/minimal.py
Executable 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
93
experiments/ttl.py
Executable 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
18
experiments/wall_time.py
Executable 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
7
firmware/Cargo.toml
Executable file
@ -0,0 +1,7 @@
|
|||||||
|
[workspace]
|
||||||
|
members = ["runtime"]
|
||||||
|
|
||||||
|
[profile.dev]
|
||||||
|
incremental = true
|
||||||
|
lto = false
|
||||||
|
opt-level = 2
|
14
firmware/libboard_misoc/Cargo.toml
Executable file
14
firmware/libboard_misoc/Cargo.toml
Executable 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
56
firmware/libboard_misoc/lib.rs
Executable 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
14
firmware/libboard_misoc/uart.rs
Executable 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);
|
||||||
|
}
|
||||||
|
}
|
30
firmware/libboard_misoc/uart_console.rs
Executable file
30
firmware/libboard_misoc/uart_console.rs
Executable 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)*));
|
||||||
|
}
|
8
firmware/libdyld/Cargo.toml
Normal file
8
firmware/libdyld/Cargo.toml
Normal 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
2737
firmware/libdyld/elf.rs
Normal file
File diff suppressed because it is too large
Load Diff
339
firmware/libdyld/lib.rs
Normal file
339
firmware/libdyld/lib.rs
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
BIN
firmware/libksupport/._eh.rs
Normal file
BIN
firmware/libksupport/._eh.rs
Normal file
Binary file not shown.
20
firmware/libksupport/Cargo.toml
Executable file
20
firmware/libksupport/Cargo.toml
Executable 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
89
firmware/libksupport/api.rs
Executable 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
12
firmware/libksupport/build.rs
Executable 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
602
firmware/libksupport/eh.rs
Normal 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
68
firmware/libksupport/glue.c
Executable 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
59
firmware/libksupport/lib.rs
Executable 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
337
firmware/libksupport/rtio.rs
Executable 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)")
|
||||||
|
}
|
15
firmware/libunwind-rs/Cargo.toml
Executable file
15
firmware/libunwind-rs/Cargo.toml
Executable 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
41
firmware/libunwind-rs/build.rs
Executable 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
29
firmware/libunwind-rs/lib.rs
Executable 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::*;
|
273
firmware/libunwind-rs/libunwind.rs
Executable file
273
firmware/libunwind-rs/libunwind.rs
Executable 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
20
firmware/runtime/Cargo.toml
Executable 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
27
firmware/runtime/Makefile
Executable 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
17
firmware/runtime/build.rs
Executable 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
68
firmware/runtime/glue.c
Executable 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
83
firmware/runtime/lscript.ld
Executable 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
92
firmware/runtime/main.rs
Executable 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
320
firmware/runtime/startup.S
Executable 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
|
185
firmware/runtime/translation_table.S
Executable file
185
firmware/runtime/translation_table.S
Executable 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
106
hp_dma.py
Executable 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
90
load.py
Executable 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
284
maxi_dma.py
Executable 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
771
ps7_init.tcl
Executable 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
24
run.py
Executable 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
46
test_hp_dma.py
Executable 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
68
test_maxi_dma.py
Executable 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
79
test_rtio_dma.py
Executable 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
61
xilinx-tcl.cfg
Executable 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
180
zedboard.py
Executable 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
211
zynq-7000.cfg
Normal 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
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user