SparkFun Forums 

Where electronics enthusiasts find answers.

Open source ARM Debugger
By mlu
#18206
Hello Dominic

Can you give a short description of the correct way to handle hosts with different endianness ?

I see you are making changes like:

target->type->read_memory(target, MC_FSR, 4, 1, (u8 *)&fsr);

to:

fsr = target_buffer_get_u32(target, (u8 *)&fsr);

Greetings
Magnus
By Dominic
#18219
Hello Magnus,

I've been writing (as on paper) about what I'd like the different API's to use, and what not. Sorry I didn't publish this earlier.

The jtag_XXX functions take u8* (pointers to unsigned 8-bit datatype) arguments to little-endian data, as that's the "natural" endianness for JTAG data (LSB first).

Memory read/write functions (target->type->read_memory/write_memory) take an u8* argument pointing to a buffer in target endianness. This is to support GDB, which uses plain byte streams to transfer data to/from the target's memory (among other things. in general, we can't know what data is inside the buffer).

All functions that specify u32[*] or u16[*] take data in host-endianness. The arm[79]tdmi_clock_<out|in> functions uses handlers to translate the data captured from the JTAG interface (little-endian) to the hosts endianness.

The arm[79]tdmi_clock_data_in_endianness are used to read data in 8, 16 or 32 bits quantities in target endianness, to faciliate loading of target-endian buffers directly.

If flash code for example wants to read a 32-bit word from the target's memory space, it can either use target->type->read_memory, reading the data in the target's endianness, and convert it using target_buffer_get_u32, or target_read_u[32|16|8] to read the data directly into a variable in host endianness.

Regards,

Dominic

---
edit:
This isn't complete yet. I'll add to this list while I'm going through my notes, possibly cleaning up the current code.
By Dominic
#18228
Here is an attempt to describe the idea a bit more structured:

- JTAG
All JTAG operations take pointers to little-endian buffers (u8*). The in_handler member of the scan_field_t structure can be used to put captured data directly in a host-endian variable, or a target-endian buffer.

- TARGET
The target interface (target_type_t, target_t, registers, algorithms) use little-endian buffers for values, to potentially allow the OpenOCD to be extended beyond 32 (64, 128) bit targets, for example in case of multi-media extensions. buf_get/set_u32 should be used to read/write these buffers.
Those interfaces currently using u32 for addresses would still have to be changed.


Target-internal functions can use whatever datatype fits the architecture, for example u32 in case of ARMv4/5. These values are stored in normal u32 variables, therefor in host-endianness. As target->type->read/write_memory operates on buffers in target-endianness, the convenience functions target_read/write_u8/6/32 have been added to directly read/write u8, u16 and u32 values in host endianness.

- FLASH
Flash functions only make use of the external target interface, and therefor operate on buffers in target endianness. If flash code has to read/write memory mapped registers, it should use the target_read/write_u8/16/32 functions. Alternatively, it can call target->type->read/write memory directly, and use target_buffer_get/set_u8/16/32 on the memory buffer (that's what I did when I started working on the at91sam7.c code. I completely forgot about these changes, and committed them together with the other changes. This is incomplete, and target_read_u32 would be more appropriate).

If code is to be executed on the target (flash write algorithms, for example), the opcodes are stored in u32[] arrays (therefor in host endianness). Before writing these opcodes to the target, target_buffer_set_u32 has to be used to convert the opcodes to target endianness. See arm7_9_bulk_write_memory for an example.

Regards,

Dominic