forked from M-Labs/artiq
netboot: support slave FPGA loading
This commit is contained in:
parent
307f39e900
commit
b25a17fa37
@ -140,15 +140,14 @@ fn load_slave_fpga() {
|
|||||||
println!(" ...Error during loading: {}", e);
|
println!(" ...Error during loading: {}", e);
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if let Err(e) = slave_fpga::complete() {
|
if let Err(e) = slave_fpga::startup() {
|
||||||
println!(" ...Error during completion: {}", e);
|
println!(" ...Error during startup: {}", e);
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
println!(" ...done");
|
println!(" ...done");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn flash_boot() {
|
fn flash_boot() {
|
||||||
const FIRMWARE: *mut u8 = board_mem::FLASH_BOOT_ADDRESS as *mut u8;
|
const FIRMWARE: *mut u8 = board_mem::FLASH_BOOT_ADDRESS as *mut u8;
|
||||||
const MAIN_RAM: *mut u8 = board_mem::MAIN_RAM_BASE as *mut u8;
|
const MAIN_RAM: *mut u8 = board_mem::MAIN_RAM_BASE as *mut u8;
|
||||||
@ -193,8 +192,16 @@ enum NetConnState {
|
|||||||
WaitCommand,
|
WaitCommand,
|
||||||
FirmwareLength(usize, u8),
|
FirmwareLength(usize, u8),
|
||||||
FirmwareDownload(usize, usize),
|
FirmwareDownload(usize, usize),
|
||||||
WaitO,
|
FirmwareWaitO,
|
||||||
WaitK
|
FirmwareWaitK,
|
||||||
|
#[cfg(has_slave_fpga_cfg)]
|
||||||
|
GatewareLength(usize, u8),
|
||||||
|
#[cfg(has_slave_fpga_cfg)]
|
||||||
|
GatewareDownload(usize, usize),
|
||||||
|
#[cfg(has_slave_fpga_cfg)]
|
||||||
|
GatewareWaitO,
|
||||||
|
#[cfg(has_slave_fpga_cfg)]
|
||||||
|
GatewareWaitK
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(has_ethmac)]
|
#[cfg(has_ethmac)]
|
||||||
@ -228,6 +235,12 @@ impl NetConn {
|
|||||||
self.state = NetConnState::FirmwareLength(0, 0);
|
self.state = NetConnState::FirmwareLength(0, 0);
|
||||||
Ok(1)
|
Ok(1)
|
||||||
},
|
},
|
||||||
|
#[cfg(has_slave_fpga_cfg)]
|
||||||
|
b'G' => {
|
||||||
|
println!("Received gateware load command");
|
||||||
|
self.state = NetConnState::GatewareLength(0, 0);
|
||||||
|
Ok(1)
|
||||||
|
}
|
||||||
b'B' => {
|
b'B' => {
|
||||||
if self.firmware_downloaded {
|
if self.firmware_downloaded {
|
||||||
println!("Received boot command");
|
println!("Received boot command");
|
||||||
@ -245,6 +258,7 @@ impl NetConn {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
NetConnState::FirmwareLength(firmware_length, recv_bytes) => {
|
NetConnState::FirmwareLength(firmware_length, recv_bytes) => {
|
||||||
let firmware_length = (firmware_length << 8) | (buf[0] as usize);
|
let firmware_length = (firmware_length << 8) | (buf[0] as usize);
|
||||||
let recv_bytes = recv_bytes + 1;
|
let recv_bytes = recv_bytes + 1;
|
||||||
@ -269,23 +283,23 @@ impl NetConn {
|
|||||||
|
|
||||||
let recv_bytes = recv_bytes + length;
|
let recv_bytes = recv_bytes + length;
|
||||||
if recv_bytes == firmware_length {
|
if recv_bytes == firmware_length {
|
||||||
self.state = NetConnState::WaitO;
|
self.state = NetConnState::FirmwareWaitO;
|
||||||
Ok(length)
|
Ok(length)
|
||||||
} else {
|
} else {
|
||||||
self.state = NetConnState::FirmwareDownload(firmware_length, recv_bytes);
|
self.state = NetConnState::FirmwareDownload(firmware_length, recv_bytes);
|
||||||
Ok(length)
|
Ok(length)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
NetConnState::WaitO => {
|
NetConnState::FirmwareWaitO => {
|
||||||
if buf[0] == b'O' {
|
if buf[0] == b'O' {
|
||||||
self.state = NetConnState::WaitK;
|
self.state = NetConnState::FirmwareWaitK;
|
||||||
Ok(1)
|
Ok(1)
|
||||||
} else {
|
} else {
|
||||||
println!("End-of-firmware confirmation failed");
|
println!("End-of-firmware confirmation failed");
|
||||||
Err(())
|
Err(())
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
NetConnState::WaitK => {
|
NetConnState::FirmwareWaitK => {
|
||||||
if buf[0] == b'K' {
|
if buf[0] == b'K' {
|
||||||
println!("Firmware successfully downloaded");
|
println!("Firmware successfully downloaded");
|
||||||
self.state = NetConnState::WaitCommand;
|
self.state = NetConnState::WaitCommand;
|
||||||
@ -296,6 +310,71 @@ impl NetConn {
|
|||||||
Err(())
|
Err(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(has_slave_fpga_cfg)]
|
||||||
|
NetConnState::GatewareLength(gateware_length, recv_bytes) => {
|
||||||
|
let gateware_length = (gateware_length << 8) | (buf[0] as usize);
|
||||||
|
let recv_bytes = recv_bytes + 1;
|
||||||
|
if recv_bytes == 4 {
|
||||||
|
if let Err(e) = slave_fpga::prepare() {
|
||||||
|
println!(" Error during slave FPGA preparation: {}", e);
|
||||||
|
return Err(())
|
||||||
|
}
|
||||||
|
self.state = NetConnState::GatewareDownload(gateware_length, 0);
|
||||||
|
} else {
|
||||||
|
self.state = NetConnState::GatewareLength(gateware_length, recv_bytes);
|
||||||
|
}
|
||||||
|
Ok(1)
|
||||||
|
},
|
||||||
|
#[cfg(has_slave_fpga_cfg)]
|
||||||
|
NetConnState::GatewareDownload(gateware_length, recv_bytes) => {
|
||||||
|
let max_length = gateware_length - recv_bytes;
|
||||||
|
let buf = if buf.len() > max_length {
|
||||||
|
&buf[..max_length]
|
||||||
|
} else {
|
||||||
|
&buf[..]
|
||||||
|
};
|
||||||
|
let length = buf.len();
|
||||||
|
|
||||||
|
if let Err(e) = slave_fpga::input(buf) {
|
||||||
|
println!("Error during slave FPGA loading: {}", e);
|
||||||
|
return Err(())
|
||||||
|
}
|
||||||
|
|
||||||
|
let recv_bytes = recv_bytes + length;
|
||||||
|
if recv_bytes == gateware_length {
|
||||||
|
self.state = NetConnState::GatewareWaitO;
|
||||||
|
Ok(length)
|
||||||
|
} else {
|
||||||
|
self.state = NetConnState::GatewareDownload(gateware_length, recv_bytes);
|
||||||
|
Ok(length)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
#[cfg(has_slave_fpga_cfg)]
|
||||||
|
NetConnState::GatewareWaitO => {
|
||||||
|
if buf[0] == b'O' {
|
||||||
|
self.state = NetConnState::GatewareWaitK;
|
||||||
|
Ok(1)
|
||||||
|
} else {
|
||||||
|
println!("End-of-gateware confirmation failed");
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
},
|
||||||
|
#[cfg(has_slave_fpga_cfg)]
|
||||||
|
NetConnState::GatewareWaitK => {
|
||||||
|
if buf[0] == b'K' {
|
||||||
|
if let Err(e) = slave_fpga::startup() {
|
||||||
|
println!("Error during slave FPGA startup: {}", e);
|
||||||
|
return Err(())
|
||||||
|
}
|
||||||
|
println!("Gateware successfully downloaded");
|
||||||
|
self.state = NetConnState::WaitCommand;
|
||||||
|
Ok(1)
|
||||||
|
} else {
|
||||||
|
println!("End-of-gateware confirmation failed");
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@ pub fn input(data: &[u8]) -> Result<(), &'static str> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn complete() -> Result<(), &'static str> {
|
pub fn startup() -> Result<(), &'static str> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let t = clock::get_ms();
|
let t = clock::get_ms();
|
||||||
while csr::slave_fpga_cfg::in_read() & DONE_BIT == 0 {
|
while csr::slave_fpga_cfg::in_read() & DONE_BIT == 0 {
|
||||||
|
@ -5,12 +5,29 @@ import socket
|
|||||||
import struct
|
import struct
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
|
||||||
|
def send_file(sock, filename):
|
||||||
|
with open(filename, "rb") as input_file:
|
||||||
|
sock.sendall(struct.pack(">I", os.fstat(input_file.fileno()).st_size))
|
||||||
|
while True:
|
||||||
|
data = input_file.read(4096)
|
||||||
|
if not data:
|
||||||
|
break
|
||||||
|
sock.sendall(data)
|
||||||
|
sock.sendall(b"OK")
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
parser = argparse.ArgumentParser(description="ARTIQ netboot tool")
|
parser = argparse.ArgumentParser(description="ARTIQ netboot tool")
|
||||||
parser.add_argument("hostname", metavar="HOSTNAME",
|
parser.add_argument("hostname", metavar="HOSTNAME",
|
||||||
help="hostname of the target board")
|
help="hostname of the target board")
|
||||||
parser.add_argument("-f", "--firmware", nargs=1,
|
parser.add_argument("-f", "--firmware", nargs=1,
|
||||||
help="firmware to load")
|
help="firmware to load")
|
||||||
|
# Note that on softcore systems, the main gateware cannot be replaced
|
||||||
|
# with -g. This option is used for loading the RTM FPGA from the AMC
|
||||||
|
# on Sayma, and the PL on Zynq.
|
||||||
|
parser.add_argument("-g", "--gateware", nargs=1,
|
||||||
|
help="gateware to load")
|
||||||
parser.add_argument("-b", "--boot", action="store_true",
|
parser.add_argument("-b", "--boot", action="store_true",
|
||||||
help="boot the device")
|
help="boot the device")
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
@ -18,15 +35,11 @@ def main():
|
|||||||
sock = socket.create_connection((args.hostname, 4269))
|
sock = socket.create_connection((args.hostname, 4269))
|
||||||
try:
|
try:
|
||||||
if args.firmware is not None:
|
if args.firmware is not None:
|
||||||
with open(args.firmware[0], "rb") as input_file:
|
sock.sendall(b"F")
|
||||||
sock.sendall(b"F")
|
send_file(sock, args.firmware[0])
|
||||||
sock.sendall(struct.pack(">I", os.fstat(input_file.fileno()).st_size))
|
if args.gateware is not None:
|
||||||
while True:
|
sock.sendall(b"G")
|
||||||
data = input_file.read(4096)
|
send_file(sock, args.gateware[0])
|
||||||
if not data:
|
|
||||||
break
|
|
||||||
sock.sendall(data)
|
|
||||||
sock.sendall(b"OK")
|
|
||||||
if args.boot:
|
if args.boot:
|
||||||
sock.sendall(b"B")
|
sock.sendall(b"B")
|
||||||
finally:
|
finally:
|
||||||
|
Loading…
Reference in New Issue
Block a user