Manipulera enstaka registerbitar i GCC.

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
Användarvisningsbild
Icecap
Inlägg: 26659
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Inlägg av Icecap »

Jag tror att sodjan avser att det är mycket få processorer som kan adressera bits direkt. PIC t.ex. kan ju setta/resetta enstaka bits MEN det görs via en R(ead)-M(odify)-W(rite) funktion och det är så nästa alla µC gör.

EDIT: Men.. sodjan!!! du kan väl inte skriva när JAG håller på att svara!!! ;-)
Användarvisningsbild
ErikJ
Inlägg: 36
Blev medlem: 17 september 2004, 16:06:53
Ort: Malung

Inlägg av ErikJ »

>>Tydlighet. Jag skulle aldrig utgå från att något blir det man tror det blir.

Jag har alltid tänkt att ": 1" bestämmer hur stor den "portionen" av bitfältet skall vara, och att kalla en 1-bitars variabel för "char" eller något annat känns tokigt. Sedan summeras det totala antalet bitar i fältet ihop, och är det fler än 8, tar bitfältet upp 2 byte. Är det fler än 16 bitar tar det upp 3 byte. Osv etc usw.

Dock kunde luft smyga sig in mellan "portionerna" om de skulle ha sträckt sig över gränsen mellan två byte på en 8-bitars maskin eller över gränsen mellan två DWORD på en 32-bitars maskin. Eller hur det nu var. Det här diskuterades i en tråd för ett år sedan eller nåt.

(uint8, int8, uint16, uint24, uint32 osv använder jag också istället för char, int, kortlång, långkort, långlång, lång-långilång och allt vad de heter. Det är mycket enklare att komma ihåg.)

Här står det bra beskrivet om bitfält:
http://publications.gbdirect.co.uk/c_bo ... ields.html


>> "char" ska defintivt vara där. Ta snarare bort "unsigned" eftersom du ändå inte använder byten i sin helhet.

Unsigned beskriver inte byten som helhet, utan "1-bits-portionen".
Nu råkar det vara unsigned som standard på bit-fältsportioner, så unsigned kan man ta bort. Men jag citerar AndLi: "Tydlighet. Jag skulle aldrig utgå från att något blir det man tror det blir."

Jag char-vägrar :D.

Skriver du däremot inget ": siffra", så blir en char 8-bitar, en int 16-bitar osv beroende på arkitektur och då pratar vi om "portionerna" INUTI bit-fältet. Se ovanstående länk.

Storleken på hela bit-fältet går såvitt jag vet inte att specificera.

Icecap och sodjan: Jag har för mig att jag har kollat upp "disassembly listingen" och sett att bitfältstilldelning översätts till BCF/BSF i MPLAB C18.
Men ändrar man i output-latchen (LATx på PIC18, eller PORTx på AVR) så är det väl inga problem?


(Med reservation för eventuella fel);)
Användarvisningsbild
Icecap
Inlägg: 26659
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Inlägg av Icecap »

"Men ändrar man i output-latchen..."
Nej, det är nog därför att de finns faktisk.
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

> Icecap och sodjan: Jag har för mig att jag har kollat upp "disassembly
> listingen" och sett att bitfältstilldelning översätts till BCF/BSF i MPLAB C18.

Ja, det var här jag funderade lite på de olika lösningarna som har
presenterats här för AVR. Hurdan kod genererar de ?

Det spelar det en väldig roll om aktuell bit som ska manipuleras ska
bestämmas vid "build-time" (d.v.s vid assembleringen eller kompileringen),
eller om det ska bestämmas dynamiskt vid run-time.

Jag tolkade den ursprungliga frågan som att det gällde statiska bitar
som är givna vid run-time, eftersom det bl.a jämfördes med PIC's
bit set/clear instruktioner, där ju aktuell bit inte är dynamiskt utan
fast inbyggt i instruktionen, så att säga.

Om man vill bestämma aktuell bit vid run-time, så blir det avsevärt mer
komplext (både för AVR och PIC, så vitt jag förstår). Med avsevärt mer
komplext, menar jag att det inte räcker med *1* instruktion... :-)

Så det första att klara ut är vilket det gäller, statiska eller dynamiska bitar ?

(Sen är det en annan sak att AVR's bit set/clear instruktioner bara fungerar
på ett subset av registren...)
Användarvisningsbild
ErikJ
Inlägg: 36
Blev medlem: 17 september 2004, 16:06:53
Ort: Malung

Inlägg av ErikJ »

Hmm

Jag tar tillbaks det där med att casta, för det går ju inte att casta till vänster om tilldelnings-tecknet. :doh:
Det fungerar bara om man skapar en variabel direkt med bitfältstypen och manipulerar bitarna, men inte om man försöker ge sig på en variabel som är en unsigned char från början. :humm:

sodjan: Jovisst är det skillnad.
Användarvisningsbild
speakman
Inlägg: 4838
Blev medlem: 18 augusti 2004, 23:03:32
Ort: Ånge

Inlägg av speakman »

Jag märker att det är skillnad på hur man ser på bitfields. Ett exempel:

Kod: Markera allt

struct bits {
    unsigned char first:2;
    unsigned char second:6;
}
Här ser jag båda fälten som en och samma unsigned char fast delat i två portitioner. Jag ser inte varje bitfält som en enskild unsigned char. Skulle det t.ex. gå att byta ut unsigned char second:2 mot signed int second:2 utan att den totala structstorleken ökar?

Jag har iallafall aldrig tänkt på det så, och det verkar råda oenighet även på nätet. Men det finns en annan drawback som Wikipedia pekar på:
However, bit members in structs have practical drawbacks. First, the ordering of bits in memory varies from compiler to compiler. [..]

Det kan vara vettigt att ta i åtanke när man nyttjar bitfields, särskilt när det går mot SFR:er där bitarna måste sitta på rätt plats.
Användarvisningsbild
speakman
Inlägg: 4838
Blev medlem: 18 augusti 2004, 23:03:32
Ort: Ånge

Inlägg av speakman »

sodjan: På en 8051:a blir det en instruktion oavsett om man ska sätta eller cleara. På PIC/AVR måste det finnas kod som först avgör om den ska sättas eller clears först innan det kan utföras.
Användarvisningsbild
ErikJ
Inlägg: 36
Blev medlem: 17 september 2004, 16:06:53
Ort: Malung

Inlägg av ErikJ »

Jag har visst rört till det lite och blandat begreppen lite. Hela strukturen är fortfarande en "struct". "Portionerna", som jag kallade dem, kallas "bit field".

speakman:
Här ser jag båda fälten som en och samma unsigned char fast delat i två portitioner. Jag ser inte varje bitfält som en enskild unsigned char. Skulle det t.ex. gå att byta ut unsigned char second:2 mot signed int second:2 utan att den totala structstorleken ökar?
Jag tror att det blir samma sak (förutom att du blandade ihop siffrorna ur din kod). Fast med signed så kan 2 bitar ha värdena -2, -1, 0 & 1. Det måste man ju tänka på (tror jag), om man ska jämföra, tex (struct bits.second == 3).

Ordningen kan man inte heller lita 100 % på, som du påpekade.
Användarvisningsbild
speakman
Inlägg: 4838
Blev medlem: 18 augusti 2004, 23:03:32
Ort: Ånge

Inlägg av speakman »

Gjorde lite tester på gcc för i386 och där blev structen ovan 1 byte med "unsigned char" och 4 byte med bara "unsigned". M.a.o. tror jag mer min teori stämmer, och att man bör definera vad man vill att det ska resultera i.
Användarvisningsbild
ErikJ
Inlägg: 36
Blev medlem: 17 september 2004, 16:06:53
Ort: Malung

Inlägg av ErikJ »

Ojdå, där ser man.
Användarvisningsbild
ErikJ
Inlägg: 36
Blev medlem: 17 september 2004, 16:06:53
Ort: Malung

Inlägg av ErikJ »

Jag gjorde också lite tester i Dev-C++ för win-32 som använder gcc och jag kom fram till att "unsigned" är "unsigned int" automatiskt. Sedan bestämmer den största "datatypen" vilken "storage unit" som skall användas. Dvs: Har du skrivit int någonstans i structen så allokeras 32-bitars-block av minne, och bitfält kan inte lappa över gränsen till nästa 32-bitars block, utan flyttas fram till nästa blocks början. Har du enbart skrivit char så allokeras bytes allt eftersom, men bitfälten kan inte gå över gränsen till nästa byte, utan flyttas fram till nästa byte.

Ett exempel:
Antag att vi vill ha 7 st 5-bitars-variabler. Totalt 35 bitar alltså. Det skulle kunna packas i 5 bytes, men nu går inte det.

Tre olika metoder:

Kod: Markera allt

typedef struct
{
  unsigned int a : 5;
  unsigned int b : 5;
  unsigned int c : 5;
  unsigned int d : 5;
  unsigned int e : 5;
  unsigned int f : 5;
  unsigned int g : 5;
} T_INT_KVINTAR;

Tager upp 8 bytes = 2 hela 32-bitars ints
allokering:

[aaaaaBBB|BBcccccD|DDDDeeee|eFFFFF--]    [ggggg---|--------|--------|--------]




typedef struct
{
  unsigned char a : 5;
  unsigned char b : 5;
  unsigned char c : 5;
  unsigned char d : 5;
  unsigned char e : 5;
  unsigned char f : 5;
  unsigned char g : 5;
} T_CHAR_KVINTAR;

Tager upp 7 bytes = 7 hela 8-bitars chars
allokering:

[aaaaa---][bbbbb---][ccccc---][ddddd---]    [eeeee---][fffff---][ggggg---]




typedef struct
{
  unsigned short a : 5;
  unsigned short b : 5;
  unsigned short c : 5;
  unsigned short d : 5;
  unsigned short e : 5;
  unsigned short f : 5;
  unsigned short g : 5;
} T_SHORT_KVINTAR;


Tager upp 6 bytes = 3 hela 16-bitars shorts
allokering:

[aaaaaBBB|BBccccc-][DDDDDeee|eeFFFFF-]    [ggggg---|--------]
(Observera att LSB eventuellt är längst till vänster i allokeringkartorna)

Slutsats: Det lönar sig att fundera vilken "storage unit" som structen skall ha. I det här fallet var short bäst.
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

> På en 8051:a blir det en instruktion oavsett om man ska sätta eller cleara.

Det enda jag kan hitta är SETB resp CLR, d.v.s två olika instruktioner. man
måste så vitt jag förstår välja om man ska göra SETB eller CLR. Eller finns
det något annan instruktion som dynamiskt kan sätta eller cleara en bit ?

> På PIC/AVR måste det finnas kod som först avgör om den ska sättas
> eller clears först innan det kan utföras.

Jag ser inte hur det är någon skillnad på 8051, förrutom att visa register
har sina "bitar" mappade till egna adresser, men det gör inte att man
dynamiskt kan välja om man ska sätta eller cleara en bit, eller gör
det det ?

Spelar ingen större roll kanske, men processorarkitekturer är intressant... :-)
Användarvisningsbild
speakman
Inlägg: 4838
Blev medlem: 18 augusti 2004, 23:03:32
Ort: Ånge

Inlägg av speakman »

Ja nog är det intressant, och det är alltid kul att reda ut saker. Jag får väl reservera mig för att jag kan ha fattat något fel, men det var väääldigt länge sedan jag satt med 8051an. Men som jag fattade det var vissa bitar adresserbara precis som ett vanligt 8-bitars register, så man med MOV kunde både sätta och cleara den. Men det kan ju mycket väl ha varit fulhack i kompilatorn som fick det att verka så också. Nånstans har jag ändå för mig att jag läst om det, men jag litar tyvärr inte allt för mycket på mitt minne.

EDIT: Hur tolkar du det här dokumentet under 1.4 Direct and Indirect Address Area, och sedan bank 2. Bit Addressable Area.

Jag är osäker hur det menas, och hittar inte mer om saken längre ner heller.
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

OK, då är jag med.

Det jag hittar om MOV är "moves" mellan "Carry" och en "directly
addressable bit".

Och genom att Carry ju kan vara 0 eller 1, så kan alltså samma en och
instruktion på det sättet antingen sätta eller cleara en "directly addressable
bit" dynamiskt på det sättet. Man kan alltså t.ex göra en aritmetiskt
operation som sätter/clearar Carry och direkt efter sätta valfri "directly
addressable bit" till samma som Carry utan vidare tester aller branch'es.

Det enda är väl att man bara kan göra detta mot de register som har
"directly addressable bits", vilket är vissa RAM adresser (20 - 2F) samt
vissa kontrolregister (vart åttonde, de vars adress slutar på 0 eller 8 ).

Och "bit-adresserna" är en egen adressrymd, de kan bara användas där
det är specat "bit" i instruktionen, inte som en adress vilken som helst.

> Hur tolkar du det här dokumentet under 1.4 Direct and Indirect Address Area,...

Precis som det står... :-)
Det som är lite förvillande är att om man anger en viss adress som en
"direkt" adress så hamnar man på et ställe, men om man lägger samma
adress i ett register och gör en indirekt adresserig via det registret så
hamnar man på ett annat ställe (i en annan adresstymd). I alla fall
för vissa modeller av processorer, se figure 6. 80H - FFH är dubblerat.

> och sedan bank 2. Bit Addressable Area.

Ja, det är ju de register i RAM som även har "bit-adresser" för de instruktioner
som har en "bit" variant som SETB/CLR och bit-varienten av MOV.
Byte-adresser och bit-adresser är alltså två helt olika adressrymder.

Så här spontant känns arkitekturen lite rörig... :-)
Användarvisningsbild
speakman
Inlägg: 4838
Blev medlem: 18 augusti 2004, 23:03:32
Ort: Ånge

Inlägg av speakman »

> Så här spontant känns arkitekturen lite rörig... Smile

Den är gaaaaammal också... :D
Skriv svar