Skip to content

Commit 4bf7875

Browse files
fallensbourdeauducq
authored andcommittedMay 27, 2015
flash_storage: refactor + unit tests + artiq_coreconfig.py CLI + doc
1 parent 36cda96 commit 4bf7875

13 files changed

+752
-132
lines changed
 

‎artiq/coredevice/comm_generic.py

+49-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,12 @@ class _H2DMsgType(Enum):
2020
RUN_KERNEL = 5
2121

2222
RPC_REPLY = 6
23-
23+
24+
FLASH_READ_REQUEST = 7
25+
FLASH_WRITE_REQUEST = 8
26+
FLASH_ERASE_REQUEST = 9
27+
FLASH_REMOVE_REQUEST = 10
28+
2429

2530
class _D2HMsgType(Enum):
2631
LOG_REPLY = 1
@@ -37,6 +42,11 @@ class _D2HMsgType(Enum):
3742

3843
RPC_REQUEST = 10
3944

45+
FLASH_READ_REPLY = 11
46+
FLASH_WRITE_REPLY = 12
47+
FLASH_OK_REPLY = 13
48+
FLASH_ERROR_REPLY = 14
49+
4050

4151
class UnsupportedDevice(Exception):
4252
pass
@@ -122,6 +132,44 @@ def run(self, kname, reset_now):
122132
self.write(bytes(kname, "ascii"))
123133
logger.debug("running kernel: %s", kname)
124134

135+
def flash_storage_read(self, key):
136+
self._write_header(9+len(key), _H2DMsgType.FLASH_READ_REQUEST)
137+
self.write(key)
138+
length, ty = self._read_header()
139+
if ty != _D2HMsgType.FLASH_READ_REPLY:
140+
raise IOError("Incorrect reply from device: {}".format(ty))
141+
value = self.read(length - 9)
142+
return value
143+
144+
def flash_storage_write(self, key, value):
145+
self._write_header(9+len(key)+1+len(value),
146+
_H2DMsgType.FLASH_WRITE_REQUEST)
147+
self.write(key)
148+
self.write(b"\x00")
149+
self.write(value)
150+
_, ty = self._read_header()
151+
if ty != _D2HMsgType.FLASH_WRITE_REPLY:
152+
if ty == _D2HMsgType.FLASH_ERROR_REPLY:
153+
raise IOError("Invalid key: not a null-terminated string")
154+
else:
155+
raise IOError("Incorrect reply from device: {}".format(ty))
156+
ret = self.read(1)
157+
if ret != b"\x01":
158+
raise IOError("Flash storage is full")
159+
160+
def flash_storage_erase(self):
161+
self._write_header(9, _H2DMsgType.FLASH_ERASE_REQUEST)
162+
_, ty = self._read_header()
163+
if ty != _D2HMsgType.FLASH_OK_REPLY:
164+
raise IOError("Incorrect reply from device: {}".format(ty))
165+
166+
def flash_storage_remove(self, key):
167+
self._write_header(9+len(key), _H2DMsgType.FLASH_REMOVE_REQUEST)
168+
self.write(key)
169+
_, ty = self._read_header()
170+
if ty != _D2HMsgType.FLASH_OK_REPLY:
171+
raise IOError("Incorrect reply from device: {}".format(ty))
172+
125173
def _receive_rpc_value(self, type_tag):
126174
if type_tag == "n":
127175
return None

‎artiq/frontend/artiq_coreconfig.py

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
#!/usr/bin/env python3
2+
3+
import argparse
4+
5+
from artiq.master.worker_db import create_device
6+
from artiq.protocols.file_db import FlatFileDB
7+
8+
9+
def to_bytes(string):
10+
return bytes(string, encoding="ascii")
11+
12+
13+
def get_argparser():
14+
parser = argparse.ArgumentParser(description="ARTIQ core device config "
15+
"remote access")
16+
parser.add_argument("-r", "--read", type=to_bytes,
17+
help="read key from core device config")
18+
parser.add_argument("-w", "--write", nargs=2, action="append", default=[],
19+
metavar=("KEY", "STRING"), type=to_bytes,
20+
help="write key-value records to core device config")
21+
parser.add_argument("-f", "--write-file", nargs=2, action="append",
22+
type=to_bytes, default=[], metavar=("KEY", "FILENAME"),
23+
help="write the content of a file into core device "
24+
"config")
25+
parser.add_argument("-e", "--erase", action="store_true",
26+
help="erase core device config")
27+
parser.add_argument("-d", "--delete", action="append", default=[],
28+
type=to_bytes,
29+
help="delete key from core device config")
30+
parser.add_argument("--ddb", default="ddb.pyon",
31+
help="device database file")
32+
return parser
33+
34+
35+
def main():
36+
args = get_argparser().parse_args()
37+
ddb = FlatFileDB(args.ddb)
38+
comm = create_device(ddb.request("comm"), None)
39+
40+
if args.read:
41+
value = comm.flash_storage_read(args.read)
42+
if not value:
43+
print("Key {} does not exist".format(args.read))
44+
else:
45+
print(value)
46+
elif args.erase:
47+
comm.flash_storage_erase()
48+
elif args.delete:
49+
for key in args.delete:
50+
comm.flash_storage_remove(key)
51+
else:
52+
if args.write:
53+
for key, value in args.write:
54+
comm.flash_storage_write(key, value)
55+
if args.write_file:
56+
for key, filename in args.write_file:
57+
with open(filename, "rb") as fi:
58+
comm.flash_storage_write(key, fi.read())
59+
60+
if __name__ == "__main__":
61+
main()

‎artiq/frontend/artiq_flash.sh

+20-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ ARTIQ_PREFIX=$(python3 -c "import artiq; print(artiq.__path__[0])")
77
# Default is kc705
88
BOARD=kc705
99

10-
while getopts "bBrht:d:" opt
10+
while getopts "bBrht:d:f:" opt
1111
do
1212
case $opt in
1313
b)
@@ -19,6 +19,15 @@ do
1919
r)
2020
FLASH_RUNTIME=1
2121
;;
22+
f)
23+
if [ -f $OPTARG ]
24+
then
25+
FILENAME=$OPTARG
26+
else
27+
echo "You specified a non-existing file to flash: $OPTARG"
28+
exit 1
29+
fi
30+
;;
2231
t)
2332
if [ "$OPTARG" == "kc705" ]
2433
then
@@ -52,6 +61,7 @@ do
5261
echo "-r Flash ARTIQ runtime"
5362
echo "-h Show this help message"
5463
echo "-t Target (kc705, pipistrello, default is: kc705)"
64+
echo "-f Flash storage image generated with artiq_mkfs"
5565
echo "-d Directory containing the binaries to be flashed"
5666
exit 1
5767
;;
@@ -95,6 +105,7 @@ then
95105
PROXY=bscan_spi_kc705.bit
96106
BIOS_ADDR=0xaf0000
97107
RUNTIME_ADDR=0xb00000
108+
FS_ADDR=0xb40000
98109
if [ -z "$BIN_PREFIX" ]; then BIN_PREFIX=$ARTIQ_PREFIX/binaries/kc705; fi
99110
search_for_proxy $PROXY
100111
elif [ "$BOARD" == "pipistrello" ]
@@ -105,12 +116,13 @@ then
105116
PROXY=bscan_spi_lx45_csg324.bit
106117
BIOS_ADDR=0x170000
107118
RUNTIME_ADDR=0x180000
119+
FS_ADDR=0x1c0000
108120
if [ -z "$BIN_PREFIX" ]; then BIN_PREFIX=$ARTIQ_PREFIX/binaries/pipistrello; fi
109121
search_for_proxy $PROXY
110122
fi
111123

112124
# Check if neither of -b|-B|-r have been used
113-
if [ -z "$FLASH_RUNTIME" -a -z "$FLASH_BIOS" -a -z "$FLASH_BITSTREAM" ]
125+
if [ -z "$FLASH_RUNTIME" -a -z "$FLASH_BIOS" -a -z "$FLASH_BITSTREAM" -a -z "$FILENAME" ]
114126
then
115127
FLASH_RUNTIME=1
116128
FLASH_BIOS=1
@@ -132,6 +144,12 @@ then
132144
fi
133145
set -e
134146

147+
if [ ! -z "$FILENAME" ]
148+
then
149+
echo "Flashing file $FILENAME at address $FS_ADDR"
150+
xc3sprog -v -c $CABLE -I$PROXY_PATH/$PROXY $FILENAME:w:$FS_ADDR:BIN
151+
fi
152+
135153
if [ "${FLASH_BITSTREAM}" == "1" ]
136154
then
137155
echo "Flashing FPGA bitstream..."

‎artiq/frontend/artiq_mkfs.py

+4-7
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,13 @@ def get_argparser():
2020

2121

2222
def write_record(f, key, value):
23+
key_size = len(key) + 1
24+
value_size = len(value)
25+
record_size = key_size + value_size + 4
26+
f.write(struct.pack(">l", record_size))
2327
f.write(key.encode())
2428
f.write(b"\x00")
25-
key_size = len(key) + 1
26-
if key_size % 4:
27-
f.write(bytes(4 - (key_size % 4)))
28-
f.write(struct.pack(">l", len(value)))
2929
f.write(value)
30-
value_size = len(value)
31-
if value_size % 4:
32-
f.write(bytes(4 - (value_size % 4)))
3330

3431

3532
def write_end_marker(f):

‎artiq/master/worker_db.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ def write_hdf5(self, f):
6565
result_dict_to_hdf5(f, self.data.read)
6666

6767

68-
def _create_device(desc, dbh):
68+
def create_device(desc, dbh):
6969
ty = desc["type"]
7070
if ty == "local":
7171
module = importlib.import_module(desc["module"])
@@ -105,7 +105,7 @@ def get_device(self, name):
105105
while isinstance(desc, str):
106106
# alias
107107
desc = self.ddb.request(desc)
108-
dev = _create_device(desc, self)
108+
dev = create_device(desc, self)
109109
self.active_devices[name] = dev
110110
return dev
111111

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
.. _core-device-flash-storage:
2+
3+
Core device flash storage
4+
=========================
5+
6+
The core device contains some flash space that can be used to store
7+
some configuration data.
8+
9+
This storage area is used to store the core device MAC address, IP address and even the idle kernel.
10+
11+
The flash storage area is one sector (64 kB) large and is organized as a list
12+
of key-value records.
13+
14+
This flash storage space can be accessed by using the artiq_coreconfig.py :ref:`core-device-configuration-tool`.

‎doc/manual/index.rst

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ Contents:
1515
core_drivers_reference
1616
protocols_reference
1717
ndsp_reference
18+
core_device_flash_storage
1819
utilities
1920
fpga_board_ports
2021
default_network_ports

‎doc/manual/installing.rst

+44
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,50 @@ These steps are required to generate bitstream (``.bit``) files, build the MiSoC
124124

125125
The communication parameters are 115200 8-N-1.
126126

127+
* Set the MAC and IP address in the :ref:`core device configuration flash storage <core-device-flash-storage>`:
128+
129+
* You can either set it by generating a flash storage image and then flash it: ::
130+
131+
$ ~/artiq-dev/artiq/frontend/artiq_mkfs.py flash_storage.img -s mac xx:xx:xx:xx:xx:xx -s ip xx.xx.xx.xx
132+
$ ~/artiq-dev/artiq/frontend/artiq_flash.sh -f flash_storage.img
133+
134+
* Or you can set it via the runtime test mode command line
135+
136+
* Boot the board.
137+
138+
* Quickly run flterm (in ``path/to/misoc/tools``) to access the serial console.
139+
140+
* If you weren't quick enough to see anything in the serial console, press the reset button.
141+
142+
* Wait for "Press 't' to enter test mode..." to appear and hit the ``t`` key.
143+
144+
* Enter the following commands (which will erase the flash storage content).
145+
146+
::
147+
148+
test> fserase
149+
test> fswrite ip xx.xx.xx.xx
150+
test> fswrite mac xx:xx:xx:xx:xx:xx
151+
152+
* Then reboot.
153+
154+
You should see something like this in the serial console: ::
155+
156+
~/dev/misoc$ ./tools/flterm --port /dev/ttyUSB1
157+
[FLTERM] Starting...
158+
159+
MiSoC BIOS http://m-labs.hk
160+
(c) Copyright 2007-2014 Sebastien Bourdeauducq
161+
[...]
162+
Press 't' to enter test mode...
163+
Entering test mode.
164+
test> fserase
165+
test> fswrite ip 192.168.10.2
166+
test> fswrite mac 11:22:33:44:55:66
167+
168+
.. note:: The reset button of the KC705 board is the "CPU_RST" labeled button.
169+
.. warning:: Both those instructions will result in the flash storage being wiped out. However you can use the test mode to change the IP/MAC without erasing everything if you skip the "fserase" command.
170+
127171
Installing the host-side software
128172
---------------------------------
129173

‎doc/manual/utilities.rst

+55
Original file line numberDiff line numberDiff line change
@@ -92,3 +92,58 @@ This tool compiles key/value pairs into a binary image suitable for flashing int
9292
.. argparse::
9393
:ref: artiq.frontend.artiq_mkfs.get_argparser
9494
:prog: artiq_mkfs
95+
96+
.. _core-device-configuration-tool:
97+
98+
Core device configuration tool
99+
------------------------------
100+
101+
The artiq_coreconfig tool allows to read, write and remove key-value records from the :ref:`core-device-flash-storage`.
102+
103+
It also allows to erase the entire flash storage area.
104+
105+
To use this tool, you need to specify a ``ddb.pyon`` DDB file which contains a ``comm`` device (an example is provided in ``artiq/examples/master/ddb.pyon``).
106+
This tells the tool how to connect to the core device (via serial or via TCP) and with which parameters (baudrate, serial device, IP address, TCP port).
107+
When not specified, the artiq_coreconfig tool will assume that there is a file named ``ddb.pyon`` in the current directory.
108+
109+
110+
To read the record whose key is ``mac``::
111+
112+
$ artiq_coreconfig -r mac
113+
114+
To write the value ``test_value`` in the key ``my_key``::
115+
116+
$ artiq_coreconfig -w my_key test_value
117+
$ artiq_coreconfig -r my_key
118+
b'test_value'
119+
120+
You can also write entire files in a record using the ``-f`` parameter::
121+
122+
$ echo "this_is_a_test" > my_filename
123+
$ artiq_coreconfig -f my_key my_filename
124+
$ artiq_coreconfig -r my_key
125+
b'this_is_a_test\n'
126+
127+
You can write several records at once::
128+
129+
$ artiq_coreconfig -w key1 value1 -f key2 filename -w key3 value3
130+
131+
To remove the previously written key ``my_key``::
132+
133+
$ artiq_coreconfig -d my_key
134+
135+
To erase the entire flash storage area::
136+
137+
$ artiq_coreconfig -e
138+
139+
You don't need to remove a record in order to change its value, just overwrite
140+
it::
141+
142+
$ artiq_coreconfig -w my_key some_value
143+
$ artiq_coreconfig -w my_key some_other_value
144+
$ artiq_coreconfig -r my_key
145+
b'some_other_value'
146+
147+
.. argparse::
148+
:ref: artiq.frontend.artiq_coreconfig.get_argparser
149+
:prog: artiq_coreconfig

0 commit comments

Comments
 (0)
Please sign in to comment.