Post B6djesS85hOglzPfqS by kabel42@polymaths.social
 (DIR) More posts by kabel42@polymaths.social
 (DIR) Post #B6d6d6YAoFPLhiP6R6 by navi@social.vlhl.dev
       0 likes, 0 repeats
       
       there’s something so satisfactory about managing bitflags w/ &= ~FLAG and |= FLAG
       
 (DIR) Post #B6d6d6jW84TwGtiA7M by lanodan@queer.hacktivis.me
       0 likes, 0 repeats
       
       @navi kind of wish it could be var.flag = 1 instead though
       
 (DIR) Post #B6d76ijJw9FAVxjviC by kabel42@polymaths.social
       0 likes, 0 repeats
       
       @lanodan @navi Trying (and failing) to get that to reliably work has caused me more headache than debugging a missing ~ on a &
       
 (DIR) Post #B6d76j4wdkXbb1rCPw by lanodan@queer.hacktivis.me
       0 likes, 0 repeats
       
       @kabel42 @navi Oh yeah, don't try unless it's a language where bitfields are properly portable.Better have stuff like macros if you're not confident in bitmasking.
       
 (DIR) Post #B6dAFxtTEAwS0qaScy by mirabilos@toot.mirbsd.org
       0 likes, 0 repeats
       
       @kabel42 @navi @lanodan asm is the way to go for that
       
 (DIR) Post #B6dFZCv25WErsxJRb6 by ska@social.treehouse.systems
       1 likes, 0 repeats
       
       @navi It's seeing the bits, isn't it. It's having proof, compiler stupidity notwithstanding, that you're not wasting a single byte. Right?
       
 (DIR) Post #B6dGkpxhMpoY7AfX28 by kabel42@polymaths.social
       0 likes, 0 repeats
       
       @mirabilos @navi @lanodan or C++ or python, but I'd like a concise C construct with minimal footguns
       
 (DIR) Post #B6dGkqBsW79mp9Ir8S by mirabilos@toot.mirbsd.org
       0 likes, 0 repeats
       
       @kabel42 @navi @lanodan do the calculation in a temporary variable and then assign to a volatile at the correct address, optionally wrapped with something like Linux’ READ_ONCE/WRITE_ONCE, but if you use tmp vars and just define the register as volatile, you don’t need that abstraction
       
 (DIR) Post #B6dGpVFlmwzLKuLXpA by mirabilos@toot.mirbsd.org
       0 likes, 0 repeats
       
       @kabel42 @navi @lanodan remaining footgun is type size, but anything the assembler can read/write in one instruction will likely work; use an integer type, not a bitfield.
       
 (DIR) Post #B6dKsCdbrAR8Hq2YOO by kabel42@polymaths.social
       0 likes, 0 repeats
       
       @mirabilos @navi @lanodansomething likevar.flag = 1 would prevent copy&paste errors like RCC->APB2PCENR |= RCC_APB1Periph_GPIOD | RCC_APB2Periph_GPIOC;
       
 (DIR) Post #B6dKsCtusXTr6PfZoG by kabel42@polymaths.social
       0 likes, 0 repeats
       
       @mirabilos @navi @lanodanthe c++ version is very verbose in comparison    GPIOC::CFGLR::merge_write<GPIOC::CFGLR::MODE0, GPIO::GPIO_CFGLR_OUT_10Mhz_PP>()                .with<GPIOC::CFGLR::MODE1, GPIO::GPIO_CFGLR_OUT_10Mhz_PP>().with<GPIOC::CFGLR::MODE3, GPIO::GPIO_CFGLR_IN_ANALOG>().done();ref
       
 (DIR) Post #B6dKsD4CGJhhcITmpk by mirabilos@toot.mirbsd.org
       0 likes, 0 repeats
       
       @lanodan @navi @kabel42 yeswelldon’t
       
 (DIR) Post #B6dLhMVou4x7gEn7dQ by mirabilos@toot.mirbsd.org
       0 likes, 0 repeats
       
       @lanodan @kabel42 @navi gimme a register definition, I have an idea
       
 (DIR) Post #B6dMM4dCI0ZQ61eeYK by kabel42@polymaths.social
       0 likes, 0 repeats
       
       @mirabilos @lanodan @navi like this?typedef struct {uint32_t DTG :8;uint32_t LOCK :2;uint32_t OSSI :1;uint32_t OSSR :1;uint32_t BKE :1;uint32_t BKP :1;uint32_t AOE :1;uint32_t MOE :1;uint32_t :16;} tim1_bdtr_t;
       
 (DIR) Post #B6dMM4n7h6VgaoIa1Y by mirabilos@toot.mirbsd.org
       0 likes, 0 repeats
       
       @kabel42 @lanodan @navi that does not sufficiently define the type :þ
       
 (DIR) Post #B6dTDGYPI6Zs9AA436 by kabel42@polymaths.social
       0 likes, 0 repeats
       
       @mirabilos @lanodan @navi
       
 (DIR) Post #B6dTDGmaRNv6r8nO9Q by mirabilos@toot.mirbsd.org
       0 likes, 0 repeats
       
       @kabel42 @lanodan @navi ah ok, das ist also 16 Bit breit, und der breite Wert ist unten?
       
 (DIR) Post #B6dTPWHgdEmWPOBRVA by mirabilos@toot.mirbsd.org
       0 likes, 0 repeats
       
       @kabel42 @lanodan @navi ah, hm, nee, 32 Bit, laut XML… und die oberen 16 Bit sind wo definiert? einfach MBZ?
       
 (DIR) Post #B6dTUqjm11KRI3rX60 by kabel42@polymaths.social
       0 likes, 0 repeats
       
       @mirabilos Ja, es gibt so ziemlich jede Kombination, aber das hat ne gute chance kaputten code zu generieren :)
       
 (DIR) Post #B6dTUqsdU4PxjY0buS by mirabilos@toot.mirbsd.org
       0 likes, 0 repeats
       
       @kabel42 ja, ist genau andersrum wie ich anhand der struct gedacht hätte
       
 (DIR) Post #B6dTZdQYvdQxSU9ssy by mirabilos@toot.mirbsd.org
       0 likes, 0 repeats
       
       @kabel42 @lanodan @navi und immer alles unsigned?
       
 (DIR) Post #B6dTlwXhgVVWDaMrRo by kabel42@polymaths.social
       0 likes, 0 repeats
       
       @mirabilos https://godbolt.org/z/TqMcEvs6e
       
 (DIR) Post #B6dTlwnejCGf13pbJQ by mirabilos@toot.mirbsd.org
       0 likes, 0 repeats
       
       @kabel42 godbolt ist KI-Slop (und tut bei mir eh nicht richtig)
       
 (DIR) Post #B6dVudhPJUboI5BHGa by kabel42@polymaths.social
       0 likes, 0 repeats
       
       @mirabilos ich glaub die Reihenfolge ist implementation defined?
       
 (DIR) Post #B6dVudtoZMX8uYzBbc by mirabilos@toot.mirbsd.org
       0 likes, 0 repeats
       
       @kabel42 ja
       
 (DIR) Post #B6dggS076r6XS0Mqjw by kabel42@polymaths.social
       0 likes, 0 repeats
       
       @mirabilosmain.c#include <stdint.h>typedef struct {uint32_t DTG :8;uint32_t LOCK :2;uint32_t OSSI :1;uint32_t OSSR :1;uint32_t BKE :1;uint32_t BKP :1;uint32_t AOE :1;uint32_t MOE :1;uint32_t :16;} tim1_bdtr_t;volatile tim1_bdtr_t TIM1_BDTR __attribute__((section(".tim1_bdtr")));int main(void) {    TIM1_BDTR.DTG = 5;}$ gcc -Os -S main.cmain.s[...]main:.LFB0:        .cfi_startproc        movb    $5, TIM1_BDTR(%rip)        xorl    %eax, %eax        ret        .cfi_endproc[...]
       
 (DIR) Post #B6dggSCWMj1s4UAl4y by mirabilos@toot.mirbsd.org
       0 likes, 0 repeats
       
       @kabel42 orr, I have something and GCC fails so bad…
       
 (DIR) Post #B6dhlSjRuzbR7XWi7k by mirabilos@toot.mirbsd.org
       0 likes, 0 repeats
       
       disregard this post, I found where I erred(though this means I’ll have to add a script, cannot do it with just XSLT… I think… at least not without putting knots into my brain…)@kabel42 before I write a combination XSLT and shell script (or maybe just XSLT but that would have trouble with omitted fields in the middle making the representation less nice), do you think you can work with this?x.cvolatile unsigned int TIM1_BDTR_ __asm__("TIM1_BDTR")    __attribute__((__common__))    __attribute__((__section__(".tim1_bdtr")));struct TIM1_BDTR {unsigned int DTG:8;unsigned int LOCK:2;unsigned int OSSI:1;unsigned int OSSR:1;unsigned int BKE:1;unsigned int BKP:1;unsigned int AOE:1;unsigned int MOE:1;} __attribute__((__packed__));#define _my_mask(w)((unsigned int)((1ULL << (w)) - 1U))#define _my_rdshift(v,pos,w)(((0U + (v)) >> (pos)) & _my_mask(w))#define _my_wrshift(v,pos,w)(((0U + (v)) & _my_mask(w)) << (pos))#define _my_shiftmask(pos,w)(_my_mask(w) << (pos))#define READ_TIM1_BDTR(tv) __extension__({\register unsigned int tv = TIM1_BDTR_;\(EXPAND_TIM1_BDTR(tv));\})#define EXPAND_TIM1_BDTR(tv) __extension__({\struct TIM1_BDTR rv = {\.DTG = _my_rdshift(tv, 0, 8),\.LOCK = _my_rdshift(tv, 8, 2),\.OSSI = _my_rdshift(tv, 10, 1),\.OSSR = _my_rdshift(tv, 11, 1),\.BKE = _my_rdshift(tv, 12, 1),\.BKP = _my_rdshift(tv, 13, 1),\.AOE = _my_rdshift(tv, 14, 1),\.MOE = _my_rdshift(tv, 15, 1),\};\(rv);\})#define WRITE_TIM1_BDTR(v) do {\TIM1_BDTR_ = PACK_TIM1_BDTR((v), 0U);\} while (/* CONSTCOND */ 0)#define PACK_TIM1_BDTR(v,iv) ((((unsigned int)(iv)) & \(~(_my_shiftmask(0, 8) | _my_shiftmask(8, 2) | _my_shiftmask(10, 1) | _my_shiftmask(11, 1) | _my_shiftmask(12, 1) | _my_shiftmask(13, 1) | _my_shiftmask(14, 1) | _my_shiftmask(15, 1)))) \| _my_wrshift((v).DTG, 0, 8)\| _my_wrshift((v).LOCK, 8, 2)\| _my_wrshift((v).OSSI, 10, 1)\| _my_wrshift((v).OSSR, 11, 1)\| _my_wrshift((v).BKE, 12, 1)\| _my_wrshift((v).BKP, 13, 1)\| _my_wrshift((v).AOE, 14, 1)\| _my_wrshift((v).MOE, 15, 1)\)#define WITH_TIM1_BDTR(block) do {\register unsigned int tv = TIM1_BDTR_;\struct TIM1_BDTR v = EXPAND_TIM1_BDTR(tv);\block\TIM1_BDTR_ = PACK_TIM1_BDTR(v, tv);\} while (/* CONSTCOND */ 0)extern struct TIM1_BDTR munge_it(void);intmain(void){struct TIM1_BDTR r = {0};__asm__ __volatile__("nop" ::: "memory"); /* marker in asm output + compiler barrier */r.DTG = 5;WRITE_TIM1_BDTR(r);__asm__ __volatile__("nop" ::: "memory"); /* marker in asm output + compiler barrier */WITH_TIM1_BDTR(/* assign to v; make sure to NOT use commas in here! */v.LOCK = 2;v.AOE = 1;);__asm__ __volatile__("nop" ::: "memory"); /* marker in asm output + compiler barrier */struct TIM1_BDTR q = munge_it();__asm__ __volatile__("nop" ::: "memory"); /* marker in asm output + compiler barrier *//* if GCC were good, this would have no overhead; instead… */WRITE_TIM1_BDTR(q);__asm__ __volatile__("nop" ::: "memory"); /* marker in asm output + compiler barrier */return (0);}x.s.file"x.c".intel_syntax noprefix.text.section.text.startup,"ax",@progbits.p2align 4.globlmain.typemain, @functionmain:.LFB0:.cfi_startprocleaecx, [esp+4].cfi_def_cfa 1, 0andesp, -16pushDWORD PTR [ecx-4]pushebp.cfi_escape 0x10,0x5,0x2,0x75,0movebp, esppushecx.cfi_escape 0xf,0x3,0x75,0x7c,0x6subesp, 32#APP# 70 "x.c" 1nop# 0 "" 2#NO_APPmovDWORD PTR TIM1_BDTR, 5#APP# 75 "x.c" 1nop# 0 "" 2#NO_APPmoveax, DWORD PTR TIM1_BDTRandah, -68orah, 66movDWORD PTR TIM1_BDTR, eax#APP# 83 "x.c" 1nop# 0 "" 2#NO_APPleaeax, [ebp-10]pusheaxcallmunge_itmovzxedx, WORD PTR [ebp-10]#APP# 85 "x.c" 1nop# 0 "" 2#NO_APPmoveax, edxmovecx, edxshrax, 8shrcx, 10andeax, 3andecx, 1salecx, 10saleax, 8oreax, ecxmovzxecx, dloreax, ecxmovecx, edxshrcx, 11andecx, 1salecx, 11oreax, ecxmovecx, edxshrcx, 12andecx, 1salecx, 12oreax, ecxmovecx, edxshrcx, 13andecx, 1salecx, 13oreax, ecxmovecx, edxshrdx, 15shrcx, 14movzxedx, dlandecx, 1saledx, 15salecx, 14oreax, ecxoreax, edxmovDWORD PTR TIM1_BDTR, eax#APP# 90 "x.c" 1nop# 0 "" 2#NO_APPmovecx, DWORD PTR [ebp-4].cfi_def_cfa 1, 0addesp, 12xoreax, eaxleave.cfi_restore 5leaesp, [ecx-4].cfi_def_cfa 4, 4ret.cfi_endproc.LFE0:.sizemain, .-main.globlTIM1_BDTR.section.tim1_bdtr,"aw".align 4.typeTIM1_BDTR, @object.sizeTIM1_BDTR, 4TIM1_BDTR:.zero4.ident"GCC: (Debian 10.2.1-6) 10.2.1 20210110".section.note.GNU-stack,"",@progbitsThe cases of “write constants” and “read, modify with constants, write” are optimised extremely nicely.Whatever GCC does there for the “write something GCC doesn’t know the value of”, though, I don’t know. Maybe pinskia has an idea (or a newer fixes it, though 15.2.0-16 shows comparable assembly).Andrea, the struct layout is identical to the layout I’m achieving with all the masking, shifting and ORing, so the part between the nops in lines 85 and 90 ought to be just…movDWORD PTR TIM1_BDTR, edx… or, actually, no due to the undefined higher half, it should be…xoreax, eaxmovax, dxmovDWORD PTR TIM1_BDTR, eax… or, actually, that movzx from the…… aaaah, the size of that struct is just 2 bytes, THAT is the problem.
       
 (DIR) Post #B6diKbCqP5FHXQ1wK8 by mirabilos@toot.mirbsd.org
       0 likes, 0 repeats
       
       @kabel42 before I write a combination XSLT and shell script (or maybe just XSLT but that would have trouble with omitted fields in the middle making the representation less nice), do you think you can work with this?x.cvolatile unsigned int TIM1_BDTR_ __asm__("TIM1_BDTR")    __attribute__((__common__))    __attribute__((__section__(".tim1_bdtr")));struct TIM1_BDTR {unsigned int DTG:8;unsigned int LOCK:2;unsigned int OSSI:1;unsigned int OSSR:1;unsigned int BKE:1;unsigned int BKP:1;unsigned int AOE:1;unsigned int MOE:1;unsigned int :16;} __attribute__((__packed__));#define _my_mask(w)((unsigned int)((1ULL << (w)) - 1U))#define _my_rdshift(v,pos,w)(((0U + (v)) >> (pos)) & _my_mask(w))#define _my_wrshift(v,pos,w)(((0U + (v)) & _my_mask(w)) << (pos))#define _my_shiftmask(pos,w)(_my_mask(w) << (pos))#define READ_TIM1_BDTR() __extension__({\register unsigned int tv = TIM1_BDTR_;\(EXPAND_TIM1_BDTR(tv));\})#define EXPAND_TIM1_BDTR(tv) __extension__({\struct TIM1_BDTR rv = {\.DTG = _my_rdshift(tv, 0, 8),\.LOCK = _my_rdshift(tv, 8, 2),\.OSSI = _my_rdshift(tv, 10, 1),\.OSSR = _my_rdshift(tv, 11, 1),\.BKE = _my_rdshift(tv, 12, 1),\.BKP = _my_rdshift(tv, 13, 1),\.AOE = _my_rdshift(tv, 14, 1),\.MOE = _my_rdshift(tv, 15, 1),\};\(rv);\})#define WRITE_TIM1_BDTR(v) do {\TIM1_BDTR_ = PACK_TIM1_BDTR((v), 0U);\} while (/* CONSTCOND */ 0)#define PACK_TIM1_BDTR(v,iv) ((((unsigned int)(iv)) & \(~(_my_shiftmask(0, 8) | _my_shiftmask(8, 2) | _my_shiftmask(10, 1) | _my_shiftmask(11, 1) | _my_shiftmask(12, 1) | _my_shiftmask(13, 1) | _my_shiftmask(14, 1) | _my_shiftmask(15, 1)))) \| _my_wrshift((v).DTG, 0, 8)\| _my_wrshift((v).LOCK, 8, 2)\| _my_wrshift((v).OSSI, 10, 1)\| _my_wrshift((v).OSSR, 11, 1)\| _my_wrshift((v).BKE, 12, 1)\| _my_wrshift((v).BKP, 13, 1)\| _my_wrshift((v).AOE, 14, 1)\| _my_wrshift((v).MOE, 15, 1)\)#define WITH_TIM1_BDTR(block) do {\register unsigned int tv = TIM1_BDTR_;\struct TIM1_BDTR v = EXPAND_TIM1_BDTR(tv);\block\TIM1_BDTR_ = PACK_TIM1_BDTR(v, tv);\} while (/* CONSTCOND */ 0)extern struct TIM1_BDTR munge_it(void);intmain(void){struct TIM1_BDTR r = {0};__asm__ __volatile__("nop" ::: "memory"); /* marker in asm output + compiler barrier */r.DTG = 5;WRITE_TIM1_BDTR(r);__asm__ __volatile__("nop" ::: "memory"); /* marker in asm output + compiler barrier */WITH_TIM1_BDTR(/* assign to v; make sure to NOT use commas in here! */v.LOCK = 2;v.AOE = 1;);__asm__ __volatile__("nop" ::: "memory"); /* marker in asm output + compiler barrier */struct TIM1_BDTR q = munge_it();__asm__ __volatile__("nop" ::: "memory"); /* marker in asm output + compiler barrier */WRITE_TIM1_BDTR(q); /* proof that this has no overhead */__asm__ __volatile__("nop" ::: "memory"); /* marker in asm output + compiler barrier */return (0);}resulting x.s.file"x.c".intel_syntax noprefix.text.section.text.startup,"ax",@progbits.p2align 4.globlmain.typemain, @functionmain:.LFB0:.cfi_startprocleaecx, [esp+4].cfi_def_cfa 1, 0andesp, -16pushDWORD PTR [ecx-4]pushebp.cfi_escape 0x10,0x5,0x2,0x75,0movebp, esppushecx.cfi_escape 0xf,0x3,0x75,0x7c,0x6subesp, 32#APP# 71 "x.c" 1nop# 0 "" 2#NO_APPmovDWORD PTR TIM1_BDTR, 5#APP# 76 "x.c" 1nop# 0 "" 2#NO_APPmoveax, DWORD PTR TIM1_BDTRandah, -68orah, 66movDWORD PTR TIM1_BDTR, eax#APP# 84 "x.c" 1nop# 0 "" 2#NO_APPleaeax, [ebp-12]pusheaxcallmunge_itmoveax, DWORD PTR [ebp-12]#APP# 86 "x.c" 1nop# 0 "" 2#NO_APPmovzxeax, axmovDWORD PTR TIM1_BDTR, eax#APP# 90 "x.c" 1nop# 0 "" 2#NO_APPmovecx, DWORD PTR [ebp-4].cfi_def_cfa 1, 0addesp, 12xoreax, eaxleave.cfi_restore 5leaesp, [ecx-4].cfi_def_cfa 4, 4ret.cfi_endproc.LFE0:.sizemain, .-main.globlTIM1_BDTR.section.tim1_bdtr,"aw".align 4.typeTIM1_BDTR, @object.sizeTIM1_BDTR, 4TIM1_BDTR:.zero4.ident"GCC: (Debian 10.2.1-6) 10.2.1 20210110".section.note.GNU-stack,"",@progbits
       
 (DIR) Post #B6djesS85hOglzPfqS by kabel42@polymaths.social
       0 likes, 0 repeats
       
       @mirabilos viel ist bool oder enum oder unsigned
       
 (DIR) Post #B6djesmgrFqNnl25tQ by mirabilos@toot.mirbsd.org
       0 likes, 0 repeats
       
       @kabel42 na bool ist ja unsigned und enum in bitfeldern auch normalerweise…
       
 (DIR) Post #B6djny9WGhd73b2m8m by mirabilos@toot.mirbsd.org
       0 likes, 0 repeats
       
       @kabel42 hmm, depending on the compiler it might need -O2 instead of -Os, I tested with the former, and i386 GCC on bullseye/amd64 produces worse (and larger) code with -Os, though they might have fixed that in the meantime, and only for those parts where the struct is copied around, so if you stick to constants or the WITH construct, it should be fine
       
 (DIR) Post #B6ejipKFqy03OJZaIy by kabel42@polymaths.social
       0 likes, 0 repeats
       
       @mirabilos I think this can be simplified to#include <stdint.h>typedef union {struct {uint32_t DTG :8;uint32_t LOCK :2;uint32_t OSSI :1;uint32_t OSSR :1;uint32_t BKE :1;uint32_t BKP :1;uint32_t AOE :1;uint32_t MOE :1;uint32_t :16;};uint32_t raw;} tim1_bdtr_t;volatile tim1_bdtr_t TIM1_BDTR __attribute__((section(".tim1_bdtr")));#define WITH_TIM1_BDTR(block) do {\register tim1_bdtr_t tv = {.raw = TIM1_BDTR.raw};\block\TIM1_BDTR.raw = tv.raw;\} while (/* CONSTCOND */ 0)int main(void) {    WITH_TIM1_BDTR(tv.DTG = 5;);}which gives.file"union.c".text.section.text.startup,"ax",@progbits.globlmain.typemain, @functionmain:.LFB0:.cfi_startprocmovlTIM1_BDTR(%rip), %eaxmovb$5, %almovl%eax, TIM1_BDTR(%rip)xorl%eax, %eaxret.cfi_endproc.LFE0:.sizemain, .-main.globlTIM1_BDTR.section.tim1_bdtr,"aw".align 4.typeTIM1_BDTR, @object.sizeTIM1_BDTR, 4TIM1_BDTR:.zero4.ident"GCC: (GNU) 16.1.1 20260430".section.note.GNU-stack,"",@progbitsor am I missing some corner case?
       
 (DIR) Post #B6ejiqJw9dL8TcQqRs by mirabilos@toot.mirbsd.org
       0 likes, 0 repeats
       
       @kabel42 yes: the layout of the struct is not guaranteed to match; my code optimises away if it does but handles properly if it doesn’t
       
 (DIR) Post #B6ejnGWUfyBqtuPk3s by kabel42@polymaths.social
       0 likes, 0 repeats
       
       @mirabilos i'll need a bit more coffee to understand this :)
       
 (DIR) Post #B6ejnGm5jyfPgHiCNE by mirabilos@toot.mirbsd.org
       0 likes, 0 repeats
       
       @kabel42 coffee is times a good idea *picks up cat from atop himself and gets up*