Доступ к битам через указатель на структуру или манипулирование битами периферии в gdb

При отладке программ под arm-none-eabi, для просмотра регистров в отладчике
arm-none-eabi-gdb в тексте программы описываю структуру регистра,
объявляю указатель на структуру и присваиваю указателю адрес регистра и вуаля,
в arm-none-eabi-gdb print печатает содержимое регистра и позволяет менять
значения битов и все в человеческом виде.
На msp430 не все так радужно.
На платформе arm-none-eabi делается это так.
Например мне нужен для препарирования регистр TIM3.
Описываем структуру TIM.
В структуре описываем байты к примеру CR1 и CR2
typedef struct cr1_type {
unsigned CEN: 1;
unsigned UDIS: 1;
unsigned URS: 1;
unsigned OPM: 1;
unsigned DIR: 1;
unsigned CMS: 2;
unsigned ARPE: 1;
unsigned CKD: 2;
unsigned Res: 6;
} cr1;
typedef struct cr2_type {
unsigned Res0: 3;
unsigned CCDS: 1;
unsigned MMS: 3;
unsigned TI1S: 1;
unsigned Res1: 8;
} cr2;
typedef struct
{
volatile cr1 CR1; /*!< TIM control register 1, Address offset: 0x00 */
uint16_t RESERVED0; /*!< Reserved, 0x02 */
volatile cr2 CR2; /*!< TIM control register 2, Address offset: 0x04 */
uint16_t RESERVED1; /*!< Reserved, 0x06 */
volatile uint16_t SMCR; /*!< TIM slave Mode Control register, Address offset: 0x08 */
uint16_t RESERVED2; /*!< Reserved, 0x0A */
volatile uint16_t DIER; /*!< TIM DMA/interrupt enable register, Address offset: 0x0C */
uint16_t RESERVED3; /*!< Reserved, 0x0E */
volatile uint16_t SR; /*!< TIM status register, Address offset: 0x10 */
uint16_t RESERVED4; /*!< Reserved, 0x12 */
volatile uint16_t EGR; /*!< TIM event generation register, Address offset: 0x14 */
uint16_t RESERVED5; /*!< Reserved, 0x16 */
volatile uint16_t CCMR1; /*!< TIM capture/compare mode register 1, Address offset: 0x18 */
uint16_t RESERVED6; /*!< Reserved, 0x1A */
volatile uint16_t CCMR2; /*!< TIM capture/compare mode register 2, Address offset: 0x1C */
uint16_t RESERVED7; /*!< Reserved, 0x1E */
volatile uint16_t CCER; /*!< TIM capture/compare enable register, Address offset: 0x20 */
uint16_t RESERVED8; /*!< Reserved, 0x22 */
volatile uint32_t CNT; /*!< TIM counter register, Address offset: 0x24 */
volatile uint16_t PSC; /*!< TIM prescaler register, Address offset: 0x28 */
uint16_t RESERVED10; /*!< Reserved, 0x2A */
volatile uint32_t ARR; /*!< TIM auto-reload register, Address offset: 0x2C */
volatile uint16_t RCR; /*!< TIM repetition counter register, Address offset: 0x30 */
uint16_t RESERVED12; /*!< Reserved, 0x32 */
volatile uint32_t CCR1; /*!< TIM capture/compare register 1, Address offset: 0x34 */
volatile uint32_t CCR2; /*!< TIM capture/compare register 2, Address offset: 0x38 */
volatile uint32_t CCR3; /*!< TIM capture/compare register 3, Address offset: 0x3C */
volatile uint32_t CCR4; /*!< TIM capture/compare register 4, Address offset: 0x40 */
volatile uint16_t BDTR; /*!< TIM break and dead-time register, Address offset: 0x44 */
uint16_t RESERVED17; /*!< Reserved, 0x26 */
volatile uint16_t DCR; /*!< TIM DMA control register, Address offset: 0x48 */
uint16_t RESERVED18; /*!< Reserved, 0x4A */
volatile uint16_t DMAR; /*!< TIM DMA address for full transfer register, Address offset: 0x4C */
uint16_t RESERVED19; /*!< Reserved, 0x4E */
volatile uint16_t OR; /*!< TIM option register, Address offset: 0x50 */
uint16_t RESERVED20; /*!< Reserved, 0x52 */
} TIM_TypeDef_bit;
В тексте программы объявляем указатель на TIM3.
volatile TIM_TypeDef_bit* p_tim3_bit = (TIM_TypeDef_bit*)TIM3;
В отладчике arm-none-eabi-gdb имеем возможность используя указатель просматривать битовое поле и менять его значение.
p p_tim3_bit->CR1.CEN
$1 = 1
Таймер включен
set p_tim3_bit->CR1.CEN = 0
Отключили таймер
Кроме того, описав такой указатель на структуру можно в тексте программы манипулировать битами регистра не через битовые операции, а напрямую через манипуляции с битами. Оно конечно не всегда имеет смысл, но в ряде случаев вполне себе иеет право на жизнь.
p_tim3_bit->CR1.CEN = 1;// включили таймер
p_tim3_bit->CR1.CEN = 0;//отключили таймер
А вот на архитектуре msp430 подобный пердимонокль не всегда работает.
Например описали структуру порта так
typedef struct port_8 {
unsigned p0: 1;
unsigned p1: 1;
unsigned p2: 1;
unsigned p3: 1;
unsigned p4: 1;
unsigned p5: 1;
unsigned p6: 1;
unsigned p7: 1;
} t_port_8;
В программе объявили указатель и прописали в нем порт P1OUT или P4OUT.
volatile t_port_8* p_aout = (t_port_8*)(PAOUT_+0);
volatile t_port_8* p_bout = (t_port_8*)(PBOUT_+0);
Используем указатель для доступа к битам порта так
p_aout->p0 = 1;
p_bout->p7 = 0;
delay(10000);
p_aout->p0 = 0;
p_bout->p7 = 1;
delay(10000);
А вот что у нас в ассемблерном выхлопе
Выхлоп msp430-gcc-4.9
MOV.W 2(R1), R12
MOV.B @R12, R13
BIS.B #1, R13
MOV.B R13, @R12
MOV.W @R1, R12
MOV.B @R12, R13
AND.B #127, R13
MOV.B R13, @R12
MOV.W #10000, R12
CALL #delay
MOV.W 2(R1), R12
MOV.B @R12, R13
BIC.B #1, R13
MOV.B R13, @R12
MOV.W @R1, R12
MOV.B @R12, R13
BIS.B #-128, R13
MOV.B R13, @R12
MOV.W #10000, R12
CALL #delay
Выхлоп msp430-gcc-4.6.3
mov -6(r4), r15
mov @r15, r14
bis #1, r14
mov r14, @r15
mov -4(r4), r15
mov @r15, r14
and #llo(-129), r14
mov r14, @r15
mov #10000, r15
call #delay
mov -6(r4), r15
mov @r15, r14
and #llo(-2), r14
mov r14, @r15
mov -4(r4), r15
mov @r15, r14
bis #128, r14
mov r14, @r15
mov #10000, r15
call #delay
Пример экспериментальной поддержки MSP430 в clang-3.5
Экспериментальная потому, что приходится вначале получать LLVM-байт код, и его уже преобразовывать в целевой ассемблерный
.LBB1_1: ; %delay.exit4
; in Loop: Header=BB1_2 Depth=1
mov.w -4(r4), r12
.LBB1_2: ; =>This Loop Header: Depth=1
; Child Loop BB1_4 Depth 2
; Child Loop BB1_7 Depth 2
bis.b #1, &514
and.b #127, &547
mov.w #0, -8(r4)
mov.w #0, -6(r4)
jmp .LBB1_4
.LBB1_3: ; %.lr.ph.i
; in Loop: Header=BB1_4 Depth=2
add.w -6(r4), -8(r4)
add.w #1, -6(r4)
.LBB1_4: ; %.lr.ph.i
; Parent Loop BB1_2 Depth=1
; => This Inner Loop Header: Depth=2
cmp.w #10000, -6(r4)
jl .LBB1_3
; BB#5: ; %delay.exit
; in Loop: Header=BB1_2 Depth=1
mov.w -8(r4), r12
and.b #-2, &514
bis.b #-128, &547
mov.w #0, -4(r4)
mov.w #0, -2(r4)
jmp .LBB1_7
.LBB1_6: ; %.lr.ph.i3
; in Loop: Header=BB1_7 Depth=2
add.w -2(r4), -4(r4)
add.w #1, -2(r4)
.LBB1_7: ; %.lr.ph.i3
; Parent Loop BB1_2 Depth=1
; => This Inner Loop Header: Depth=2
cmp.w #10000, -2(r4)
jl .LBB1_6
А вот для сравнения описание структуры для доступа к порту размером в слово
typedef struct port_16 {
unsigned p0: 1;
unsigned p1: 1;
unsigned p2: 1;
unsigned p3: 1;
unsigned p4: 1;
unsigned p5: 1;
unsigned p6: 1;
unsigned p7: 1;
unsigned p8: 1;
unsigned p9: 1;
unsigned p10: 1;
unsigned p11: 1;
unsigned p12: 1;
unsigned p13: 1;
unsigned p14: 1;
unsigned p15: 1;
} t_port_16;
Используем в программе так
Объявление указателя
volatile t_port_16* p_aout = (t_port_16*)(PAOUT_+0);
volatile t_port_16* p_bout = (t_port_16*)(PBOUT_+0);
Использование в коде
p_aout->p0 = 1;
p_bout->p15 = 0;
delay(10000);
p_aout->p0 = 0;
p_bout->p15 = 1;
delay(10000);
Тут следует помнить, что 15 бит порта B и 7 бит порта 4 у MSP430 одно и то же
Вот выхлоп ассемблера у msp430-gcc-4.9
MOV.W 2(R1), R12
MOV.W @R12, R13
BIS.W #1, R13
MOV.W R13, @R12
MOV.W @R1, R12
MOV.W @R12, R13
AND.W #32767, R13
MOV.W R13, @R12
MOV.W #10000, R12
CALL #delay
MOV.W 2(R1), R12
MOV.W @R12, R13
BIC.W #1, R13
MOV.W R13, @R12
MOV.W @R1, R12
MOV.W @R12, R13
BIS.W #-32768, R13
MOV.W R13, @R12
MOV.W #10000, R12
CALL #delay
И вот какой выхлоп ассемблера у msp430-gcc-4.6.3
mov -6(r4), r15
mov @r15, r14
bis #1, r14
mov r14, @r15
mov -4(r4), r15
mov @r15, r14
and #32767, r14
mov r14, @r15
mov #10000, r15
call #delay
mov -6(r4), r15
mov @r15, r14
and #llo(-2), r14
mov r14, @r15
mov -4(r4), r15
mov @r15, r14
bis #llo(-32768), r14
mov r14, @r15
mov #10000, r15
call #delay
То есть msp430-gcc-4.9 и clang-3.5 видят разницу между структурами размером в байт и размеров в два байта,
а msp430-gcc-4.6.3 разницы не видит и мапит адреса как Бог на душу положит.
Таким образом, если используем msp430-gcc-4.6.3, структура, через которую получаем доступ к битовым полям, должна быть выровнена по двум байтам, иначе через указатель вы получите доступ к левым адресам в памяти.
И похоже лечится это указанием ключа -fpack-struct. Тогда ассемблерный выхлоп такой будет.
mov -6(r4), r15
mov.b @r15, r14
bis.b #1, r14
mov.b r14, @r15
mov -4(r4), r15
mov.b @r15, r14
and.b #127, r14
mov.b r14, @r15
mov #10000, r15
call #delay
mov -6(r4), r15
mov.b @r15, r14
and.b #llo(-2), r14
mov.b r14, @r15
mov -4(r4), r15
mov.b @r15, r14
bis.b #llo(-128), r14
mov.b r14, @r15
mov #10000, r15
call #delay
Как вариант объявить структуру с атрибутом __attribute__((packed))
typedef struct port_8 {
unsigned p0: 1;
unsigned p1: 1;
unsigned p2: 1;
unsigned p3: 1;
unsigned p4: 1;
unsigned p5: 1;
unsigned p6: 1;
unsigned p7: 1;
} __attribute__((packed)) t_port_8;
Тогда выхлоп ассемблерный будет так же корректный
mov -6(r4), r15
mov.b @r15, r14
bis.b #1, r14
mov.b r14, @r15
mov -4(r4), r15
mov.b @r15, r14
and.b #127, r14
mov.b r14, @r15
mov #10000, r15
call #delay
mov -6(r4), r15
mov.b @r15, r14
and.b #llo(-2), r14
mov.b r14, @r15
mov -4(r4), r15
mov.b @r15, r14
bis.b #llo(-128), r14
mov.b r14, @r15
mov #10000, r15
Иначе говоря, что бы в программе манипулировать битами через указатель на структуру, нужно что бы либо указатель был на структуру размером в два байта,, либо структура с атрибутом __attribute__((packed)), либо ключ -fpack-struct использовать с msp430-gcc-4.6.3.
Или просто компилить модуль шлангом или gcc-4.9.
Для манипулирования через указатель на структуру в отладчике, можно вручную поправить адрес в указателе и тогда доступ через байтовую структуру будет работать и в случае использования msp430-gcc-4.6.3.
- +4
- 03 ноября 2015, 13:24
- fr0ster
mspgcc давно уже obsolete, discontinued, abadoned и not recommended. В смысле, тот, что с саурсфорджа, 4.6. Увы. То, что сделал РедХат выглядит уродливее, да, но хоть как-то поддерживается.
А вот клангом для msp430 надо бы научиться пользоваться, я вообще кланг клюблю больше gcc :)
А вот клангом для msp430 надо бы научиться пользоваться, я вообще кланг клюблю больше gcc :)
Есть еще mspgcc который TI курирует, он GPL и он новее.
Вот только он с mspdebug не дружит, а что вместо mspdebug взять консольное для unix не знаю :(
А clang конечно интересная вещь, хотя «gcc наше фсе»(C) :)
По поводу clang и msp430 есть статья и перевод.
Пока clang не умеет генерить бинарник ни elf, ни obj напрямую.
Я себе Makefile сделал, и собираю по цепочке c->ll->s->o->elf.
Соответственно c->ll это clang, ll->s это llc, а s->o и o->elf это mspgcc, даже 4.6 справляется :)
Вот только он с mspdebug не дружит, а что вместо mspdebug взять консольное для unix не знаю :(
А clang конечно интересная вещь, хотя «gcc наше фсе»(C) :)
По поводу clang и msp430 есть статья и перевод.
Пока clang не умеет генерить бинарник ни elf, ни obj напрямую.
Я себе Makefile сделал, и собираю по цепочке c->ll->s->o->elf.
Соответственно c->ll это clang, ll->s это llc, а s->o и o->elf это mspgcc, даже 4.6 справляется :)
CC=msp430-gcc -O
CLANG=clang -O3
LLC=llc
RM=rm
INCLUDE_DIR=/usr/msp430/include/
CFLAGS=-D__MSP430F5529__ -I /usr/msp430/include/
LDFLAGS=-L /usr/msp430/lib/ldscripts/msp430f5529/
MSPFLAGS=-mmcu=msp430f5529
SOURCES=blink.c
ASMFILES=$(LLFILES:.ll=.s)
LLFILES=$(SOURCES:.c=.ll)
OBJECTS=$(ASMFILES:.s=.o)
EXECUTABLE=blink.elf
CTAGS=ctags
#all: $(SOURCES) $(LLFILES) $(ASMFILES) $(EXECUTABLE)
all: $(EXECUTABLE)
@printf "all\n\r"
$(EXECUTABLE): $(OBJECTS)
@printf "$(OBJECTS)\n\r"
@$(CC) $(MSPFLAGS) $(OBJECTS) -o $@
$(OBJECTS): $(ASMFILES)
@printf "$(ASMFILES)\n\r"
@$(CC) -c $(ASMFILES) $(MSPFLAGS) -o $@
$(ASMFILES): $(LLFILES)
@printf "$(LLFILES)\n\r"
@$(LLC) -march=msp430 $< -o $@
$(LLFILES): $(SOURCES)
@printf "$(SOURCES)\n\r"
@$(CLANG) --target=msp430 -S -emit-llvm -c $< $(CFLAGS) -o $@
@$(CTAGS) -a $<
.c.ll:
@printf "$<\n\r"
@$(CLANG) --target=msp430 -S -emit-llvm -c $< $(CFLAGS) -o $@
@$(CTAGS) -a $<
.ll.s:
@printf "$<\n\r"
@$(LLC) -march=msp430 $< -o $@
.s.o:
@printf "$<\n\r"
@$(CC) -c $< $(MSPFLAGS) -o $@
clean:
@printf "clean\n\r"
@$(RM) -f $(EXECUTABLE) $(OBJECTS) $(ASMFILES) $(LLFILES) tags
tags:
@printf "tags\n\r"
@./ctags_with_dep.sh $(SOURCES)
@$(CTAGS) -a $(SOURCES)
flash:
@printf "flash\n\r"
@mspdebug tilib "prog $(EXECUTABLE)"
Есть еще mspgcc который TI курирует, он GPL и он новее.Я его и назвал РедХатовским, потому что по факту его пилят люди из РедХата по заказу ТИ.
Вообще-то для линукса, винды и макоси у него в комплекте есть прокси для gdb, да и gdb тоже там есть внутри в полном комплекте. Я не очень понимаю, что значит, что он не дружит с mspdebug, как вообще связан компилятор и отладчик, можете пояснить? Мне вот, на FreeBSD, сложнее, там нет прокси для gdb, но можно собрать libmsp430.so, которую умеет грузить mspdebug (драйвер «tilib») и с отладочными плдатами оно у меня работало.
Статью про clang я нашёл, но ей больше года, уже clang 3.7 вышел, 3.8 на подходе, надо посмотреть, может там что поменялось. Но встаёт вопрос libc и вообще рантайма в такой ситуации.
Грубо говоря есть gdb-клиент и gdb-сервер.
Первый входит в тулчейн и должен понимать бинарник, который тулчейн компилит, а второй должен уметь управлять отладчиком.
Второй это openocd, jlink-gdb-server и mspdebug. Первый это arm-none-eabi-gdb, msp430-elf-gdb.
И оба должны понимать протокол общения.
Так вот, когда я говорю, что mspgcc от TI/RedHat, то это значит протокол общения редхатовско-тишного клиента сломали/допилили/поменяли, или существующий mspdebug не полностью поддерживает протокол общения.
Если запустить mspdebug и подключаться к нему msp430-elf-gdb от TI/RedHat, то после коннекта пишет что-то про нераспознанную строку, полученную от mspdebug и коннект рвется.
В комплекте есть gdb-server вместо mspdebug?
А насчет clang-3.8, уже его можно скачать. Сачал, собрал, по отношению к msp430 пока дело слабо сдвинулось, напрямую бинарник генерить не может пока(а может и не пока).
Первый входит в тулчейн и должен понимать бинарник, который тулчейн компилит, а второй должен уметь управлять отладчиком.
Второй это openocd, jlink-gdb-server и mspdebug. Первый это arm-none-eabi-gdb, msp430-elf-gdb.
И оба должны понимать протокол общения.
Так вот, когда я говорю, что mspgcc от TI/RedHat, то это значит протокол общения редхатовско-тишного клиента сломали/допилили/поменяли, или существующий mspdebug не полностью поддерживает протокол общения.
Если запустить mspdebug и подключаться к нему msp430-elf-gdb от TI/RedHat, то после коннекта пишет что-то про нераспознанную строку, полученную от mspdebug и коннект рвется.
В комплекте есть gdb-server вместо mspdebug?
А насчет clang-3.8, уже его можно скачать. Сачал, собрал, по отношению к msp430 пока дело слабо сдвинулось, напрямую бинарник генерить не может пока(а может и не пока).
В комплекте есть gdb-server вместо mspdebug?Да, если качать полный пакет с соглашением с лицензией на сайте и установщиком, а не архив.
Ну а mspdebug, надеюсь, автор починит под новый gdb, он его активно пилит же.
Комментарии (12)
RSS свернуть / развернуть