333 Commits

Author SHA1 Message Date
8d40210d87 flake: update boot.bif to use elf_use_ph 2026-02-14 18:18:46 +08:00
15eaa4eb65 flake: update dependencies 2026-02-14 18:17:03 +08:00
3c70203709 clean up example DDBs 2026-01-23 19:04:58 +08:00
9614c48e9d flake: update dependencies 2026-01-23 18:31:03 +08:00
1c4534637d rtio_acp: fix batch not remapping back for 0 events 2026-01-23 18:26:28 +08:00
5bd6fe0ad5 cargo fmt 2026-01-23 18:26:28 +08:00
a8cf7644a2 flake.lock: update 2026-01-23 18:26:28 +08:00
febc623c4b acp: reset batch state properly 2026-01-23 18:26:28 +08:00
ebdfff202a linker: make pages overlap in VMA 2026-01-23 18:26:28 +08:00
c4334a1d8c ksupport: use page linker symbols 2026-01-23 18:26:28 +08:00
35be9d5501 linker script: use proper page size 2026-01-23 18:26:28 +08:00
1309fe1c97 libksupport: map rtio output functions to aligned symbols 2026-01-23 18:26:28 +08:00
29bb0aba28 comms: remove self-imposed recv buffer size limit
On recv bytes through TCP conection, a heap buffer of dynamic size is allocated as the memory backing.
2026-01-23 09:48:59 +08:00
d877013a2a cxp_phys: add gtx equalizer config 2026-01-13 11:12:37 +08:00
30fc3ef2e8 flake: fix acpki tests 2026-01-09 13:14:45 +08:00
2fb3c7274d fix minor build errors after adding batching 2026-01-09 10:23:57 +08:00
8d01fe7a20 flake: add rtio batch driver to ddb for acpki hitl tests 2026-01-08 19:33:01 +08:00
b8c4184f8e cargo fmt 2026-01-08 19:33:01 +08:00
e2ce90f051 acpki: get rid of batch_len csr 2026-01-08 19:33:01 +08:00
5c8ea9b885 rtio_acp: get rid of batch_len csr, pass whole struct 2026-01-08 19:33:01 +08:00
963d4194b1 acp: use last target pointer for error display 2026-01-08 19:33:01 +08:00
be38a5d2ee acpki gateware fixes 2026-01-08 19:33:01 +08:00
ad340334fb gateware: add acpki_batch_size config variable 2026-01-08 19:33:01 +08:00
9a5e68af41 acpki: fix maximum burst length 2026-01-08 19:33:01 +08:00
f9255d0611 gateware/kasli_soc: obtain acpki flag from json description
this introduces a breaking change where the acpki flag cannot be passed through the constructor of the SoCCore classes anymore.
2026-01-08 19:33:01 +08:00
7350e6dff5 gateware/kasli_soc: removed unused imports
Signed-off-by: Leon Riesebos <tiny.water9944@fastmail.com>
2026-01-08 19:33:01 +08:00
5270fce5f5 rtio_acp batching: move to a static buffer 2026-01-08 19:33:01 +08:00
3a410e5414 acpki: store the target of an rtio error 2026-01-08 19:33:01 +08:00
01609cce59 acpki: support batched RTIO in KernelInitiator 2026-01-08 19:33:01 +08:00
ce48d430af rtio_acp: add batching 2026-01-08 19:33:01 +08:00
b83772baf5 flake: update dependencies 2026-01-08 19:27:17 +08:00
099c344cc4 flake: update dependencies 2025-12-23 19:42:26 +08:00
c65b130275 jsons: base -> drtio_role
"base" is deprecated.
2025-12-01 13:04:44 +08:00
efd45316e7 cargo fmt 2025-11-28 22:32:13 +08:00
1f8c9c3ee3 flake: add zc706 acpki hitl tests 2025-11-28 22:17:14 +08:00
4a1dc628d9 acpki: fix wait delay, rtio output waits only in gateware 2025-11-28 22:14:46 +08:00
72407a19a3 rtio_acp: decrease latency for rtio events
move the status clear to after the status is read, rather than beginning
this saves the time for slow volatile write
fixes test_exceptions RTIO underflow test
2025-11-28 22:14:45 +08:00
d9871ed0a7 libkernel: acp: refactor, shortening the functions 2025-11-28 22:14:45 +08:00
90db06a9e1 kasli soc: add phaser_drtio support
kasli soc: refactor and move drtio over eem peripheral into a list
kasli soc: raise error when using drito over eem in standalone
2025-11-24 12:10:51 +08:00
446384d787 flake: update dependencies 2025-11-22 10:39:40 +08:00
dly04
f3d4793fcb deal with setting uart filter level to trace, to prevent drtioaux timeout 2025-11-19 11:15:43 +08:00
dly04
00c4d48211 use coremgmt config to set runtime and stored log level 2025-11-19 10:58:20 +08:00
fd1b2453d7 flake: format 2025-11-18 18:19:45 +08:00
6ff895c0bf flake: update dependencies 2025-11-18 18:06:23 +08:00
dly04
b55f629486 fix format 2025-11-18 16:30:04 +08:00
dly
61dbb6a0f1 fix handling of the various log levels
Fix the global log level at TRACE, modifying only buffer log level when calling `artiq_coremgmt log set_level`.
By replacing `set_max_level` being called after `artiq_coremgmt log set_level` by `set_buffer_log_level`.
So that `artiq_coremgmt log set_level` won't affect UART log level.
Tested on Kasli-Soc.

Co-authored-by: dly04 <yliujc@connect.ust.hk>
Reviewed-on: #429
Reviewed-by: mwojcik <mw@m-labs.hk>
Reviewed-by: srenblad <srenblad@m-labs.hk>
Co-authored-by: dly <dly@m-labs.hk>
Co-committed-by: dly <dly@m-labs.hk>
2025-11-18 12:24:36 +08:00
159987a64b remote_run: fix target host name 2025-11-14 10:50:27 +08:00
3be9250978 flake: use artiq-build (artiq with minimal dependencies) 2025-11-10 18:39:08 +08:00
b88bb90139 flake: update dependencies 2025-11-10 18:38:38 +08:00
3b0b52ef2c si549: clean up remaining GlobalTimer usage
Missing as it did not show up in testing / searching.
2025-11-10 14:10:11 +08:00
982828bde1 flake: update dependencies 2025-11-04 22:34:12 +08:00
db0231956e firmware: expose ldexp 2025-11-04 21:24:43 +08:00
d9bf878d03 flake: update dependencies 2025-10-09 17:12:06 +08:00
beb98b52fd flake: update artiq and dependencies for SoC v1.2
For including the system description JSON schema change in
https://github.com/m-labs/artiq/pull/2857, so that a hw_rev of v1.2 for
the Kasli-SoC could be specified for building.
2025-09-12 13:30:20 +08:00
d57f308765 Add minimal support for Kasli-SoC v1.2
- Update cfg directives to consider a hw_rev of 1.2.
- Turn on EEM power, without checking for faults for the time being.
2025-09-12 13:30:10 +08:00
d9f2f84480 update cargo lockfile 2025-08-22 14:57:48 +08:00
c317b3a0ac satman: async_errors is always 0 2025-08-22 14:57:26 +08:00
54ce700fde ksupport: move async error reporting to runtime 2025-08-22 14:57:26 +08:00
7f28167279 ksupport: move device map to core0 2025-08-22 12:00:47 +08:00
307ced4585 ksupport: move i2c to core0
In order for the firmware to interop with Kasli v2, all inter core comms
need to be through the message passing interface (sync_channel/mailbox).
2025-08-20 12:35:01 +08:00
3f497e08a4 runtime: cleanup imports 2025-08-19 16:24:53 +08:00
Harry Poon
9a816e1d5b coremgmt: fix formatting 2025-08-15 11:08:46 +08:00
7cceda9353 terminate old aqctl_corelog connections when receiving new ones
#424
Co-authored-by: harryp <thpoonaa@connect.ust.hk>
Co-committed-by: harryp <thpoonaa@connect.ust.hk>
2025-08-14 19:01:26 +08:00
a325d5ce78 flake: update dependencies 2025-08-11 23:18:28 +08:00
40f1c94ecf satman: flush uart before reboot 2025-08-11 15:10:18 +08:00
92c586d266 runtime: flush uart before rebooting 2025-08-11 15:10:18 +08:00
96928b7d0d logger: implement flush for BufferLogger 2025-08-11 15:10:18 +08:00
59266fd141 runtime: make routing table static OnceLock 2025-08-04 12:55:40 +08:00
78080eae2b flake: add new required fields for buildPythonPackage 2025-07-31 15:17:07 +08:00
f1e79310ec update cargo lock 2025-07-31 15:07:04 +08:00
3a65d6c2a5 libksupport: wrap RTIO_DEVICE_MAP in OnceLock 2025-07-31 15:07:04 +08:00
734fd11ad6 libboard_artiq: wrap LOGGER in OnceLock 2025-07-31 15:07:04 +08:00
5843138a8e flake: update dependencies 2025-07-31 15:06:03 +08:00
1ab755838a ksupport: expose libc/compiler-rt strlen and bcmp 2025-07-30 18:17:09 +08:00
e21873d227 runtime: make aux_mutex static 2025-07-25 16:27:01 +08:00
767b725db7 runtime: make restart_idle static
Semaphore is already Send/Sync so there is no need to wrap it in an Rc
and pass it around.
2025-07-16 14:00:36 +08:00
e02b56b709 flake: update dependencies 2025-07-16 12:39:09 +08:00
8223d263f6 libconfig: remove Config struct
Replaced with module level functions.
2025-07-16 12:39:01 +08:00
1c64f4488a update cargo lockfile 2025-07-15 16:05:27 +08:00
67d79c81a5 satman: return rtio init reply in subkernels 2025-07-14 11:22:04 +08:00
9e6b06250a cargo fmt 2025-07-11 17:09:13 +08:00
58e54ec7af rtio init: wait for comms to acknowledge the reset 2025-07-11 17:03:51 +08:00
089f3cb664 cxp_camera_setup: support async read/write
cxp_camera_setup: change u32&u64 read/write functions to be async
2025-07-04 16:38:25 +08:00
b0f508f675 cxp_packet: support u64 async read/write
cxp_packet: refactor get_ctrl fns for reuse
cxp_packet: remove gating on async fns for cxp_camera_setup
cxp_packet: change u64 read/write fns to be async
cxp_packet: keep u32 read/write sync fn for cxp syscalls
2025-07-04 16:38:25 +08:00
89f22883e5 comms: suppress warning 2025-07-04 14:47:06 +08:00
160132a858 si5324: fix zc706 switch clock error 2025-07-04 10:55:53 +08:00
eeda17bbb5 rtio_mgt: don't panic if master not found 2025-07-04 10:16:10 +08:00
b7588ed629 rtio_mgt: do not assume master is at destination 0 2025-07-04 10:16:10 +08:00
7fc7e971f7 core1: don't assume 0 is the master's destination 2025-07-04 10:16:10 +08:00
aacf22211b rtio_mgt: move local rtio setup to link thread beginning 2025-07-04 10:16:10 +08:00
8769439d60 flake: update dependencies 2025-07-03 19:47:41 +08:00
7fb596e803 satman main: add CXP grabber thread and phy setup 2025-07-03 17:42:46 +08:00
137fb5375e satman: handle CXP drtio aux packet
satman main: gate drtiosat_cxp.rs behind has_cxp_grabber
drtiosat_cxp: spawn separate async task for read and write CXP operation
drtiosat_cxp: reply error if camera is not detected
drtiosat_cxp: process cxp roi viewer setup and data request
drtiosat_aux: forward and handle cxp aux packets
2025-07-03 17:42:46 +08:00
23af88157e si5324: fix no ack error with coaxpress_sfp led
si5324: select i2c mux ports when changing recovery clock
2025-07-03 17:42:46 +08:00
37cdc02b66 kasli_soc satellite: add coaxpress_sfp support
kasli_soc: remove error message when using coaxpress_sfp with satellite
satellite: use sfp slot 0 for coaxpress_sfp
satellite: connect the right virtual led bits when drtio_ch < 4
2025-07-03 17:42:46 +08:00
74a1ff2bc7 satellite json: add coaxpress_sfp 2025-07-03 17:42:46 +08:00
54d494e6ec kernel cxp: add CXP satellite support
api: compile cxp.rs with DRTIO using cfg gating
cxp: refactor xml helper fns to accept read byte closure
cxp: support non-local destination CXP syscall
cxp: pass satellite read, write, roi viewer request to core0
cxp: raise error when local has no cxp_grabber and no drtio
cxp: pass CXP error from satellite as CXPError
2025-07-03 17:42:46 +08:00
871de86e18 comms: handle CXP kernel message
kernel: add CXP error, read, write, roi viewer kernel messages
comms: send roi viewer setup to satellite
comms: support polling for roi viewer data, read, write request
comms: printout drtio aux and unexpected packet via error macro
comms: pass CXP error to kernel
2025-07-03 17:42:46 +08:00
fcb668dd23 drtioaux_proto: add CXP packets
proto: add CXP payload size in u8 and u64
proto: add CXP err, wait, read, write, roi viewer packets
2025-07-03 17:33:06 +08:00
7478ff4967 cxp_packet: add async CXP read/write operations 2025-07-03 17:33:06 +08:00
d9b5bb83c2 cxp_grabber: use async mutex to prevent deadlock 2025-07-03 17:33:06 +08:00
2defdc13bd cxp_grabber: move roi viewer setup from syscall 2025-07-03 17:33:06 +08:00
bb8bc269a2 cxp_grabber: move CXP thread from runtime main 2025-07-03 17:33:06 +08:00
c03d3c500b cargo fmt 2025-07-02 15:18:49 +08:00
23512254d4 cxp syscall: clear roi viewer ready CSR 2025-07-02 14:35:31 +08:00
e8b73e45fb cxp syscall: move to kernel directory 2025-07-02 14:35:31 +08:00
a5b46ca948 flake: update dependencies 2025-06-26 18:45:05 +08:00
eace3e9fb7 runtime: fix import warns 2025-06-26 15:39:02 +08:00
f2462b28e6 remove GlobalTimer, CountDown 2025-06-26 12:35:33 +08:00
ba3eec7154 flake: update dependencies 2025-06-26 12:35:25 +08:00
0c216c86ae flake: cleanup ramda python dep 2025-06-25 21:36:03 +08:00
ea3b6141c4 flake: update dependencies 2025-06-25 21:06:50 +08:00
955283eea4 cargo fmt 2025-06-19 10:54:31 +08:00
e4800e1343 libboard_artiq: remove unnecessary libsupport_zynq dep 2025-06-17 16:54:03 +08:00
6124937da0 update cargo lock 2025-06-16 15:14:10 +08:00
32b91027fd comms: remove Sockets::run 2025-06-16 15:14:10 +08:00
5afc1d4296 flake: update dependencies 2025-06-16 15:14:04 +08:00
1b012fd708 Shrink the DMA buffer after recording
We have to be careful here to ensure the DMA buffer is 512-bit
aligned. We used to do this by reserving space for padding, and then
adding it afterwards. Now we add it all up-front.
2025-06-16 12:35:44 +08:00
81baed1231 cargo fmt 2025-06-11 15:25:23 +08:00
bc80454c8d subkernel: async port
cargo: add async-recursion for rpc_async.rs
satman: add rpc_async.rs for subkernel
subkernel: Manager now take RefCell for config for async
subkernel: use async_send and async recv_w_timeout to prevent blocking
satman main: init config with RefCell
satman main: add awiat to async fn
dma, drtiosat_aux: add await to async fn
2025-06-11 15:25:23 +08:00
23d92f1cc2 routing: async port
drtiosat_aux: add await to routing async fn
2025-06-11 15:25:23 +08:00
9093ee9350 repeater: async port
repeater: use async delay and drtioaux_async to prevent blocking
drtiosat_aux and satman: add await to repeater async fn
2025-06-11 15:25:23 +08:00
c34779c20c drtiosat_aux: async port
drtiosat: use drtioaux_async to prevent blocking
satman main: add await for process_aux_packets
2025-06-11 15:25:23 +08:00
192f8b24fd satman main: main loop async port
main: use block_on on async main loop
main loop: use drtio_async to prevent blocking
main loop: refactor linkup_service into a separate function
grabber: spawn as separate async task instead of in the loop as hw tick
drtiosat_process_error: spawn as async task instead of in the loop
2025-06-11 15:25:23 +08:00
724ba885b0 satman: move process_aux_packet to drtiosat_aux 2025-06-11 15:24:49 +08:00
2340b44dae cargo fmt 2025-06-11 11:17:54 +08:00
0c642c48c0 update rustfmt 2025-06-11 11:17:54 +08:00
3338dcd56b flake: update dependencies 2025-06-11 09:09:23 +08:00
a9a85b440e cargo fmt 2025-06-10 16:35:54 +08:00
67dfbe6860 allow static_mut_refs 2025-06-10 15:29:39 +08:00
2c1979d380 fix target-spec json 2025-06-10 15:17:02 +08:00
f3c0fc24cd libunwind: allow internal features 2025-06-10 15:17:02 +08:00
5dff8636f6 satman: remove no_mangle from panic_fmt
#51647 has been closed
2025-06-10 15:17:02 +08:00
0933a0f013 satman: always print panic message 2025-06-10 15:17:02 +08:00
80309e8cdc runtime: always print panic message 2025-06-10 15:17:02 +08:00
39cf613818 specify C ABI for api! macro 2025-06-10 15:17:02 +08:00
1ace72f2f0 remove unnecessary feature attributes 2025-06-10 15:17:02 +08:00
bb700bc955 silence unexpected cfg warns 2025-06-10 15:08:11 +08:00
8c5c8b8169 use naked_asm for interrupt_handler 2025-06-10 15:08:11 +08:00
ae0abe364f move cargo -> cargo.toml 2025-06-10 15:08:11 +08:00
f5a6a674f5 flake: update rust lib lockfile 2025-06-10 15:07:50 +08:00
15e9f09a54 flake: move to clang 20 2025-06-10 15:06:03 +08:00
5ceff93a7a libdyld: move to ed2018 2025-06-10 13:51:11 +08:00
d77e092523 libbuild_zynq: move to ed2018 2025-06-10 13:51:11 +08:00
dcc022d8c8 libio: move to ed2018 2025-06-10 13:51:11 +08:00
d9388adc05 satman: move to ed2018 2025-06-10 13:51:11 +08:00
3f1186d363 analyzer: mark BUFFER as immutable 2025-06-10 13:03:06 +08:00
7cad72fc39 flake: update migen-axi 2025-06-05 14:49:01 +08:00
56b5240039 master json: add coaxpress_sfp 2025-06-05 10:38:12 +08:00
e05df9791b kasli_soc master: add coaxpress_sfp support
kasli_soc: move "add_coaxpress_sfp" out of standalone
kasli_soc: use provided refclk for coaxpress_sfp GTX
kasli_soc: update error message when using coaxpress_sfp with satellite
master: use sfp slot 0 for coaxpress_sfp
master: connect the right virtual led bits when drtio_ch < 4
2025-06-05 10:38:12 +08:00
a37124b318 flake: apply migen-axi-pr-34.patch to migen-axi 2025-06-05 10:06:21 +08:00
e7bcbf43d6 flake: update dependencies 2025-06-02 15:59:13 +08:00
add27693c5 cxp_grabber: remove unnecessary mut 2025-05-27 15:43:18 +08:00
8be4ac6265 CXP thread: improve async performance
cxp_camera_setup: use async delay instead of blocking timer.delay
cxp_camera_setup: manually yield timeout function to reduce blocking
cxp_grabber and main: add .await for async fns
2025-05-27 13:28:17 +08:00
c0eb70247a cxp camera setup: extend RX connection test time 2025-05-24 07:34:44 +08:00
7df7335cce flake: update dependencies 2025-05-21 17:16:20 +08:00
13654d9f5a runtime main: add i2c to CXP grabber thread 2025-05-19 11:32:13 +08:00
1445ab16d6 cxp_grabber: use i2c to update_led in FSM
cxp_grabber: gate update_led using has_cxp_led cfg
2025-05-19 11:32:13 +08:00
257e6c4772 cxp_led: add CoaXPress-SFP status LED support
cxp_led: add PCA9530 LED blinker support
lib: gate cxp_led.rs with has_cxp_led rust cfg
2025-05-19 11:32:13 +08:00
2157539140 kasli_soc GW: add HAS_CXP_LED rust cfg 2025-05-15 13:24:38 +08:00
c60b6bcd41 cxp setup: add reg read check in camera discovery 2025-05-15 12:31:43 +08:00
228050c54d zc706 CXP: update parameter names 2025-05-14 13:42:03 +08:00
da4748bea7 demo json: add coaxpress_sfp 2025-05-14 13:42:03 +08:00
0717003c42 kasli soc: add coaxpress-sfp support to standalone
cxp-sfp: add IBUFDS_GTE2
cxp-sfp: add CXPGrabber with its memory region and CSR
cxp-sfp: add `CXPGrabber` rtio interface to self.rtio_channels
cxp-sfp: add timing requirement for cd_cxp_gt_rx
master/satellite: raise warning when using coaxpress-sfp
2025-05-14 13:42:03 +08:00
04856e66d0 cxp_phy: fix TXOUT_DIV 2025-05-14 13:42:03 +08:00
1dd864f9e5 flake: update dependencies 2025-05-14 13:42:03 +08:00
168529e26d move to naersk, build-std
remove direct compiler_builtins dep
2025-05-13 17:36:13 +08:00
f917457fbd flake: update dependencies 2025-05-13 17:36:06 +08:00
29ed10dfb3 ksupport: no rtio_init after forceful termination 2025-04-24 17:34:41 +08:00
afd0389bf3 rtio: reset satellites on rtio_init as well 2025-04-10 15:01:46 +08:00
f5139ee140 i2c io expander: fix the write changes 2025-04-01 14:37:37 +08:00
761b7c99cd i2c io expander: stop the bus even after an error 2025-03-29 16:37:24 +08:00
5982937ee6 flake: update dependencies 2025-03-29 16:37:06 +08:00
32889c11f1 i2c: dispatch remote i2c requests from kernel 2025-03-24 11:32:00 +08:00
bc7925989b cxp syscall: use usual order of ROI coordinates 2025-03-20 15:47:18 +08:00
b2256800fe cxp syscall: error if roiviewer over height limit 2025-03-20 15:47:18 +08:00
637163bbca flake: update dependencies 2025-03-19 17:25:37 +08:00
50ead76c09 i2c: use error enum, nacks cannot be ignored 2025-03-19 16:36:56 +08:00
267a1222ed cxp_grabber: add ROIViewer syscalls
api: add start roi viewer to flush the fifo and set the ROI coordinate
api: add roi viewer frame download
2025-03-14 12:12:58 +08:00
fe09e8615e flake: update dependencies 2025-03-14 12:11:57 +08:00
cb8fa20beb remove/allow dead code
CxpRead/CxpWrite functions are unused
and unplanned, removing. DrtioContext emits warn
because Clone is ignored in dead code analysis.
2025-03-14 11:30:31 +08:00
0efa450537 update cargo lockfile 2025-03-14 11:29:43 +08:00
4c59ab933b cargo fmt 2025-03-12 17:36:34 +08:00
504d7a8d5b flake: update dependencies 2025-03-12 17:28:35 +08:00
a577238bae bump rustfmt 2025-03-12 13:56:26 +08:00
1c90228f84 silence static mut ref warn for RECORDER 2025-03-12 13:56:26 +08:00
8129b8163c update futures, num-derive, async-recursion
bunched together to avoid depending on two separate `syn`
versions
2025-03-12 13:56:26 +08:00
95175b7168 silence dead code warns 2025-03-12 13:56:26 +08:00
3172625ba6 allow internal features
Signed-off-by: Simon Renblad <srenblad@m-labs.hk>
2025-03-12 13:56:26 +08:00
9e51599195 remove unnecessary imports 2025-03-12 13:56:26 +08:00
5445a1268c remove unnecessary mut 2025-03-12 13:56:26 +08:00
48ed2f188e fix dropping references 2025-03-12 13:56:26 +08:00
64d79de6c5 bump compiler_builtins to 0.1.108 2025-03-12 13:56:26 +08:00
be8f618d95 renamed const_btree_new feature 2025-03-12 13:56:26 +08:00
dca808b2e4 remove stabilized nll, static_nobundle flags 2025-03-12 13:56:26 +08:00
e4b85bf51a bump llvm to 18 2025-03-12 13:56:26 +08:00
c2c5367572 kasli-soc: support shuttler as a peripheral of kasli-soc satellite 2025-03-11 11:45:45 +08:00
290134e07e libio: add endianness as generic type param
Based on the API of ReadBytesExt, WriteBytesExt
from byteorder without the std dependency.
2025-03-10 15:44:33 +08:00
e07dad71d5 libksupport: add cxp syscall support
cxp: add read/write 32 bit value
cxp: add xml file download
lib: gate cxp import
api: add cxp syscalls
2025-03-04 14:46:39 +08:00
d0c34671d7 artiq error: add cxp error for syscall 2025-03-04 14:46:39 +08:00
82a1b38a19 runtime main: add cxp grabber support
main: init cxp phys
main: start cxp grabber task
2025-03-04 14:46:39 +08:00
db76dfc209 cxp_grabber fw: add cxp grabber handler
cxp_grabber: add cxp grabber tick task
cxp_grabber: add camera_connected and with_tag helper fns for syscall
libboard_artiq: add cxp_grabber.rs
2025-03-04 14:46:39 +08:00
b0ceac0f3a cxp_camera_setup fw: initalize camera
camera_setup: add setup error and error message
camera_setup: add camera discovery
camera_setup: add camera setup sequence
camera_setup: add placeholder HOST_CONNECTION_ID
libboard_artiq: add cxp_camera_setup.rs
2025-03-04 14:46:39 +08:00
a0673f13a1 cxp_packet fw: add cxp packet handler
packet: add receiving/sending control packet (w/ or w/o tags) handling
packet: add sending test packet
packet: add read/write register interface
packet: add read bytes for xml file download
libboard_artiq: add cxp_packet.rs
2025-03-04 14:46:39 +08:00
6086b867c8 cxp_ctrl fw: add cxp control packet parser
ctrl: add control packet error and error message
ctrl: add CXPCRC32 calculation
ctrl: use byteoder crate to handle endianness
ctrl: add control packer reader and writer
ctrl: add error correction for reading 4x char
libboard_artiq: add cxp_ctrl.rs
2025-03-04 14:46:39 +08:00
17f59e2353 cxp_phys fw: add CXP TRX phys support
phys: add tx & rx setup
tx: add csr to change linerate between 20.83/41.6Mpbs
rx: add GTX and QPLL DRP to change linerate 1.25-12.5Gbps
libboard artiq: add cxp_phys.rs
2025-03-04 14:46:39 +08:00
f080bee029 libboard_artiq cargo: add byteorder 2025-03-04 14:46:39 +08:00
599442dc0d flake: add zc706 cxp_4r_fmc variant build options 2025-03-04 14:46:39 +08:00
622bca24d1 zc706: add CXP_4R_FMC variant
zc706 base: expose cdr_clk (gt_refclk) for CXPGrabber
grabber: add cxp_4r_fmc pads
grabber: add CXPGrabber module
grabber: add csr and memory group for CXPGrabber
grabber: add CXPGrabber and user led to rtio_channel
grabber: add constraint for cd_cxp_gt_rx
2025-03-04 14:46:39 +08:00
bcab64f1ff gateware: add cxp_4r_fmc pinout 2025-03-04 14:46:39 +08:00
dfc731a4c1 flake: update dependencies 2025-03-04 14:46:39 +08:00
58ecf62921 libksupport: inline _resolve_channel_name helper
Signed-off-by: Simon Renblad <srenblad@m-labs.hk>
2025-03-04 14:19:50 +08:00
11134cdfd6 use MaybeUninit for LOGGER 2025-02-27 13:18:23 +08:00
2e99b9cf0d use MaybeUninit for I2C_BUS, create get_bus helper 2025-02-27 13:18:23 +08:00
4f79ee962c fix cargo-xbuild dependency 2025-02-17 15:15:33 +08:00
d4105b79e7 flake: update dependencies 2025-02-17 15:15:22 +08:00
1beb6fd944 cargo fmt 2025-02-13 17:46:15 +08:00
ce1c430fdc upgrade rustfmt required version 2025-02-13 17:45:29 +08:00
cf99700299 update cargo lockfile 2025-02-13 17:31:43 +08:00
9f1f349b29 export rust_eh_personality manually 2025-02-13 17:31:43 +08:00
98255ec25a prevent vectorizing copy_work_buffer 2025-02-13 17:31:43 +08:00
421033ef98 remove unused asm feature flag 2025-02-13 17:31:43 +08:00
c603a4ba12 remove allow incomplete features 2025-02-13 17:31:43 +08:00
529d7819a9 fix missing asm macro 2025-02-13 17:31:43 +08:00
1a1a7112ca silence target-feature warns 2025-02-13 17:31:43 +08:00
e524317eb9 bump to llvm14 2025-02-13 17:31:43 +08:00
d545feddbd flake: update dependencies 2025-02-13 17:31:28 +08:00
0e6da19406 ksupport: remove redundant enable_fpu 2025-02-11 20:16:24 +08:00
d0e2404311 flake: update zynq-rs 2025-02-11 20:15:55 +08:00
cd9f8e6d7c flake: update dependencies 2025-02-11 20:11:53 +08:00
4a2b28dcc3 flake: update dependencies 2025-02-06 20:16:34 +08:00
21a4a0b5dd core1: use C repr in attribute writeback 2025-02-06 14:34:18 +08:00
a82d356f52 flake: update dependencies 2025-02-05 16:58:48 +08:00
8b9bb38331 Do not apply offsets to null pointers 2025-02-03 12:04:02 +00:00
63157588bb flake: update dependencies 2025-01-15 21:17:34 +08:00
11f8675ad6 drtio: fix RTIO channel name resolution for remote channels 2025-01-15 13:12:14 +08:00
a0281e4989 cargo fmt 2024-12-23 12:51:10 +08:00
850e783139 bump rustfmt 2024-12-23 12:50:54 +08:00
8fd8cae9d5 update dependencies 2024-12-20 16:11:26 +08:00
7acf8af7f7 flake add outputHashes 2024-12-20 16:11:26 +08:00
13264d9992 update cargo lockfile 2024-12-20 16:11:26 +08:00
8d07f006f2 silence inline_const warns 2024-12-20 16:11:26 +08:00
97e15d51f2 remove unused abi-blacklist, force-unwind-tables 2024-12-20 16:11:26 +08:00
0021a01bdf use forked core_io, up nalgebra 2024-12-20 16:11:04 +08:00
16801a35f4 llvm11 -> llvm13 2024-12-18 17:06:39 +08:00
81eba30a29 prevent cursor r/w optimization 2024-12-18 17:06:39 +08:00
7d6d40a785 replace deprecated NoneError use 2024-12-18 17:06:39 +08:00
ffe3020788 replace const_in_array_expression with inline 2024-12-18 17:06:39 +08:00
8f510b5ca6 change to C-unwind interface 2024-12-18 17:06:38 +08:00
5582ca74d2 runtime: clean up unused imports 2024-12-17 15:52:17 +08:00
7c741d9c18 flake: update dependencies 2024-12-11 13:34:54 +08:00
922a03b807 drtio: restore copy_work_buffer for transmission 2024-12-11 12:09:21 +08:00
716a5924d1 kasli_soc: fix acpki import 2024-12-10 12:54:22 +08:00
4856cddb65 gateware: add extra ident info, source version 2024-12-10 12:54:22 +08:00
e1f493f3ca drtio: add InjectionRequest to expects_response 2024-11-26 14:58:24 +08:00
1f5ea41934 flake: update dependencies 2024-11-20 19:58:55 +08:00
7f83d56ef5 cargo fmt 2024-11-20 09:42:49 +08:00
1d431456f4 Fix DWARF parser treating catch blocks as unconditional
Signed-off-by: Jonathan Coates <jonathan.coates@oxionics.com>
2024-11-20 09:32:38 +08:00
b03e380c1e flake: update dependencies 2024-11-20 09:07:00 +08:00
47fc53c4bf drtio_tuple -> drtio_context 2024-11-18 13:13:10 +08:00
42eaecf9e1 remove debug message 2024-11-18 12:19:37 +08:00
beb7e6f994 cargo fmt 2024-11-18 12:19:37 +08:00
4502a47aa6 drtio_proto: add allocate step for flashing
This avoids reallocation while transfering binaries.
2024-11-18 12:19:37 +08:00
ac6b7d5cf0 satman: fix checksum error message 2024-11-18 12:19:37 +08:00
3019bc6123 runtime: check crc when flashing 2024-11-18 12:19:37 +08:00
95b8562812 cargo fmt 2024-11-18 12:19:37 +08:00
a13f5d02fa mgmt: supplementary tuple -> tuple struct 2024-11-18 12:19:37 +08:00
e52aa77068 cargo fmt 2024-11-18 12:19:37 +08:00
8e28d12ad0 runtime mgmt: avoid pull_log resource hog 2024-11-18 12:19:37 +08:00
47cddae04f runtime mgmt: avoid passing incomplete log to core_log 2024-11-18 12:19:37 +08:00
27a65df40e satman mgmt: fix uart log level change message 2024-11-18 12:19:37 +08:00
759cca3bfd satman mgmt: allow sliceable to consume log source 2024-11-18 12:19:37 +08:00
aadb6fc22d satman mgmt: get logger unconditionally 2024-11-18 12:19:37 +08:00
ae4d5a4228 mgmt: minor fix 2024-11-18 12:19:37 +08:00
6f1d727ca2 drtio-proto: avoid expecting response to drop link ack 2024-11-18 12:19:37 +08:00
7da5061f7e coremgmt: fix import/uses 2024-11-18 12:19:37 +08:00
47d418c69e coremgmt: remove unnecsaary cursors 2024-11-18 12:19:37 +08:00
d2979e8894 runtime coremgmt: implement firmware rewrite 2024-11-18 12:19:37 +08:00
3884c14a19 satman coremgmt: code after reboot is unreachable 2024-11-18 12:19:37 +08:00
c5b00d8e4e cargo fmt 2024-11-18 12:19:37 +08:00
2985875f9a satman: implement boot file rewrite sequence 2024-11-18 12:19:37 +08:00
5cb565a7e0 coremgr: current_payload -> config_payload 2024-11-18 12:19:37 +08:00
59954829a2 drtio-proto: (N)ACK -> Reply { succeeded } 2024-11-18 12:19:37 +08:00
960864c847 drtio-proto: add coremgmt-over-drtio messages 2024-11-18 12:19:37 +08:00
bdc29e5709 runtime: support coremgmt on satellites 2024-11-18 12:19:37 +08:00
332732dc44 satman: implement cfg/mgmt operations 2024-11-18 12:19:37 +08:00
244c7396d9 runtime: handle drtio-eem satellite disconnection 2024-11-18 12:08:44 +08:00
2c633409b8 Set FCLK0 for EBAZ4205
EBAZ4205 uses FCLK0 as the RTIO clock.

If the user modifies the gateware to use an external clock, FCLK0 is not used.
Co-authored-by: newell <newell.jensen@gmail.com>
Co-committed-by: newell <newell.jensen@gmail.com>
2024-11-17 10:08:43 +08:00
9774b39fd8 flake: update zynq-rs 2024-11-16 17:32:05 +08:00
9054e4a7cb flake: update zynq-rs, switch to oxalica rust overlay 2024-11-16 17:22:01 +08:00
d79bf8d54a gateware: Add default TTLs to EBAZ4205 (#335)
Co-authored-by: newell <newell.jensen@gmail.com>
Co-committed-by: newell <newell.jensen@gmail.com>
2024-11-16 10:40:45 +08:00
75e7fc55a3 flake: update dependencies 2024-11-16 10:39:39 +08:00
24a4d79f0f README: general update 2024-11-07 19:07:38 +01:00
9ce3aadb15 cargo fmt 2024-10-18 17:43:39 +08:00
3390abd5a1 subkernels: pass now_mu when calling subkernels 2024-10-18 13:51:48 +08:00
a410c40b50 ADD SPI to EBAZ4205 for AD9834 (#331)
Co-authored-by: newell <newell.jensen@gmail.com>
Co-committed-by: newell <newell.jensen@gmail.com>
2024-10-17 15:06:11 +08:00
030247be18 add pre-commit hooks for code formatting
Co-authored-by: newell <newell.jensen@gmail.com>
Co-committed-by: newell <newell.jensen@gmail.com>
2024-10-08 15:19:07 +08:00
61df939c87 ebaz4205: add variant and hydra job
Co-authored-by: newell <newell.jensen@gmail.com>
Co-committed-by: newell <newell.jensen@gmail.com>
2024-10-08 11:35:31 +08:00
aba97175c6 Fix formatting 2024-10-05 16:30:45 -07:00
81790257a5 Add ebaz4205 support (#327)
Co-authored-by: newell <newell.jensen@gmail.com>
Co-committed-by: newell <newell.jensen@gmail.com>
2024-10-05 15:05:49 +08:00
1f81d038e0 update dependencies 2024-10-05 14:50:13 +08:00
1e42228aac flake: remove deprecated pytest-runner 2024-09-30 16:19:56 +08:00
c84653b500 flake: update dependencies 2024-09-30 16:01:11 +08:00
6585b9b441 flake: update dependencies 2024-09-30 14:17:25 +08:00
873dd86b4d runtime: cargo fmt (NFC) 2024-09-19 10:23:31 +08:00
e7614d2e8e rerun idle kernel on finish 2024-09-13 09:35:38 +08:00
491e426222 run idle kernel on flash 2024-09-12 16:12:57 +08:00
ccd3bf3003 runtime: fix drtio inject lock 2024-09-02 17:19:20 +08:00
3fdb7e80a8 flake: update dependencies 2024-08-23 19:14:08 +08:00
bd1de933fb cargo fmt 2024-08-23 17:49:14 +08:00
e8d77fca3e firmware: add UnwrapNoneError exception 2024-08-23 16:50:47 +08:00
85e8a3fc44 firmware: add LinAlgError exception 2024-08-22 10:42:28 +08:00
04078b3d89 flake: update dependencies 2024-08-21 18:51:19 +08:00
d508c5c6f8 firmware: add unit tests for exception sync 2024-08-21 16:35:03 +08:00
bae41253e4 firmware: sync exception names and ids 2024-08-21 16:34:25 +08:00
20181e9915 fix nalgebra url 2024-08-07 13:49:03 +08:00
a835149619 kernel/linalg: remove redundant unsafe blocks 2024-08-07 13:48:21 +08:00
78d6b7ddcf cargo fmt 2024-08-05 19:37:55 +08:00
fad1db9796 comms: remove idle kernel DRTIO error case 2024-08-05 19:28:09 +08:00
fee30033ec comms: run idle kernel on start-up 2024-08-05 19:28:09 +08:00
fe6f259d48 kernel: add linalg functions 2024-08-01 18:20:32 +08:00
e4d7ce114f flake: update fastnumbers 2024-08-01 07:41:32 +08:00
63f4783687 subkernels: support exceptions from subkernels 2024-07-31 17:22:29 +08:00
69a0b1bfb7 subkernels: raise exceptions to kernel 2024-07-31 17:22:29 +08:00
f6bff80105 flake: update dependencies 2024-07-31 17:20:54 +08:00
57fd327ecb rustfmt 2024-07-22 18:55:17 +08:00
69d5b11ebf kernel/api: add nalgebra::linalg methods 2024-07-22 11:57:58 +08:00
bab938c563 add nalgebra dependency
Co-authored-by: abdul124 <ar@m-labs.hk>
Co-committed-by: abdul124 <ar@m-labs.hk>
2024-07-22 11:13:45 +08:00
d51e5e60c3 repeater: handle async messages 2024-07-09 23:04:34 +08:00
23857eef63 allow toggling SED spread with flash config key 2024-07-09 18:11:20 +08:00
d0615bf965 flake: update dependencies 2024-07-09 10:37:37 +02:00
3a789889cf kernel/api: add rint api 2024-07-05 14:53:09 +08:00
72b814f7fd repeater: clear buffer after ping 2024-07-04 17:30:04 +08:00
99 changed files with 9981 additions and 3731 deletions

View File

@@ -4,60 +4,102 @@ ARTIQ on Zynq
How to use
----------
1. Install the ARTIQ version that corresponds to the artiq-zynq version you are targeting.
2. To obtain firmware binaries, select the latest successful build on [Hydra](https://nixbld.m-labs.hk/) for the targeted artiq-zynq version, or use AFWS. If using Hydra, search for the job named ``<board>-<variant>-sd`` (for example: ``zc706-nist_clock-sd`` or ``zc706-nist_qc2-sd``).
3. Place the ``boot.bin`` file, obtained from Hydra's "binary distribution" download link or from AFWS, at the root of a FAT-formatted SD card.
4. Optionally, create a ``config.txt`` configuration file at the root of the SD card containing ``key=value`` pairs on each line. Use the ``ip``, ``ip6`` and ``mac`` keys to respectively set the IPv4, IPv6 and MAC address of the board. Configuring an IPv6 address is entirely optional. If these keys are not found, the firmware will use default values that may or may not be compatible with your network.
5. Insert the SD card into the board and set up the board to boot from the SD card. For the ZC706, this is achieved by placing the large DIP switch SW11 in the 00110 position.
6. Power up the board. After the firmware starts successfully, it should respond to ping at its IP addresses, and boot messages can be observed from its UART at 115200bps.
7. Create and use an ARTIQ device database as usual, but set ``"target": "cortexa9"`` in the arguments of the core device.
1. [Install ARTIQ](https://m-labs.hk/artiq/manual/installing.html). Get the corresponding version to the ``artiq-zynq`` version you are targeting.
2. To obtain firmware binaries, use AFWS or build your own; see [the ARTIQ manual](https://m-labs.hk/artiq/manual/building_developing.html) for detailed instructions or skip to "Development" below. ZC706 variants only can also be downloaded from latest successful build on [Hydra](https://nixbld.m-labs.hk/).
3. Place ``boot.bin`` file at the root ``/`` of a FAT-formatted SD card.
4. Optionally, create a ``config.txt`` configuration file containing ``key=value`` pairs on each line and place it at the root of the SD card. See below for valid keys. The ``ip``, ``ip6`` and ``mac`` keys can be used to set networking information. If these keys are not found, the firmware will use default values which may or may not be compatible with your network.
5. Insert the SD card into the board and set the board to boot from the SD card. For ZC706, this is achieved by placing the large DIP switch SW11 into the 00110 position. On Kasli-SoC, place the BOOT MODE switches to SD.
6. Power up the board. After successful boot the firmware should respond to ping at its IP addresses. Boot output can be observed from UART at 115200bps 8-N-1.
7. Create and use an ARTIQ device database as usual.
Configuration
-------------
Configuring the device is done using the ``config.txt`` text file at the root of the SD card, plus the contents of the ``config`` folder. When searching for a configuration key, the firmware first looks for a file named ``/config/[key].bin`` and, if it exists, returns the contents of that file. If not, it looks into ``/config.txt``, which contains a list of ``key=value`` pairs, one per line. The ``config`` folder allows configuration values that consist in binary data, such as the startup kernel.
Configuring the device is done using the ``config.txt`` text file at the root of the SD card plus optionally a ``config`` folder. When searching for a configuration key, the firmware first looks for a file named ``/config/[key].bin`` and, if it exists, returns the contents of that file. If not, it looks into ``/config.txt``, which should contain a list of ``key=value`` pairs, one per line. ``config.txt`` should be used for most keys but the ``config`` folder allows for setting configuration values which consist of binary data, such as the startup kernel.
The following configuration keys are available:
The following configuration keys are available among others:
- ``mac``: Ethernet MAC address.
- ``ip``: IPv4 address.
- ``ip6``: IPv6 address.
- ``startup``: startup kernel in ELF format (as produced by ``artiq_compile``).
- ``idle_kernel``: idle kernel in ELF format (as produced by ``artiq_compile``).
- ``startup_kernel``: startup kernel in ELF format (as produced by ``artiq_compile``).
- ``rtio_clock``: source of RTIO clock; valid values are ``ext0_bypass`` and ``int_125``.
- ``boot``: SD card "boot.bin" file, for replacing the boot firmware/gateware. Write only.
Configurations can be read/written/removed via ``artiq_coremgmt``. Config erase is
not implemented as it seems not very useful.
See [ARTIQ manual](https://m-labs.hk/artiq/manual-beta/core_device.html#configuration-storage) for full list. Configurations can be read/written/removed with ``artiq_coremgmt``. Config erase is not implemented, as it isn't particularly useful.
For convenience, the ``boot`` key can be used with ``artiq_coremgmt`` and a ``boot.bin`` file to replace firmware/gateware in a running system. This key is read-only. When loading ``boot.bin`` onto the SD card directly, place it at the root and not in the ``config`` folder.
Development instructions
------------------------
ARTIQ on Zynq is packaged using the [Nix](https://nixos.org) Flakes system. Install Nix 2.8+ and enable flakes by adding ``experimental-features = nix-command flakes`` to ``nix.conf`` (e.g. ``~/.config/nix/nix.conf``).
ARTIQ on Zynq is packaged using [Nix](https://nixos.org) Flakes. Install Nix 2.8+ and enable flakes by adding ``experimental-features = nix-command flakes`` to ``nix.conf`` (e.g. ``~/.config/nix/nix.conf``).
Pure build with Nix and execution on a remote JTAG server:
**Pure build with Nix:**
```shell
nix build .#zc706-nist_clock-jtag # or zc706-nist_qc2-jtag or zc706-nist_clock_satellite-jtag etc.
./remote_run.sh
nix build .#zc706-nist_clock-jtag # or zc706-nist_qc2-jtag or zc706-nist_clock-sd or etc
```
Impure incremental build and execution on a remote JTAG server:
Run ``nix flake show`` to see all valid build targets. Targets suffixed with ``-jtag`` produce separate firmware and gateware files, intended for use in booting via JTAG server/Ethernet, e.g. ``./remote_run.sh -i`` with a remote JTAG server. Targets suffixed with ``-sd`` will produce ``boot.bin`` file suitable for SD card boot. ``-firmware`` and ``-gateware`` respectively build firmware and gateware only.
The Kasli-SoC target requires a system description file as input. See ARTIQ manual for exact instructions or use incremental build.
**Impure incremental build:**
For boards with fixed variants, i.e. ZC706, etc. :
```shell
nix develop
cd src
gateware/zc706.py -g ../build/gateware -V <variant> # build gateware
make GWARGS="-V <variant>" <runtime/satman> # build firmware
cd ..
./remote_run.sh -i
gateware/<board>.py -g ../build/gateware -V <variant> # gateware
make GWARGS="-V <variant>" <runtime/satman> # firmware
```
For boards with system descriptions, i.e. Kasli-SoC, etc. :
```shell
nix develop
cd src
gateware/<board>.py -g ../build/gateware <description.json> # gateware
make TARGET=<board> GWARGS="path/to/description.json" <runtime/satman> # firmware
```
``szl.elf`` can be obtained with:
```shell
nix build git+https://git.m-labs.hk/m-labs/zynq-rs#<board>-szl
```
To generate ``boot.bin`` use ``mkbootimage``, e.g.:
```shell
echo "the_ROM_image:
{
[bootloader]result/szl.elf
gateware/top.bit
[elf_use_ph]firmware/armv7-none-eabihf/release/<runtime/satman>
}
EOF" >> boot.bif
mkbootimage boot.bif boot.bin
```
Notes:
- The impure build process is also compatible with non-Nix systems.
- When calling make, you need to specify both the variant and firmware type.
- Firmware type must be either ``runtime`` for DRTIO-less or DRTIO master variants, or ``satman`` for DRTIO satellite.
- If the board is connected to the local machine, use the ``local_run.sh`` script.
- If the board is connected to the local machine by JTAG, use the ``local_run.sh`` script.
- A known Xilinx hardware bug prevents repeatedly loading the bootloader over JTAG without a POR reset. If booting over JTAG, install a jumper on ``PS_POR_B`` and use the POR reset script [here](https://git.m-labs.hk/M-Labs/zynq-rs/src/branch/master/kasli_soc_por.py).
Pre-Commit Hooks
----------------
You are strongly recommended to use the provided pre-commit hooks to automatically reformat files and check for non-optimal Rust/C/C++ practices. Run `pre-commit install` to install the hook and `pre-commit` will automatically run `cargo fmt`, `cargo clippy`, and `clang-format` for you.
Several things to note:
- If `cargo fmt`, `cargo clippy`, or `clang-format` returns an error, the pre-commit hook will fail. You should fix all errors before trying to commit again.
- If `cargo fmt` or `clang-format` reformats some files, the pre-commit hook will also fail. You should review the changes and, if satisfied, try to commit again.
License
-------

View File

@@ -2,8 +2,11 @@
"target": "kasli_soc",
"variant": "demo",
"hw_rev": "v1.0",
"base": "standalone",
"drtio_role": "standalone",
"peripherals": [
{
"type": "coaxpress_sfp"
},
{
"type": "grabber",
"ports": [0]

View File

@@ -1,76 +0,0 @@
# For NIST_QC2
device_db = {
"core": {
"type": "local",
"module": "artiq.coredevice.core",
"class": "Core",
"arguments": {
"host": "192.168.1.52",
"ref_period": 1e-9,
"ref_multiplier": 8,
"target": "cortexa9"
}
},
"core_cache": {
"type": "local",
"module": "artiq.coredevice.cache",
"class": "CoreCache"
},
"core_dma": {
"type": "local",
"module": "artiq.coredevice.dma",
"class": "CoreDMA"
},
"i2c_switch": {
"type": "local",
"module": "artiq.coredevice.i2c",
"class": "PCA9548"
},
"led0": {
"type": "local",
"module": "artiq.coredevice.ttl",
"class": "TTLOut",
"arguments": {"channel": 41},
},
}
# TTLs on QC2 backplane
for i in range(40):
device_db["ttl" + str(i)] = {
"type": "local",
"module": "artiq.coredevice.ttl",
"class": "TTLInOut",
"arguments": {"channel": i}
}
device_db["ad9914dds0"] = {
"type": "local",
"module": "artiq.coredevice.ad9914",
"class": "AD9914",
"arguments": {"sysclk": 3e9, "bus_channel": 50, "channel": 0},
}
device_db["ad9914dds1"] = {
"type": "local",
"module": "artiq.coredevice.ad9914",
"class": "AD9914",
"arguments": {"sysclk": 3e9, "bus_channel": 50, "channel": 1},
}
for i in range(4):
device_db["ttl"+str(i)+"_counter"] = {
"type": "local",
"module": "artiq.coredevice.edge_counter",
"class": "EdgeCounter",
"arguments": {"channel": 52+i}
}
# for ARTIQ test suite
device_db.update(
loop_out="ttl0",
loop_in="ttl1",
ttl_out="ttl2",
ttl_out_serdes="ttl2",
)

1
examples/device_db.py Symbolic link
View File

@@ -0,0 +1 @@
device_db_zc706.py

View File

@@ -0,0 +1,78 @@
core_addr = "192.168.1.57"
device_db = {
"core": {
"type": "local",
"module": "artiq.coredevice.core",
"class": "Core",
"arguments": {
"host": core_addr,
"ref_period": 1e-9,
"target": "cortexa9",
},
},
"core_log": {
"type": "controller",
"host": "::1",
"port": 1068,
"command": "aqctl_corelog -p {port} --bind {bind} " + core_addr,
},
"core_moninj": {
"type": "controller",
"host": "::1",
"port_proxy": 1383,
"port": 1384,
"command": "aqctl_moninj_proxy --port-proxy {port_proxy} --port-control {port} --bind {bind} "
+ core_addr,
},
"core_analyzer": {
"type": "controller",
"host": "::1",
"port_proxy": 1385,
"port": 1386,
"command": "aqctl_coreanalyzer_proxy --port-proxy {port_proxy} --port-control {port} --bind {bind} "
+ core_addr,
},
"core_cache": {
"type": "local",
"module": "artiq.coredevice.cache",
"class": "CoreCache",
},
"core_dma": {"type": "local", "module": "artiq.coredevice.dma", "class": "CoreDMA"},
"led0": {
"type": "local",
"module": "artiq.coredevice.ttl",
"class": "TTLOut",
"arguments": {"channel": 0},
},
"led1": {
"type": "local",
"module": "artiq.coredevice.ttl",
"class": "TTLOut",
"arguments": {"channel": 1},
},
}
# TTLs starting at RTIO channel 2, ending at RTIO channel 15
for i in range(2, 16):
device_db["ttl" + str(i)] = {
"type": "local",
"module": "artiq.coredevice.ttl",
"class": "TTLInOut",
"arguments": {"channel": i},
}
device_db.update(
spi0={
"type": "local",
"module": "artiq.coredevice.spi2",
"class": "SPIMaster",
"arguments": {"channel": 16},
},
dds0={
"type": "local",
"module": "artiq.coredevice.ad9834",
"class": "AD9834",
"arguments": {"spi_device": "spi0"},
},
)

View File

@@ -0,0 +1,86 @@
# For NIST_QC2
import os
device_db = {
"core": {
"type": "local",
"module": "artiq.coredevice.core",
"class": "Core",
"arguments": {
"host": "192.168.1.52",
"ref_period": 1e-9,
"ref_multiplier": 8,
"target": "cortexa9"
}
},
"core_cache": {
"type": "local",
"module": "artiq.coredevice.cache",
"class": "CoreCache"
},
"core_dma": {
"type": "local",
"module": "artiq.coredevice.dma",
"class": "CoreDMA"
},
"i2c_switch": {
"type": "local",
"module": "artiq.coredevice.i2c",
"class": "PCA9548"
},
"led0": {
"type": "local",
"module": "artiq.coredevice.ttl",
"class": "TTLOut",
"arguments": {"channel": 41},
},
}
# TTLs on QC2 backplane
for i in range(40):
device_db["ttl" + str(i)] = {
"type": "local",
"module": "artiq.coredevice.ttl",
"class": "TTLInOut",
"arguments": {"channel": i}
}
device_db["ad9914dds0"] = {
"type": "local",
"module": "artiq.coredevice.ad9914",
"class": "AD9914",
"arguments": {"sysclk": 3e9, "bus_channel": 50, "channel": 0},
}
device_db["ad9914dds1"] = {
"type": "local",
"module": "artiq.coredevice.ad9914",
"class": "AD9914",
"arguments": {"sysclk": 3e9, "bus_channel": 50, "channel": 1},
}
for i in range(4):
device_db["ttl"+str(i)+"_counter"] = {
"type": "local",
"module": "artiq.coredevice.edge_counter",
"class": "EdgeCounter",
"arguments": {"channel": 52+i}
}
# for ARTIQ test suite
device_db.update(
loop_out="ttl0",
loop_in="ttl1",
ttl_out="ttl2",
ttl_out_serdes="ttl2",
)
if os.environ.get("ENABLE_ACPKI"):
device_db["core_batch"] = {
"type": "local",
"module": "artiq.coredevice.rtio",
"class": "RTIOBatch"
}

310
flake.lock generated
View File

@@ -3,25 +3,26 @@
"artiq": {
"inputs": {
"artiq-comtools": "artiq-comtools",
"mozilla-overlay": "mozilla-overlay",
"naersk": "naersk",
"nixpkgs": "nixpkgs",
"rust-overlay": "rust-overlay",
"sipyco": "sipyco",
"src-migen": "src-migen",
"src-misoc": "src-misoc",
"src-pythonparser": "src-pythonparser"
},
"locked": {
"lastModified": 1717638354,
"narHash": "sha256-eyI8OsOrn/j8ChbCpyFpS5VXBW8xSNGGIboFGQj/d4I=",
"lastModified": 1770708569,
"narHash": "sha256-Q/qir1PtGhinxNzkm/SzySwtLK0nsc06xn6BBPMuKlw=",
"ref": "refs/heads/master",
"rev": "ebc1e3fb767d6c0eac6eac20c3afeaba2ab70d1a",
"revCount": 8833,
"rev": "80d453eb23c5db45e02b7a84cf9b07ae8bf9bcfd",
"revCount": 9621,
"type": "git",
"url": "https://github.com/m-labs/artiq.git"
"url": "https://git.m-labs.hk/m-labs/artiq"
},
"original": {
"type": "git",
"url": "https://github.com/m-labs/artiq.git"
"url": "https://git.m-labs.hk/m-labs/artiq"
}
},
"artiq-comtools": {
@@ -37,16 +38,62 @@
]
},
"locked": {
"lastModified": 1717637438,
"narHash": "sha256-BXFidNm3Em8iChPGu1L0s2bY+f2yQ0VVid4MuOoTehw=",
"owner": "m-labs",
"repo": "artiq-comtools",
"rev": "78d27026efe76a13f7b4698a554f55811369ec4d",
"lastModified": 1767353405,
"narHash": "sha256-KGQqMMN+xavRYEPsBHnNptLvMGxaPzVqHJnYiOEo57c=",
"ref": "refs/heads/master",
"rev": "3da1f80d702b3a01c4b4fba9e5bc832b79097338",
"revCount": 44,
"type": "git",
"url": "https://git.m-labs.hk/M-Labs/artiq-comtools.git"
},
"original": {
"type": "git",
"url": "https://git.m-labs.hk/M-Labs/artiq-comtools.git"
}
},
"fenix": {
"inputs": {
"nixpkgs": [
"artiq",
"naersk",
"nixpkgs"
],
"rust-analyzer-src": "rust-analyzer-src"
},
"locked": {
"lastModified": 1752475459,
"narHash": "sha256-z6QEu4ZFuHiqdOPbYss4/Q8B0BFhacR8ts6jO/F/aOU=",
"owner": "nix-community",
"repo": "fenix",
"rev": "bf0d6f70f4c9a9cf8845f992105652173f4b617f",
"type": "github"
},
"original": {
"owner": "m-labs",
"repo": "artiq-comtools",
"owner": "nix-community",
"repo": "fenix",
"type": "github"
}
},
"fenix_2": {
"inputs": {
"nixpkgs": [
"zynq-rs",
"naersk",
"nixpkgs"
],
"rust-analyzer-src": "rust-analyzer-src_2"
},
"locked": {
"lastModified": 1752475459,
"narHash": "sha256-z6QEu4ZFuHiqdOPbYss4/Q8B0BFhacR8ts6jO/F/aOU=",
"owner": "nix-community",
"repo": "fenix",
"rev": "bf0d6f70f4c9a9cf8845f992105652173f4b617f",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "fenix",
"type": "github"
}
},
@@ -55,11 +102,11 @@
"systems": "systems"
},
"locked": {
"lastModified": 1710146030,
"narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
"lastModified": 1731533236,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"type": "github"
},
"original": {
@@ -68,66 +115,62 @@
"type": "github"
}
},
"mozilla-overlay": {
"flake": false,
"naersk": {
"inputs": {
"fenix": "fenix",
"nixpkgs": [
"artiq",
"nixpkgs"
]
},
"locked": {
"lastModified": 1704373101,
"narHash": "sha256-+gi59LRWRQmwROrmE1E2b3mtocwueCQqZ60CwLG+gbg=",
"owner": "mozilla",
"repo": "nixpkgs-mozilla",
"rev": "9b11a87c0cc54e308fa83aac5b4ee1816d5418a2",
"lastModified": 1768908532,
"narHash": "sha256-HIdLXEFaUVE8FiaCPJbCfBMsnF+mVtDub8Jwj2BD+mk=",
"owner": "nix-community",
"repo": "naersk",
"rev": "8d97452673640eb7fabe428e8b6a425bc355008b",
"type": "github"
},
"original": {
"owner": "mozilla",
"repo": "nixpkgs-mozilla",
"owner": "nix-community",
"repo": "naersk",
"type": "github"
}
},
"mozilla-overlay_2": {
"flake": false,
"naersk_2": {
"inputs": {
"fenix": "fenix_2",
"nixpkgs": [
"zynq-rs",
"nixpkgs"
]
},
"locked": {
"lastModified": 1704373101,
"narHash": "sha256-+gi59LRWRQmwROrmE1E2b3mtocwueCQqZ60CwLG+gbg=",
"owner": "mozilla",
"repo": "nixpkgs-mozilla",
"rev": "9b11a87c0cc54e308fa83aac5b4ee1816d5418a2",
"lastModified": 1769799857,
"narHash": "sha256-88IFXZ7Sa1vxbz5pty0Io5qEaMQMMUPMonLa3Ls/ss4=",
"owner": "nix-community",
"repo": "naersk",
"rev": "9d4ed44d8b8cecdceb1d6fd76e74123d90ae6339",
"type": "github"
},
"original": {
"owner": "mozilla",
"repo": "nixpkgs-mozilla",
"type": "github"
}
},
"mozilla-overlay_3": {
"flake": false,
"locked": {
"lastModified": 1704373101,
"narHash": "sha256-+gi59LRWRQmwROrmE1E2b3mtocwueCQqZ60CwLG+gbg=",
"owner": "mozilla",
"repo": "nixpkgs-mozilla",
"rev": "9b11a87c0cc54e308fa83aac5b4ee1816d5418a2",
"type": "github"
},
"original": {
"owner": "mozilla",
"repo": "nixpkgs-mozilla",
"owner": "nix-community",
"repo": "naersk",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1717281328,
"narHash": "sha256-evZPzpf59oNcDUXxh2GHcxHkTEG4fjae2ytWP85jXRo=",
"lastModified": 1768940263,
"narHash": "sha256-sJERJIYTKPFXkoz/gBaBtRKke82h4DkX3BBSsKbfbvI=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "b3b2b28c1daa04fe2ae47c21bb76fd226eac4ca1",
"rev": "3ceaaa8bc963ced4d830e06ea2d0863b6490ff03",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-24.05",
"ref": "nixos-25.11",
"repo": "nixpkgs",
"type": "github"
}
@@ -135,10 +178,86 @@
"root": {
"inputs": {
"artiq": "artiq",
"mozilla-overlay": "mozilla-overlay_2",
"zynq-rs": "zynq-rs"
}
},
"rust-analyzer-src": {
"flake": false,
"locked": {
"lastModified": 1752428706,
"narHash": "sha256-EJcdxw3aXfP8Ex1Nm3s0awyH9egQvB2Gu+QEnJn2Sfg=",
"owner": "rust-lang",
"repo": "rust-analyzer",
"rev": "591e3b7624be97e4443ea7b5542c191311aa141d",
"type": "github"
},
"original": {
"owner": "rust-lang",
"ref": "nightly",
"repo": "rust-analyzer",
"type": "github"
}
},
"rust-analyzer-src_2": {
"flake": false,
"locked": {
"lastModified": 1752428706,
"narHash": "sha256-EJcdxw3aXfP8Ex1Nm3s0awyH9egQvB2Gu+QEnJn2Sfg=",
"owner": "rust-lang",
"repo": "rust-analyzer",
"rev": "591e3b7624be97e4443ea7b5542c191311aa141d",
"type": "github"
},
"original": {
"owner": "rust-lang",
"ref": "nightly",
"repo": "rust-analyzer",
"type": "github"
}
},
"rust-overlay": {
"inputs": {
"nixpkgs": [
"artiq",
"nixpkgs"
]
},
"locked": {
"lastModified": 1719454714,
"narHash": "sha256-MojqG0lyUINkEk0b3kM2drsU5vyaF8DFZe/FAlZVOGs=",
"owner": "oxalica",
"repo": "rust-overlay",
"rev": "d1c527659cf076ecc4b96a91c702d080b213801e",
"type": "github"
},
"original": {
"owner": "oxalica",
"ref": "snapshot/2024-08-01",
"repo": "rust-overlay",
"type": "github"
}
},
"rust-overlay_2": {
"inputs": {
"nixpkgs": [
"zynq-rs",
"nixpkgs"
]
},
"locked": {
"lastModified": 1771038269,
"narHash": "sha256-TygYZ7JhnJbRoWOk7d5HaA/GhEVCvtRruN7TqaN9s/c=",
"owner": "oxalica",
"repo": "rust-overlay",
"rev": "d7a86c8a4df49002446737603a3e0d7ef91a9637",
"type": "github"
},
"original": {
"owner": "oxalica",
"repo": "rust-overlay",
"type": "github"
}
},
"sipyco": {
"inputs": {
"nixpkgs": [
@@ -147,67 +266,67 @@
]
},
"locked": {
"lastModified": 1717637367,
"narHash": "sha256-4mSm9wl5EMgzzrW6w86IDUevkEOT99FESHGcxcyQbD0=",
"owner": "m-labs",
"repo": "sipyco",
"rev": "02b96ec2473a3c3d3c980899de2564ddce949dab",
"type": "github"
"lastModified": 1767320872,
"narHash": "sha256-0lUkzOxOnjk3vQdsL9Yt3KLctYBTZgIRd8RvcITbqO0=",
"ref": "refs/heads/master",
"rev": "ce454bb64257b1bcef3703f258aaf7fa4ee0c275",
"revCount": 154,
"type": "git",
"url": "https://git.m-labs.hk/M-Labs/sipyco.git"
},
"original": {
"owner": "m-labs",
"repo": "sipyco",
"type": "github"
"type": "git",
"url": "https://git.m-labs.hk/M-Labs/sipyco.git"
}
},
"src-migen": {
"flake": false,
"locked": {
"lastModified": 1715484909,
"narHash": "sha256-4DCHBUBfc/VA+7NW2Hr0+JP4NnKPru2uVJyZjCCk0Ws=",
"owner": "m-labs",
"repo": "migen",
"rev": "4790bb577681a8c3a8d226bc196a4e5deb39e4df",
"type": "github"
"lastModified": 1768997857,
"narHash": "sha256-bdKQUQ3XLc4fV5sYBfKMuHuOS7nlF0ZU7rjWIKDzFzA=",
"ref": "refs/heads/master",
"rev": "44e5627d367c528b3ce5e686b6f305a9dfc56f2a",
"revCount": 2076,
"type": "git",
"url": "https://git.m-labs.hk/M-Labs/migen.git"
},
"original": {
"owner": "m-labs",
"repo": "migen",
"type": "github"
"type": "git",
"url": "https://git.m-labs.hk/M-Labs/migen.git"
}
},
"src-misoc": {
"flake": false,
"locked": {
"lastModified": 1715647536,
"narHash": "sha256-q+USDcaKHABwW56Jzq8u94iGPWlyLXMyVt0j/Gyg+IE=",
"lastModified": 1765867404,
"narHash": "sha256-YPYUHVIryXDp4W2hUtHUtBbRKIrbhInWImT0NKaacSY=",
"ref": "refs/heads/master",
"rev": "fea9de558c730bc394a5936094ae95bb9d6fa726",
"revCount": 2455,
"rev": "7ab412de11f6533cd68cd818924da5c28a484ccd",
"revCount": 2509,
"submodules": true,
"type": "git",
"url": "https://github.com/m-labs/misoc.git"
"url": "https://git.m-labs.hk/M-Labs/misoc.git"
},
"original": {
"submodules": true,
"type": "git",
"url": "https://github.com/m-labs/misoc.git"
"url": "https://git.m-labs.hk/M-Labs/misoc.git"
}
},
"src-pythonparser": {
"flake": false,
"locked": {
"lastModified": 1628745371,
"narHash": "sha256-p6TgeeaK4NEmbhimEXp31W8hVRo4DgWmcCoqZ+UdN60=",
"owner": "m-labs",
"repo": "pythonparser",
"rev": "5413ee5c9f8760e95c6acd5d6e88dabb831ad201",
"type": "github"
"lastModified": 1767427016,
"narHash": "sha256-E57okn+3gwvtXnF/qF/jypNYqijCLUYOEYLF9ZCzHpE=",
"ref": "refs/heads/master",
"rev": "a2ace427c84ee5b1e9bd9dbc9b9337e50fc54077",
"revCount": 152,
"type": "git",
"url": "https://git.m-labs.hk/M-Labs/pythonparser.git"
},
"original": {
"owner": "m-labs",
"repo": "pythonparser",
"type": "github"
"type": "git",
"url": "https://git.m-labs.hk/M-Labs/pythonparser.git"
}
},
"systems": {
@@ -227,18 +346,19 @@
},
"zynq-rs": {
"inputs": {
"mozilla-overlay": "mozilla-overlay_3",
"naersk": "naersk_2",
"nixpkgs": [
"artiq",
"nixpkgs"
]
],
"rust-overlay": "rust-overlay_2"
},
"locked": {
"lastModified": 1716889070,
"narHash": "sha256-w+M5NfukmcMTt73+u6Cmltjn4qpQH8bcoTGskB2IzBE=",
"lastModified": 1771064140,
"narHash": "sha256-udr/yfbyupzRr2HAYlqE/XMZ5lbPX3arYESrJ3hqKrc=",
"ref": "refs/heads/master",
"rev": "51b8111e799ebe90ca231ae4d02f84ede32632d5",
"revCount": 646,
"rev": "6e4e0548a2b98a6acdec8bb306caa08af8f41c2e",
"revCount": 742,
"type": "git",
"url": "https://git.m-labs.hk/m-labs/zynq-rs"
},

434
flake.nix
View File

@@ -1,29 +1,36 @@
{
description = "ARTIQ port to the Zynq-7000 platform";
inputs.artiq.url = git+https://github.com/m-labs/artiq.git;
inputs.mozilla-overlay = { url = github:mozilla/nixpkgs-mozilla; flake = false; };
inputs.artiq.url = git+https://git.m-labs.hk/m-labs/artiq;
inputs.zynq-rs.url = git+https://git.m-labs.hk/m-labs/zynq-rs;
inputs.zynq-rs.inputs.nixpkgs.follows = "artiq/nixpkgs";
outputs = { self, mozilla-overlay, zynq-rs, artiq }:
let
pkgs = import artiq.inputs.nixpkgs { system = "x86_64-linux"; overlays = [ (import mozilla-overlay) ]; };
outputs = {
self,
zynq-rs,
artiq,
}: let
pkgs = import artiq.inputs.nixpkgs {
system = "x86_64-linux";
overlays = [(import zynq-rs.inputs.rust-overlay)];
};
zynqpkgs = zynq-rs.packages.x86_64-linux;
artiqpkgs = artiq.packages.x86_64-linux;
llvmPackages_11 = zynq-rs.llvmPackages_11;
zynqRev = self.sourceInfo.rev or "unknown";
rust = zynq-rs.rust;
rustPlatform = zynq-rs.rustPlatform;
naerskLib = zynq-rs.naerskLib;
fastnumbers = pkgs.python3Packages.buildPythonPackage rec {
pname = "fastnumbers";
version = "2.2.1";
version = "5.1.0";
src = pkgs.python3Packages.fetchPypi {
inherit pname version;
sha256 = "0j15i54p7nri6hkzn1wal9pxri4pgql01wgjccig6ar0v5jjbvsy";
sha256 = "sha256-4JLTP4uVwxcaL7NOV57+DFSwKQ3X+W/6onYkN2AdkKc=";
};
pyproject = true;
build-system = [pkgs.python3Packages.setuptools];
};
artiq-netboot = pkgs.python3Packages.buildPythonPackage rec {
@@ -35,6 +42,8 @@
rev = "04f69eb07df73abe4b89fde2c24084f7664f2104";
sha256 = "0ql4fr8m8gpb2yql8aqsdqsssxb8zqd6l65kl1f6s9845zy7shs9";
};
pyproject = true;
build-system = [pkgs.python3Packages.setuptools];
};
ramda = pkgs.python3Packages.buildPythonPackage {
@@ -47,11 +56,13 @@
rev = "d315a9717ebd639366bf3fe26bad9e3d08ec3c49";
sha256 = "sha256-bmSt/IHDnULsZjsC6edELnNH7LoJSVF4L4XhwBAXRkY=";
};
pyproject = true;
build-system = [pkgs.python3Packages.setuptools];
nativeBuildInputs = with pkgs.python3Packages; [ pbr ];
propagatedBuildInputs = with pkgs.python3Packages; [ future fastnumbers ];
nativeBuildInputs = with pkgs.python3Packages; [pbr];
propagatedBuildInputs = with pkgs.python3Packages; [fastnumbers];
checkInputs = with pkgs.python3Packages; [ pytest ];
checkInputs = with pkgs.python3Packages; [pytest];
checkPhase = "pytest";
doCheck = false;
@@ -67,15 +78,15 @@
src = pkgs.fetchFromGitHub {
owner = "peteut";
repo = "migen-axi";
rev = "27eaa84a70a3abfe1930c86c36c4de2cd652da35";
sha256 = "sha256-3Y9W5ns+1wbVd14iePzgSBzE+LxnGMUDtUw3BccFt80=";
rev = "98649a92ed7d4e43f75231e6ef9753e1212fab41";
sha256 = "sha256-0kEHK+l6gZW750tq89fHRxIh3Gnj5EP2GZX/neWaWzU=";
};
pyproject = true;
build-system = [pkgs.python3Packages.setuptools];
format = "pyproject";
propagatedBuildInputs = with pkgs.python3Packages; [setuptools click numpy toolz jinja2 ramda artiqpkgs.migen artiqpkgs.misoc];
propagatedBuildInputs = with pkgs.python3Packages; [ setuptools click numpy toolz jinja2 ramda artiqpkgs.migen artiqpkgs.misoc ];
checkInputs = with pkgs.python3Packages; [ pytest-runner pytestCheckHook pytest-timeout ];
checkInputs = with pkgs.python3Packages; [pytestCheckHook pytest-timeout];
# migen/misoc version checks are broken with pyproject for some reason
postPatch = ''
@@ -88,22 +99,29 @@
substituteInPlace setup.cfg --replace '--flake8' ""
'';
};
binutils = { platform, target, zlib }: pkgs.stdenv.mkDerivation rec {
basename = "binutils";
version = "2.30";
name = "${basename}-${platform}-${version}";
src = pkgs.fetchurl {
url = "https://ftp.gnu.org/gnu/binutils/binutils-${version}.tar.bz2";
sha256 = "028cklfqaab24glva1ks2aqa1zxa6w6xmc8q34zs1sb7h22dxspg";
binutils = {
platform,
target,
zlib,
}:
pkgs.stdenv.mkDerivation rec {
basename = "binutils";
version = "2.30";
name = "${basename}-${platform}-${version}";
src = pkgs.fetchurl {
url = "https://ftp.gnu.org/gnu/binutils/binutils-${version}.tar.bz2";
sha256 = "028cklfqaab24glva1ks2aqa1zxa6w6xmc8q34zs1sb7h22dxspg";
};
configureFlags = ["--enable-shared" "--enable-deterministic-archives" "--target=${target}"];
outputs = ["out" "info" "man"];
depsBuildBuild = [pkgs.buildPackages.stdenv.cc];
buildInputs = [zlib];
enableParallelBuilding = true;
};
configureFlags =
[ "--enable-shared" "--enable-deterministic-archives" "--target=${target}"];
outputs = [ "out" "info" "man" ];
depsBuildBuild = [ pkgs.buildPackages.stdenv.cc ];
buildInputs = [ zlib ];
enableParallelBuilding = true;
binutils-arm = pkgs.callPackage binutils {
platform = "arm";
target = "armv7-unknown-linux-gnueabihf";
};
binutils-arm = pkgs.callPackage binutils { platform = "arm"; target = "armv7-unknown-linux-gnueabihf"; };
# FSBL configuration supplied by Vivado 2020.1 for these boards:
fsblTargets = ["zc702" "zc706" "zed"];
@@ -111,76 +129,97 @@
# kasli-soc satellite variants
"satellite"
# zc706 satellite variants
"nist_clock_satellite" "nist_qc2_satellite" "acpki_nist_clock_satellite" "acpki_nist_qc2_satellite"
"nist_clock_satellite_100mhz" "nist_qc2_satellite_100mhz" "acpki_nist_clock_satellite_100mhz" "acpki_nist_qc2_satellite_100mhz"
"nist_clock_satellite"
"nist_qc2_satellite"
"acpki_nist_clock_satellite"
"acpki_nist_qc2_satellite"
"nist_clock_satellite_100mhz"
"nist_qc2_satellite_100mhz"
"acpki_nist_clock_satellite_100mhz"
"acpki_nist_qc2_satellite_100mhz"
];
board-package-set = { target, variant, json ? null }: let
board-package-set = {
target,
variant,
json ? null,
}: let
szl = zynqpkgs."${target}-szl";
fsbl = zynqpkgs."${target}-fsbl";
fwtype = if builtins.elem variant sat_variants then "satman" else "runtime";
fwtype =
if builtins.elem variant sat_variants
then "satman"
else "runtime";
firmware = rustPlatform.buildRustPackage rec {
firmware = naerskLib.buildPackage rec {
name = "firmware";
src = ./src;
cargoLock = {
lockFile = src/Cargo.lock;
outputHashes = {
"tar-no-std-0.1.8" = "sha256-xm17108v4smXOqxdLvHl9CxTCJslmeogjm4Y87IXFuM=";
};
};
additionalCargoLock = "${rust}/lib/rustlib/src/rust/library/Cargo.lock";
singleStep = true;
nativeBuildInputs = [
pkgs.gnumake
(pkgs.python3.withPackages(ps: [ ps.jsonschema artiqpkgs.migen migen-axi artiqpkgs.misoc artiqpkgs.artiq ]))
zynqpkgs.cargo-xbuild
llvmPackages_11.llvm
llvmPackages_11.clang-unwrapped
(pkgs.python3.withPackages (ps: [artiqpkgs.migen migen-axi artiqpkgs.misoc artiqpkgs.artiq-build]))
pkgs.llvmPackages_20.llvm
pkgs.llvmPackages_20.clang-unwrapped
];
buildPhase = ''
export XARGO_RUST_SRC="${rust}/lib/rustlib/src/rust/library"
export CLANG_EXTRA_INCLUDE_DIR="${llvmPackages_11.clang-unwrapped.lib}/lib/clang/11.1.0/include"
export CARGO_HOME=$(mktemp -d cargo-home.XXX)
export ZYNQ_RS=${zynq-rs}
make TARGET=${target} GWARGS="${if json == null then "-V ${variant}" else json}" ${fwtype}
'';
installPhase = ''
mkdir -p $out $out/nix-support
cp ../build/${fwtype}.bin $out/${fwtype}.bin
cp ../build/firmware/armv7-none-eabihf/release/${fwtype} $out/${fwtype}.elf
echo file binary-dist $out/${fwtype}.bin >> $out/nix-support/hydra-build-products
echo file binary-dist $out/${fwtype}.elf >> $out/nix-support/hydra-build-products
'';
overrideMain = _: {
buildPhase = ''
export ZYNQ_REV=${zynqRev}
export CLANG_EXTRA_INCLUDE_DIR="${pkgs.llvmPackages_20.clang-unwrapped.lib}/lib/clang/20/include"
export ZYNQ_RS=${zynq-rs}
make TARGET=${target} GWARGS="${
if json == null
then "-V ${variant}"
else json
}" ${fwtype}
'';
doCheck = false;
dontFixup = true;
auditable = false;
installPhase = ''
mkdir -p $out $out/nix-support
cp ../build/${fwtype}.bin $out/${fwtype}.bin
cp ../build/firmware/armv7-none-eabihf/release/${fwtype} $out/${fwtype}.elf
echo file binary-dist $out/${fwtype}.bin >> $out/nix-support/hydra-build-products
echo file binary-dist $out/${fwtype}.elf >> $out/nix-support/hydra-build-products
'';
doCheck = false;
dontFixup = true;
};
};
gateware = pkgs.runCommand "${target}-${variant}-gateware"
gateware =
pkgs.runCommand "${target}-${variant}-gateware"
{
nativeBuildInputs = [
(pkgs.python3.withPackages(ps: [ ps.jsonschema artiqpkgs.migen migen-axi artiqpkgs.misoc artiqpkgs.artiq ]))
nativeBuildInputs = [
(pkgs.python3.withPackages (ps: [artiqpkgs.migen migen-axi artiqpkgs.misoc artiqpkgs.artiq-build]))
artiqpkgs.vivado
];
}
''
python ${./src/gateware}/${target}.py -g build ${if json == null then "-V ${variant}" else json}
export ZYNQ_REV=${zynqRev}
python ${./src/gateware}/${target}.py -g build ${
if json == null
then "-V ${variant}"
else json
}
mkdir -p $out $out/nix-support
cp build/top.bit $out
echo file binary-dist $out/top.bit >> $out/nix-support/hydra-build-products
'';
# SZL startup
jtag = pkgs.runCommand "${target}-${variant}-jtag" {}
jtag =
pkgs.runCommand "${target}-${variant}-jtag" {}
''
mkdir $out
ln -s ${szl}/szl.elf $out
ln -s ${firmware}/${fwtype}.bin $out
ln -s ${gateware}/top.bit $out
'';
sd = pkgs.runCommand "${target}-${variant}-sd"
sd =
pkgs.runCommand "${target}-${variant}-sd"
{
buildInputs = [ zynqpkgs.mkbootimage ];
buildInputs = [zynqpkgs.mkbootimage];
}
''
# Do not use "long" paths in boot.bif, because embedded developers
@@ -195,7 +234,7 @@
{
[bootloader]szl.elf
top.bit
${fwtype}.elf
[elf_use_ph]${fwtype}.elf
}
EOF
mkdir $out $out/nix-support
@@ -204,9 +243,10 @@
'';
# FSBL startup
fsbl-sd = pkgs.runCommand "${target}-${variant}-fsbl-sd"
fsbl-sd =
pkgs.runCommand "${target}-${variant}-fsbl-sd"
{
buildInputs = [ zynqpkgs.mkbootimage ];
buildInputs = [zynqpkgs.mkbootimage];
}
''
bifdir=`mktemp -d`
@@ -226,33 +266,34 @@
mkbootimage boot.bif $out/boot.bin
echo file binary-dist $out/boot.bin >> $out/nix-support/hydra-build-products
'';
in {
"${target}-${variant}-firmware" = firmware;
"${target}-${variant}-gateware" = gateware;
"${target}-${variant}-jtag" = jtag;
"${target}-${variant}-sd" = sd;
} // (
if builtins.elem target fsblTargets
then {
"${target}-${variant}-fsbl-sd" = fsbl-sd;
in
{
"${target}-${variant}-firmware" = firmware;
"${target}-${variant}-gateware" = gateware;
"${target}-${variant}-jtag" = jtag;
"${target}-${variant}-sd" = sd;
}
else {}
);
// (
if builtins.elem target fsblTargets
then {
"${target}-${variant}-fsbl-sd" = fsbl-sd;
}
else {}
);
gateware-sim = pkgs.stdenv.mkDerivation {
name = "gateware-sim";
nativeBuildInputs = [
(pkgs.python3.withPackages(ps: [ artiqpkgs.migen migen-axi artiqpkgs.artiq ]))
nativeBuildInputs = [
(pkgs.python3.withPackages (ps: [artiqpkgs.migen migen-axi artiqpkgs.artiq-build]))
];
phases = [ "buildPhase" ];
phases = ["buildPhase"];
buildPhase =
''
buildPhase = ''
python -m unittest discover ${self}/src/gateware -v
touch $out
'';
'';
};
fmt-check = pkgs.stdenvNoCC.mkDerivation {
@@ -260,35 +301,47 @@
src = ./src;
nativeBuildInputs = [ rust pkgs.gnumake ];
nativeBuildInputs = [rust pkgs.gnumake];
phases = [ "unpackPhase" "buildPhase" ];
phases = ["unpackPhase" "buildPhase"];
buildPhase =
''
buildPhase = ''
export ZYNQ_RS=${zynq-rs}
make manifests
cargo fmt -- --check
touch $out
'';
'';
};
# for hitl-tests
zc706-nist_qc2 = (board-package-set { target = "zc706"; variant = "nist_qc2"; });
zc706-hitl-tests = pkgs.stdenv.mkDerivation {
name = "zc706-hitl-tests";
zc706-nist_qc2 = board-package-set {
target = "zc706";
variant = "nist_qc2";
};
zc706-acpki_nist_qc2 = board-package-set {
target = "zc706";
variant = "acpki_nist_qc2";
};
make-zc706-hitl-tests = { name, board-package, setup-commands ? ""}: pkgs.stdenv.mkDerivation {
name = "zc706-hitl-tests-${name}";
__networked = true; # compatibility with old patched Nix
__networked = true; # compatibility with old patched Nix
# breaks hydra, https://github.com/NixOS/hydra/issues/1216
#__impure = true; # Nix 2.8+
buildInputs = [
pkgs.netcat pkgs.openssh pkgs.rsync artiqpkgs.artiq artiq-netboot zynqpkgs.zc706-szl
pkgs.netcat
pkgs.openssh
pkgs.rsync
artiqpkgs.artiq
artiq-netboot
zynqpkgs.zc706-szl
];
phases = [ "buildPhase" ];
phases = ["buildPhase"];
buildPhase =
''
buildPhase = ''
${setup-commands}
export NIX_SSHOPTS="-F /dev/null -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o LogLevel=ERROR -i /opt/hydra_id_ed25519"
LOCKCTL=$(mktemp -d)
mkfifo $LOCKCTL/lockctl
@@ -314,7 +367,7 @@
export USER=hydra
export OPENOCD_ZYNQ=${zynq-rs}/openocd
export SZL=${zynqpkgs.szl}
bash ${self}/remote_run.sh -h rpi-4 -o "$NIX_SSHOPTS" -d ${zc706-nist_qc2.zc706-nist_qc2-jtag}
bash ${self}/remote_run.sh -h rpi-4 -o "$NIX_SSHOPTS" -d ${board-package}
echo Waiting for the firmware to boot...
sleep 15
@@ -334,64 +387,163 @@
(echo b; sleep 5) | nc -N -w6 192.168.1.31 3131
echo Board powered off
)
'';
'';
};
zc706-hitl-tests = make-zc706-hitl-tests {
name = "nist_qc2";
board-package = zc706-nist_qc2.zc706-nist_qc2-jtag;
};
zc706-acpki-hitl-tests = make-zc706-hitl-tests {
name = "acpki_nist_qc2";
board-package = zc706-acpki_nist_qc2.zc706-acpki_nist_qc2-jtag;
setup-commands = "export ENABLE_ACPKI=1";
};
in rec {
packages.x86_64-linux =
{
inherit fastnumbers artiq-netboot ramda migen-axi binutils-arm;
} //
(board-package-set { target = "zc706"; variant = "nist_clock"; }) //
(board-package-set { target = "zc706"; variant = "nist_clock_master"; }) //
(board-package-set { target = "zc706"; variant = "nist_clock_master_100mhz"; }) //
(board-package-set { target = "zc706"; variant = "nist_clock_satellite"; }) //
(board-package-set { target = "zc706"; variant = "nist_clock_satellite_100mhz"; }) //
(board-package-set { target = "zc706"; variant = "nist_qc2"; }) //
(board-package-set { target = "zc706"; variant = "nist_qc2_master"; }) //
(board-package-set { target = "zc706"; variant = "nist_qc2_master_100mhz"; }) //
(board-package-set { target = "zc706"; variant = "nist_qc2_satellite"; }) //
(board-package-set { target = "zc706"; variant = "nist_qc2_satellite_100mhz"; }) //
(board-package-set { target = "zc706"; variant = "acpki_nist_clock"; }) //
(board-package-set { target = "zc706"; variant = "acpki_nist_clock_master"; }) //
(board-package-set { target = "zc706"; variant = "acpki_nist_clock_master_100mhz"; }) //
(board-package-set { target = "zc706"; variant = "acpki_nist_clock_satellite"; }) //
(board-package-set { target = "zc706"; variant = "acpki_nist_clock_satellite_100mhz"; }) //
(board-package-set { target = "zc706"; variant = "acpki_nist_qc2"; }) //
(board-package-set { target = "zc706"; variant = "acpki_nist_qc2_master"; }) //
(board-package-set { target = "zc706"; variant = "acpki_nist_qc2_master_100mhz"; }) //
(board-package-set { target = "zc706"; variant = "acpki_nist_qc2_satellite"; }) //
(board-package-set { target = "zc706"; variant = "acpki_nist_qc2_satellite_100mhz"; }) //
(board-package-set { target = "kasli_soc"; variant = "demo"; json = ./demo.json; }) //
(board-package-set { target = "kasli_soc"; variant = "master"; json = ./kasli-soc-master.json; }) //
(board-package-set { target = "kasli_soc"; variant = "satellite"; json = ./kasli-soc-satellite.json; });
}
// (board-package-set {
target = "zc706";
variant = "cxp_4r_fmc";
})
// (board-package-set {
target = "zc706";
variant = "nist_clock";
})
// (board-package-set {
target = "zc706";
variant = "nist_clock_master";
})
// (board-package-set {
target = "zc706";
variant = "nist_clock_master_100mhz";
})
// (board-package-set {
target = "zc706";
variant = "nist_clock_satellite";
})
// (board-package-set {
target = "zc706";
variant = "nist_clock_satellite_100mhz";
})
// (board-package-set {
target = "zc706";
variant = "nist_qc2";
})
// (board-package-set {
target = "zc706";
variant = "nist_qc2_master";
})
// (board-package-set {
target = "zc706";
variant = "nist_qc2_master_100mhz";
})
// (board-package-set {
target = "zc706";
variant = "nist_qc2_satellite";
})
// (board-package-set {
target = "zc706";
variant = "nist_qc2_satellite_100mhz";
})
// (board-package-set {
target = "zc706";
variant = "acpki_nist_clock";
})
// (board-package-set {
target = "zc706";
variant = "acpki_nist_clock_master";
})
// (board-package-set {
target = "zc706";
variant = "acpki_nist_clock_master_100mhz";
})
// (board-package-set {
target = "zc706";
variant = "acpki_nist_clock_satellite";
})
// (board-package-set {
target = "zc706";
variant = "acpki_nist_clock_satellite_100mhz";
})
// (board-package-set {
target = "zc706";
variant = "acpki_nist_qc2";
})
// (board-package-set {
target = "zc706";
variant = "acpki_nist_qc2_master";
})
// (board-package-set {
target = "zc706";
variant = "acpki_nist_qc2_master_100mhz";
})
// (board-package-set {
target = "zc706";
variant = "acpki_nist_qc2_satellite";
})
// (board-package-set {
target = "zc706";
variant = "acpki_nist_qc2_satellite_100mhz";
})
// (board-package-set {
target = "kasli_soc";
variant = "demo";
json = ./demo.json;
})
// (board-package-set {
target = "kasli_soc";
variant = "master";
json = ./kasli-soc-master.json;
})
// (board-package-set {
target = "kasli_soc";
variant = "satellite";
json = ./kasli-soc-satellite.json;
})
// (board-package-set {
target = "ebaz4205";
variant = "base";
});
hydraJobs = packages.x86_64-linux // { inherit zc706-hitl-tests; inherit gateware-sim; inherit fmt-check; };
hydraJobs =
packages.x86_64-linux
// {
inherit zc706-hitl-tests;
inherit zc706-acpki-hitl-tests;
inherit gateware-sim;
inherit fmt-check;
};
formatter.x86_64-linux = pkgs.alejandra;
devShell.x86_64-linux = pkgs.mkShell {
name = "artiq-zynq-dev-shell";
buildInputs = with pkgs; [
rust
llvmPackages_11.llvm
llvmPackages_11.clang-unwrapped
llvmPackages_20.llvm
llvmPackages_20.clang-unwrapped
gnumake
cacert
zynqpkgs.cargo-xbuild
zynqpkgs.mkbootimage
openocd
openssh rsync
(python3.withPackages(ps: (with artiqpkgs; [ migen migen-axi misoc artiq artiq-netboot ps.jsonschema ps.pyftdi ])))
openocd
openssh
rsync
(python3.withPackages (ps: (with artiqpkgs; [migen migen-axi misoc artiq artiq-netboot ps.jsonschema ps.pyftdi])))
artiqpkgs.artiq
artiqpkgs.vivado
binutils-arm
pre-commit
];
XARGO_RUST_SRC = "${rust}/lib/rustlib/src/rust/library";
CLANG_EXTRA_INCLUDE_DIR = "${llvmPackages_11.clang-unwrapped.lib}/lib/clang/11.1.0/include";
ZYNQ_REV = "${zynqRev}";
CLANG_EXTRA_INCLUDE_DIR = "${pkgs.llvmPackages_20.clang-unwrapped.lib}/lib/clang/20/include";
ZYNQ_RS = "${zynq-rs}";
OPENOCD_ZYNQ = "${zynq-rs}/openocd";
SZL = "${zynqpkgs.szl}";
};
makeArtiqZynqPackage = board-package-set;
};
}

View File

@@ -2,8 +2,11 @@
"target": "kasli_soc",
"variant": "master",
"hw_rev": "v1.0",
"base": "master",
"drtio_role": "master",
"peripherals": [
{
"type": "coaxpress_sfp"
},
{
"type": "grabber",
"ports": [0]

View File

@@ -2,8 +2,11 @@
"target": "kasli_soc",
"variant": "satellite",
"hw_rev": "v1.0",
"base": "satellite",
"drtio_role": "satellite",
"peripherals": [
{
"type": "coaxpress_sfp"
},
{
"type": "grabber",
"ports": [0]

View File

@@ -13,7 +13,7 @@ if [ -z "$SZL" ]; then
exit 1
fi
target_host="rpi-4.m-labs.hk"
target_host="rpi-4"
impure=0
pure_dir="result"
impure_dir="build"

View File

@@ -1,9 +1,12 @@
[target.armv7-none-eabihf]
rustflags = [
"-C", "link-arg=-Tlink.x",
"-C", "target-feature=a9,armv7-a,neon",
"-C", "link-arg=--no-check-sections", # required for overlapping sections
"-C", "target-cpu=cortex-a9",
]
[build]
target = "armv7-none-eabihf.json"
[unstable]
build-std = ["core", "alloc", "compiler_builtins"]

32
src/.clang-format Normal file
View File

@@ -0,0 +1,32 @@
BasedOnStyle: LLVM
Language: Cpp
Standard: Cpp11
AccessModifierOffset: -1
AlignEscapedNewlines: Left
AlwaysBreakAfterReturnType: None
AlwaysBreakTemplateDeclarations: Yes
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortFunctionsOnASingleLine: Inline
BinPackParameters: false
BreakBeforeBinaryOperators: NonAssignment
BreakBeforeTernaryOperators: true
BreakConstructorInitializers: AfterColon
BreakInheritanceList: AfterColon
ColumnLimit: 120
ConstructorInitializerAllOnOneLineOrOnePerLine: true
ContinuationIndentWidth: 4
DerivePointerAlignment: false
IndentCaseLabels: true
IndentPPDirectives: None
IndentWidth: 4
MaxEmptyLinesToKeep: 1
PointerAlignment: Left
ReflowComments: true
SortIncludes: false
SortUsingDeclarations: true
SpaceAfterTemplateKeyword: false
SpacesBeforeTrailingComments: 2
TabWidth: 4
UseTab: Never

1
src/.clippy.toml Normal file
View File

@@ -0,0 +1 @@
doc-valid-idents = ["CPython", "NumPy", ".."]

View File

@@ -0,0 +1,32 @@
# See https://pre-commit.com for more information
# See https://pre-commit.com/hooks.html for more hooks
default_stages: [commit]
repos:
- repo: local
hooks:
- id: cargo-fmt
name: artiq-zynq cargo format
entry: nix
language: system
types: [file, rust]
pass_filenames: false
description: Runs cargo fmt on the codebase.
args: [develop, -c, cargo, fmt, --manifest-path, src/Cargo.toml, --all]
- id: cargo-clippy
name: artiq-zynq cargo clippy
entry: nix
language: system
types: [file, rust]
pass_filenames: false
description: Runs cargo clippy on the codebase.
args: [develop, -c, cargo, clippy, --manifest-path, src/Cargo.toml, --tests]
- repo: https://github.com/pre-commit/mirrors-clang-format
rev: v19.1.0
hooks:
- id: clang-format
name: artiq-zynq clang-format
description: Runs clang-format on the codebase.
files: \.(cpp|h|hpp|c)$
args: [-style=file, -fallback-style=none, -assume-filename=src/.clang-format]

188
src/Cargo.lock generated
View File

@@ -1,6 +1,15 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
version = 4
[[package]]
name = "approx"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6"
dependencies = [
"num-traits",
]
[[package]]
name = "arrayvec"
@@ -10,9 +19,9 @@ checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711"
[[package]]
name = "async-recursion"
version = "0.3.2"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7d78656ba01f1b93024b7c3a0467f1608e4be67d725749fdcd7d2c7678fd7a2"
checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11"
dependencies = [
"proc-macro2",
"quote",
@@ -49,9 +58,9 @@ version = "0.0.0"
[[package]]
name = "byteorder"
version = "1.4.3"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
checksum = "60f0b0d4c0a382d2734228fd12b5a6b5dac185c60e938026fd31b265b94f9bd2"
[[package]]
name = "cc"
@@ -71,20 +80,10 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "compiler_builtins"
version = "0.1.39"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3748f82c7d366a0b4950257d19db685d4958d2fa27c6d164a3f069fec42b748b"
[[package]]
name = "core_io"
version = "0.1.20210325"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97f8932064288cc79feb4d343a399d353a6f6f001e586ece47fe518a9e8507df"
dependencies = [
"rustc_version",
]
version = "0.1.0"
source = "git+https://git.m-labs.hk/M-Labs/rs-core_io.git?rev=e9d3edf027#e9d3edf0272502b0dd6c26e8a4869c2912657615"
[[package]]
name = "crc"
@@ -106,7 +105,6 @@ name = "dwarf"
version = "0.0.0"
dependencies = [
"cfg-if 0.1.10",
"compiler_builtins",
"cslice",
"libc",
"unwind",
@@ -132,9 +130,8 @@ dependencies = [
[[package]]
name = "fatfs"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e18f80a87439240dac45d927fd8f8081b6f1e34c03e97271189fa8a8c2e96c8f"
version = "0.3.6"
source = "git+https://git.m-labs.hk/M-Labs/rust-fatfs.git?rev=4b5e420084#4b5e420084fd1c4a9c105680b687523909b6469c"
dependencies = [
"bitflags",
"byteorder",
@@ -144,9 +141,9 @@ dependencies = [
[[package]]
name = "futures"
version = "0.3.25"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38390104763dc37a5145a53c29c63c1290b5d316d6086ec32c293f6736051bb0"
checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876"
dependencies = [
"futures-channel",
"futures-core",
@@ -158,9 +155,9 @@ dependencies = [
[[package]]
name = "futures-channel"
version = "0.3.25"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52ba265a92256105f45b719605a571ffe2d1f0fea3807304b522c1d778f79eed"
checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10"
dependencies = [
"futures-core",
"futures-sink",
@@ -168,21 +165,21 @@ dependencies = [
[[package]]
name = "futures-core"
version = "0.3.25"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04909a7a7e4633ae6c4a9ab280aeb86da1236243a77b694a49eacd659a4bd3ac"
checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e"
[[package]]
name = "futures-io"
version = "0.3.25"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00f5fb52a06bdcadeb54e8d3671f8888a39697dcb0b81b23b55174030427f4eb"
checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6"
[[package]]
name = "futures-macro"
version = "0.3.25"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bdfb8ce053d86b91919aad980c220b1fb8401a9394410e1c289ed7e66b61835d"
checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
dependencies = [
"proc-macro2",
"quote",
@@ -191,21 +188,21 @@ dependencies = [
[[package]]
name = "futures-sink"
version = "0.3.25"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39c15cf1a4aa79df40f1bb462fb39676d0ad9e366c2a33b590d7c66f4f81fcf9"
checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7"
[[package]]
name = "futures-task"
version = "0.3.25"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2ffb393ac5d9a6eaa9d3fdf37ae2776656b706e200c8e16b1bdb227f5198e6ea"
checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988"
[[package]]
name = "futures-util"
version = "0.3.25"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "197676987abd2f9cadff84926f410af1c183608d36641465df73ae8211dc65d6"
checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81"
dependencies = [
"futures-core",
"futures-macro",
@@ -246,7 +243,7 @@ dependencies = [
"libsupport_zynq",
"log",
"log_buffer",
"nb 0.1.3",
"nalgebra",
"unwind",
"vcell",
"void",
@@ -259,7 +256,6 @@ dependencies = [
"embedded-hal",
"libcortex_a9",
"nb 1.0.0",
"pin-utils",
"smoltcp",
]
@@ -268,6 +264,7 @@ name = "libboard_artiq"
version = "0.0.0"
dependencies = [
"build_zynq",
"byteorder",
"core_io",
"crc",
"embedded-hal",
@@ -277,7 +274,6 @@ dependencies = [
"libconfig",
"libcortex_a9",
"libregister",
"libsupport_zynq",
"log",
"log_buffer",
"nb 1.0.0",
@@ -315,6 +311,7 @@ dependencies = [
"core_io",
"fatfs",
"libboard_zynq",
"libcortex_a9",
"log",
]
@@ -347,7 +344,6 @@ name = "libsupport_zynq"
version = "0.0.0"
dependencies = [
"cc",
"compiler_builtins",
"libboard_zynq",
"libcortex_a9",
"libregister",
@@ -363,9 +359,9 @@ checksum = "822add9edb1860698b79522510da17bef885171f75aa395cff099d770c609c24"
[[package]]
name = "log"
version = "0.4.17"
version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
dependencies = [
"cfg-if 1.0.0",
]
@@ -382,6 +378,19 @@ version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c75de51135344a4f8ed3cfe2720dc27736f7711989703a0b43aadf3753c55577"
[[package]]
name = "nalgebra"
version = "0.32.6"
source = "git+https://git.m-labs.hk/M-Labs/nalgebra.git?rev=ad42410ab0#ad42410ab0abb014229e3ff6bc6ccd39ca92d5d1"
dependencies = [
"approx",
"num-complex",
"num-rational",
"num-traits",
"simba",
"typenum",
]
[[package]]
name = "nb"
version = "0.1.3"
@@ -398,10 +407,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "546c37ac5d9e56f55e73b677106873d9d9f5190605e41a856503623648488cae"
[[package]]
name = "num-derive"
version = "0.3.3"
name = "num-complex"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d"
checksum = "26873667bbbb7c5182d4a37c1add32cdf09f841af72da53318fdb81543c15085"
dependencies = [
"num-traits",
]
[[package]]
name = "num-derive"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202"
dependencies = [
"proc-macro2",
"quote",
@@ -409,14 +427,41 @@ dependencies = [
]
[[package]]
name = "num-traits"
version = "0.2.15"
name = "num-integer"
version = "0.1.46"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
dependencies = [
"num-traits",
]
[[package]]
name = "num-rational"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d41702bd167c2df5520b384281bc111a4b5efcf7fbc4c9c222c815b07e0a6a6a"
dependencies = [
"autocfg",
"num-integer",
"num-traits",
]
[[package]]
name = "num-traits"
version = "0.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
dependencies = [
"autocfg",
"libm",
]
[[package]]
name = "paste"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
[[package]]
name = "pin-project-lite"
version = "0.2.9"
@@ -431,18 +476,18 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
name = "proc-macro2"
version = "1.0.43"
version = "1.0.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab"
checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.21"
version = "1.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179"
checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc"
dependencies = [
"proc-macro2",
]
@@ -461,6 +506,7 @@ dependencies = [
"build_zynq",
"byteorder",
"core_io",
"crc",
"cslice",
"dwarf",
"dyld",
@@ -478,6 +524,7 @@ dependencies = [
"libsupport_zynq",
"log",
"log_buffer",
"nb 0.1.3",
"num-derive",
"num-traits",
"tar-no-std",
@@ -486,21 +533,15 @@ dependencies = [
"void",
]
[[package]]
name = "rustc_version"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c5f5376ea5e30ce23c03eb77cbe4962b988deead10910c372b226388b594c084"
dependencies = [
"semver",
]
[[package]]
name = "satman"
version = "0.0.0"
dependencies = [
"async-recursion",
"build_zynq",
"byteorder",
"core_io",
"crc",
"cslice",
"embedded-hal",
"io",
@@ -518,10 +559,16 @@ dependencies = [
]
[[package]]
name = "semver"
version = "0.1.20"
name = "simba"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4f410fedcf71af0345d7607d246e7ad15faaadd49d240ee3b24e5dc21a820ac"
checksum = "50582927ed6f77e4ac020c057f37a268fc6aebc29225050365aacbb9deeeddc4"
dependencies = [
"approx",
"num-complex",
"num-traits",
"paste",
]
[[package]]
name = "smoltcp"
@@ -536,9 +583,9 @@ dependencies = [
[[package]]
name = "syn"
version = "1.0.101"
version = "2.0.98"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e90cde112c4b9690b8cbe810cba9ddd8bc1d7472e2cae317b69e9438c1cba7d2"
checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1"
dependencies = [
"proc-macro2",
"quote",
@@ -555,6 +602,12 @@ dependencies = [
"log",
]
[[package]]
name = "typenum"
version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
[[package]]
name = "unicode-ident"
version = "1.0.5"
@@ -567,7 +620,6 @@ version = "0.0.0"
dependencies = [
"cc",
"cfg-if 0.1.10",
"compiler_builtins",
"libc",
]

View File

@@ -21,20 +21,18 @@ manifests: $(manifests)
python gateware/$(TARGET).py -r ../build/pl.rs -c ../build/rustc-cfg -m ../build/mem.rs $(GWARGS)
../build/firmware/armv7-none-eabihf/release/runtime: ../build/pl.rs ../build/rustc-cfg ../build/mem.rs $(manifests) $(shell find . -type f -not -name Cargo.toml -print)
cd runtime && \
XBUILD_SYSROOT_PATH=`pwd`/../../build/sysroot \
cargo xbuild --release \
--target-dir ../../build/firmware \
cargo build --release \
-p runtime \
--target-dir ../build/firmware \
--no-default-features --features=target_$(TARGET)
../build/runtime.bin: ../build/firmware/armv7-none-eabihf/release/runtime
llvm-objcopy -O binary ../build/firmware/armv7-none-eabihf/release/runtime ../build/runtime.bin
../build/firmware/armv7-none-eabihf/release/satman: ../build/pl.rs ../build/rustc-cfg ../build/mem.rs $(manifests) $(shell find . -type f -not -name Cargo.toml -print)
cd satman && \
XBUILD_SYSROOT_PATH=`pwd`/../../build/sysroot \
cargo xbuild --release \
--target-dir ../../build/firmware \
cargo build --release \
-p satman \
--target-dir ../build/firmware \
--no-default-features --features=target_$(TARGET)
../build/satman.bin: ../build/firmware/armv7-none-eabihf/release/satman

View File

@@ -1,30 +1,20 @@
{
"abi-blacklist": [
"stdcall",
"fastcall",
"vectorcall",
"thiscall",
"win64",
"sysv64"
],
"arch": "arm",
"data-layout": "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64",
"emit-debug-gdb-scripts": false,
"env": "",
"executables": true,
"features": "+v7,+vfp3,-d32,+thumb2,-neon",
"is-builtin": false,
"features": "+v7,+vfp3,-d32,+thumb2,+neon,+a9,+armv7-a",
"linker": "rust-lld",
"linker-flavor": "ld.lld",
"llvm-target": "armv7-unknown-none-eabihf",
"llvm-floatabi": "hard",
"max-atomic-width": 32,
"os": "none",
"panic-strategy": "abort",
"requires-uwtable": true,
"force-unwind-tables": "yes",
"relocation-model": "static",
"target-c-int-width": "32",
"target-endian": "little",
"target-pointer-width": "32",
"vendor": ""
"target-pointer-width": "32"
}

View File

@@ -7,22 +7,28 @@ from misoc.interconnect.csr import *
from artiq.gateware import rtio
OUT_BURST_LEN = 10
IN_BURST_LEN = 4
# Burst len defined as number of transfers (0 -> 1, 1 -> 2 ..)
# thus equal to (64-bit) word count minus one
FIRST_BURST_LEN = 12 - 1 # extra 2 words for meta
OUT_BURST_LEN = 10 - 1
IN_BURST_LEN = 3 - 1
RTIO_I_STATUS_WAIT_STATUS = 4
RTIO_O_STATUS_WAIT = 1
BATCH_ENTRY_LEN = 80
class Engine(Module, AutoCSR):
def __init__(self, bus, user):
self.addr_base = CSRStorage(32)
self.trig_count = CSRStatus(32)
self.write_count = CSRStatus(32)
self.addr_base = Signal(32)
self.write_addr = Signal(32)
self.trigger_stb = Signal()
# 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
# When stb is asserted, index shows word being read/written,
# dout/din holds data
#
# Cycle:
# trigger_stb pulsed at start
@@ -35,11 +41,10 @@ class Engine(Module, AutoCSR):
self.din_ready = Signal()
self.dout = Signal(64)
self.din = Signal(64)
self.dout_burst_len = Signal(4)
###
self.sync += If(self.trigger_stb, self.trig_count.status.eq(self.trig_count.status+1))
self.comb += [
user.aruser.eq(0x1f),
user.awuser.eq(0x1f)
@@ -49,12 +54,12 @@ class Engine(Module, AutoCSR):
### Read
self.comb += [
ar.addr.eq(self.addr_base.storage),
ar.addr.eq(self.addr_base),
self.dout.eq(r.data),
r.ready.eq(1),
ar.burst.eq(axi.Burst.incr.value),
ar.len.eq(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.len.eq(self.dout_burst_len),
ar.size.eq(3), # Width of burst: 3 = 8 bytes = 64 bits
ar.cache.eq(0xf),
]
@@ -86,22 +91,23 @@ class Engine(Module, AutoCSR):
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)
)
).Elif(r.valid & read_fsm.ongoing("READ"),
self.dout_index.eq(self.dout_index+1)
)
]
self.comb += self.dout_stb.eq(r.valid & r.ready)
self.read_idle = Signal()
self.comb += self.read_idle.eq(read_fsm.ongoing("IDLE"))
### Write
self.comb += [
w.data.eq(self.din),
aw.addr.eq(self.addr_base.storage+96),
aw.addr.eq(self.write_addr),
w.strb.eq(0xff),
aw.burst.eq(axi.Burst.incr.value),
aw.len.eq(IN_BURST_LEN-1), # Number of transfers in burst minus 1
aw.size.eq(3), # Width of burst: 3 = 8 bytes = 64 bits
aw.len.eq(IN_BURST_LEN), # 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),
]
@@ -113,7 +119,7 @@ class Engine(Module, AutoCSR):
aw.valid.eq(0),
If(self.trigger_stb,
aw.valid.eq(1),
If(aw.ready, # assumes aw.ready is not randomly deasserted
If(aw.ready, # assumes aw.ready is not deasserted from now on
NextState("DATA_WAIT")
).Else(
NextState("AW_READY_WAIT")
@@ -140,8 +146,6 @@ class Engine(Module, AutoCSR):
)
)
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)
@@ -150,18 +154,20 @@ class Engine(Module, AutoCSR):
]
self.comb += [
w.last.eq(0),
If(self.din_index==aw.len, w.last.eq(1))
w.last.eq(self.din_index==aw.len),
self.din_stb.eq(w.valid & w.ready)
]
self.comb += self.din_stb.eq(w.valid & w.ready)
self.write_idle = Signal()
self.comb += self.write_idle.eq(write_fsm.ongoing("IDLE"))
class KernelInitiator(Module, AutoCSR):
def __init__(self, tsc, bus, user, evento):
# Core is disabled upon reset to avoid spurious triggering if evento toggles from e.g. boot code.
# Should be also reset between kernels (?)
self.enable = CSRStorage()
self.out_base = CSRStorage(32) # output data (to CRI)
self.in_base = CSRStorage(32) # in data (RTIO reply)
self.counter = CSRStatus(64)
self.counter_update = CSR()
@@ -173,12 +179,22 @@ class KernelInitiator(Module, AutoCSR):
###
batch_en = Signal()
batch_offset = Signal.like(self.out_base.storage) # address offset
batch_len = Signal(32)
batch_ptr = Signal(32)
batch_stb = Signal() # triggers the next event in the batch
evento_stb = Signal()
evento_latched = Signal()
evento_latched_d = Signal()
self.specials += MultiReg(evento, evento_latched)
self.sync += evento_latched_d.eq(evento_latched)
self.comb += self.engine.trigger_stb.eq(self.enable.storage & (evento_latched != evento_latched_d))
self.comb += [
self.engine.trigger_stb.eq(self.enable.storage & ((evento_latched != evento_latched_d) | batch_stb)),
self.engine.write_addr.eq(self.in_base.storage),
]
cri = self.cri
@@ -186,77 +202,130 @@ class KernelInitiator(Module, AutoCSR):
cmd_write = Signal()
cmd_read = Signal()
self.comb += [
cmd_write.eq(cmd == 0),
cmd_read.eq(cmd == 1)
cmd_write.eq(batch_en | (cmd == 0)), # rtio output, forced in batch mode
cmd_read.eq(~batch_en & (cmd == 1)), # rtio input, disallowed in batch mode
]
out_len = Signal(8)
dout_cases = {}
dout_cases[0] = [
cmd.eq(self.engine.dout[:8]),
out_len.eq(self.engine.dout[8:16]),
cri.chan_sel.eq(self.engine.dout[40:]),
cri.o_address.eq(self.engine.dout[32:40])
cmd.eq(self.engine.dout[:8]), # request_cmd: i8
out_len.eq(self.engine.dout[8:16]), # data_width: i8
# padding (2 bytes)
cri.o_address.eq(self.engine.dout[32:40]), # request_target: i32
cri.chan_sel.eq(self.engine.dout[40:]), # request_target cont.
]
for i in range(8):
target = cri.o_data[i*64:(i+1)*64]
dout_cases[0] += [If(i >= self.engine.dout[8:16], target.eq(0))]
dout_cases[1] = [
cri.o_timestamp.eq(self.engine.dout),
cri.i_timeout.eq(self.engine.dout)
cri.o_timestamp.eq(self.engine.dout), # request_timestamp: i64
cri.i_timeout.eq(self.engine.dout),
]
for i in range(8):
target = cri.o_data[i*64:(i+1)*64]
target = cri.o_data[i*64:(i+1)*64] # request_data: [i32; 16]
dout_cases[i+2] = [target.eq(self.engine.dout)]
# first iteration has extra 8 bytes for metadata
first_iter = Signal()
self.sync += [
cri.cmd.eq(rtio.cri.commands["nop"]),
If(self.engine.dout_stb,
Case(self.engine.dout_index, dout_cases),
If(self.engine.dout_index == out_len + 2,
If(cmd_write, cri.cmd.eq(rtio.cri.commands["write"])),
If(cmd_read, cri.cmd.eq(rtio.cri.commands["read"]))
)
If(first_iter,
# manual case for metadata
If(self.engine.dout_index == 0,
batch_len.eq(self.engine.dout[:32]),
batch_en.eq(self.engine.dout[32:40] == 1),
).Elif(self.engine.dout_index >= 2,
Case(self.engine.dout_index-2, dout_cases)
),
If(self.engine.dout_index == out_len + 4,
If(cmd_write, cri.cmd.eq(rtio.cri.commands["write"])),
If(cmd_read, cri.cmd.eq(rtio.cri.commands["read"]))
)
).Else(
Case(self.engine.dout_index, dout_cases),
If(self.engine.dout_index == out_len + 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
# If input event, wait for response before
# allowing the input data to be sampled
self.submodules.fsm = fsm = FSM(reset_state="IDLE")
fsm.act("IDLE",
If(self.engine.trigger_stb, NextState("WAIT_OUT_CYCLE"))
If(self.engine.trigger_stb,
NextState("FIRST_WAIT")),
)
fsm.act("WAIT_OUT_CYCLE",
fsm.act("FIRST_WAIT",
# first cycle - with extra 16 bytes for metadata
self.engine.din_ready.eq(0),
If(self.engine.dout_stb & cmd_write & (self.engine.dout_index == out_len + 2),
NextState("WAIT_READY")
),
# for some reason read requires some delay until the next state
If(self.engine.dout_stb & cmd_read & (self.engine.dout_index == out_len + 3),
batch_stb.eq(0),
first_iter.eq(1),
If(self.engine.dout_stb & (self.engine.dout_index == out_len + 5),
# prepare for the next step (no metadata for the next iterations)
If(batch_en,
NextValue(batch_ptr, batch_ptr + 1),
NextValue(self.engine.addr_base, self.engine.addr_base + BATCH_ENTRY_LEN + 16),
NextValue(self.engine.dout_burst_len, OUT_BURST_LEN),
),
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),
self.engine.din_ready.eq(1),
NextState("IDLE")
fsm.act("BATCH_NEXT_CYCLE",
self.engine.din_ready.eq(0),
batch_stb.eq(0),
first_iter.eq(0),
If(self.engine.dout_stb & (self.engine.dout_index == out_len + 3),
If(batch_en,
NextValue(batch_ptr, batch_ptr + 1),
NextValue(self.engine.addr_base, self.engine.addr_base + BATCH_ENTRY_LEN)
),
NextState("WAIT_READY")
)
)
fsm.act("WAIT_READY",
batch_stb.eq(0),
If((cmd_read & (cri.i_status & RTIO_I_STATUS_WAIT_STATUS == 0)) \
| (cmd_write & (cri.o_status & RTIO_O_STATUS_WAIT == 0)),
# stop the batch in case of an error or when reaching the capacity
If(~batch_en |
(batch_en & (((batch_len - 1) == batch_ptr) | (cri.o_status != 0))),
self.engine.din_ready.eq(1),
NextState("IDLE")
).Elif(self.engine.read_idle,
batch_stb.eq(1),
NextState("BATCH_NEXT_CYCLE")
)
)
)
self.sync += [
If(fsm.ongoing("IDLE"),
batch_ptr.eq(0),
batch_offset.eq(0),
self.engine.addr_base.eq(self.out_base.storage),
self.engine.dout_burst_len.eq(FIRST_BURST_LEN),
),
]
din_cases_cmdwrite = {
0: [self.engine.din.eq((1<<16) | cri.o_status)],
1: [self.engine.din.eq(0)],
2: [self.engine.din.eq(batch_ptr)]
}
din_cases_cmdread = {
# reply_status: VolatileCell<i32>, reply_data: VolatileCell<i32>
0: [self.engine.din[:32].eq((1<<16) | cri.i_status), self.engine.din[32:].eq(cri.i_data)],
1: [self.engine.din.eq(cri.i_timestamp)]
1: [self.engine.din.eq(cri.i_timestamp)], # reply_timestamp: VolatileCell<i64>,
2: [self.engine.din.eq(batch_ptr)] # reply_batch_count: VolatileCell<i32>
}
self.comb += [

View File

@@ -1,5 +1,15 @@
import os
from artiq._version import get_version
from misoc.integration import cpu_interface
def generate_ident(variant):
return "{}+{};{}".format(
get_version().split(".")[0],
os.getenv("ZYNQ_REV", default="unknown")[:8],
variant,
)
def write_csr_file(soc, filename):
with open(filename, "w") as f:
f.write(cpu_interface.get_csr_rust(

View File

@@ -0,0 +1,74 @@
from migen.build.generic_platform import *
fmc_adapter_io = [
# CoaXPress high speed link
("CXP_HS", 0,
Subsignal("rxp", Pins("HPC:DP0_M2C_P")),
Subsignal("rxn", Pins("HPC:DP0_M2C_N")),
),
("CXP_HS", 1,
Subsignal("rxp", Pins("HPC:DP1_M2C_P")),
Subsignal("rxn", Pins("HPC:DP1_M2C_N")),
),
("CXP_HS", 2,
Subsignal("rxp", Pins("HPC:DP2_M2C_P")),
Subsignal("rxn", Pins("HPC:DP2_M2C_N")),
),
("CXP_HS", 3,
Subsignal("rxp", Pins("HPC:DP3_M2C_P")),
Subsignal("rxn", Pins("HPC:DP3_M2C_N")),
),
# CoaXPress low speed link
("CXP_LS", 0, Pins("HPC:LA00_CC_P"), IOStandard("LVCMOS33")),
("CXP_LS", 1, Pins("HPC:LA01_CC_N"), IOStandard("LVCMOS33")),
("CXP_LS", 2, Pins("HPC:LA01_CC_P"), IOStandard("LVCMOS33")),
("CXP_LS", 3, Pins("HPC:LA02_N"), IOStandard("LVCMOS33")),
# CoaXPress green and red LED
("CXP_LED", 0,
Subsignal("green", Pins("HPC:LA11_P"), IOStandard("LVCMOS33")),
Subsignal("red", Pins("HPC:LA11_N"), IOStandard("LVCMOS33")),
),
("CXP_LED", 1,
Subsignal("green", Pins("HPC:LA12_P"), IOStandard("LVCMOS33")),
Subsignal("red", Pins("HPC:LA12_N"), IOStandard("LVCMOS33")),
),
("CXP_LED", 2,
Subsignal("green", Pins("HPC:LA13_P"), IOStandard("LVCMOS33")),
Subsignal("red", Pins("HPC:LA13_N"), IOStandard("LVCMOS33")),
),
("CXP_LED", 3,
Subsignal("green", Pins("HPC:LA14_P"), IOStandard("LVCMOS33")),
Subsignal("red", Pins("HPC:LA14_N"), IOStandard("LVCMOS33")),
),
# Power over CoaXPress
("PoCXP", 0,
Subsignal("enable", Pins("HPC:LA21_N"), IOStandard("LVCMOS33")),
Subsignal("alert", Pins("HPC:LA18_CC_P"), IOStandard("LVCMOS33")),
),
("PoCXP", 1,
Subsignal("enable", Pins("HPC:LA21_P"), IOStandard("LVCMOS33")),
Subsignal("alert", Pins("HPC:LA19_N"), IOStandard("LVCMOS33")),
),
("PoCXP", 2,
Subsignal("enable", Pins("HPC:LA22_N"), IOStandard("LVCMOS33")),
Subsignal("alert", Pins("HPC:LA19_P"), IOStandard("LVCMOS33")),
),
("PoCXP", 3,
Subsignal("enable", Pins("HPC:LA22_P"), IOStandard("LVCMOS33")),
Subsignal("alert", Pins("HPC:LA20_N"), IOStandard("LVCMOS33")),
),
("i2c", 0,
Subsignal("scl", Pins("HPC:IIC_SCL")),
Subsignal("sda", Pins("HPC:IIC_SDA")),
IOStandard("LVCMOS33")
),
# On board 125MHz reference
("clk125", 0,
Subsignal("p", Pins("HPC:GBTCLK0_M2C_P")),
Subsignal("n", Pins("HPC:GBTCLK0_M2C_N")),
),
]

309
src/gateware/ebaz4205.py Normal file
View File

@@ -0,0 +1,309 @@
#!/usr/bin/env python
import argparse
import analyzer
import dma
from artiq.gateware import rtio
from artiq.gateware.rtio.phy import spi2, ttl_simple
from artiq.gateware.rtio.xilinx_clocking import fix_serdes_timing_path
from config import generate_ident, write_csr_file, write_mem_file, write_rustc_cfg_file
from migen import *
from migen.build.generic_platform import IOStandard, Misc, Pins, Subsignal
from migen.build.platforms import ebaz4205
from migen_axi.integration.soc_core import SoCCore
from misoc.interconnect.csr import *
_ps = [
(
"ps",
0,
Subsignal("clk", Pins("E7"), IOStandard("LVCMOS33"), Misc("SLEW=FAST")),
Subsignal("por_b", Pins("C7"), IOStandard("LVCMOS33"), Misc("SLEW=FAST")),
Subsignal("srst_b", Pins("B10"), IOStandard("LVCMOS18"), Misc("SLEW=FAST")),
)
]
_ddr = [
(
"ddr",
0,
Subsignal(
"a",
Pins("N2 K2 M3 K3 M4 L1 L4 K4 K1 J4 F5 G4 E4 D4 F4"),
IOStandard("SSTL15"),
),
Subsignal("ba", Pins("L5 R4 J5"), IOStandard("SSTL15")),
Subsignal("cas_n", Pins("P5"), IOStandard("SSTL15")),
Subsignal("cke", Pins("N3"), IOStandard("SSTL15")),
Subsignal("cs_n", Pins("N1"), IOStandard("SSTL15")),
Subsignal("ck_n", Pins("M2"), IOStandard("DIFF_SSTL15"), Misc("SLEW=FAST")),
Subsignal("ck_p", Pins("L2"), IOStandard("DIFF_SSTL15"), Misc("SLEW=FAST")),
# Pins "T1 Y1" not connected
Subsignal("dm", Pins("A1 F1"), IOStandard("SSTL15_T_DCI"), Misc("SLEW=FAST")),
Subsignal(
"dq",
Pins("C3 B3 A2 A4 D3 D1 C1 E1 E2 E3 G3 H3 J3 H2 H1 J1"),
# Pins "P1 P3 R3 R1 T4 U4 U2 U3 V1 Y3 W1 Y4 Y2 W3 V2 V3" not connected
IOStandard("SSTL15_T_DCI"),
Misc("SLEW=FAST"),
),
Subsignal(
"dqs_n",
Pins("B2 F2"), # Pins "T2 W4" not connected
IOStandard("DIFF_SSTL15_T_DCI"),
Misc("SLEW=FAST"),
),
Subsignal(
"dqs_p",
Pins("C2 G2"), # Pins "R2 W5" not connected
IOStandard("DIFF_SSTL15_T_DCI"),
Misc("SLEW=FAST"),
),
Subsignal("vrn", Pins("G5"), IOStandard("SSTL15_T_DCI"), Misc("SLEW=FAST")),
Subsignal("vrp", Pins("H5"), IOStandard("SSTL15_T_DCI"), Misc("SLEW=FAST")),
Subsignal("drst_n", Pins("B4"), IOStandard("SSTL15"), Misc("SLEW=FAST")),
Subsignal("odt", Pins("N5"), IOStandard("SSTL15")),
Subsignal("ras_n", Pins("P4"), IOStandard("SSTL15")),
Subsignal("we_n", Pins("M5"), IOStandard("SSTL15")),
)
]
# Connector J3
_i2c = [
(
"i2c",
0,
Subsignal("scl", Pins("U12"), IOStandard("LVCMOS33")),
Subsignal("sda", Pins("V13"), IOStandard("LVCMOS33")),
)
]
_spi = [
(
"spi",
0,
Subsignal("clk", Pins("V20")),
Subsignal("mosi", Pins("U20")),
Subsignal("cs_n", Pins("P19")),
IOStandard("LVCMOS33"),
)
]
# Connector DATA1
def _create_ttl():
_ttl = []
for idx, elem in enumerate([x for x in range(5, 21) if x not in (10, 12)]):
_ttl.append(
("ttl", idx, Pins("DATA1:DATA1-{}".format(elem)), IOStandard("LVCMOS33")),
)
return _ttl
class EBAZ4205(SoCCore):
def __init__(self, rtio_clk=125e6, acpki=False, acpki_batch_size=1e5):
self.acpki = acpki
platform = ebaz4205.Platform()
platform.toolchain.bitstream_commands.extend(
[
"set_property BITSTREAM.GENERAL.COMPRESS True [current_design]",
]
)
platform.add_extension(_ps)
platform.add_extension(_ddr)
platform.add_extension(_i2c)
platform.add_extension(_spi)
platform.add_extension(_create_ttl())
gmii = platform.request("gmii")
platform.add_period_constraint(gmii.rx_clk, 10)
platform.add_period_constraint(gmii.tx_clk, 10)
platform.add_platform_command(
"set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets gmii_tx_clk_IBUF]"
)
ident = generate_ident(self.__class__.__name__)
if self.acpki:
ident = "acpki_" + ident
SoCCore.__init__(self, platform=platform, csr_data_width=32, ident=ident)
fix_serdes_timing_path(platform)
self.config["RTIO_FREQUENCY"] = str(rtio_clk / 1e6)
platform.add_period_constraint(self.ps7.cd_sys.clk, 10)
self.comb += [
self.ps7.enet0.enet.gmii.tx_clk.eq(gmii.tx_clk),
self.ps7.enet0.enet.gmii.rx_clk.eq(gmii.rx_clk),
]
self.clock_domains.cd_eth_rx = ClockDomain(reset_less=False)
self.clock_domains.cd_eth_tx = ClockDomain(reset_less=False)
self.comb += [
ClockSignal("eth_rx").eq(gmii.rx_clk),
ClockSignal("eth_tx").eq(gmii.tx_clk),
]
self.sync.eth_tx += [
gmii.txd.eq(self.ps7.enet0.enet.gmii.txd),
gmii.tx_en.eq(self.ps7.enet0.enet.gmii.tx_en),
]
self.sync.eth_rx += [
self.ps7.enet0.enet.gmii.rxd.eq(gmii.rxd),
self.ps7.enet0.enet.gmii.rx_dv.eq(gmii.rx_dv),
]
# MDIO
mdio = platform.request("mdio")
self.comb += mdio.mdc.eq(self.ps7.enet0.enet.mdio.mdc)
self.specials += Instance(
"IOBUF",
i_I=self.ps7.enet0.enet.mdio.o,
io_IO=mdio.mdio,
o_O=self.ps7.enet0.enet.mdio.i,
i_T=~self.ps7.enet0.enet.mdio.t_n,
)
# I2C
i2c = self.platform.request("i2c")
self.specials += [
# SCL
Instance(
"IOBUF",
i_I=self.ps7.i2c0.scl.o,
io_IO=i2c.scl,
o_O=self.ps7.i2c0.scl.i,
i_T=~self.ps7.i2c0.scl.t_n,
),
# SDA
Instance(
"IOBUF",
i_I=self.ps7.i2c0.sda.o,
io_IO=i2c.sda,
o_O=self.ps7.i2c0.sda.i,
i_T=~self.ps7.i2c0.sda.t_n,
),
]
self.rtio_channels = []
for i in (0, 1):
print("USER LED at RTIO channel 0x{:06x}".format(len(self.rtio_channels)))
user_led = self.platform.request("user_led", i)
phy = ttl_simple.Output(user_led)
self.submodules += phy
self.rtio_channels.append(rtio.Channel.from_phy(phy))
for i in range(14):
print("TTL at RTIO channel 0x{:06x}".format(len(self.rtio_channels)))
ttl = self.platform.request("ttl", i)
phy = ttl_simple.InOut(ttl)
self.submodules += phy
self.rtio_channels.append(rtio.Channel.from_phy(phy))
print("SPI at RTIO channel 0x{:06x}".format(len(self.rtio_channels)))
spi_phy = spi2.SPIMaster(platform.request("spi"))
self.submodules += spi_phy
self.rtio_channels.append(rtio.Channel.from_phy(spi_phy, ififo_depth=4))
self.config["RTIO_LOG_CHANNEL"] = len(self.rtio_channels)
self.rtio_channels.append(rtio.LogChannel())
self.submodules.rtio_tsc = rtio.TSC(glbl_fine_ts_width=3)
self.submodules.rtio_core = rtio.Core(self.rtio_tsc, self.rtio_channels)
self.csr_devices.append("rtio_core")
if self.acpki:
import acpki
self.config["KI_IMPL"] = "acp"
self.config["ACPKI_BATCH_SIZE"] = int(acpki_batch_size)
self.submodules.rtio = acpki.KernelInitiator(
self.rtio_tsc,
bus=self.ps7.s_axi_acp,
user=self.ps7.s_axi_acp_user,
evento=self.ps7.event.o,
)
self.csr_devices.append("rtio")
else:
self.config["KI_IMPL"] = "csr"
self.submodules.rtio = rtio.KernelInitiator(self.rtio_tsc, now64=True)
self.csr_devices.append("rtio")
self.submodules.rtio_dma = dma.DMA(self.ps7.s_axi_hp0)
self.csr_devices.append("rtio_dma")
self.submodules.cri_con = rtio.CRIInterconnectShared(
[self.rtio.cri, self.rtio_dma.cri],
[self.rtio_core.cri],
enable_routing=True,
)
self.csr_devices.append("cri_con")
self.submodules.rtio_moninj = rtio.MonInj(self.rtio_channels)
self.csr_devices.append("rtio_moninj")
self.submodules.rtio_analyzer = analyzer.Analyzer(
self.rtio_tsc, self.rtio_core.cri, self.ps7.s_axi_hp1
)
self.csr_devices.append("rtio_analyzer")
class BASE(EBAZ4205):
def __init__(self, rtio_clk, acpki, acpki_batch_size):
EBAZ4205.__init__(self, rtio_clk, acpki, acpki_batch_size)
VARIANTS = {cls.__name__.lower(): cls for cls in [BASE]}
def main():
parser = argparse.ArgumentParser(
description="ARTIQ port to the EBAZ4205 control card of Ebit E9+ BTC miner"
)
parser.add_argument(
"-r", default=None, help="build Rust interface into the specified file"
)
parser.add_argument(
"-m", default=None, help="build Rust memory interface into the specified file"
)
parser.add_argument(
"-c",
default=None,
help="build Rust compiler configuration into the specified file",
)
parser.add_argument(
"-g", default=None, help="build gateware into the specified directory"
)
parser.add_argument("--rtio-clk", default=125e6, help="RTIO Clock Frequency (Hz)")
parser.add_argument("--acpki-batch-size", default=10000, help="ACPKI batch buffer size")
parser.add_argument(
"-V",
"--variant",
default="base",
help="variant: " "[acpki_]base" "(default: %(default)s)",
)
args = parser.parse_args()
rtio_clk = int(args.rtio_clk)
variant = args.variant.lower()
acpki = variant.startswith("acpki_")
if acpki:
variant = variant[6:]
try:
cls = VARIANTS[variant]
except KeyError:
raise SystemExit("Invalid variant (-V/--variant)")
soc = cls(rtio_clk=rtio_clk, acpki=acpki, acpki_batch_size=args.acpki_batch_size)
soc.finalize()
if args.r is not None:
write_csr_file(soc, args.r)
if args.m is not None:
write_mem_file(soc, args.m)
if args.c is not None:
write_rustc_cfg_file(soc, args.c)
if args.g is not None:
soc.build(build_dir=args.g)
if __name__ == "__main__":
main()

View File

@@ -1,11 +1,9 @@
#!/usr/bin/env python
import argparse
from operator import itemgetter
from migen import *
from migen.build.generic_platform import *
from migen.genlib.resetsync import AsyncResetSynchronizer
from migen.genlib.cdc import MultiReg
from migen_axi.integration.soc_core import SoCCore
from migen_axi.platforms import kasli_soc
@@ -15,7 +13,7 @@ from misoc.cores import virtual_leds
from artiq.coredevice import jsondesc
from artiq.gateware import rtio, eem_7series
from artiq.gateware.rtio.xilinx_clocking import fix_serdes_timing_path
from artiq.gateware.rtio.phy import ttl_simple
from artiq.gateware.rtio.phy import ttl_simple, cxp_grabber
from artiq.gateware.drtio.transceiver import gtx_7series, eem_serdes
from artiq.gateware.drtio.siphaser import SiPhaser7Series
from artiq.gateware.drtio.rx_synchronizer import XilinxRXSynchronizer
@@ -24,10 +22,10 @@ from artiq.gateware.wrpll import wrpll
import dma
import analyzer
import acpki
import acpki as acpki_lib
import drtio_aux_controller
import zynq_clocking
from config import write_csr_file, write_mem_file, write_rustc_cfg_file
from config import generate_ident, write_csr_file, write_mem_file, write_rustc_cfg_file
eem_iostandard_dict = {
0: "LVDS_25",
@@ -44,6 +42,7 @@ eem_iostandard_dict = {
11: "LVDS",
}
DRTIO_EEM_PERIPHERALS = ["shuttler", "phaser_drtio"]
def eem_iostandard(eem):
return IOStandard(eem_iostandard_dict[eem])
@@ -105,9 +104,52 @@ class GTPBootstrapClock(Module):
raise ValueError("Bootstrap frequency must be 100 or 125MHz")
def add_coaxpress_sfp(cls, clk_freq, roi_engine_count, refclk=None):
if refclk is None:
refclk = Signal()
gt_refclk_pad = cls.platform.request("clk_gtp")
cls.platform.add_period_constraint(gt_refclk_pad.p, 8.0)
cls.specials += Instance("IBUFDS_GTE2",
i_CEB=0,
i_I=gt_refclk_pad.p,
i_IB=gt_refclk_pad.n,
o_O=refclk,
p_CLKCM_CFG="TRUE",
p_CLKRCV_TRST="TRUE",
p_CLKSWING_CFG=3
)
sfp_slot = 0
cls.submodules.cxp_grabber = cxp_grabber.CXPGrabber(
refclk=refclk,
gt_pads=[cls.platform.request("sfp", sfp_slot)],
sys_clk_freq=clk_freq,
roi_engine_count=roi_engine_count
)
cls.config["HAS_CXP_LED"] = None
mem_size = cls.cxp_grabber.core.get_mem_size()
# upper half is tx while lower half is rx
memory_address = cls.axi2csr.register_port(cls.cxp_grabber.core.get_tx_port(), mem_size)
cls.axi2csr.register_port(cls.cxp_grabber.core.get_rx_port(), mem_size)
cls.add_memory_region("cxp_mem", cls.mem_map["csr"] + memory_address, mem_size * 2)
cls.csr_devices.append("cxp_grabber")
print("CoaXPress-SFP (SFP{}) at RTIO channel 0x{:06x}".format(sfp_slot, len(cls.rtio_channels)))
cls.rtio_channels += [
rtio.Channel(cls.cxp_grabber.trigger),
rtio.Channel(cls.cxp_grabber.config),
rtio.Channel(cls.cxp_grabber.gate_data),
]
# max freq of cxp_gt_rx = linerate/internal_datawidth = 12.5Gbps/40 = 312.5MHz
rx = cls.cxp_grabber.phy.phys[0]
cls.platform.add_period_constraint(rx.gtx.cd_cxp_gt_rx.clk, 3.2)
# constraint the clk path
cls.platform.add_false_path_constraints(cls.sys_crg.cd_sys.clk, rx.gtx.cd_cxp_gt_rx.clk)
class GenericStandalone(SoCCore):
def __init__(self, description, acpki=False):
self.acpki = acpki
def __init__(self, description):
self.acpki = description["enable_acpki"]
clk_freq = description["rtio_frequency"]
with_wrpll = description["enable_wrpll"]
@@ -115,7 +157,7 @@ class GenericStandalone(SoCCore):
platform.toolchain.bitstream_commands.extend([
"set_property BITSTREAM.GENERAL.COMPRESS True [current_design]",
])
ident = description["variant"]
ident = generate_ident(description["variant"])
if self.acpki:
ident = "acpki_" + ident
SoCCore.__init__(self, platform=platform, csr_data_width=32, ident=ident, ps_cd_sys=False)
@@ -161,12 +203,20 @@ class GenericStandalone(SoCCore):
self.config["HAS_SI5324"] = None
self.config["SI5324_SOFT_RESET"] = None
self.rtio_channels = []
has_grabber = any(peripheral["type"] == "grabber" for peripheral in description["peripherals"])
if has_grabber:
self.grabber_csr_group = []
eem_7series.add_peripherals(self, description["peripherals"], iostandard=eem_iostandard)
has_grabber = False
eem_peripherals = []
for peripheral in description["peripherals"]:
if peripheral["type"] == "coaxpress_sfp":
add_coaxpress_sfp(self, clk_freq, peripheral["roi_engine_count"])
elif peripheral["type"] == "grabber":
has_grabber = True
self.grabber_csr_group = []
eem_peripherals.append(peripheral)
else:
eem_peripherals.append(peripheral)
eem_7series.add_peripherals(self, eem_peripherals, iostandard=eem_iostandard)
for i in (0, 1):
print("USER LED at RTIO channel 0x{:06x}".format(len(self.rtio_channels)))
user_led = self.platform.request("user_led", i)
@@ -184,10 +234,11 @@ class GenericStandalone(SoCCore):
if self.acpki:
self.config["KI_IMPL"] = "acp"
self.submodules.rtio = acpki.KernelInitiator(self.rtio_tsc,
bus=self.ps7.s_axi_acp,
user=self.ps7.s_axi_acp_user,
evento=self.ps7.event.o)
self.config["ACPKI_BUFFER_SIZE"] = int(description["acpki_buffer_size"])
self.submodules.rtio = acpki_lib.KernelInitiator(self.rtio_tsc,
bus=self.ps7.s_axi_acp,
user=self.ps7.s_axi_acp_user,
evento=self.ps7.event.o)
self.csr_devices.append("rtio")
else:
self.config["KI_IMPL"] = "csr"
@@ -218,29 +269,42 @@ class GenericStandalone(SoCCore):
class GenericMaster(SoCCore):
def __init__(self, description, acpki=False):
def __init__(self, description):
clk_freq = description["rtio_frequency"]
with_wrpll = description["enable_wrpll"]
has_drtio_over_eem = any(peripheral["type"] == "shuttler" for peripheral in description["peripherals"])
self.acpki = acpki
self.acpki = description["enable_acpki"]
platform = kasli_soc.Platform()
platform.toolchain.bitstream_commands.extend([
"set_property BITSTREAM.GENERAL.COMPRESS True [current_design]",
])
ident = description["variant"]
ident = generate_ident(description["variant"])
if self.acpki:
ident = "acpki_" + ident
SoCCore.__init__(self, platform=platform, csr_data_width=32, ident=ident, ps_cd_sys=False)
self.config["HW_REV"] = description["hw_rev"]
data_pads = [platform.request("sfp", i) for i in range(4)]
eem_peripherals = []
drtio_sfp_slots = list(range(4))
has_coaxpress_sfp, has_grabber = False, False
for peripheral in description["peripherals"]:
if peripheral["type"] == "coaxpress_sfp":
has_coaxpress_sfp = True
cxp_roi_counts = peripheral["roi_engine_count"]
# use sfp slot 0 for coaxpress_sfp
drtio_sfp_slots = list(range(1, 4))
elif peripheral["type"] == "grabber":
has_grabber = True
eem_peripherals.append(peripheral)
else:
eem_peripherals.append(peripheral)
self.submodules.gt_drtio = gtx_7series.GTX(
clock_pads=platform.request("clk_gtp"),
pads=data_pads,
pads=[self.platform.request("sfp", i) for i in drtio_sfp_slots],
clk_freq=clk_freq)
self.csr_devices.append("gt_drtio")
self.config["RTIO_FREQUENCY"] = str(clk_freq/1e6)
@@ -291,12 +355,13 @@ class GenericMaster(SoCCore):
self.config["SI5324_SOFT_RESET"] = None
self.rtio_channels = []
has_grabber = any(peripheral["type"] == "grabber" for peripheral in description["peripherals"])
if has_drtio_over_eem:
self.eem_drtio_channels = []
if has_grabber:
self.grabber_csr_group = []
eem_7series.add_peripherals(self, description["peripherals"], iostandard=eem_iostandard)
if has_coaxpress_sfp:
add_coaxpress_sfp(self, clk_freq, cxp_roi_counts, self.gt_drtio.refclk)
eem_7series.add_peripherals(self, eem_peripherals, iostandard=eem_iostandard)
for i in (0, 1):
print("USER LED at RTIO channel 0x{:06x}".format(len(self.rtio_channels)))
user_led = self.platform.request("user_led", i)
@@ -349,10 +414,11 @@ class GenericMaster(SoCCore):
if self.acpki:
self.config["KI_IMPL"] = "acp"
self.submodules.rtio = acpki.KernelInitiator(self.rtio_tsc,
bus=self.ps7.s_axi_acp,
user=self.ps7.s_axi_acp_user,
evento=self.ps7.event.o)
self.config["ACPKI_BUFFER_SIZE"] = int(description["acpki_buffer_size"])
self.submodules.rtio = acpki_lib.KernelInitiator(self.rtio_tsc,
bus=self.ps7.s_axi_acp,
user=self.ps7.s_axi_acp_user,
evento=self.ps7.event.o)
self.csr_devices.append("rtio")
else:
self.config["KI_IMPL"] = "csr"
@@ -387,7 +453,7 @@ class GenericMaster(SoCCore):
self.csr_devices.append("virtual_leds")
self.comb += [self.virtual_leds.get(i).eq(channel.rx_ready)
for i, channel in enumerate(self.gt_drtio.channels)]
for i, channel in zip(drtio_sfp_slots, self.gt_drtio.channels)]
def add_eem_drtio(self, eem_drtio_channels):
# Must be called before invoking add_rtio() to construct the CRI
@@ -428,28 +494,42 @@ class GenericMaster(SoCCore):
class GenericSatellite(SoCCore):
def __init__(self, description, acpki=False):
def __init__(self, description):
clk_freq = description["rtio_frequency"]
with_wrpll = description["enable_wrpll"]
self.acpki = acpki
has_drtio_over_eem = any(peripheral["type"] == "shuttler" for peripheral in description["peripherals"])
self.acpki = description["enable_acpki"]
platform = kasli_soc.Platform()
platform.toolchain.bitstream_commands.extend([
"set_property BITSTREAM.GENERAL.COMPRESS True [current_design]",
])
ident = description["variant"]
ident = generate_ident(description["variant"])
if self.acpki:
ident = "acpki_" + ident
SoCCore.__init__(self, platform=platform, csr_data_width=32, ident=ident, ps_cd_sys=False)
self.config["HW_REV"] = description["hw_rev"]
data_pads = [platform.request("sfp", i) for i in range(4)]
eem_peripherals = []
drtio_sfp_slots = list(range(4))
has_coaxpress_sfp, has_grabber = False, False
for peripheral in description["peripherals"]:
if peripheral["type"] == "coaxpress_sfp":
has_coaxpress_sfp = True
cxp_roi_counts = peripheral["roi_engine_count"]
# use sfp slot 0 for coaxpress_sfp
drtio_sfp_slots = list(range(1, 4))
elif peripheral["type"] == "grabber":
has_grabber = True
eem_peripherals.append(peripheral)
else:
eem_peripherals.append(peripheral)
self.submodules.gt_drtio = gtx_7series.GTX(
clock_pads=platform.request("clk_gtp"),
pads=data_pads,
pads=[platform.request("sfp", i) for i in drtio_sfp_slots],
clk_freq=clk_freq)
self.csr_devices.append("gt_drtio")
@@ -480,9 +560,13 @@ class GenericSatellite(SoCCore):
self.rtio_channels = []
has_grabber = any(peripheral["type"] == "grabber" for peripheral in description["peripherals"])
if has_drtio_over_eem:
self.eem_drtio_channels = []
if has_grabber:
self.grabber_csr_group = []
eem_7series.add_peripherals(self, description["peripherals"], iostandard=eem_iostandard)
if has_coaxpress_sfp:
add_coaxpress_sfp(self, clk_freq, cxp_roi_counts, self.gt_drtio.refclk)
eem_7series.add_peripherals(self, eem_peripherals, iostandard=eem_iostandard)
for i in (0, 1):
print("USER LED at RTIO channel 0x{:06x}".format(len(self.rtio_channels)))
user_led = self.platform.request("user_led", i)
@@ -494,15 +578,15 @@ class GenericSatellite(SoCCore):
self.submodules.rtio_tsc = rtio.TSC(glbl_fine_ts_width=3)
drtioaux_csr_group = []
drtioaux_memory_group = []
drtiorep_csr_group = []
self.drtioaux_csr_group = []
self.drtioaux_memory_group = []
self.drtiorep_csr_group = []
self.drtio_cri = []
for i in range(len(self.gt_drtio.channels)):
coreaux_name = "drtioaux" + str(i)
memory_name = "drtioaux" + str(i) + "_mem"
drtioaux_csr_group.append(coreaux_name)
drtioaux_memory_group.append(memory_name)
self.drtioaux_csr_group.append(coreaux_name)
self.drtioaux_memory_group.append(memory_name)
cdr = ClockDomainsRenamer({"rtio_rx": "rtio_rx" + str(i)})
@@ -515,7 +599,7 @@ class GenericSatellite(SoCCore):
self.csr_devices.append("drtiosat")
else:
corerep_name = "drtiorep" + str(i-1)
drtiorep_csr_group.append(corerep_name)
self.drtiorep_csr_group.append(corerep_name)
core = cdr(DRTIORepeater(
self.rtio_tsc, self.gt_drtio.channels[i]))
@@ -538,16 +622,17 @@ class GenericSatellite(SoCCore):
self.add_memory_region(memory_name, self.mem_map["csr"] + memory_address, mem_size * 2)
self.config["HAS_DRTIO"] = None
self.config["HAS_DRTIO_ROUTING"] = None
self.add_csr_group("drtioaux", drtioaux_csr_group)
self.add_memory_group("drtioaux_mem", drtioaux_memory_group)
self.add_csr_group("drtiorep", drtiorep_csr_group)
if has_drtio_over_eem:
self.add_eem_drtio(self.eem_drtio_channels)
self.add_drtio_cpuif_groups()
if self.acpki:
self.config["KI_IMPL"] = "acp"
self.submodules.rtio = acpki.KernelInitiator(self.rtio_tsc,
bus=self.ps7.s_axi_acp,
user=self.ps7.s_axi_acp_user,
evento=self.ps7.event.o)
self.config["ACPKI_BUFFER_SIZE"] = int(description["acpki_buffer_size"])
self.submodules.rtio = acpki_lib.KernelInitiator(self.rtio_tsc,
bus=self.ps7.s_axi_acp,
user=self.ps7.s_axi_acp_user,
evento=self.ps7.event.o)
self.csr_devices.append("rtio")
else:
self.config["KI_IMPL"] = "csr"
@@ -560,7 +645,10 @@ class GenericSatellite(SoCCore):
self.submodules.local_io = SyncRTIO(
self.rtio_tsc, self.rtio_channels, lane_count=description["sed_lanes"]
)
self.comb += self.drtiosat.async_errors.eq(self.local_io.async_errors)
self.comb += [
self.drtiosat.async_errors.eq(self.local_io.async_errors),
self.local_io.sed_spread_enable.eq(self.drtiosat.sed_spread_enable.storage)
]
self.submodules.cri_con = rtio.CRIInterconnectShared(
[self.drtiosat.cri, self.rtio_dma.cri, self.rtio.cri],
@@ -620,7 +708,51 @@ class GenericSatellite(SoCCore):
self.csr_devices.append("virtual_leds")
self.comb += [self.virtual_leds.get(i).eq(channel.rx_ready)
for i, channel in enumerate(self.gt_drtio.channels)]
for i, channel in zip(drtio_sfp_slots, self.gt_drtio.channels)]
def add_eem_drtio(self, eem_drtio_channels):
# Must be called before constructing CRIInterconnectShared
self.submodules.eem_transceiver = eem_serdes.EEMSerdes(self.platform, eem_drtio_channels)
self.csr_devices.append("eem_transceiver")
self.config["HAS_DRTIO_EEM"] = None
self.config["EEM_DRTIO_COUNT"] = len(eem_drtio_channels)
for i in range(len(self.eem_transceiver.channels)):
channel = i + len(self.gt_drtio.channels)
coreaux_name = "drtioaux" + str(channel)
memory_name = "drtioaux" + str(channel) + "_mem"
self.drtioaux_csr_group.append(coreaux_name)
self.drtioaux_memory_group.append(memory_name)
cdr = ClockDomainsRenamer({"rtio_rx": "sys"})
corerep_name = "drtiorep" + str(channel-1)
self.drtiorep_csr_group.append(corerep_name)
core = cdr(DRTIORepeater(
self.rtio_tsc, self.eem_transceiver.channels[i]))
setattr(self.submodules, corerep_name, core)
self.drtio_cri.append(core.cri)
self.csr_devices.append(corerep_name)
coreaux = cdr(drtio_aux_controller.DRTIOAuxControllerBare(core.link_layer))
setattr(self.submodules, coreaux_name, coreaux)
self.csr_devices.append(coreaux_name)
mem_size = coreaux.get_mem_size()
tx_port = coreaux.get_tx_port()
rx_port = coreaux.get_rx_port()
memory_address = self.axi2csr.register_port(tx_port, mem_size)
# rcv in upper half of the memory, thus added second
self.axi2csr.register_port(rx_port, mem_size)
# and registered in PS interface
# manually, because software refers to rx/tx by halves of entire memory block, not names
self.add_memory_region(memory_name, self.mem_map["csr"] + memory_address, mem_size * 2)
def add_drtio_cpuif_groups(self):
self.add_csr_group("drtiorep", self.drtiorep_csr_group)
self.add_csr_group("drtioaux", self.drtioaux_csr_group)
self.add_memory_group("drtioaux_mem", self.drtioaux_memory_group)
def main():
parser = argparse.ArgumentParser(
@@ -633,8 +765,6 @@ def main():
help="build Rust memory interface into the specified file")
parser.add_argument("-g", default=None,
help="build gateware into the specified directory")
parser.add_argument("--acpki", default=False, action="store_true",
help="enable ACPKI")
parser.add_argument("description", metavar="DESCRIPTION",
help="JSON system description file")
args = parser.parse_args()
@@ -652,7 +782,11 @@ def main():
else:
raise ValueError("Invalid DRTIO role")
soc = cls(description, acpki=args.acpki)
for peripheral in description["peripherals"]:
if peripheral["type"] in DRTIO_EEM_PERIPHERALS and description["drtio_role"] == "standalone":
raise ValueError("{} requires DRTIO, please switch role to master or satellite".format(peripheral["type"]))
soc = cls(description)
soc.finalize()
if args.r is not None:

View File

@@ -13,7 +13,7 @@ from misoc.interconnect.csr import *
from misoc.cores import gpio
from artiq.gateware import rtio, nist_clock, nist_qc2
from artiq.gateware.rtio.phy import ttl_simple, ttl_serdes_7series, dds, spi2, edge_counter
from artiq.gateware.rtio.phy import ttl_simple, ttl_serdes_7series, dds, spi2, edge_counter, cxp_grabber
from artiq.gateware.rtio.xilinx_clocking import fix_serdes_timing_path
from artiq.gateware.drtio.transceiver import gtx_7series
from artiq.gateware.drtio.siphaser import SiPhaser7Series
@@ -25,7 +25,8 @@ import analyzer
import acpki
import drtio_aux_controller
import zynq_clocking
from config import write_csr_file, write_mem_file, write_rustc_cfg_file
import cxp_4r_fmc
from config import generate_ident, write_csr_file, write_mem_file, write_rustc_cfg_file
class SMAClkinForward(Module):
def __init__(self, platform):
@@ -124,13 +125,13 @@ def prepare_zc706_platform(platform):
])
class ZC706(SoCCore):
def __init__(self, acpki=False):
def __init__(self, acpki=False, acpki_batch_size=1e5):
self.acpki = acpki
platform = zc706.Platform()
prepare_zc706_platform(platform)
ident = self.__class__.__name__
ident = generate_ident(self.__class__.__name__)
if self.acpki:
ident = "acpki_" + ident
SoCCore.__init__(self, platform=platform, csr_data_width=32, ident=ident, ps_cd_sys=False)
@@ -138,7 +139,7 @@ class ZC706(SoCCore):
platform.add_extension(si5324_fmc33)
self.comb += platform.request("si5324_33").rst_n.eq(1)
cdr_clk = Signal()
self.cdr_clk = Signal()
cdr_clk_buf = Signal()
si5324_out = platform.request("si5324_clkout")
platform.add_period_constraint(si5324_out.p, 8.0)
@@ -146,15 +147,16 @@ class ZC706(SoCCore):
Instance("IBUFDS_GTE2",
i_CEB=0,
i_I=si5324_out.p, i_IB=si5324_out.n,
o_O=cdr_clk,
o_O=self.cdr_clk,
p_CLKCM_CFG="TRUE",
p_CLKRCV_TRST="TRUE",
p_CLKSWING_CFG=3),
Instance("BUFG", i_I=cdr_clk, o_O=cdr_clk_buf)
Instance("BUFG", i_I=self.cdr_clk, o_O=cdr_clk_buf)
]
self.config["HAS_SI5324"] = None
self.config["SI5324_AS_SYNTHESIZER"] = None
self.config["SI5324_SOFT_RESET"] = None
self.config["ACPKI_BATCH_SIZE"] = int(acpki_batch_size)
self.submodules.bootstrap = CLK200BootstrapClock(platform)
self.submodules.sys_crg = zynq_clocking.SYSCRG(self.platform, self.ps7, cdr_clk_buf)
@@ -196,14 +198,14 @@ class ZC706(SoCCore):
class _MasterBase(SoCCore):
def __init__(self, acpki=False, drtio100mhz=False):
def __init__(self, acpki=False, drtio100mhz=False, acpki_batch_size=1e5):
self.acpki = acpki
clk_freq = 100e6 if drtio100mhz else 125e6
platform = zc706.Platform()
prepare_zc706_platform(platform)
ident = self.__class__.__name__
ident = generate_ident(self.__class__.__name__)
if self.acpki:
ident = "acpki_" + ident
SoCCore.__init__(self, platform=platform, csr_data_width=32, ident=ident, ps_cd_sys=False)
@@ -287,6 +289,8 @@ class _MasterBase(SoCCore):
self.config["HAS_SI5324"] = None
self.config["SI5324_AS_SYNTHESIZER"] = None
self.config["ACPKI_BATCH_SIZE"] = int(acpki_batch_size)
# Constrain TX & RX timing for the first transceiver channel
# (First channel acts as master for phase alignment for all channels' TX)
platform.add_false_path_constraints(
@@ -337,14 +341,14 @@ class _MasterBase(SoCCore):
class _SatelliteBase(SoCCore):
def __init__(self, acpki=False, drtio100mhz=False):
def __init__(self, acpki=False, drtio100mhz=False, acpki_batch_size=1e5):
self.acpki = acpki
clk_freq = 100e6 if drtio100mhz else 125e6
platform = zc706.Platform()
prepare_zc706_platform(platform)
ident = self.__class__.__name__
ident = generate_ident(self.__class__.__name__)
if self.acpki:
ident = "acpki_" + ident
SoCCore.__init__(self, platform=platform, csr_data_width=32, ident=ident, ps_cd_sys=False)
@@ -440,6 +444,7 @@ class _SatelliteBase(SoCCore):
self.add_memory_group("drtioaux_mem", drtioaux_memory_group)
self.config["RTIO_FREQUENCY"] = str(self.gt_drtio.rtio_clk_freq/1e6)
self.config["ACPKI_BATCH_SIZE"] = int(acpki_batch_size)
# Si5324 Phaser
self.submodules.siphaser = SiPhaser7Series(
@@ -487,6 +492,10 @@ class _SatelliteBase(SoCCore):
self.csr_devices.append("rtio_dma")
self.submodules.local_io = SyncRTIO(self.rtio_tsc, rtio_channels)
self.comb += [
self.drtiosat.async_errors.eq(self.local_io.async_errors),
self.local_io.sed_spread_enable.eq(self.drtiosat.sed_spread_enable.storage)
]
self.submodules.cri_con = rtio.CRIInterconnectShared(
[self.drtiosat.cri, self.rtio_dma.cri, self.rtio.cri],
[self.local_io.cri] + self.drtio_cri,
@@ -648,40 +657,95 @@ class _NIST_QC2_RTIO:
self.add_rtio(rtio_channels)
class _CXP_4R_FMC_RTIO():
"""
CoaXpress host FMC card
"""
def __init__(self):
platform = self.platform
platform.add_extension(cxp_4r_fmc.fmc_adapter_io)
platform.add_extension(leds_fmc33)
rtio_channels = []
clk_freq = 125e6
self.submodules.cxp_grabber = cxp_grabber.CXPGrabber(
refclk=self.cdr_clk,
non_gt_tx_pads=[platform.request("CXP_LS", 0)],
gt_pads=[platform.request("CXP_HS", 0)],
sys_clk_freq=clk_freq,
)
mem_size = self.cxp_grabber.core.get_mem_size()
# upper half is tx while lower half is rx
memory_address = self.axi2csr.register_port(self.cxp_grabber.core.get_tx_port(), mem_size)
self.axi2csr.register_port(self.cxp_grabber.core.get_rx_port(), mem_size)
self.add_memory_region("cxp_mem", self.mem_map["csr"] + memory_address, mem_size * 2)
self.csr_devices.append("cxp_grabber")
print("CoaXPress at RTIO channel 0x{:06x}".format(len(rtio_channels)))
rtio_channels += [
rtio.Channel(self.cxp_grabber.trigger),
rtio.Channel(self.cxp_grabber.config),
rtio.Channel(self.cxp_grabber.gate_data),
]
# max freq of cxp_gt_rx = linerate/internal_datawidth = 12.5Gbps/40 = 312.5MHz
# zc706 use speed grade 2 which only support up to 10.3125Gbps (~4ns)
# pushing to 12.5Gbps (3.2ns) will result in Pulse width violation but setup/hold times will still meet
rx = self.cxp_grabber.phy_rx.phys[0]
platform.add_period_constraint(rx.gtx.cd_cxp_gt_rx.clk, 3.2)
# constraint the clk path
platform.add_false_path_constraints(self.sys_crg.cd_sys.clk, rx.gtx.cd_cxp_gt_rx.clk)
# Add a user LED for rtio moninj
print("USER LED at RTIO channel 0x{:06x}".format(len(rtio_channels)))
phy = ttl_simple.Output(self.platform.request("user_led_33", 0))
self.submodules += phy
rtio_channels.append(rtio.Channel.from_phy(phy))
self.config["HAS_RTIO_LOG"] = None
rtio_channels.append(rtio.LogChannel())
self.config["RTIO_LOG_CHANNEL"] = len(rtio_channels)
self.add_rtio(rtio_channels)
class NIST_CLOCK(ZC706, _NIST_CLOCK_RTIO):
def __init__(self, acpki, drtio100mhz):
ZC706.__init__(self, acpki)
def __init__(self, acpki, drtio100mhz, acpki_batch_size):
ZC706.__init__(self, acpki, acpki_batch_size)
self.submodules += SMAClkinForward(self.platform)
_NIST_CLOCK_RTIO.__init__(self)
class NIST_CLOCK_Master(_MasterBase, _NIST_CLOCK_RTIO):
def __init__(self, acpki, drtio100mhz):
_MasterBase.__init__(self, acpki, drtio100mhz)
def __init__(self, acpki, drtio100mhz, acpki_batch_size):
_MasterBase.__init__(self, acpki, drtio100mhz, acpki_batch_size)
_NIST_CLOCK_RTIO.__init__(self)
class NIST_CLOCK_Satellite(_SatelliteBase, _NIST_CLOCK_RTIO):
def __init__(self, acpki, drtio100mhz):
_SatelliteBase.__init__(self, acpki, drtio100mhz)
def __init__(self, acpki, drtio100mhz, acpki_batch_size):
_SatelliteBase.__init__(self, acpki, drtio100mhz, acpki_batch_size)
_NIST_CLOCK_RTIO.__init__(self)
class NIST_QC2(ZC706, _NIST_QC2_RTIO):
def __init__(self, acpki, drtio100mhz):
ZC706.__init__(self, acpki)
def __init__(self, acpki, drtio100mhz, acpki_batch_size):
ZC706.__init__(self, acpki, acpki_batch_size)
self.submodules += SMAClkinForward(self.platform)
_NIST_QC2_RTIO.__init__(self)
class NIST_QC2_Master(_MasterBase, _NIST_QC2_RTIO):
def __init__(self, acpki, drtio100mhz):
_MasterBase.__init__(self, acpki, drtio100mhz)
def __init__(self, acpki, drtio100mhz, acpki_batch_size):
_MasterBase.__init__(self, acpki, drtio100mhz, acpki_batch_size)
_NIST_QC2_RTIO.__init__(self)
class NIST_QC2_Satellite(_SatelliteBase, _NIST_QC2_RTIO):
def __init__(self, acpki, drtio100mhz):
_SatelliteBase.__init__(self, acpki, drtio100mhz)
def __init__(self, acpki, drtio100mhz, acpki_batch_size):
_SatelliteBase.__init__(self, acpki, drtio100mhz, acpki_batch_size)
_NIST_QC2_RTIO.__init__(self)
class CXP_4R_FMC(ZC706, _CXP_4R_FMC_RTIO):
def __init__(self, acpki, drtio100mhz, acpki_batch_size):
ZC706.__init__(self, acpki, acpki_batch_size)
_CXP_4R_FMC_RTIO.__init__(self)
VARIANTS = {cls.__name__.lower(): cls for cls in [NIST_CLOCK, NIST_CLOCK_Master, NIST_CLOCK_Satellite,
NIST_QC2, NIST_QC2_Master, NIST_QC2_Satellite]}
NIST_QC2, NIST_QC2_Master, NIST_QC2_Satellite, CXP_4R_FMC]}
def main():
parser = argparse.ArgumentParser(
@@ -698,6 +762,7 @@ def main():
help="variant: "
"[acpki_]nist_clock/nist_qc2[_master/_satellite][_100mhz]"
"(default: %(default)s)")
parser.add_argument("--acpki-batch-size", default=10000, help="ACPKI batch buffer size")
args = parser.parse_args()
variant = args.variant.lower()
@@ -712,7 +777,7 @@ def main():
except KeyError:
raise SystemExit("Invalid variant (-V/--variant)")
soc = cls(acpki=acpki, drtio100mhz=drtio100mhz)
soc = cls(acpki=acpki, drtio100mhz=drtio100mhz, acpki_batch_size=args.acpki_batch_size)
soc.finalize()
if args.r is not None:

View File

@@ -10,6 +10,7 @@ name = "libboard_artiq"
[features]
target_zc706 = ["libboard_zynq/target_zc706", "libconfig/target_zc706"]
target_kasli_soc = ["libboard_zynq/target_kasli_soc", "libconfig/target_kasli_soc"]
target_ebaz4205 = ["libboard_zynq/target_ebaz4205", "libconfig/target_ebaz4205"]
calibrate_wrpll_skew = []
[build-dependencies]
@@ -19,14 +20,14 @@ build_zynq = { path = "../libbuild_zynq" }
log = "0.4"
log_buffer = { version = "1.2" }
crc = { version = "1.7", default-features = false }
core_io = { version = "0.1", features = ["collections"] }
core_io = { git = "https://git.m-labs.hk/M-Labs/rs-core_io.git", rev = "e9d3edf027", features = ["collections"] }
embedded-hal = "0.2"
nb = "1.0"
void = { version = "1", default-features = false }
byteorder = { version = "1.3", default-features = false }
io = { path = "../libio", features = ["byteorder"] }
libboard_zynq = { path = "@@ZYNQ_RS@@/libboard_zynq" }
libsupport_zynq = { path = "@@ZYNQ_RS@@/libsupport_zynq", default-features = false, features = ["alloc_core"] }
libboard_zynq = { path = "@@ZYNQ_RS@@/libboard_zynq", features = ["async"] }
libregister = { path = "@@ZYNQ_RS@@/libregister" }
libconfig = { path = "@@ZYNQ_RS@@/libconfig", features = ["fat_lfn"] }
libcortex_a9 = { path = "@@ZYNQ_RS@@/libcortex_a9" }

View File

@@ -0,0 +1,312 @@
use core::fmt;
use libasync::task;
use libboard_zynq::timer;
use log::debug;
use crate::{cxp_ctrl::Error as CtrlErr,
cxp_packet::{async_read_u32, async_read_u64, async_write_u32, async_write_u64, reset_tag,
send_test_packet, write_bytes_no_ack},
cxp_phys::{CXPSpeed, rx, tx},
pl::csr};
// Bootstrap registers address
const STANDARD: u32 = 0x0000;
const REVISION: u32 = 0x0004;
const CONNECTION_RESET: u32 = 0x4000;
const DEVICE_CONNECTION_ID: u32 = 0x4004;
const MASTER_HOST_CONNECTION_ID: u32 = 0x4008;
const STREAM_PACKET_SIZE_MAX: u32 = 0x4010;
const CONNECTION_CFG: u32 = 0x4014;
const CONNECTION_CFG_DEFAULT: u32 = 0x4018;
const TESTMODE: u32 = 0x401C;
const TEST_ERROR_COUNT_SELECTOR: u32 = 0x4020;
const TEST_ERROR_COUNT: u32 = 0x4024;
const TEST_PACKET_COUNT_TX: u32 = 0x4028;
const TEST_PACKET_COUNT_RX: u32 = 0x4030;
const VERSION_SUPPORTED: u32 = 0x4044;
const VERSION_USED: u32 = 0x4048;
// Setup const
const CHANNEL_LEN: u8 = 1;
const HOST_CONNECTION_ID: u32 = 0x00006303; // TODO: rename to CXP grabber sinara number when it comes out
// The MAX_STREAM_PAK_SIZE should be set as large as possible - Section 9.5.2 (CXP-001-2021)
// Since the ROI pipeline just consume all pixel data without buffering, any big number will do.
const MAX_STREAM_PAK_SIZE: u32 = 16384; // 16 KiB
const TX_TEST_CNT: u8 = 10;
// From DS191 (v1.18.1), max CDR time lock is 37*10^6 UI,
// 37*10^6 UI at lowest CXP linerate of 1.25Gbps = 29.6 ms, double it to account for overhead
const MONITOR_TIMEOUT_MS: u64 = 60;
pub enum Error {
CameraNotDetected,
ConnectionLost,
UnstableRX,
UnstableTX,
UnsupportedSpeed(u32),
UnsupportedTopology,
UnsupportedVersion,
CtrlPacketError(CtrlErr),
}
impl From<CtrlErr> for Error {
fn from(value: CtrlErr) -> Error {
Error::CtrlPacketError(value)
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&Error::CameraNotDetected => write!(f, "CameraNotDetected"),
&Error::ConnectionLost => write!(f, "ConnectionLost - Channel #0 cannot be detected"),
&Error::UnstableRX => write!(f, "UnstableRX - RX connection test failed"),
&Error::UnstableTX => write!(f, "UnstableTX - TX connection test failed"),
&Error::UnsupportedSpeed(linerate_code) => write!(
f,
"UnsupportedSpeed - {:#X} linerate code is not supported",
linerate_code
),
&Error::UnsupportedTopology => {
write!(
f,
"UnsupportedTopology - Channel #0 should be connected to the master channel"
)
}
&Error::UnsupportedVersion => write!(
f,
"UnsupportedVersion - Cannot find a compatible protocol version between the cxp grabber & camera"
),
&Error::CtrlPacketError(ref err) => write!(f, "{}", err),
}
}
}
pub fn master_channel_ready() -> bool {
unsafe { csr::cxp_grabber::core_rx_ready_read() == 1 }
}
async fn monitor_channel_status_timeout() -> Result<(), Error> {
let limit = timer::get_ms() + MONITOR_TIMEOUT_MS;
while timer::get_ms() < limit {
task::r#yield().await;
if master_channel_ready() {
return Ok(());
}
}
Err(Error::ConnectionLost)
}
pub async fn discover_camera() -> Result<(), Error> {
// Section 7.6 (CXP-001-2021)
// 1.25Gbps (CXP_1) and 3.125Gbps (CXP_3) are the discovery rate
// both linerate need to be checked as camera only support ONE of discovery rates
for speed in [CXPSpeed::CXP1, CXPSpeed::CXP3].iter() {
// Section 12.1.2 (CXP-001-2021)
// set tx linerate -> send ConnectionReset -> wait 200ms -> set rx linerate -> monitor connection status with a timeout
tx::change_linerate(*speed);
write_bytes_no_ack(CONNECTION_RESET, &1_u32.to_be_bytes(), false)?;
timer::async_delay_ms(200).await;
rx::change_linerate(*speed);
// Check the camera is responsive in case the RX phy picks up noise as an IDLE word
if monitor_channel_status_timeout().await.is_ok() {
if let Ok(0xC0A79AE5) = async_read_u32(STANDARD, false).await {
debug!("camera detected at linerate {:}", speed);
return Ok(());
}
}
}
Err(Error::CameraNotDetected)
}
async fn check_master_channel() -> Result<(), Error> {
if async_read_u32(DEVICE_CONNECTION_ID, false).await? == 0 {
Ok(())
} else {
Err(Error::UnsupportedTopology)
}
}
async fn disable_excess_channels() -> Result<(), Error> {
let current_cfg = async_read_u32(CONNECTION_CFG, false).await?;
let active_camera_chs = current_cfg >> 16;
// After camera receive ConnectionReset, only the master connection should be active while
// the extension connections shall not be active - Section 12.3.33 (CXP-001-2021)
// In case some camera didn't follow the spec properly (e.g. Basler boA2448-250cm),
// the grabber need to manually disable the excess channels
if active_camera_chs > CHANNEL_LEN as u32 {
debug!(
"only {} channel(s) is available on cxp grabber, disabling excess channels on camera",
CHANNEL_LEN
);
// disable excess channels and preserve the discovery linerate
async_write_u32(CONNECTION_CFG, current_cfg & 0xFFFF | (CHANNEL_LEN as u32) << 16, false).await?;
// check if the master channel is down after the cfg change
monitor_channel_status_timeout().await
} else {
Ok(())
}
}
async fn set_host_connection_id() -> Result<(), Error> {
debug!("set host connection id to = {:#X}", HOST_CONNECTION_ID);
async_write_u32(MASTER_HOST_CONNECTION_ID, HOST_CONNECTION_ID, false).await?;
Ok(())
}
async fn negotiate_cxp_version() -> Result<bool, Error> {
let rev = async_read_u32(REVISION, false).await?;
let mut major_rev: u32 = rev >> 16;
let mut minor_rev: u32 = rev & 0xFF;
debug!("camera's CoaXPress revision is {}.{}", major_rev, minor_rev);
// Section 12.1.4 (CXP-001-2021)
// For CXP 2.0 and onward, Host need to check the VersionSupported register to determine
// the highest common version that supported by both device & host
if major_rev >= 2 {
let reg = async_read_u32(VERSION_SUPPORTED, false).await?;
// grabber support CXP 2.1, 2.0 and 1.1 only
if ((reg >> 3) & 1) == 1 {
major_rev = 2;
minor_rev = 1;
} else if ((reg >> 2) & 1) == 1 {
major_rev = 2;
minor_rev = 0;
} else if ((reg >> 1) & 1) == 1 {
major_rev = 1;
minor_rev = 1;
} else {
return Err(Error::UnsupportedVersion);
}
async_write_u32(VERSION_USED, major_rev << 16 | minor_rev, false).await?;
}
debug!(
"both camera and cxp grabber support CoaXPress {}.{}, switch to CoaXPress {}.{} protocol now",
major_rev, minor_rev, major_rev, minor_rev
);
Ok(major_rev >= 2)
}
async fn negotiate_pak_max_size(with_tag: bool) -> Result<(), Error> {
async_write_u32(STREAM_PACKET_SIZE_MAX, MAX_STREAM_PAK_SIZE, with_tag).await?;
Ok(())
}
fn decode_cxp_speed(linerate_code: u32) -> Option<CXPSpeed> {
match linerate_code {
0x28 => Some(CXPSpeed::CXP1),
0x30 => Some(CXPSpeed::CXP2),
0x38 => Some(CXPSpeed::CXP3),
0x40 => Some(CXPSpeed::CXP5),
0x48 => Some(CXPSpeed::CXP6),
0x50 => Some(CXPSpeed::CXP10),
0x58 => Some(CXPSpeed::CXP12),
_ => None,
}
}
async fn set_operation_linerate(with_tag: bool) -> Result<(), Error> {
let recommended_linerate_code = async_read_u32(CONNECTION_CFG_DEFAULT, with_tag).await? & 0xFFFF;
if let Some(speed) = decode_cxp_speed(recommended_linerate_code) {
debug!("changing linerate to {}", speed);
// preserve the number of active channels
let current_cfg = async_read_u32(CONNECTION_CFG, with_tag).await?;
async_write_u32(
CONNECTION_CFG,
current_cfg & 0xFFFF0000 | recommended_linerate_code,
with_tag,
)
.await?;
tx::change_linerate(speed);
rx::change_linerate(speed);
monitor_channel_status_timeout().await
} else {
Err(Error::UnsupportedSpeed(recommended_linerate_code))
}
}
async fn test_counter_reset(with_tag: bool) -> Result<(), Error> {
unsafe { csr::cxp_grabber::core_rx_test_counts_reset_write(1) };
async_write_u32(TEST_ERROR_COUNT_SELECTOR, 0, with_tag).await?;
async_write_u32(TEST_ERROR_COUNT, 0, with_tag).await?;
async_write_u64(TEST_PACKET_COUNT_TX, 0, with_tag).await?;
async_write_u64(TEST_PACKET_COUNT_RX, 0, with_tag).await?;
Ok(())
}
async fn verify_test_result(with_tag: bool) -> Result<(), Error> {
async_write_u32(TEST_ERROR_COUNT_SELECTOR, 0, with_tag).await?;
// Section 9.9.3 (CXP-001-2021)
// verify grabber -> camera connection test result
if async_read_u64(TEST_PACKET_COUNT_RX, with_tag).await? != TX_TEST_CNT as u64 {
return Err(Error::UnstableTX);
};
if async_read_u32(TEST_ERROR_COUNT, with_tag).await? > 0 {
return Err(Error::UnstableTX);
};
// Section 9.9.4 (CXP-001-2021)
// verify camera -> grabber connection test result
let camera_test_pak_cnt = async_read_u64(TEST_PACKET_COUNT_TX, true).await?;
unsafe {
if csr::cxp_grabber::core_rx_test_packet_counter_read() != camera_test_pak_cnt as u16 {
return Err(Error::UnstableRX);
};
if csr::cxp_grabber::core_rx_test_error_counter_read() > 0 {
return Err(Error::UnstableRX);
};
};
debug!("channel #0 passed connection test");
Ok(())
}
async fn test_channel_stability(with_tag: bool) -> Result<(), Error> {
test_counter_reset(with_tag).await?;
// cxp grabber -> camera connection test
for _ in 0..TX_TEST_CNT {
send_test_packet()?;
// sending the whole test sequence @ 20.833Mbps will take a minimum of 1.972ms
// and leave some room to send IDLE word
timer::async_delay_ms(2).await;
}
// camera -> grabber connection test
// enabling the TESTMODE on master channel will send test packets on all channels
async_write_u32(TESTMODE, 1, with_tag).await?;
timer::async_delay_ms(2000).await;
async_write_u32(TESTMODE, 0, with_tag).await?;
verify_test_result(with_tag).await?;
Ok(())
}
pub async fn camera_setup() -> Result<bool, Error> {
reset_tag();
check_master_channel().await?;
disable_excess_channels().await?;
set_host_connection_id().await?;
let with_tag = negotiate_cxp_version().await?;
negotiate_pak_max_size(with_tag).await?;
set_operation_linerate(with_tag).await?;
test_channel_stability(with_tag).await?;
Ok(with_tag)
}

View File

@@ -0,0 +1,250 @@
use core::fmt;
use byteorder::{ByteOrder, NetworkEndian};
use core_io::{Error as IoError, Read, Write};
use crc::crc32::checksum_ieee;
use io::{Cursor, ProtoRead, ProtoWrite};
pub const CTRL_PACKET_MAXSIZE: usize = 128; // for compatibility with version1.x compliant Devices - Section 12.1.6 (CXP-001-2021)
pub const DATA_MAXSIZE: usize =
CTRL_PACKET_MAXSIZE - /*packet start KCodes, data packet types, CMD, Tag, Addr, CRC, packet end KCode*/4*7;
pub enum Error {
CorruptedPacket,
CtrlAckError(u8),
Io(IoError),
LengthOutOfRange(u32),
TagMismatch,
TimedOut,
UnexpectedReply,
UnknownPacket(u8),
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&Error::CorruptedPacket => write!(f, "CorruptedPacket - Received packet fail CRC test"),
&Error::CtrlAckError(ref ack_code) => match ack_code {
0x40 => write!(f, "CtrlAckError - Invalid Address"),
0x41 => write!(f, "CtrlAckError - Invalid data for the address"),
0x42 => write!(f, "CtrlAckError - Invalid operation code"),
0x43 => write!(f, "CtrlAckError - Write attempted to a read-only address"),
0x44 => write!(f, "CtrlAckError - Read attempted from a write-only address"),
0x45 => write!(f, "CtrlAckError - Size field too large, exceed packet size limit"),
0x46 => write!(f, "CtrlAckError - Message size is inconsistent with size field"),
0x47 => write!(f, "CtrlAckError - Malformed packet"),
0x80 => write!(f, "CtrlAckError - Failed CRC test in last received command"),
_ => write!(f, "CtrlAckError - Unknown ack code {:#X}", ack_code),
},
&Error::Io(ref err) => write!(f, "IoError - {:?}", err),
&Error::LengthOutOfRange(length) => write!(
f,
"LengthOutOfRange - Message length {} is not between 1 and {}",
length, DATA_MAXSIZE
),
&Error::TagMismatch => write!(f, "TagMismatch - Received tag is different from the transmitted tag"),
&Error::TimedOut => write!(f, "MessageTimedOut"),
&Error::UnexpectedReply => write!(f, "UnexpectedReply"),
&Error::UnknownPacket(packet_type) => {
write!(f, "UnknownPacket - Unknown packet type id {:#X} ", packet_type)
}
}
}
}
impl From<IoError> for Error {
fn from(value: IoError) -> Error {
Error::Io(value)
}
}
fn get_cxp_crc(bytes: &[u8]) -> u32 {
// Section 9.2.2.2 (CXP-001-2021)
// Only Control packet need CRC32 appended in the end of the packet
// CoaXpress use the polynomial of IEEE-802.3 (Ethernet) CRC but the checksum calculation is different
(!checksum_ieee(bytes)).swap_bytes()
}
trait CxpRead: Read {
fn read_exact_4x(&mut self, buf: &mut [u8]) -> Result<(), Error> {
let mut temp = [0u8; 4];
for byte in buf {
// Section 9.2.2.1 (CXP-001-2021)
// decoder should immune to single bit errors when handling 4x duplicated characters
self.read_exact(&mut temp)?;
let [a, b, c, d] = temp;
// vote and return majority
*byte = a & b & c | a & b & d | a & c & d | b & c & d;
}
Ok(())
}
fn read_4x_u8(&mut self) -> Result<u8, Error> {
let mut bytes = [0; 1];
self.read_exact_4x(&mut bytes)?;
Ok(bytes[0])
}
}
impl<T: Read> CxpRead for T {}
impl<T: Write> CxpWrite for T {}
#[derive(Debug)]
pub enum RXCTRLPacket {
CtrlReply {
tag: Option<u8>,
length: u32,
data: [u8; DATA_MAXSIZE],
},
CtrlDelay {
tag: Option<u8>,
time: u32,
},
CtrlAck {
tag: Option<u8>,
},
}
impl RXCTRLPacket {
pub fn read_from(reader: &mut Cursor<&[u8]>) -> Result<Self, Error> {
match reader.read_4x_u8()? {
0x03 => RXCTRLPacket::get_ctrl_packet(reader, false),
0x06 => RXCTRLPacket::get_ctrl_packet(reader, true),
ty => Err(Error::UnknownPacket(ty)),
}
}
fn get_ctrl_packet(reader: &mut Cursor<&[u8]>, with_tag: bool) -> Result<Self, Error> {
let mut tag: Option<u8> = None;
if with_tag {
tag = Some(reader.read_4x_u8()?);
}
let ackcode = reader.read_4x_u8()?;
match ackcode {
0x00 | 0x04 => {
let length = reader.read_u32::<NetworkEndian>()?;
let mut data: [u8; DATA_MAXSIZE] = [0; DATA_MAXSIZE];
reader.read(&mut data[0..length as usize])?;
// Section 9.6.3 (CXP-001-2021)
// when length is not multiple of 4, dummy bits are padded to align to the word boundary
// set position to next word boundary for CRC calculation
let padding = (4 - (reader.position() % 4)) % 4;
reader.set_position(reader.position() + padding);
// Section 9.6.3 (CXP-001-2021)
// only bytes after the first 4 are used in calculating the checksum
let checksum = get_cxp_crc(&reader.get_ref()[4..reader.position()]);
if reader.read_u32::<NetworkEndian>()? != checksum {
return Err(Error::CorruptedPacket);
}
if ackcode == 0x00 {
return Ok(RXCTRLPacket::CtrlReply { tag, length, data });
} else {
return Ok(RXCTRLPacket::CtrlDelay {
tag,
time: NetworkEndian::read_u32(&data[..4]),
});
}
}
0x01 => return Ok(RXCTRLPacket::CtrlAck { tag }),
_ => return Err(Error::CtrlAckError(ackcode)),
}
}
}
trait CxpWrite: Write {
fn write_all_4x(&mut self, buf: &[u8]) -> Result<(), Error> {
for byte in buf {
self.write_all(&[*byte; 4])?;
}
Ok(())
}
fn write_4x_u8(&mut self, value: u8) -> Result<(), Error> {
self.write_all_4x(&[value])
}
}
#[derive(Debug)]
pub enum TXCTRLPacket {
CtrlRead {
tag: Option<u8>,
addr: u32,
length: u32,
},
CtrlWrite {
tag: Option<u8>,
addr: u32,
length: u32,
data: [u8; DATA_MAXSIZE],
},
}
impl TXCTRLPacket {
pub fn write_to(&self, writer: &mut Cursor<&mut [u8]>) -> Result<(), Error> {
match *self {
TXCTRLPacket::CtrlRead { tag, addr, length } => {
match tag {
Some(t) => {
writer.write_4x_u8(0x05)?;
writer.write_4x_u8(t)?;
}
None => {
writer.write_4x_u8(0x02)?;
}
}
let mut bytes = [0; 3];
NetworkEndian::write_u24(&mut bytes, length);
writer.write_all(&[0x00, bytes[0], bytes[1], bytes[2]])?;
writer.write_u32::<NetworkEndian>(addr)?;
// Section 9.6.2 (CXP-001-2021)
// only bytes after the first 4 are used in calculating the checksum
let checksum = get_cxp_crc(&writer.get_ref()[4..writer.position()]);
writer.write_u32::<NetworkEndian>(checksum)?;
}
TXCTRLPacket::CtrlWrite {
tag,
addr,
length,
data,
} => {
match tag {
Some(t) => {
writer.write_4x_u8(0x05)?;
writer.write_4x_u8(t)?;
}
None => {
writer.write_4x_u8(0x02)?;
}
}
let mut bytes = [0; 3];
NetworkEndian::write_u24(&mut bytes, length);
writer.write_all(&[0x01, bytes[0], bytes[1], bytes[2]])?;
writer.write_u32::<NetworkEndian>(addr)?;
writer.write_all(&data[0..length as usize])?;
// Section 9.6.2 (CXP-001-2021)
// when length is not multiple of 4, dummy bites are padded to align to the word boundary
let padding = (4 - (writer.position() % 4)) % 4;
for _ in 0..padding {
writer.write_u8(0)?;
}
// Section 9.6.2 (CXP-001-2021)
// only bytes after the first 4 are used in calculating the checksum
let checksum = get_cxp_crc(&writer.get_ref()[4..writer.position()]);
writer.write_u32::<NetworkEndian>(checksum)?;
}
}
Ok(())
}
}

View File

@@ -0,0 +1,134 @@
use libboard_zynq::{i2c, timer};
use libcortex_a9::mutex::Mutex;
use log::{error, info};
#[cfg(has_cxp_led)]
use crate::cxp_led::{LEDState, update_led};
use crate::{cxp_camera_setup::{camera_setup, discover_camera, master_channel_ready},
pl::csr};
#[derive(Clone, Copy, Debug, PartialEq)]
enum State {
Connected,
Detected,
Disconnected,
}
// Mutex as they are needed by core1 cxp api calls
static STATE: Mutex<State> = Mutex::new(State::Disconnected);
static WITH_TAG: Mutex<bool> = Mutex::new(false);
pub fn camera_connected() -> bool {
*STATE.lock() == State::Connected
}
pub fn with_tag() -> bool {
*WITH_TAG.lock()
}
pub async fn async_camera_connected() -> bool {
*STATE.async_lock().await == State::Connected
}
pub async fn async_with_tag() -> bool {
*WITH_TAG.async_lock().await
}
pub async fn thread(i2c: &mut i2c::I2c) {
loop {
tick(i2c).await;
timer::async_delay_ms(200).await;
}
}
async fn tick(_i2c: &mut i2c::I2c) {
// Get the value and drop the mutexguard to prevent blocking other async task that need to use it
let current_state = { *STATE.async_lock().await };
let next_state = match current_state {
State::Disconnected => {
#[cfg(has_cxp_led)]
update_led(_i2c, LEDState::RedFlash1Hz);
match discover_camera().await {
Ok(_) => {
info!("camera detected, setting up camera...");
State::Detected
}
Err(_) => State::Disconnected,
}
}
State::Detected => {
#[cfg(has_cxp_led)]
update_led(_i2c, LEDState::OrangeFlash12Hz5);
match camera_setup().await {
Ok(with_tag) => {
info!("camera setup complete");
*WITH_TAG.async_lock().await = with_tag;
State::Connected
}
Err(e) => {
error!("camera setup failure: {}", e);
*WITH_TAG.async_lock().await = false;
State::Disconnected
}
}
}
State::Connected => {
#[cfg(has_cxp_led)]
update_led(_i2c, LEDState::GreenSolid);
if master_channel_ready() {
unsafe {
if csr::cxp_grabber::stream_decoder_crc_error_read() == 1 {
error!("frame packet has CRC error");
csr::cxp_grabber::stream_decoder_crc_error_write(1);
};
if csr::cxp_grabber::stream_decoder_stream_type_error_read() == 1 {
error!("Non CoaXPress stream type detected, the CXP grabber doesn't support GenDC stream type");
csr::cxp_grabber::stream_decoder_stream_type_error_write(1);
};
if csr::cxp_grabber::core_rx_trigger_ack_read() == 1 {
info!("received CXP linktrigger ack");
csr::cxp_grabber::core_rx_trigger_ack_write(1);
};
if csr::cxp_grabber::stream_decoder_new_frame_read() == 1 {
let width = csr::cxp_grabber::stream_decoder_x_size_read();
let height = csr::cxp_grabber::stream_decoder_y_size_read();
match csr::cxp_grabber::stream_decoder_pixel_format_code_read() {
0x0101 => info!("received frame: {}x{} with MONO8 format", width, height),
0x0102 => info!("received frame: {}x{} with MONO10 format", width, height),
0x0103 => info!("received frame: {}x{} with MONO12 format", width, height),
0x0104 => info!("received frame: {}x{} with MONO14 format", width, height),
0x0105 => info!("received frame: {}x{} with MONO16 format", width, height),
_ => info!("received frame: {}x{} with Unsupported pixel format", width, height),
};
csr::cxp_grabber::stream_decoder_new_frame_write(1);
};
}
State::Connected
} else {
*WITH_TAG.async_lock().await = false;
info!("camera disconnected");
State::Disconnected
}
}
};
{
*STATE.async_lock().await = next_state
};
}
pub fn roi_viewer_setup(x0: u16, y0: u16, x1: u16, y1: u16) {
unsafe {
// flush the fifo before arming
while csr::cxp_grabber::roi_viewer_fifo_stb_read() == 1 {
csr::cxp_grabber::roi_viewer_fifo_ack_write(1);
}
csr::cxp_grabber::roi_viewer_x0_write(x0);
csr::cxp_grabber::roi_viewer_x1_write(x1);
csr::cxp_grabber::roi_viewer_y0_write(y0);
csr::cxp_grabber::roi_viewer_y1_write(y1);
csr::cxp_grabber::roi_viewer_arm_write(1);
}
}

View File

@@ -0,0 +1,84 @@
use libboard_zynq::i2c;
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum LEDState {
Off,
RedFlash1Hz, // Not connected
OrangeFlash12Hz5, // camera setup
GreenSolid, // Connected
}
const SFP_SLOT: u8 = 0;
static mut PREVIOUS_STATE: LEDState = LEDState::Off;
const PCA9530_ADDR: u8 = 0x60;
const PSC0_ADDR: u8 = 0x01;
const PWM0_ADDR: u8 = 0x02;
const LS0_ADDR: u8 = 0x05;
pub fn update_led(i2c: &mut i2c::I2c, state: LEDState) {
if unsafe { state != PREVIOUS_STATE } {
match write_settings(i2c, state) {
Ok(_) => unsafe { PREVIOUS_STATE = state },
Err(_) => {
// stop i2c in case error happen during read/write operation
let _ = i2c.stop();
}
};
}
}
fn write_settings(i2c: &mut i2c::I2c, state: LEDState) -> Result<(), i2c::Error> {
i2c.pca954x_select(0x70, None)?;
i2c.pca954x_select(0x71, Some(SFP_SLOT))?;
write_pwm_freq(i2c, state)?;
write_pwm_duty(i2c, state)?;
write_pwm_output(i2c, state)?;
Ok(())
}
fn write_pwm_freq(i2c: &mut i2c::I2c, state: LEDState) -> Result<(), i2c::Error> {
match state {
LEDState::OrangeFlash12Hz5 => {
i2c_write(i2c, PSC0_ADDR, 0xB)?; // set PWM0 frequency to 12.5 Hz
}
LEDState::RedFlash1Hz => {
i2c_write(i2c, PSC0_ADDR, 0x97)?; // set PWM0 frequency to 1 Hz
}
_ => {}
};
Ok(())
}
fn write_pwm_duty(i2c: &mut i2c::I2c, state: LEDState) -> Result<(), i2c::Error> {
match state {
LEDState::OrangeFlash12Hz5 => {
i2c_write(i2c, PWM0_ADDR, 0x40)?; // set PWM0 duty cycle to 25%
}
LEDState::RedFlash1Hz => {
i2c_write(i2c, PWM0_ADDR, 0x33)?; // set PWM0 duty cycle to 20%
}
_ => {}
};
Ok(())
}
fn write_pwm_output(i2c: &mut i2c::I2c, state: LEDState) -> Result<(), i2c::Error> {
let reg = match state {
LEDState::GreenSolid => 0xF1, // Green: always on, Red: off
LEDState::Off => 0xF0, // Green: off, Red: off
LEDState::OrangeFlash12Hz5 => 0xFA, // Green: use PWM0, Red: use PWM0
LEDState::RedFlash1Hz => 0xF8, // Green: off, Red: use PWM0
};
i2c_write(i2c, LS0_ADDR, reg)?;
Ok(())
}
fn i2c_write(i2c: &mut i2c::I2c, reg_addr: u8, val: u8) -> Result<(), i2c::Error> {
i2c.start()?;
i2c.write(PCA9530_ADDR << 1)?;
i2c.write(reg_addr)?;
i2c.write(val)?;
i2c.stop()?;
Ok(())
}

View File

@@ -0,0 +1,275 @@
use core::slice;
use byteorder::{ByteOrder, NetworkEndian};
use io::Cursor;
use libasync::task;
use libboard_zynq::timer;
use crate::{cxp_ctrl::{CTRL_PACKET_MAXSIZE, DATA_MAXSIZE, Error, RXCTRLPacket, TXCTRLPacket},
mem::mem,
pl::csr};
const TRANSMISSION_TIMEOUT: u64 = 200;
// Section 9.6.1.2 (CXP-001-2021)
// CTRL packet need to be tagged for CXP 2.0 or greater
static mut TAG: u8 = 0;
pub fn reset_tag() {
unsafe { TAG = 0 };
}
fn increment_tag() {
unsafe { TAG = TAG.wrapping_add(1) };
}
fn check_tag(tag: Option<u8>) -> Result<(), Error> {
unsafe {
if tag.is_some() && tag != Some(TAG) {
Err(Error::TagMismatch)
} else {
Ok(())
}
}
}
fn receive_ctrl_packet() -> Result<Option<RXCTRLPacket>, Error> {
if unsafe { csr::cxp_grabber::core_rx_pending_packet_read() == 1 } {
unsafe {
let read_buffer_ptr = csr::cxp_grabber::core_rx_read_ptr_read() as usize;
let ptr = (mem::CXP_MEM_BASE + mem::CXP_MEM_SIZE / 2 + read_buffer_ptr * CTRL_PACKET_MAXSIZE) as *mut u32;
let mut reader = Cursor::new(slice::from_raw_parts(ptr as *const u8, CTRL_PACKET_MAXSIZE));
let packet = RXCTRLPacket::read_from(&mut reader);
csr::cxp_grabber::core_rx_pending_packet_write(1);
Ok(Some(packet?))
}
} else {
Ok(None)
}
}
fn receive_ctrl_packet_timeout(timeout_ms: u64) -> Result<RXCTRLPacket, Error> {
// assume timer was initialized successfully
let limit = timer::get_ms() + timeout_ms;
while timer::get_ms() < limit {
match receive_ctrl_packet()? {
None => (),
Some(packet) => return Ok(packet),
}
}
Err(Error::TimedOut)
}
async fn async_receive_ctrl_packet_timeout(timeout_ms: u64) -> Result<RXCTRLPacket, Error> {
// assume timer was initialized successfully
let limit = timer::get_ms() + timeout_ms;
while timer::get_ms() < limit {
match receive_ctrl_packet()? {
None => (),
Some(packet) => return Ok(packet),
}
task::r#yield().await;
}
Err(Error::TimedOut)
}
fn send_ctrl_packet(packet: &TXCTRLPacket) -> Result<(), Error> {
unsafe {
while csr::cxp_grabber::core_tx_writer_busy_read() == 1 {}
let ptr = mem::CXP_MEM_BASE as *mut u32;
let mut writer = Cursor::new(slice::from_raw_parts_mut(ptr as *mut u8, CTRL_PACKET_MAXSIZE));
packet.write_to(&mut writer)?;
csr::cxp_grabber::core_tx_writer_word_len_write((writer.position() / 4) as u8);
csr::cxp_grabber::core_tx_writer_stb_write(1);
}
Ok(())
}
pub fn send_test_packet() -> Result<(), Error> {
unsafe {
while csr::cxp_grabber::core_tx_writer_busy_read() == 1 {}
csr::cxp_grabber::core_tx_writer_stb_testseq_write(1);
}
Ok(())
}
fn get_ctrl_ack(packet: RXCTRLPacket, timeout_ms: &mut u64) -> Result<bool, Error> {
match packet {
RXCTRLPacket::CtrlDelay { tag, time } => {
check_tag(tag)?;
*timeout_ms = time.into();
Ok(false)
}
RXCTRLPacket::CtrlAck { tag } => {
check_tag(tag)?;
Ok(true)
}
_ => Err(Error::UnexpectedReply),
}
}
fn get_ctrl_reply(
packet: RXCTRLPacket,
timeout_ms: &mut u64,
expected_length: u32,
) -> Result<Option<[u8; DATA_MAXSIZE]>, Error> {
match packet {
RXCTRLPacket::CtrlDelay { tag, time } => {
check_tag(tag)?;
*timeout_ms = time.into();
Ok(None)
}
RXCTRLPacket::CtrlReply {
tag,
length: replied_length,
data,
} => {
check_tag(tag)?;
if replied_length != expected_length {
return Err(Error::UnexpectedReply);
};
Ok(Some(data))
}
_ => Err(Error::UnexpectedReply),
}
}
fn check_length(length: u32) -> Result<(), Error> {
if length > DATA_MAXSIZE as u32 || length == 0 {
Err(Error::LengthOutOfRange(length))
} else {
Ok(())
}
}
pub fn write_bytes_no_ack(addr: u32, val: &[u8], with_tag: bool) -> Result<(), Error> {
let length = val.len() as u32;
check_length(length)?;
let mut data: [u8; DATA_MAXSIZE] = [0; DATA_MAXSIZE];
data[..length as usize].clone_from_slice(val);
let tag: Option<u8> = if with_tag { Some(unsafe { TAG }) } else { None };
send_ctrl_packet(&TXCTRLPacket::CtrlWrite {
tag,
addr,
length,
data,
})
}
fn write_bytes(addr: u32, val: &[u8], with_tag: bool) -> Result<(), Error> {
write_bytes_no_ack(addr, val, with_tag)?;
let mut timeout_ms = TRANSMISSION_TIMEOUT;
loop {
let packet = receive_ctrl_packet_timeout(timeout_ms)?;
if get_ctrl_ack(packet, &mut timeout_ms)? {
break;
}
}
if with_tag {
increment_tag();
};
Ok(())
}
pub fn write_u32(addr: u32, val: u32, with_tag: bool) -> Result<(), Error> {
write_bytes(addr, &val.to_be_bytes(), with_tag)
}
async fn async_write_bytes(addr: u32, val: &[u8], with_tag: bool) -> Result<(), Error> {
write_bytes_no_ack(addr, val, with_tag)?;
let mut timeout_ms = TRANSMISSION_TIMEOUT;
loop {
let packet = async_receive_ctrl_packet_timeout(timeout_ms).await?;
if get_ctrl_ack(packet, &mut timeout_ms)? {
break;
}
}
if with_tag {
increment_tag();
};
Ok(())
}
pub async fn async_write_u32(addr: u32, val: u32, with_tag: bool) -> Result<(), Error> {
async_write_bytes(addr, &val.to_be_bytes(), with_tag).await
}
pub async fn async_write_u64(addr: u32, val: u64, with_tag: bool) -> Result<(), Error> {
async_write_bytes(addr, &val.to_be_bytes(), with_tag).await
}
pub fn read_bytes(addr: u32, bytes: &mut [u8], with_tag: bool) -> Result<(), Error> {
let length = bytes.len() as u32;
check_length(length)?;
let tag: Option<u8> = if with_tag { Some(unsafe { TAG }) } else { None };
send_ctrl_packet(&TXCTRLPacket::CtrlRead { tag, addr, length })?;
let mut timeout_ms = TRANSMISSION_TIMEOUT;
loop {
let packet = receive_ctrl_packet_timeout(timeout_ms)?;
if let Some(data) = get_ctrl_reply(packet, &mut timeout_ms, length)? {
bytes.copy_from_slice(&data[..length as usize]);
break;
}
}
if with_tag {
increment_tag();
};
Ok(())
}
pub fn read_u32(addr: u32, with_tag: bool) -> Result<u32, Error> {
let mut bytes: [u8; 4] = [0; 4];
read_bytes(addr, &mut bytes, with_tag)?;
let val = NetworkEndian::read_u32(&bytes);
Ok(val)
}
pub async fn async_read_bytes(addr: u32, bytes: &mut [u8], with_tag: bool) -> Result<(), Error> {
let length = bytes.len() as u32;
check_length(length)?;
let tag: Option<u8> = if with_tag { Some(unsafe { TAG }) } else { None };
send_ctrl_packet(&TXCTRLPacket::CtrlRead { tag, addr, length })?;
let mut timeout_ms = TRANSMISSION_TIMEOUT;
loop {
let packet = async_receive_ctrl_packet_timeout(timeout_ms).await?;
if let Some(data) = get_ctrl_reply(packet, &mut timeout_ms, length)? {
bytes.copy_from_slice(&data[..length as usize]);
break;
}
}
if with_tag {
increment_tag();
};
Ok(())
}
pub async fn async_read_u32(addr: u32, with_tag: bool) -> Result<u32, Error> {
let mut bytes: [u8; 4] = [0; 4];
async_read_bytes(addr, &mut bytes, with_tag).await?;
let val = NetworkEndian::read_u32(&bytes);
Ok(val)
}
pub async fn async_read_u64(addr: u32, with_tag: bool) -> Result<u64, Error> {
let mut bytes: [u8; 8] = [0; 8];
async_read_bytes(addr, &mut bytes, with_tag).await?;
let val = NetworkEndian::read_u64(&bytes);
Ok(val)
}

View File

@@ -0,0 +1,203 @@
use core::fmt;
use crate::pl::csr;
#[derive(Clone, Copy)]
pub enum CXPSpeed {
CXP1,
CXP2,
CXP3,
CXP5,
CXP6,
CXP10,
CXP12,
}
impl fmt::Display for CXPSpeed {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&CXPSpeed::CXP1 => write!(f, "1.25 Gbps"),
&CXPSpeed::CXP2 => write!(f, "2.5 Gbps"),
&CXPSpeed::CXP3 => write!(f, "3.125 Gbps"),
&CXPSpeed::CXP5 => write!(f, "5 Gbps"),
&CXPSpeed::CXP6 => write!(f, "6.25 Gbps"),
&CXPSpeed::CXP10 => write!(f, "10 Gbps"),
&CXPSpeed::CXP12 => write!(f, "12.5 Gbps"),
}
}
}
pub fn setup() {
let init_speed = CXPSpeed::CXP1;
tx::setup();
tx::change_linerate(init_speed);
rx::setup();
rx::change_linerate(init_speed);
}
pub mod tx {
use super::*;
pub fn setup() {
unsafe {
csr::cxp_grabber::phy_tx_enable_write(1);
}
}
pub fn change_linerate(speed: CXPSpeed) {
unsafe {
match speed {
CXPSpeed::CXP1 | CXPSpeed::CXP2 | CXPSpeed::CXP3 | CXPSpeed::CXP5 | CXPSpeed::CXP6 => {
csr::cxp_grabber::phy_tx_bitrate2x_enable_write(0);
}
CXPSpeed::CXP10 | CXPSpeed::CXP12 => {
csr::cxp_grabber::phy_tx_bitrate2x_enable_write(1);
}
};
csr::cxp_grabber::phy_tx_clk_reset_write(1);
}
}
}
pub mod rx {
use super::*;
pub fn setup() {
unsafe {
csr::cxp_grabber::phy_rx_gtx_refclk_stable_write(1);
}
}
pub fn change_linerate(speed: CXPSpeed) {
change_qpll_fb_divider(speed);
change_gtx_divider(speed);
change_cdr_cfg(speed);
change_eq_cfg(speed);
unsafe {
csr::cxp_grabber::phy_rx_qpll_reset_write(1);
while csr::cxp_grabber::phy_rx_qpll_locked_read() != 1 {}
// Changing RXOUT_DIV via DRP requires a manual reset
// https://adaptivesupport.amd.com/s/question/0D52E00006hplwnSAA/re-gtx-line-rate-change
csr::cxp_grabber::phy_rx_gtx_restart_write(1);
}
}
fn change_qpll_fb_divider(speed: CXPSpeed) {
let qpll_div_reg = match speed {
CXPSpeed::CXP1 | CXPSpeed::CXP2 | CXPSpeed::CXP5 | CXPSpeed::CXP10 => 0x0120, // FB_Divider = 80, QPLL VCO @ 10GHz
CXPSpeed::CXP3 | CXPSpeed::CXP6 | CXPSpeed::CXP12 => 0x0170, // FB_Divider = 100, QPLL VCO @ 12.5GHz
};
qpll_write(0x36, qpll_div_reg);
}
fn change_gtx_divider(speed: CXPSpeed) {
let div_reg = match speed {
CXPSpeed::CXP1 => 0x03, // TXOUT_DIV = 1, RXOUT_DIV = 8
CXPSpeed::CXP2 | CXPSpeed::CXP3 => 0x02, // TXOUT_DIV = 1, RXOUT_DIV = 4
CXPSpeed::CXP5 | CXPSpeed::CXP6 => 0x01, // TXOUT_DIV = 1, RXOUT_DIV = 2
CXPSpeed::CXP10 | CXPSpeed::CXP12 => 0x00, // TXOUT_DIV = 1, RXOUT_DIV = 1
};
gtx_write(0x88, div_reg);
}
fn change_cdr_cfg(speed: CXPSpeed) {
struct CdrConfig {
pub cfg_reg0: u16, // addr = 0xA8
pub cfg_reg1: u16, // addr = 0xA9
pub cfg_reg2: u16, // addr = 0xAA
pub cfg_reg3: u16, // addr = 0xAB
pub cfg_reg4: u16, // addr = 0xAC
}
let cdr_cfg = match speed {
// when RXOUT_DIV = 8
CXPSpeed::CXP1 => CdrConfig {
cfg_reg0: 0x0020,
cfg_reg1: 0x1008,
cfg_reg2: 0x23FF,
cfg_reg3: 0x0000,
cfg_reg4: 0x0003,
},
// when RXOUT_DIV = 4
CXPSpeed::CXP2 | CXPSpeed::CXP5 => CdrConfig {
cfg_reg0: 0x0020,
cfg_reg1: 0x1010,
cfg_reg2: 0x23FF,
cfg_reg3: 0x0000,
cfg_reg4: 0x0003,
},
// when RXOUT_DIV= 2
CXPSpeed::CXP3 | CXPSpeed::CXP6 => CdrConfig {
cfg_reg0: 0x0020,
cfg_reg1: 0x1020,
cfg_reg2: 0x23FF,
cfg_reg3: 0x0000,
cfg_reg4: 0x0003,
},
// when RXOUT_DIV= 1
CXPSpeed::CXP10 | CXPSpeed::CXP12 => CdrConfig {
cfg_reg0: 0x0020,
cfg_reg1: 0x1040,
cfg_reg2: 0x23FF,
cfg_reg3: 0x0000,
cfg_reg4: 0x000B,
},
};
gtx_write(0x0A8, cdr_cfg.cfg_reg0);
gtx_write(0x0A9, cdr_cfg.cfg_reg1);
gtx_write(0x0AA, cdr_cfg.cfg_reg2);
gtx_write(0x0AB, cdr_cfg.cfg_reg3);
gtx_write(0x0AC, cdr_cfg.cfg_reg4);
}
fn change_eq_cfg(speed: CXPSpeed) {
let eq_cfg = match speed {
CXPSpeed::CXP1 | CXPSpeed::CXP2 | CXPSpeed::CXP3 | CXPSpeed::CXP5 | CXPSpeed::CXP6 => 0x0904,
CXPSpeed::CXP10 | CXPSpeed::CXP12 => 0x0104,
};
gtx_write(0x029, eq_cfg);
}
#[allow(dead_code)]
fn gtx_read(address: u16) -> u16 {
unsafe {
csr::cxp_grabber::phy_rx_gtx_daddr_write(address);
csr::cxp_grabber::phy_rx_gtx_dread_write(1);
while csr::cxp_grabber::phy_rx_gtx_dready_read() != 1 {}
csr::cxp_grabber::phy_rx_gtx_dout_read()
}
}
fn gtx_write(address: u16, value: u16) {
unsafe {
csr::cxp_grabber::phy_rx_gtx_daddr_write(address);
csr::cxp_grabber::phy_rx_gtx_din_write(value);
csr::cxp_grabber::phy_rx_gtx_din_stb_write(1);
while csr::cxp_grabber::phy_rx_gtx_dready_read() != 1 {}
}
}
#[allow(dead_code)]
fn qpll_read(address: u8) -> u16 {
unsafe {
csr::cxp_grabber::phy_rx_qpll_daddr_write(address);
csr::cxp_grabber::phy_rx_qpll_dread_write(1);
while csr::cxp_grabber::phy_rx_qpll_dready_read() != 1 {}
csr::cxp_grabber::phy_rx_qpll_dout_read()
}
}
fn qpll_write(address: u8, value: u16) {
unsafe {
csr::cxp_grabber::phy_rx_qpll_daddr_write(address);
csr::cxp_grabber::phy_rx_qpll_din_write(value);
csr::cxp_grabber::phy_rx_qpll_din_stb_write(1);
while csr::cxp_grabber::phy_rx_qpll_dready_read() != 1 {}
}
}
}

View File

@@ -1,7 +1,7 @@
use embedded_hal::prelude::_embedded_hal_blocking_delay_DelayUs;
use libboard_zynq::timer::GlobalTimer;
use libconfig::Config;
use libsupport_zynq::alloc::format;
use alloc::format;
use libboard_zynq::timer;
use libconfig;
use log::{debug, error, info};
use crate::pl;
@@ -27,23 +27,23 @@ fn select_lane(lane_no: u8) {
}
}
fn apply_delay(tap: u8, timer: &mut GlobalTimer) {
fn apply_delay(tap: u8) {
unsafe {
pl::csr::eem_transceiver::dly_cnt_in_write(tap);
pl::csr::eem_transceiver::dly_ld_write(1);
timer.delay_us(1);
timer::delay_us(1);
assert!(tap as u8 == pl::csr::eem_transceiver::dly_cnt_out_read());
}
}
fn apply_config(config: &SerdesConfig, timer: &mut GlobalTimer) {
fn apply_config(config: &SerdesConfig) {
for lane_no in 0..4 {
select_lane(lane_no as u8);
apply_delay(config.delay[lane_no], timer);
apply_delay(config.delay[lane_no]);
}
}
unsafe fn assign_delay(timer: &mut GlobalTimer) -> SerdesConfig {
unsafe fn assign_delay() -> SerdesConfig {
// Select an appropriate delay for lane 0
select_lane(0);
@@ -54,8 +54,8 @@ unsafe fn assign_delay(timer: &mut GlobalTimer) -> SerdesConfig {
loop {
let mut prev = None;
for curr_dly in 0..32 {
//let read_align = read_align_fn(curr_dly, timer);
let curr_low_rate = read_align(curr_dly, timer);
//let read_align = read_align_fn(curr_dly);
let curr_low_rate = read_align(curr_dly);
if let Some(prev_low_rate) = prev {
// This is potentially a crossover position
@@ -86,7 +86,7 @@ unsafe fn assign_delay(timer: &mut GlobalTimer) -> SerdesConfig {
if best_dly.is_none() {
error!("setup/hold timing calibration failed, retry in 1s...");
timer.delay_us(1_000_000);
timer::delay_us(1_000_000);
} else {
break;
}
@@ -94,7 +94,7 @@ unsafe fn assign_delay(timer: &mut GlobalTimer) -> SerdesConfig {
let best_dly = best_dly.unwrap();
apply_delay(best_dly, timer);
apply_delay(best_dly);
let mut delay_list = [best_dly; 4];
// Assign delay for other lanes
@@ -105,7 +105,7 @@ unsafe fn assign_delay(timer: &mut GlobalTimer) -> SerdesConfig {
let mut min_idx = 0;
for dly_delta in -3..=3 {
let index = (best_dly as isize + dly_delta) as u8;
let low_rate = read_align(index, timer);
let low_rate = read_align(index);
// abs() from f32 is not available in core library
let deviation = if low_rate < 0.5 { 0.5 - low_rate } else { low_rate - 0.5 };
@@ -115,7 +115,7 @@ unsafe fn assign_delay(timer: &mut GlobalTimer) -> SerdesConfig {
}
}
apply_delay(min_idx, timer);
apply_delay(min_idx);
delay_list[lane_no] = min_idx;
}
@@ -124,13 +124,13 @@ unsafe fn assign_delay(timer: &mut GlobalTimer) -> SerdesConfig {
SerdesConfig { delay: delay_list }
}
fn read_align(dly: u8, timer: &mut GlobalTimer) -> f32 {
fn read_align(dly: u8) -> f32 {
unsafe {
apply_delay(dly, timer);
apply_delay(dly);
pl::csr::eem_transceiver::counter_reset_write(1);
pl::csr::eem_transceiver::counter_enable_write(1);
timer.delay_us(2000);
timer::delay_us(2000);
pl::csr::eem_transceiver::counter_enable_write(0);
let (high, low) = (
@@ -145,7 +145,7 @@ fn read_align(dly: u8, timer: &mut GlobalTimer) -> f32 {
}
}
unsafe fn align_comma(timer: &mut GlobalTimer) {
unsafe fn align_comma() {
loop {
for slip in 1..=10 {
// The soft transceiver has 2 8b10b decoders, which receives lane
@@ -169,10 +169,10 @@ unsafe fn align_comma(timer: &mut GlobalTimer) {
// timing is met.
pl::csr::eem_transceiver::bitslip_write(1);
pl::csr::eem_transceiver::bitslip_write(1);
timer.delay_us(1);
timer::delay_us(1);
pl::csr::eem_transceiver::comma_align_reset_write(1);
timer.delay_us(100);
timer::delay_us(100);
if pl::csr::eem_transceiver::comma_read() == 1 {
debug!("comma alignment completed after {} bitslips", slip);
@@ -181,11 +181,29 @@ unsafe fn align_comma(timer: &mut GlobalTimer) {
}
error!("comma alignment failed, retrying in 1s...");
timer.delay_us(1_000_000);
timer::delay_us(1_000_000);
}
}
pub fn init(timer: &mut GlobalTimer, cfg: &Config) {
pub unsafe fn align_wordslip(trx_no: u8) -> bool {
pl::csr::eem_transceiver::transceiver_sel_write(trx_no);
for slip in 0..=1 {
pl::csr::eem_transceiver::wordslip_write(slip as u8);
timer::delay_us(1);
pl::csr::eem_transceiver::comma_align_reset_write(1);
timer::delay_us(100);
if pl::csr::eem_transceiver::comma_read() == 1 {
debug!("comma alignment completed with {} wordslip", slip);
return true;
}
}
false
}
pub fn init() {
for trx_no in 0..pl::csr::CONFIG_EEM_DRTIO_COUNT {
unsafe {
pl::csr::eem_transceiver::transceiver_sel_write(trx_no as u8);
@@ -193,19 +211,19 @@ pub fn init(timer: &mut GlobalTimer, cfg: &Config) {
let key = format!("eem_drtio_delay{}", trx_no);
let cfg_read = cfg.read(&key);
let cfg_read = libconfig::read(&key);
match cfg_read {
Ok(record) => {
info!("loading calibrated timing values from sd card");
unsafe {
apply_config(&*(record.as_ptr() as *const SerdesConfig), timer);
apply_config(&*(record.as_ptr() as *const SerdesConfig));
}
}
Err(_) => {
info!("calibrating...");
let config = unsafe { assign_delay(timer) };
let config = unsafe { assign_delay() };
match cfg.write(&key, config.as_bytes().to_vec()) {
match libconfig::write(&key, config.as_bytes().to_vec()) {
Ok(()) => {
info!("storing calibration timing values into sd card");
}
@@ -221,8 +239,7 @@ pub fn init(timer: &mut GlobalTimer, cfg: &Config) {
}
unsafe {
align_comma(timer);
pl::csr::eem_transceiver::rx_ready_write(1);
align_comma();
}
}
}

View File

@@ -1,6 +1,6 @@
use core::fmt;
use libconfig::Config;
use libconfig;
use log::{info, warn};
#[cfg(has_drtio_routing)]
@@ -56,9 +56,9 @@ impl fmt::Display for RoutingTable {
}
}
pub fn config_routing_table(default_n_links: usize, cfg: &Config) -> RoutingTable {
pub fn config_routing_table(default_n_links: usize) -> RoutingTable {
let mut ret = RoutingTable::default_master(default_n_links);
if let Ok(data) = cfg.read("routing_table") {
if let Ok(data) = libconfig::read("routing_table") {
if data.len() == DEST_COUNT * MAX_HOPS {
for i in 0..DEST_COUNT {
for j in 0..MAX_HOPS {

View File

@@ -1,12 +1,12 @@
use core::slice;
use core::{arch::asm, slice};
use byteorder::NativeEndian;
use core_io::{Error as IoError, ErrorKind as IoErrorKind};
use crc;
use io::{proto::{ProtoRead, ProtoWrite},
Cursor};
use libboard_zynq::{time::Milliseconds, timer::GlobalTimer};
use io::{Cursor,
proto::{ProtoRead, ProtoWrite}};
use libboard_zynq::timer;
pub use crate::drtioaux_proto::Packet;
pub use crate::drtioaux_proto::{MAX_PACKET, Packet};
use crate::{drtioaux_proto::Error as ProtocolError, mem::mem::DRTIOAUX_MEM, pl::csr::DRTIOAUX};
#[derive(Debug)]
@@ -35,6 +35,16 @@ impl From<IoError> for Error {
}
}
pub fn copy_work_buffer(src: *mut u32, dst: *mut u32, len: isize) {
// fix for artiq-zynq#344
unsafe {
for i in 0..(len / 4) {
asm!("", options(preserves_flags, nostack, readonly));
*dst.offset(i) = *src.offset(i);
}
}
}
pub fn reset(linkno: u8) {
let linkno = linkno as usize;
unsafe {
@@ -90,17 +100,17 @@ pub fn recv(linkno: u8) -> Result<Option<Packet>, Error> {
let checksum_at = reader.position() + padding;
let checksum = crc::crc32::checksum_ieee(&reader.get_ref()[0..checksum_at]);
reader.set_position(checksum_at);
if reader.read_u32()? != checksum {
if reader.read_u32::<NativeEndian>()? != checksum {
return Err(Error::CorruptedPacket);
}
Ok(packet)
})
}
pub fn recv_timeout(linkno: u8, timeout_ms: Option<u64>, timer: GlobalTimer) -> Result<Packet, Error> {
let timeout_ms = Milliseconds(timeout_ms.unwrap_or(10));
let limit = timer.get_time() + timeout_ms;
while timer.get_time() < limit {
pub fn recv_timeout(linkno: u8, timeout_ms: Option<u64>) -> Result<Packet, Error> {
let timeout_ms = timeout_ms.unwrap_or(10);
let limit = timer::get_ms() + timeout_ms;
while timer::get_ms() < limit {
match recv(linkno)? {
None => (),
Some(packet) => return Ok(packet),
@@ -115,7 +125,9 @@ where F: FnOnce(&mut [u8]) -> Result<usize, Error> {
unsafe {
while (DRTIOAUX[linkno].aux_tx_read)() != 0 {}
let ptr = DRTIOAUX_MEM[linkno].base as *mut u32;
let len = f(slice::from_raw_parts_mut(ptr as *mut u8, 0x400 as usize))?;
let mut buf: [u8; MAX_PACKET] = [0; MAX_PACKET];
let len = f(&mut buf)?;
copy_work_buffer(buf.as_mut_ptr() as *mut u32, ptr, len as isize);
(DRTIOAUX[linkno].aux_tx_length_write)(len as u16);
(DRTIOAUX[linkno].aux_tx_write)(1);
Ok(())
@@ -135,7 +147,7 @@ pub fn send(linkno: u8, packet: &Packet) -> Result<(), Error> {
}
let checksum = crc::crc32::checksum_ieee(&writer.get_ref()[0..writer.position()]);
writer.write_u32(checksum)?;
writer.write_u32::<NativeEndian>(checksum)?;
Ok(writer.position())
})

View File

@@ -1,16 +1,15 @@
use core::slice;
use byteorder::NativeEndian;
use core_io::{Error as IoError, ErrorKind as IoErrorKind};
use crc;
use io::{proto::{ProtoRead, ProtoWrite},
Cursor};
use io::{Cursor,
proto::{ProtoRead, ProtoWrite}};
use libasync::{block_async, task};
use libboard_zynq::{time::Milliseconds, timer::GlobalTimer};
use nb;
use libboard_zynq::timer;
use void::Void;
pub use crate::drtioaux_proto::Packet;
use crate::{drtioaux::{has_rx_error, Error},
pub use crate::drtioaux_proto::{MAX_PACKET, Packet};
use crate::{drtioaux::{Error, copy_work_buffer, has_rx_error},
mem::mem::DRTIOAUX_MEM,
pl::csr::DRTIOAUX};
@@ -68,7 +67,7 @@ pub async fn recv(linkno: u8) -> Result<Option<Packet>, Error> {
let checksum_at = reader.position() + padding;
let checksum = crc::crc32::checksum_ieee(&reader.get_ref()[0..checksum_at]);
reader.set_position(checksum_at);
if reader.read_u32()? != checksum {
if reader.read_u32::<NativeEndian>()? != checksum {
return Err(Error::CorruptedPacket);
}
Ok(packet)
@@ -76,11 +75,11 @@ pub async fn recv(linkno: u8) -> Result<Option<Packet>, Error> {
.await
}
pub async fn recv_timeout(linkno: u8, timeout_ms: Option<u64>, timer: GlobalTimer) -> Result<Packet, Error> {
let timeout_ms = Milliseconds(timeout_ms.unwrap_or(10));
let limit = timer.get_time() + timeout_ms;
pub async fn recv_timeout(linkno: u8, timeout_ms: Option<u64>) -> Result<Packet, Error> {
let timeout_ms = timeout_ms.unwrap_or(10);
let limit = timer::get_ms() + timeout_ms;
let mut would_block = false;
while timer.get_time() < limit {
while timer::get_ms() < limit {
// to ensure one last time recv would run one last time
// in case async would return after timeout
if would_block {
@@ -102,7 +101,9 @@ where F: FnOnce(&mut [u8]) -> Result<usize, Error> {
unsafe {
let _ = block_async!(tx_ready(linkno)).await;
let ptr = DRTIOAUX_MEM[linkno].base as *mut u32;
let len = f(slice::from_raw_parts_mut(ptr as *mut u8, 0x400 as usize))?;
let mut buf: [u8; MAX_PACKET] = [0; MAX_PACKET];
let len = f(&mut buf)?;
copy_work_buffer(buf.as_mut_ptr() as *mut u32, ptr, len as isize);
(DRTIOAUX[linkno].aux_tx_length_write)(len as u16);
(DRTIOAUX[linkno].aux_tx_write)(1);
Ok(())
@@ -122,7 +123,7 @@ pub async fn send(linkno: u8, packet: &Packet) -> Result<(), Error> {
}
let checksum = crc::crc32::checksum_ieee(&writer.get_ref()[0..writer.position()]);
writer.write_u32(checksum)?;
writer.write_u32::<NativeEndian>(checksum)?;
Ok(writer.position())
})

View File

@@ -1,11 +1,18 @@
use core_io::{Error as IoError, Read, Write};
use byteorder::NativeEndian;
use core_io::Error as IoError;
use io::proto::{ProtoRead, ProtoWrite};
const MAX_PACKET: usize = 1024;
pub const MAX_PACKET: usize = 1024;
// maximum size of arbitrary payloads
// used by satellite -> master CoaXPress communication and errors
pub const CXP_PAYLOAD_MAX_SIZE: usize = /*max size*/
MAX_PACKET - /*packet ID*/1 - /*length*/2 - /*CRC*/4 - /*padding to keep CXP register access 4 bytes align*/1;
// used by satellite -> master CoaXPress roi viewer pixel data transfer
pub const CXP_PAYLOAD_MAX_SIZE_U64: usize = CXP_PAYLOAD_MAX_SIZE / 8;
// used by satellite -> master analyzer, subkernel exceptions
pub const SAT_PAYLOAD_MAX_SIZE: usize = /*max size*/MAX_PACKET - /*CRC*/4 - /*packet ID*/1 - /*last*/1 - /*length*/2;
pub const SAT_PAYLOAD_MAX_SIZE: usize = /*max size*/
MAX_PACKET - /*CRC*/4 - /*packet ID*/1 - /*last*/1 - /*length*/2;
// used by DDMA, subkernel program data (need to provide extra ID and destination)
pub const MASTER_PAYLOAD_MAX_SIZE: usize = SAT_PAYLOAD_MAX_SIZE - /*source*/1 - /*destination*/1 - /*ID*/4;
@@ -255,6 +262,7 @@ pub enum Packet {
destination: u8,
id: u32,
run: bool,
timestamp: u64,
},
SubkernelLoadRunReply {
destination: u8,
@@ -267,12 +275,14 @@ pub enum Packet {
exception_src: u8,
},
SubkernelExceptionRequest {
source: u8,
destination: u8,
},
SubkernelException {
destination: u8,
last: bool,
length: u16,
data: [u8; SAT_PAYLOAD_MAX_SIZE],
data: [u8; MASTER_PAYLOAD_MAX_SIZE],
},
SubkernelMessage {
source: u8,
@@ -285,11 +295,113 @@ pub enum Packet {
SubkernelMessageAck {
destination: u8,
},
CoreMgmtGetLogRequest {
destination: