Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
8cb9969
Refactor for reuse
jreineckearm Feb 20, 2026
532cb9f
Get SCVD files from derived class
jreineckearm Feb 20, 2026
ffde1d4
Add Core Peripheral Viewer
jreineckearm Feb 20, 2026
89e9725
Add core peripheral scvd files
jreineckearm Feb 20, 2026
60ec5f2
Read core perpiheral scvd files
jreineckearm Feb 20, 2026
52666b6
tests
jreineckearm Feb 20, 2026
33e2553
Fixes after rebase to main
jreineckearm Feb 24, 2026
d64d8ff
"Core Peripheral Viewer" -> "Core Periphersals"
jreineckearm Feb 24, 2026
f1aa682
Merge branch 'main' into core-peripheral-viewer
jreineckearm Feb 25, 2026
b08880a
Merge branch 'main' into core-peripheral-viewer
jreineckearm Feb 27, 2026
cd3d188
Fix vscode mock
jreineckearm Feb 27, 2026
fd0616c
ComponentViewer tests -> ComponentViewerBase tests
jreineckearm Feb 27, 2026
a57c5df
tree data provider factory
jreineckearm Feb 27, 2026
9f3043f
Reduce redundant test code
jreineckearm Feb 27, 2026
cc0ab2a
Factory refactoring
jreineckearm Feb 27, 2026
f0d6e54
Component Viewer tests
jreineckearm Feb 27, 2026
290a15f
Fix missing clear on deactivate
jreineckearm Feb 27, 2026
6f1eaae
extension.ts tests for core peripherals
jreineckearm Feb 27, 2026
d6856a5
Make ComponentViewerBase abstract (avoid getScvdFilePaths() base impl…
jreineckearm Feb 27, 2026
36cd238
Refactor for testability, revert making ComponentViewerBase abstract
jreineckearm Feb 27, 2026
b3668b8
Move debug-session.factory close to implementation files
jreineckearm Feb 27, 2026
99b971e
Core Peripherals SCVD Collector tests
jreineckearm Feb 28, 2026
e54f0d7
Fix and extend debug session factory
jreineckearm Feb 28, 2026
869cf12
ComponentViewerScvdCollector tests
jreineckearm Feb 28, 2026
365cbca
Remove redundant check
jreineckearm Feb 28, 2026
949d8b0
Enable Core Peripherals with hidden setting
jreineckearm Mar 2, 2026
d1603cd
Update tests to mock 'cmsis-debugger.corePeripherals.enabled' setting
jreineckearm Mar 2, 2026
4bef31c
Try-catch around file read
jreineckearm Mar 2, 2026
9b54f64
Merge branch 'main' into core-peripheral-viewer
jreineckearm Mar 3, 2026
238eb2e
Merge branch 'main' into core-peripheral-viewer
jreineckearm Mar 3, 2026
6b9edd6
Merge branch 'main' into core-peripheral-viewer
jreineckearm Mar 4, 2026
6f44003
Merge branch 'main' into core-peripheral-viewer
jreineckearm Mar 6, 2026
414bfc2
Feedback omarArm
jreineckearm Mar 6, 2026
a9e4c28
Merge branch 'main' into core-peripheral-viewer
jreineckearm Mar 6, 2026
740f70e
Merge branch 'main' into core-peripheral-viewer
jreineckearm Mar 6, 2026
0ebf889
Add Core Peripheral Index schema
jreineckearm Mar 2, 2026
e13baf4
Core Peripheral Index file (initial version)
jreineckearm Mar 2, 2026
f552dce
renaming
jreineckearm Mar 2, 2026
099fb80
Schema update
jreineckearm Mar 3, 2026
9e7a229
CorePeripheralsIndexReader and initial test
jreineckearm Mar 3, 2026
b5d8d6f
Use index reader in SCVD collector
jreineckearm Mar 3, 2026
0c44ff0
Preliminary update cbuildrun format:
jreineckearm Mar 3, 2026
faa8b4d
Add filtering in Core Peripherals SCVD Collector
jreineckearm Mar 3, 2026
685689c
Add README on how to write index file
jreineckearm Mar 3, 2026
3607e63
Copilot feedback
jreineckearm Mar 3, 2026
9dceeea
Fix comment to silence qlty
jreineckearm Mar 3, 2026
766213c
Extend Core Peripherals Index Reader tests
jreineckearm Mar 4, 2026
8da1177
Add integrity test for core peripheral config folder
jreineckearm Mar 4, 2026
9d249f5
Refine core peripheral scvd collector (filter behavior)
jreineckearm Mar 4, 2026
911162d
Tests for CorePeripheralScvdCollector
jreineckearm Mar 4, 2026
4f4b82c
Updated readme
jreineckearm Mar 5, 2026
c7eea9f
Refine wildcard handling to exclude `none`
jreineckearm Mar 5, 2026
1708b62
fs.promises vs promisify
jreineckearm Mar 6, 2026
94e6339
readme update
jreineckearm Mar 9, 2026
e10c7fa
Merge branch 'main' into core-peripherals-index
jreineckearm Mar 9, 2026
3881550
Merge branch 'main' into core-peripherals-index
thorstendb-ARM Mar 10, 2026
7a1d73d
Merge branch 'main' into core-peripherals-index
jreineckearm Mar 13, 2026
4a7327c
More intuitive handling of `none` and '*' wildcard
jreineckearm Mar 13, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 80 additions & 0 deletions configs/core-peripherals/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# Core Peripherals Index (`core-peripherals-index.yml`)

This file lists SCVD files and optional conditions that decide whether each file is loaded for
a CPU connection. The input for the condition is based on the selected core and its available
features as described under `system-resources`>`processors` in the `*.cbuild-run.yml` file.

## File format

```yaml
core-peripherals:
- file: Nested_Vectored_Interrupt_Controller_M33_with_TZ.scvd
cpu-type: Cortex-M33
cpu-features:
trustzone: present
info: Example for a CPU specific NVIC description.

- file: My_M55_M85_CorePeripheral.scvd
cpu-type:
- Cortex-M55
- Cortex-M85
cpu-features:
mve: fp
dsp: present
fpu: dp
info: Example for a core peripheral description valid for multiple CPU types with available CPU features.

- file: Memory_Protection_Unit.scvd
cpu-type: "*"
cpu-features:
mpu: present
fpu: "*"
info: Example for wildcard usage
```

- `file` (required): Path to an SCVD file, relative to this folder (`configs/core-peripherals`).
- `cpu-type` (optional): String or list of strings matching processor `core` from `system-resources`>`processors` in `*.cbuild-run.yml`.
- `cpu-features` (optional): Key/value map matched against processor properties.
- `info` (optional): Free-text description.

## Filtering behavior

### Processor selection

- If the core connection's `pname` matches a child node of `system-resources`>`processors`, then that processor is used.
- If `pname` is missing, then a single-core system is assumed. Hence, the first processor in the list is used.
- If no processors are available, the collector treats the processor as unknown. In this case only entries without `cpu-type`/`cpu-features`
constraints, those using the "*" wildcard, and those using value `none` will match; entries requiring a specific `cpu-type` or specific feature values are excluded.

### `cpu-type` matching

- If omitted or set to the `"*"` wildcard, then entry is valid for all CPU types.
- Otherwise, SCVD files are loaded if the connection's core matches one of the given `core` values.
Matching is case-insensitive.

### `cpu-features` matching

- If omitted, no feature constraints are applied.
- All listed feature conditions must match (`AND` logic).
- Feature must exist in the selected processor object and values must match (case-insensitive).
- Feature value `"*"` matches any value for that key that indicates presence of the feature.

## Feature keys and allowed values

Use feature keys that can appear on a processor entry in `system-resources`>`processors` of `*.cbuild-run.yml`.

- `fpu`: `sp`, `dp`, `none`
- `mpu`: `present`, `none`
- `dsp`: `present`, `none`
- `trustzone`: `present`, `none`
- `mve`: `int`, `fp`, `none`
- `pacbti`: `present`, `none`
- `endian`: `little`, `big`, `configurable`

Additional notes for filter behavior:

- `cpu-features` keys are matched exactly by key name (for example `mpu`, not `MPU`).
- Feature value comparison is case-insensitive after converting values to strings.
- If a key is listed in `cpu-features` but missing on the selected processor, the entry only matches if it has the value `none`.
This is to reflect that a missing processor feature usually means it is not implemented.
- Use `"*"` as a feature value to accept any value for that key that indicates presence of the feature.
75 changes: 75 additions & 0 deletions configs/core-peripherals/core-peripherals-index.schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
{
"$comment": "Index of core peripheral SCVD files and conditions when to use them.",
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://raw.githubusercontent.com/Open-CMSIS-Pack/vscode-cmsis-debugger/configs/core-peripherals/core-peripherals-index.schema.json",
"title": "Core Peripherals index",
"description": "Index listing core peripheral SCVD description files and CPU type/feature conditions under which each file is active.",
"version": "0.1.0",
"type": "object",
"properties": {
"core-peripherals": {
"$ref": "#/definitions/CorePeripherals"
}
},
"required": ["core-peripherals"],
"additionalProperties": false,
"definitions": {
"CorePeripherals": {
"type": "array",
"description": "Array of core peripheral entries (SCVD files with optional activation conditions).",
"items": {
"$ref": "#/definitions/CorePeripheralEntry"
},
"minItems": 0,
"uniqueItems": true
},
"CorePeripheralEntry": {
"type": "object",
"description": "Single SCVD description entry with optional CPU type and CPU feature conditions.",
"properties": {
"file": {
"$ref": "#/definitions/ScvdFileType"
},
"cpu-type": {
"$ref": "#/definitions/CpuType"
},
"cpu-features": {
"$ref": "#/definitions/CpuFeatures"
},
"info": {
"type": "string",
"description": "Optional human-readable description."
}
},
"required": ["file"],
"additionalProperties": false
},
"ScvdFileType": {
"type": "string",
"description": "Path or identifier of the SCVD description file."
},
"CpuType": {
"description": "Specifies one or more CPU types. '*' is allowed as wildcard and is the default if omitted.",
"oneOf": [
{
"type": "string"
},
{
"type": "array",
"items": {
"type": "string"
},
"minItems": 1,
"uniqueItems": true
}
]
},
"CpuFeatures": {
"type": "object",
"description": "Map of CPU features and their value. Each feature key may only appear once. '*' is allowed as wildcard and is the default if omitted.",
"additionalProperties": {
"type": "string"
}
}
}
}
11 changes: 11 additions & 0 deletions configs/core-peripherals/core-peripherals-index.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
core-peripherals:
- file: Memory_Protection_Unit.scvd
cpu-type: "*"
cpu-features:
mpu: present
- file: Nested_Vectored_Interrupt_Controller.scvd
cpu-type: "*"
- file: System_Config_and_Control.scvd
cpu-type: "*"
- file: System_Tick_Timer.scvd
cpu-type: "*"
22 changes: 20 additions & 2 deletions src/cbuild-run/cbuild-run-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,26 @@ export interface MemoryType {
'from-pack'?: string;
};

// Preliminary type, to be implemented in CMSIS Toolbox first.
export interface ProcessorType {
core: string;
revision: string;
'max-clock': number;
pname?: string;
punits?: number;
endian?: 'little' | 'big' | 'configurable';
fpu?: 'sp' | 'dp' | 'none';
mpu?: 'present' | 'none';
dsp?: 'present' | 'none';
trustzone?: 'present' | 'none';
mve?: 'int' | 'fp' | 'none';
cdecp?: number;
pacbti?: 'present' | 'none';
}

export interface SystemResourcesType {
memory?: MemoryType[];
processors?: ProcessorType[];
};

export type SystemDescriptionTypeType = 'svd'|'scvd';
Expand Down Expand Up @@ -139,7 +157,7 @@ export interface PunitType {
address: number;
};

export interface ProcessorType {
export interface TopologyProcessorType {
pname?: string;
punits?: PunitType[];
apid?: number;
Expand All @@ -148,7 +166,7 @@ export interface ProcessorType {

export interface DebugTopologyType {
debugports?: DebugPortType[];
processors?: ProcessorType[];
processors?: TopologyProcessorType[];
swj?: boolean;
dormant?: boolean;
sdf?: string;
Expand Down
5 changes: 4 additions & 1 deletion src/debug-session/__test__/debug-session.factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,10 @@ export const debugSessionFactory = (
hasCbuildRun = true
): Session => {
// Ensure same object returned for multiple calls to getCbuildRun.
const cbuildRunMock = hasCbuildRun ? { getScvdFilePaths: () => paths } : undefined;
const cbuildRunMock = hasCbuildRun ? {
getContents: jest.fn(),
getScvdFilePaths: () => paths
} : undefined;
return {
session: { id },
getCbuildRun: async () => cbuildRunMock,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing

exports[`CorePeripheralsIndexReader can read index file 1`] = `
{
"core-peripherals": [
{
"cpu-features": {
"mpu": "present",
},
"cpu-type": "*",
"file": "Memory_Protection_Unit.scvd",
},
{
"cpu-type": "*",
"file": "Nested_Vectored_Interrupt_Controller.scvd",
},
{
"cpu-type": "*",
"file": "System_Config_and_Control.scvd",
},
{
"cpu-type": "*",
"file": "System_Tick_Timer.scvd",
},
],
}
`;
73 changes: 73 additions & 0 deletions src/views/core-peripherals/core-peripherals-index-reader.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/**
* Copyright 2026 Arm Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import * as fs from 'fs';
import * as path from 'path';
import { CorePeripheralsIndexReader } from './core-peripherals-index-reader';

// Tests are executed with different working directory, so different input path needed.
const TEST_INDEX_BASE_PATH = path.resolve(__dirname, '../../../configs/core-peripherals');
const TEST_INDEX_PATH = path.resolve(TEST_INDEX_BASE_PATH, 'core-peripherals-index.yml');
const EMPTY_INDEX_PATH = path.resolve(__dirname, '../../../test-data/core-peripherals/empty-index/core-peripherals-index.yml');

describe('CorePeripheralsIndexReader', () => {

it('finds all core peripherals entries of index file in folder', async () => {
// eslint-disable-next-line security/detect-non-literal-fs-filename
const filesInDir = await fs.promises.readdir(TEST_INDEX_BASE_PATH, {
encoding: 'buffer',
withFileTypes: true
});
const scvdFilesInDir = filesInDir.filter(entry => entry.isFile() && entry.name.toString().toLowerCase().endsWith('.scvd'));
const scvdFilePathsInDir = scvdFilesInDir.map(file => path.resolve(TEST_INDEX_BASE_PATH, file.name.toString()));
const indexReader = new CorePeripheralsIndexReader();
await expect(indexReader.parse(TEST_INDEX_PATH)).resolves.not.toThrow();
const indexEntries = indexReader.getCorePeripherals().map(entry => path.resolve(TEST_INDEX_BASE_PATH, entry.file));
expect(indexEntries.length).toBe(scvdFilePathsInDir.length);
scvdFilePathsInDir.forEach(filePath => {
expect(indexEntries.includes(filePath)).toBe(true);
});
});

it('can read index file', async () => {
const indexReader = new CorePeripheralsIndexReader();
await expect(indexReader.parse(TEST_INDEX_PATH)).resolves.not.toThrow();
expect(indexReader.hasContents()).toBe(true);
const contents = indexReader.getContents();
expect(contents).toMatchSnapshot();
});

it('returns empty array if no core peripherals parsed', async () => {
const indexReader = new CorePeripheralsIndexReader();
// Get peripherals without parsing file first, should return empty array.
expect(indexReader.hasContents()).toBe(false);
expect(indexReader.getContents()).toBeUndefined();
expect(indexReader.getCorePeripherals()).toEqual([]);
});

it('throws for an empty index file', async () => {
const indexReader = new CorePeripheralsIndexReader();
await expect(indexReader.parse(EMPTY_INDEX_PATH)).rejects.toThrow('Invalid \'core-peripherals-index\' file');
});

it('parses only once', async () => {
const indexReader = new CorePeripheralsIndexReader();
await expect(indexReader.parse(TEST_INDEX_PATH)).resolves.not.toThrow();
// Clear spy calls and parse an empty file. It should not throw because it should not attempt to parse the file again.
await expect(indexReader.parse(EMPTY_INDEX_PATH)).resolves.not.toThrow();
});

});
66 changes: 66 additions & 0 deletions src/views/core-peripherals/core-peripherals-index-reader.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/**
* Copyright 2026 Arm Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/


import * as path from 'path';
import * as yaml from 'yaml';
import { FileReader, VscodeFileReader } from '../../desktop/file-reader';
import { CorePeripheralEntryType, CorePeripheralsType } from './core-peripherals-index-types';

export class CorePeripheralsIndexReader {
private isParsed = false;
private contents: CorePeripheralsType | undefined;
private filePath: string | undefined;
private directory: string | undefined;

constructor(private reader: FileReader = new VscodeFileReader()) {}

public hasContents(): boolean {
return !!this.contents;
}

public getContents(): CorePeripheralsType | undefined {
return this.contents;
}

public async parse(filePath: string): Promise<void> {
if (this.isParsed) {
return;
}
this.filePath = filePath;
this.directory = path.dirname(this.filePath);
const fileContents = await this.reader.readFileToString(this.filePath);
this.contents = yaml.parse(fileContents) as CorePeripheralsType;
if (!this.contents) {
throw new Error(`Invalid 'core-peripherals-index' file: ${this.filePath}`);
}
this.isParsed = true;
}

public getCorePeripherals(): CorePeripheralEntryType[] {
const corePeripherals = this.contents?.['core-peripherals'];
if (!corePeripherals) {
return [];
}
const resolvedPeripherals = corePeripherals.map(
entry => ({
...entry,
file: this.directory ? path.resolve(this.directory, entry.file) : entry.file
})
);
return resolvedPeripherals ?? [];
}
}
Loading
Loading