Skip to content

Add hisilicon ws63 bs21#2

Open
sanchuanhehe wants to merge 12 commits into
masterfrom
add-hisilicon-ws63-bs21
Open

Add hisilicon ws63 bs21#2
sanchuanhehe wants to merge 12 commits into
masterfrom
add-hisilicon-ws63-bs21

Conversation

@sanchuanhehe

Copy link
Copy Markdown
Collaborator

No description provided.

sanchuanhehe and others added 10 commits June 11, 2026 18:43
These chips are HiSilicon RISC-V cores whose Debug Module is reached through an
ARM CoreSight DAP (AHB-AP) — the same topology probe-rs already supports for
RP2350 via mem_ap_dtm. So this needs a target definition + a small DM-base
extension + a debug sequence + a flash algorithm, NOT a new backend (the vendor
needed a dedicated OpenOCD 'riscvcs' patch for exactly this; probe-rs has it).

Adds, under doc/hisilicon-ws63-bs21/:
- README.md: architecture, the RP2350/mem-AP feasibility finding, reverse-
  engineered ground truth (DAP IDCODE 0x5ba0_0477, WS63 AP0/DM 0x80000000,
  custom LOCI CSRs, memory maps, debug-enable), and the open hardware-gated items.
- WS63.wip.yaml / BS21.wip.yaml: target scaffolds (RISC-V via !Riscv mem_ap +
  dm_base, real memory maps; flash_algorithms TODO).
- mem_ap_dtm.patch.txt: the one required core change — an optional dm_base on
  RiscvCoreAccessOptions + MemApDtm so the DM can sit off AP-offset-0 (WS63 needs
  0x80000000; default 0 keeps RP2350 and all existing targets byte-identical).

WIP: debug bring-up is achievable with the dm_base change; flash programming and
on-silicon validation remain open (need a board). Sourced from HiSpark Studio's
bundled patched OpenOCD (riscvcs/batchcs, flash/nor/ws63.c, vendorhm/WS63-*.cfg)
and the fbb_ws63/fbb_bs2x SDKs.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The RISC-V mem-AP DTM (used when the RISC-V Debug Module sits behind a CoreSight
mem-AP, e.g. RP235x) hard-coded the DM at AP offset 0 (dmi_register*4). HiSilicon
WS63 (Hi3863) has the same topology but its DM is at 0x80000000. Add an optional
DM base so such parts work, then ship WS63 as a debug target.

- probe-rs-target: add `dm_base: u64` (#[serde(default)] -> 0) to
  RiscvCoreAccessOptions. Only meaningful with `mem_ap`.
- mem_ap_dtm: MemApDtm carries dm_base; new(memory, dm_base);
  dmi_register_to_ap_address = dm_base + dmi_register*4.
- session.rs: thread dm_base through riscv_mem_ap_cores (now a 3-tuple) at all
  three MemApDtm::new sites, sourced from the core's CoreAccessOptions::Riscv.
- registry.rs / target-gen: set dm_base: 0 at the generic-RISC-V construction sites.
- targets/HiSilicon_WS63.yaml: new built-in target. RISC-V core behind CoreSight
  AP0, dm_base 0x80000000 (from HiSpark Studio's patched OpenOCD WS63-*.cfg).
  DEBUG-only (attach/halt/mem/registers); no flash algorithm yet.

Default dm_base 0 keeps RP235x and every existing target byte-identical.

Verified: cargo check -p probe-rs-target / -p probe-rs / -p probe-rs
--no-default-features all clean; cargo fmt --check clean; the validate_builtin
test (validates all built-in targets incl. WS63) passes.

Refs doc/hisilicon-ws63-bs21/README.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Address the adversarial completeness review: the dm_base change + WS63 target
wire the DTM/target LAYER, but that is not an end-to-end 'attach works' claim.
Make the README precise — items 1-2 (dm_base, WS63 target) landed; items 3-4
(vendor DebugSequence for debug-port enable + CSR expose; flash algorithm) plus
AP0 enumeration, the external GPIO_04-high strap, and on-silicon validation are
still required before attach succeeds on a board. Add explicit
'flash_algorithms: []' to HiSilicon_WS63.yaml for clarity.

No code change; validate_builtin still passes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
WS63 is an ArmWithRiscv target (RISC-V core via mem-AP behind a CoreSight DAP), so
the chip-specific debug bring-up must hook the ARM DAP, not RISC-V: a RISC-V
on_connect runs too late (after enter_debug_mode first touches the DM), and for
ArmWithRiscv targets the DAP path uses the Arm sequence (session.rs maps
DebugSequence::Riscv(_) -> DefaultArmSequence). So the vendor returns
DebugSequence::Arm.

- new probe-rs/src/vendor/hisilicon/{mod.rs,sequences.rs}: HiSilicon vendor +
  Ws63 ArmDebugSequence; registered in vendor/mod.rs. Matches chip name 'WS63'.
- Ws63::debug_device_unlock performs the debug-port enable (0x40010260 = 1,
  'enable coresight-swd mode' from the vendor OpenOCD cfg) as a best-effort write:
  on failure it logs and continues, since on most boards the port is enabled by
  the external GPIO_04-high-at-power-on strap (which probe-rs cannot do).
- ws63_uses_hisilicon_arm_sequence test: WS63 resolves to DebugSequence::Arm
  end-to-end (YAML -> registry -> vendor).
- expose_csrs has no probe-rs equivalent (register lists are compile-time static);
  prefer_sba is moot on the mem-AP path (DMI routes through the ARM AP). Documented.

Still unvalidated on silicon (needs the GPIO_04 strap + AP0 to enumerate).

Verified: cargo check / fmt / clippy clean; registry tests pass (incl. the new
test + validate_builtin). Adversarially reviewed (attach-path + honesty: both pass).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A complete probe-rs flash loader for the WS63 SFC NOR flash, ported from the
fbb_ws63 hal_sfc_v150 register/command sequence (corroborated by HiSpark OpenOCD
ws63.c): WREN/RDSR/4K-erase/page-program via SFC reg mode (base 0x48000000,
cmd_config@0x300 / cmd_ins@0x308 / cmd_addr@0x30c / cmd_databuf@0x400), 64-byte
chunks, WIP poll, CPU-XIP->flash offset via 0x200000.

- doc/hisilicon-ws63-bs21/flash-algorithm/: no_std crate using flash-algorithm
  0.7 (default-features off + panic-handler; erase-chip off so probe-rs erases
  per-sector). Built for riscv32imc (WS63 has no atomics; probe-rs doesn't
  preserve FP). Excluded from the workspace (root Cargo.toml) so host builds skip
  it.
- VERIFIED: builds for riscv32imc; the ELF exports Init/UnInit/EraseSector/
  ProgramPage/FlashDevice; 'target-gen elf' extracts a well-formed algorithm
  (pc_init/pc_uninit/pc_program_page/pc_erase_sector/data_section_offset +
  flash_properties range 0x200000..0xa00000, page 0x100, 4K sectors). fmt+clippy
  clean. Adversarially reviewed against the SDK: faithful port, no transcription
  bugs (3-byte addressing assumption noted in the validation checklist).
- DELIBERATELY NOT embedded into HiSilicon_WS63.yaml (flash_algorithms stays []):
  an unvalidated erase/program algo in the default flash path could corrupt a
  board on 'probe-rs download'. Embed via 'target-gen ... --update' only after
  the hardware validation checklist in flash-algorithm/README.md. WS63 stays
  debug-only until then.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… DMs

A postexec-only abstract command (postexec=1, transfer=0) built with
aarsize=0 is rejected by some DM implementations — notably the HiSilicon
WS63, which returns abstractcs.cmderr=NotSupported. This aborted attach
on real WS63 silicon (the DM has no abstract CSR access and no system
bus, so all CSR/memory access must go through the program buffer, whose
execution relies on these postexec commands).

OpenOCD always issues postexec commands with a valid aarsize and
regno=x0 (e.g. command=0x241000). Match that: add `postexec_command()`
(aarsize selected by XLEN, regno=x0) and use it for the four
program-buffer paths: read/write_csr_progbuf and read/write_dcsr_inline.

Verified on WS63 hardware over J-Link: `probe-rs read --chip WS63`
now attaches, halts, and reads memory through the program buffer
(0xDEADBEEF from SRAM); previously failed with
AbstractCommand(NotSupported). The rejected 0x40000 command is gone,
replaced by 0x241000, with zero NotSupported errors.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
probe-rs can now erase/program the WS63 on-chip SPI-NOR flash over J-Link.
Hardware-verified: `probe-rs download --chip WS63 --verify` writes real data
and reads it back correctly.

Getting there required fixing several issues for the program-buffer-only WS63
debug module and the flash-algorithm crate's RISC-V support:

flash algorithm (doc/hisilicon-ws63-bs21/flash-algorithm):
- Init clears the flash chip's block-protect bits (WREN + WRSR 0x00). On this
  board (GD25Q32) they are set at power-on (RDSR=0x1e) and silently reject all
  erase/program until cleared.
- Add an `ebreak` trampoline at PrgCode offset 0 (link.x + build.rs). probe-rs
  sets ra=load_address per CMSIS convention and expects a routine's `ret` to
  self-trap there, but the crate lays functions out at .entry with no trap, so
  without this Init's `ret` fell through into EraseSector and timed out.
- Build with code-model=medium (RISC-V medany). The default medlow emits
  absolute `lui`+offset for statics (e.g. _IS_INIT), which point at the wrong
  place once the blob is loaded at a runtime RAM address and make the algo run
  off the rails (the DM even drops out). medany is PC-relative.
- Bound wait_cmd_done so a routine can never spin forever.

probe-rs riscv:
- halt(): set ebreakm on the fast halt path too, so an ebreak (such as the
  flash algorithm's return trampoline) traps to debug mode instead of raising
  an exception.

HiSilicon_WS63.yaml: embed the ws63-sfc flash algorithm.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…gorithm

The WS63 SFC NOR flash loader was carried in-tree under
doc/hisilicon-ws63-bs21/flash-algorithm/ as a standalone (workspace-excluded)
riscv32imc crate. It now lives in its own general-purpose workspace,
https://github.com/hispark-rs/hisi-flash-algorithm (the ws63 crate), with room
for future HiSilicon families (bs2x). The algorithm itself is unchanged and
stays embedded in probe-rs/targets/HiSilicon_WS63.yaml (flash_algorithms:
[ws63-sfc]); that file is not touched here.

- Remove the doc/hisilicon-ws63-bs21/flash-algorithm/ crate and its workspace
  `exclude` entry in the root Cargo.toml.
- Add doc/hisilicon-ws63-bs21/flash-algorithm.md pointing at the new repo and
  documenting the build -> target-gen --update re-embed workflow.
- Refresh the WS63 doc README: the flash algorithm is now embedded and
  hardware-verified (probe-rs download erase/program on a GD25Q32), not a
  scaffold.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
reset_hart_and_halt relied solely on a held haltreq across ndmreset. On
targets where the halt lands a few instructions late, the hart runs past
the reset vector before halting — on the HiSilicon WS63 a plain-haltreq
reset_and_halt ends up ~46 instructions deep in the mask ROM (PC 0x1000b8)
with stale CSRs (mepc/mcause left over from a prior run), which is
misleading when bringing up an app.

When the DM advertises dmstatus.hasresethaltreq, arm the dedicated
halt-on-reset request (resethaltreq) before the reset pulse so the hart
halts at the FIRST instruction out of reset, then disarm it (clrresethaltreq)
once the hart is confirmed halted. Targets without the capability keep the
previous held-haltreq behavior unchanged.

Validated on WS63: reset_and_halt now lands at the reset vector 0x100000
instead of 0x1000b8.

Also adds examples/trapdump.rs — a WS63 bring-up HIL diagnostic (HW-bp at
app entry, run-to-milestone, free-run PC/GPIO sampling) used to find and
verify this.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…eset

The WS63 boot ROM initializes the SFC (SPI Flash Controller) during normal
reset. Using the Debug Module's ndmreset or hartreset+resethaltreq resets
the SoC but halts the CPU before the boot ROM can run SFC init, leaving
the SFC controller in a partially-initialized state. This causes
'Flash Init Fail! ret = 0x80001341' on subsequent boots.

Root fix: override RiscvDebugSequence::reset_system_and_halt for WS63 to
use the system controller's software reset (sc_sys_res), mirroring
HiSilicon's official OpenOCD HISPARK_TRACE_MODIFIES flow:

1. Write SC_HRST_RES debug flag
2. Unlock SC_CFG_LOCK
3. Set PERI_CRG to HOSC clock
4. Trigger SC_SYS_RES system reset
5. Wait 5ms, read SC_HRST_RES, wait 10ms (assert_reset)
6. Halt core
7. Wait 500ms for halt to take effect (deassert_reset)

The vendor now returns DebugSequence::Riscv(Ws63) so the RISC-V core
gets the custom reset sequence. The ARM DAP bring-up falls back to
DefaultArmSequence (same pattern as RP235x_riscv).

Verified on WS63 silicon: probe-rs reset no longer breaks SFC; board
boots normally with no 'Flash Init Fail' and UART output is intact.
@sanchuanhehe sanchuanhehe force-pushed the add-hisilicon-ws63-bs21 branch from 1d613fb to 434ce29 Compare July 5, 2026 10:08
Sync with hisi-flash-algorithm f9b774e:
- pc_init 0x78→0x70, pc_uninit 0x240→0x278, pc_program_page 0x10a→0x154
- data_section_offset 0x2ac→0x3b4
- erase_sector_timeout 5000→30000
New algo includes wait_ready_best_effort + SR save/restore in Drop.
…SFC init

The previous reset_system_and_halt used interface.halt(), which is
synchronous — it writes haltreq and immediately polls allhalted. This
catches the CPU inside Boot ROM before SFC is initialized, causing
'Flash Init Fail!' on subsequent boots.

OpenOCD's 'deassert_reset' does the same: target_halt + 500 ms wait,
relying on the halt request being asynchronous — the CPU runs through
Boot ROM → flashboot → app during that window before actually stopping.

Mirror that behavior: write haltreq without polling, wait 500 ms for
Boot ROM + flashboot to complete, then confirm the halt synchronously.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant