Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
C
Compact Universal Timing Endpoint based on White Rabbit
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
Wiki
Wiki
image/svg+xml
Discourse
Discourse
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
Projects
Compact Universal Timing Endpoint based on White Rabbit
Commits
2dc1f007
Commit
2dc1f007
authored
Jan 09, 2015
by
Qiang Du
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Fix flash writting scripts, enable sector erasing.
Flash programming partially works
parent
077d77d1
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
81 additions
and
245 deletions
+81
-245
eb.py
tools/lib-multiboot/eb/eb.py
+13
-15
etherbone.py
tools/lib-multiboot/eb/etherbone.py
+7
-199
flash_m25p.py
tools/lib-multiboot/flash_m25p.py
+23
-4
mbtest.py
tools/lib-multiboot/mbtest.py
+24
-11
xil_multiboot.py
tools/lib-multiboot/xil_multiboot.py
+14
-16
No files found.
tools/lib-multiboot/eb/eb.py
View file @
2dc1f007
...
...
@@ -16,6 +16,7 @@
import
etherbone
as
eb
import
sys
import
logging
class
EB
:
""" access a Etherbone device. """
...
...
@@ -40,27 +41,24 @@ class EB:
self
.
socket
.
close
()
def
write
(
self
,
addr
,
val
):
logging
.
debug
(
'write: 0x
%08
x'
%
val
)
self
.
device
.
write
(
addr
,
val
)
def
writemregs
(
self
,
addr
,
dlist
):
curr_addr
=
addr
self
.
cycle
=
eb
.
Cycle
(
self
.
device
,
0
,
0
)
self
.
cycle
.
__enter__
()
for
i
in
dlist
:
curr_addr
+=
i
self
.
cycle
.
write
(
curr_addr
,
i
)
self
.
cycle
.
close
()
with
eb
.
Cycle
(
self
.
device
,
0
,
0
)
as
cycle
:
for
v
in
dlist
:
logging
.
debug
(
'mwrite: 0x
%08
x'
%
v
)
cycle
.
write
(
addr
,
v
)
def
read
(
self
,
addr
):
return
self
.
device
.
read
(
addr
)
val
=
self
.
device
.
read
(
addr
)
logging
.
debug
(
'read: 0x
%08
x'
%
val
)
return
val
def
readmregs
(
self
,
addr
,
nrregs
):
curr_addr
=
addr
dlist
=
[]
self
.
cycle
=
eb
.
Cycle
(
self
.
device
,
0
,
0
)
self
.
cycle
.
__enter__
()
for
i
in
xrange
(
nrregs
):
curr_addr
+=
i
dlist
[
i
]
=
self
.
cycle
.
read
(
curr_addr
)
self
.
cycle
.
close
()
with
eb
.
Cycle
(
self
.
device
,
0
,
0
)
as
cycle
:
for
i
in
nrregs
:
dlist
.
append
(
cycle
.
read
(
addr
,
v
))
logging
.
debug
(
'mread: 0x
%08
x'
%
dlist
[
i
])
return
dlist
tools/lib-multiboot/eb/etherbone.py
View file @
2dc1f007
...
...
@@ -37,19 +37,6 @@ eb_device_t = c_uint16
eb_cycle_t
=
c_uint16
# status codes
eb_status_t
=
c_int
(
EB_OK
,
EB_FAIL
,
EB_ABORT
,
EB_ADDRESS
,
EB_OVERFLOW
,
EB_ENDIAN
,
EB_BUSY
,
EB_TIMEOUT
,
EB_OOM
,
EB_ABI
,
EB_SEGFAULT
)
=
range
(
0
,
-
11
,
-
1
)
eb_err_code
=
{
0
:
'EB_OK'
,
-
1
:
'EB_FAIL'
,
...
...
@@ -113,7 +100,7 @@ class Socket():
def
__enter__
(
self
):
status
=
self
.
open
(
self
.
port
,
self
.
widths
,
self
.
socket
)
if
(
status
!=
0
):
print
'error opening device, code '
,
eb_err_code
[
status
]
raise
IOError
(
'error opening device, code '
,
eb_err_code
[
status
])
return
self
def
__exit__
(
self
,
type
,
value
,
traceback
):
...
...
@@ -155,20 +142,20 @@ class Device():
def
__enter__
(
self
):
status
=
self
.
open
(
self
.
socket
,
self
.
address
,
self
.
widths
)
if
(
status
!=
0
):
print
'error opening device, code '
,
eb_err_code
[
status
]
raise
IOError
(
'error opening device, code '
,
eb_err_code
[
status
])
return
self
def
__exit__
(
self
,
type
,
value
,
traceback
):
self
.
close
()
def
open
(
self
,
socket
,
ip_port
,
widths
):
def
open
(
self
,
socket
,
ip_port
,
widths
,
retry
=
3
):
"""open a remote Etherbone device
This resolves the address and performs Etherbone end-point discovery.
From the mask of proposed bus widths, one will be selected.
The default port is taken as 0xEBD0.
"""
return
lib
.
eb_device_open
(
socket
,
ip_port
,
widths
,
3
,
byref
(
self
.
device
))
return
lib
.
eb_device_open
(
socket
,
ip_port
,
widths
,
retry
,
byref
(
self
.
device
))
def
close
(
self
):
"""close a remote Etherbone device
...
...
@@ -185,7 +172,7 @@ class Device():
"""
return
lib
.
eb_device_width
(
self
.
device
)
def
read
(
self
,
address
):
def
read
(
self
,
address
,
user_data
=
None
,
callback
=
None
):
"""perform a single-read wishbone cycle
Semantically equivalent to cycle_open, cycle_read, cycle_close.
...
...
@@ -195,19 +182,15 @@ class Device():
The user parameter is passed through uninspected to the callback.
"""
data
=
eb_data_t
()
user_data
=
None
callback
=
None
lib
.
eb_device_read
(
self
.
device
,
address
,
self
.
data_format
,
byref
(
data
),
user_data
,
callback
)
return
data
.
value
def
write
(
self
,
address
,
data
):
def
write
(
self
,
address
,
data
,
user_data
=
None
,
callback
=
None
):
"""perform a single-write wishbone cycle
Semantically equivalent to cycle_open, cycle_write, cycle_close.
data is written to the given address on the remote device.
"""
user_data
=
None
callback
=
None
return
lib
.
eb_device_write
(
self
.
device
,
address
,
self
.
data_format
,
data
,
user_data
,
callback
)
class
Cycle
():
...
...
@@ -226,7 +209,7 @@ class Cycle():
def
__enter__
(
self
):
status
=
self
.
open
(
self
.
dev_handle
,
self
.
user_data
,
self
.
callback
)
if
(
status
!=
0
):
print
'error opening device, code '
,
eb_err_code
[
status
]
raise
IOError
(
'error opening device, code '
,
eb_err_code
[
status
])
return
self
def
__exit__
(
self
,
type
,
value
,
traceback
):
...
...
@@ -265,178 +248,3 @@ class Cycle():
If the device was read-only, the operation is discarded.
"""
return
lib
.
eb_cycle_write
(
self
.
cycle
,
address
,
self
.
data_format
,
data
)
#
# C99 API
#
def
eb_socket_open
(
port
,
widths
,
socket
):
"""
Open an Etherbone socket for communicating with remote devices.
The port parameter is optional; 0 lets the operating system choose.
After opening the socket, poll must be hooked into an event loop.
Return codes:
OK - successfully open the socket port
FAIL - operating system forbids access
BUSY - specified port is in use (only possible if port != 0)
"""
return
lib
.
eb_socket_open
(
EB_ABI_CODE
,
port
,
widths
,
socket
)
def
eb_socket_close
(
socket
):
"""
Close the Etherbone socket.
Any use of the socket after successful close will probably segfault!
Return codes:
OK - successfully closed the socket and freed memory
BUSY - there are open devices on this socket
"""
return
lib
.
eb_socket_close
(
socket
)
def
eb_socket_poll
(
socket
):
"""
Poll the Etherbone socket for activity.
This function must be called regularly to receive incoming packets.
Either call poll very often or hook a read listener on its descriptor.
Callback functions are only executed from within the poll function.
Return codes:
OK - poll complete; no further packets to process
FAIL - socket error (probably closed)
"""
return
lib
.
eb_socket_poll
(
socket
)
def
eb_socket_block
(
socket
,
timeout_us
):
"""
Block until the socket is ready to be polled.
This function is useful if your program has no event loop of its own.
It returns the time spent while waiting.
"""
return
lib
.
eb_socket_block
(
socket
,
timeout_us
)
def
eb_socket_descriptor
(
socket
):
"""
Access the underlying file descriptor of the Etherbone socket.
THIS MUST NEVER BE READ, WRITTEN, CLOSED, OR MODIFIED IN ANY WAY!
It may be used to watch for read readiness to call poll.
"""
return
lib
.
eb_socket_descriptor
(
socket
)
def
eb_socket_attach
(
socket
,
handler
):
"""
Add a device to the virtual bus.
This handler receives all reads and writes to the specified address.
NOTE: the address range [0x0, 0x7fff) is reserved for internal use.
Return codes:
OK - the handler has been installed
FAIL - out of memory
ADDRESS - the specified address range overlaps an existing device.
"""
return
lib
.
eb_socket_attach
(
socket
,
handler
)
def
eb_socket_detach
(
socket
,
address
):
"""
Detach the device from the virtual bus.
Return codes:
OK - the devices has be removed
FAIL - there is no device at the specified address.
"""
return
lib
.
eb_socket_detach
(
socket
,
address
)
def
eb_device_open
(
socket
,
ip_port
,
proposed_widths
,
result
):
"""
Open a remote Etherbone device.
This resolves the address and performs Etherbone end-point discovery.
From the mask of proposed bus widths, one will be selected.
The default port is taken as 0xEBD0.
Return codes:
OK - the remote etherbone device is ready
FAIL - the remote address did not identify itself as etherbone conformant
ADDRESS - the network address could not be parsed
ABORT - could not negotiate an acceptable data bus width
"""
return
lib
.
eb_device_open
(
socket
,
ip_port
,
proposed_widths
,
result
)
def
eb_device_width
(
device
):
"""
Recover the negotiated data width of the target device.
"""
return
lib
.
eb_device_width
(
device
)
def
eb_device_close
(
device
):
"""
Close a remote Etherbone device.
Return codes:
OK - associated memory has been freed
BUSY - there are outstanding wishbone cycles on this device
"""
return
lib
.
eb_device_close
(
device
)
def
eb_device_socket
(
device
):
"""Access the socket backing this device
"""
return
lib
.
eb_device_socket
(
device
)
def
eb_cycle_close
(
cycle
):
"""
End a wishbone cycle.
This places the complete cycle at end of the device''s send queue.
"""
return
lib
.
eb_cycle_close
(
cycle
)
def
eb_cycle_device
(
cycle
):
"""Access the device targetted by this cycle
"""
return
eb_cycle_device
(
cycle
)
def
eb_cycle_read
(
cycle
,
address
):
"""
Prepare a wishbone read phase.
The given address is read from the remote device.
"""
return
lib
.
eb_cycle_read
(
cycle
,
address
)
def
eb_cycle_write
(
cycle
,
data
):
"""
Perform a wishbone write phase.
data is written to the current cursor on the remote device.
If the device was read-only, the operation is discarded.
"""
return
lib
.
eb_cycle_write
(
cycle
,
data
)
def
eb_device_read
(
device
,
address
,
userdata
,
cb
):
"""
Perform a single-read wishbone cycle.
Semantically equivalent to cycle_open, cycle_read, cycle_close.
The given address is read on the remote device.
The callback cb(user, status, data) is invoked with the result.
The user parameter is passed through uninspected to the callback.
Status codes:
OK - the operation completed successfully
FAIL - the operation failed due to an wishbone ERR_O signal
ABORT - an earlier operation failed and this operation was thus aborted
"""
return
lib
.
eb_device_read
(
device
,
address
,
userdata
,
cb
)
def
eb_device_write
(
device
,
address
,
data
):
"""
Perform a single-write wishbone cycle.
Semantically equivalent to cycle_open, cycle_write, cycle_close.
data is written to the given address on the remote device.
"""
return
lib
.
eb_device_write
(
device
,
address
,
data
)
tools/lib-multiboot/flash_m25p.py
View file @
2dc1f007
...
...
@@ -20,6 +20,7 @@
#
import
sys
import
logging
import
struct
sys
.
path
.
append
(
"eb"
)
from
eb
import
*
...
...
@@ -56,7 +57,6 @@ class FlashM25P:
# control byte, to be shifted left by 24
ctrl
=
((
cs
<<
3
)
|
0x4
)
|
(
nbytes
-
1
)
if
(
self
.
comm
==
ELMA_I2C_MULTIBOOT
):
# Use appropriate command by type
#
# write - we send up to three data bytes in one FAR register write
...
...
@@ -79,6 +79,7 @@ class FlashM25P:
wval
.
append
((
ctrl
<<
24
)
|
dat
[
i
])
self
.
ebone
.
writemregs
(
self
.
mb_base
+
0x10
,
wval
)
# Read the data and prepare the return value
while
(
retval
&
(
1
<<
28
)
==
0
):
retval
=
self
.
ebone
.
read
(
self
.
mb_base
+
0x10
)
...
...
@@ -88,14 +89,23 @@ class FlashM25P:
# and sends the commands to the flash chip. You can follow the logic of this
# function by looking at the sequence of the write command in [1]
def
write
(
self
,
addr
,
dat
):
logging
.
debug
(
'Writting to address 0x
%
x'
%
addr
)
# write enable cmd
self
.
spi_transfer
(
1
,
1
,
0x06
)
self
.
spi_transfer
(
1
,
0
,
0
)
# check status (WIP, WEL) bits
status
=
0
retry
=
3
while
(
status
!=
0x2
):
logging
.
debug
(
'Flash not ready, status: 0x
%
x'
%
status
)
if
(
retry
<=
0
):
raise
IOError
(
'Error writing, status not vaild: 0x
%
x'
%
status
)
logging
.
debug
(
'retry =
%
d'
%
retry
)
retry
-=
1
status
=
self
.
rsr
()
# write page cmd
self
.
spi_transfer
(
1
,
1
,
0x02
)
# send address in reverse order
self
.
spi_transfer
(
3
,
1
,
self
.
rev_addr
(
addr
))
...
...
@@ -139,6 +149,7 @@ class FlashM25P:
# It returns the values of the three consecutive flash registers packed into
# one 24-bit data value in little-endian order
def
read
(
self
,
addr
,
nrbytes
):
logging
.
debug
(
'Reading from 0x
%
x...'
%
addr
)
ret
=
[]
self
.
spi_transfer
(
1
,
1
,
0x0b
)
...
...
@@ -146,7 +157,7 @@ class FlashM25P:
self
.
spi_transfer
(
3
,
1
,
self
.
rev_addr
(
addr
))
self
.
spi_transfer
(
1
,
1
,
0
)
# Read bytes in groups of
thre
e
# Read bytes in groups of
on
e
for
i
in
range
(
nrbytes
):
ret
.
append
(
self
.
spi_transfer
(
1
,
1
,
0
))
self
.
spi_transfer
(
1
,
0
,
0
)
...
...
@@ -155,12 +166,18 @@ class FlashM25P:
# Send a sector erase command
def
serase
(
self
,
addr
):
logging
.
debug
(
'Sector Erasing from 0x
%
x'
%
addr
)
self
.
spi_transfer
(
1
,
1
,
0x06
)
self
.
spi_transfer
(
1
,
0
,
0
)
self
.
spi_transfer
(
1
,
1
,
0xD8
)
# send address in reverse order
self
.
spi_transfer
(
3
,
1
,
self
.
rev_addr
(
addr
))
self
.
spi_transfer
(
1
,
0
,
0
)
# wait until finish
status
=
1
while
(
status
!=
0x0
):
logging
.
debug
(
'Sector erasing...'
)
status
=
self
.
rsr
()
# Send a block erase command
def
berase
(
self
):
...
...
@@ -174,6 +191,7 @@ class FlashM25P:
self
.
spi_transfer
(
1
,
1
,
0x05
)
ret
=
self
.
spi_transfer
(
1
,
1
,
0
)
self
.
spi_transfer
(
1
,
0
,
0
)
logging
.
debug
(
'Status Register: 0x
%
x'
%
ret
)
return
ret
def
read_id
(
self
):
...
...
@@ -183,6 +201,7 @@ class FlashM25P:
ret
.
append
(
self
.
spi_transfer
(
1
,
1
,
0
))
self
.
spi_transfer
(
1
,
0
,
0
)
ret_pack
=
struct
.
pack
(
'B'
*
20
,
*
ret
)
logging
.
debug
(
'Flash ID: 0x'
+
ret_pack
.
encode
(
'hex'
))
return
ret_pack
def
rev_addr
(
self
,
addr
):
...
...
tools/lib-multiboot/mbtest.py
View file @
2dc1f007
...
...
@@ -2,29 +2,42 @@ import os
import
sys
import
time
import
struct
import
logging
sys
.
path
.
append
(
"eb"
)
from
eb
import
*
from
xil_multiboot
import
*
if
__name__
==
"__main__"
:
def
main
():
log_level
=
logging
.
DEBUG
log_level
=
logging
.
INFO
logging
.
basicConfig
(
level
=
log_level
)
ip
=
'rflab2.lbl.gov'
target
=
EB
(
ip
)
target
.
open
()
baseaddr
=
0x20800
mb
=
XilMultiboot
(
ETHERBONE
,
target
,
baseaddr
,
"foo_bit"
)
mb
.
write
(
0
)
flash_address
=
0x10
flash_length
=
0x1f
file_name
=
'foo_bit'
mb
=
XilMultiboot
(
ETHERBONE
,
target
,
baseaddr
,
file_name
)
status
=
mb
.
flash
.
rsr
()
print
'Status:'
+
hex
(
status
)
# read id
id
=
mb
.
flash
.
read_id
()
logging
.
info
(
'Flash ID: 0x'
+
id
.
encode
(
'hex'
))
#logging.info('Programming file %s'% file_name)
#mb.write(flash_address)
#mb.read(0,0xff)
# read id
id
=
mb
.
flash
.
read_id
()
print
'ID: 0x'
+
id
.
encode
(
'hex'
)
# mb.flash.serase(flash_address)
mb
.
flash
.
write
(
flash_address
,
range
(
0x15
,
0x15
+
flash_length
))
status
=
mb
.
flash
.
rsr
()
logging
.
info
(
'Status: 0x
%
x'
,
status
)
#mb.flash.serase(0x0)
# mb.flash.write(0x0,range(0,255))
dat
=
mb
.
flash
.
read
(
0x0
,
0xff
)
dat
=
mb
.
flash
.
read
(
flash_address
,
flash_length
)
dat_pack
=
struct
.
pack
(
'B'
*
len
(
dat
),
*
dat
)
print
'Flash: 0x'
+
dat_pack
.
encode
(
'hex'
)
if
__name__
==
"__main__"
:
main
()
tools/lib-multiboot/xil_multiboot.py
View file @
2dc1f007
...
...
@@ -19,6 +19,7 @@
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
#
import
logging
import
sys
sys
.
path
.
append
(
"eb"
)
from
eb
import
*
...
...
@@ -64,8 +65,7 @@ class XilMultiboot:
progress
=
(
float
(
actual
)
/
float
(
total
))
*
100
if
(
progress
>
100.00
):
progress
=
100.00
sys
.
stdout
.
write
(
"
\r
%3.2
f
%%
(0x
%06
x)"
%
(
progress
,
ca
))
sys
.
stdout
.
flush
()
logging
.
info
(
"
\r
%3.2
f
%%
(0x
%06
x)"
%
(
progress
,
ca
))
#
# Read from flash
...
...
@@ -76,14 +76,13 @@ class XilMultiboot:
f
=
open
(
fname
,
'wb'
)
# Read the data and dump to file
print
(
"Reading flash contents from board in slot
%
d"
%
self
.
slot
)
logging
.
info
(
"Reading flash contents from board in slot
%
d"
%
self
.
slot
)
dat
=
[]
for
i
in
range
(
sa
,
ea
,
256
):
dat
+=
self
.
flash
.
read
(
i
,
256
)
self
.
_progress
(
sa
,
ea
,
i
)
i
+=
256
self
.
_progress
(
sa
,
ea
,
i
)
print
(
""
)
dat
=
''
.
join
(
map
(
chr
,
dat
))
f
.
write
(
dat
)
f
.
close
()
...
...
@@ -93,7 +92,7 @@ class XilMultiboot:
#
def
write
(
self
,
addr
):
print
(
"Writing bitstream to board in slot
%
d"
%
self
.
slot
)
logging
.
info
(
"Writing bitstream to board in slot
%
d"
%
self
.
slot
)
# Ask for and open bitstream file
f
=
open
(
self
.
bitstream
,
'rb'
)
...
...
@@ -108,7 +107,7 @@ class XilMultiboot:
# Erase on sector boundary
if
not
(
addr
%
0x10000
):
print
'erase sector boundary'
logging
.
info
(
'erase sector boundary'
)
self
.
flash
.
serase
(
addr
)
while
(
self
.
flash
.
rsr
()
&
0x01
):
pass
...
...
@@ -122,18 +121,17 @@ class XilMultiboot:
addr
+=
256
self
.
_progress
(
sta
,
end
,
addr
)
print
(
""
)
# Close file handle
f
.
close
()
print
(
"DONE!"
)
logging
.
info
(
"DONE!"
)
#
# Start IPROG sequence
#
def
iprog
(
self
,
addr
):
if
(
self
.
comm
==
ELMA_I2C_MULTIBOOT
):
print
(
"Issuing IPROG command to board in slot
%
d..."
%
self
.
slot
)
logging
.
info
(
"Issuing IPROG command to board in slot
%
d..."
%
self
.
slot
)
self
.
elma
.
write
(
self
.
slot
,
self
.
mb_base
+
MB_GBBAR_OFS
,
0x44
|
(
0x0b
<<
24
))
self
.
elma
.
write
(
self
.
slot
,
self
.
mb_base
+
MB_MBBAR_OFS
,
addr
|
(
0x0b
<<
24
))
self
.
elma
.
write
(
self
.
slot
,
self
.
mb_base
+
MB_CR_OFS
,
0x10000
)
...
...
@@ -150,13 +148,13 @@ class XilMultiboot:
while
(
1
):
try
:
if
(
time
.
time
()
>=
t1
):
print
(
"Timeout, IPROG unsuccessful!"
)
logging
.
error
(
"Timeout, IPROG unsuccessful!"
)
break
if
((
self
.
elma
.
read
(
self
.
slot
,
0x4
)
&
0xf0
)
==
0x00
):
print
(
"IPROG unsuccessful, fallback to Golden bitstream occured!"
)
logging
.
info
(
"IPROG unsuccessful, fallback to Golden bitstream occured!"
)
break
else
:
print
(
"IPROG successful!"
)
logging
.
info
(
"IPROG successful!"
)
break
except
NAckError
:
continue
...
...
@@ -165,7 +163,7 @@ class XilMultiboot:
# Sequence to read FPGA configuration register
#
def
rdcfgreg
(
self
):
print
(
"Press 'q' to end config reg readout"
)
logging
.
info
(
"Press 'q' to end config reg readout"
)
while
1
:
try
:
reg
=
raw_input
(
'Address (hex): '
)
...
...
@@ -176,13 +174,13 @@ class XilMultiboot:
self
.
elma
.
write
(
self
.
slot
,
self
.
mb_base
+
MB_CR_OFS
,
(
1
<<
6
)
|
reg
)
val
=
self
.
elma
.
read
(
self
.
slot
,
self
.
mb_base
+
MB_SR_OFS
)
if
(
val
&
(
1
<<
16
)):
print
(
"REG(0x
%02
X) = 0x
%04
X"
%
(
reg
,
val
&
0xffff
))
logging
.
info
(
"REG(0x
%02
X) = 0x
%04
X"
%
(
reg
,
val
&
0xffff
))
else
:
print
(
"CFGREGIMG invalid!"
)
logging
.
error
(
"CFGREGIMG invalid!"
)
except
ValueError
:
if
(
reg
==
'q'
):
break
print
(
"Please input a hex value in the range [0x00, 0x22] or 'q' to quit"
)
logging
.
error
(
"Please input a hex value in the range [0x00, 0x22] or 'q' to quit"
)
#
# Set bitstream file path
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment