Flags in Boolean Record packen - geht das?

Rund um die LCL und andere Komponenten

Flags in Boolean Record packen - geht das?

Beitragvon Timm Thaler » 5. Mär 2018, 10:53 Flags in Boolean Record packen - geht das?

Wenn man in Pascal eine Variable Boolean anlegt, belegt die mindestens ein Byte, obwohl sie nur zwei Zustände hat.

Ich speichere üblicherweise Statusflags auf dem AVR platzsparend in einer Variable vom Typ uint8, so dass jedes Flag ein Bit belegt, bekomme also 8 Booleans in ein Byte. Das sieht dann etwa so aus:

Code: Alles auswählen
const
  E_rtc       = 1 shl 0// Flag Fehler RTC
  E_twi       = 1 shl 1// Flag Fehler TWI
  E_eeprom    = 1 shl 2// Flag Fehler EEPROM
  E_sens      = 1 shl 7// Flag Fehler Sensor
var
  error : uint8;
 
  error := error or E_sens;  // Fehler Sensor setzen
  error := error and not E_sens;  // Fehler Sensor löschen
  if (error and E_rtc) = 0 then... // kein Fehler RTC
  if (error and E_rtc) <> 0 then... // Fehler RTC
  error := 0// Fehler löschen
 

Alternativ kann man auch statt der Bitmaske die Bitstelle nehmen, man darf es halt nicht mischen:

Code: Alles auswählen
const
  e_rtc       = 0// Flag Fehler RTC
  e_twi       = 1// Flag Fehler TWI
  e_eeprom    = 2// Flag Fehler EEPROM
  e_sens      = 7// Flag Fehler Sensor
var
  error : uint8;
 
  error := error or (1 << e_sens)// Fehler Sensor setzen
  error := error and not (1 << e_sens)// Fehler Sensor löschen
  if (error and (1 << e_rtc)) = 0 then... // kein Fehler RTC
  if (error and (1 << e_rtc)) <> 0 then... // Fehler RTC
  error := 0// Fehler löschen
 

Ist recht viel Schreibkram, da habe ich mir gedacht, es wäre doch schön, wenn es sowas gäbe:

Code: Alles auswählen
errtype = record
  rtc  : boolean;  // Flag Fehler RTC
  twi  : boolean;  // Flag Fehler TWI
  eeprom  : boolean;  // Flag Fehler EEPROM
  sens  : boolean;  // Flag Fehler Sensor
var
  error : errtype;
 

Wobei jedes Element in error nur ein Bit belegt.

Dann könnte man das so ansprechen:
Code: Alles auswählen
  error.sens := true// Fehler Sensor setzen
  error.sens := false// Fehler Sensor löschen
  if not error.rtc then... // kein Fehler RTC
  if error.rtc then... // Fehler RTC
  error := 0// alle Fehler löschen => naja, das wäre ein Bonus
 

Ich weiss, dass es solche gepackten Booleans unter Ada gibt, geht das in Pascal vielleicht auch? Und wird das für die Embedded AVR umgesetzt?
Timm Thaler
 
Beiträge: 622
Registriert: 20. Mär 2016, 22:14
OS, Lazarus, FPC: Win7-64bit Laz1.9.0 FPC3.1.1 für Win, RPi, AVR embedded | 
CPU-Target: Raspberry Pi 3
Nach oben

Beitragvon m.fuchs » 5. Mär 2018, 11:07 Re: Flags in Boolean Record packen - geht das?

Eigentlich kann kannst du das per Set eines Enums machen.
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de
m.fuchs
 
Beiträge: 1959
Registriert: 22. Sep 2006, 18:32
Wohnort: Berlin
OS, Lazarus, FPC: Winux (L 1.8.4, FPC 3.0.4) | 
CPU-Target: x86, x64, arm
Nach oben

Beitragvon Mathias » 5. Mär 2018, 12:29 Re: Flags in Boolean Record packen - geht das?

Hast du dies mal angeguckt ?
Code: Alles auswählen
var
  LEDPort: bitpacked array [0..7] of boolean absolute PORTD;
 
begin
  LEDPort[0] := True;
  LEDPort[1] := True;
  LEDPort[2] := False;
  LEDPort[3] := False;
Zuletzt geändert von Mathias am 5. Mär 2018, 18:13, insgesamt 2-mal geändert.
Mit Lazarus sehe ich gün
Mit Java und C/C++ sehe ich rot
Mathias
 
Beiträge: 4107
Registriert: 2. Jan 2014, 17:21
Wohnort: Schweiz
OS, Lazarus, FPC: Linux (die neusten Trunc) | 
CPU-Target: 64Bit
Nach oben

Beitragvon marcov » 5. Mär 2018, 12:49 Re: Flags in Boolean Record packen - geht das?

Siehe auch http://wiki.freepascal.org/Bit_manipulation zb

Code: Alles auswählen
TByteBits = bitpacked record
  Bit0, Bit1, Bit2, Bit3, Bit4, Bit5, Bit6, Bit7: Boolean;
end;
 
TByteEx = packed record
  case Integer of
    0: (ByteAccess: Byte);
    1: (BitAccess: TByteBits);
end;
 
TSomeBitLevelStructure = bitpacked record
  OneBit: 0..1;
  TwoBits: 0..3;
  FourBits: 0..15;
  EightBits: 0..255
end;
marcov
 
Beiträge: 1030
Registriert: 5. Aug 2008, 08:37
Wohnort: Eindhoven (Niederlande)
OS, Lazarus, FPC: Windows ,Linux,FreeBSD,Dos (L trunk FPC trunk) | 
CPU-Target: 32/64,PPC(+64), ARM
Nach oben

Beitragvon Mathias » 5. Mär 2018, 18:21 Re: Flags in Boolean Record packen - geht das?

bitpacked ist eine praktische Funktion, siehe Mini-Code.
Code: Alles auswählen
function ByteToBin(b:Byte):String;
var
  ba: bitpacked array[0..7] of Boolean absolute b;
  i:Integer;
begin
  SetLength(Result, 8);
  for i := 0 to 7 do begin
    Result[i + 1] := char(48 + byte(ba[i]));
  end;
end;
 
procedure TForm1.Button1Click(Sender: TObject);
begin
  Caption:=ByteToBin(%11110011);
end;
Mit Lazarus sehe ich gün
Mit Java und C/C++ sehe ich rot
Mathias
 
Beiträge: 4107
Registriert: 2. Jan 2014, 17:21
Wohnort: Schweiz
OS, Lazarus, FPC: Linux (die neusten Trunc) | 
CPU-Target: 64Bit
Nach oben

Beitragvon Timm Thaler » 12. Mär 2018, 01:50 Re: Flags in Boolean Record packen - geht das?

Das sieht doch ganz gut aus:

Code: Alles auswählen
type
  terror = bitpacked record  // Errorflags
    case byte of
      0 : (rtc,  // Flag Fehler RTC
           twi,  // Flag Fehler RTC
           eeprom,  // Flag Fehler EEPROM
           bit3,
           bit4,
           bit5,
           bit6,
           sens : boolean)// Flag Fehler Sensor
      1 : (all : uint8);
  end;
 
var
  error : terror;
 
  error.all := 0;
  error.rtc := true;
  error.rtc := false;
  if error.rtc then ...
  if not error.rtc then ...
Timm Thaler
 
Beiträge: 622
Registriert: 20. Mär 2016, 22:14
OS, Lazarus, FPC: Win7-64bit Laz1.9.0 FPC3.1.1 für Win, RPi, AVR embedded | 
CPU-Target: Raspberry Pi 3
Nach oben

Beitragvon Timm Thaler » 12. Mär 2018, 12:23 Re: Flags in Boolean Record packen - geht das?

Ich nehms zurück: Bei globaler Deklaration der Flag-Variablen wird das recht optimal umgesetzt. Aber bei Zuweisung über eine Prozedur

Code: Alles auswählen
type
  tSadc = bitpacked record  // Statusflags ADC
    case byte of
      0 : (bit0, bit1, bit2, bit3, gnd, open, noack, err : boolean);
      1 : (all : uint8);
  end;
 
var
  Sstat : array [1..Clen] of tSadc;  // Status Flags
 
write_status(Sstat[nr]);
 
procedure write_status(stat : tSadc);
begin
    if stat.noack then begin
      serial_string(@text_noack);
    end else if stat.open then begin
      serial_string(@text_opn)...
 


macht der Compiler leider sowas draus:

Code: Alles auswählen
# [363] if stat.noack then begin
   mov   r18,r2
   lsr   r18
   lsr   r18
   lsr   r18
   lsr   r18
   lsr   r18
   lsr   r18
   sbrs   r18,0
   rjmp   .Lj152
.Lj151:


Häh? Warum wird hier nicht gleich mit sbrs an der richtigen Bitstelle geprüft?
Timm Thaler
 
Beiträge: 622
Registriert: 20. Mär 2016, 22:14
OS, Lazarus, FPC: Win7-64bit Laz1.9.0 FPC3.1.1 für Win, RPi, AVR embedded | 
CPU-Target: Raspberry Pi 3
Nach oben

Beitragvon siro » 12. Mär 2018, 16:01 Re: Flags in Boolean Record packen - geht das?

Das gefällt mir....
er schiebt das abzufragende Bit Stück für Stück ins LSB um dann mit dem gleichen Befehl das Bit abzufragen,
mit dem er es auch ohne zu schieben abfragen kann... :mrgreen:

Compiler erzeugen nunmal nicht immer optimalen Code.
Die wenigsten schauen sich aber heutzutage den erzeugten Assemblercode noch an,
da sind wir wohl eher eine aussterbende Rasse....

Hast Du mal einen anderen Optimierungsslevel versucht:
https://www.freepascal.org/docs-html/prog/progse49.html

Siro
Grüße von Siro
Bevor ich "C" ertragen muß, nehm ich lieber Lazarus...
siro
 
Beiträge: 296
Registriert: 23. Aug 2016, 13:25
Wohnort: Berlin
OS, Lazarus, FPC: Windows 7 Windows 8.1 Windows 10 | 
CPU-Target: 64Bit
Nach oben

Beitragvon Timm Thaler » 12. Mär 2018, 17:00 Re: Flags in Boolean Record packen - geht das?

siro hat geschrieben:Compiler erzeugen nunmal nicht immer optimalen Code.


Es ist nur schade, dass die umständliche Schreibweise (Sstat[k] and (1 shl 6) = 0 wunderbar zu sbrc r18,6 kompiliert wird, die elegantere Schreibweise mit bitpacked record das aber nicht nutzt.

siro hat geschrieben:Die wenigsten schauen sich aber heutzutage den erzeugten Assemblercode noch an


Plötzlich 300 Byte Flashbedarf mehr "aus dem Nichts", ohne zusätzliche Funktionen implementiert zu haben fällt halt auf. Und da habe ich nur einen Teil meiner Flag-Abfragen (Test auf Error-Flags) umgestellt, der Rest arbeitet noch mit Bitmasken und Vergleich. Wenn ich die alle umsetze wird es wahrscheinlich 1k mehr Speicherbedarf durch die lsr ohne Zugewinn an Funktionalität.

siro hat geschrieben:Hast Du mal einen anderen Optimierungsslevel versucht:


Ich optimiere für AVR immer auf -O3, -O4 möche ich für ein Projekt bei dem es auf Zuverlässigkeit ankommt nicht machen müssen.
Timm Thaler
 
Beiträge: 622
Registriert: 20. Mär 2016, 22:14
OS, Lazarus, FPC: Win7-64bit Laz1.9.0 FPC3.1.1 für Win, RPi, AVR embedded | 
CPU-Target: Raspberry Pi 3
Nach oben

Beitragvon Mathias » 12. Mär 2018, 18:23 Re: Flags in Boolean Record packen - geht das?

Es ist nur schade, dass die umständliche Schreibweise (Sstat[k] and (1 shl 6) = 0 wunderbar zu sbrc r18,6 kompiliert wird, die elegantere Schreibweise mit bitpacked record das aber nicht nutzt.
Als ich dazumal das Tutorial erstellt, hatten alle Pin-Zugriffe den gleichen Speicherbedarf.

http://wiki.freepascal.org/AVR_Embedded_Tutorial_-_Simple_GPIO_on_and_off_output/de#Pin_direkt_ansprechen

Oder hat der Compiler Mühe mit dem case im record ?
Mit Lazarus sehe ich gün
Mit Java und C/C++ sehe ich rot
Mathias
 
Beiträge: 4107
Registriert: 2. Jan 2014, 17:21
Wohnort: Schweiz
OS, Lazarus, FPC: Linux (die neusten Trunc) | 
CPU-Target: 64Bit
Nach oben

Beitragvon Timm Thaler » 12. Mär 2018, 19:46 Re: Flags in Boolean Record packen - geht das?

Mathias hat geschrieben:Als ich dazumal das Tutorial erstellt, hatten alle Pin-Zugriffe den gleichen Speicherbedarf.


Das sind auch Portzugriffe mit sbi und cbi. Da kann der Compiler nichts sinnvoll shiften.

Mathias hat geschrieben:Oder hat der Compiler Mühe mit dem case im record ?


Nope, keine Änderung, wenn bitpacked record ohne case angelegt wird.
Timm Thaler
 
Beiträge: 622
Registriert: 20. Mär 2016, 22:14
OS, Lazarus, FPC: Win7-64bit Laz1.9.0 FPC3.1.1 für Win, RPi, AVR embedded | 
CPU-Target: Raspberry Pi 3
Nach oben

Beitragvon Timm Thaler » 13. Mär 2018, 02:31 Re: Flags in Boolean Record packen - geht das?

Ist optimiert:
Code: Alles auswählen
# [81] if ftest.bit6 then begin
   lds   r18,(U_sHVS_DEFINE_ss_FTEST)
   sbrs   r18,6
   rjmp   .Lj19
.Lj18:
# [82] if not ftest.bit3 then begin
   lds   r18,(U_sHVS_DEFINE_ss_FTEST)
   sbrc   r18,3
   rjmp   .Lj21
.Lj22:
 


Dieser Florian ist echt fit. https://bugs.freepascal.org/view.php?id=33417
Timm Thaler
 
Beiträge: 622
Registriert: 20. Mär 2016, 22:14
OS, Lazarus, FPC: Win7-64bit Laz1.9.0 FPC3.1.1 für Win, RPi, AVR embedded | 
CPU-Target: Raspberry Pi 3
Nach oben

Beitragvon Socke » 13. Mär 2018, 09:03 Re: Flags in Boolean Record packen - geht das?

Timm Thaler hat geschrieben:Dieser Florian ist echt fit.

Dieser Florian entwickelt auch schon seit 1993 am Free Pascal Compiler :D
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein
Socke
 
Beiträge: 2512
Registriert: 22. Jul 2008, 18:27
Wohnort: Köln
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 8.1/Debian GNU/Linux/Raspbian/openSUSE | 
CPU-Target: 32bit x86 armhf
Nach oben

Beitragvon Timm Thaler » 13. Mär 2018, 12:35 Re: Flags in Boolean Record packen - geht das?

Ach, der Florian ist das.

Ich glaub es ist noch ein Bug im if not Vergleich auf einzelne Bits, ich bin gerade dabei das einzugrenzen.
Timm Thaler
 
Beiträge: 622
Registriert: 20. Mär 2016, 22:14
OS, Lazarus, FPC: Win7-64bit Laz1.9.0 FPC3.1.1 für Win, RPi, AVR embedded | 
CPU-Target: Raspberry Pi 3
Nach oben

Beitragvon Timm Thaler » 13. Mär 2018, 16:55 Re: Flags in Boolean Record packen - geht das?

Also da ist momentan noch ein Bug, wenn man mit if not ... then auf false prüft und der record by value an eine Prozedur übergeben wurde. Dann werden die Anweisungen nach then ignoriert. Bei Prüfung auf true oder bei Übergabe by reference funktioniert es.

(https://bugs.freepascal.org/view.php?id=33423)

Boah, auf so komische Fehler muss man erstmal kommen. Und ich wunder mich, warum meine Heizung nicht geht... ;-)
Timm Thaler
 
Beiträge: 622
Registriert: 20. Mär 2016, 22:14
OS, Lazarus, FPC: Win7-64bit Laz1.9.0 FPC3.1.1 für Win, RPi, AVR embedded | 
CPU-Target: Raspberry Pi 3
Nach oben

» Weitere Beiträge siehe nächste Seite »
Nächste

Zurück zu Komponenten und Packages



Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 2 Gäste

cron
porpoises-institution
accuracy-worried