Compare commits

...

150 Commits

Author SHA1 Message Date
Florian Agbuya 195a21fe78 use nix format for arm gnu toolchain 2024-03-25 17:20:19 +08:00
Florian Agbuya 96cefe6f06 update fsbl source 2024-03-25 17:16:56 +08:00
morgan 7c58c0cf43 abort: rename to exception_vectors 2024-03-07 12:26:28 +08:00
morgan 9005b73316 experiment: add set_vector_table example 2024-03-07 12:03:49 +08:00
morgan b1994dbe16 abort: support custom exception vector table addr 2024-03-07 12:03:29 +08:00
morgan 5bd336c961 add support for using custom FIQ handler
cfg: add dummy FIQ handler cfg
abort: gate dummy FIQ handler using cfg
2024-02-02 17:01:07 +08:00
morgan 298f64a2f9 boot: enable FIQ
asm: add FIQ enable instruction
2024-02-02 16:34:28 +08:00
morgan 4168eb63a7 GIC: fix wrong core target config when enabling interrupt (#109)
# Summary

- Before the patch, an extra 1 is added to `target_cpu` and the interrupt will be configured to the wrong CPU target.

| target_cpu | bits set before patch | bits set after patch   |
| -----------| -----------                      | -----------                       |
| core0      | 0b10 (enable interrupt on core1) | 0b01 (enable interrupt on core0)  |
| core1      | 0b11 (enable interrupt on core0 & core1)| 0b10 (enable interrupt on core1) |

- [Correct ICDIPTR Register configuration from AMD](https://docs.xilinx.com/r/en-US/ug585-zynq-7000-SoC-TRM/Software-Generated-Interrupts-SGI?tocId=0TsxAmy8MHRPDsayG96K1Q)

Reviewed-on: M-Labs/zynq-rs#109
Co-authored-by: morgan <mc@m-labs.hk>
Co-committed-by: morgan <mc@m-labs.hk>
2023-12-19 18:41:03 +08:00
Sebastien Bourdeauducq a43b8bf64e mkbootimage: work around buffer overflow 2023-12-03 16:16:22 +08:00
Sebastien Bourdeauducq 91bae572f9 fix "unknown argument '-Wl,--undefined=AUDITABLE_VERSION_INFO'" 2023-12-03 11:09:31 +08:00
Sebastien Bourdeauducq 301f9236e5 switch to nixpkgs cargo-xbuild (with workaround for rust nonsense) 2023-12-03 10:55:05 +08:00
Sebastien Bourdeauducq 55b36ee37e switch to new nixpkgs release 2023-12-03 10:45:47 +08:00
morgan 24c804e6f0 libcortex_a9: add interrupt exit support for interrupt_handler macro (#107)
Co-authored-by: morgan <mc@m-labs.hk>
Co-committed-by: morgan <mc@m-labs.hk>
2023-11-20 12:30:27 +08:00
Sebastien Bourdeauducq be672ab662 flake: update dependencies 2023-10-20 17:46:01 +08:00
mwojcik 0106430805 remove gpio reset 2023-10-18 17:33:19 +08:00
jmatyas c15b54f92b kasli-soc: add support for PHY_RST GPIO 2023-08-31 12:58:59 +02:00
Sebastien Bourdeauducq de42a5d1b2 flake: update to LLVM 14 2023-08-07 23:26:58 +08:00
Sebastien Bourdeauducq ff03bf92a3 flake: update dependencies 2023-08-07 23:23:02 +08:00
Sebastien Bourdeauducq f20c008264 flake: nixpkgs 23.05 2023-05-27 18:20:53 +08:00
Sebastien Bourdeauducq 67dbb5932f flake: update mkbootimage 2022-11-30 22:36:56 +08:00
Sebastien Bourdeauducq dab5c6f070 flake: NixOS 22.11, update dependencies 2022-11-30 22:29:58 +08:00
Egor Savkin 0a3a777652 Fix soft_rst bit, add reboot function 2022-10-07 12:57:56 +08:00
mwojcik 92b3f3e1dd panic: turn on error_led for kasli_soc 2022-08-26 17:22:42 +08:00
mwojcik f586ba5a13 experiments: add error led test for kasli_soc 2022-08-26 17:22:42 +08:00
mwojcik 42cc256812 add error led 2022-08-26 17:22:42 +08:00
occheung 043a152b91 szl: change CPU frequency of Kasli-SoC to 1 GHz 2022-07-20 15:16:15 +08:00
Sebastien Bourdeauducq 6cd32f6ee0 flake: update dependencies 2022-05-31 21:02:28 +08:00
mwojcik 605c8f73a6 mutex: add async version of lock 2022-05-25 10:22:16 +08:00
mwojcik 56c27e98e4 config: add "fat_lfn" feature 2022-04-07 15:44:07 +08:00
mwojcik f496da4f3e config: create config dir if not present 2022-04-06 16:17:35 +08:00
mwojcik 1c8e2c318c eth phy: reset page to 0 on kasli-soc for ident 2022-03-10 17:11:41 +08:00
mwojcik 67880b4e0b openocd: moved common code from target files 2022-03-10 17:05:25 +08:00
Sebastien Bourdeauducq e96222ff6f update dependencies 2022-03-10 17:01:37 +08:00
mwojcik dc1ca3d3d0 szl: fallback to netboot if boot mode not supported 2022-03-10 16:48:00 +08:00
mwojcik c4c52c33b4 eth phy: use unreachable!() for impossible values 2022-03-10 16:45:29 +08:00
mwojcik 072fd5f015 eth phy: set LEDs only on Kasli-SoC 2022-03-10 16:42:25 +08:00
mwojcik 2b3c7e4b2f eth leds:
* break led0 from led1 - similar, but not the same settings (led2 not implemented)
* fix values, make it compilable
* set default behavior (one led for link, other for activity)
2022-03-10 16:42:25 +08:00
mwojcik 84d6d391ce libboard_zynq: eth phy for Marvell 88E1518
* add support for LED control registers
* support for registers on different pages
2022-03-10 16:42:25 +08:00
mwojcik 43e0440911 Kasli-SoC: Get MAC address from EEPROM (#90)
Co-authored-by: mwojcik <mw@m-labs.hk>
Co-committed-by: mwojcik <mw@m-labs.hk>
2022-03-07 18:01:44 +08:00
mwojcik 3e95df1f64 pca954x_select: api supports no channel enabled 2022-02-11 13:46:51 +08:00
mwojcik 26ab2927b9 pca954x: log detected type 2022-02-11 12:00:39 +08:00
mwojcik dacc816eb4 pca954x: improve code, fix I2C_SW_RESET behavior 2022-02-11 11:22:53 +08:00
mwojcik fbc783d7ad flake: add pyftdi to env 2022-02-11 11:19:15 +08:00
mwojcik 14b0247716 pca954x: fix to work on cold boot 2022-02-09 17:23:33 +08:00
mwojcik bc41b91192 adjust pca address 2022-02-08 16:39:12 +08:00
mwojcik 3efc682bd6 add pca954x autodetection, pca9547 support 2022-02-08 15:40:17 +08:00
mwojcik e5e646f40e Additional outputs to flakes (#86)
Co-authored-by: mwojcik <mw@m-labs.hk>
Co-committed-by: mwojcik <mw@m-labs.hk>
2022-02-04 18:42:35 +08:00
Sebastien Bourdeauducq 2e7cfe04c8 update copyright year 2022-01-27 18:00:24 +08:00
mwojcik 24e0d724f2 nix flakes support (#85)
Reviewed-on: M-Labs/zynq-rs#85
Co-authored-by: mwojcik <mw@m-labs.hk>
Co-committed-by: mwojcik <mw@m-labs.hk>
2022-01-27 16:26:33 +08:00
Sebastien Bourdeauducq 823e909281 openocd: upgrade deprecated syntax 2021-12-03 18:42:45 +08:00
Sebastien Bourdeauducq 57d8d8fbc7 update dependencies 2021-08-09 15:05:05 +08:00
Sebastien Bourdeauducq a4902966d1 update Rust Mozilla overlay 2021-08-09 14:53:08 +08:00
Sebastien Bourdeauducq 2c161720fa revert a11cb852a8 2021-07-05 13:45:22 +08:00
topquark12 a42e5a95ff phy: fix issue 78, scan PHY MDIO addr starting at 0 2021-07-05 13:25:22 +08:00
Sebastien Bourdeauducq 03122f810a openocd: adapt to newer version (zc706) 2021-06-25 17:43:05 +08:00
Sebastien Bourdeauducq c7e9f85de2 openocd: adapt to newer version 2021-06-25 17:01:02 +08:00
Sebastien Bourdeauducq 104d1ef232 openocd: name kasli_soc consistently 2021-06-25 16:45:38 +08:00
Sebastien Bourdeauducq b0ec74d764 i2c: half_period -> unit_delay 2021-06-25 16:26:53 +08:00
Sebastien Bourdeauducq 4159aab6c8 i2c: conservative timing, avoid SCL/SDA races. Closes #83 2021-06-25 16:26:04 +08:00
Sebastien Bourdeauducq d18c77c0eb i2c: fix error messages 2021-06-25 16:23:50 +08:00
Sebastien Bourdeauducq 8dbe2cf9f3 add SZL multi-board package 2021-06-25 16:21:49 +08:00
Sebastien Bourdeauducq 040d41fd76 update cargosha256 2021-06-19 22:47:21 +08:00
Sebastien Bourdeauducq 9180918619 update dependencies 2021-06-19 22:40:09 +08:00
Sebastien Bourdeauducq 8ec7216e9a update cargo-xbuild 2021-06-19 22:25:07 +08:00
Sebastien Bourdeauducq 0e9d3f146a remove use of deprecated stdenv.lib 2021-06-19 22:04:14 +08:00
Sebastien Bourdeauducq 411eebd96c i2c: configure I2C_SW_RESET MIO on Kasli-SoC 2021-06-19 18:49:51 +08:00
sb10q e31adb722d README: add Kasli-SoC 2021-05-30 07:37:27 +08:00
Sebastien Bourdeauducq 759bf95a76 add Kasli-SoC POR control program 2021-05-29 17:43:21 +08:00
Sebastien Bourdeauducq f83ef218de update cargosha256 2021-05-29 14:13:51 +08:00
Sebastien Bourdeauducq 062b894a4b use updated upstream core_io 2021-05-29 14:09:11 +08:00
Sebastien Bourdeauducq 2f9019ca0f szl: update copyright year 2021-05-29 14:01:29 +08:00
Sebastien Bourdeauducq 7b29ab2628 update dependencies
Prevent cargo from messing up core_io this time.
2021-05-29 13:10:54 +08:00
Sebastien Bourdeauducq a9697ec8d8 Revert "update dependencies"
This reverts commit 0220cf19eb.
2021-05-29 13:05:35 +08:00
Sebastien Bourdeauducq 0220cf19eb update dependencies 2021-05-29 13:03:35 +08:00
Sebastien Bourdeauducq a11cb852a8 libboard_zynq: work around Kasli-SoC MDIO breakage (#78) 2021-05-29 12:50:28 +08:00
Sebastien Bourdeauducq 42cdedae91 openocd: fix Kasli-SoC nSRST 2021-05-29 12:17:59 +08:00
Sebastien Bourdeauducq 823ec374ba kasli-soc: internal JTAG 2021-05-28 18:44:07 +08:00
Sebastien Bourdeauducq 666c077cef openocd: add Kasli-SoC (with digilent external JTAG) 2021-05-28 18:22:17 +08:00
Sebastien Bourdeauducq def17829d9 LGPLv3 2021-04-06 16:46:38 +08:00
Astro ba252e72da libasync: provide get/set ack_delay (new in smoltcp 0.7.0) 2021-02-08 03:06:51 +01:00
Astro a2416f26a0 default.nix: update cargoSha256* 2021-02-04 18:29:00 +01:00
Astro bf9f1e33c8 update smoltcp 0.6.0 -> 0.7.0 2021-02-04 18:29:00 +01:00
Astro 481a0eb25f Revert "default.nix: update cargoSha256*"
This reverts commit 89e4d61dc0.
2021-02-04 18:27:44 +01:00
Astro 05c30dd52e Revert "update smoltcp 0.6.0 -> 0.7.0"
This reverts commit ccf758cc85.
2021-02-04 18:27:42 +01:00
Astro f816a04cef Revert "Revert "update smoltcp 0.6.0 -> 0.7.0""
This reverts commit faa64c2ce8.
2021-02-04 16:22:39 +01:00
Astro faa64c2ce8 Revert "update smoltcp 0.6.0 -> 0.7.0"
This reverts commit ccf758cc85.

Blocked by: https://github.com/smoltcp-rs/smoltcp/issues/415
2021-02-04 16:22:16 +01:00
Astro 89e4d61dc0 default.nix: update cargoSha256* 2021-02-04 00:32:57 +01:00
Astro 0b07e9fefc update Rust
the old nightly crashes with smoltcp 0.7.0
2021-02-03 22:42:00 +01:00
Astro ccf758cc85 update smoltcp 0.6.0 -> 0.7.0 2021-02-03 22:41:32 +01:00
pca006132 78d58d17ec libsupport_zynq: fix stack pointer problems 2021-01-28 12:33:06 +08:00
pca006132 06c646e61f libcortex_a9: added interrupt_handler macro
closes #73
2021-01-28 11:41:34 +08:00
pca006132 7681745282 experiments: fix broken build 2021-01-26 12:53:26 +08:00
pca006132 6e6612bc3e szl: move enable l2c to artiq-zynq 2021-01-26 11:19:33 +08:00
pca006132 b50540915d libcortex_a9: memcpy throughput optimization 2021-01-26 11:16:37 +08:00
pca006132 4aa252546f experiments: updated experiment 2021-01-15 17:08:20 +08:00
pca006132 b42869e655 libsupport_zynq: removed naked annotation 2021-01-15 17:08:20 +08:00
pca006132 d62c77e6e0 libcortex_a9: fixed usage of deprecated APIs 2021-01-15 17:08:20 +08:00
pca006132 4555afa624 libsupport_zynq: custom memcpy 2021-01-15 17:08:14 +08:00
pca006132 5923a66512 libsupport_zynq/boot: enable FPU on boot 2021-01-15 16:45:27 +08:00
pca006132 2c6cc58c07 updated rust and compiler_builtins 2021-01-15 16:45:11 +08:00
Astro b4d91e7904 nix/rust-platform: remove rustcSrc which had to be kept in sync 2021-01-15 00:52:22 +01:00
Astro 4c79c797d5 default.nix: filterSource 2021-01-15 00:51:45 +01:00
Astro 966e43e14e update dependency: linked_list_allocator 2020-12-24 00:52:14 +01:00
Astro 8432ff3e30 default.nix: update cargoSha256* 2020-11-20 17:32:52 +01:00
Astro 1cd4056370 libboard_zynq: remove unused eth phy name information 2020-11-20 17:21:38 +01:00
Astro ddff295ae1 libboard_zynq: implement eth hot-plugging 2020-11-20 17:12:22 +01:00
Astro 379b6b973a libboard_zynq: add support for target_kasli_soc's Marvell88E1512 eth phy 2020-11-19 20:38:10 +01:00
Astro 178ab38e35 experiments: delint 2020-11-19 20:27:05 +01:00
Astro 3172aba1a8 libboard_zynq: improve i2c doc 2020-11-19 20:26:48 +01:00
Astro a62ca507d0 libregister: allow rustdoc for register! macro 2020-11-19 20:26:18 +01:00
Astro 975202a653 libboard_zynq: enable i2c+eeprom for target_kasli_soc 2020-11-19 20:17:36 +01:00
Astro d76a77b443 libregister: s/libregister::/$crate::/ 2020-11-19 20:16:36 +01:00
Astro 500472b2a8 add feature target_kasli_soc to libsupport_zynq, libconfig, experiments, szl, default.nix 2020-11-19 19:41:38 +01:00
Astro 02217f27d1 libcortex_a9: remove useless target_* features 2020-11-19 19:38:57 +01:00
Astro a3eabf1947 libboard_zynq: prepare target_kasli_soc 2020-11-19 19:28:17 +01:00
Astro a32d7abb9a libboard_zynq: rename ddr DCI_FREQ to DCI_MAX_FREQ 2020-11-19 19:21:38 +01:00
Sebastien Bourdeauducq 0e8354faa1 remote_run.sh: clean up getopts 2020-11-18 17:45:43 +08:00
Sebastien Bourdeauducq 07f161d9d8 libconfig: fix ipv6 address configuration key 2020-11-18 10:47:48 +08:00
Sebastien Bourdeauducq ef160aa841 README: update board support info 2020-11-18 10:36:55 +08:00
Astro cb50c8d61b update deps, pin compiler_builtins to 0.1.35 2020-11-13 19:40:38 +01:00
Astro 7bbd16f143 default.nix: build crates for all targets 2020-11-13 18:07:22 +01:00
Astro 0714162113 rename target_cora_z7_10 to target_coraz7 globally 2020-11-13 17:56:47 +01:00
Astro 5b2c779cba libboard_zynq: delint ps7_init 2020-11-13 00:23:56 +01:00
Astro 0a40d4f36d libboard_zynq: fix zc706 build 2020-11-13 00:23:38 +01:00
Astro 55f8d02da8 libboard_zynq: remove ddr-only ps7_init for redpitaya 2020-11-13 00:12:43 +01:00
Astro 990fa56d6a libboard_zynq: complete ddr without ps7_init for redpitaya 2020-11-13 00:10:34 +01:00
Astro 8fd317d580 libboard_zynq: remove ps7_init for cora_z7_10 2020-11-11 14:21:48 +01:00
Astro 07fedddad9 libboard_zynq: doc ddr size limitation, correct target_redpitaya to 512MB 2020-11-11 13:25:55 +01:00
Astro 0fde82a982 szl: add target_cora_z7_10 2020-11-10 20:57:31 +01:00
Astro dffe3cb251 libboard_zynq: rm superfluous ddr settings for cora_z7_10 2020-11-10 20:53:46 +01:00
Astro b9323653bb libboard_zynq: complete ddr without ps7_init for cora_z7_10 2020-11-10 14:33:31 +01:00
Astro 515d3bb381 libboard_zynq: configure ddr while keeping rstb low 2020-11-08 22:47:59 +01:00
Astro 7e22010d7d libboard_zynq: fix pll_cp/pll_res swap in ClockSource::setup() 2020-11-08 22:46:43 +01:00
Astro 9ee77d8f44 libboard_zynq: indent ps7_init/cora_z7_10 2020-11-08 19:32:31 +01:00
Astro e508b78b3e libboard_zynq: add ps7_init for cora_z7_10 2020-11-08 19:28:59 +01:00
Astro aef010cb14 openocd: remove xilinx-tcl on Cora Z7 2020-11-08 18:44:41 +01:00
pca006132 d623913535 libconfig: fixed szl build.
to_lowercase would handle unicode which causes a huge increase in rodata
size, we have to use to_ascii_lowercase.
2020-11-04 20:47:40 +08:00
pca006132 0efc7a616f libconfig: implemented config write
Config write and config remove are now implemented.
Config keys are now treated case insensitively, which is consistence to
the filesystem behavior.
BOOT.BIN can be replaced by setting the config key "boot".
2020-10-30 16:11:18 +08:00
pca006132 22833ef0c6 libconfig/sd_reader: added FAT16_LBA ID 2020-10-17 13:37:18 +08:00
Sebastien Bourdeauducq 80d12d5780 libconfig: make default IP/MAC depend on board 2020-10-14 12:53:32 +08:00
Sebastien Bourdeauducq 4dd8c93729 add SZL for Red Pitaya 2020-10-14 12:35:23 +08:00
Sebastien Bourdeauducq 6266d28095 expose patched cargo-xbuild 2020-10-13 18:43:37 +08:00
Sebastien Bourdeauducq 1796d4e236 update some dependencies
Older versions do not compile with newer Rust.
2020-10-13 18:28:42 +08:00
Sebastien Bourdeauducq 56c94b0855 patch cargo-xbuild to ensure copied Cargo.lock is writable
https://github.com/rust-osdev/cargo-xbuild/issues/96
2020-10-13 18:27:52 +08:00
Sebastien Bourdeauducq 34a63d7732 use new location for libraries in Rust source 2020-10-13 18:27:01 +08:00
Sebastien Bourdeauducq 27d310a937 update Rust
Needed for compatibility with recent cargo-xbuild.
2020-10-13 18:25:39 +08:00
pca006132 f60d0589cc fix ps7_init compilation error and warnings 2020-10-01 00:17:47 +08:00
Sebastien Bourdeauducq 7c9edfdbd5 README: add introduction 2020-09-29 16:27:44 +08:00
pca006132 c336e450b1 libboard_zynq/eth/phy: add PEF7071 2020-09-29 16:01:54 +08:00
pca006132 6af453494b libboard_zynq/ddr: use ps7_init for redpitaya ddr 2020-09-26 17:01:37 +08:00
89 changed files with 2640 additions and 23592 deletions

1
.gitignore vendored
View File

@ -1 +1,2 @@
/target
result*

209
Cargo.lock generated
View File

@ -4,238 +4,255 @@
name = "bit_field"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dcb6dd1c2376d2e096796e234a70e17e94cc2d5d54ff8ce42b28cef1d0d359a4"
[[package]]
name = "bitflags"
version = "1.2.1"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "byteorder"
version = "1.3.4"
version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]]
name = "cc"
version = "1.0.73"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"
[[package]]
name = "cfg-if"
version = "0.1.10"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "compiler_builtins"
version = "0.1.35"
version = "0.1.39"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3748f82c7d366a0b4950257d19db685d4958d2fa27c6d164a3f069fec42b748b"
[[package]]
name = "core_io"
version = "0.1.20200410"
version = "0.1.20210325"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97f8932064288cc79feb4d343a399d353a6f6f001e586ece47fe518a9e8507df"
dependencies = [
"memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_version",
]
[[package]]
name = "embedded-hal"
version = "0.2.4"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "35949884794ad573cf46071e41c9b60efb0cb311e3ca01f7af807af1debc66ff"
dependencies = [
"nb 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"nb 0.1.3",
"void",
]
[[package]]
name = "experiments"
version = "0.0.0"
dependencies = [
"embedded-hal 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
"libasync 0.0.0",
"libboard_zynq 0.0.0",
"libcortex_a9 0.0.0",
"libregister 0.0.0",
"libsupport_zynq 0.0.0",
"log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
"embedded-hal",
"libasync",
"libboard_zynq",
"libcortex_a9",
"libregister",
"libsupport_zynq",
"log",
]
[[package]]
name = "fatfs"
version = "0.3.4"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e18f80a87439240dac45d927fd8f8081b6f1e34c03e97271189fa8a8c2e96c8f"
dependencies = [
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"core_io 0.1.20200410",
"log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags",
"byteorder",
"core_io",
"log",
]
[[package]]
name = "libasync"
version = "0.0.0"
dependencies = [
"embedded-hal 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
"libcortex_a9 0.0.0",
"nb 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"pin-utils 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"smoltcp 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"embedded-hal",
"libcortex_a9",
"nb 1.0.0",
"pin-utils",
"smoltcp",
]
[[package]]
name = "libboard_zynq"
version = "0.0.0"
dependencies = [
"bit_field 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
"embedded-hal 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
"libcortex_a9 0.0.0",
"libregister 0.0.0",
"log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
"nb 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"smoltcp 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"volatile-register 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"bit_field",
"embedded-hal",
"libasync",
"libcortex_a9",
"libregister",
"log",
"nb 0.1.3",
"smoltcp",
"void",
"volatile-register",
]
[[package]]
name = "libconfig"
version = "0.1.0"
dependencies = [
"core_io 0.1.20200410",
"fatfs 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"libboard_zynq 0.0.0",
"log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
"core_io",
"fatfs",
"libboard_zynq",
"log",
]
[[package]]
name = "libcortex_a9"
version = "0.0.0"
dependencies = [
"bit_field 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libregister 0.0.0",
"volatile-register 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"bit_field",
"libregister",
"volatile-register",
]
[[package]]
name = "libregister"
version = "0.0.0"
dependencies = [
"bit_field 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
"vcell 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"volatile-register 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"bit_field",
"vcell",
"volatile-register",
]
[[package]]
name = "libsupport_zynq"
version = "0.0.0"
dependencies = [
"compiler_builtins 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
"libboard_zynq 0.0.0",
"libcortex_a9 0.0.0",
"libregister 0.0.0",
"linked_list_allocator 0.8.5 (registry+https://github.com/rust-lang/crates.io-index)",
"r0 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"cc",
"compiler_builtins",
"libboard_zynq",
"libcortex_a9",
"libregister",
"linked_list_allocator",
"r0",
]
[[package]]
name = "linked_list_allocator"
version = "0.8.5"
version = "0.8.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "822add9edb1860698b79522510da17bef885171f75aa395cff099d770c609c24"
[[package]]
name = "log"
version = "0.4.11"
version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
dependencies = [
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"cfg-if",
]
[[package]]
name = "managed"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "memchr"
version = "2.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c75de51135344a4f8ed3cfe2720dc27736f7711989703a0b43aadf3753c55577"
[[package]]
name = "nb"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f"
dependencies = [
"nb 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"nb 1.0.0",
]
[[package]]
name = "nb"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "546c37ac5d9e56f55e73b677106873d9d9f5190605e41a856503623648488cae"
[[package]]
name = "pin-utils"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
name = "r0"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd7a31eed1591dcbc95d92ad7161908e72f4677f8fabf2a32ca49b4237cbf211"
[[package]]
name = "rustc_version"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c5f5376ea5e30ce23c03eb77cbe4962b988deead10910c372b226388b594c084"
dependencies = [
"semver",
]
[[package]]
name = "semver"
version = "0.1.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4f410fedcf71af0345d7607d246e7ad15faaadd49d240ee3b24e5dc21a820ac"
[[package]]
name = "smoltcp"
version = "0.6.0"
version = "0.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e4a069bef843d170df47e7c0a8bf8d037f217d9f5b325865acc3e466ffe40d3"
dependencies = [
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"managed 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags",
"byteorder",
"managed",
]
[[package]]
name = "szl"
version = "0.1.0"
dependencies = [
"byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"core_io 0.1.20200410",
"libboard_zynq 0.0.0",
"libconfig 0.1.0",
"libcortex_a9 0.0.0",
"libregister 0.0.0",
"libsupport_zynq 0.0.0",
"log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder",
"core_io",
"libboard_zynq",
"libconfig",
"libcortex_a9",
"libregister",
"libsupport_zynq",
"log",
]
[[package]]
name = "vcell"
version = "0.1.2"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002"
[[package]]
name = "void"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
[[package]]
name = "volatile-register"
version = "0.2.0"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ee8f19f9d74293faf70901bc20ad067dc1ad390d2cbf1e3f75f721ffee908b6"
dependencies = [
"vcell 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"vcell",
]
[metadata]
"checksum bit_field 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dcb6dd1c2376d2e096796e234a70e17e94cc2d5d54ff8ce42b28cef1d0d359a4"
"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
"checksum byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
"checksum compiler_builtins 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "e3fcd8aba10d17504c87ef12d4f62ef404c6a4703d16682a9eb5543e6cf24455"
"checksum embedded-hal 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "fa998ce59ec9765d15216393af37a58961ddcefb14c753b4816ba2191d865fcb"
"checksum fatfs 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "93079df23039e52059e1f03b4c29fb0c72da2c792aad91bb2236c9fb81d3592e"
"checksum linked_list_allocator 0.8.5 (registry+https://github.com/rust-lang/crates.io-index)" = "660b26e6156a7d00eefb19052fe1943cf5ab2f353a723a577fad6ba2f99d1f90"
"checksum log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b"
"checksum managed 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c75de51135344a4f8ed3cfe2720dc27736f7711989703a0b43aadf3753c55577"
"checksum memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400"
"checksum nb 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f"
"checksum nb 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "546c37ac5d9e56f55e73b677106873d9d9f5190605e41a856503623648488cae"
"checksum pin-utils 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
"checksum r0 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bd7a31eed1591dcbc95d92ad7161908e72f4677f8fabf2a32ca49b4237cbf211"
"checksum smoltcp 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0fe46639fd2ec79eadf8fe719f237a7a0bd4dac5d957f1ca5bbdbc1c3c39e53a"
"checksum vcell 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "876e32dcadfe563a4289e994f7cb391197f362b6315dc45e8ba4aa6f564a4b3c"
"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
"checksum volatile-register 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0d67cb4616d99b940db1d6bd28844ff97108b498a6ca850e5b6191a532063286"

View File

@ -6,7 +6,6 @@ members = [
"libsupport_zynq",
"libasync",
"libconfig",
"libcoreio",
"experiments",
"szl",
]
@ -15,10 +14,7 @@ members = [
panic = "abort"
debug = true
codegen-units = 1
opt-level = 'z'
opt-level = 's'
lto = true
debug-assertions = false
overflow-checks = false
[patch.crates-io]
core_io = { path = "./libcoreio" }

165
LICENSE Normal file
View File

@ -0,0 +1,165 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
"The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.

View File

@ -1,31 +1,69 @@
# Build
# Bare-metal Rust on Zynq-7000
Supported features:
* Clocking setup
* UART
* SDRAM setup
* Ethernet with smoltcp and async-await on TCP sockets
* SD card
* PL programming and startup
* Pure Rust SZL first-stage bootloader, with SD boot and netboot
* Control of second CPU core and message passing, with async-await support
Supported boards:
* Kasli-SoC
* ZC706
* Red Pitaya
* Cora Z7-10 (seems to also run on Cora Z7-07S, including dual-core support)
## Build
Zynq-rs is packaged using the [Nix](https://nixos.org) Flakes system. Install Nix 2.4+ and enable flakes by adding ``experimental-features = nix-command flakes`` to ``nix.conf`` (e.g. ``~/.config/nix/nix.conf``).
You can build SZL or experiments crate for the platform of your choice by using ``nix build`` command, e.g.
```shell
nix-shell --command "cargo xbuild --release -p experiments"
nix build .#coraz7-experiments
```
Currently the ELF output is placed at `target/armv7-none-eabihf/release/experiments`
# Debug
## Running on the ZC706
Alternatively, you can still use ``cargo xbuild`` within ``nix develop`` shell.
```shell
nix-shell --command "cargo xbuild --release -p experiments"
nix develop
cargo xbuild --release -p experiments
```
Currently the ELF output is placed at `target/armv7-none-eabihf/release/experiments`, or `result/experiments.elf` for Nix Flakes build.
## Debug
### Running on the ZC706
```shell
nix develop
cargo xbuild --release -p experiments
cd openocd
openocd -f zc706.cfg
```
## Running on the Cora Z7-10
### Running on the Cora Z7-10
```shell
nix-shell --command "cd experiments && cargo xbuild --release --no-default-features --features=target_cora_z7_10"
nix develop
cargo xbuild --release -p experiments --no-default-features --features=target_coraz7
cd openocd
openocd -f cora-z7-10.cfg
```
## Loading a bitstream into volatile memory
### Loading a bitstream into volatile memory
```shell
openocd -f zc706.cfg -c "pld load 0 blinker_migen.bit; exit"
```
## License
Copyright (C) 2019-2022 M-Labs Limited.
Released under the GNU LGPL v3. See the LICENSE file for details.

View File

@ -1,38 +0,0 @@
let
pkgs = import <nixpkgs> { overlays = [ (import ./nix/mozilla-overlay.nix) ]; };
rustPlatform = (import ./nix/rust-platform.nix { inherit pkgs; });
build-crate = name: crate: features:
rustPlatform.buildRustPackage rec {
name = "${crate}";
src = ./.;
cargoSha256 = "1f2psa1g41pl2j8n60hhik2s2pqdfjhr5capimvajf81kxrnn2ck";
nativeBuildInputs = [ pkgs.cargo-xbuild ];
buildPhase = ''
export XARGO_RUST_SRC="${rustPlatform.rust.rustc.src}/src"
export CARGO_HOME=$(mktemp -d cargo-home.XXX)
pushd ${crate}
cargo xbuild --release --frozen \
--no-default-features \
--features=${features}
popd
'';
installPhase = ''
mkdir -p $out $out/nix-support
cp target/armv7-none-eabihf/release/${name} $out/${name}.elf
echo file binary-dist $out/${name}.elf >> $out/nix-support/hydra-build-products
'';
doCheck = false;
dontFixup = true;
};
in
{
zc706-experiments = build-crate "zc706-experiments" "experiments" "target_zc706";
cora-experiments = build-crate "cora-experiments" "experiments" "target_cora_z7_10";
redpitaya-experiments = build-crate "redpitaya-experiments" "experiments" "target_redpitaya";
zc706-fsbl = (import ./nix/fsbl.nix { inherit pkgs; });
zc706-szl = build-crate "zc706-szl" "szl" "target_zc706";
}

View File

@ -7,8 +7,9 @@ edition = "2018"
[features]
target_zc706 = ["libboard_zynq/target_zc706", "libsupport_zynq/target_zc706"]
target_cora_z7_10 = ["libboard_zynq/target_cora_z7_10", "libsupport_zynq/target_cora_z7_10"]
target_coraz7 = ["libboard_zynq/target_coraz7", "libsupport_zynq/target_coraz7"]
target_redpitaya = ["libboard_zynq/target_redpitaya", "libsupport_zynq/target_redpitaya"]
target_kasli_soc = ["libboard_zynq/target_kasli_soc", "libsupport_zynq/target_kasli_soc"]
default = ["target_zc706"]
[dependencies]
@ -17,5 +18,5 @@ embedded-hal = "0.2"
libregister = { path = "../libregister" }
libcortex_a9 = { path = "../libcortex_a9" }
libboard_zynq = { path = "../libboard_zynq" }
libsupport_zynq = { path = "../libsupport_zynq", default-features = false, features = ["panic_handler"]}
libsupport_zynq = { path = "../libsupport_zynq", default-features = false, features = ["panic_handler", "dummy_fiq_handler"]}
libasync = { path = "../libasync" }

View File

@ -34,6 +34,20 @@ SECTIONS
__bss_end = .;
} > OCM3
.irq_stack1 (NOLOAD) : ALIGN(8)
{
__irq_stack1_end = .;
. += 0x100;
__irq_stack1_start = .;
} > OCM3
.irq_stack0 (NOLOAD) : ALIGN(8)
{
__irq_stack0_end = .;
. += 0x100;
__irq_stack0_start = .;
} > OCM3
.stack1 (NOLOAD) : ALIGN(8) {
__stack1_end = .;
. += 0x200;

View File

@ -2,6 +2,7 @@
#![no_main]
#![feature(const_in_array_repeat_expressions)]
#![feature(naked_functions)]
#![feature(asm)]
extern crate alloc;
@ -34,11 +35,11 @@ use libcortex_a9::{
sync_channel,
regs::{MPIDR, SP},
spin_lock_yield, notify_spin_lock,
asm
asm, interrupt_handler
};
use libregister::{RegisterR, RegisterW};
use libsupport_zynq::{
boot, ram,
boot, exception_vectors, ram,
};
use log::{info, warn};
use core::sync::atomic::{AtomicBool, Ordering};
@ -54,28 +55,35 @@ extern "C" {
static CORE1_RESTART: AtomicBool = AtomicBool::new(false);
#[link_section = ".text.boot"]
#[no_mangle]
#[naked]
pub unsafe extern "C" fn IRQ() {
if MPIDR.read().cpu_id() == 1{
let mpcore = mpcore::RegisterBlock::mpcore();
let mut gic = gic::InterruptController::gic(mpcore);
let id = gic.get_interrupt_id();
if id.0 == 0 {
gic.end_interrupt(id);
asm::exit_irq();
SP.write(&mut __stack1_start as *mut _ as u32);
asm::enable_irq();
CORE1_RESTART.store(false, Ordering::Relaxed);
notify_spin_lock();
main_core1();
}
interrupt_handler!(IRQ, irq, __irq_stack0_start, __irq_stack1_start, {
let mpcore = mpcore::RegisterBlock::mpcore();
let mut gic = gic::InterruptController::gic(mpcore);
let id = gic.get_interrupt_id();
match MPIDR.read().cpu_id(){
0 => {
if id.0 == 0 {
println!("Interrupting core0...");
gic.end_interrupt(id);
return;
}
},
1 => {
if id.0 == 0 {
gic.end_interrupt(id);
asm::exit_irq();
SP.write(&mut __stack1_start as *mut _ as u32);
asm::enable_irq();
CORE1_RESTART.store(false, Ordering::Relaxed);
notify_spin_lock();
main_core1();
}
},
_ => {}
}
stdio::drop_uart();
println!("IRQ");
loop {}
}
});
pub fn restart_core1() {
let mut interrupt_controller = gic::InterruptController::gic(mpcore::RegisterBlock::mpcore());
@ -88,13 +96,12 @@ pub fn restart_core1() {
#[no_mangle]
pub fn main_core0() {
exception_vectors::set_vector_table(0x0);
// zynq::clocks::CpuClocks::enable_io(1_250_000_000);
enable_l2_cache();
enable_l2_cache(0x8);
println!("\nZynq experiments");
let mut interrupt_controller = gic::InterruptController::gic(mpcore::RegisterBlock::mpcore());
interrupt_controller.enable_interrupts();
// ps7_init::apply();
libboard_zynq::stdio::drop_uart();
libboard_zynq::logger::init().unwrap();
log::set_max_level(log::LevelFilter::Trace);
@ -107,31 +114,20 @@ pub fn main_core0() {
.boot_mode_pins()
);
#[cfg(feature = "target_zc706")]
#[cfg(any(
feature = "target_zc706",
feature = "target_redpitaya",
feature = "target_kasli_soc",
))]
const CPU_FREQ: u32 = 800_000_000;
#[cfg(feature = "target_cora_z7_10")]
#[cfg(feature = "target_coraz7")]
const CPU_FREQ: u32 = 650_000_000;
#[cfg(feature = "target_redpitaya")]
const CPU_FREQ: u32 = 800_000_000;
info!("Setup clock sources...");
ArmPll::setup(2 * CPU_FREQ);
Clocks::set_cpu_freq(CPU_FREQ);
#[cfg(feature = "target_zc706")]
{
IoPll::setup(1_000_000_000);
libboard_zynq::stdio::drop_uart();
}
#[cfg(feature = "target_cora_z7_10")]
{
IoPll::setup(1_000_000_000);
libboard_zynq::stdio::drop_uart();
}
#[cfg(feature = "target_redpitaya")]
{
IoPll::setup(1_000_000_000);
libboard_zynq::stdio::drop_uart();
}
IoPll::setup(1_000_000_000);
libboard_zynq::stdio::drop_uart();
info!("PLLs set up");
let clocks = zynq::clocks::Clocks::get();
info!(
@ -149,6 +145,10 @@ pub fn main_core0() {
ddr.memtest();
ram::init_alloc_ddr(&mut ddr);
info!("Send software interrupt to core0");
interrupt_controller.send_sgi(gic::InterruptId(0), gic::CPUCore::Core0.into());
info!("Core0 returned from interrupt");
boot::Core1::start(false);
let core1_req = unsafe { &mut CORE1_REQ.0 };
@ -198,6 +198,20 @@ pub fn main_core0() {
println!("");
}
#[cfg(feature = "target_kasli_soc")]
{
let mut err_cdwn = timer.countdown();
let mut err_state = true;
let mut led = zynq::error_led::ErrorLED::error_led();
task::spawn( async move {
loop {
led.toggle(err_state);
err_state = !err_state;
delay(&mut err_cdwn, Milliseconds(1000)).await;
}
});
}
let eth = zynq::eth::Eth::eth0(HWADDR.clone());
println!("Eth on");
@ -231,12 +245,12 @@ pub fn main_core0() {
while let Ok(stream) = TcpStream::accept(TCP_PORT, 0x10_0000, 0x10_0000).await {
let stats_tx = stats_tx.clone();
task::spawn(async move {
let tx_data = (0..=255).take(4096).collect::<alloc::vec::Vec<u8>>();
let tx_data = (0..=255).cycle().take(4096).collect::<alloc::vec::Vec<u8>>();
loop {
// const CHUNK_SIZE: usize = 65536;
// match stream.send((0..=255).cycle().take(CHUNK_SIZE)).await {
match stream.send_slice(&tx_data[..]).await {
Ok(len) => stats_tx.borrow_mut().1 += tx_data.len(), //CHUNK_SIZE,
Ok(_len) => stats_tx.borrow_mut().1 += tx_data.len(), //CHUNK_SIZE,
Err(e) => {
warn!("tx: {:?}", e);
break

44
flake.lock Normal file
View File

@ -0,0 +1,44 @@
{
"nodes": {
"mozilla-overlay": {
"flake": false,
"locked": {
"lastModified": 1695805681,
"narHash": "sha256-1ElPLD8eFfnuIk0G52HGGpRtQZ4QPCjChRlEOfkZ5ro=",
"owner": "mozilla",
"repo": "nixpkgs-mozilla",
"rev": "6eabade97bc28d707a8b9d82ad13ef143836736e",
"type": "github"
},
"original": {
"owner": "mozilla",
"repo": "nixpkgs-mozilla",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1701389149,
"narHash": "sha256-rU1suTIEd5DGCaAXKW6yHoCfR1mnYjOXQFOaH7M23js=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "5de0b32be6e85dc1a9404c75131316e4ffbc634c",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-23.11",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"mozilla-overlay": "mozilla-overlay",
"nixpkgs": "nixpkgs"
}
}
},
"root": "root",
"version": 7
}

172
flake.nix Normal file
View File

@ -0,0 +1,172 @@
{
description = "Bare-metal Rust on Zynq-7000";
inputs.nixpkgs.url = github:NixOS/nixpkgs/nixos-23.11;
inputs.mozilla-overlay = { url = github:mozilla/nixpkgs-mozilla; flake = false; };
outputs = { self, nixpkgs, mozilla-overlay }:
let
pkgs = import nixpkgs { system = "x86_64-linux"; overlays = [ (import mozilla-overlay) crosspkgs-overlay ]; };
rustManifest = pkgs.fetchurl {
url = "https://static.rust-lang.org/dist/2021-01-29/channel-rust-nightly.toml";
sha256 = "sha256-EZKgw89AH4vxaJpUHmIMzMW/80wAFQlfcxRoBD9nz0c=";
};
rustTargets = [];
rustChannelOfTargets = _channel: _date: targets:
(pkgs.lib.rustLib.fromManifestFile rustManifest {
inherit (pkgs) stdenv lib fetchurl patchelf;
}).rust.override {
inherit targets;
extensions = ["rust-src"];
};
rust = rustChannelOfTargets "nightly" null rustTargets;
rustPlatform = pkgs.recurseIntoAttrs (pkgs.makeRustPlatform {
rustc = rust;
cargo = rust;
});
crosspkgs-overlay = (self: super: {
pkgsCross = super.pkgsCross // {
zynq-baremetal = import super.path {
system = "x86_64-linux";
crossSystem = {
config = "arm-none-eabihf";
libc = "newlib";
gcc.cpu = "cortex-a9";
gcc.fpu = "vfpv3";
};
};
};
});
mkbootimage = pkgs.stdenv.mkDerivation {
pname = "mkbootimage";
version = "2.3dev";
src = pkgs.fetchFromGitHub {
owner = "antmicro";
repo = "zynq-mkbootimage";
rev = "872363ce32c249f8278cf107bc6d3bdeb38d849f";
sha256 = "sha256-5FPyAhUWZDwHbqmp9J2ZXTmjaXPz+dzrJMolaNwADHs=";
};
propagatedBuildInputs = [ pkgs.libelf pkgs.pcre ];
patchPhase =
''
substituteInPlace Makefile --replace "git rev-parse --short HEAD" "echo nix"
'';
installPhase =
''
mkdir -p $out/bin
cp mkbootimage $out/bin
'';
hardeningDisable = [ "fortify" ];
};
fsbl = { board ? "zc706" }: pkgs.stdenv.mkDerivation {
name = "${board}-fsbl";
src = pkgs.fetchFromGitHub {
owner = "Xilinx";
repo = "embeddedsw";
rev = "xilinx_v2022.2";
sha256 = "sha256-UDz9KK/Hw3qM1BAeKif30rE8Bi6C2uvuZlvyvtJCMfw=";
};
nativeBuildInputs = [
pkgs.pkgsCross.zynq-baremetal.buildPackages.binutils
pkgs.pkgsCross.zynq-baremetal.buildPackages.gcc
];
patchPhase = ''
patchShebangs lib/sw_apps/zynq_fsbl/misc/copy_bsp.sh
for x in lib/sw_apps/zynq_fsbl/src/Makefile lib/sw_apps/zynq_fsbl/misc/copy_bsp.sh lib/bsp/standalone/src/arm/cortexa9/gcc/Makefile; do
substituteInPlace $x \
--replace "arm-none-eabi-" "arm-none-eabihf-"
done
'';
buildPhase = ''
cd lib/sw_apps/zynq_fsbl/src
make BOARD=${board} "CFLAGS=-DFSBL_DEBUG_INFO -g"
'';
installPhase = ''
mkdir $out
cp fsbl.elf $out
'';
doCheck = false;
dontFixup = true;
};
cargo-xbuild = pkgs.cargo-xbuild.overrideAttrs(oa: {
postPatch = "substituteInPlace src/sysroot.rs --replace 2021 2018";
});
build-crate = name: crate: features: rustPlatform.buildRustPackage rec {
name = "${crate}";
src = builtins.filterSource (path: type:
baseNameOf path != "target"
) ./.;
cargoLock = { lockFile = ./Cargo.lock; };
nativeBuildInputs = [ cargo-xbuild pkgs.llvmPackages_14.clang-unwrapped ];
buildPhase = ''
export XARGO_RUST_SRC="${rust}/lib/rustlib/src/rust/library"
export CARGO_HOME=$(mktemp -d cargo-home.XXX)
pushd ${crate}
cargo xbuild --release --frozen \
--no-default-features \
--features=${features}
popd
'';
installPhase = ''
mkdir -p $out $out/nix-support
cp target/armv7-none-eabihf/release/${name} $out/${name}.elf
echo file binary-dist $out/${name}.elf >> $out/nix-support/hydra-build-products
'';
doCheck = false;
dontFixup = true;
auditable = false;
};
targetCrates = target: {
"${target}-experiments" = build-crate "${target}-experiments" "experiments" "target_${target}";
"${target}-szl" = build-crate "${target}-szl" "szl" "target_${target}";
};
targets = ["zc706" "coraz7" "redpitaya" "kasli_soc"];
allTargetCrates = (builtins.foldl' (results: target:
results // targetCrates target
) {} targets);
szl = pkgs.runCommand "szl" {} (builtins.foldl' (commands: target:
let
szlResult = builtins.getAttr "${target}-szl" allTargetCrates;
in
commands + "ln -s ${szlResult}/szl.elf $out/szl-${target}.elf\n"
) "mkdir $out\n" targets);
in rec {
packages.x86_64-linux = {
inherit cargo-xbuild szl mkbootimage;
zc706-fsbl = fsbl { board = "zc706"; };
} // allTargetCrates ;
hydraJobs = packages.x86_64-linux;
inherit rust rustPlatform;
devShell.x86_64-linux = pkgs.mkShell {
name = "zynq-rs-dev-shell";
buildInputs = [
rust
cargo-xbuild
mkbootimage
pkgs.openocd pkgs.gdb
pkgs.openssh pkgs.rsync
pkgs.llvmPackages_14.clang-unwrapped
(pkgs.python3.withPackages(ps: [ ps.pyftdi ]))
];
};
};
}

17
kasli_soc_por.py Normal file
View File

@ -0,0 +1,17 @@
from time import sleep
from pyftdi.ftdi import Ftdi
POR = 1 << 7
def main():
dev = Ftdi()
dev.open_bitbang_from_url("ftdi://ftdi:4232h/0")
dev.set_bitmode(POR, Ftdi.BitMode.BITBANG)
dev.write_data(bytes([0]))
sleep(0.1)
dev.write_data(bytes([POR]))
sleep(0.1)
dev.close()
if __name__ == "__main__":
main()

View File

@ -9,10 +9,10 @@ edition = "2018"
#futures = { version = "0.3", default-features = false }
pin-utils = "0.1.0-alpha.4"
embedded-hal = "0.2"
nb = "0.1"
nb = "1.0"
libcortex_a9 = { path = "../libcortex_a9" }
[dependencies.smoltcp]
version = "0.6"
version = "0.7"
default-features = false
features = ["alloc"]

View File

@ -7,17 +7,23 @@ use smoltcp::{
iface::EthernetInterface,
phy::Device,
socket::SocketSet,
time::Instant,
time::{Duration, Instant},
};
use crate::task;
mod tcp_stream;
pub use tcp_stream::TcpStream;
pub trait LinkCheck {
type Link;
fn is_idle(&self) -> bool;
fn check_link_change(&mut self) -> Option<Self::Link>;
}
static mut SOCKETS: Option<Sockets> = None;
pub struct Sockets {
sockets: RefCell<SocketSet<'static, 'static, 'static>>,
sockets: RefCell<SocketSet<'static>>,
wakers: RefCell<Vec<Waker>>,
}
@ -41,14 +47,24 @@ impl Sockets {
/// Block and run executor indefinitely while polling the smoltcp
/// iface
pub fn run<'b, 'c, 'e, D: for<'d> Device<'d>>(
iface: &mut EthernetInterface<'b, 'c, 'e, D>,
pub fn run<'b, D: for<'d> Device<'d> + LinkCheck>(
iface: &mut EthernetInterface<'b, D>,
mut get_time: impl FnMut() -> Instant,
) -> ! {
task::block_on(async {
let mut last_link_check = Instant::from_millis(0);
const LINK_CHECK_INTERVAL: u64 = 500;
loop {
let instant = get_time();
Self::instance().poll(iface, instant);
let dev = iface.device_mut();
if dev.is_idle() && instant >= last_link_check + Duration::from_millis(LINK_CHECK_INTERVAL) {
dev.check_link_change();
last_link_check = instant;
}
task::r#yield().await;
}
})
@ -58,9 +74,9 @@ impl Sockets {
unsafe { SOCKETS.as_ref().expect("Sockets") }
}
fn poll<'b, 'c, 'e, D: for<'d> Device<'d>>(
fn poll<'b, D: for<'d> Device<'d>>(
&self,
iface: &mut EthernetInterface<'b, 'c, 'e, D>,
iface: &mut EthernetInterface<'b, D>,
instant: Instant
) {
let processed = {

View File

@ -262,6 +262,14 @@ impl TcpStream {
pub fn set_timeout(&mut self, duration: Option<Duration>) {
self.with_socket(|mut socket| socket.set_timeout(duration));
}
pub fn ack_delay(&self) -> Option<Duration> {
self.with_socket(|socket| socket.ack_delay())
}
pub fn set_ack_delay(&mut self, duration: Option<Duration>) {
self.with_socket(|mut socket| socket.set_ack_delay(duration));
}
}
impl Drop for TcpStream {

View File

@ -7,8 +7,9 @@ edition = "2018"
[features]
target_zc706 = []
target_cora_z7_10 = []
target_coraz7 = []
target_redpitaya = []
target_kasli_soc = []
ipv6 = [ "smoltcp/proto-ipv6" ]
[dependencies]
@ -20,8 +21,9 @@ void = { version = "1", default-features = false }
log = "0.4"
libregister = { path = "../libregister" }
libcortex_a9 = { path = "../libcortex_a9" }
libasync = { path = "../libasync" }
[dependencies.smoltcp]
version = "0.6"
version = "0.7"
features = ["ethernet", "proto-ipv4", "socket-tcp"]
default-features = false

View File

@ -4,10 +4,12 @@ use super::slcr;
#[cfg(feature = "target_zc706")]
pub const PS_CLK: u32 = 33_333_333;
#[cfg(feature = "target_cora_z7_10")]
#[cfg(feature = "target_coraz7")]
pub const PS_CLK: u32 = 50_000_000;
#[cfg(feature = "target_redpitaya")]
pub const PS_CLK: u32 = 33_333_333;
#[cfg(feature = "target_kasli_soc")]
pub const PS_CLK: u32 = 33_333_333;
/// (pll_fdiv_max, (pll_cp, pll_res, lock_cnt))
const PLL_FDIV_LOCK_PARAM: &[(u16, (u8, u8, u16))] = &[
@ -57,7 +59,7 @@ pub trait ClockSource {
/// 25.10.4 PLLs
fn setup(target_freq: u32) {
let fdiv = (target_freq / PS_CLK).min(66) as u16;
let (pll_res, pll_cp, lock_cnt) = PLL_FDIV_LOCK_PARAM.iter()
let (pll_cp, pll_res, lock_cnt) = PLL_FDIV_LOCK_PARAM.iter()
.filter(|(fdiv_max, _)| fdiv <= *fdiv_max)
.nth(0)
.expect("PLL_FDIV_LOCK_PARAM")

View File

@ -1,7 +1,9 @@
use libregister::{RegisterR, RegisterW, RegisterRW};
use log::{debug, info, error};
use crate::{print, println};
use super::slcr::{self, DdriobVrefSel};
use super::slcr;
#[cfg(feature = "target_zc706")]
use super::slcr::DdriobVrefSel;
use super::clocks::{Clocks, source::{DdrPll, ClockSource}};
mod regs;
@ -10,16 +12,19 @@ mod regs;
/// Micron MT41J256M8HX-15E: 667 MHz DDR3
const DDR_FREQ: u32 = 666_666_666;
#[cfg(feature = "target_cora_z7_10")]
#[cfg(feature = "target_coraz7")]
/// Micron MT41K256M16HA-125: 800 MHz DDR3L, max supported 533 MHz
const DDR_FREQ: u32 = 525_000_000;
#[cfg(feature = "target_redpitaya")]
/// Alliance Memory AS4C256M16D3B: 800 MHz DDR3
const DDR_FREQ: u32 = 800_000_000;
/// Alliance Memory AS4C256M16D3B: 800 MHz DDR3 at 533 MHz
const DDR_FREQ: u32 = 533_333_333;
/// MT41K256M16HA-125
const DCI_FREQ: u32 = 10_000_000;
#[cfg(feature = "target_kasli_soc")]
/// MT41K256M16HA-125:E: 800 MHz DDR3L at 533 MHz
const DDR_FREQ: u32 = 533_333_333;
const DCI_MAX_FREQ: u32 = 10_000_000;
pub struct DdrRam {
regs: &'static mut regs::RegisterBlock,
@ -28,13 +33,11 @@ pub struct DdrRam {
impl DdrRam {
pub fn ddrram() -> Self {
let clocks = Self::clock_setup();
Self::calibrate_iob_impedance(&clocks);
Self::configure_iob();
Self::calibrate_iob_impedance(&clocks);
let regs = regs::RegisterBlock::ddrc();
let mut ddr = DdrRam { regs };
ddr.configure();
ddr.reset_ddrc();
ddr.reset_ddrc(|ddr| ddr.configure());
ddr
}
@ -61,7 +64,7 @@ impl DdrRam {
}
fn calculate_dci_divisors(clocks: &Clocks) -> (u8, u8) {
let target = (DCI_FREQ - 1 + clocks.ddr) / DCI_FREQ;
let target = (DCI_MAX_FREQ - 1 + clocks.ddr) / DCI_MAX_FREQ;
let mut best = None;
let mut best_error = 0;
@ -144,13 +147,13 @@ impl DdrRam {
.output_en(slcr::DdriobOutputEn::Obuf);
#[cfg(feature = "target_zc706")]
let data1_config = data0_config.clone();
#[cfg(feature = "target_cora_z7_10")]
#[cfg(any(feature = "target_coraz7", feature = "target_kasli_soc"))]
let data0_config = slcr::DdriobConfig::zeroed()
.inp_type(slcr::DdriobInputType::VrefDifferential)
.term_en(true)
.dci_type(slcr::DdriobDciType::Termination)
.output_en(slcr::DdriobOutputEn::Obuf);
#[cfg(feature = "target_cora_z7_10")]
#[cfg(any(feature = "target_coraz7", feature = "target_kasli_soc"))]
let data1_config = slcr::DdriobConfig::zeroed()
.pullup_en(true);
#[cfg(feature = "target_redpitaya")]
@ -173,13 +176,13 @@ impl DdrRam {
.output_en(slcr::DdriobOutputEn::Obuf);
#[cfg(feature = "target_zc706")]
let diff1_config = diff0_config.clone();
#[cfg(feature = "target_cora_z7_10")]
#[cfg(any(feature = "target_coraz7", feature = "target_kasli_soc"))]
let diff0_config = slcr::DdriobConfig::zeroed()
.inp_type(slcr::DdriobInputType::Differential)
.term_en(true)
.dci_type(slcr::DdriobDciType::Termination)
.output_en(slcr::DdriobOutputEn::Obuf);
#[cfg(feature = "target_cora_z7_10")]
#[cfg(any(feature = "target_coraz7", feature = "target_kasli_soc"))]
let diff1_config = slcr::DdriobConfig::zeroed()
.pullup_en(true);
#[cfg(feature = "target_redpitaya")]
@ -207,12 +210,12 @@ impl DdrRam {
slcr.ddriob_drive_slew_clock.write(0x00F9861C);
}
// Enable external V[REF]
#[cfg(feature = "target_cora_z7_10")]
#[cfg(any(feature = "target_coraz7", feature = "target_kasli_soc"))]
slcr.ddriob_ddr_ctrl.modify(|_, w| w
.vref_int_en(false)
.vref_ext_en_lower(true)
.vref_ext_en_upper(false)
.refio_en(true)
);
#[cfg(feature = "target_zc706")]
slcr.ddriob_ddr_ctrl.modify(|_, w| w
@ -226,17 +229,43 @@ impl DdrRam {
.vref_int_en(false)
.vref_ext_en_lower(true)
.vref_ext_en_upper(false)
.refio_en(true)
);
});
}
fn configure(&mut self) {
#[cfg(any(feature = "target_coraz7", feature = "target_kasli_soc"))]
self.regs.dram_param0.write(
regs::DramParam0::zeroed()
.t_rc(0x1a)
.t_rfc_min(0x9e)
.post_selfref_gap_x32(0x10)
);
#[cfg(feature = "target_redpitaya")]
self.regs.dram_param0.write(
regs::DramParam0::zeroed()
.t_rc(0x1b)
.t_rfc_min(0xa0)
.post_selfref_gap_x32(0x10)
);
#[cfg(feature = "target_zc706")]
self.regs.dram_param0.write(
regs::DramParam0::zeroed()
.t_rc(0x1b)
.t_rfc_min(0x56)
.post_selfref_gap_x32(0x10)
);
#[cfg(feature = "target_redpitaya")]
self.regs.dram_param1.modify(
|_, w| w
.wr2pre(0x12)
.powerdown_to_x32(6)
.t_faw(0x16)
.t_ras_max(0x24)
.t_ras_min(0x13)
.t_cke(4)
);
self.regs.dram_param2.write(
regs::DramParam2::zeroed()
@ -248,6 +277,20 @@ impl DdrRam {
.rd2pre(0x4)
.t_rcd(0x7)
);
#[cfg(feature = "target_redpitaya")]
self.regs.dram_param3.modify(
|_, w| w
.t_ccd(4)
.t_rrd(6)
.refresh_margin(2)
.t_rp(7)
.refresh_to_x32(8)
.mobile(false)
.dfi_dram_clk_disable(false)
.read_latency(7)
.mode_ddr1_ddr2(true)
.dis_pad_pd(false)
);
self.regs.dram_emr_mr.write(
regs::DramEmrMr::zeroed()
@ -255,6 +298,23 @@ impl DdrRam {
.emr(0x4)
);
#[cfg(any(feature = "target_coraz7", feature = "target_kasli_soc"))]
self.regs.phy_configs[2].modify(
|_, w| w.data_slice_in_use(false)
);
#[cfg(any(feature = "target_coraz7", feature = "target_kasli_soc"))]
self.regs.phy_configs[3].modify(
|_, w| w.data_slice_in_use(false)
);
#[cfg(feature = "target_redpitaya")]
self.regs.phy_configs[2].modify(
|_, w| w.data_slice_in_use(false)
);
#[cfg(feature = "target_redpitaya")]
self.regs.phy_configs[3].modify(
|_, w| w.data_slice_in_use(false)
);
self.regs.phy_cmd_timeout_rddata_cpt.modify(
|_, w| w
.rd_cmd_to_data(0x0)
@ -287,12 +347,32 @@ impl DdrRam {
.ctrlup_max(0x40)
);
self.regs.phy_init_ratio3.write(
#[cfg(feature = "target_zc706")]
self.regs.phy_init_ratios[3].write(
regs::PhyInitRatio::zeroed()
.wrlvl_init_ratio(0x21)
.gatelvl_init_ratio(0xee)
);
#[cfg(any(feature = "target_coraz7", feature = "target_kasli_soc"))]
self.regs.reg_64.modify(
|_, w| w
.phy_ctrl_slave_ratio(0x100)
.phy_invert_clkout(true)
);
#[cfg(feature = "target_redpitaya")]
self.regs.reg_64.modify(
|_, w| w
.phy_bl2(false)
.phy_invert_clkout(true)
.phy_sel_logic(false)
.phy_ctrl_slave_ratio(0x100)
.phy_ctrl_slave_force(false)
.phy_ctrl_slave_delay(0)
.phy_lpddr(false)
.phy_cmd_latency(false)
);
self.regs.reg_65.write(
regs::Reg65::zeroed()
.wr_rl_delay(0x2)
@ -307,18 +387,10 @@ impl DdrRam {
}
/// Reset DDR controller
fn reset_ddrc(&mut self) {
#[cfg(feature = "target_zc706")]
unsafe {
// row/column address bits
self.regs.dram_addr_map_bank.write(0x00000777);
self.regs.dram_addr_map_col.write(0xFFF00000);
self.regs.dram_addr_map_row.write(0x0F666666);
}
fn reset_ddrc<F: FnMut(&mut Self)>(&mut self, mut f: F) {
#[cfg(feature = "target_zc706")]
let width = regs::DataBusWidth::Width32bit;
#[cfg(feature = "target_cora_z7_10")]
#[cfg(any(feature = "target_coraz7", feature = "target_kasli_soc"))]
let width = regs::DataBusWidth::Width16bit;
#[cfg(feature = "target_redpitaya")]
let width = regs::DataBusWidth::Width16bit;
@ -327,6 +399,27 @@ impl DdrRam {
.powerdown_en(false)
.data_bus_width(width)
);
f(self);
#[cfg(feature = "target_zc706")]
unsafe {
// row/column address bits
self.regs.dram_addr_map_bank.write(0x00000777);
self.regs.dram_addr_map_col.write(0xFFF00000);
self.regs.dram_addr_map_row.write(0x0F666666);
}
#[cfg(any(
feature = "target_coraz7",
feature = "target_redpitaya",
feature = "target_kasli_soc",
))]
unsafe {
// row/column address bits
self.regs.dram_addr_map_bank.write(0x00000666);
self.regs.dram_addr_map_col.write(0xFFFF0000);
self.regs.dram_addr_map_row.write(0x0F555555);
}
self.regs.ddrc_ctrl.modify(|_, w| w
.soft_rstb(true)
.powerdown_en(false)
@ -347,12 +440,16 @@ impl DdrRam {
/// actually there's 1 MB more but starting at 0x0000_0000
/// overlaps with OCM.
pub fn size(&self) -> usize {
// DDR range ends at 0x3FFF_FFFF in the default SCU address
// filtering address map
#[cfg(feature = "target_zc706")]
let megabytes = 1023;
#[cfg(feature = "target_cora_z7_10")]
let megabytes = 511;
#[cfg(feature = "target_redpitaya")]
let megabytes = 511;
#[cfg(any(
feature = "target_coraz7",
feature = "target_redpitaya",
feature = "target_kasli_soc",
))]
let megabytes = 512;
megabytes * 1024 * 1024
}

View File

@ -33,14 +33,14 @@ pub struct RegisterBlock {
pub lpr: RW<u32>,
pub wr: RW<u32>,
pub dram_param0: DramParam0,
pub dram_param1: RW<u32>,
pub dram_param1: DramParam1,
pub dram_param2: DramParam2,
pub dram_param3: RW<u32>,
pub dram_param3: DramParam3,
pub dram_param4: RW<u32>,
pub dram_init_param: RW<u32>,
pub dram_emr: RW<u32>,
pub dram_emr_mr: DramEmrMr,
pub dram_burst8_rdwr: RW<u32>,
pub dram_burst8_rdwr: Burst8Rdwr,
pub dram_disable_dq: RW<u32>,
pub dram_addr_map_bank: RW<u32>,
pub dram_addr_map_col: RW<u32>,
@ -60,7 +60,7 @@ pub struct RegisterBlock {
pub ctrl6: RW<u32>,
_unused1: [RO<u32>; 8],
pub che_refresh_timer01: RW<u32>,
pub che_t_zq: RW<u32>,
pub che_t_zq: CheTZq,
pub che_t_zq_short_interval: RW<u32>,
pub deep_pwrdwn: RW<u32>,
pub reg_2c: Reg2C,
@ -84,15 +84,9 @@ pub struct RegisterBlock {
pub che_ecc_corr_bit_mask_63_32_offset: RW<u32>,
_unused3: [RO<u32>; 5],
pub phy_rcvr_enable: RW<u32>,
pub phy_config0: RW<u32>,
pub phy_config1: RW<u32>,
pub phy_config2: RW<u32>,
pub phy_config3: RW<u32>,
pub phy_configs: [PhyConfig; 4],
_unused4: RO<u32>,
pub phy_init_ratio0: PhyInitRatio,
pub phy_init_ratio1: PhyInitRatio,
pub phy_init_ratio2: PhyInitRatio,
pub phy_init_ratio3: PhyInitRatio,
pub phy_init_ratios: [PhyInitRatio; 4],
_unused5: RO<u32>,
pub phy_rd_dqs_cfg0: RW<u32>,
pub phy_rd_dqs_cfg1: RW<u32>,
@ -114,7 +108,7 @@ pub struct RegisterBlock {
pub wr_data_slv2: RW<u32>,
pub wr_data_slv3: RW<u32>,
_unused9: RO<u32>,
pub reg_64: RW<u32>,
pub reg_64: Reg64,
pub reg_65: Reg65,
_unused10: [RO<u32>; 3],
pub reg69_6a0: RW<u32>,
@ -138,14 +132,8 @@ pub struct RegisterBlock {
_unused14: [RO<u32>; 5],
pub axi_id: RW<u32>,
pub page_mask: RW<u32>,
pub axi_priority_wr_port0: RW<u32>,
pub axi_priority_wr_port1: RW<u32>,
pub axi_priority_wr_port2: RW<u32>,
pub axi_priority_wr_port3: RW<u32>,
pub axi_priority_rd_port0: RW<u32>,
pub axi_priority_rd_port1: RW<u32>,
pub axi_priority_rd_port2: RW<u32>,
pub axi_priority_rd_port3: RW<u32>,
pub axi_priority_wr_ports: [RW<u32>; 4],
pub axi_priority_rd_ports: [AxiPriorityRd; 4],
_unused15: [RO<u32>; 27],
pub excl_access_cfg0: RW<u32>,
pub excl_access_cfg1: RW<u32>,
@ -173,6 +161,14 @@ register_bits!(dram_param0, t_rc, u8, 0, 5);
register_bits!(dram_param0, t_rfc_min, u8, 6, 13);
register_bits!(dram_param0, post_selfref_gap_x32, u8, 14, 20);
register!(dram_param1, DramParam1, RW, u32);
register_bits!(dram_param1, wr2pre, u8, 0, 4);
register_bits!(dram_param1, powerdown_to_x32, u8, 5, 9);
register_bits!(dram_param1, t_faw, u8, 10, 15);
register_bits!(dram_param1, t_ras_max, u8, 16, 21);
register_bits!(dram_param1, t_ras_min, u8, 22, 26);
register_bits!(dram_param1, t_cke, u8, 28, 31);
register!(dram_param2, DramParam2, RW, u32);
register_bits!(dram_param2, write_latency, u8, 0, 4);
register_bits!(dram_param2, rd2wr, u8, 5, 9);
@ -182,10 +178,29 @@ register_bits!(dram_param2, pad_pd, u8, 20, 22);
register_bits!(dram_param2, rd2pre, u8, 23, 27);
register_bits!(dram_param2, t_rcd, u8, 28, 31);
register!(dram_param3, DramParam3, RW, u32);
register_bits!(dram_param3, t_ccd, u8, 2, 4);
register_bits!(dram_param3, t_rrd, u8, 5, 7);
register_bits!(dram_param3, refresh_margin, u8, 8, 11);
register_bits!(dram_param3, t_rp, u8, 12, 15);
register_bits!(dram_param3, refresh_to_x32, u8, 16, 20);
register_bit!(dram_param3, sdram, 21);
register_bit!(dram_param3, mobile, 22);
register_bit!(dram_param3, dfi_dram_clk_disable, 23);
register_bits!(dram_param3, read_latency, u8, 24, 28);
register_bit!(dram_param3, mode_ddr1_ddr2, 29);
register_bit!(dram_param3, dis_pad_pd, 30);
register!(dram_emr_mr, DramEmrMr, RW, u32);
register_bits!(dram_emr_mr, mr, u16, 0, 15);
register_bits!(dram_emr_mr, emr, u16, 16, 31);
register!(burst8_rdwr, Burst8Rdwr, RW, u32);
register_bits!(burst8_rdwr, burst_rdwr, u8, 0, 3);
register_bits!(burst8_rdwr, pre_cke_x1024, u16, 4, 13);
register_bits!(burst8_rdwr, post_cke_x1024, u16, 16, 25);
register_bit!(burst8_rdwr, burstchop, 28);
register!(phy_cmd_timeout_rddata_cpt, PhyCmdTimeoutRddataCpt, RW, u32);
register_bits!(phy_cmd_timeout_rddata_cpt, rd_cmd_to_data, u8, 0, 3);
register_bits!(phy_cmd_timeout_rddata_cpt, wr_cmd_to_data, u8, 4, 7);
@ -198,6 +213,13 @@ register_bit!(phy_cmd_timeout_rddata_cpt, clk_stall_level, 19);
register_bits!(phy_cmd_timeout_rddata_cpt, gatelvl_num_of_dq0, u8, 24, 27);
register_bits!(phy_cmd_timeout_rddata_cpt, wrlvl_num_of_dq0, u8, 28, 31);
register!(che_t_zq, CheTZq, RW, u32);
register_bit!(che_t_zq, dis_auto_zq, 0);
register_bit!(che_t_zq, ddr3, 1);
register_bits!(che_t_zq, t_mod, u8, 2, 11);
register_bits!(che_t_zq, t_zq_long_nop, u16, 12, 21);
register_bits!(che_t_zq, t_zq_short_nop, u16, 22, 31);
register!(reg_2c, Reg2C, RW, u32);
register_bits!(reg_2c, wrlvl_max_x1024, u16, 0, 11);
register_bits!(reg_2c, rdlvl_max_x1024, u16, 12, 23);
@ -212,10 +234,27 @@ register_bits!(dfi_timing, rddata_en, u8, 0, 4);
register_bits!(dfi_timing, ctrlup_min, u16, 5, 14);
register_bits!(dfi_timing, ctrlup_max, u16, 15, 24);
register!(phy_config, PhyConfig, RW, u32);
register_bit!(phy_config, data_slice_in_use, 0);
register_bit!(phy_config, rdlvl_inc_mode, 1);
register_bit!(phy_config, gatelvl_inc_mode, 2);
register_bit!(phy_config, wrlvl_inc_mode, 3);
register_bits!(phy_config, dq_offset, u8, 24, 30);
register!(phy_init_ratio, PhyInitRatio, RW, u32);
register_bits!(phy_init_ratio, wrlvl_init_ratio, u16, 0, 9);
register_bits!(phy_init_ratio, gatelvl_init_ratio, u16, 10, 19);
register!(reg_64, Reg64, RW, u32);
register_bit!(reg_64, phy_bl2, 1);
register_bit!(reg_64, phy_invert_clkout, 7);
register_bit!(reg_64, phy_sel_logic, 9);
register_bits!(reg_64, phy_ctrl_slave_ratio, u16, 10, 19);
register_bit!(reg_64, phy_ctrl_slave_force, 20);
register_bits!(reg_64, phy_ctrl_slave_delay, u8, 21, 27);
register_bit!(reg_64, phy_lpddr, 29);
register_bit!(reg_64, phy_cmd_latency, 30);
register!(reg_65, Reg65, RW, u32);
register_bits!(reg_65, wr_rl_delay, u8, 0, 4);
register_bits!(reg_65, rd_rl_delay, u8, 5, 9);
@ -231,3 +270,10 @@ register!(mode_sts_reg,
ModeStsReg, RO, u32);
register_bits_typed!(mode_sts_reg, operating_mode, u8, ControllerStatus, 0, 2);
// (mode_sts_reg) ...
register!(axi_priority_rd, AxiPriorityRd, RW, u32);
register_bits!(axi_priority_rd, arb_pri_rd_portn, u16, 0, 9);
register_bit!(axi_priority_rd, arb_disable_aging_rd_portn, 16);
register_bit!(axi_priority_rd, arb_disable_urgent_rd_portn, 17);
register_bit!(axi_priority_rd, arb_disable_page_match_rd_portn, 18);
register_bit!(axi_priority_rd, arb_set_hpr_rd_portn, 19);

View File

@ -0,0 +1,114 @@
use libregister::{RegisterRW, RegisterW};
use libregister::{register, register_at, register_bit, register_bits};
use super::slcr;
pub struct ErrorLED {
regs: RegisterBlock,
}
impl ErrorLED {
#[cfg(feature = "target_kasli_soc")]
pub fn error_led() -> Self {
slcr::RegisterBlock::unlocked(|slcr| {
// Error LED at MIO pin 37
slcr.mio_pin_37.write(
slcr::MioPin37::zeroed()
.l3_sel(0b000)
.io_type(slcr::IoBufferType::Lvcmos25)
.pullup(true)
.disable_rcvr(true)
);
});
Self::error_led_common(0xFFFF - 0x0080)
}
fn error_led_common(gpio_output_mask: u16) -> Self {
// Setup register block
let self_ = Self {
regs: RegisterBlock::error_led(),
};
// Setup GPIO output mask
self_.regs.gpio_output_mask.modify(|_, w| {
w.mask(gpio_output_mask)
});
self_.regs.gpio_direction.modify(|_, w| {
w.lederr(true)
});
self_
}
fn led_oe(&mut self, oe: bool) {
self.regs.gpio_output_enable.modify(|_, w| {
w.lederr(oe)
})
}
fn led_o(&mut self, o: bool) {
self.regs.gpio_output_mask.modify(|_, w| {
w.lederr_o(o)
})
}
pub fn toggle(&mut self, state: bool) {
self.led_o(state);
self.led_oe(state);
}
}
pub struct RegisterBlock {
pub gpio_output_mask: &'static mut GPIOOutputMask,
pub gpio_direction: &'static mut GPIODirection,
pub gpio_output_enable: &'static mut GPIOOutputEnable,
}
impl RegisterBlock {
pub fn error_led() -> Self {
Self {
gpio_output_mask: GPIOOutputMask::new(),
gpio_direction: GPIODirection::new(),
gpio_output_enable: GPIOOutputEnable::new()
}
}
}
register!(gpio_output_mask,
/// MASK_DATA_1_LSW:
/// Maskable output data for MIO[47:32]
GPIOOutputMask, RW, u32);
#[cfg(feature = "target_kasli_soc")]
register_at!(GPIOOutputMask, 0xE000A008, new);
#[cfg(feature = "target_kasli_soc")]
register_bit!(gpio_output_mask,
/// Output for LED_ERR (MIO[37])
lederr_o, 5);
#[cfg(feature = "target_kasli_soc")]
register_bits!(gpio_output_mask,
mask, u16, 16, 31);
register!(gpio_direction,
/// DIRM_1:
/// Direction mode for MIO[53:32]; 0/1 = in/out
GPIODirection, RW, u32);
#[cfg(feature = "target_kasli_soc")]
register_at!(GPIODirection, 0xE000A244, new);
#[cfg(feature = "target_kasli_soc")]
register_bit!(gpio_direction,
/// Direction for LED_ERR
lederr, 5);
register!(gpio_output_enable,
/// OEN_1:
/// Output enable for MIO[53:32]
GPIOOutputEnable, RW, u32);
#[cfg(feature = "target_kasli_soc")]
register_at!(GPIOOutputEnable, 0xE000A248, new);
#[cfg(feature = "target_kasli_soc")]
register_bit!(gpio_output_enable,
/// Output enable for LED_ERR
lederr, 5);

View File

@ -13,6 +13,9 @@ mod regs;
pub mod rx;
pub mod tx;
use super::time::Milliseconds;
use embedded_hal::timer::CountDown;
/// Size of all the buffers
pub const MTU: usize = 1536;
/// Maximum MDC clock
@ -145,6 +148,8 @@ pub struct Eth<GEM: Gem, RX, TX> {
tx: TX,
inner: EthInner<GEM>,
phy: Phy,
/// keep track of RX path occupation to avoid needless `check_link_change()`
idle: bool,
}
impl Eth<Gem0, (), ()> {
@ -298,22 +303,32 @@ impl<GEM: Gem> Eth<GEM, (), ()> {
fn gem_common(macaddr: [u8; 6]) -> Self {
GEM::setup_clock(TX_1000);
#[cfg(feature="target_kasli_soc")]
{
let mut eth_reset_pin = PhyRst::rst_pin();
eth_reset_pin.reset();
}
let mut inner = EthInner {
gem: PhantomData,
link: None,
};
inner.init();
inner.configure(macaddr);
let phy = Phy::find(&mut inner).expect("phy");
phy.reset(&mut inner);
phy.restart_autoneg(&mut inner);
#[cfg(feature="target_kasli_soc")]
phy.set_leds(&mut inner);
Eth {
rx: (),
tx: (),
inner,
phy,
idle: true,
}
}
}
@ -325,6 +340,7 @@ impl<GEM: Gem, RX, TX> Eth<GEM, RX, TX> {
tx: self.tx,
inner: self.inner,
phy: self.phy,
idle: self.idle,
};
let list_addr = new_self.rx.list_addr();
assert!(list_addr & 0b11 == 0);
@ -344,6 +360,7 @@ impl<GEM: Gem, RX, TX> Eth<GEM, RX, TX> {
tx: tx::DescList::new(tx_size),
inner: self.inner,
phy: self.phy,
idle: self.idle,
};
let list_addr = &new_self.tx.list_addr();
assert!(list_addr & 0b11 == 0);
@ -395,17 +412,31 @@ impl<GEM: Gem, TX> Eth<GEM, rx::DescList, TX> {
regs::RxStatus::zeroed()
.frame_recd(true)
);
self.idle = true;
}
_ => {}
_ =>
self.idle = false,
}
result
} else {
self.inner.check_link_change(&self.phy);
self.idle = true;
Ok(None)
}
}
}
impl<GEM: Gem, TX> libasync::smoltcp::LinkCheck for &mut Eth<GEM, rx::DescList, TX> {
type Link = Option<phy::Link>;
fn check_link_change(&mut self) -> Option<Self::Link> {
self.inner.check_link_change(&self.phy)
}
fn is_idle(&self) -> bool {
self.idle
}
}
impl<GEM: Gem, RX> Eth<GEM, RX, tx::DescList> {
pub fn send<'s: 'p, 'p>(&'s mut self, length: usize) -> Option<tx::PktRef<'p>> {
self.tx.send(GEM::regs(), length)
@ -439,10 +470,11 @@ impl<'a, GEM: Gem> smoltcp::phy::Device<'a> for &mut Eth<GEM, rx::DescList, tx::
regs: GEM::regs(),
desc_list: &mut self.tx,
};
self.idle = false;
Some((pktref, tx_token))
}
Ok(None) => {
self.inner.check_link_change(&self.phy);
self.idle = true;
None
}
Err(e) => {
@ -460,6 +492,69 @@ impl<'a, GEM: Gem> smoltcp::phy::Device<'a> for &mut Eth<GEM, rx::DescList, tx::
}
}
pub struct PhyRst {
regs: regs::GpioRegisterBlock,
count_down: super::timer::global::CountDown<Milliseconds>,
}
impl PhyRst {
pub fn rst_pin() -> Self {
slcr::RegisterBlock::unlocked(|slcr| {
// Hardware Reset for PHY
slcr.mio_pin_47.write(
slcr::MioPin47::zeroed()
.l3_sel(0b000)
.io_type(slcr::IoBufferType::Lvcmos18)
.pullup(true)
.disable_rcvr(true)
);
});
Self::eth_reset_common(0xFFFF - 0x8000)
}
fn delay_ms(&mut self, ms: u64) {
self.count_down.start(Milliseconds(ms));
nb::block!(self.count_down.wait()).unwrap();
}
fn eth_reset_common(gpio_output_mask: u16) -> Self {
let self_ = Self {
regs: regs::GpioRegisterBlock::regs(),
count_down: unsafe { super::timer::GlobalTimer::get() }.countdown(),
};
// Setup GPIO output mask
self_.regs.gpio_output_mask.modify(|_, w| {
w.mask(gpio_output_mask)
});
self_.regs.gpio_direction.modify(|_, w| {
w.phy_rst(true)
});
self_
}
fn oe(&mut self, oe: bool) {
self.regs.gpio_output_enable.modify(|_, w| {
w.phy_rst(oe)
})
}
fn toggle(&mut self, o: bool) {
self.regs.gpio_output_mask.modify(|_, w| {
w.phy_rst(o)
})
}
pub fn reset(&mut self) {
self.toggle(false); // drive phy_rst (active LOW) pin low
self.oe(true); // enable pin's output
self.delay_ms(10);
self.toggle(true);
}
}
struct EthInner<GEM: Gem> {
gem: PhantomData<GEM>,
@ -602,13 +697,7 @@ impl<GEM: Gem> EthInner<GEM> {
}
fn check_link_change(&mut self, phy: &Phy) {
// As the PHY access takes some time, exit early if there was
// already a link. TODO: check once per second.
if self.link.is_some() {
return
}
fn check_link_change(&mut self, phy: &Phy) -> Option<Option<phy::Link>> {
let link = phy.get_link(self);
// Check link state transition
@ -640,6 +729,9 @@ impl<GEM: Gem> EthInner<GEM> {
}
self.link = link;
Some(link)
} else {
None
}
}
}

View File

@ -82,6 +82,10 @@ impl PhyRegister for Control {
fn addr() -> u8 {
0
}
fn page() -> u8 {
0
}
}
impl From<u16> for Control {

View File

@ -11,6 +11,9 @@ pub struct PhyIdentifier {
}
pub fn identify_phy<PA: PhyAccess>(pa: &mut PA, addr: u8) -> Option<PhyIdentifier> {
#[cfg(feature = "target_kasli_soc")]
pa.write_phy(addr, 0x16, 0); //reset page
let id1 = pa.read_phy(addr, 2);
let id2 = pa.read_phy(addr, 3);
if id1 != 0xFFFF || id2 != 0xFFFF {

View File

@ -0,0 +1,79 @@
use bit_field::BitField;
use super::{PhyRegister, Led0Control, Led1Control};
#[derive(Clone, Copy, Debug)]
/// LED Control Register
pub struct Leds(pub u16);
impl Leds {
pub fn led0(&self) -> Led0Control {
match self.0.get_bits(0..=3) {
0b0000 => Led0Control::OnLinkOffNoLink,
0b0001 => Led0Control::OnLinkBlinkActivityOffNoLink,
0b0010 => Led0Control::BlinkDependingOnLink,
0b0011 => Led0Control::OnActivityOffNoActivity,
0b0100 => Led0Control::BlinkActivityOffNoActivity,
0b0101 => Led0Control::OnTransmitOffNoTransmit,
0b0110 => Led0Control::OnCopperLinkOffElse,
0b0111 => Led0Control::On1000LinkOffElse,
0b1000 => Led0Control::ForceOff,
0b1001 => Led0Control::ForceOn,
0b1010 => Led0Control::ForceHiZ,
0b1011 => Led0Control::ForceBlink,
0b1100 => Led0Control::Mode1,
0b1101 => Led0Control::Mode2,
0b1110 => Led0Control::Mode3,
0b1111 => Led0Control::Mode4,
_ => unreachable!()
}
}
pub fn led1(&self) -> Led1Control {
match self.0.get_bits(4..=7) {
0b0000 => Led1Control::OnReceiveOffNoReceive,
0b0001 => Led1Control::OnLinkBlinkActivityOffNoLink,
0b0010 => Led1Control::OnLinkBlinkReceiveOffNoLink,
0b0011 => Led1Control::OnActivityOffNoActivity,
0b0100 => Led1Control::BlinkActivityOffNoActivity,
0b0101 => Led1Control::On100OrFiberOffElse,
0b0110 => Led1Control::On1001000LinkOffElse,
0b0111 => Led1Control::On100LinkOffElse,
0b1000 => Led1Control::ForceOff,
0b1001 => Led1Control::ForceOn,
0b1010 => Led1Control::ForceHiZ,
0b1011 => Led1Control::ForceBlink,
_ => unreachable!()
}
}
pub fn set_led0(mut self, setting: Led0Control) -> Self {
self.0.set_bits(0..=3, setting as u16);
self
}
pub fn set_led1(mut self, setting: Led1Control) -> Self {
self.0.set_bits(4..=7, setting as u16);
self
}
}
impl PhyRegister for Leds {
fn addr() -> u8 {
0x10
}
fn page() -> u8 {
3
}
}
impl From<u16> for Leds {
fn from(value: u16) -> Self {
Leds(value)
}
}
impl Into<u16> for Leds {
fn into(self) -> u16 {
self.0
}
}

View File

@ -6,8 +6,10 @@ mod control;
pub use control::Control;
mod pssr;
pub use pssr::PSSR;
mod leds;
pub use leds::Leds;
#[derive(Clone, Debug, PartialEq)]
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Link {
pub speed: LinkSpeed,
pub duplex: LinkDuplex,
@ -26,51 +28,98 @@ pub enum LinkDuplex {
Full,
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Led0Control {
OnLinkOffNoLink = 0b0000,
OnLinkBlinkActivityOffNoLink = 0b0001,
BlinkDependingOnLink = 0b0010,
OnActivityOffNoActivity = 0b0011,
BlinkActivityOffNoActivity = 0b0100,
OnTransmitOffNoTransmit = 0b0101,
OnCopperLinkOffElse = 0b0110,
On1000LinkOffElse = 0b0111,
ForceOff = 0b1000,
ForceOn = 0b1001,
ForceHiZ = 0b1010,
ForceBlink = 0b1011,
Mode1 = 0b1100,
Mode2 = 0b1101,
Mode3 = 0b1110,
Mode4 = 0b1111
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Led1Control {
OnReceiveOffNoReceive = 0b0000,
OnLinkBlinkActivityOffNoLink = 0b0001,
OnLinkBlinkReceiveOffNoLink = 0b0010,
OnActivityOffNoActivity = 0b0011,
BlinkActivityOffNoActivity = 0b0100,
On100OrFiberOffElse = 0b0101,
On1001000LinkOffElse = 0b0110,
On100LinkOffElse = 0b0111,
ForceOff = 0b1000,
ForceOn = 0b1001,
ForceHiZ = 0b1010,
ForceBlink = 0b1011,
}
pub trait PhyAccess {
fn read_phy(&mut self, addr: u8, reg: u8) -> u16;
fn write_phy(&mut self, addr: u8, reg: u8, data: u16);
}
pub trait PhyRegister {
fn addr() -> u8;
fn page() -> u8;
}
#[derive(Clone)]
pub struct Phy {
pub addr: u8,
device: PhyDevice,
}
#[derive(Clone, Copy)]
pub enum PhyDevice {
Marvell88E1116R,
Rtl8211E,
}
const OUI_MARVELL: u32 = 0x005043;
const OUI_REALTEK: u32 = 0x000732;
const OUI_LANTIQ : u32 = 0x355969;
//only change pages on Kasli-SoC's Marvel 88E11xx
#[cfg(feature="target_kasli_soc")]
const PAGE_REGISTER: u8 = 0x16;
impl Phy {
/// Probe all addresses on MDIO for a known PHY
pub fn find<PA: PhyAccess>(pa: &mut PA) -> Option<Phy> {
(1..32).filter_map(|addr| {
match identify_phy(pa, addr) {
(0..32).find(|addr| {
match identify_phy(pa, *addr) {
Some(PhyIdentifier {
oui: OUI_MARVELL,
// Marvell 88E1116R
model: 36,
..
}) => Some(PhyDevice::Marvell88E1116R),
}) => true,
Some(PhyIdentifier {
oui: OUI_MARVELL,
// Marvell 88E1512
model: 29,
..
}) => true,
Some(PhyIdentifier {
oui: OUI_REALTEK,
// RTL 8211E
model: 0b010001,
rev: 0b0101,
}) => Some(PhyDevice::Rtl8211E),
_ => None,
}.map(|device| Phy { addr, device })
}).next()
}
pub fn name(&self) -> &'static str {
match self.device {
PhyDevice::Marvell88E1116R => &"Marvell 88E1116R",
PhyDevice::Rtl8211E => &"RTL8211E",
}
}) => true,
Some(PhyIdentifier {
oui: OUI_LANTIQ,
// Intel XWAY PHY11G (PEF 7071/PEF 7072) v1.5 / v1.6
model: 0,
..
}) => true,
_ => false,
}
}).map(|addr| Phy { addr })
}
pub fn read_reg<PA, PR>(&self, pa: &mut PA) -> PR
@ -78,6 +127,9 @@ impl Phy {
PA: PhyAccess,
PR: PhyRegister + From<u16>,
{
#[cfg(feature="target_kasli_soc")]
pa.write_phy(self.addr, PAGE_REGISTER, PR::page().into());
pa.read_phy(self.addr, PR::addr()).into()
}
@ -87,6 +139,9 @@ impl Phy {
PR: PhyRegister + From<u16> + Into<u16>,
F: FnMut(PR) -> PR,
{
#[cfg(feature="target_kasli_soc")]
pa.write_phy(self.addr, PAGE_REGISTER, PR::page().into());
let reg = pa.read_phy(self.addr, PR::addr()).into();
let reg = f(reg);
pa.write_phy(self.addr, PR::addr(), reg.into())
@ -100,6 +155,14 @@ impl Phy {
self.modify_reg(pa, f)
}
pub fn modify_leds<PA, F>(&self, pa: &mut PA, f: F)
where
PA: PhyAccess,
F: FnMut(Leds) -> Leds,
{
self.modify_reg(pa, f)
}
pub fn get_control<PA: PhyAccess>(&self, pa: &mut PA) -> Control {
self.read_reg(pa)
}
@ -133,8 +196,12 @@ impl Phy {
.set_restart_autoneg(true)
);
}
}
pub trait PhyRegister {
fn addr() -> u8;
#[cfg(feature="target_kasli_soc")]
pub fn set_leds<PA: PhyAccess>(&self, pa: &mut PA) {
self.modify_leds(pa, |leds|
leds.set_led0(Led0Control::OnCopperLinkOffElse)
.set_led1(Led1Control::BlinkActivityOffNoActivity)
);
}
}

View File

@ -43,6 +43,10 @@ impl PhyRegister for PSSR {
fn addr() -> u8 {
0x11
}
fn page() -> u8 {
0
}
}
impl From<u16> for PSSR {

View File

@ -100,6 +100,10 @@ impl PhyRegister for Status {
fn addr() -> u8 {
1
}
fn page() -> u8 {
0
}
}
impl From<u16> for Status {

View File

@ -110,6 +110,49 @@ pub struct RegisterBlock {
pub design_cfg5: RO<u32>,
}
pub struct GpioRegisterBlock {
pub gpio_output_mask: &'static mut OutputMask,
pub gpio_direction: &'static mut Direction,
pub gpio_output_enable: &'static mut OutputEnable,
}
impl GpioRegisterBlock {
pub fn regs() -> Self {
Self {
gpio_output_mask: OutputMask::new(),
gpio_direction: Direction::new(),
gpio_output_enable: OutputEnable::new(),
}
}
}
register!(gpio_output_mask,
/// MASK_DATA_1_SW:
/// Maskable output data for MIO[47:32]
OutputMask, RW, u32);
register_at!(OutputMask, 0xE000A008, new);
register_bit!(gpio_output_mask,
/// Output for PHY_RST (MIO[47])
phy_rst, 15);
register_bits!(gpio_output_mask,
mask, u16, 16, 31);
register!(gpio_direction,
/// DIRM_1:
/// Direction mode for MIO[53:32]; 0/1 = in/out
Direction, RW, u32);
register_at!(Direction, 0xE000A244, new);
register_bit!(gpio_direction,
/// Direction for PHY_RST
phy_rst, 15);
register!(gpio_output_enable,
/// OEN_1:
/// Output enable for MIO[53:32]
OutputEnable, RW, u32);
register_at!(OutputEnable, 0xE000A248, new);
register_bit!(gpio_output_enable,
/// Output enable for PHY_RST
phy_rst, 15);
register_at!(RegisterBlock, 0xE000B000, gem0);
register_at!(RegisterBlock, 0xE000C000, gem1);

View File

@ -115,7 +115,7 @@ impl InterruptController {
let m = (id.0 >> 2) as usize;
let n = (8 * (id.0 & 3)) as usize;
unsafe {
self.mpcore.icdiptr[m].modify(|mut icdiptr| *icdiptr.set_bits(n..=n+1, target_cpu as u32 + 1));
self.mpcore.icdiptr[m].modify(|mut icdiptr| *icdiptr.set_bits(n..=n+1, target_cpu as u32));
}
// sensitivity

View File

@ -22,10 +22,27 @@ impl<'a> EEPROM<'a> {
}
}
#[cfg(feature = "target_kasli_soc")]
pub fn new(i2c: &'a mut I2c, page_size: u8) -> Self {
EEPROM {
i2c: i2c,
port: 3,
address: 0x57,
page_size: page_size,
count_down: unsafe { crate::timer::GlobalTimer::get() }.countdown()
}
}
#[cfg(feature = "target_zc706")]
fn select(&mut self) -> Result<(), &'static str> {
let mask: u16 = 1 << self.port;
self.i2c.pca9548_select(0b1110100, mask as u8)?;
self.i2c.pca954x_select(0b1110100, Some(self.port))?;
Ok(())
}
#[cfg(feature = "target_kasli_soc")]
fn select(&mut self) -> Result<(), &'static str> {
// tca9548 is compatible with pca9548
self.i2c.pca954x_select(0b1110001, Some(self.port))?;
Ok(())
}

View File

@ -6,14 +6,23 @@ use super::slcr;
use super::time::Microseconds;
use embedded_hal::timer::CountDown;
use libregister::{RegisterR, RegisterRW, RegisterW};
#[cfg(feature = "target_kasli_soc")]
use log::info;
pub enum I2cMultiplexer {
PCA9548 = 0,
#[cfg(feature = "target_kasli_soc")]
PCA9547 = 1,
}
pub struct I2c {
regs: regs::RegisterBlock,
count_down: super::timer::global::CountDown<Microseconds>
count_down: super::timer::global::CountDown<Microseconds>,
pca_type: I2cMultiplexer
}
impl I2c {
#[cfg(feature = "target_zc706")]
#[cfg(any(feature = "target_zc706", feature = "target_kasli_soc"))]
pub fn i2c0() -> Self {
// Route I2C 0 SCL / SDA Signals to MIO Pins 50 / 51
slcr::RegisterBlock::unlocked(|slcr| {
@ -33,18 +42,28 @@ impl I2c {
.pullup(true)
.disable_rcvr(true)
);
// Reset
slcr.gpio_rst_ctrl.reset_gpio();
// On Kasli-SoC prototype, leakage through the unconfigured I2C_SW_RESET
// MIO pin develops enough voltage on the T21 gate to assert the reset.
// Configure the pin to avoid this problem.
#[cfg(feature = "target_kasli_soc")]
slcr.mio_pin_33.write(
slcr::MioPin33::zeroed()
.l3_sel(0b000)
.io_type(slcr::IoBufferType::Lvcmos33)
.pullup(false)
.disable_rcvr(true)
);
});
Self::i2c_common(0xFFFF - 0x000C)
Self::i2c_common(0xFFFF - 0x000C, 0xFFFF - 0x0002)
}
fn i2c_common(gpio_output_mask: u16) -> Self {
fn i2c_common(gpio_output_mask: u16, _gpio_output_mask_lower: u16) -> Self {
// Setup register block
let self_ = Self {
regs: regs::RegisterBlock::i2c(),
count_down: unsafe { super::timer::GlobalTimer::get() }.countdown()
count_down: unsafe { super::timer::GlobalTimer::get() }.countdown(),
pca_type: I2cMultiplexer::PCA9548 //default for zc706
};
// Setup GPIO output mask
@ -56,6 +75,17 @@ impl I2c {
w.scl(true).sda(true)
});
//Kasli-SoC only: I2C_SW_RESET configuration
#[cfg(feature = "target_kasli_soc")]
{
self_.regs.gpio_output_mask_lower.modify(|_, w| {
w.mask(_gpio_output_mask_lower)
});
self_.regs.gpio_direction.modify(|_, w| {
w.i2cswr(true)
});
}
self_
}
@ -65,7 +95,7 @@ impl I2c {
nb::block!(self.count_down.wait()).unwrap();
}
fn half_period(&mut self) { self.delay_us(100) }
fn unit_delay(&mut self) { self.delay_us(100) }
fn sda_i(&mut self) -> bool {
self.regs.gpio_input.read().sda()
@ -99,6 +129,48 @@ impl I2c {
})
}
#[cfg(feature = "target_kasli_soc")]
fn i2cswr_oe(&mut self, oe: bool) {
self.regs.gpio_output_enable.modify(|_, w| {
w.i2cswr(oe)
})
}
#[cfg(feature = "target_kasli_soc")]
fn i2cswr_o(&mut self, o: bool) {
self.regs.gpio_output_mask_lower.modify(|_, w| {
w.i2cswr_o(o)
})
}
#[cfg(feature = "target_kasli_soc")]
fn pca_autodetect(&mut self) -> Result<I2cMultiplexer, &'static str> {
// start with resetting the PCA954X
// SDA must be clear (before start)
// reset time is 500ns, unit_delay (100us) to account for propagation
self.i2cswr_o(true);
self.unit_delay();
self.i2cswr_o(false);
self.unit_delay();
let pca954x_read_addr = (0x71 << 1) | 0x01;
self.start()?;
// read the config register
if !self.write(pca954x_read_addr)? {
return Err("PCA954X failed to ack read address");
}
let config = self.read(false)?;
let pca = match config {
0x00 => { info!("PCA9548 detected"); I2cMultiplexer::PCA9548 },
0x08 => { info!("PCA9547 detected"); I2cMultiplexer::PCA9547 },
_ => { return Err("Unknown response for PCA954X autodetect")},
};
self.stop()?;
Ok(pca)
}
pub fn init(&mut self) -> Result<(), &'static str> {
self.scl_oe(false);
self.sda_oe(false);
@ -106,15 +178,15 @@ impl I2c {
self.sda_o(false);
// Check the I2C bus is ready
self.half_period();
self.half_period();
self.unit_delay();
self.unit_delay();
if !self.sda_i() {
// Try toggling SCL a few times
for _bit in 0..8 {
self.scl_oe(true);
self.half_period();
self.unit_delay();
self.scl_oe(false);
self.half_period();
self.unit_delay();
}
}
@ -122,23 +194,31 @@ impl I2c {
return Err("SDA is stuck low and doesn't get unstuck");
}
if !self.scl_i() {
return Err("SCL is stuck low and doesn't get unstuck");
return Err("SCL is stuck low");
}
// postcondition: SCL and SDA high
#[cfg(feature = "target_kasli_soc")]
{
self.i2cswr_oe(true);
self.pca_type = self.pca_autodetect()?;
}
Ok(())
}
pub fn start(&mut self) -> Result<(), &'static str> {
// precondition: SCL and SDA high
if !self.scl_i() {
return Err("SCL is stuck low and doesn't get unstuck");
return Err("SCL is stuck low");
}
if !self.sda_i() {
return Err("SDA arbitration lost");
}
self.sda_oe(true);
self.half_period();
self.unit_delay();
self.scl_oe(true);
self.unit_delay();
// postcondition: SCL and SDA low
Ok(())
}
@ -146,9 +226,9 @@ impl I2c {
pub fn restart(&mut self) -> Result<(), &'static str> {
// precondition SCL and SDA low
self.sda_oe(false);
self.half_period();
self.unit_delay();
self.scl_oe(false);
self.half_period();
self.unit_delay();
self.start()?;
// postcondition: SCL and SDA low
Ok(())
@ -156,11 +236,11 @@ impl I2c {
pub fn stop(&mut self) -> Result<(), &'static str> {
// precondition: SCL and SDA low
self.half_period();
self.unit_delay();
self.scl_oe(false);
self.half_period();
self.unit_delay();
self.sda_oe(false);
self.half_period();
self.unit_delay();
if !self.sda_i() {
return Err("SDA arbitration lost");
}
@ -173,18 +253,20 @@ impl I2c {
// MSB first
for bit in (0..8).rev() {
self.sda_oe(data & (1 << bit) == 0);
self.half_period();
self.unit_delay();
self.scl_oe(false);
self.half_period();
self.unit_delay();
self.scl_oe(true);
self.unit_delay();
}
self.sda_oe(false);
self.half_period();
self.unit_delay();
self.scl_oe(false);
self.half_period();
self.unit_delay();
// Read ack/nack
let ack = !self.sda_i();
self.scl_oe(true);
self.unit_delay();
self.sda_oe(true);
// postcondition: SCL and SDA low
@ -199,17 +281,17 @@ impl I2c {
// MSB first
for bit in (0..8).rev() {
self.half_period();
self.unit_delay();
self.scl_oe(false);
self.half_period();
self.unit_delay();
if self.sda_i() { data |= 1 << bit }
self.scl_oe(true);
}
// Send ack/nack
// Send ack/nack (true = nack, false = ack)
self.sda_oe(ack);
self.half_period();
self.unit_delay();
self.scl_oe(false);
self.half_period();
self.unit_delay();
self.scl_oe(true);
self.sda_oe(true);
// postcondition: SCL and SDA low
@ -217,13 +299,32 @@ impl I2c {
Ok(data)
}
pub fn pca9548_select(&mut self, address: u8, channels: u8) -> Result<(), &'static str> {
pub fn pca954x_select(&mut self, address: u8, channel: Option<u8>) -> Result<(), &'static str> {
self.start()?;
// PCA9547 supports only one channel at a time
// for compatibility, PCA9548 is treated as such too
// channel - Some(x) - # of the channel [0,7], or None for all disabled
let setting = match self.pca_type {
I2cMultiplexer::PCA9548 => {
match channel {
Some(ch) => 1 << ch,
None => 0,
}
},
#[cfg(feature = "target_kasli_soc")]
I2cMultiplexer::PCA9547 => {
match channel {
Some(ch) => ch | 0x08,
None => 0,
}
}
};
if !self.write(address << 1)? {
return Err("PCA9548 failed to ack write address")
return Err("PCA954X failed to ack write address")
}
if !self.write(channels)? {
return Err("PCA9548 failed to ack control word")
if !self.write(setting)? {
return Err("PCA954X failed to ack control word")
}
self.stop()?;
Ok(())

View File

@ -20,12 +20,15 @@ use libregister::{
//
// Current compatibility:
// zc706: GPIO 50, 51 == SCL, SDA
// kasli_soc: GPIO 50, 51 == SCL, SDA; GPIO 33 == I2C_SW_RESET
pub struct RegisterBlock {
pub gpio_output_mask: &'static mut GPIOOutputMask,
pub gpio_input: &'static mut GPIOInput,
pub gpio_direction: &'static mut GPIODirection,
pub gpio_output_enable: &'static mut GPIOOutputEnable,
#[cfg(feature = "target_kasli_soc")]
pub gpio_output_mask_lower: &'static mut GPIOOutputMaskLower,
}
impl RegisterBlock {
@ -34,58 +37,98 @@ impl RegisterBlock {
gpio_output_mask: GPIOOutputMask::new(),
gpio_input: GPIOInput::new(),
gpio_direction: GPIODirection::new(),
gpio_output_enable: GPIOOutputEnable::new()
gpio_output_enable: GPIOOutputEnable::new(),
#[cfg(feature = "target_kasli_soc")]
gpio_output_mask_lower: GPIOOutputMaskLower::new(),
}
}
}
// MASK_DATA_1_MSW:
// Maskable output data for MIO[53:48]
register!(gpio_output_mask, GPIOOutputMask, RW, u32);
#[cfg(feature = "target_zc706")]
register!(gpio_output_mask,
/// MASK_DATA_1_MSW:
/// Maskable output data for MIO[53:48]
GPIOOutputMask, RW, u32);
#[cfg(any(feature = "target_zc706", feature = "target_kasli_soc"))]
register_at!(GPIOOutputMask, 0xE000A00C, new);
// Output for SCL
#[cfg(feature = "target_zc706")]
register_bit!(gpio_output_mask, scl_o, 2);
// Output for SDA
#[cfg(feature = "target_zc706")]
register_bit!(gpio_output_mask, sda_o, 3);
// Mask for keeping bits except SCL and SDA unchanged
#[cfg(feature = "target_zc706")]
register_bits!(gpio_output_mask, mask, u16, 16, 31);
#[cfg(any(feature = "target_zc706", feature = "target_kasli_soc"))]
register_bit!(gpio_output_mask,
/// Output for SCL
scl_o, 2);
#[cfg(any(feature = "target_zc706", feature = "target_kasli_soc"))]
register_bit!(gpio_output_mask,
/// Output for SDA
sda_o, 3);
#[cfg(any(feature = "target_zc706", feature = "target_kasli_soc"))]
register_bits!(gpio_output_mask,
/// Mask for keeping bits except SCL and SDA unchanged
mask, u16, 16, 31);
// DATA_1_RO:
// Input data for MIO[53:32]
register!(gpio_input, GPIOInput, RO, u32);
#[cfg(feature = "target_zc706")]
register!(gpio_output_mask_lower,
/// MASK_DATA_1_LSW:
/// Maskable output data for MIO[47:32]
GPIOOutputMaskLower, RW, u32);
#[cfg(feature = "target_kasli_soc")]
register_at!(GPIOOutputMaskLower, 0xE000A008, new);
#[cfg(feature = "target_kasli_soc")]
register_bit!(gpio_output_mask_lower,
/// Output for I2C_SW_RESET (MIO[33])
i2cswr_o, 1);
#[cfg(feature = "target_kasli_soc")]
register_bits!(gpio_output_mask_lower,
mask, u16, 16, 31);
register!(gpio_input,
/// DATA_1_RO:
/// Input data for MIO[53:32]
GPIOInput, RO, u32);
#[cfg(any(feature = "target_zc706", feature = "target_kasli_soc"))]
register_at!(GPIOInput, 0xE000A064, new);
// Input for SCL
#[cfg(feature = "target_zc706")]
register_bit!(gpio_input, scl, 18);
// Input for SDA
#[cfg(feature = "target_zc706")]
register_bit!(gpio_input, sda, 19);
#[cfg(any(feature = "target_zc706", feature = "target_kasli_soc"))]
register_bit!(gpio_input,
/// Input for SCL
scl, 18);
#[cfg(any(feature = "target_zc706", feature = "target_kasli_soc"))]
register_bit!(gpio_input,
/// Input for SDA
sda, 19);
// DIRM_1:
// Direction mode for MIO[53:32]; 0/1 = in/out
register!(gpio_direction, GPIODirection, RW, u32);
#[cfg(feature = "target_zc706")]
register!(gpio_direction,
/// DIRM_1:
/// Direction mode for MIO[53:32]; 0/1 = in/out
GPIODirection, RW, u32);
#[cfg(any(feature = "target_zc706", feature = "target_kasli_soc"))]
register_at!(GPIODirection, 0xE000A244, new);
// Direction for SCL
#[cfg(feature = "target_zc706")]
register_bit!(gpio_direction, scl, 18);
// Direction for SDA
#[cfg(feature = "target_zc706")]
register_bit!(gpio_direction, sda, 19);
#[cfg(any(feature = "target_zc706", feature = "target_kasli_soc"))]
register_bit!(gpio_direction,
/// Direction for SCL
scl, 18);
#[cfg(any(feature = "target_zc706", feature = "target_kasli_soc"))]
register_bit!(gpio_direction,
/// Direction for SDA
sda, 19);
#[cfg(feature = "target_kasli_soc")]
register_bit!(gpio_direction,
/// Direction for I2C_SW_RESET
i2cswr, 1);
// OEN_1:
// Output enable for MIO[53:32]
register!(gpio_output_enable, GPIOOutputEnable, RW, u32);
#[cfg(feature = "target_zc706")]
register!(gpio_output_enable,
/// OEN_1:
/// Output enable for MIO[53:32]
GPIOOutputEnable, RW, u32);
#[cfg(any(feature = "target_zc706", feature = "target_kasli_soc"))]
register_at!(GPIOOutputEnable, 0xE000A248, new);
// Output enable for SCL
#[cfg(feature = "target_zc706")]
register_bit!(gpio_output_enable, scl, 18);
// Output enable for SDA
#[cfg(feature = "target_zc706")]
register_bit!(gpio_output_enable, sda, 19);
#[cfg(any(feature = "target_zc706", feature = "target_kasli_soc"))]
register_bit!(gpio_output_enable,
/// Output enable for SCL
scl, 18);
#[cfg(any(feature = "target_zc706", feature = "target_kasli_soc"))]
register_bit!(gpio_output_enable,
/// Output enable for SDA
sda, 19);
#[cfg(feature = "target_kasli_soc")]
register_bit!(gpio_output_enable,
/// Output enable for I2C_SW_RESET
i2cswr, 1);

View File

@ -19,7 +19,9 @@ pub mod gic;
pub mod time;
pub mod timer;
pub mod sdio;
#[cfg(feature = "target_zc706")]
#[cfg(any(feature = "target_zc706", feature = "target_kasli_soc"))]
pub mod i2c;
pub mod logger;
pub mod ps7_init;
#[cfg(feature="target_kasli_soc")]
pub mod error_led;

View File

@ -1,14 +1,14 @@
#![cfg(feature = "target_zc706")]
use crate::println;
#[cfg(feature = "target_zc706")]
mod zc706;
// mod cora_z7_10;
#[cfg(not(feature = "target_zc706"))]
mod none;
#[cfg(feature = "target_zc706")]
use zc706 as target;
// #[cfg(feature = "target_cora_z7_10")]
// use cora_z7_10 as target;
#[cfg(not(feature = "target_zc706"))]
use none as target;
pub fn report_differences() {
for (i, op) in target::INIT_DATA.iter().enumerate() {

View File

@ -0,0 +1,4 @@
use super::InitOp;
pub const INIT_DATA: &'static [InitOp] = &[
];

View File

@ -105,7 +105,7 @@ impl Sdio {
);
}
// cora card detect pin
#[cfg(feature = "target_cora_z7_10")]
#[cfg(feature = "target_coraz7")]
{
unsafe {
slcr.sd0_wp_cd_sel.write(47 << 16);
@ -117,7 +117,7 @@ impl Sdio {
);
}
// redpitaya card detect pin
#[cfg(feature = "target_redpitaya")]
#[cfg(any(feature = "target_redpitaya", feature = "target_kasli_soc"))]
{
unsafe {
slcr.sd0_wp_cd_sel.write(46 << 16);

View File

@ -587,6 +587,17 @@ register_bit!(a9_cpu_rst_ctrl, a9_clkstop0, 4);
register_bit!(a9_cpu_rst_ctrl, a9_rst1, 1);
register_bit!(a9_cpu_rst_ctrl, a9_rst0, 0);
pub fn reboot() {
RegisterBlock::unlocked(|slcr| {
unsafe {
let reboot = slcr.reboot_status.read();
slcr.reboot_status.write(reboot & 0xF0FFFFFF);
slcr.pss_rst_ctrl.modify(|_, w| w.soft_rst(true));
}
});
}
#[derive(Clone, Copy, Debug, PartialEq)]
#[repr(u8)]
pub enum BootModePins {
@ -605,7 +616,7 @@ register_bit!(boot_mode, jtag_routing, 3);
register_bits_typed!(boot_mode, boot_mode_pins, u8, BootModePins, 0, 2);
register!(pss_rst_ctrl, PssRstCtrl, RW, u32);
register_bit!(pss_rst_ctrl, soft_rst, 1);
register_bit!(pss_rst_ctrl, soft_rst, 0);
/// Used for MioPin*.io_type
#[repr(u8)]

View File

@ -45,9 +45,9 @@ impl DerefMut for LazyUart {
fn deref_mut(&mut self) -> &mut Uart {
match self {
LazyUart::Uninitialized => {
#[cfg(any(feature = "target_cora_z7_10", feature = "target_redpitaya"))]
#[cfg(any(feature = "target_coraz7", feature = "target_redpitaya"))]
let uart = Uart::uart0(UART_RATE);
#[cfg(feature = "target_zc706")]
#[cfg(any(feature = "target_zc706", feature = "target_kasli_soc"))]
let uart = Uart::uart1(UART_RATE);
*self = LazyUart::Initialized(uart);
self

View File

@ -13,7 +13,7 @@ pub struct Uart {
}
impl Uart {
#[cfg(any(feature = "target_cora_z7_10", feature = "target_redpitaya"))]
#[cfg(any(feature = "target_coraz7", feature = "target_redpitaya"))]
pub fn uart0(baudrate: u32) -> Self {
slcr::RegisterBlock::unlocked(|slcr| {
// Route UART 0 RxD/TxD Signals to MIO Pins
@ -46,7 +46,7 @@ impl Uart {
self_
}
#[cfg(feature = "target_zc706")]
#[cfg(any(feature = "target_zc706", feature = "target_kasli_soc"))]
pub fn uart1(baudrate: u32) -> Self {
slcr::RegisterBlock::unlocked(|slcr| {
// Route UART 1 RxD/TxD Signals to MIO Pins

View File

@ -11,5 +11,9 @@ fatfs = { version = "0.3", features = ["core_io"], default-features = false }
log = "0.4"
[features]
target_zc706 = []
target_coraz7 = []
target_redpitaya = []
target_kasli_soc = []
ipv6 = []
fat_lfn = [ "fatfs/alloc" ]

View File

@ -3,7 +3,7 @@ extern crate alloc;
use core::fmt;
use alloc::{string::FromUtf8Error, string::String, vec::Vec, rc::Rc};
use core_io::{self as io, BufRead, BufReader, Read};
use core_io::{self as io, BufRead, BufReader, Read, Write, Seek, SeekFrom};
use libboard_zynq::sdio;
pub mod sd_reader;
@ -56,9 +56,9 @@ fn parse_config<'a>(
buffer: &mut Vec<u8>,
file: fatfs::File<sd_reader::SdReader>,
) -> Result<'a, ()> {
let prefix = [key, "="].concat();
let prefix = [key, "="].concat().to_ascii_lowercase();
for line in BufReader::new(file).lines() {
let line = line?;
let line = line?.to_ascii_lowercase();
if line.starts_with(&prefix) {
buffer.extend(line[prefix.len()..].as_bytes());
return Ok(());
@ -71,6 +71,8 @@ pub struct Config {
fs: Option<Rc<fatfs::FileSystem<sd_reader::SdReader>>>,
}
const NEWLINE: &[u8] = b"\n";
impl Config {
pub fn new() -> Result<'static, Self> {
let sdio = sdio::Sdio::sdio0(true);
@ -112,4 +114,61 @@ impl Config {
pub fn read_str<'b>(&self, key: &'b str) -> Result<'b, String> {
Ok(String::from_utf8(self.read(key)?)?)
}
pub fn remove<'b>(&self, key: &'b str) -> Result<'b, ()> {
if let Some(fs) = &self.fs {
let root_dir = fs.root_dir();
match root_dir.remove(&["/CONFIG/", key, ".BIN"].concat()) {
Ok(()) => Ok(()),
Err(_) => {
let prefix = [key, "="].concat().to_ascii_lowercase();
match root_dir.create_file("/CONFIG.TXT") {
Ok(mut f) => {
let mut buffer = String::new();
f.read_to_string(&mut buffer)?;
f.seek(SeekFrom::Start(0))?;
f.truncate()?;
for line in buffer.lines() {
if line.len() > 0 && !line.to_ascii_lowercase().starts_with(&prefix) {
f.write(line.as_bytes())?;
f.write(NEWLINE)?;
}
}
Ok(())
},
Err(_) => Err(Error::KeyNotFoundError(key))
}
}
}
} else {
Err(Error::NoConfig)
}
}
pub fn write<'b>(&self, key: &'b str, value: Vec<u8>) -> Result<'b, ()> {
if self.fs.is_none() {
return Err(Error::NoConfig);
}
let fs = self.fs.as_ref().unwrap();
let root_dir = fs.root_dir();
let is_str = value.len() <= 100 && value.is_ascii() && !value.contains(&b'\n');
if key == "boot" {
let mut f = root_dir.create_file("/BOOT.BIN")?;
f.truncate()?;
f.write_all(&value)?;
drop(f);
} else {
let _ = self.remove(key);
if is_str {
let mut f = root_dir.create_file("/CONFIG.TXT")?;
f.seek(SeekFrom::End(0))?;
write!(f, "{}={}\n", key, String::from_utf8(value).unwrap())?;
} else {
let dir = root_dir.create_dir("/CONFIG")?;
let mut f = dir.create_file(&[key, ".BIN"].concat())?;
f.write_all(&value)?;
}
}
Ok(())
}
}

View File

@ -30,9 +30,35 @@ impl fmt::Display for NetAddresses {
}
}
pub fn get_adresses(cfg: &Config) -> NetAddresses {
#[cfg(feature = "target_kasli_soc")]
fn get_address_from_eeprom() -> EthernetAddress {
use libboard_zynq::i2c::{I2c, eeprom};
let mut i2c = I2c::i2c0();
i2c.init().unwrap();
let mut eeprom = eeprom::EEPROM::new(&mut i2c, 16);
let address = eeprom.read_eui48().unwrap_or([0x02, 0x00, 0x00, 0x00, 0x00, 0x56]);
EthernetAddress(address)
}
pub fn get_addresses(cfg: &Config) -> NetAddresses {
#[cfg(feature = "target_zc706")]
let mut hardware_addr = EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x52]);
#[cfg(feature = "target_zc706")]
let mut ipv4_addr = IpAddress::v4(192, 168, 1, 52);
#[cfg(feature = "target_coraz7")]
let mut hardware_addr = EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x54]);
#[cfg(feature = "target_coraz7")]
let mut ipv4_addr = IpAddress::v4(192, 168, 1, 54);
#[cfg(feature = "target_redpitaya")]
let mut hardware_addr = EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x55]);
#[cfg(feature = "target_redpitaya")]
let mut ipv4_addr = IpAddress::v4(192, 168, 1, 55);
#[cfg(feature = "target_kasli_soc")]
let mut hardware_addr = get_address_from_eeprom();
#[cfg(feature = "target_kasli_soc")]
let mut ipv4_addr = IpAddress::v4(192, 168, 1, 56);
if let Ok(Ok(addr)) = cfg.read_str("mac").map(|s| s.parse()) {
hardware_addr = addr;
@ -41,7 +67,7 @@ pub fn get_adresses(cfg: &Config) -> NetAddresses {
ipv4_addr = addr;
}
#[cfg(feature = "ipv6")]
let ipv6_addr = cfg.read_str("ipv6").ok().and_then(|s| s.parse().ok());
let ipv6_addr = cfg.read_str("ip6").ok().and_then(|s| s.parse().ok());
#[cfg(feature = "ipv6")]
let ipv6_ll_addr = IpAddress::v6(

View File

@ -10,6 +10,7 @@ const PARTID_FAT16_LESS32M: u8 = 0x04;
const PARTID_FAT16: u8 = 0x06;
const PARTID_FAT32: u8 = 0x0B;
const PARTID_FAT32_LBA: u8 = 0x0C;
const PARTID_FAT16_LBA: u8 = 0x0E;
fn cmd_error_to_io_error(_: CmdTransferError) -> Error {
Error::new(ErrorKind::Other, "Command transfer error")
@ -161,7 +162,7 @@ impl SdReader {
debug!("Partition ID: {:0X}", buffer[0]);
match buffer[0] {
PARTID_FAT12 | PARTID_FAT16_LESS32M | PARTID_FAT16 |
PARTID_FAT32 | PARTID_FAT32_LBA => {}
PARTID_FAT16_LBA | PARTID_FAT32 | PARTID_FAT32_LBA => {}
_ => {
return Err(Error::new(
ErrorKind::InvalidData,

View File

@ -1,14 +0,0 @@
[package]
authors = ["M-Labs"]
name = "core_io"
version = "0.1.20200410"
[lib]
name = "core_io"
[dependencies]
memchr = { version = "2", default-features = false, optional = true }
[features]
alloc = []
collections = ["alloc", "memchr"]

File diff suppressed because it is too large Load Diff

View File

@ -1,896 +0,0 @@
use crate::io::prelude::*;
use core::cmp;
use crate::io::{self, Error, ErrorKind, Initializer, SeekFrom};
#[cfg(feature = "collections")]
use core::convert::TryInto;
#[cfg(feature="collections")]
use collections::vec::Vec;
#[cfg(feature = "alloc")]
use alloc::boxed::Box;
/// A `Cursor` wraps an in-memory buffer and provides it with a
/// [`Seek`] implementation.
///
/// `Cursor`s are used with in-memory buffers, anything implementing
/// `AsRef<[u8]>`, to allow them to implement [`Read`] and/or [`Write`],
/// allowing these buffers to be used anywhere you might use a reader or writer
/// that does actual I/O.
///
/// The standard library implements some I/O traits on various types which
/// are commonly used as a buffer, like `Cursor<`[`Vec`]`<u8>>` and
/// `Cursor<`[`&[u8]`][bytes]`>`.
///
/// # Examples
///
/// We may want to write bytes to a [`File`] in our production
/// code, but use an in-memory buffer in our tests. We can do this with
/// `Cursor`:
///
/// [`Seek`]: trait.Seek.html
/// [`Read`]: ../../std/io/trait.Read.html
/// [`Write`]: ../../std/io/trait.Write.html
/// [`Vec`]: ../../std/vec/struct.Vec.html
/// [bytes]: ../../std/primitive.slice.html
/// [`File`]: ../fs/struct.File.html
///
/// ```no_run
/// use std::io::prelude::*;
/// use std::io::{self, SeekFrom};
/// use std::fs::File;
///
/// // a library function we've written
/// fn write_ten_bytes_at_end<W: Write + Seek>(writer: &mut W) -> io::Result<()> {
/// writer.seek(SeekFrom::End(-10))?;
///
/// for i in 0..10 {
/// writer.write(&[i])?;
/// }
///
/// // all went well
/// Ok(())
/// }
///
/// # fn foo() -> io::Result<()> {
/// // Here's some code that uses this library function.
/// //
/// // We might want to use a BufReader here for efficiency, but let's
/// // keep this example focused.
/// let mut file = File::create("foo.txt")?;
///
/// write_ten_bytes_at_end(&mut file)?;
/// # Ok(())
/// # }
///
/// // now let's write a test
/// #[test]
/// fn test_writes_bytes() {
/// // setting up a real File is much slower than an in-memory buffer,
/// // let's use a cursor instead
/// use std::io::Cursor;
/// let mut buff = Cursor::new(vec![0; 15]);
///
/// write_ten_bytes_at_end(&mut buff).unwrap();
///
/// assert_eq!(&buff.get_ref()[5..15], &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
/// }
/// ```
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct Cursor<T> {
inner: T,
pos: u64,
}
impl<T> Cursor<T> {
/// Creates a new cursor wrapping the provided underlying in-memory buffer.
///
/// Cursor initial position is `0` even if underlying buffer (e.g., `Vec`)
/// is not empty. So writing to cursor starts with overwriting `Vec`
/// content, not with appending to it.
///
/// # Examples
///
/// ```
/// use std::io::Cursor;
///
/// let buff = Cursor::new(Vec::new());
/// # fn force_inference(_: &Cursor<Vec<u8>>) {}
/// # force_inference(&buff);
/// ```
pub fn new(inner: T) -> Cursor<T> {
Cursor { pos: 0, inner }
}
/// Consumes this cursor, returning the underlying value.
///
/// # Examples
///
/// ```
/// use std::io::Cursor;
///
/// let buff = Cursor::new(Vec::new());
/// # fn force_inference(_: &Cursor<Vec<u8>>) {}
/// # force_inference(&buff);
///
/// let vec = buff.into_inner();
/// ```
pub fn into_inner(self) -> T {
self.inner
}
/// Gets a reference to the underlying value in this cursor.
///
/// # Examples
///
/// ```
/// use std::io::Cursor;
///
/// let buff = Cursor::new(Vec::new());
/// # fn force_inference(_: &Cursor<Vec<u8>>) {}
/// # force_inference(&buff);
///
/// let reference = buff.get_ref();
/// ```
pub fn get_ref(&self) -> &T {
&self.inner
}
/// Gets a mutable reference to the underlying value in this cursor.
///
/// Care should be taken to avoid modifying the internal I/O state of the
/// underlying value as it may corrupt this cursor's position.
///
/// # Examples
///
/// ```
/// use std::io::Cursor;
///
/// let mut buff = Cursor::new(Vec::new());
/// # fn force_inference(_: &Cursor<Vec<u8>>) {}
/// # force_inference(&buff);
///
/// let reference = buff.get_mut();
/// ```
pub fn get_mut(&mut self) -> &mut T {
&mut self.inner
}
/// Returns the current position of this cursor.
///
/// # Examples
///
/// ```
/// use std::io::Cursor;
/// use std::io::prelude::*;
/// use std::io::SeekFrom;
///
/// let mut buff = Cursor::new(vec![1, 2, 3, 4, 5]);
///
/// assert_eq!(buff.position(), 0);
///
/// buff.seek(SeekFrom::Current(2)).unwrap();
/// assert_eq!(buff.position(), 2);
///
/// buff.seek(SeekFrom::Current(-1)).unwrap();
/// assert_eq!(buff.position(), 1);
/// ```
pub fn position(&self) -> u64 {
self.pos
}
/// Sets the position of this cursor.
///
/// # Examples
///
/// ```
/// use std::io::Cursor;
///
/// let mut buff = Cursor::new(vec![1, 2, 3, 4, 5]);
///
/// assert_eq!(buff.position(), 0);
///
/// buff.set_position(2);
/// assert_eq!(buff.position(), 2);
///
/// buff.set_position(4);
/// assert_eq!(buff.position(), 4);
/// ```
pub fn set_position(&mut self, pos: u64) {
self.pos = pos;
}
}
impl<T> io::Seek for Cursor<T>
where
T: AsRef<[u8]>,
{
fn seek(&mut self, style: SeekFrom) -> io::Result<u64> {
let (base_pos, offset) = match style {
SeekFrom::Start(n) => {
self.pos = n;
return Ok(n);
}
SeekFrom::End(n) => (self.inner.as_ref().len() as u64, n),
SeekFrom::Current(n) => (self.pos, n),
};
let new_pos = if offset >= 0 {
base_pos.checked_add(offset as u64)
} else {
base_pos.checked_sub((offset.wrapping_neg()) as u64)
};
match new_pos {
Some(n) => {
self.pos = n;
Ok(self.pos)
}
None => Err(Error::new(
ErrorKind::InvalidInput,
"invalid seek to a negative or overflowing position",
)),
}
}
fn stream_len(&mut self) -> io::Result<u64> {
Ok(self.inner.as_ref().len() as u64)
}
fn stream_position(&mut self) -> io::Result<u64> {
Ok(self.pos)
}
}
impl<T> Read for Cursor<T>
where
T: AsRef<[u8]>,
{
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let n = Read::read(&mut self.get_ref().as_ref(), buf)?;
self.pos += n as u64;
Ok(n)
}
fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
let n = buf.len();
Read::read_exact(&mut self.get_ref().as_ref(), buf)?;
self.pos += n as u64;
Ok(())
}
#[inline]
unsafe fn initializer(&self) -> Initializer {
Initializer::nop()
}
}
#[cfg(feature = "collections")]
impl<T> BufRead for Cursor<T>
where
T: AsRef<[u8]>,
{
fn fill_buf(&mut self) -> io::Result<&[u8]> {
let amt = cmp::min(self.pos, self.inner.as_ref().len() as u64);
Ok(&self.inner.as_ref()[(amt as usize)..])
}
fn consume(&mut self, amt: usize) {
self.pos += amt as u64;
}
}
// Non-resizing write implementation
#[inline]
fn slice_write(pos_mut: &mut u64, slice: &mut [u8], buf: &[u8]) -> io::Result<usize> {
let pos = cmp::min(*pos_mut, slice.len() as u64);
let amt = (&mut slice[(pos as usize)..]).write(buf)?;
*pos_mut += amt as u64;
Ok(amt)
}
// Resizing write implementation
#[cfg(feature = "collections")]
fn vec_write(pos_mut: &mut u64, vec: &mut Vec<u8>, buf: &[u8]) -> io::Result<usize> {
let pos: usize = (*pos_mut).try_into().map_err(|_| {
Error::new(
ErrorKind::InvalidInput,
"cursor position exceeds maximum possible vector length",
)
})?;
// Make sure the internal buffer is as least as big as where we
// currently are
let len = vec.len();
if len < pos {
// use `resize` so that the zero filling is as efficient as possible
vec.resize(pos, 0);
}
// Figure out what bytes will be used to overwrite what's currently
// there (left), and what will be appended on the end (right)
{
let space = vec.len() - pos;
let (left, right) = buf.split_at(cmp::min(space, buf.len()));
vec[pos..pos + left.len()].copy_from_slice(left);
vec.extend_from_slice(right);
}
// Bump us forward
*pos_mut = (pos + buf.len()) as u64;
Ok(buf.len())
}
impl Write for Cursor<&mut [u8]> {
#[inline]
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
slice_write(&mut self.pos, self.inner, buf)
}
#[inline]
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
#[cfg(feature = "collections")]
impl Write for Cursor<&mut Vec<u8>> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
vec_write(&mut self.pos, self.inner, buf)
}
#[inline]
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
#[cfg(feature = "collections")]
impl Write for Cursor<Vec<u8>> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
vec_write(&mut self.pos, &mut self.inner, buf)
}
#[inline]
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
#[cfg(feature = "alloc")]
impl Write for Cursor<Box<[u8]>> {
#[inline]
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
slice_write(&mut self.pos, &mut self.inner, buf)
}
#[inline]
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
#[cfg(test)]
mod tests {
use crate::io::prelude::*;
use crate::io::{Cursor, IoSlice, IoSliceMut, SeekFrom};
#[test]
fn test_vec_writer() {
let mut writer = Vec::new();
assert_eq!(writer.write(&[0]).unwrap(), 1);
assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3);
assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4);
assert_eq!(
writer
.write_vectored(&[IoSlice::new(&[]), IoSlice::new(&[8, 9]), IoSlice::new(&[10])],)
.unwrap(),
3
);
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
assert_eq!(writer, b);
}
#[test]
fn test_mem_writer() {
let mut writer = Cursor::new(Vec::new());
assert_eq!(writer.write(&[0]).unwrap(), 1);
assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3);
assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4);
assert_eq!(
writer
.write_vectored(&[IoSlice::new(&[]), IoSlice::new(&[8, 9]), IoSlice::new(&[10])],)
.unwrap(),
3
);
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
assert_eq!(&writer.get_ref()[..], b);
}
#[test]
fn test_mem_mut_writer() {
let mut vec = Vec::new();
let mut writer = Cursor::new(&mut vec);
assert_eq!(writer.write(&[0]).unwrap(), 1);
assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3);
assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4);
assert_eq!(
writer
.write_vectored(&[IoSlice::new(&[]), IoSlice::new(&[8, 9]), IoSlice::new(&[10])],)
.unwrap(),
3
);
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
assert_eq!(&writer.get_ref()[..], b);
}
#[test]
fn test_box_slice_writer() {
let mut writer = Cursor::new(vec![0u8; 9].into_boxed_slice());
assert_eq!(writer.position(), 0);
assert_eq!(writer.write(&[0]).unwrap(), 1);
assert_eq!(writer.position(), 1);
assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3);
assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4);
assert_eq!(writer.position(), 8);
assert_eq!(writer.write(&[]).unwrap(), 0);
assert_eq!(writer.position(), 8);
assert_eq!(writer.write(&[8, 9]).unwrap(), 1);
assert_eq!(writer.write(&[10]).unwrap(), 0);
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8];
assert_eq!(&**writer.get_ref(), b);
}
#[test]
fn test_box_slice_writer_vectored() {
let mut writer = Cursor::new(vec![0u8; 9].into_boxed_slice());
assert_eq!(writer.position(), 0);
assert_eq!(writer.write_vectored(&[IoSlice::new(&[0])]).unwrap(), 1);
assert_eq!(writer.position(), 1);
assert_eq!(
writer
.write_vectored(&[IoSlice::new(&[1, 2, 3]), IoSlice::new(&[4, 5, 6, 7]),])
.unwrap(),
7,
);
assert_eq!(writer.position(), 8);
assert_eq!(writer.write_vectored(&[]).unwrap(), 0);
assert_eq!(writer.position(), 8);
assert_eq!(writer.write_vectored(&[IoSlice::new(&[8, 9])]).unwrap(), 1);
assert_eq!(writer.write_vectored(&[IoSlice::new(&[10])]).unwrap(), 0);
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8];
assert_eq!(&**writer.get_ref(), b);
}
#[test]
fn test_buf_writer() {
let mut buf = [0 as u8; 9];
{
let mut writer = Cursor::new(&mut buf[..]);
assert_eq!(writer.position(), 0);
assert_eq!(writer.write(&[0]).unwrap(), 1);
assert_eq!(writer.position(), 1);
assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3);
assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4);
assert_eq!(writer.position(), 8);
assert_eq!(writer.write(&[]).unwrap(), 0);
assert_eq!(writer.position(), 8);
assert_eq!(writer.write(&[8, 9]).unwrap(), 1);
assert_eq!(writer.write(&[10]).unwrap(), 0);
}
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8];
assert_eq!(buf, b);
}
#[test]
fn test_buf_writer_vectored() {
let mut buf = [0 as u8; 9];
{
let mut writer = Cursor::new(&mut buf[..]);
assert_eq!(writer.position(), 0);
assert_eq!(writer.write_vectored(&[IoSlice::new(&[0])]).unwrap(), 1);
assert_eq!(writer.position(), 1);
assert_eq!(
writer
.write_vectored(&[IoSlice::new(&[1, 2, 3]), IoSlice::new(&[4, 5, 6, 7])],)
.unwrap(),
7,
);
assert_eq!(writer.position(), 8);
assert_eq!(writer.write_vectored(&[]).unwrap(), 0);
assert_eq!(writer.position(), 8);
assert_eq!(writer.write_vectored(&[IoSlice::new(&[8, 9])]).unwrap(), 1);
assert_eq!(writer.write_vectored(&[IoSlice::new(&[10])]).unwrap(), 0);
}
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8];
assert_eq!(buf, b);
}
#[test]
fn test_buf_writer_seek() {
let mut buf = [0 as u8; 8];
{
let mut writer = Cursor::new(&mut buf[..]);
assert_eq!(writer.position(), 0);
assert_eq!(writer.write(&[1]).unwrap(), 1);
assert_eq!(writer.position(), 1);
assert_eq!(writer.seek(SeekFrom::Start(2)).unwrap(), 2);
assert_eq!(writer.position(), 2);
assert_eq!(writer.write(&[2]).unwrap(), 1);
assert_eq!(writer.position(), 3);
assert_eq!(writer.seek(SeekFrom::Current(-2)).unwrap(), 1);
assert_eq!(writer.position(), 1);
assert_eq!(writer.write(&[3]).unwrap(), 1);
assert_eq!(writer.position(), 2);
assert_eq!(writer.seek(SeekFrom::End(-1)).unwrap(), 7);
assert_eq!(writer.position(), 7);
assert_eq!(writer.write(&[4]).unwrap(), 1);
assert_eq!(writer.position(), 8);
}
let b: &[_] = &[1, 3, 2, 0, 0, 0, 0, 4];
assert_eq!(buf, b);
}
#[test]
fn test_buf_writer_error() {
let mut buf = [0 as u8; 2];
let mut writer = Cursor::new(&mut buf[..]);
assert_eq!(writer.write(&[0]).unwrap(), 1);
assert_eq!(writer.write(&[0, 0]).unwrap(), 1);
assert_eq!(writer.write(&[0, 0]).unwrap(), 0);
}
#[test]
fn test_mem_reader() {
let mut reader = Cursor::new(vec![0, 1, 2, 3, 4, 5, 6, 7]);
let mut buf = [];
assert_eq!(reader.read(&mut buf).unwrap(), 0);
assert_eq!(reader.position(), 0);
let mut buf = [0];
assert_eq!(reader.read(&mut buf).unwrap(), 1);
assert_eq!(reader.position(), 1);
let b: &[_] = &[0];
assert_eq!(buf, b);
let mut buf = [0; 4];
assert_eq!(reader.read(&mut buf).unwrap(), 4);
assert_eq!(reader.position(), 5);
let b: &[_] = &[1, 2, 3, 4];
assert_eq!(buf, b);
assert_eq!(reader.read(&mut buf).unwrap(), 3);
let b: &[_] = &[5, 6, 7];
assert_eq!(&buf[..3], b);
assert_eq!(reader.read(&mut buf).unwrap(), 0);
}
#[test]
fn test_mem_reader_vectored() {
let mut reader = Cursor::new(vec![0, 1, 2, 3, 4, 5, 6, 7]);
let mut buf = [];
assert_eq!(reader.read_vectored(&mut [IoSliceMut::new(&mut buf)]).unwrap(), 0);
assert_eq!(reader.position(), 0);
let mut buf = [0];
assert_eq!(
reader
.read_vectored(&mut [IoSliceMut::new(&mut []), IoSliceMut::new(&mut buf),])
.unwrap(),
1,
);
assert_eq!(reader.position(), 1);
let b: &[_] = &[0];
assert_eq!(buf, b);
let mut buf1 = [0; 4];
let mut buf2 = [0; 4];
assert_eq!(
reader
.read_vectored(&mut [IoSliceMut::new(&mut buf1), IoSliceMut::new(&mut buf2),])
.unwrap(),
7,
);
let b1: &[_] = &[1, 2, 3, 4];
let b2: &[_] = &[5, 6, 7];
assert_eq!(buf1, b1);
assert_eq!(&buf2[..3], b2);
assert_eq!(reader.read(&mut buf).unwrap(), 0);
}
#[test]
fn test_boxed_slice_reader() {
let mut reader = Cursor::new(vec![0, 1, 2, 3, 4, 5, 6, 7].into_boxed_slice());
let mut buf = [];
assert_eq!(reader.read(&mut buf).unwrap(), 0);
assert_eq!(reader.position(), 0);
let mut buf = [0];
assert_eq!(reader.read(&mut buf).unwrap(), 1);
assert_eq!(reader.position(), 1);
let b: &[_] = &[0];
assert_eq!(buf, b);
let mut buf = [0; 4];
assert_eq!(reader.read(&mut buf).unwrap(), 4);
assert_eq!(reader.position(), 5);
let b: &[_] = &[1, 2, 3, 4];
assert_eq!(buf, b);
assert_eq!(reader.read(&mut buf).unwrap(), 3);
let b: &[_] = &[5, 6, 7];
assert_eq!(&buf[..3], b);
assert_eq!(reader.read(&mut buf).unwrap(), 0);
}
#[test]
fn test_boxed_slice_reader_vectored() {
let mut reader = Cursor::new(vec![0, 1, 2, 3, 4, 5, 6, 7].into_boxed_slice());
let mut buf = [];
assert_eq!(reader.read_vectored(&mut [IoSliceMut::new(&mut buf)]).unwrap(), 0);
assert_eq!(reader.position(), 0);
let mut buf = [0];
assert_eq!(
reader
.read_vectored(&mut [IoSliceMut::new(&mut []), IoSliceMut::new(&mut buf),])
.unwrap(),
1,
);
assert_eq!(reader.position(), 1);
let b: &[_] = &[0];
assert_eq!(buf, b);
let mut buf1 = [0; 4];
let mut buf2 = [0; 4];
assert_eq!(
reader
.read_vectored(&mut [IoSliceMut::new(&mut buf1), IoSliceMut::new(&mut buf2)],)
.unwrap(),
7,
);
let b1: &[_] = &[1, 2, 3, 4];
let b2: &[_] = &[5, 6, 7];
assert_eq!(buf1, b1);
assert_eq!(&buf2[..3], b2);
assert_eq!(reader.read(&mut buf).unwrap(), 0);
}
#[test]
fn read_to_end() {
let mut reader = Cursor::new(vec![0, 1, 2, 3, 4, 5, 6, 7]);
let mut v = Vec::new();
reader.read_to_end(&mut v).unwrap();
assert_eq!(v, [0, 1, 2, 3, 4, 5, 6, 7]);
}
#[test]
fn test_slice_reader() {
let in_buf = vec![0, 1, 2, 3, 4, 5, 6, 7];
let reader = &mut &in_buf[..];
let mut buf = [];
assert_eq!(reader.read(&mut buf).unwrap(), 0);
let mut buf = [0];
assert_eq!(reader.read(&mut buf).unwrap(), 1);
assert_eq!(reader.len(), 7);
let b: &[_] = &[0];
assert_eq!(&buf[..], b);
let mut buf = [0; 4];
assert_eq!(reader.read(&mut buf).unwrap(), 4);
assert_eq!(reader.len(), 3);
let b: &[_] = &[1, 2, 3, 4];
assert_eq!(&buf[..], b);
assert_eq!(reader.read(&mut buf).unwrap(), 3);
let b: &[_] = &[5, 6, 7];
assert_eq!(&buf[..3], b);
assert_eq!(reader.read(&mut buf).unwrap(), 0);
}
#[test]
fn test_slice_reader_vectored() {
let in_buf = vec![0, 1, 2, 3, 4, 5, 6, 7];
let reader = &mut &in_buf[..];
let mut buf = [];
assert_eq!(reader.read_vectored(&mut [IoSliceMut::new(&mut buf)]).unwrap(), 0);
let mut buf = [0];
assert_eq!(
reader
.read_vectored(&mut [IoSliceMut::new(&mut []), IoSliceMut::new(&mut buf),])
.unwrap(),
1,
);
assert_eq!(reader.len(), 7);
let b: &[_] = &[0];
assert_eq!(buf, b);
let mut buf1 = [0; 4];
let mut buf2 = [0; 4];
assert_eq!(
reader
.read_vectored(&mut [IoSliceMut::new(&mut buf1), IoSliceMut::new(&mut buf2)],)
.unwrap(),
7,
);
let b1: &[_] = &[1, 2, 3, 4];
let b2: &[_] = &[5, 6, 7];
assert_eq!(buf1, b1);
assert_eq!(&buf2[..3], b2);
assert_eq!(reader.read(&mut buf).unwrap(), 0);
}
#[test]
fn test_read_exact() {
let in_buf = vec![0, 1, 2, 3, 4, 5, 6, 7];
let reader = &mut &in_buf[..];
let mut buf = [];
assert!(reader.read_exact(&mut buf).is_ok());
let mut buf = [8];
assert!(reader.read_exact(&mut buf).is_ok());
assert_eq!(buf[0], 0);
assert_eq!(reader.len(), 7);
let mut buf = [0, 0, 0, 0, 0, 0, 0];
assert!(reader.read_exact(&mut buf).is_ok());
assert_eq!(buf, [1, 2, 3, 4, 5, 6, 7]);
assert_eq!(reader.len(), 0);
let mut buf = [0];
assert!(reader.read_exact(&mut buf).is_err());
}
#[test]
fn test_buf_reader() {
let in_buf = vec![0, 1, 2, 3, 4, 5, 6, 7];
let mut reader = Cursor::new(&in_buf[..]);
let mut buf = [];
assert_eq!(reader.read(&mut buf).unwrap(), 0);
assert_eq!(reader.position(), 0);
let mut buf = [0];
assert_eq!(reader.read(&mut buf).unwrap(), 1);
assert_eq!(reader.position(), 1);
let b: &[_] = &[0];
assert_eq!(buf, b);
let mut buf = [0; 4];
assert_eq!(reader.read(&mut buf).unwrap(), 4);
assert_eq!(reader.position(), 5);
let b: &[_] = &[1, 2, 3, 4];
assert_eq!(buf, b);
assert_eq!(reader.read(&mut buf).unwrap(), 3);
let b: &[_] = &[5, 6, 7];
assert_eq!(&buf[..3], b);
assert_eq!(reader.read(&mut buf).unwrap(), 0);
}
#[test]
fn seek_past_end() {
let buf = [0xff];
let mut r = Cursor::new(&buf[..]);
assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10);
assert_eq!(r.read(&mut [0]).unwrap(), 0);
let mut r = Cursor::new(vec![10]);
assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10);
assert_eq!(r.read(&mut [0]).unwrap(), 0);
let mut buf = [0];
let mut r = Cursor::new(&mut buf[..]);
assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10);
assert_eq!(r.write(&[3]).unwrap(), 0);
let mut r = Cursor::new(vec![10].into_boxed_slice());
assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10);
assert_eq!(r.write(&[3]).unwrap(), 0);
}
#[test]
fn seek_past_i64() {
let buf = [0xff];
let mut r = Cursor::new(&buf[..]);
assert_eq!(r.seek(SeekFrom::Start(6)).unwrap(), 6);
assert_eq!(r.seek(SeekFrom::Current(0x7ffffffffffffff0)).unwrap(), 0x7ffffffffffffff6);
assert_eq!(r.seek(SeekFrom::Current(0x10)).unwrap(), 0x8000000000000006);
assert_eq!(r.seek(SeekFrom::Current(0)).unwrap(), 0x8000000000000006);
assert!(r.seek(SeekFrom::Current(0x7ffffffffffffffd)).is_err());
assert_eq!(r.seek(SeekFrom::Current(-0x8000000000000000)).unwrap(), 6);
let mut r = Cursor::new(vec![10]);
assert_eq!(r.seek(SeekFrom::Start(6)).unwrap(), 6);
assert_eq!(r.seek(SeekFrom::Current(0x7ffffffffffffff0)).unwrap(), 0x7ffffffffffffff6);
assert_eq!(r.seek(SeekFrom::Current(0x10)).unwrap(), 0x8000000000000006);
assert_eq!(r.seek(SeekFrom::Current(0)).unwrap(), 0x8000000000000006);
assert!(r.seek(SeekFrom::Current(0x7ffffffffffffffd)).is_err());
assert_eq!(r.seek(SeekFrom::Current(-0x8000000000000000)).unwrap(), 6);
let mut buf = [0];
let mut r = Cursor::new(&mut buf[..]);
assert_eq!(r.seek(SeekFrom::Start(6)).unwrap(), 6);
assert_eq!(r.seek(SeekFrom::Current(0x7ffffffffffffff0)).unwrap(), 0x7ffffffffffffff6);
assert_eq!(r.seek(SeekFrom::Current(0x10)).unwrap(), 0x8000000000000006);
assert_eq!(r.seek(SeekFrom::Current(0)).unwrap(), 0x8000000000000006);
assert!(r.seek(SeekFrom::Current(0x7ffffffffffffffd)).is_err());
assert_eq!(r.seek(SeekFrom::Current(-0x8000000000000000)).unwrap(), 6);
let mut r = Cursor::new(vec![10].into_boxed_slice());
assert_eq!(r.seek(SeekFrom::Start(6)).unwrap(), 6);
assert_eq!(r.seek(SeekFrom::Current(0x7ffffffffffffff0)).unwrap(), 0x7ffffffffffffff6);
assert_eq!(r.seek(SeekFrom::Current(0x10)).unwrap(), 0x8000000000000006);
assert_eq!(r.seek(SeekFrom::Current(0)).unwrap(), 0x8000000000000006);
assert!(r.seek(SeekFrom::Current(0x7ffffffffffffffd)).is_err());
assert_eq!(r.seek(SeekFrom::Current(-0x8000000000000000)).unwrap(), 6);
}
#[test]
fn seek_before_0() {
let buf = [0xff];
let mut r = Cursor::new(&buf[..]);
assert!(r.seek(SeekFrom::End(-2)).is_err());
let mut r = Cursor::new(vec![10]);
assert!(r.seek(SeekFrom::End(-2)).is_err());
let mut buf = [0];
let mut r = Cursor::new(&mut buf[..]);
assert!(r.seek(SeekFrom::End(-2)).is_err());
let mut r = Cursor::new(vec![10].into_boxed_slice());
assert!(r.seek(SeekFrom::End(-2)).is_err());
}
#[test]
fn test_seekable_mem_writer() {
let mut writer = Cursor::new(Vec::<u8>::new());
assert_eq!(writer.position(), 0);
assert_eq!(writer.write(&[0]).unwrap(), 1);
assert_eq!(writer.position(), 1);
assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3);
assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4);
assert_eq!(writer.position(), 8);
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7];
assert_eq!(&writer.get_ref()[..], b);
assert_eq!(writer.seek(SeekFrom::Start(0)).unwrap(), 0);
assert_eq!(writer.position(), 0);
assert_eq!(writer.write(&[3, 4]).unwrap(), 2);
let b: &[_] = &[3, 4, 2, 3, 4, 5, 6, 7];
assert_eq!(&writer.get_ref()[..], b);
assert_eq!(writer.seek(SeekFrom::Current(1)).unwrap(), 3);
assert_eq!(writer.write(&[0, 1]).unwrap(), 2);
let b: &[_] = &[3, 4, 2, 0, 1, 5, 6, 7];
assert_eq!(&writer.get_ref()[..], b);
assert_eq!(writer.seek(SeekFrom::End(-1)).unwrap(), 7);
assert_eq!(writer.write(&[1, 2]).unwrap(), 2);
let b: &[_] = &[3, 4, 2, 0, 1, 5, 6, 1, 2];
assert_eq!(&writer.get_ref()[..], b);
assert_eq!(writer.seek(SeekFrom::End(1)).unwrap(), 10);
assert_eq!(writer.write(&[1]).unwrap(), 1);
let b: &[_] = &[3, 4, 2, 0, 1, 5, 6, 1, 2, 0, 1];
assert_eq!(&writer.get_ref()[..], b);
}
#[test]
fn vec_seek_past_end() {
let mut r = Cursor::new(Vec::new());
assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10);
assert_eq!(r.write(&[3]).unwrap(), 1);
}
#[test]
fn vec_seek_before_0() {
let mut r = Cursor::new(Vec::new());
assert!(r.seek(SeekFrom::End(-2)).is_err());
}
#[test]
#[cfg(target_pointer_width = "32")]
fn vec_seek_and_write_past_usize_max() {
let mut c = Cursor::new(Vec::new());
c.set_position(<usize>::max_value() as u64 + 1);
assert!(c.write_all(&[1, 2, 3]).is_err());
}
#[test]
fn test_partial_eq() {
assert_eq!(Cursor::new(Vec::<u8>::new()), Cursor::new(Vec::<u8>::new()));
}
#[test]
fn test_eq() {
struct AssertEq<T: Eq>(pub T);
let _: AssertEq<Cursor<Vec<u8>>> = AssertEq(Cursor::new(Vec::new()));
}
}

View File

@ -1,551 +0,0 @@
#[cfg(feature="alloc")] use alloc::boxed::Box;
#[cfg(not(feature="alloc"))] use ::FakeBox as Box;
use core::convert::Into;
use core::fmt;
use core::marker::{Send, Sync};
use core::option::Option::{self, Some, None};
use core::result;
#[cfg(feature="collections")] use collections::string::String;
#[cfg(not(feature="collections"))] use ::ErrorString as String;
use core::convert::From;
/// A specialized [`Result`](../result/enum.Result.html) type for I/O
/// operations.
///
/// This type is broadly used across [`std::io`] for any operation which may
/// produce an error.
///
/// This typedef is generally used to avoid writing out [`io::Error`] directly and
/// is otherwise a direct mapping to [`Result`].
///
/// While usual Rust style is to import types directly, aliases of [`Result`]
/// often are not, to make it easier to distinguish between them. [`Result`] is
/// generally assumed to be [`std::result::Result`][`Result`], and so users of this alias
/// will generally use `io::Result` instead of shadowing the prelude's import
/// of [`std::result::Result`][`Result`].
///
/// [`std::io`]: ../io/index.html
/// [`io::Error`]: ../io/struct.Error.html
/// [`Result`]: ../result/enum.Result.html
///
/// # Examples
///
/// A convenience function that bubbles an `io::Result` to its caller:
///
/// ```
/// use std::io;
///
/// fn get_string() -> io::Result<String> {
/// let mut buffer = String::new();
///
/// io::stdin().read_line(&mut buffer)?;
///
/// Ok(buffer)
/// }
/// ```
pub type Result<T> = result::Result<T, Error>;
/// The error type for I/O operations of the [`Read`], [`Write`], [`Seek`], and
/// associated traits.
///
/// Errors mostly originate from the underlying OS, but custom instances of
/// `Error` can be created with crafted error messages and a particular value of
/// [`ErrorKind`].
///
/// [`Read`]: ../io/trait.Read.html
/// [`Write`]: ../io/trait.Write.html
/// [`Seek`]: ../io/trait.Seek.html
/// [`ErrorKind`]: enum.ErrorKind.html
pub struct Error {
repr: Repr,
}
impl fmt::Debug for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&self.repr, f)
}
}
enum Repr {
Os(i32),
Simple(ErrorKind),
#[cfg(feature="alloc")]
Custom(Box<Custom>),
#[cfg(not(feature="alloc"))]
Custom(Custom),
}
#[derive(Debug)]
struct Custom {
kind: ErrorKind,
error: String,
}
/// A list specifying general categories of I/O error.
///
/// This list is intended to grow over time and it is not recommended to
/// exhaustively match against it.
///
/// It is used with the [`io::Error`] type.
///
/// [`io::Error`]: struct.Error.html
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[allow(deprecated)]
#[non_exhaustive]
pub enum ErrorKind {
/// An entity was not found, often a file.
NotFound,
/// The operation lacked the necessary privileges to complete.
PermissionDenied,
/// The connection was refused by the remote server.
ConnectionRefused,
/// The connection was reset by the remote server.
ConnectionReset,
/// The connection was aborted (terminated) by the remote server.
ConnectionAborted,
/// The network operation failed because it was not connected yet.
NotConnected,
/// A socket address could not be bound because the address is already in
/// use elsewhere.
AddrInUse,
/// A nonexistent interface was requested or the requested address was not
/// local.
AddrNotAvailable,
/// The operation failed because a pipe was closed.
BrokenPipe,
/// An entity already exists, often a file.
AlreadyExists,
/// The operation needs to block to complete, but the blocking operation was
/// requested to not occur.
WouldBlock,
/// A parameter was incorrect.
InvalidInput,
/// Data not valid for the operation were encountered.
///
/// Unlike [`InvalidInput`], this typically means that the operation
/// parameters were valid, however the error was caused by malformed
/// input data.
///
/// For example, a function that reads a file into a string will error with
/// `InvalidData` if the file's contents are not valid UTF-8.
///
/// [`InvalidInput`]: #variant.InvalidInput
InvalidData,
/// The I/O operation's timeout expired, causing it to be canceled.
TimedOut,
/// An error returned when an operation could not be completed because a
/// call to [`write`] returned [`Ok(0)`].
///
/// This typically means that an operation could only succeed if it wrote a
/// particular number of bytes but only a smaller number of bytes could be
/// written.
///
/// [`write`]: ../../std/io/trait.Write.html#tymethod.write
/// [`Ok(0)`]: ../../std/io/type.Result.html
WriteZero,
/// This operation was interrupted.
///
/// Interrupted operations can typically be retried.
Interrupted,
/// Any I/O error not part of this list.
Other,
/// An error returned when an operation could not be completed because an
/// "end of file" was reached prematurely.
///
/// This typically means that an operation could only succeed if it read a
/// particular number of bytes but only a smaller number of bytes could be
/// read.
UnexpectedEof,
}
impl ErrorKind {
pub(crate) fn as_str(&self) -> &'static str {
match *self {
ErrorKind::NotFound => "entity not found",
ErrorKind::PermissionDenied => "permission denied",
ErrorKind::ConnectionRefused => "connection refused",
ErrorKind::ConnectionReset => "connection reset",
ErrorKind::ConnectionAborted => "connection aborted",
ErrorKind::NotConnected => "not connected",
ErrorKind::AddrInUse => "address in use",
ErrorKind::AddrNotAvailable => "address not available",
ErrorKind::BrokenPipe => "broken pipe",
ErrorKind::AlreadyExists => "entity already exists",
ErrorKind::WouldBlock => "operation would block",
ErrorKind::InvalidInput => "invalid input parameter",
ErrorKind::InvalidData => "invalid data",
ErrorKind::TimedOut => "timed out",
ErrorKind::WriteZero => "write zero",
ErrorKind::Interrupted => "operation interrupted",
ErrorKind::Other => "other os error",
ErrorKind::UnexpectedEof => "unexpected end of file",
}
}
}
/// Intended for use for errors not exposed to the user, where allocating onto
/// the heap (for normal construction via Error::new) is too costly.
impl From<ErrorKind> for Error {
/// Converts an [`ErrorKind`] into an [`Error`].
///
/// This conversion allocates a new error with a simple representation of error kind.
///
/// # Examples
///
/// ```
/// use std::io::{Error, ErrorKind};
///
/// let not_found = ErrorKind::NotFound;
/// let error = Error::from(not_found);
/// assert_eq!("entity not found", format!("{}", error));
/// ```
///
/// [`ErrorKind`]: ../../std/io/enum.ErrorKind.html
/// [`Error`]: ../../std/io/struct.Error.html
#[inline]
fn from(kind: ErrorKind) -> Error {
Error { repr: Repr::Simple(kind) }
}
}
impl Error {
/// Creates a new I/O error from a known kind of error as well as an
/// arbitrary error payload.
///
/// This function is used to generically create I/O errors which do not
/// originate from the OS itself. The `error` argument is an arbitrary
/// payload which will be contained in this `Error`.
///
/// # Examples
///
/// ```
/// use std::io::{Error, ErrorKind};
///
/// // errors can be created from strings
/// let custom_error = Error::new(ErrorKind::Other, "oh no!");
///
/// // errors can also be created from other errors
/// let custom_error2 = Error::new(ErrorKind::Interrupted, custom_error);
/// ```
pub fn new<E>(kind: ErrorKind, error: E) -> Error
where
E: Into<String>,
{
Self::_new(kind, error.into())
}
fn _new(kind: ErrorKind, error: String) -> Error {
Error { repr: Repr::Custom(Box::new(Custom { kind, error })) }
}
/// Creates a new instance of an `Error` from a particular OS error code.
///
/// # Examples
///
/// On Linux:
///
/// ```
/// # if cfg!(target_os = "linux") {
/// use std::io;
///
/// let error = io::Error::from_raw_os_error(22);
/// assert_eq!(error.kind(), io::ErrorKind::InvalidInput);
/// # }
/// ```
///
/// On Windows:
///
/// ```
/// # if cfg!(windows) {
/// use std::io;
///
/// let error = io::Error::from_raw_os_error(10022);
/// assert_eq!(error.kind(), io::ErrorKind::InvalidInput);
/// # }
/// ```
pub fn from_raw_os_error(code: i32) -> Error {
Error { repr: Repr::Os(code) }
}
/// Returns the OS error that this error represents (if any).
///
/// If this `Error` was constructed via `last_os_error` or
/// `from_raw_os_error`, then this function will return `Some`, otherwise
/// it will return `None`.
///
/// # Examples
///
/// ```
/// use std::io::{Error, ErrorKind};
///
/// fn print_os_error(err: &Error) {
/// if let Some(raw_os_err) = err.raw_os_error() {
/// println!("raw OS error: {:?}", raw_os_err);
/// } else {
/// println!("Not an OS error");
/// }
/// }
///
/// fn main() {
/// // Will print "raw OS error: ...".
/// print_os_error(&Error::last_os_error());
/// // Will print "Not an OS error".
/// print_os_error(&Error::new(ErrorKind::Other, "oh no!"));
/// }
/// ```
pub fn raw_os_error(&self) -> Option<i32> {
match self.repr {
Repr::Os(i) => Some(i),
Repr::Custom(..) => None,
Repr::Simple(..) => None,
}
}
/// Returns a reference to the inner error wrapped by this error (if any).
///
/// If this `Error` was constructed via `new` then this function will
/// return `Some`, otherwise it will return `None`.
///
/// # Examples
///
/// ```
/// use std::io::{Error, ErrorKind};
///
/// fn print_error(err: &Error) {
/// if let Some(inner_err) = err.get_ref() {
/// println!("Inner error: {:?}", inner_err);
/// } else {
/// println!("No inner error");
/// }
/// }
///
/// fn main() {
/// // Will print "No inner error".
/// print_error(&Error::last_os_error());
/// // Will print "Inner error: ...".
/// print_error(&Error::new(ErrorKind::Other, "oh no!"));
/// }
/// ```
pub fn get_ref(&self) -> Option<&String> {
match self.repr {
Repr::Os(..) => None,
Repr::Simple(..) => None,
Repr::Custom(ref c) => Some(&c.error),
}
}
/// Returns a mutable reference to the inner error wrapped by this error
/// (if any).
///
/// If this `Error` was constructed via `new` then this function will
/// return `Some`, otherwise it will return `None`.
///
/// # Examples
///
/// ```
/// use std::io::{Error, ErrorKind};
/// use std::{error, fmt};
/// use std::fmt::Display;
///
/// #[derive(Debug)]
/// struct MyError {
/// v: String,
/// }
///
/// impl MyError {
/// fn new() -> MyError {
/// MyError {
/// v: "oh no!".to_string()
/// }
/// }
///
/// fn change_message(&mut self, new_message: &str) {
/// self.v = new_message.to_string();
/// }
/// }
///
/// impl error::Error for MyError {}
///
/// impl Display for MyError {
/// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
/// write!(f, "MyError: {}", &self.v)
/// }
/// }
///
/// fn change_error(mut err: Error) -> Error {
/// if let Some(inner_err) = err.get_mut() {
/// inner_err.downcast_mut::<MyError>().unwrap().change_message("I've been changed!");
/// }
/// err
/// }
///
/// fn print_error(err: &Error) {
/// if let Some(inner_err) = err.get_ref() {
/// println!("Inner error: {}", inner_err);
/// } else {
/// println!("No inner error");
/// }
/// }
///
/// fn main() {
/// // Will print "No inner error".
/// print_error(&change_error(Error::last_os_error()));
/// // Will print "Inner error: ...".
/// print_error(&change_error(Error::new(ErrorKind::Other, MyError::new())));
/// }
/// ```
pub fn get_mut(&mut self) -> Option<&mut String> {
match self.repr {
Repr::Os(..) => None,
Repr::Simple(..) => None,
Repr::Custom(ref mut c) => Some(&mut c.error),
}
}
/// Consumes the `Error`, returning its inner error (if any).
///
/// If this `Error` was constructed via `new` then this function will
/// return `Some`, otherwise it will return `None`.
///
/// # Examples
///
/// ```
/// use std::io::{Error, ErrorKind};
///
/// fn print_error(err: Error) {
/// if let Some(inner_err) = err.into_inner() {
/// println!("Inner error: {}", inner_err);
/// } else {
/// println!("No inner error");
/// }
/// }
///
/// fn main() {
/// // Will print "No inner error".
/// print_error(Error::last_os_error());
/// // Will print "Inner error: ...".
/// print_error(Error::new(ErrorKind::Other, "oh no!"));
/// }
/// ```
pub fn into_inner(self) -> Option<String> {
match self.repr {
Repr::Os(..) => None,
Repr::Simple(..) => None,
Repr::Custom(c) => Some(c.error),
}
}
/// Returns the corresponding `ErrorKind` for this error.
///
/// # Examples
///
/// ```
/// use std::io::{Error, ErrorKind};
///
/// fn print_error(err: Error) {
/// println!("{:?}", err.kind());
/// }
///
/// fn main() {
/// // Will print "No inner error".
/// print_error(Error::last_os_error());
/// // Will print "Inner error: ...".
/// print_error(Error::new(ErrorKind::AddrInUse, "oh no!"));
/// }
/// ```
pub fn kind(&self) -> ErrorKind {
match self.repr {
Repr::Os(_code) => ErrorKind::Other,
Repr::Custom(ref c) => c.kind,
Repr::Simple(kind) => kind,
}
}
}
impl fmt::Debug for Repr {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
Repr::Os(code) => fmt
.debug_struct("Os")
.field("code", &code)
.finish(),
Repr::Custom(ref c) => fmt::Debug::fmt(&c, fmt),
Repr::Simple(kind) => fmt.debug_tuple("Kind").field(&kind).finish(),
}
}
}
impl fmt::Display for Error {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.repr {
Repr::Os(code) => {
write!(fmt, "os error {}", code)
}
Repr::Custom(ref c) => c.error.fmt(fmt),
Repr::Simple(kind) => write!(fmt, "{}", kind.as_str()),
}
}
}
fn _assert_error_is_sync_send() {
fn _is_sync_send<T: Sync + Send>() {}
_is_sync_send::<Error>();
}
#[cfg(test)]
mod test {
use super::{Custom, Error, ErrorKind, Repr};
use crate::error;
use crate::fmt;
use crate::sys::decode_error_kind;
use crate::sys::os::error_string;
#[test]
fn test_debug_error() {
let code = 6;
let msg = error_string(code);
let kind = decode_error_kind(code);
let err = Error {
repr: Repr::Custom(box Custom {
kind: ErrorKind::InvalidInput,
error: box Error { repr: super::Repr::Os(code) },
}),
};
let expected = format!(
"Custom {{ \
kind: InvalidInput, \
error: Os {{ \
code: {:?}, \
kind: {:?}, \
message: {:?} \
}} \
}}",
code, kind, msg
);
assert_eq!(format!("{:?}", err), expected);
}
#[test]
fn test_downcasting() {
#[derive(Debug)]
struct TestError;
impl fmt::Display for TestError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("asdf")
}
}
impl error::Error for TestError {}
// we have to call all of these UFCS style right now since method
// resolution won't implicitly drop the Send+Sync bounds
let mut err = Error::new(ErrorKind::Other, TestError);
assert!(err.get_ref().unwrap().is::<TestError>());
assert_eq!("asdf", err.get_ref().unwrap().to_string());
assert!(err.get_mut().unwrap().is::<TestError>());
let extracted = err.into_inner().unwrap();
extracted.downcast::<TestError>().unwrap();
}
}

View File

@ -1,378 +0,0 @@
use core::cmp;
use core::fmt;
use crate::io::{
self, Error, ErrorKind, Initializer, Read, Seek, SeekFrom, Write,
};
#[cfg(feature = "collections")] use crate::io::BufRead;
use core::mem;
#[cfg(feature="collections")]
use collections::{
vec::Vec,
string::String,
};
#[cfg(feature = "alloc")]
use alloc::boxed::Box;
// =============================================================================
// Forwarding implementations
impl<R: Read + ?Sized> Read for &mut R {
#[inline]
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
(**self).read(buf)
}
#[inline]
unsafe fn initializer(&self) -> Initializer {
(**self).initializer()
}
#[cfg(feature="collections")]
#[inline]
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
(**self).read_to_end(buf)
}
#[cfg(feature="collections")]
#[inline]
fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
(**self).read_to_string(buf)
}
#[inline]
fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
(**self).read_exact(buf)
}
}
impl<W: Write + ?Sized> Write for &mut W {
#[inline]
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
(**self).write(buf)
}
#[inline]
fn flush(&mut self) -> io::Result<()> {
(**self).flush()
}
#[inline]
fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
(**self).write_all(buf)
}
#[inline]
fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> {
(**self).write_fmt(fmt)
}
}
impl<S: Seek + ?Sized> Seek for &mut S {
#[inline]
fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
(**self).seek(pos)
}
}
#[cfg(feature = "collections")]
impl<B: BufRead + ?Sized> BufRead for &mut B {
#[inline]
fn fill_buf(&mut self) -> io::Result<&[u8]> {
(**self).fill_buf()
}
#[inline]
fn consume(&mut self, amt: usize) {
(**self).consume(amt)
}
#[cfg(feature="collections")]
#[inline]
fn read_until(&mut self, byte: u8, buf: &mut Vec<u8>) -> io::Result<usize> {
(**self).read_until(byte, buf)
}
#[cfg(feature="collections")]
#[inline]
fn read_line(&mut self, buf: &mut String) -> io::Result<usize> {
(**self).read_line(buf)
}
}
#[cfg(feature="alloc")]
#[cfg(feature="collections")]
impl<R: Read + ?Sized> Read for Box<R> {
#[inline]
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
(**self).read(buf)
}
#[cfg(feature="collections")]
#[inline]
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
(**self).read_to_end(buf)
}
#[cfg(feature="collections")]
#[inline]
fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
(**self).read_to_string(buf)
}
#[inline]
fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
(**self).read_exact(buf)
}
}
#[cfg(feature="alloc")]
#[cfg(feature="collections")]
impl<W: Write + ?Sized> Write for Box<W> {
#[inline]
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
(**self).write(buf)
}
#[inline]
fn flush(&mut self) -> io::Result<()> {
(**self).flush()
}
#[inline]
fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
(**self).write_all(buf)
}
#[inline]
fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> {
(**self).write_fmt(fmt)
}
}
#[cfg(feature="collections")]
impl<S: Seek + ?Sized> Seek for Box<S> {
#[inline]
fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
(**self).seek(pos)
}
}
#[cfg(feature="collections")]
impl<B: BufRead + ?Sized> BufRead for Box<B> {
#[inline]
fn fill_buf(&mut self) -> io::Result<&[u8]> {
(**self).fill_buf()
}
#[inline]
fn consume(&mut self, amt: usize) {
(**self).consume(amt)
}
#[inline]
fn read_until(&mut self, byte: u8, buf: &mut Vec<u8>) -> io::Result<usize> {
(**self).read_until(byte, buf)
}
#[inline]
fn read_line(&mut self, buf: &mut String) -> io::Result<usize> {
(**self).read_line(buf)
}
}
// Used by panicking::default_hook
#[cfg(test)]
/// This impl is only used by printing logic, so any error returned is always
/// of kind `Other`, and should be ignored.
#[cfg(feature="collections")]
impl Write for Box<dyn (::realstd::io::Write) + Send> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
(**self).write(buf).map_err(|_| ErrorKind::Other.into())
}
fn flush(&mut self) -> io::Result<()> {
(**self).flush().map_err(|_| ErrorKind::Other.into())
}
}
// =============================================================================
// In-memory buffer implementations
/// Read is implemented for `&[u8]` by copying from the slice.
///
/// Note that reading updates the slice to point to the yet unread part.
/// The slice will be empty when EOF is reached.
impl Read for &[u8] {
#[inline]
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let amt = cmp::min(buf.len(), self.len());
let (a, b) = self.split_at(amt);
// First check if the amount of bytes we want to read is small:
// `copy_from_slice` will generally expand to a call to `memcpy`, and
// for a single byte the overhead is significant.
if amt == 1 {
buf[0] = a[0];
} else {
buf[..amt].copy_from_slice(a);
}
*self = b;
Ok(amt)
}
#[inline]
unsafe fn initializer(&self) -> Initializer {
Initializer::nop()
}
#[inline]
fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
if buf.len() > self.len() {
return Err(Error::new(ErrorKind::UnexpectedEof, "failed to fill whole buffer"));
}
let (a, b) = self.split_at(buf.len());
// First check if the amount of bytes we want to read is small:
// `copy_from_slice` will generally expand to a call to `memcpy`, and
// for a single byte the overhead is significant.
if buf.len() == 1 {
buf[0] = a[0];
} else {
buf.copy_from_slice(a);
}
*self = b;
Ok(())
}
#[cfg(feature="collections")]
#[inline]
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
buf.extend_from_slice(*self);
let len = self.len();
*self = &self[len..];
Ok(len)
}
}
#[cfg(feature="collections")]
impl BufRead for &[u8] {
#[inline]
fn fill_buf(&mut self) -> io::Result<&[u8]> {
Ok(*self)
}
#[inline]
fn consume(&mut self, amt: usize) {
*self = &self[amt..];
}
}
/// Write is implemented for `&mut [u8]` by copying into the slice, overwriting
/// its data.
///
/// Note that writing updates the slice to point to the yet unwritten part.
/// The slice will be empty when it has been completely overwritten.
impl Write for &mut [u8] {
#[inline]
fn write(&mut self, data: &[u8]) -> io::Result<usize> {
let amt = cmp::min(data.len(), self.len());
let (a, b) = mem::replace(self, &mut []).split_at_mut(amt);
a.copy_from_slice(&data[..amt]);
*self = b;
Ok(amt)
}
#[inline]
fn write_all(&mut self, data: &[u8]) -> io::Result<()> {
if self.write(data)? == data.len() {
Ok(())
} else {
Err(Error::new(ErrorKind::WriteZero, "failed to write whole buffer"))
}
}
#[inline]
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
/// Write is implemented for `Vec<u8>` by appending to the vector.
/// The vector will grow as needed.
#[cfg(feature="collections")]
impl Write for Vec<u8> {
#[inline]
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.extend_from_slice(buf);
Ok(buf.len())
}
#[inline]
fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
self.extend_from_slice(buf);
Ok(())
}
#[inline]
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
#[cfg(test)]
mod tests {
use crate::io::prelude::*;
#[bench]
fn bench_read_slice(b: &mut test::Bencher) {
let buf = [5; 1024];
let mut dst = [0; 128];
b.iter(|| {
let mut rd = &buf[..];
for _ in 0..8 {
let _ = rd.read(&mut dst);
test::black_box(&dst);
}
})
}
#[bench]
fn bench_write_slice(b: &mut test::Bencher) {
let mut buf = [0; 1024];
let src = [5; 128];
b.iter(|| {
let mut wr = &mut buf[..];
for _ in 0..8 {
let _ = wr.write_all(&src);
test::black_box(&wr);
}
})
}
#[bench]
fn bench_read_vec(b: &mut test::Bencher) {
let buf = vec![5; 1024];
let mut dst = [0; 128];
b.iter(|| {
let mut rd = &buf[..];
for _ in 0..8 {
let _ = rd.read(&mut dst);
test::black_box(&dst);
}
})
}
#[bench]
fn bench_write_vec(b: &mut test::Bencher) {
let mut buf = Vec::with_capacity(1024);
let src = [5; 128];
b.iter(|| {
let mut wr = &mut buf[..];
for _ in 0..8 {
let _ = wr.write_all(&src);
test::black_box(&wr);
}
})
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,13 +0,0 @@
//! The I/O Prelude
//!
//! The purpose of this module is to alleviate imports of many common I/O traits
//! by adding a glob import to the top of I/O heavy modules:
//!
//! ```
//! # #![allow(unused_imports)]
//! use std::io::prelude::*;
//! ```
pub use super::{Read, Seek, Write};
#[cfg(feature = "collections")] pub use super::BufRead;

View File

@ -1,269 +0,0 @@
#![allow(missing_copy_implementations)]
use core::fmt;
use core::mem;
use crate::io::{self, ErrorKind, Initializer, Read, Write};
#[cfg(feature = "collections")] use crate::io::BufRead;
/// Copies the entire contents of a reader into a writer.
///
/// This function will continuously read data from `reader` and then
/// write it into `writer` in a streaming fashion until `reader`
/// returns EOF.
///
/// On success, the total number of bytes that were copied from
/// `reader` to `writer` is returned.
///
/// If youre wanting to copy the contents of one file to another and youre
/// working with filesystem paths, see the [`fs::copy`] function.
///
/// [`fs::copy`]: ../fs/fn.copy.html
///
/// # Errors
///
/// This function will return an error immediately if any call to `read` or
/// `write` returns an error. All instances of `ErrorKind::Interrupted` are
/// handled by this function and the underlying operation is retried.
///
/// # Examples
///
/// ```
/// use std::io;
///
/// fn main() -> io::Result<()> {
/// let mut reader: &[u8] = b"hello";
/// let mut writer: Vec<u8> = vec![];
///
/// io::copy(&mut reader, &mut writer)?;
///
/// assert_eq!(&b"hello"[..], &writer[..]);
/// Ok(())
/// }
/// ```
pub fn copy<R: ?Sized, W: ?Sized>(reader: &mut R, writer: &mut W) -> io::Result<u64>
where
R: Read,
W: Write,
{
let mut buf = unsafe {
#[allow(deprecated)]
let mut buf: [u8; super::DEFAULT_BUF_SIZE] = mem::uninitialized();
reader.initializer().initialize(&mut buf);
buf
};
let mut written = 0;
loop {
let len = match reader.read(&mut buf) {
Ok(0) => return Ok(written),
Ok(len) => len,
Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
Err(e) => return Err(e),
};
writer.write_all(&buf[..len])?;
written += len as u64;
}
}
/// A reader which is always at EOF.
///
/// This struct is generally created by calling [`empty`]. Please see
/// the documentation of [`empty()`][`empty`] for more details.
///
/// [`empty`]: fn.empty.html
pub struct Empty {
_priv: (),
}
/// Constructs a new handle to an empty reader.
///
/// All reads from the returned reader will return [`Ok`]`(0)`.
///
/// [`Ok`]: ../result/enum.Result.html#variant.Ok
///
/// # Examples
///
/// A slightly sad example of not reading anything into a buffer:
///
/// ```
/// use std::io::{self, Read};
///
/// let mut buffer = String::new();
/// io::empty().read_to_string(&mut buffer).unwrap();
/// assert!(buffer.is_empty());
/// ```
pub fn empty() -> Empty {
Empty { _priv: () }
}
impl Read for Empty {
#[inline]
fn read(&mut self, _buf: &mut [u8]) -> io::Result<usize> {
Ok(0)
}
#[inline]
unsafe fn initializer(&self) -> Initializer {
Initializer::nop()
}
}
#[cfg(feature="collections")]
impl BufRead for Empty {
#[inline]
fn fill_buf(&mut self) -> io::Result<&[u8]> {
Ok(&[])
}
#[inline]
fn consume(&mut self, _n: usize) {}
}
impl fmt::Debug for Empty {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.pad("Empty { .. }")
}
}
/// A reader which yields one byte over and over and over and over and over and...
///
/// This struct is generally created by calling [`repeat`][repeat]. Please
/// see the documentation of `repeat()` for more details.
///
/// [repeat]: fn.repeat.html
pub struct Repeat {
byte: u8,
}
/// Creates an instance of a reader that infinitely repeats one byte.
///
/// All reads from this reader will succeed by filling the specified buffer with
/// the given byte.
///
/// # Examples
///
/// ```
/// use std::io::{self, Read};
///
/// let mut buffer = [0; 3];
/// io::repeat(0b101).read_exact(&mut buffer).unwrap();
/// assert_eq!(buffer, [0b101, 0b101, 0b101]);
/// ```
pub fn repeat(byte: u8) -> Repeat {
Repeat { byte }
}
impl Read for Repeat {
#[inline]
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
for slot in &mut *buf {
*slot = self.byte;
}
Ok(buf.len())
}
#[inline]
unsafe fn initializer(&self) -> Initializer {
Initializer::nop()
}
}
impl fmt::Debug for Repeat {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.pad("Repeat { .. }")
}
}
/// A writer which will move data into the void.
///
/// This struct is generally created by calling [`sink`][sink]. Please
/// see the documentation of `sink()` for more details.
///
/// [sink]: fn.sink.html
pub struct Sink {
_priv: (),
}
/// Creates an instance of a writer which will successfully consume all data.
///
/// All calls to `write` on the returned instance will return `Ok(buf.len())`
/// and the contents of the buffer will not be inspected.
///
/// # Examples
///
/// ```rust
/// use std::io::{self, Write};
///
/// let buffer = vec![1, 2, 3, 5, 8];
/// let num_bytes = io::sink().write(&buffer).unwrap();
/// assert_eq!(num_bytes, 5);
/// ```
pub fn sink() -> Sink {
Sink { _priv: () }
}
impl Write for Sink {
#[inline]
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
Ok(buf.len())
}
#[inline]
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
impl fmt::Debug for Sink {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.pad("Sink { .. }")
}
}
#[cfg(test)]
mod tests {
use crate::io::prelude::*;
use crate::io::{copy, empty, repeat, sink};
#[test]
fn copy_copies() {
let mut r = repeat(0).take(4);
let mut w = sink();
assert_eq!(copy(&mut r, &mut w).unwrap(), 4);
let mut r = repeat(0).take(1 << 17);
assert_eq!(copy(&mut r as &mut dyn Read, &mut w as &mut dyn Write).unwrap(), 1 << 17);
}
#[test]
fn sink_sinks() {
let mut s = sink();
assert_eq!(s.write(&[]).unwrap(), 0);
assert_eq!(s.write(&[0]).unwrap(), 1);
assert_eq!(s.write(&[0; 1024]).unwrap(), 1024);
assert_eq!(s.by_ref().write(&[0; 1024]).unwrap(), 1024);
}
#[test]
fn empty_reads() {
let mut e = empty();
assert_eq!(e.read(&mut []).unwrap(), 0);
assert_eq!(e.read(&mut [0]).unwrap(), 0);
assert_eq!(e.read(&mut [0; 1024]).unwrap(), 0);
assert_eq!(e.by_ref().read(&mut [0; 1024]).unwrap(), 0);
}
#[test]
fn repeat_repeats() {
let mut r = repeat(4);
let mut b = [0; 1024];
assert_eq!(r.read(&mut b).unwrap(), 1024);
assert!(b.iter().all(|b| *b == 4));
}
#[test]
fn take_some_bytes() {
assert_eq!(repeat(4).take(100).bytes().count(), 100);
assert_eq!(repeat(4).take(100).bytes().next().unwrap().unwrap(), 4);
assert_eq!(repeat(1).take(10).chain(repeat(2).take(10)).bytes().count(), 20);
}
}

View File

@ -1,51 +0,0 @@
//! <p id="core_io-show-docblock"></p>
//! This is just a listing of the functionality available in this crate. See
//! the [std documentation](https://doc.rust-lang.org/nightly/std/io/index.html)
//! for a full description of the functionality.
#![allow(stable_features,unused_features)]
#![feature(question_mark,const_fn,copy_from_slice,try_from,str_internals,align_offset,slice_internals)]
#![cfg_attr(any(feature="alloc",feature="collections"),feature(alloc))]
#![cfg_attr(pattern_guards,feature(bind_by_move_pattern_guards,nll))]
#![cfg_attr(non_exhaustive,feature(non_exhaustive))]
#![cfg_attr(unicode,feature(str_char))]
#![cfg_attr(unicode,feature(unicode))]
#![no_std]
#[cfg_attr(feature="collections",macro_use)]
#[cfg_attr(feature="collections",allow(unused_imports))]
#[cfg(feature="collections")] extern crate alloc as collections;
#[cfg(feature="alloc")] extern crate alloc;
#[cfg(rustc_unicode)]
extern crate rustc_unicode;
#[cfg(std_unicode)]
extern crate std_unicode;
#[cfg(not(feature="collections"))]
pub type ErrorString = &'static str;
// Provide Box::new wrapper
#[cfg(not(feature="alloc"))]
struct FakeBox<T>(core::marker::PhantomData<T>);
#[cfg(not(feature="alloc"))]
impl<T> FakeBox<T> {
fn new(val: T) -> T {
val
}
}
// Needed for older compilers, to ignore vec!/format! macros in tests
#[cfg(not(feature="collections"))]
#[allow(unused)]
macro_rules! vec (
( $ elem : expr ; $ n : expr ) => { () };
( $ ( $ x : expr ) , * ) => { () };
( $ ( $ x : expr , ) * ) => { () };
);
#[cfg(not(feature="collections"))]
#[allow(unused)]
macro_rules! format {
( $ ( $ arg : tt ) * ) => { () };
}
mod io;
pub use io::*;

View File

@ -5,11 +5,8 @@ authors = ["M-Labs"]
edition = "2018"
[features]
target_zc706 = []
target_cora_z7_10 = []
target_redpitaya = []
power_saving = []
default = ["target_zc706"]
default = []
[dependencies]
bit_field = "0.10"

View File

@ -34,6 +34,12 @@ pub fn isb() {
unsafe { llvm_asm!("isb" :::: "volatile") }
}
/// Enable FIQ
#[inline]
pub unsafe fn enable_fiq() {
llvm_asm!("cpsie f":::: "volatile");
}
/// Enable IRQ
#[inline]
pub unsafe fn enable_irq() {

View File

@ -2,7 +2,9 @@ use libregister::{register, register_at, register_bit, register_bits, RegisterRW
use super::asm::dmb;
use volatile_register::RW;
pub fn enable_l2_cache() {
/// enable L2 cache with specific prefetch offset
/// prefetch offset requires manual tuning, it seems that 8 is good for ZC706 current settings
pub fn enable_l2_cache(offset: u8) {
dmb();
let regs = RegisterBlock::new();
// disable L2 cache
@ -14,6 +16,7 @@ pub fn enable_l2_cache() {
.double_linefill_en(true)
.incr_double_linefill_en(true)
.pref_drop_en(true)
.prefetch_offset(offset)
);
regs.reg1_aux_control.modify(|_, w| {
w.early_bresp_en(true)
@ -326,3 +329,5 @@ register_bit!(reg15_prefetch_ctrl, instr_prefetch_en, 29);
register_bit!(reg15_prefetch_ctrl, data_prefetch_en, 28);
register_bit!(reg15_prefetch_ctrl, pref_drop_en, 24);
register_bit!(reg15_prefetch_ctrl, incr_double_linefill_en, 23);
register_bits!(reg15_prefetch_ctrl, prefetch_offset, u8, 0, 4);

View File

@ -6,17 +6,17 @@
extern crate alloc;
pub mod asm;
pub mod regs;
pub mod cache;
mod fpu;
pub mod l2c;
pub mod mmu;
pub mod mutex;
pub mod sync_channel;
pub mod regs;
pub mod semaphore;
pub mod l2c;
pub mod sync_channel;
mod uncached;
mod fpu;
pub use uncached::UncachedSlice;
pub use fpu::enable_fpu;
pub use uncached::UncachedSlice;
global_asm!(include_str!("exceptions.s"));
@ -35,3 +35,47 @@ pub fn notify_spin_lock() {
}
}
#[macro_export]
/// Interrupt handler, which setup the stack and preserve registers before jumping to actual interrupt handler.
/// Registers r0-r12, PC, SP and CPSR are restored after the actual handler.
///
/// - `name` is the name of the interrupt, should be the same as the one defined in vector table.
/// - `name2` is the name for the actual handler, should be different from name.
/// - `stack0` is the stack for the interrupt handler when called from core0.
/// - `stack1` is the stack for the interrupt handler when called from core1.
/// - `body` is the body of the actual interrupt handler, should be a normal unsafe rust function
/// body.
///
/// Note that the interrupt handler would use the same stack as normal programs by default.
macro_rules! interrupt_handler {
($name:ident, $name2:ident, $stack0:ident, $stack1:ident, $body:block) => {
#[link_section = ".text.boot"]
#[no_mangle]
#[naked]
pub unsafe extern "C" fn $name() -> ! {
asm!(
// setup SP, depending on CPU 0 or 1
// and preserve registers
"sub lr, lr, #4",
"stmfd sp!, {{r0-r12, lr}}",
"mrc p15, #0, r0, c0, c0, #5",
concat!("movw r1, :lower16:", stringify!($stack0)),
concat!("movt r1, :upper16:", stringify!($stack0)),
"tst r0, #3",
concat!("movwne r1, :lower16:", stringify!($stack1)),
concat!("movtne r1, :upper16:", stringify!($stack1)),
"mov r0, sp",
"mov sp, r1",
"push {{r0, r1}}", // 2 registers are pushed to maintain 8 byte stack alignment
concat!("bl ", stringify!($name2)),
"pop {{r0, r1}}",
"mov sp, r0",
"ldmfd sp!, {{r0-r12, pc}}^", // caret ^ : copy SPSR to the CPSR
options(noreturn)
);
}
#[no_mangle]
pub unsafe extern "C" fn $name2() $body
};
}

View File

@ -1,6 +1,9 @@
use core::ops::{Deref, DerefMut};
use core::sync::atomic::{AtomicU32, Ordering};
use core::cell::UnsafeCell;
use core::task::{Context, Poll};
use core::pin::Pin;
use core::future::Future;
use super::{
spin_lock_yield, notify_spin_lock,
asm::{enter_critical, exit_critical}
@ -20,6 +23,23 @@ pub struct Mutex<T> {
unsafe impl<T: Send> Sync for Mutex<T> {}
unsafe impl<T: Send> Send for Mutex<T> {}
struct Fut<'a, T>(&'a Mutex<T>);
impl<'a, T> Future for Fut<'a, T> {
type Output = MutexGuard<'a, T>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let irq = unsafe { enter_critical() };
if self.0.locked.compare_exchange_weak(UNLOCKED, LOCKED, Ordering::AcqRel, Ordering::Relaxed).is_err() {
unsafe { exit_critical(irq) };
cx.waker().wake_by_ref();
Poll::Pending
}
else {
Poll::Ready(MutexGuard { mutex: self.0, irq })
}
}
}
impl<T> Mutex<T> {
/// Constructor, const-fn
pub const fn new(inner: T) -> Self {
@ -32,7 +52,7 @@ impl<T> Mutex<T> {
/// Lock the Mutex, blocks when already locked
pub fn lock(&self) -> MutexGuard<T> {
let mut irq = unsafe { enter_critical() };
while self.locked.compare_and_swap(UNLOCKED, LOCKED, Ordering::AcqRel) != UNLOCKED {
while self.locked.compare_exchange_weak(UNLOCKED, LOCKED, Ordering::AcqRel, Ordering::Relaxed).is_err() {
unsafe {
exit_critical(irq);
spin_lock_yield();
@ -42,9 +62,13 @@ impl<T> Mutex<T> {
MutexGuard { mutex: self, irq }
}
pub async fn async_lock(&self) -> MutexGuard<'_, T> {
Fut(&self).await
}
pub fn try_lock(&self) -> Option<MutexGuard<T>> {
let irq = unsafe { enter_critical() };
if self.locked.compare_and_swap(UNLOCKED, LOCKED, Ordering::AcqRel) != UNLOCKED {
if self.locked.compare_exchange_weak(UNLOCKED, LOCKED, Ordering::AcqRel, Ordering::Relaxed).is_err() {
unsafe { exit_critical(irq) };
None
} else {

View File

@ -173,7 +173,7 @@ impl RegisterRW for ACTLR {
impl ACTLR {
pub fn enable_smp(&mut self) {
self.modify(|_, w| w.smp(true).fw(true));
self.modify(|_, w| w.smp(true).fw(true).alloc_one_way(true));
}
pub fn enable_prefetch(&mut self) {

View File

@ -20,7 +20,7 @@ impl Semaphore {
loop {
let value = self.value.load(Ordering::Relaxed);
if value > 0 {
if self.value.compare_and_swap(value, value - 1, Ordering::SeqCst) == value {
if self.value.compare_exchange_weak(value, value - 1, Ordering::SeqCst, Ordering::Relaxed).is_ok() {
return Some(());
}
} else {
@ -58,7 +58,7 @@ impl Semaphore {
loop {
let value = self.value.load(Ordering::Relaxed);
if value < self.max {
if self.value.compare_and_swap(value, value + 1, Ordering::SeqCst) == value {
if self.value.compare_exchange_weak(value, value + 1, Ordering::SeqCst, Ordering::Relaxed).is_ok() {
notify_spin_lock();
return;
}

View File

@ -2,7 +2,7 @@ use core::{
ops::{Deref, DerefMut},
mem::{align_of, size_of},
};
use alloc::alloc::{dealloc, Layout, LayoutErr};
use alloc::alloc::{dealloc, Layout, LayoutError};
use crate::mmu::{L1_PAGE_SIZE, L1Table};
pub struct UncachedSlice<T: 'static> {
@ -12,7 +12,7 @@ pub struct UncachedSlice<T: 'static> {
impl<T> UncachedSlice<T> {
/// allocates in chunks of 1 MB
pub fn new<F: Fn() -> T>(len: usize, default: F) -> Result<Self, LayoutErr> {
pub fn new<F: Fn() -> T>(len: usize, default: F) -> Result<Self, LayoutError> {
// round to full pages
let size = ((len * size_of::<T>() - 1) | (L1_PAGE_SIZE - 1)) + 1;
let align = align_of::<T>()

View File

@ -30,8 +30,9 @@ pub trait RegisterRW: RegisterR + RegisterW {
#[doc(hidden)]
#[macro_export]
macro_rules! register_common {
($mod_name: ident, $struct_name: ident, $access: ty, $inner: ty) => (
($mod_name: ident, $(#[$outer:meta])* $struct_name: ident, $access: ty, $inner: ty) => (
#[repr(C)]
$(#[$outer])*
pub struct $struct_name {
inner: $access,
}
@ -52,7 +53,7 @@ macro_rules! register_common {
#[macro_export]
macro_rules! register_r {
($mod_name: ident, $struct_name: ident) => (
impl libregister::RegisterR for $struct_name {
impl $crate::RegisterR for $struct_name {
type R = $mod_name::Read;
#[inline]
@ -67,7 +68,7 @@ macro_rules! register_r {
#[macro_export]
macro_rules! register_w {
($mod_name: ident, $struct_name: ident) => (
impl libregister::RegisterW for $struct_name {
impl $crate::RegisterW for $struct_name {
type W = $mod_name::Write;
#[inline]
@ -88,7 +89,7 @@ macro_rules! register_w {
#[macro_export]
macro_rules! register_rw {
($mod_name: ident, $struct_name: ident) => (
impl libregister::RegisterRW for $struct_name {
impl $crate::RegisterRW for $struct_name {
#[inline]
fn modify<F: FnOnce(Self::R, Self::W) -> Self::W>(&mut self, f: F) {
unsafe {
@ -101,7 +102,7 @@ macro_rules! register_rw {
}
);
($mod_name: ident, $struct_name: ident, $mask: expr) => (
impl libregister::RegisterRW for $struct_name {
impl $crate::RegisterRW for $struct_name {
#[inline]
fn modify<F: FnOnce(Self::R, Self::W) -> Self::W>(&mut self, f: F) {
unsafe {
@ -119,7 +120,7 @@ macro_rules! register_rw {
#[macro_export]
macro_rules! register_vcell {
($mod_name: ident, $struct_name: ident) => (
impl libregister::RegisterR for $struct_name {
impl $crate::RegisterR for $struct_name {
type R = $mod_name::Read;
#[inline]
@ -128,7 +129,7 @@ macro_rules! register_vcell {
$mod_name::Read { inner }
}
}
impl libregister::RegisterW for $struct_name {
impl $crate::RegisterW for $struct_name {
type W = $mod_name::Write;
#[inline]
@ -141,7 +142,7 @@ macro_rules! register_vcell {
self.inner.set(w.inner);
}
}
impl libregister::RegisterRW for $struct_name {
impl $crate::RegisterRW for $struct_name {
#[inline]
fn modify<F: FnOnce(Self::R, Self::W) -> Self::W>(&mut self, f: F) {
let r = self.read();
@ -157,37 +158,37 @@ macro_rules! register_vcell {
#[macro_export]
macro_rules! register {
// Define read-only register
($mod_name: ident, $struct_name: ident, RO, $inner: ty) => (
libregister::register_common!($mod_name, $struct_name, libregister::RO<$inner>, $inner);
libregister::register_r!($mod_name, $struct_name);
($mod_name: ident, $(#[$outer:meta])* $struct_name: ident, RO, $inner: ty) => (
$crate::register_common!($mod_name, $(#[$outer])* $struct_name, $crate::RO<$inner>, $inner);
$crate::register_r!($mod_name, $struct_name);
);
// Define write-only register
($mod_name: ident, $struct_name: ident, WO, $inner: ty) => (
libregister::register_common!($mod_name, $struct_name, volatile_register::WO<$inner>, $inner);
libregister::register_w!($mod_name, $struct_name);
($mod_name: ident, $(#[$outer:meta])* $struct_name: ident, WO, $inner: ty) => (
$crate::register_common!($mod_name, $(#[$outer])* $struct_name, volatile_register::WO<$inner>, $inner);
$crate::register_w!($mod_name, $struct_name);
);
// Define read-write register
($mod_name: ident, $struct_name: ident, RW, $inner: ty) => (
libregister::register_common!($mod_name, $struct_name, volatile_register::RW<$inner>, $inner);
libregister::register_r!($mod_name, $struct_name);
libregister::register_w!($mod_name, $struct_name);
libregister::register_rw!($mod_name, $struct_name);
($mod_name: ident, $(#[$outer:meta])* $struct_name: ident, RW, $inner: ty) => (
$crate::register_common!($mod_name, $(#[$outer])* $struct_name, volatile_register::RW<$inner>, $inner);
$crate::register_r!($mod_name, $struct_name);
$crate::register_w!($mod_name, $struct_name);
$crate::register_rw!($mod_name, $struct_name);
);
// Define read-write register
($mod_name: ident, $struct_name: ident, VolatileCell, $inner: ty) => (
libregister::register_common!($mod_name, $struct_name, VolatileCell<$inner>, $inner);
libregister::register_vcell!($mod_name, $struct_name);
($mod_name: ident, $(#[$outer:meta])* $struct_name: ident, VolatileCell, $inner: ty) => (
$crate::register_common!($mod_name, $(#[$outer])* $struct_name, VolatileCell<$inner>, $inner);
$crate::register_vcell!($mod_name, $struct_name);
);
// Define read-write register with mask on write (for WTC mixed access.)
($mod_name: ident, $struct_name: ident, RW, $inner: ty, $mask: expr) => (
libregister::register_common!($mod_name, $struct_name, volatile_register::RW<$inner>, $inner);
libregister::register_r!($mod_name, $struct_name);
libregister::register_w!($mod_name, $struct_name);
libregister::register_rw!($mod_name, $struct_name, $mask);
($mod_name: ident, $(#[$outer:meta])* $struct_name: ident, RW, $inner: ty, $mask: expr) => (
$crate::register_common!($mod_name, $(#[$outer])* $struct_name, volatile_register::RW<$inner>, $inner);
$crate::register_r!($mod_name, $struct_name);
$crate::register_w!($mod_name, $struct_name);
$crate::register_rw!($mod_name, $struct_name, $mask);
);
}

View File

@ -7,18 +7,23 @@ edition = "2018"
[features]
target_zc706 = ["libboard_zynq/target_zc706"]
target_cora_z7_10 = ["libboard_zynq/target_cora_z7_10"]
target_coraz7 = ["libboard_zynq/target_coraz7"]
target_redpitaya = ["libboard_zynq/target_redpitaya"]
target_kasli_soc = ["libboard_zynq/target_kasli_soc"]
panic_handler = []
dummy_irq_handler = []
dummy_fiq_handler = []
alloc_core = []
default = ["panic_handler", "dummy_irq_handler"]
default = ["panic_handler", "dummy_irq_handler", "dummy_fiq_handler"]
[dependencies]
r0 = "1"
compiler_builtins = "0.1"
linked_list_allocator = { version = "0.8", default-features = false }
compiler_builtins = "=0.1.39"
linked_list_allocator = { version = "0.8", default-features = false, features = ["const_mut_refs"] }
libregister = { path = "../libregister" }
libcortex_a9 = { path = "../libcortex_a9" }
libboard_zynq = { path = "../libboard_zynq" }
[build-dependencies]
cc = { version = "1.0" }

24
libsupport_zynq/build.rs Normal file
View File

@ -0,0 +1,24 @@
fn main() {
println!("cargo:rerun-if-changed=build.rs");
compile_memcpy();
}
fn compile_memcpy() {
use std::path::Path;
extern crate cc;
let cfg = &mut cc::Build::new();
cfg.compiler("clang");
cfg.no_default_flags(true);
cfg.warnings(false);
cfg.flag("--target=armv7-none-eabihf");
let sources = vec![
"memcpy.S",
];
let root = Path::new("src/asm");
for src in sources {
println!("cargo:rerun-if-changed={}", src);
cfg.file(root.join(src));
}
cfg.compile("memcpy");
}

View File

@ -1,70 +0,0 @@
use libregister::RegisterR;
use libcortex_a9::regs::{DFSR, MPIDR};
use libboard_zynq::{println, stdio};
#[link_section = ".text.boot"]
#[no_mangle]
#[naked]
pub unsafe extern "C" fn UndefinedInstruction() {
stdio::drop_uart();
println!("UndefinedInstruction");
loop {}
}
#[link_section = ".text.boot"]
#[no_mangle]
#[naked]
pub unsafe extern "C" fn SoftwareInterrupt() {
stdio::drop_uart();
println!("SoftwareInterrupt");
loop {}
}
#[link_section = ".text.boot"]
#[no_mangle]
#[naked]
pub unsafe extern "C" fn PrefetchAbort() {
stdio::drop_uart();
println!("PrefetchAbort");
loop {}
}
#[link_section = ".text.boot"]
#[no_mangle]
#[naked]
pub unsafe extern "C" fn DataAbort() {
stdio::drop_uart();
println!("DataAbort on core {}", MPIDR.read().cpu_id());
println!("DFSR: {:03X}", DFSR.read());
loop {}
}
#[link_section = ".text.boot"]
#[no_mangle]
#[naked]
pub unsafe extern "C" fn ReservedException() {
stdio::drop_uart();
println!("ReservedException");
loop {}
}
#[link_section = ".text.boot"]
#[no_mangle]
#[naked]
#[cfg(feature = "dummy_irq_handler")]
pub unsafe extern "C" fn IRQ() {
stdio::drop_uart();
println!("IRQ");
loop {}
}
#[link_section = ".text.boot"]
#[no_mangle]
#[naked]
pub unsafe extern "C" fn FIQ() {
stdio::drop_uart();
println!("FIQ");
loop {}
}

View File

@ -0,0 +1,626 @@
/* Copyright (c) 2013, Linaro Limited
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of Linaro Limited nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
This memcpy routine is optimised for Cortex-A15 cores and takes advantage
of VFP or NEON when built with the appropriate flags.
Assumptions:
ARMv6 (ARMv7-a if using Neon)
ARM state
Unaligned accesses
LDRD/STRD support unaligned word accesses
If compiled with GCC, this file should be enclosed within following
pre-processing check:
if defined (__ARM_ARCH_7A__) && defined (__ARM_FEATURE_UNALIGNED)
*/
.syntax unified
/* This implementation requires ARM state. */
.arm
#ifdef __ARM_NEON__
.fpu neon
.arch armv7-a
# define FRAME_SIZE 4
# define USE_VFP
# define USE_NEON
#elif !defined (__SOFTFP__)
.arch armv6
.fpu vfpv2
# define FRAME_SIZE 32
# define USE_VFP
#else
.arch armv6
# define FRAME_SIZE 32
#endif
/* Old versions of GAS incorrectly implement the NEON align semantics. */
#ifdef BROKEN_ASM_NEON_ALIGN
#define ALIGN(addr, align) addr,:align
#else
#define ALIGN(addr, align) addr:align
#endif
#define PC_OFFSET 8 /* PC pipeline compensation. */
#define INSN_SIZE 4
/* Call parameters. */
#define dstin r0
#define src r1
#define count r2
/* Locals. */
#define tmp1 r3
#define dst ip
#define tmp2 r10
#ifndef USE_NEON
/* For bulk copies using GP registers. */
#define A_l r2 /* Call-clobbered. */
#define A_h r3 /* Call-clobbered. */
#define B_l r4
#define B_h r5
#define C_l r6
#define C_h r7
#define D_l r8
#define D_h r9
#endif
/* Number of lines ahead to pre-fetch data. If you change this the code
below will need adjustment to compensate. */
#define prefetch_lines 5
#ifdef USE_VFP
.macro cpy_line_vfp vreg, base
vstr \vreg, [dst, #\base]
vldr \vreg, [src, #\base]
vstr d0, [dst, #\base + 8]
vldr d0, [src, #\base + 8]
vstr d1, [dst, #\base + 16]
vldr d1, [src, #\base + 16]
vstr d2, [dst, #\base + 24]
vldr d2, [src, #\base + 24]
vstr \vreg, [dst, #\base + 32]
vldr \vreg, [src, #\base + prefetch_lines * 64 - 32]
vstr d0, [dst, #\base + 40]
vldr d0, [src, #\base + 40]
vstr d1, [dst, #\base + 48]
vldr d1, [src, #\base + 48]
vstr d2, [dst, #\base + 56]
vldr d2, [src, #\base + 56]
.endm
.macro cpy_tail_vfp vreg, base
vstr \vreg, [dst, #\base]
vldr \vreg, [src, #\base]
vstr d0, [dst, #\base + 8]
vldr d0, [src, #\base + 8]
vstr d1, [dst, #\base + 16]
vldr d1, [src, #\base + 16]
vstr d2, [dst, #\base + 24]
vldr d2, [src, #\base + 24]
vstr \vreg, [dst, #\base + 32]
vstr d0, [dst, #\base + 40]
vldr d0, [src, #\base + 40]
vstr d1, [dst, #\base + 48]
vldr d1, [src, #\base + 48]
vstr d2, [dst, #\base + 56]
vldr d2, [src, #\base + 56]
.endm
#endif
.macro def_fn f p2align=0
.text
.p2align \p2align
.global \f
.type \f, %function
\f:
.endm
.global __aeabi_memcpy
.global __aeabi_memcpy4
.global __aeabi_memcpy8
.set __aeabi_memcpy, fast_memcpy
.set __aeabi_memcpy4, fast_memcpy
.set __aeabi_memcpy8, fast_memcpy
def_fn fast_memcpy p2align=6
mov dst, dstin /* Preserve dstin, we need to return it. */
cmp count, #64
bge .Lcpy_not_short
/* Deal with small copies quickly by dropping straight into the
exit block. */
.Ltail63unaligned:
#ifdef USE_NEON
and tmp1, count, #0x38
rsb tmp1, tmp1, #(56 - PC_OFFSET + INSN_SIZE)
add pc, pc, tmp1
vld1.8 {d0}, [src]! /* 14 words to go. */
vst1.8 {d0}, [dst]!
vld1.8 {d0}, [src]! /* 12 words to go. */
vst1.8 {d0}, [dst]!
vld1.8 {d0}, [src]! /* 10 words to go. */
vst1.8 {d0}, [dst]!
vld1.8 {d0}, [src]! /* 8 words to go. */
vst1.8 {d0}, [dst]!
vld1.8 {d0}, [src]! /* 6 words to go. */
vst1.8 {d0}, [dst]!
vld1.8 {d0}, [src]! /* 4 words to go. */
vst1.8 {d0}, [dst]!
vld1.8 {d0}, [src]! /* 2 words to go. */
vst1.8 {d0}, [dst]!
tst count, #4
ldrne tmp1, [src], #4
strne tmp1, [dst], #4
#else
/* Copy up to 15 full words of data. May not be aligned. */
/* Cannot use VFP for unaligned data. */
and tmp1, count, #0x3c
add dst, dst, tmp1
add src, src, tmp1
rsb tmp1, tmp1, #(60 - PC_OFFSET/2 + INSN_SIZE/2)
/* Jump directly into the sequence below at the correct offset. */
add pc, pc, tmp1, lsl #1
ldr tmp1, [src, #-60] /* 15 words to go. */
str tmp1, [dst, #-60]
ldr tmp1, [src, #-56] /* 14 words to go. */
str tmp1, [dst, #-56]
ldr tmp1, [src, #-52]
str tmp1, [dst, #-52]
ldr tmp1, [src, #-48] /* 12 words to go. */
str tmp1, [dst, #-48]
ldr tmp1, [src, #-44]
str tmp1, [dst, #-44]
ldr tmp1, [src, #-40] /* 10 words to go. */
str tmp1, [dst, #-40]
ldr tmp1, [src, #-36]
str tmp1, [dst, #-36]
ldr tmp1, [src, #-32] /* 8 words to go. */
str tmp1, [dst, #-32]
ldr tmp1, [src, #-28]
str tmp1, [dst, #-28]
ldr tmp1, [src, #-24] /* 6 words to go. */
str tmp1, [dst, #-24]
ldr tmp1, [src, #-20]
str tmp1, [dst, #-20]
ldr tmp1, [src, #-16] /* 4 words to go. */
str tmp1, [dst, #-16]
ldr tmp1, [src, #-12]
str tmp1, [dst, #-12]
ldr tmp1, [src, #-8] /* 2 words to go. */
str tmp1, [dst, #-8]
ldr tmp1, [src, #-4]
str tmp1, [dst, #-4]
#endif
lsls count, count, #31
ldrhcs tmp1, [src], #2
ldrbne src, [src] /* Src is dead, use as a scratch. */
strhcs tmp1, [dst], #2
strbne src, [dst]
bx lr
.Lcpy_not_short:
/* At least 64 bytes to copy, but don't know the alignment yet. */
str tmp2, [sp, #-FRAME_SIZE]!
and tmp2, src, #7
and tmp1, dst, #7
cmp tmp1, tmp2
bne .Lcpy_notaligned
#ifdef USE_VFP
/* Magic dust alert! Force VFP on Cortex-A9. Experiments show
that the FP pipeline is much better at streaming loads and
stores. This is outside the critical loop. */
vmov.f32 s0, s0
#endif
/* SRC and DST have the same mutual 32-bit alignment, but we may
still need to pre-copy some bytes to get to natural alignment.
We bring DST into full 64-bit alignment. */
lsls tmp2, dst, #29
beq 1f
rsbs tmp2, tmp2, #0
sub count, count, tmp2, lsr #29
ldrmi tmp1, [src], #4
strmi tmp1, [dst], #4
lsls tmp2, tmp2, #2
ldrhcs tmp1, [src], #2
ldrbne tmp2, [src], #1
strhcs tmp1, [dst], #2
strbne tmp2, [dst], #1
1:
subs tmp2, count, #64 /* Use tmp2 for count. */
blt .Ltail63aligned
cmp tmp2, #512
bge .Lcpy_body_long
.Lcpy_body_medium: /* Count in tmp2. */
#ifdef USE_VFP
1:
vldr d0, [src, #0]
subs tmp2, tmp2, #64
vldr d1, [src, #8]
vstr d0, [dst, #0]
vldr d0, [src, #16]
vstr d1, [dst, #8]
vldr d1, [src, #24]
vstr d0, [dst, #16]
vldr d0, [src, #32]
vstr d1, [dst, #24]
vldr d1, [src, #40]
vstr d0, [dst, #32]
vldr d0, [src, #48]
vstr d1, [dst, #40]
vldr d1, [src, #56]
vstr d0, [dst, #48]
add src, src, #64
vstr d1, [dst, #56]
add dst, dst, #64
bge 1b
tst tmp2, #0x3f
beq .Ldone
.Ltail63aligned: /* Count in tmp2. */
and tmp1, tmp2, #0x38
add dst, dst, tmp1
add src, src, tmp1
rsb tmp1, tmp1, #(56 - PC_OFFSET + INSN_SIZE)
add pc, pc, tmp1
vldr d0, [src, #-56] /* 14 words to go. */
vstr d0, [dst, #-56]
vldr d0, [src, #-48] /* 12 words to go. */
vstr d0, [dst, #-48]
vldr d0, [src, #-40] /* 10 words to go. */
vstr d0, [dst, #-40]
vldr d0, [src, #-32] /* 8 words to go. */
vstr d0, [dst, #-32]
vldr d0, [src, #-24] /* 6 words to go. */
vstr d0, [dst, #-24]
vldr d0, [src, #-16] /* 4 words to go. */
vstr d0, [dst, #-16]
vldr d0, [src, #-8] /* 2 words to go. */
vstr d0, [dst, #-8]
#else
sub src, src, #8
sub dst, dst, #8
1:
ldrd A_l, A_h, [src, #8]
strd A_l, A_h, [dst, #8]
ldrd A_l, A_h, [src, #16]
strd A_l, A_h, [dst, #16]
ldrd A_l, A_h, [src, #24]
strd A_l, A_h, [dst, #24]
ldrd A_l, A_h, [src, #32]
strd A_l, A_h, [dst, #32]
ldrd A_l, A_h, [src, #40]
strd A_l, A_h, [dst, #40]
ldrd A_l, A_h, [src, #48]
strd A_l, A_h, [dst, #48]
ldrd A_l, A_h, [src, #56]
strd A_l, A_h, [dst, #56]
ldrd A_l, A_h, [src, #64]!
strd A_l, A_h, [dst, #64]!
subs tmp2, tmp2, #64
bge 1b
tst tmp2, #0x3f
bne 1f
ldr tmp2,[sp], #FRAME_SIZE
bx lr
1:
add src, src, #8
add dst, dst, #8
.Ltail63aligned: /* Count in tmp2. */
/* Copy up to 7 d-words of data. Similar to Ltail63unaligned, but
we know that the src and dest are 32-bit aligned so we can use
LDRD/STRD to improve efficiency. */
/* TMP2 is now negative, but we don't care about that. The bottom
six bits still tell us how many bytes are left to copy. */
and tmp1, tmp2, #0x38
add dst, dst, tmp1
add src, src, tmp1
rsb tmp1, tmp1, #(56 - PC_OFFSET + INSN_SIZE)
add pc, pc, tmp1
ldrd A_l, A_h, [src, #-56] /* 14 words to go. */
strd A_l, A_h, [dst, #-56]
ldrd A_l, A_h, [src, #-48] /* 12 words to go. */
strd A_l, A_h, [dst, #-48]
ldrd A_l, A_h, [src, #-40] /* 10 words to go. */
strd A_l, A_h, [dst, #-40]
ldrd A_l, A_h, [src, #-32] /* 8 words to go. */
strd A_l, A_h, [dst, #-32]
ldrd A_l, A_h, [src, #-24] /* 6 words to go. */
strd A_l, A_h, [dst, #-24]
ldrd A_l, A_h, [src, #-16] /* 4 words to go. */
strd A_l, A_h, [dst, #-16]
ldrd A_l, A_h, [src, #-8] /* 2 words to go. */
strd A_l, A_h, [dst, #-8]
#endif
tst tmp2, #4
ldrne tmp1, [src], #4
strne tmp1, [dst], #4
lsls tmp2, tmp2, #31 /* Count (tmp2) now dead. */
ldrhcs tmp1, [src], #2
ldrbne tmp2, [src]
strhcs tmp1, [dst], #2
strbne tmp2, [dst]
.Ldone:
ldr tmp2, [sp], #FRAME_SIZE
bx lr
.Lcpy_body_long: /* Count in tmp2. */
/* Long copy. We know that there's at least (prefetch_lines * 64)
bytes to go. */
#ifdef USE_VFP
/* Don't use PLD. Instead, read some data in advance of the current
copy position into a register. This should act like a PLD
operation but we won't have to repeat the transfer. */
vldr d3, [src, #0]
vldr d4, [src, #64]
vldr d5, [src, #128]
vldr d6, [src, #192]
vldr d7, [src, #256]
vldr d0, [src, #8]
vldr d1, [src, #16]
vldr d2, [src, #24]
add src, src, #32
subs tmp2, tmp2, #prefetch_lines * 64 * 2
blt 2f
1:
cpy_line_vfp d3, 0
cpy_line_vfp d4, 64
cpy_line_vfp d5, 128
add dst, dst, #3 * 64
add src, src, #3 * 64
cpy_line_vfp d6, 0
cpy_line_vfp d7, 64
add dst, dst, #2 * 64
add src, src, #2 * 64
subs tmp2, tmp2, #prefetch_lines * 64
bge 1b
2:
cpy_tail_vfp d3, 0
cpy_tail_vfp d4, 64
cpy_tail_vfp d5, 128
add src, src, #3 * 64
add dst, dst, #3 * 64
cpy_tail_vfp d6, 0
vstr d7, [dst, #64]
vldr d7, [src, #64]
vstr d0, [dst, #64 + 8]
vldr d0, [src, #64 + 8]
vstr d1, [dst, #64 + 16]
vldr d1, [src, #64 + 16]
vstr d2, [dst, #64 + 24]
vldr d2, [src, #64 + 24]
vstr d7, [dst, #64 + 32]
add src, src, #96
vstr d0, [dst, #64 + 40]
vstr d1, [dst, #64 + 48]
vstr d2, [dst, #64 + 56]
add dst, dst, #128
add tmp2, tmp2, #prefetch_lines * 64
b .Lcpy_body_medium
#else
/* Long copy. Use an SMS style loop to maximize the I/O
bandwidth of the core. We don't have enough spare registers
to synthesise prefetching, so use PLD operations. */
/* Pre-bias src and dst. */
sub src, src, #8
sub dst, dst, #8
pld [src, #8]
pld [src, #72]
subs tmp2, tmp2, #64
pld [src, #136]
ldrd A_l, A_h, [src, #8]
strd B_l, B_h, [sp, #8]
ldrd B_l, B_h, [src, #16]
strd C_l, C_h, [sp, #16]
ldrd C_l, C_h, [src, #24]
strd D_l, D_h, [sp, #24]
pld [src, #200]
ldrd D_l, D_h, [src, #32]!
b 1f
.p2align 6
2:
pld [src, #232]
strd A_l, A_h, [dst, #40]
ldrd A_l, A_h, [src, #40]
strd B_l, B_h, [dst, #48]
ldrd B_l, B_h, [src, #48]
strd C_l, C_h, [dst, #56]
ldrd C_l, C_h, [src, #56]
strd D_l, D_h, [dst, #64]!
ldrd D_l, D_h, [src, #64]!
subs tmp2, tmp2, #64
1:
strd A_l, A_h, [dst, #8]
ldrd A_l, A_h, [src, #8]
strd B_l, B_h, [dst, #16]
ldrd B_l, B_h, [src, #16]
strd C_l, C_h, [dst, #24]
ldrd C_l, C_h, [src, #24]
strd D_l, D_h, [dst, #32]
ldrd D_l, D_h, [src, #32]
bcs 2b
/* Save the remaining bytes and restore the callee-saved regs. */
strd A_l, A_h, [dst, #40]
add src, src, #40
strd B_l, B_h, [dst, #48]
ldrd B_l, B_h, [sp, #8]
strd C_l, C_h, [dst, #56]
ldrd C_l, C_h, [sp, #16]
strd D_l, D_h, [dst, #64]
ldrd D_l, D_h, [sp, #24]
add dst, dst, #72
tst tmp2, #0x3f
bne .Ltail63aligned
ldr tmp2, [sp], #FRAME_SIZE
bx lr
#endif
.Lcpy_notaligned:
pld [src]
pld [src, #64]
/* There's at least 64 bytes to copy, but there is no mutual
alignment. */
/* Bring DST to 64-bit alignment. */
lsls tmp2, dst, #29
pld [src, #(2 * 64)]
beq 1f
rsbs tmp2, tmp2, #0
sub count, count, tmp2, lsr #29
ldrmi tmp1, [src], #4
strmi tmp1, [dst], #4
lsls tmp2, tmp2, #2
ldrbne tmp1, [src], #1
ldrhcs tmp2, [src], #2
strbne tmp1, [dst], #1
strhcs tmp2, [dst], #2
1:
pld [src, #(3 * 64)]
subs count, count, #64
ldrmi tmp2, [sp], #FRAME_SIZE
bmi .Ltail63unaligned
pld [src, #(4 * 64)]
#ifdef USE_NEON
vld1.8 {d0-d3}, [src]!
vld1.8 {d4-d7}, [src]!
subs count, count, #64
bmi 2f
1:
pld [src, #(4 * 64)]
vst1.8 {d0-d3}, [ALIGN (dst, 64)]!
vld1.8 {d0-d3}, [src]!
vst1.8 {d4-d7}, [ALIGN (dst, 64)]!
vld1.8 {d4-d7}, [src]!
subs count, count, #64
bpl 1b
2:
vst1.8 {d0-d3}, [ALIGN (dst, 64)]!
vst1.8 {d4-d7}, [ALIGN (dst, 64)]!
ands count, count, #0x3f
#else
/* Use an SMS style loop to maximize the I/O bandwidth. */
sub src, src, #4
sub dst, dst, #8
subs tmp2, count, #64 /* Use tmp2 for count. */
ldr A_l, [src, #4]
ldr A_h, [src, #8]
strd B_l, B_h, [sp, #8]
ldr B_l, [src, #12]
ldr B_h, [src, #16]
strd C_l, C_h, [sp, #16]
ldr C_l, [src, #20]
ldr C_h, [src, #24]
strd D_l, D_h, [sp, #24]
ldr D_l, [src, #28]
ldr D_h, [src, #32]!
b 1f
.p2align 6
2:
pld [src, #(5 * 64) - (32 - 4)]
strd A_l, A_h, [dst, #40]
ldr A_l, [src, #36]
ldr A_h, [src, #40]
strd B_l, B_h, [dst, #48]
ldr B_l, [src, #44]
ldr B_h, [src, #48]
strd C_l, C_h, [dst, #56]
ldr C_l, [src, #52]
ldr C_h, [src, #56]
strd D_l, D_h, [dst, #64]!
ldr D_l, [src, #60]
ldr D_h, [src, #64]!
subs tmp2, tmp2, #64
1:
strd A_l, A_h, [dst, #8]
ldr A_l, [src, #4]
ldr A_h, [src, #8]
strd B_l, B_h, [dst, #16]
ldr B_l, [src, #12]
ldr B_h, [src, #16]
strd C_l, C_h, [dst, #24]
ldr C_l, [src, #20]
ldr C_h, [src, #24]
strd D_l, D_h, [dst, #32]
ldr D_l, [src, #28]
ldr D_h, [src, #32]
bcs 2b
/* Save the remaining bytes and restore the callee-saved regs. */
strd A_l, A_h, [dst, #40]
add src, src, #36
strd B_l, B_h, [dst, #48]
ldrd B_l, B_h, [sp, #8]
strd C_l, C_h, [dst, #56]
ldrd C_l, C_h, [sp, #16]
strd D_l, D_h, [dst, #64]
ldrd D_l, D_h, [sp, #24]
add dst, dst, #72
ands count, tmp2, #0x3f
#endif
ldr tmp2, [sp], #FRAME_SIZE
bne .Ltail63unaligned
bx lr
.size memcpy, . - memcpy

View File

@ -2,9 +2,9 @@ use r0::zero_bss;
use core::ptr::write_volatile;
use libregister::{
VolatileCell,
RegisterR, RegisterW, RegisterRW,
RegisterR, RegisterRW,
};
use libcortex_a9::{asm, l2c, regs::*, cache, mmu, spin_lock_yield, notify_spin_lock};
use libcortex_a9::{asm, l2c, regs::*, cache, mmu, spin_lock_yield, notify_spin_lock, enable_fpu, interrupt_handler};
use libboard_zynq::{slcr, mpcore};
extern "C" {
@ -18,31 +18,27 @@ extern "C" {
static mut CORE1_ENABLED: VolatileCell<bool> = VolatileCell::new(false);
#[link_section = ".text.boot"]
#[no_mangle]
#[naked]
pub unsafe extern "C" fn Reset() -> ! {
interrupt_handler!(Reset, reset_irq, __stack0_start, __stack1_start, {
// no need to setup stack here, as we already did when entering the handler
match MPIDR.read().cpu_id() {
0 => {
SP.write(&mut __stack0_start as *mut _ as u32);
boot_core0();
}
1 => {
while !CORE1_ENABLED.get() {
spin_lock_yield();
}
SP.write(&mut __stack1_start as *mut _ as u32);
boot_core1();
}
_ => unreachable!(),
}
}
});
#[naked]
#[inline(never)]
unsafe fn boot_core0() -> ! {
unsafe extern "C" fn boot_core0() -> ! {
l1_cache_init();
enable_fpu();
let mpcore = mpcore::RegisterBlock::mpcore();
mpcore.scu_invalidate.invalidate_all_cores();
@ -58,15 +54,15 @@ unsafe fn boot_core0() -> ! {
asm::dmb();
asm::dsb();
asm::enable_fiq();
asm::enable_irq();
main_core0();
panic!("return from main");
});
}
#[naked]
#[inline(never)]
unsafe fn boot_core1() -> ! {
unsafe extern "C" fn boot_core1() -> ! {
l1_cache_init();
let mpcore = mpcore::RegisterBlock::mpcore();
@ -80,6 +76,7 @@ unsafe fn boot_core1() -> ! {
asm::dmb();
asm::dsb();
asm::enable_fiq();
asm::enable_irq();
main_core1();
panic!("return from main_core1");

View File

@ -0,0 +1,54 @@
use libregister::{RegisterR, RegisterW};
use libcortex_a9::{regs::{DFSR, MPIDR, VBAR}, interrupt_handler};
use libboard_zynq::{println, stdio};
pub fn set_vector_table(base_addr: u32){
VBAR.write(base_addr);
}
interrupt_handler!(UndefinedInstruction, undefined_instruction, __irq_stack0_start, __irq_stack1_start, {
stdio::drop_uart();
println!("UndefinedInstruction");
loop {}
});
interrupt_handler!(SoftwareInterrupt, software_interrupt, __irq_stack0_start, __irq_stack1_start, {
stdio::drop_uart();
println!("SoftwareInterrupt");
loop {}
});
interrupt_handler!(PrefetchAbort, prefetch_abort, __irq_stack0_start, __irq_stack1_start, {
stdio::drop_uart();
println!("PrefetchAbort");
loop {}
});
interrupt_handler!(DataAbort, data_abort, __irq_stack0_start, __irq_stack1_start, {
stdio::drop_uart();
println!("DataAbort on core {}", MPIDR.read().cpu_id());
println!("DFSR: {:03X}", DFSR.read());
loop {}
});
interrupt_handler!(ReservedException, reserved_exception, __irq_stack0_start, __irq_stack1_start, {
stdio::drop_uart();
println!("ReservedException");
loop {}
});
#[cfg(feature = "dummy_irq_handler")]
interrupt_handler!(IRQ, irq, __irq_stack0_start, __irq_stack1_start, {
stdio::drop_uart();
println!("IRQ");
loop {}
});
#[cfg(feature = "dummy_fiq_handler")]
interrupt_handler!(FIQ, fiq, __irq_stack0_start, __irq_stack1_start, {
stdio::drop_uart();
println!("FIQ");
loop {}
});

View File

@ -1,14 +1,16 @@
#![no_std]
#![feature(naked_functions)]
#![feature(alloc_error_handler)]
#![feature(panic_info_message)]
#![feature(naked_functions)]
#![feature(asm)]
pub extern crate alloc;
pub extern crate compiler_builtins;
pub mod boot;
mod abort;
pub mod exception_vectors;
#[cfg(feature = "panic_handler")]
mod panic;
pub mod ram;

View File

@ -1,4 +1,6 @@
use libboard_zynq::{print, println};
#[cfg(feature = "target_kasli_soc")]
use libboard_zynq::error_led::ErrorLED;
#[panic_handler]
fn panic(info: &core::panic::PanicInfo) -> ! {
@ -13,6 +15,10 @@ fn panic(info: &core::panic::PanicInfo) -> ! {
} else {
println!("");
}
#[cfg(feature = "target_kasli_soc")]
{
let mut err_led = ErrorLED::error_led();
err_led.toggle(true);
}
loop {}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,37 +0,0 @@
{ pkgs, board ? "zc706" }:
let
gnutoolchain = import ./gnutoolchain.nix { inherit pkgs; };
in
pkgs.stdenv.mkDerivation {
name = "${board}-fsbl";
src = pkgs.fetchFromGitHub {
owner = "Xilinx";
repo = "embeddedsw";
rev = "65c849ed46c88c67457e1fc742744f96db968ff1";
sha256 = "1rvl06ha40dzd6s9aa4sylmksh4xb9dqaxq462lffv1fdk342pda";
};
patches = [ ./fsbl.patch ];
nativeBuildInputs = [
pkgs.gnumake
gnutoolchain.binutils
gnutoolchain.gcc
];
patchPhase =
''
patch -p1 -i ${./fsbl.patch}
patchShebangs lib/sw_apps/zynq_fsbl/misc/copy_bsp.sh
echo 'SEARCH_DIR("${gnutoolchain.newlib}/arm-none-eabi/lib");' >> lib/sw_apps/zynq_fsbl/src/lscript.ld
'';
buildPhase =
''
cd lib/sw_apps/zynq_fsbl/src
make BOARD=${board} "CFLAGS=-DFSBL_DEBUG_INFO -g"
'';
installPhase =
''
mkdir $out
cp fsbl.elf $out
'';
doCheck = false;
dontFixup = true;
}

View File

@ -1,31 +0,0 @@
diff --git a/lib/sw_apps/zynq_fsbl/src/Makefile b/lib/sw_apps/zynq_fsbl/src/Makefile
index 0e3ccdf1c5..a5b02f386e 100644
--- a/lib/sw_apps/zynq_fsbl/src/Makefile
+++ b/lib/sw_apps/zynq_fsbl/src/Makefile
@@ -71,11 +71,14 @@ endif
all: $(EXEC)
$(EXEC): $(LIBS) $(OBJS) $(INCLUDES)
- cp $(BSP_DIR)/$(BOARD)/ps7_init.* .
$(LINKER) $(LD1FLAGS) -o $@ $(OBJS) $(LDFLAGS)
rm -rf $(OBJS)
-
-
+
+.PHONY: ps7_init
+
+ps7_init:
+ cp $(BSP_DIR)/$(BOARD)/ps7_init.* .
+
$(LIBS):
echo "Copying BSP files"
$(BSP_DIR)/copy_bsp.sh $(BOARD) $(CC)
@@ -86,7 +89,7 @@ $(LIBS):
make -C $(BSP_DIR) -k all "CC=armcc" "AR=armar" "C_FLAGS= -O2 -c" "EC_FLAGS=--debug --wchar32"; \
fi;
-%.o:%.c
+%.o:%.c ps7_init
$(CC) $(CC_FLAGS) $(CFLAGS) $(ECFLAGS) -c $< -o $@ $(INCLUDEPATH)
%.o:%.S

View File

@ -1,134 +0,0 @@
{ pkgs ? import <nixpkgs> }:
let
platform = "arm-none-eabi";
binutils-pkg = { stdenv, buildPackages
, fetchurl, zlib
, extraConfigureFlags ? []
}:
stdenv.mkDerivation rec {
basename = "binutils";
version = "2.30";
name = "${basename}-${platform}-${version}";
src = fetchurl {
url = "https://ftp.gnu.org/gnu/binutils/binutils-${version}.tar.bz2";
sha256 = "028cklfqaab24glva1ks2aqa1zxa6w6xmc8q34zs1sb7h22dxspg";
};
configureFlags = [
"--enable-deterministic-archives"
"--target=${platform}"
"--with-cpu=cortex-a9"
"--with-fpu=vfpv3"
"--with-float=hard"
"--with-mode=thumb"
] ++ extraConfigureFlags;
outputs = [ "out" "info" "man" ];
depsBuildBuild = [ buildPackages.stdenv.cc ];
buildInputs = [ zlib ];
enableParallelBuilding = true;
meta = {
description = "Tools for manipulating binaries (linker, assembler, etc.)";
longDescription = ''
The GNU Binutils are a collection of binary tools. The main
ones are `ld' (the GNU linker) and `as' (the GNU assembler).
They also include the BFD (Binary File Descriptor) library,
`gprof', `nm', `strip', etc.
'';
homepage = http://www.gnu.org/software/binutils/;
license = stdenv.lib.licenses.gpl3Plus;
/* Give binutils a lower priority than gcc-wrapper to prevent a
collision due to the ld/as wrappers/symlinks in the latter. */
priority = "10";
};
};
gcc-pkg = { stdenv, buildPackages
, fetchurl, gmp, mpfr, libmpc, platform-binutils
, extraConfigureFlags ? []
}:
stdenv.mkDerivation rec {
basename = "gcc";
version = "9.1.0";
name = "${basename}-${platform}-${version}";
src = fetchurl {
url = "https://ftp.gnu.org/gnu/gcc/gcc-${version}/gcc-${version}.tar.xz";
sha256 = "1817nc2bqdc251k0lpc51cimna7v68xjrnvqzvc50q3ax4s6i9kr";
};
preConfigure =
''
mkdir build
cd build
'';
configureScript = "../configure";
configureFlags =
[ "--target=${platform}"
"--with-arch=armv7-a"
"--with-tune=cortex-a9"
"--with-fpu=vfpv3"
"--with-float=hard"
"--disable-libssp"
"--enable-languages=c"
"--with-as=${platform-binutils}/bin/${platform}-as"
"--with-ld=${platform-binutils}/bin/${platform}-ld" ] ++ extraConfigureFlags;
outputs = [ "out" "info" "man" ];
hardeningDisable = [ "format" "pie" ];
propagatedBuildInputs = [ gmp mpfr libmpc platform-binutils ];
enableParallelBuilding = true;
dontFixup = true;
};
newlib-pkg = { stdenv, fetchurl, buildPackages, platform-binutils, platform-gcc }:
stdenv.mkDerivation rec {
pname = "newlib";
version = "3.1.0";
src = fetchurl {
url = "ftp://sourceware.org/pub/newlib/newlib-${version}.tar.gz";
sha256 = "0ahh3n079zjp7d9wynggwrnrs27440aac04340chf1p9476a2kzv";
};
nativeBuildInputs = [ platform-binutils platform-gcc ];
configureFlags = [
"--target=${platform}"
"--with-cpu=cortex-a9"
"--with-fpu=vfpv3"
"--with-float=hard"
"--with-mode=thumb"
"--enable-interwork"
"--disable-multilib"
"--disable-newlib-supplied-syscalls"
"--with-gnu-ld"
"--with-gnu-as"
"--disable-newlib-io-float"
"--disable-werror"
];
dontFixup = true;
};
in rec {
binutils-bootstrap = pkgs.callPackage binutils-pkg { };
gcc-bootstrap = pkgs.callPackage gcc-pkg {
platform-binutils = binutils-bootstrap;
extraConfigureFlags = [ "--disable-libgcc" ];
};
newlib = pkgs.callPackage newlib-pkg {
platform-binutils = binutils-bootstrap;
platform-gcc = gcc-bootstrap;
};
binutils = pkgs.callPackage binutils-pkg {
extraConfigureFlags = [ "--with-lib-path=${newlib}/arm-none-eabi/lib" ];
};
gcc = pkgs.callPackage gcc-pkg {
platform-binutils = binutils;
extraConfigureFlags = [ "--enable-newlib" "--with-headers=${newlib}/arm-none-eabi/include" ];
};
}

View File

@ -1,24 +0,0 @@
{ pkgs }:
pkgs.stdenv.mkDerivation {
pname = "mkbootimage";
version = "2.2";
src = pkgs.fetchFromGitHub {
owner = "antmicro";
repo = "zynq-mkbootimage";
rev = "4ee42d782a9ba65725ed165a4916853224a8edf7";
sha256 = "1k1mbsngqadqihzjgvwvsrkvryxy5ladpxd9yh9iqn2s7fxqwqa9";
};
propagatedBuildInputs = [ pkgs.libelf pkgs.pcre ];
patchPhase =
''
substituteInPlace Makefile --replace "git rev-parse --short HEAD" "echo nix"
'';
installPhase =
''
mkdir -p $out/bin
cp mkbootimage $out/bin
'';
}

View File

@ -1,10 +0,0 @@
let
pkgs = import <nixpkgs> {};
overlay = pkgs.fetchFromGitHub {
owner = "mozilla";
repo = "nixpkgs-mozilla";
rev = "efda5b357451dbb0431f983cca679ae3cd9b9829";
sha256 = "11wqrg86g3qva67vnk81ynvqyfj0zxk83cbrf0p9hsvxiwxs8469";
};
in
import overlay

View File

@ -1,24 +0,0 @@
{ pkgs }:
let
rustcSrc = pkgs.fetchgit {
url = "https://github.com/rust-lang/rust.git";
# sync with git_commit_hash from pkg.rust in channel-rust-nightly.toml
rev = "5ef299eb9805b4c86b227b718b39084e8bf24454";
sha256 = "0gc9hmb1sfkaf3ba8fsynl1n6bs8nk65hbhhx7ss89dfkrsxrn0x";
fetchSubmodules = true;
};
rustManifest = ./channel-rust-nightly.toml;
targets = [];
rustChannelOfTargets = _channel: _date: targets:
(pkgs.lib.rustLib.fromManifestFile rustManifest {
inherit (pkgs) stdenv fetchurl patchelf;
}).rust.override { inherit targets; };
rust =
rustChannelOfTargets "nightly" null targets;
in
pkgs.recurseIntoAttrs (pkgs.makeRustPlatform {
rustc = rust // { src = rustcSrc; };
cargo = rust;
})

20
openocd/common.cfg Normal file
View File

@ -0,0 +1,20 @@
set XC7_JSHUTDOWN 0x0d
set XC7_JPROGRAM 0x0b
set XC7_JSTART 0x0c
set XC7_BYPASS 0x3f
proc xc7_program {tap} {
global XC7_JSHUTDOWN XC7_JPROGRAM XC7_JSTART XC7_BYPASS
irscan $tap $XC7_JSHUTDOWN
irscan $tap $XC7_JPROGRAM
runtest 60000
#JSTART prevents this from working...
#irscan $tap $XC7_JSTART
runtest 2000
irscan $tap $XC7_BYPASS
runtest 2000
}
pld device virtex2 zynq.tap 1
init
xc7_program zynq.tap

View File

@ -5,35 +5,15 @@ set PL_TAPID 0x13722093
set SMP 1
source ./zynq-7000.cfg
source ./xilinx-tcl.cfg
reset_config srst_only srst_push_pull
set XC7_JSHUTDOWN 0x0d
set XC7_JPROGRAM 0x0b
set XC7_JSTART 0x0c
set XC7_BYPASS 0x3f
proc xc7_program {tap} {
global XC7_JSHUTDOWN XC7_JPROGRAM XC7_JSTART XC7_BYPASS
irscan $tap $XC7_JSHUTDOWN
irscan $tap $XC7_JPROGRAM
runtest 60000
#JSTART prevents this from working...
#irscan $tap $XC7_JSTART
runtest 2000
irscan $tap $XC7_BYPASS
runtest 2000
}
pld device virtex2 zynq.tap 1
init
xc7_program zynq.tap
source ./common.cfg
reset halt
# Disable MMU
targets $_TARGETNAME_1
arm mcr 15 0 1 0 0 [expr [arm mrc 15 0 1 0 0] & ~0xd]
arm mcr 15 0 1 0 0 [expr { [arm mrc 15 0 1 0 0] & ~0xd }]
targets $_TARGETNAME_0
arm mcr 15 0 1 0 0 [expr [arm mrc 15 0 1 0 0] & ~0xd]
arm mcr 15 0 1 0 0 [expr { [arm mrc 15 0 1 0 0] & ~0xd }]

View File

@ -3,7 +3,7 @@
# this supports JTAG-HS2 (and apparently Nexys4 as well)
interface ftdi
adapter driver ftdi
ftdi_vid_pid 0x0403 0x6014
ftdi_channel 0

28
openocd/kasli_soc.cfg Normal file
View File

@ -0,0 +1,28 @@
adapter driver ftdi
ftdi_device_desc "Quad RS232-HS"
ftdi_vid_pid 0x0403 0x6011
ftdi_channel 0
# some GPIOs need to be set, otherwise the FTDI chip craps out for some reason.
ftdi_layout_init 0x0098 0x008b
transport select jtag
adapter speed 1000
set PL_TAPID 0x1372c093
set SMP 1
source ./zynq-7000.cfg
ftdi_layout_signal nSRST -oe 0x0004
reset_config srst_only srst_open_drain
adapter srst pulse_width 250
adapter srst delay 400
source ./common.cfg
reset halt
# Disable MMU
targets $_TARGETNAME_1
arm mcr 15 0 1 0 0 [expr { [arm mrc 15 0 1 0 0] & ~0xd }]
targets $_TARGETNAME_0
arm mcr 15 0 1 0 0 [expr { [arm mrc 15 0 1 0 0] & ~0xd }]

View File

@ -1,5 +1,5 @@
source ./digilent-hs2.cfg
adapter_khz 1000
adapter speed 1000
set PL_TAPID 0x13722093
set SMP 1
@ -8,31 +8,12 @@ source ./zynq-7000.cfg
reset_config none
set XC7_JSHUTDOWN 0x0d
set XC7_JPROGRAM 0x0b
set XC7_JSTART 0x0c
set XC7_BYPASS 0x3f
proc xc7_program {tap} {
global XC7_JSHUTDOWN XC7_JPROGRAM XC7_JSTART XC7_BYPASS
irscan $tap $XC7_JSHUTDOWN
irscan $tap $XC7_JPROGRAM
runtest 60000
#JSTART prevents this from working...
#irscan $tap $XC7_JSTART
runtest 2000
irscan $tap $XC7_BYPASS
runtest 2000
}
pld device virtex2 zynq.tap 1
init
xc7_program zynq.tap
source ./common.cfg
halt
# Disable MMU
targets $_TARGETNAME_1
arm mcr 15 0 1 0 0 [expr [arm mrc 15 0 1 0 0] & ~0xd]
arm mcr 15 0 1 0 0 [expr { [arm mrc 15 0 1 0 0] & ~0xd }]
targets $_TARGETNAME_0
arm mcr 15 0 1 0 0 [expr [arm mrc 15 0 1 0 0] & ~0xd]
arm mcr 15 0 1 0 0 [expr { [arm mrc 15 0 1 0 0] & ~0xd }]

View File

@ -1,5 +1,5 @@
source [find interface/ftdi/olimex-arm-usb-tiny-h.cfg]
adapter_khz 1000
adapter speed 1000
set PL_TAPID 0x23731093
set SMP 1
@ -7,34 +7,15 @@ set SMP 1
source ./zynq-7000.cfg
reset_config srst_only srst_open_drain
adapter_nsrst_assert_width 250
adapter_nsrst_delay 400
adapter srst pulse_width 250
adapter srst delay 400
set XC7_JSHUTDOWN 0x0d
set XC7_JPROGRAM 0x0b
set XC7_JSTART 0x0c
set XC7_BYPASS 0x3f
proc xc7_program {tap} {
global XC7_JSHUTDOWN XC7_JPROGRAM XC7_JSTART XC7_BYPASS
irscan $tap $XC7_JSHUTDOWN
irscan $tap $XC7_JPROGRAM
runtest 60000
#JSTART prevents this from working...
#irscan $tap $XC7_JSTART
runtest 2000
irscan $tap $XC7_BYPASS
runtest 2000
}
pld device virtex2 zynq.tap 1
init
xc7_program zynq.tap
source ./common.cfg
reset halt
# Disable MMU
targets $_TARGETNAME_1
arm mcr 15 0 1 0 0 [expr [arm mrc 15 0 1 0 0] & ~0xd]
arm mcr 15 0 1 0 0 [expr { [arm mrc 15 0 1 0 0] & ~0xd }]
targets $_TARGETNAME_0
arm mcr 15 0 1 0 0 [expr [arm mrc 15 0 1 0 0] & ~0xd]
arm mcr 15 0 1 0 0 [expr { [arm mrc 15 0 1 0 0] & ~0xd }]

View File

@ -81,15 +81,16 @@ jtag newtap $_CHIPNAME dap -irlen 4 -ircapture 0x01 -irmask 0x03 \
set _TARGETNAME_0 $_CHIPNAME.cpu.0
set _TARGETNAME_1 $_CHIPNAME.cpu.1
dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.dap
target create $_TARGETNAME_0 cortex_a -coreid 0 \
-endian $_ENDIAN \
-chain-position $_CHIPNAME.dap \
-dap $_CHIPNAME.dap \
-dbgbase 0x80090000
if { $_SMP } {
echo "Zynq CPU1."
target create $_TARGETNAME_1 cortex_a -coreid 1 \
-endian $_ENDIAN \
-chain-position $_CHIPNAME.dap \
-dap $_CHIPNAME.dap \
-dbgbase 0x80092000
target smp $_TARGETNAME_0 $_TARGETNAME_1
}

View File

@ -4,7 +4,7 @@ set -e
target_host="rpi-4.m-labs.hk"
while getopts "h:i" opt; do
while getopts "h:" opt; do
case "$opt" in
\?) exit 0
;;

View File

@ -1,24 +0,0 @@
let
pkgs = import <nixpkgs> { overlays = [ (import ./nix/mozilla-overlay.nix) ]; };
rustPlatform = (import ./nix/rust-platform.nix { inherit pkgs; });
in
pkgs.stdenv.mkDerivation {
name = "zynq-env";
buildInputs = [
rustPlatform.rust.rustc
rustPlatform.rust.cargo
pkgs.cacert
pkgs.cargo-xbuild
pkgs.openocd pkgs.gdb
pkgs.openssh pkgs.rsync
(import ./nix/mkbootimage.nix { inherit pkgs; })
];
XARGO_RUST_SRC = "${rustPlatform.rust.rustc.src}/src";
shellHook = ''
echo "Run 'cargo xbuild --release -p ...' to build."
'';
}

View File

@ -6,7 +6,10 @@ authors = ["M-Labs"]
edition = "2018"
[features]
target_zc706 = ["libboard_zynq/target_zc706", "libsupport_zynq/target_zc706"]
target_zc706 = ["libboard_zynq/target_zc706", "libsupport_zynq/target_zc706", "libconfig/target_zc706"]
target_coraz7 = ["libboard_zynq/target_coraz7", "libsupport_zynq/target_coraz7", "libconfig/target_coraz7"]
target_redpitaya = ["libboard_zynq/target_redpitaya", "libsupport_zynq/target_redpitaya", "libconfig/target_redpitaya"]
target_kasli_soc = ["libboard_zynq/target_kasli_soc", "libsupport_zynq/target_kasli_soc", "libconfig/target_kasli_soc"]
default = ["target_zc706"]
[dependencies]

View File

@ -59,6 +59,21 @@ SECTIONS
__stack0_start = .;
} > OCM3
.irq_stack1 (NOLOAD) : ALIGN(8)
{
__irq_stack1_end = .;
. += 0x100;
__irq_stack1_start = .;
} > OCM3
.irq_stack0 (NOLOAD) : ALIGN(8)
{
__irq_stack0_end = .;
. += 0x100;
__irq_stack0_start = .;
} > OCM3
/DISCARD/ :
{
/* Unused exception related info that only wastes space */

View File

@ -20,8 +20,6 @@ use libconfig::{bootgen, sd_reader, Config};
use libcortex_a9::{
asm::{dsb, isb},
cache::{bpiall, dcciall, iciallu},
enable_fpu,
l2c::enable_l2_cache,
};
use libregister::RegisterR;
use libsupport_zynq::ram;
@ -66,7 +64,6 @@ fn boot_sd<File: Read + Seek>(
#[no_mangle]
pub fn main_core0() {
GlobalTimer::start();
enable_fpu();
logger::init().unwrap();
log::set_max_level(log::LevelFilter::Debug);
println!(
@ -78,14 +75,17 @@ pub fn main_core0() {
___/ / / /__/ /___
/____/ /____/_____/
(C) 2020 M-Labs
(C) 2020-2022 M-Labs
"#
);
info!("Simple Zynq Loader starting...");
enable_l2_cache();
#[cfg(not(feature = "target_kasli_soc"))]
const CPU_FREQ: u32 = 800_000_000;
#[cfg(feature = "target_kasli_soc")]
const CPU_FREQ: u32 = 1_000_000_000;
ArmPll::setup(2 * CPU_FREQ);
Clocks::set_cpu_freq(CPU_FREQ);
IoPll::setup(1_000_000_000);
@ -140,7 +140,14 @@ pub fn main_core0() {
}
}
v => {
panic!("Boot mode {:?} not supported", v);
log::error!("Boot mode {:?} not supported", v);
log::info!("Fall back on netboot");
netboot::netboot(
&mut bootgen_file,
config,
&mut __runtime_start as *mut usize as *mut u8,
max_len,
)
}
};
}

View File

@ -316,7 +316,7 @@ pub fn netboot<File: Read + Seek>(
runtime_max_len: usize,
) {
log::info!("Preparing network for netboot");
let net_addresses = net_settings::get_adresses(&cfg);
let net_addresses = net_settings::get_addresses(&cfg);
log::info!("Network addresses: {}", net_addresses);
let eth = Eth::eth0(net_addresses.hardware_addr.0.clone());
let eth = eth.start_rx(8);