netboot: support slave FPGA loading

This commit is contained in:
Sebastien Bourdeauducq 2019-11-05 16:28:49 +08:00
parent 307f39e900
commit b25a17fa37
3 changed files with 111 additions and 19 deletions

View File

@ -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(())
}
}
} }
} }

View File

@ -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 {

View File

@ -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: