Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New GDB monitor command for reading target registers #115

Open
navnavnav opened this issue Aug 12, 2024 · 2 comments
Open

New GDB monitor command for reading target registers #115

navnavnav opened this issue Aug 12, 2024 · 2 comments
Assignees
Labels
enhancement New feature or request
Milestone

Comments

@navnavnav
Copy link
Member

Currently, the only way to read target registers via GDB is to issue a memory access command, and supply a memory address. This is tedious and the output format is limited. I believe this can be improved with a new GDB monitor command, using TDF keys to reference peripherals and registers.

With the new TDF format, all peripherals, register groups and registers have unique keys that can be used to reference those entities.

I'd like to introduce a new rr (read register) monitor command:

(gdb) mon rr [PERIPHERAL_KEY] [ABS_REGISTER_KEY]

Which should output the details of the register, as well as its current value, in hexadecimal and binary form. The output should also include all bit fields, and their current values.

Example:

(gdb) mon rr clkctrl clkctrl.mclkctrlc
Register name: "MCLKCTRLC"
Address: 0x00000062
Size: 1 byte(s)

--------- Value -----------
Hexadecimal: 0x06
Binary: 0b00000110

CFDSRC: 0b01
CFDTST: 0b1
CFDEN: 0b0

Users can use the new target details page on the Bloom website to obtain peripheral and register keys:

Screenshot from 2024-08-12 18-12-51

@navnavnav navnavnav added the enhancement New feature or request label Aug 12, 2024
@navnavnav navnavnav self-assigned this Aug 12, 2024
@navnavnav
Copy link
Member Author

Development work for this is complete.

I have added two GDB monitor commands: lr and rr.

Listing registers (lr)

The lr command will list all target registers:

(gdb) mon lr
---------- AC0 (ac0) peripheral registers ----------

ac, ctrla, CTRLA, 0x00000680, 1 byte(s), "Control A"
ac, ctrlb, CTRLB, 0x00000681, 1 byte(s), "Control B"
ac, dacref, DACREF, 0x00000685, 1 byte(s), "DAC Voltage Reference"
ac, intctrl, INTCTRL, 0x00000686, 1 byte(s), "Interrupt Control"
ac, muxctrl, MUXCTRL, 0x00000682, 1 byte(s), "Mux Control A"
ac, status, STATUS, 0x00000687, 1 byte(s), "Status"

---------- AC1 (ac1) peripheral registers ----------

ac, ctrla, CTRLA, 0x00000688, 1 byte(s), "Control A"
ac, ctrlb, CTRLB, 0x00000689, 1 byte(s), "Control B"
ac, dacref, DACREF, 0x0000068D, 1 byte(s), "DAC Voltage Reference"
ac, intctrl, INTCTRL, 0x0000068E, 1 byte(s), "Interrupt Control"
ac, muxctrl, MUXCTRL, 0x0000068A, 1 byte(s), "Mux Control A"
ac, status, STATUS, 0x0000068F, 1 byte(s), "Status"

---------- AC2 (ac2) peripheral registers ----------

ac, ctrla, CTRLA, 0x00000690, 1 byte(s), "Control A"
ac, ctrlb, CTRLB, 0x00000691, 1 byte(s), "Control B"
ac, dacref, DACREF, 0x00000695, 1 byte(s), "DAC Voltage Reference"
...

A peripheral key can be provided to list all registers within a specific peripheral:

(gdb) mon lr porta
---------- PORTA (porta) peripheral registers ----------

port, dir, DIR, 0x00000400, 1 byte(s), "Data Direction"
port, dirclr, DIRCLR, 0x00000402, 1 byte(s), "Data Direction Clear"
port, dirset, DIRSET, 0x00000401, 1 byte(s), "Data Direction Set"
port, dirtgl, DIRTGL, 0x00000403, 1 byte(s), "Data Direction Toggle"
port, in, IN, 0x00000408, 1 byte(s), "Input Value"
port, intflags, INTFLAGS, 0x00000409, 1 byte(s), "Interrupt Flags"
port, out, OUT, 0x00000404, 1 byte(s), "Output Value"
port, outclr, OUTCLR, 0x00000406, 1 byte(s), "Output Value Clear"
port, outset, OUTSET, 0x00000405, 1 byte(s), "Output Value Set"
port, outtgl, OUTTGL, 0x00000407, 1 byte(s), "Output Value Toggle"
port, pin0ctrl, PIN0CTRL, 0x00000410, 1 byte(s), "Pin 0 Control"
port, pin1ctrl, PIN1CTRL, 0x00000411, 1 byte(s), "Pin 1 Control"
port, pin2ctrl, PIN2CTRL, 0x00000412, 1 byte(s), "Pin 2 Control"
port, pin3ctrl, PIN3CTRL, 0x00000413, 1 byte(s), "Pin 3 Control"
port, pin4ctrl, PIN4CTRL, 0x00000414, 1 byte(s), "Pin 4 Control"
port, pin5ctrl, PIN5CTRL, 0x00000415, 1 byte(s), "Pin 5 Control"
port, pin6ctrl, PIN6CTRL, 0x00000416, 1 byte(s), "Pin 6 Control"
port, pin7ctrl, PIN7CTRL, 0x00000417, 1 byte(s), "Pin 7 Control"
port, pinconfig, PINCONFIG, 0x0000040B, 1 byte(s), "Pin Control Config"
port, pinctrlclr, PINCTRLCLR, 0x0000040E, 1 byte(s), "Pin Control Clear"
port, pinctrlset, PINCTRLSET, 0x0000040D, 1 byte(s), "Pin Control Set"
port, pinctrlupd, PINCTRLUPD, 0x0000040C, 1 byte(s), "Pin Control Update"
port, portctrl, PORTCTRL, 0x0000040A, 1 byte(s), "Port Control"

Reading registers (rr)

The rr command can be used to read a value of any target register:

mon rr [PERIPHERAL_KEY] [REGISTER_GROUP_KEY] [REGISTER_KEY]
(gdb) mon rr porta port dir

Name: DIR
Address: 0x00000400
Size: 1 byte(s)

----------- Value -----------
0x00 (0, 0b00000000)

The group key can be omitted when the peripheral has only a single register group, and the register resides directly within (not in a subgroup):

(gdb) mon rr porta dir

Name: DIR
Address: 0x00000400
Size: 1 byte(s)

----------- Value -----------
0x00 (0, 0b00000000)

If no register key is provided, all registers within the given peripheral or register group will be read:

(gdb) mon rr tca0
Reading TCA0 peripheral registers...

tca.single, cmp0, CMP0, 0x00000A28, 2 byte(s) | 0x0000 (0, 0b0000000000000000)
tca.single, cmp0buf, CMP0BUF, 0x00000A38, 2 byte(s) | 0x0000 (0, 0b0000000000000000)
tca.single, cmp1, CMP1, 0x00000A2A, 2 byte(s) | 0x0000 (0, 0b0000000000000000)
tca.single, cmp1buf, CMP1BUF, 0x00000A3A, 2 byte(s) | 0x0000 (0, 0b0000000000000000)
tca.single, cmp2, CMP2, 0x00000A2C, 2 byte(s) | 0x0000 (0, 0b0000000000000000)
tca.single, cmp2buf, CMP2BUF, 0x00000A3C, 2 byte(s) | 0x0000 (0, 0b0000000000000000)
tca.single, cnt, CNT, 0x00000A20, 2 byte(s) | 0x0000 (0, 0b0000000000000000)
tca.single, ctrla, CTRLA, 0x00000A00, 1 byte(s) | 0x00 (0, 0b00000000), CLKSEL: 0b000, ENABLE: 0b0, RUNSTDBY: 0b0
tca.single, ctrlb, CTRLB, 0x00000A01, 1 byte(s) | 0x00 (0, 0b00000000), ALUPD: 0b0, CMP0EN: 0b0, CMP1EN: 0b0, CMP2EN: 0b0, WGMODE: 0b000
tca.single, ctrlc, CTRLC, 0x00000A02, 1 byte(s) | 0x00 (0, 0b00000000), CMP0OV: 0b0, CMP1OV: 0b0, CMP2OV: 0b0
tca.single, ctrld, CTRLD, 0x00000A03, 1 byte(s) | 0x00 (0, 0b00000000), SPLITM: 0b0
tca.single, ctrleclr, CTRLECLR, 0x00000A04, 1 byte(s) | 0x00 (0, 0b00000000), CMD: 0b00, DIR: 0b0, LUPD: 0b0
tca.single, ctrleset, CTRLESET, 0x00000A05, 1 byte(s) | 0x00 (0, 0b00000000), CMD: 0b00, DIR: 0b0, LUPD: 0b0
tca.single, ctrlfclr, CTRLFCLR, 0x00000A06, 1 byte(s) | 0x00 (0, 0b00000000), CMP0BV: 0b0, CMP1BV: 0b0, CMP2BV: 0b0, PERBV: 0b0
tca.single, ctrlfset, CTRLFSET, 0x00000A07, 1 byte(s) | 0x00 (0, 0b00000000), CMP0BV: 0b0, CMP1BV: 0b0, CMP2BV: 0b0, PERBV: 0b0
tca.single, dbgctrl, DBGCTRL, 0x00000A0E, 1 byte(s) | 0x00 (0, 0b00000000), DBGRUN: 0b0
tca.single, evctrl, EVCTRL, 0x00000A09, 1 byte(s) | 0x00 (0, 0b00000000), CNTAEI: 0b0, CNTBEI: 0b0, EVACTA: 0b000, EVACTB: 0b000
tca.single, intctrl, INTCTRL, 0x00000A0A, 1 byte(s) | 0x00 (0, 0b00000000), CMP0: 0b0, CMP1: 0b0, CMP2: 0b0, OVF: 0b0
tca.single, intflags, INTFLAGS, 0x00000A0B, 1 byte(s) | 0x00 (0, 0b00000000), CMP0: 0b0, CMP1: 0b0, CMP2: 0b0, OVF: 0b0
tca.single, per, PER, 0x00000A26, 2 byte(s) | 0xFFFF (65535, 0b1111111111111111)
tca.single, perbuf, PERBUF, 0x00000A36, 2 byte(s) | 0xFFFF (65535, 0b1111111111111111)
tca.single, temp, TEMP, 0x00000A0F, 1 byte(s) | 0x00 (0, 0b00000000)
tca.split, ctrla, CTRLA, 0x00000A00, 1 byte(s) | 0x00 (0, 0b00000000), CLKSEL: 0b000, ENABLE: 0b0, RUNSTDBY: 0b0
tca.split, ctrlb, CTRLB, 0x00000A01, 1 byte(s) | 0x00 (0, 0b00000000), HCMP0EN: 0b0, HCMP1EN: 0b0, HCMP2EN: 0b0, LCMP0EN: 0b0, LCMP1EN: 0b0, LCMP2EN: 0b0
tca.split, ctrlc, CTRLC, 0x00000A02, 1 byte(s) | 0x00 (0, 0b00000000), HCMP0OV: 0b0, HCMP1OV: 0b0, HCMP2OV: 0b0, LCMP0OV: 0b0, LCMP1OV: 0b0, LCMP2OV: 0b0
tca.split, ctrld, CTRLD, 0x00000A03, 1 byte(s) | 0x00 (0, 0b00000000), SPLITM: 0b0
tca.split, ctrleclr, CTRLECLR, 0x00000A04, 1 byte(s) | 0x00 (0, 0b00000000), CMD: 0b00, CMDEN: 0b00
tca.split, ctrleset, CTRLESET, 0x00000A05, 1 byte(s) | 0x00 (0, 0b00000000), CMD: 0b00, CMDEN: 0b00
tca.split, dbgctrl, DBGCTRL, 0x00000A0E, 1 byte(s) | 0x00 (0, 0b00000000), DBGRUN: 0b0
tca.split, hcmp0, HCMP0, 0x00000A29, 1 byte(s) | 0x00 (0, 0b00000000)
tca.split, hcmp1, HCMP1, 0x00000A2B, 1 byte(s) | 0x00 (0, 0b00000000)
tca.split, hcmp2, HCMP2, 0x00000A2D, 1 byte(s) | 0x00 (0, 0b00000000)
tca.split, hcnt, HCNT, 0x00000A21, 1 byte(s) | 0x00 (0, 0b00000000)
tca.split, hper, HPER, 0x00000A27, 1 byte(s) | 0xFF (255, 0b11111111)
tca.split, intctrl, INTCTRL, 0x00000A0A, 1 byte(s) | 0x00 (0, 0b00000000), HUNF: 0b0, LCMP0: 0b0, LCMP1: 0b0, LCMP2: 0b0, LUNF: 0b0
tca.split, intflags, INTFLAGS, 0x00000A0B, 1 byte(s) | 0x00 (0, 0b00000000), HUNF: 0b0, LCMP0: 0b0, LCMP1: 0b0, LCMP2: 0b0, LUNF: 0b0
tca.split, lcmp0, LCMP0, 0x00000A28, 1 byte(s) | 0x00 (0, 0b00000000)
tca.split, lcmp1, LCMP1, 0x00000A2A, 1 byte(s) | 0x00 (0, 0b00000000)
tca.split, lcmp2, LCMP2, 0x00000A2C, 1 byte(s) | 0x00 (0, 0b00000000)
tca.split, lcnt, LCNT, 0x00000A20, 1 byte(s) | 0x00 (0, 0b00000000)
tca.split, lper, LPER, 0x00000A26, 1 byte(s) | 0xFF (255, 0b11111111)

Terminal font colors are adjusted in the output for easier reading:

image

These changes will be included in the v1.1.0 release. Will close the ticket once the release is published.

@navnavnav navnavnav added this to the v1.1.0 milestone Aug 26, 2024
@navnavnav
Copy link
Member Author

I may add a wr command, for writing to registers...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Development

No branches or pull requests

1 participant