AVR microcontroller unit format lazarus / 64-FPC development ---------------------------------------------------------------------- ccrause · 2017-11-03 19:57 I am busy regenerating the port/register and bit field definitions for AVR microcontrollers.  While I'm at it I thought of reformatting the units so that bit definitions appear directly after the relevant register, similar to GCC style.  Since register locations are specified as variables at absolute addresses and bit definitions are specified as constants this leads to mixing of var/const definitions which kind of seem un-Pascal like. Is there any reasonable objection against this style? Example:Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i var  TCNT0: byte absolute $46;  // Timer/Counter0  OCR0A: byte absolute $47;  // Timer/Counter0 Output Compare Register  OCR0B: byte absolute $48;  // Timer/Counter0 Output Compare Register  GPIOR1: byte absolute $4A;  // General Purpose I/O Register 1  GPIOR2: byte absolute $4B;  // General Purpose I/O Register 2  SPCR: byte absolute $4C;  // SPI Control Registerconst  SPR0 = $00;  // SPI Clock Rate Selects  SPR1 = $01;  // SPI Clock Rate Selects  CPHA = $02;  // Clock Phase  CPOL = $03;  // Clock polarity  MSTR = $04;  // Master/Slave Select  DORD = $05;  // Data Order  SPE = $06;  // SPI Enable  SPIE = $07;  // SPI Interrupt Enable var  SPSR: byte absolute $4D;  // SPI Status Registerconst  SPI2X = $00;  // Double SPI Speed Bit  WCOL = $06;  // Write Collision Flag  SPIF = $07;  // SPI Interrupt Flag ---------------------------------------------------------------------- Leledumbo · 2017-11-04 08:16 I don't see any un-Pascalism there, looks OK to me. ---------------------------------------------------------------------- Thaddy · 2017-11-04 09:47 No, not at all. I approach it basically in the same way: declaring with absolute. But if you want to get rid of the var, you can also do: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i {$push}{$writebleconst on} // or {$J+}const  TCNT0: byte absolute $46;  // Timer/Counter0  OCR0A: byte absolute $47;  // Timer/Counter0 Output Compare Register  OCR0B: byte absolute $48;  // Timer/Counter0 Output Compare Register  GPIOR1: byte absolute $4A;  // General Purpose I/O Register 1  GPIOR2: byte absolute $4B;  // General Purpose I/O Register 2  SPCR: byte absolute $4C;  // SPI Control Register  SPR0 = $00;  // SPI Clock Rate Selects  SPR1 = $01;  // SPI Clock Rate Selects  CPHA = $02;  // Clock Phase  CPOL = $03;  // Clock polarity  MSTR = $04;  // Master/Slave Select  DORD = $05;  // Data Order  SPE = $06;  // SPI Enable  SPIE = $07;  // SPI Interrupt Enable  SPSR: byte absolute $4D;  // SPI Status Register  SPI2X = $00;  // Double SPI Speed Bit  WCOL = $06;  // Write Collision Flag  SPIF = $07;  // SPI Interrupt Flag{$pop} Maybe you can also group the vars that are now typed consts and have only those between the writable consts stuff. {$J+} is a local directive. Don't forget push/pop to restore the original flag. Something like: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i const  SPR0 = $00;  // SPI Clock Rate Selects  SPR1 = $01;  // SPI Clock Rate Selects  CPHA = $02;  // Clock Phase  CPOL = $03;  // Clock polarity  MSTR = $04;  // Master/Slave Select  DORD = $05;  // Data Order  SPE = $06;  // SPI Enable  SPIE = $07;  // SPI Interrupt Enable  SPI2X = $00;  // Double SPI Speed Bit  WCOL = $06;  // Write Collision Flag  SPIF = $07;  // SPI Interrupt Flag{$push}{$j+}  TCNT0: byte absolute $46;  // Timer/Counter0  OCR0A: byte absolute $47;  // Timer/Counter0 Output Compare Register  OCR0B: byte absolute $48;  // Timer/Counter0 Output Compare Register  GPIOR1: byte absolute $4A;  // General Purpose I/O Register 1  GPIOR2: byte absolute $4B;  // General Purpose I/O Register 2  SPCR: byte absolute $4C;  // SPI Control Register  SPSR: byte absolute $4D;  // SPI Status Register{$pop}That makes only the typed consts writable for just that block and other type consts will remain not writable. (or writable if $J+ was already active. That's where the push pop comes in.) But basically your code is fine. ---------------------------------------------------------------------- kupferstecher · 2017-11-04 10:22 Quote from: ccrause on November 03, 2017, 08:57:41 pmIs there any reasonable objection against this style?In my feeling its better to seperate the register and the bit definitions. With this its easier to get an overview of the available registers and compare them to the datasheet. Mixing with the bit-definitions makes it more cryptic in my opinion, especially for beginnners. A way to keep it structured probably would be to still group registers within their peripherial and list bit definitions below. E.g. all UART-registers, then all UART-bit definitions. But that means quite some efforts if its not ready in the source. Is there a technical reason you want to do it that way? Probably extracting the definitions from the GCC-header? I checked the assembler header, there the register and bit definitions are seperated. Short extract: Code: [Select]; ***** I/O REGISTER DEFINITIONS ***************************************** ; NOTE: ; Definitions marked "MEMORY MAPPED"are extended I/O ports ; and cannot be used with IN/OUT instructions .equ SREG = 0x3f .equ SPL = 0x3d .equ SPH = 0x3e .equ OCR0 = 0x3c .equ GICR = 0x3b .equ GIFR = 0x3a [...] ; ***** BIT DEFINITIONS ************************************************** ; ***** EEPROM *********************** ; EEDR - EEPROM Data Register .equ EEDR0 = 0 ; EEPROM Data Register bit 0 .equ EEDR1 = 1 ; EEPROM Data Register bit 1 .equ EEDR2 = 2 ; EEPROM Data Register bit 2 .equ EEDR3 = 3 ; EEPROM Data Register bit 3 .equ EEDR4 = 4 ; EEPROM Data Register bit 4 .equ EEDR5 = 5 ; EEPROM Data Register bit 5 .equ EEDR6 = 6 ; EEPROM Data Register bit 6 .equ EEDR7 = 7 ; EEPROM Data Register bit 7 ; EECR - EEPROM Control Register .equ EERE = 0 ; EEPROM Read Enable .equ EEWE = 1 ; EEPROM Write Enable [...] ---------------------------------------------------------------------- Thaddy · 2017-11-04 10:42 Yes, you suggest a better order too. But in that case (it is nitpicking) you can also use a bitpacked record or bitpacked set for the subsequent bits, which makes it even more readable and pascal like. ---------------------------------------------------------------------- kupferstecher · 2017-11-04 10:57 Quote from: Thaddy on November 04, 2017, 11:42:28 amyou can also use a bitpacked record or bitpacked set for the subsequent bits That discussion was here, before. While bitpacking makes the access to bits easier and clearer, the access to the complete register is getting more complicated. I prefer the "standard" way, where no cryptic errors could occur because you try to assign an integer value to a bitpacked type. ---------------------------------------------------------------------- Thaddy · 2017-11-04 11:24 The access to the register can be very nicely done using a bitpacked variant record.... Or an advanced record  Anyway, I do it like in my first code example above. Any example adapted from the wiki: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i     TRegisterBits = bitpacked record     Bit0, Bit1, Bit2, Bit3, Bit4, Bit5, Bit6, Bit7: Boolean;// replace BitX with bit name/meaning    end;      TAVRRegister = bitpacked record     case boolean of      false:(register:byte);     true:(Bit:TRegisterBits);    end;  http://wiki.freepascal.org/Bit_manipulation ---------------------------------------------------------------------- ccrause · 2017-11-04 14:30 Quote from: kupferstecher on November 04, 2017, 11:22:35 amIs there a technical reason you want to do it that way? Probably extracting the definitions from the GCC-header? I checked the assembler header, there the register and bit definitions are seperated.I want to regenerate the AVR microcontroller units to fix up some mixed up bit field names, so I am thinking of ways in which the presentation of the information can be improved.  Currently the register and bit definitions are separate like you suggested.  For me the current layout doesn't provide much insight, if I didn't know the datasheet names of bit fields for a register I would most probably not find them at all. I've looked at how GCC does it and that convention seems a bit better for me. ---------------------------------------------------------------------- ccrause · 2017-11-04 15:09 Quote from: Thaddy on November 04, 2017, 12:24:24 pmThe access to the register can be very nicely done using a bitpacked variant record.... Or an advanced record  Anyway, I do it like in my first code example above. Any example adapted from the wiki: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i     TRegisterBits = bitpacked record     Bit0, Bit1, Bit2, Bit3, Bit4, Bit5, Bit6, Bit7: Boolean;// replace BitX with bit name/meaning    end;      TAVRRegister = bitpacked record     case boolean of      false:(register:byte);     true:(Bit:TRegisterBits);    end; So this looks like an elegant option, but do I then have to create a new type for each config register with unique bit names? Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i type  TADCSRA = bitpacked record  case boolean of  false:(      ADPS: 0..7;      ADIE,      ADIF,      ADATE,      ADSC,      ADEN: 0..1);  true:  (b: byte);  end; var  ADCSRA_: TADCSRA absolute $7A;The benefit of using bitpacked records are not that clear to me ( I am not familiar with the use of bitpacked records): Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i   ADCSRA_.ADPS := 6; // prescaler = 64  ADCSRA_.ADIE := 0;  ADCSRA_.ADATE := 0;  ADCSRA_.ADEN := 1; // enable ADC   // alternative  ADCSRA_.b := (6 shl ADPS0) or (1 shl ADEN); // prescaler = 64, enable ADCvs. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i   ADCSRA := (6 shl ADPS0) or (1 shl ADEN); // prescaler = 64, enable ADCSo in the end it seems like it gives the user a convenient way of seeing the bit names, but then some extra code is necessary to define the record structures. Also in many use cases one would want to configure all bits in a register in one instruction so then then one still needs the bit constants, am I understanding this correctly? ---------------------------------------------------------------------- Thaddy · 2017-11-04 15:21 The whole point of my example was to show you that all those shifts are not necessary.... AND you can set the whole byte at once. In C speak: it is a union, not a record.... ---------------------------------------------------------------------- marcov · 2017-11-04 15:25 It depends on the architecture. The bit notation expresses more what you want, and it might be easier to transform to (atomic) read/modify/write bit instructions (if the architecture has some). Example 8-bit and 16-bit pic/dspic. The shift option is better if you have an architecture that works with SET and CLR registers to erase bits (like PIC32 (general MIPS?)). I like the bits notation more though. It is more readable than the one with shifts. ---------------------------------------------------------------------- ccrause · 2017-11-04 15:41 Quote from: marcov on November 04, 2017, 04:25:11 pmThe bit notation expresses more what you wantI'm not seeing the picture (or less poetically the code) here.  If I want to set a specific bit then I agree the above bitpacked record syntax makes it very clear what is meant.  What I don't understand is the use case where I want to set more than one bit in one statement, it seems to me that I need to revert to OR'ing bit shifts together to construct a byte which then is assigned to a byte variable.  I guess I'm asking what the alternative "bitpacked" way is to express the following in such a way that equivalent compact code gets generated:Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i   ADCSRA_.b := (6 shl ADPS0) or (1 shl ADEN); ---------------------------------------------------------------------- Thaddy · 2017-11-04 15:59 packed Bit sets... Then you can use include, exclude, basically all set operations on the register, which again makes it more readable. But Marco is right: not every architecture is suited for that. (your AVR is, I think) ---------------------------------------------------------------------- marcov · 2017-11-04 16:07 Quote from: ccrause on November 04, 2017, 04:41:29 pmQuote from: marcov on November 04, 2017, 04:25:11 pmThe bit notation expresses more what you wantI'm not seeing the picture (or less poetically the code) here.  If I want to set a specific bit then I agree the above bitpacked record syntax makes it very clear what is meant.  What I don't understand is the use case where I want to set more than one bit in one statement, it seems to me that I need to revert to OR'ing bit shifts together to construct a byte which then is assigned to a byte variable.  Yes. For arbitrary values. If most bits are boolean though, you might make it readable simply by having masks rather than shifts. The PIC32 (Microchip XC16) headers define it simply all. So both the bitpacked records, _POSITION for shift values and _MASK for the corresponding mask.  (1 shl xx) The bits registers on all microchip systems have -bits suffixed, and the straight name is reserved for the as a whole integer (byte,word,dword, depending on arch) register. ADCSRAbits.ADPS0=1; // not atomic on PIC32, atomic on PIC8/dspic ADCSRA= yy;    // sets to 00010000 or whatever. ADCSRASET = yy ;    // atomic set on PIC32, sets to xxx1xxxx ADCSRACLR = yy;     // atomic clear on PIC32, sets to xxx0xxxx where yy = 1 shl ADPS0_POSITION or yy = ADPS0_MASK would all work. Combinations too. The SET and CLR options are an architecture feature. These registers have a different address. ---------------------------------------------------------------------- Edson · 2017-11-04 17:59 There was a similar discussion http://forum.lazarus.freepascal.org/index.php/topic,36374.0.html for Microchip compiler PicPas https://github.com/t-edson/PicPas Just for information currently PicPas, support bit access, using fields for basic types: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i TRISA := $FF;TRISA.bit1 := 1;STATUS.bit0 := STATUS.bit1;word_variable.high.bit7 := byte_variable.bit7; But this a language constructions that the compiler implements and optimize for this architecture. ---------------------------------------------------------------------- Thaddy · 2017-11-04 20:01 Quote from: kupferstecher on November 04, 2017, 11:57:14 amI prefer the "standard" way, where no cryptic errors could occur because you try to assign an integer value to a bitpacked type. A bit late but: can you give an example?....... ((That would be either wrong or the error is correct. I can see in the future....) Assigning an integer to a byte?... yeah, right! (that rhymes). ---------------------------------------------------------------------- avra · 2017-11-04 20:33 Quote from: ccrause on November 04, 2017, 04:41:29 pmCode: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i   ADCSRA_.b := (6 shl ADPS0) or (1 shl ADEN);When I saw this my first thought was that I should better stick with GCC. I can live with such code since it might at the end be more efficient, but I do not like it. I also prefer plain ADCSRA over c-ish ADCSRA_ whenever possible. Please don't kill me for being honest and so subjective on this. I prefer bitpacked variant records with named bits, with or without type helpers, and bitsets. Something like Thaddy and Marco have already mentioned. I know it's a lot of work that needs to be repeated for each CPU (and there are many), but benefit is more pascalish syntax. Take a look at this discussion: http://forum.lazarus.freepascal.org/index.php/topic,36374.msg242412.ht ml#msg242412 http://forum.lazarus.freepascal.org/index.php/topic,36374.msg242438.ht ml#msg242438 http://forum.lazarus.freepascal.org/index.php/topic,36374.msg242464.ht ml#msg242464 http://forum.lazarus.freepascal.org/index.php/topic,36374.msg242293.ht ml#msg242293 http://forum.lazarus.freepascal.org/index.php/topic,36374.msg242628.ht ml#msg242628 http://forum.lazarus.freepascal.org/index.php/topic,36374.msg242713.ht ml#msg242713 Quote from: ccrause on November 04, 2017, 04:09:41 pmSo in the end it seems like it gives the user a convenient way of seeing the bit names, but then some extra code is necessary to define the record structures. Also in many use cases one would want to configure all bits in a register in one instruction so then then one still needs the bit constants, am I understanding this correctly?Yes. Let the user decide between comfort and efficiency based on his use case. ---------------------------------------------------------------------- ccrause · 2017-11-04 20:37 Thanks for all the ideas Thaddy, Marco and Edson.  If I cater for all the variations I've picked up (since there isn't one correct way to do this) then the following is required for one register with its associated bit definitions:Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i type  TBitField = 0..1;  // move to shared location   TADCSRA_set = set of (ADPS0, ADPS1, ADPS2, ADIE, ADIF, ADATE, ADSC, ADEN);   TADCSRA = bitpacked record  case boolean of  false:(      ADPS: 0..7;      ADIE,      ADIF,      ADATE,      ADSC,      ADEN: TBitField);  true:    (asByte: byte);  end; var  ADCSRA: byte absolute $7A;  ADCSRA_bits: TADCSRA absolute ADCSRA;  ADCSRA_set: TADCSRA_set absolute ADCSRA; const  ADPS0_mask = 1;  ADPS1_mask = 2;  ADPS2_mask = 4;  ADIE_mask = 8;  ADIF_mask = 16;  ADATE_mask = 32;  ADSC_mask = 64;  ADEN_mask = 128;This would allow all of the following variations: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i   // A - Bit fields  ADCSRA_bits.ADPS := 6;  ADCSRA_bits.ADEN := 1;   // B - Bit sets  ADCSRA_set := [ADPS1, ADPS2, ADEN];   // C - Variant record as byte  ADCSRA_.asByte := ADPS1_mask or ADPS2_mask or ADEN_mask;   // D - Straight value assignment to byte  ADCSRA := ADPS1_mask or ADPS2_mask or ADEN_mask;So variation A is very clear, but generates 8 instructions and should only be used when manipulating or inspecting one bit at a time (in my opinion).  Variations B, C & D compile to exactly the same two instructions, hence it comes down to personal preference. Now the variant record seems superfluous if a regular byte variable is also declared, so I would drop the asByte bit of the bitpacked record. Does this appraoch seem excessively verbose? ---------------------------------------------------------------------- kupferstecher · 2017-11-04 20:53 Thaddy, the variant record is what I was missing. So in your example a register ABC would be accessible as follows?  ABC.Register:= 123; or  ABC.Bit.Bit1:= true; Quote from: ccrause link=topic=38809.msg264889#msg264889What I don't understand is the use case where I want to set more than one bit in one statement, [..] Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i   ADCSRA_.b := (6 shl ADPS0) or (1 shl ADEN);I think this is only possible if the bits are defined also as constants and doing the shift operation (or the mask). Right? Would it even be possible to use the same names in the bitpacked record and in the constants? Quote from: marcov on November 04, 2017, 04:25:11 pmThe shift option is better if you have an architecture that works with SET and CLR registers to erase bits (like PIC32 (general MIPS?)).The AVR has commands for setting and clearing a single bit in the IO-registers. Quote from: marcov on November 04, 2017, 05:07:00 pmADCSRAbits.ADPS0=1; // not atomic on PIC32, atomic on PIC8/dspic ADCSRA= yy;    // sets to 00010000 or whatever. So there are two names for the same register (ADCSRAbits and ADCSRA) and two names for the same bit (ADPS0 and ADPS0_POSITION)? I think thats quite confusing (although the naming seems ok)... ---------------------------------------------------------------------- ccrause · 2017-11-04 20:55 Quote from: avra on November 04, 2017, 09:33:39 pmYes. Let the user decide between comfort and efficiency based on his use case. I started this thread because I was trying to keep the unit structure as simple as possible so that it could be easy to follow, but it appears as if there is much interest in having a few alternatives.  Since including the currently discussed options into the units will not increase compiled code size I guess that it is acceptable to include a whole bunch of declarations. QuoteI also prefer plain ADCSRA over c-ish ADCSRA_ No problem, I used the underscore to distinguish between the existing register definition and the alternative declaration in the old example.  See my later example for alternative names.  Of course if I include declarations for different approaches then I need to generate unique names somehow. ---------------------------------------------------------------------- ccrause · 2017-11-04 21:06 Quote from: kupferstecher on November 04, 2017, 09:53:32 pmWould it even be possible to use the same names in the bitpacked record and in the constants? ... So there are two names for the same register (ADCSRAbits and ADCSRA) and two names for the same bit (ADPS0 and ADPS0_POSITION)? I think thats quite confusing (although the naming seems ok)... Indeed,I was also a bit lost for names, but Marco's suggestion of rather using the mask instead of the bit location makes sense in the conventional use case so I changed the regular bit namess to e.g. ADPS0_mask and set the value to 1 shl ADPS0.  No more name clashes and one doesn't need to calculate a mask on the fly for assignment to a register. ---------------------------------------------------------------------- avra · 2017-11-05 00:51 Quote from: ccrause on November 04, 2017, 09:37:25 pmNow the variant record seems superfluous if a regular byte variable is also declared, so I would drop the asByte bit of the bitpacked record.I would keep AsByte and add AsSet. If you define something like this: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i {$MODESWITCH TYPEHELPERS} type  TBitField = 0..1;   TAvrByteHelper = type helper for Byte    function  GetBit(Index: Byte): Boolean;    procedure SetBit(Index: Byte; Value: Boolean);    property  Bit[Index: Byte]: Boolean read GetBit write SetBit;  end;   TADCSRA_bits = (ADPS0, ADPS1, ADPS2, ADIE, ADIF, ADATE, ADSC, ADEN);  TADCSRA_set  = set of TADCSRA_bits;   TADCSRA = bitpacked record  case byte of  0:(    ADPS: 0..7;      ADIE,      ADIF,      ADATE,      ADSC,      ADEN: TBitField);  1:(      AsByte: byte);  2:(      AsSet: TADCSRA_set);  end;   TMCUCSR_bits = (PORF, EXTRF, BORF, WDRF, JTRF, ISC2 = 6 {skip dummy bit 5}, JTD);  TMCUCSR_set  = set of TMCUCSR_bits;   TMCUCSR = bitpacked record  case byte of  0:(      PORF,      EXTRF,      BORF,      WDRF,      JTRF,      DummyBit5,      ISC2,      JTD: TBitField);  1:(      AsByte: byte);  2:(      AsSet: TMCUCSR_set);  end;  const  ADCSRA_ADDR = $7A;  MCUCSR_ADDR = $54; var  ADCSRA_: byte           absolute ADCSRA_ADDR;  ADCSRA: TADCSRA         absolute ADCSRA_ADDR;  MCUCSR_: byte           absolute MCUCSR_ADDR;  MCUCSR: TMCUCSR       absolute MCUCSR_ADDR;     implementation function TAvrByteHelper.GetBit(Index: Byte): Boolean;begin  Result := ((Self shr Index) and $01) <> 0;end; procedure TAvrByteHelper.SetBit(Index: Byte; Value: Boolean);begin  if Value then    Self := Self or ($01 shl Index)  else    Self := Self and not ($01 shl Index);end; then you could have all these: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i    ADCSRA.ADPS := %110;   ADCSRA.ADEN := 1;   MCUCSR_.Bit[3] := true;   MCUCSR_.Bit[Byte(PORF)] := true;   MCUCSR.AsByte.Bit[7] := true;   MCUCSR.ISC2 := 1;    MCUCSR.AsSet := [WDRF, JTD, JTRF] + [JTD, ISC2];   ADCSRA.AsSet := [ADPS1, ADEN];   ADCSRA.AsSet := ADCSRA.AsSet + [ADIF, ADATE];   Include(ADCSRA.AsSet, ADPS0);   Exclude(ADCSRA.AsSet, ADPS0);    ADCSRA.AsByte := (1 shl byte(ADPS1)) or (1 shl byte(ADPS2));   ADCSRA_ := (1 shl byte(ADPS1)) or (1 shl byte(ADPS2)); I like just few of these possibilities, but they are all there for consumation ;-) ---------------------------------------------------------------------- marcov · 2017-11-05 03:51 I like Crause's syntax more,  but would kill the _ so  ADCSRAbits and  ADCSRAset.  But it also depends on how AVR does this in typical sources. My conventions were mostly PIC. ---------------------------------------------------------------------- ccrause · 2017-11-05 06:55 Thanks avra, I guess your approach could be called the all-in-one record which nicely puts all variants in one record definition.  My perception of the downside is that the user code then is a bit more verbose since one has to explicitly reference the variant in the record. Quote from: marcov on November 05, 2017, 04:51:31 amBut it also depends on how AVR does this in typical sources.So I thought of grabbing a typical bit of GCC style C code, but then stumbled onto this thread which started off as a demonstration of macro gymnastics but then contains this interesting bit : Quote from: david.prenticeThere are many different schemes for describing special_bits in special function registers. Personally, I like the bitfield_structure used by PIC (and others). It is a historic thing. I suspect that the early compilers were not clever enough. Hence we are stuck with the bit_position scheme.Since we are dealing with a "smart" compiler, it seems more natural then to use bit masks and eliminate all the (1 shl bitname) fluff.  I will need to get used to these alternatives, I've been using avr-gcc for a number of years now and obviously need to relearn some Pascal alternatives. ---------------------------------------------------------------------- kupferstecher · 2017-11-05 10:45 The advantage of the bitpacked record that the IDE can list the bit names is significant, but I still don't like the multiple names for the same thing. I came up with an alternative approach. It doesn't mean its my favourite, but I want to put it to discussion. The idea is to use the "standard" way and additionally provide the bit-values through class constants. The bits then can be accessed through the class name ("T" + register name), so the IDE can list the according bits. Usage example: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i UCSRA:= (1 shl UDRE);        //"traditional" wayUCSRA:= (1 shl TUCSRA.UDRE); //using class constant and with type helpers: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i UCSRA.SetBit(TUCSRA.UDRE, true);UCSRA.SetBit(UDRE, true); Advantage: Its backwards compatible and the bit names are always the same, so the type of the register can be typed to get the bits-list and deleteded again for readability. EDIT: here the implementation of the class constants: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i Type TUCSRA = object  const RXC = 7; // USART Receive Complete  const TXC = 6; // USART Transmitt Complete  const UDRE = 5; // USART Data Register Empty  const FE = 4; // Framing Error  const DOR = 3; // Data overRun  const UPE = 2; // Parity Error  const U2X = 1; // Double the USART transmission speed  const MPCM = 0; // Multi-processor Communication Modeend; ---------------------------------------------------------------------- Thaddy · 2017-11-05 10:56 You can even do this and work by index: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i Type TUCSRA = bitpacked object  const RXC = 7; // USART Receive Complete  const TXC = 6; // USART Transmitt Complete  const UDRE = 5; // USART Data Register Empty  const FE = 4; // Framing Error  const DOR = 3; // Data overRun  const UPE = 2; // Parity Error  const U2X = 1; // Double the USART transmission speed  const MPCM = 0; // Multi-processor Communication Modeend; Yes, objects can be bitpacked too ---------------------------------------------------------------------- kupferstecher · 2017-11-05 11:19 Thaddy, how to use it then? ---------------------------------------------------------------------- Thaddy · 2017-11-05 15:15 Like this, but now I integrated and improved on AVRA's idea that was very good in my opinion.. I believe this is the simplest and shortest  approach: [EDIT] Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i program testme3;{$mode objfpc}{$bitpacking on}{$packset 1}{$packenum 1}{$modeswitch typehelpers}{.$define ADCSRA_REAL} //define for real processor{$I-}type  TADCSRA_pins = (ADPS0, ADPS1, ADPS2, ADIE, ADIF, ADATE, ADSC, ADEN);  TADCSRA_set  = bitpacked set of TADCSRA_pins;  TADCSRA_range = ADPS0..ADEN;    TADCSRA_sethelper = type helper for TADCSRA_set    procedure PinHi(const pin:TADCSRA_pins);inline;    procedure PinLo(const pin:TADCSRA_pins);inline;    procedure Toggle(const pin:TADCSRA_pins);inline;    function IsOn(const pin:TADCSRA_pins):Boolean;inline;    function IsOff(const pin:TADCSRA_pins):Boolean;inline;    function AsByte:Byte;inline;    function AsString:string;    function AsBin:string;  end;    procedure TADCSRA_sethelper.PinHi(const pin:TADCSRA_pins);inline;  begin    include(self,pin);  end;    procedure TADCSRA_sethelper.PinLo(const pin:TADCSRA_pins);inline;  begin    exclude(self,pin);  end;    procedure TADCSRA_sethelper.Toggle(const pin:TADCSRA_pins);inline;  begin    //if pin in self then exclude(self,pin) else include(self,pin);    self := self >< [pin] //same as above but more fun for noobs   end;   function TADCSRA_sethelper.IsOn(const pin:TADCSRA_pins):Boolean;inline;  begin    Result := pin in self;  end;   function TADCSRA_sethelper.IsOff(const pin:TADCSRA_pins):Boolean;inline;  begin    Result := not (pin in self);  end;    function TADCSRA_sethelper.AsByte:byte;inline;    begin    result := byte(self);  end;   function BitAsString(pin:TADCSRA_pins):string;  begin    writestr(result,pin:6);  end;   function TADCSRA_sethelper.AsString:string;  var    t:TADCSRA_pins;  begin    result :='';    for t in self do       result+=BitAsString(t);  end; function TADCSRA_sethelper.AsBin:string;  begin     Result :=Binstr(byte(self),8);  end;/////////////////////////////////////////////////// example code/////////////////////////////////////////////////const TADCSRA = $7A;  var   ADCSRA:TADCSRA_set {$ifdef ADCSRA_REAL}absolute TADCSRA{$else}=[]{$endif};begin    writeln(ADCSRA.IsOn(ADPS0));   writeln(ADCSRA.AsString);   ADCSRA.PinHi(ADPS0);   writeln(ADCSRA.IsOff(ADPS0));   writeln(ADCSRA.AsString);   ADCSRA.PinHi(ADPS1);   writeln(ADCSRA.AsString);   ADCSRA.PinHi(ADPS2);   writeln(ADCSRA.AsString);   ADCSRA.PinHi(ADIE);   writeln(ADCSRA.AsString);   writeln(ADCSRA.AsBin);   ADCSRA.PinHi(ADIF);   writeln(ADCSRA.AsString);   ADCSRA.PinHi(ADATE);   writeln(ADCSRA.AsString);   ADCSRA.PinHi(ADSC);   writeln(ADCSRA.AsString);   ADCSRA.PinHi(ADEN);   writeln(ADCSRA.AsBin);   writeln(ADCSRA.AsString);   ADCSRA.PinLo(ADPS0);   writeln(ADCSRA.AsString);   ADCSRA.PinLo(ADPS1);   writeln(ADCSRA.AsString);   writeln(ADCSRA.AsBin);   ADCSRA.PinLo(ADPS2);   writeln(ADCSRA.AsString);   ADCSRA.PinLo(ADIE);   writeln(ADCSRA.AsString);   ADCSRA.PinLo(ADIF);   writeln(ADCSRA.AsString);   ADCSRA.PinLo(ADATE);   writeln(ADCSRA.AsString);   ADCSRA.PinLo(ADSC);   writeln(ADCSRA.AsString);   ADCSRA.PinLo(ADEN);   writeln(ADCSRA.AsString);   writeln(ADCSRA.AsBin);   ADCSRA.Toggle(ADIE);   writeln(ADCSRA.IsOn(ADIE));   ADCSRA.Toggle(ADIE);   writeln(ADCSRA.IsOn(ADIE));   ADCSRA.Toggle(ADIE);   writeln(ADCSRA.IsOn(ADIE));   ADCSRA.Toggle(ADIE);   writeln(ADCSRA.IsOn(ADIE));end. This reduces the whole shebang to just the bit set. Really easy to implement for the rest too. See this as a template to show the techniques. The code should be really efficient... ---------------------------------------------------------------------- marcov · 2017-11-05 15:47 Quote from: Thaddy on November 05, 2017, 04:15:23 pm   procedure TADCSRA_sethelper.Toggle(pin:TADCSRA_pins);inline;   begin     if pin in self then exclude(self,pin) else include(self,pin);   end; Btw many 8 and 16-bitters have a dedicated atomic bit-toggle instruction, usually triggered by some intrinsic like __builtintoggle(LATA,1) for PIC, doing it in one instruction, and not 4. (though on the faster models you get a cycle penalty for the r/m/w operation) ---------------------------------------------------------------------- Thaddy · 2017-11-05 16:44 @Marco  what about: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i   procedure TADCSRA_sethelper.Toggle(pin:TADCSRA_pins);inline;  begin    //if pin in self then exclude(self,pin) else include(self,pin);    self := self >< [pin]  // this is hardcore Pascal.... don't use unless you understand it when you read it....  end; I have to check what it generates....but usually that should be a maximum of two operands for symmetric difference. In this case I used it as the toggle. [edit] on arm that does this in both cases, given ADIE: Code: Text  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i         tst     r0,#8        movne   r2,#1        moveq   r2,#0 Which means the compiler sees the symmetric difference as if/then/else at least on arm. (Aside: finally a case again where i could use symmetric difference in reasonably normal code.. ). I have no real hardware available atm. Maybe someone can test what it really does? On arm it should generate eor (which it does in a simpler example), a single instruction over three registers. ---------------------------------------------------------------------- ccrause · 2017-11-05 19:48 Thaddy, the toggle code in the type helper doesn't look great with the AVR compiler (it actually looks wrong): Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i   ADCSRA.Toggle(ADIE);  ae:   21 2d           mov     r18, r1  b0:   33 e0           ldi     r19, 0x03       ; 3  b2:   41 e0           ldi   r20, 0x01       ; 1  b4:   33 23           and     r19, r19  b6:   19 f0           breq    .+6             ; 0xbe   b8:   44 0f           add     r20, r20  ba:   3a 95           dec     r19  bc:   e9 f7           brne    .-6             ; 0xb8   be:   24 2b           or      r18, r20  c0:   30 91 7a 00     lds     r19, 0x007A  c4:   23 27           eor     r18, r19  c6:   20 93 7a 00     sts     0x007A, r18 It seems to have something to do with the type helper construct, calling the symmetric difference directly create much better code: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i   ADCSRA := ADCSRA >< [ADIE];  a2:   20 91 7a 00     lds     r18, 0x007A  a6:   38 e0           ldi     r19, 0x08       ; 8  a8:   23 27           eor   r18, r19  aa:   20 93 7a 00     sts     0x007A, r18 Edit: compiled with -O3 ---------------------------------------------------------------------- Thaddy · 2017-11-05 21:13 @ccrause Actually, I noticed that, in so far that the compiler also generates different code for simpler things: I already noted here the eor for arm instruction for simpler code. I wonder if it is a bug in the type helper code. Must be in the high level side. What  can do is box the whole thing in a bitpacked record - get rid of the helper - and see what happens. I could only test on my Pi today, and there it works. Tomorrow I can do some more. Anyway, does the code work? Efficient or not? I will take care of the efficiency later if possible. I still think we can pack everything in just a few lines that are understandable. [edit] with the record approach I can reduce to: Code: Text  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i         eor     r4,r1,r0 Skipped loading, though, and did not profile yet. ---------------------------------------------------------------------- ccrause · 2017-11-06 06:15 I have to run off to my day job, but will pick this up in a couple of days again.  My summary so far: Many people in this thread indicated a preference for a more Object Pascal interface to the registers and bitsI would like to retain the old school byte variable approach so that existing code works as far as possible - AVR isn't really supported in the current release so is backwards compatibility much of an issue?I am in favour of dropping bit index constants (ADEN = 7) and change to bitmapped constants (ADEN = 128) to eliminate the whole register := (1 shl ADEN) constructI could add all variations in principle, but it would clutter the source file (minor issue I think) and then there is the issue of naming the different types (ADCSRA, ADCSRAset, ADCSRAbitfield etc.) - so which type should have the bare register name ADCSRA? Probably the byte type variable?.I think type helpers could eliminate some of the problems with naming different types that point to the same register address since the base type can be type casted in the type helper to various approaches.  Not sure about this though.Perhaps move extended types to a different file - problem is then maintenance of separate files with similar functionality. ---------------------------------------------------------------------- avra · 2017-11-15 14:37 Quote from: ccrause on November 06, 2017, 07:15:30 amMany people in this thread indicated a preference for a more Object Pascal interface to the registers and bits+1 QuoteI would like to retain the old school byte variable approach so that existing code works as far as possible - AVR isn't really supported in the current release so is backwards compatibility much of an issue?No. QuoteI am in favour of dropping bit index constants (ADEN = 7) and change to bitmapped constants (ADEN = 128) to eliminate the whole register := (1 shl ADEN) constructOnly people copying some C code snippet might prefer to use such code. I would not make such change to avoid confusion for them. QuoteI could add all variations in principle, but it would clutter the source file (minor issue I think) and then there is the issue of naming the different types (ADCSRA, ADCSRAset, ADCSRAbitfield etc.) - so which type should have the bare register name ADCSRA? Probably the byte type variable?.+1 for all variations. Instead of ADCSRA / ADCSRAset / ADCSRAbitfield, I would leave ADCSRA for byte access (again to avoid confusion for people translating C code snippets), and add X prefix for all bitpacked records/sets like this: XADCSRA: TADCSRA (look at my last example) for Pascalish access to bits. Pascal people are already used to adding F and T prefixes and know meaning of such a convention. You could just exploit this fact and extend it. That would make code look much cleaner and save lots of typing. QuoteI think type helpers could eliminate some of the problems with naming different types that point to the same register address since the base type can be type casted in the type helper to various approaches.  Not sure about this though.Perhaps move extended types to a different file - problem is then maintenance of separate files with similar functionality.code generator? I have just seen question about usage of volatile in another thread: h ttps://forum.lazarus.freepascal.org/index.php/topic,38961.msg266000.ht ml. That reminded me that there are lots of things in small AVR that don't have their counter part in big world so have not been addressed by FPC. They need to be addressed sooner or later, so I would like to point how this has been addressed by very nice E-Lab's Multitasking AvrCo compiler. Having in mind that FPC needs to be reused as much as possible and that new features/constructions are added with great care, I would more look at AvrCo as an inspiration since no one is creating here a compiler from scratch and therefore adopting options are sometimes quite limited. Anyway, it might be a worthy inspiration since it solved many problems that FPC-AVR needs to address also. So, here it is. If you want you can download compiler manual from http://www.e-lab.de/AVRco/index_en.html following this link: http://www.e-lab.de/AVRco/DOC_en/DocuCompiler.pdf. Some interesting topics worth a look might be: Page 177: Eeprom access (so much more elegant then in C)Page 199: VolatilityPage 204: Memory administration (how variables are defined to be in registers for super fast access, ram, external ram, eeprom, and user defined storage)Page 33: Distinction of pointer to ram and pointer to eepromPage 62: Definition of locked variables which will have interrupts disabled on accessPage 182: Boot vectors and boot trapsPage 41: Comparison with Delphi typesPage 39: TimersPage 37: Semaphores and pipesPage 54: FusesPage 69: Processes and TasksPage 77: Interrupts, Traps and ExceptionsPage 167: SysTickPage 172: WatchDogPage 195: Multitasking ---------------------------------------------------------------------- Thaddy · 2017-11-15 15:05 Quote from: avra on November 15, 2017, 03:37:05 pmI have just seen question about usage of volatile in another thread: https://forum.laza rus.freepascal.org/index.php/topic,38961.msg266000.html. Good advice. But please....Note volatile in Pascal is just a writable typed const instead of var... Has been since TP days.... ---------------------------------------------------------------------- ccrause · 2017-11-20 20:19 So this is my first try at the fancy code generator:Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i {$bitpacking on}{$packset 1}{$packenum 1}type  TBitField = 0..1; var  PINB: byte absolute $23;  // Port B Input Pins  DDRB: byte absolute $24;  // Port B Data Direction Registertype  TPORTBset = bitpacked set of (sPB0, sPB1, sPB2, sPB3, sPB4, sPB5, sPB6, sPB7);  TPORTBrec = bitpacked record    PB0,    PB1,    PB2,    PB3,    PB4,    PB5,    PB6,    PB7: TBitField;  end;var  PORTB: byte absolute $25;  // Port B Data Register  PORTBset: TPORTBset absolute $25;  PORTBrec: TPORTBrec absolute $25;const  PB0 = 0;  PB1 = 1;  PB2 = 2;  PB3 = 3;  PB4 = 4;  PB5 = 5;  PB6 = 6;  PB7 = 7;An example of a sparse register:Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i type  TTIFR1set = bitpacked set of (sTOV1, sOCF1A, sOCF1B, sICF1=5);  TTIFR1rec = bitpacked record    TOV1,    OCF1A,    OCF1B,    reserved0,    reserved1,    ICF1,    reserved2,    reserved3: TBitField;  end;var  TIFR1: byte absolute $36;  // Timer/Counter Interrupt Flag register  TIFR1set: TTIFR1set absolute $36;  TIFR1rec: TTIFR1rec absolute $36;const  TOV1 = 0;  // Timer/Counter1 Overflow Flag  OCF1A = 1;  // Output Compare Flag 1A  OCF1B = 2;  // Output Compare Flag 1B  ICF1 = 5;  // Input Capture Flag 1I could still stuff the byte, record and set definitions into a variant record, but in my mind it adds more clutter to the code without extra functionality. ---------------------------------------------------------------------- engkin · 2017-11-21 02:29 Quote from: Thaddy on November 15, 2017, 04:05:19 pmQuote from: avra on November 15, 2017, 03:37:05 pmI have just seen question about usage of volatile in another thread: https://forum.lazarus.freepascal.org/in dex.php/topic,38961.msg266000.html. But please....Note volatile in Pascal is just a writable typed const instead of var... Has been since TP days.... Not true. ---------------------------------------------------------------------- avra · 2017-11-21 09:45 Quote from: ccrause on November 20, 2017, 09:19:28 pmSo this is my first try at the fancy code generator: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i ...  PORTB: byte absolute $25;  // Port B Data Register  PORTBset: TPORTBset absolute $25;  PORTBrec: TPORTBrec absolute $25;...I still prefer single letter prefix like sPORTB and rPORTB over PORTBset and PORTBrec, but these are also fine. Quote from: ccrause on November 20, 2017, 09:19:28 pmCode: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i ...  TTIFR1rec = bitpacked record    TOV1,    OCF1A,    OCF1B,    reserved0,    reserved1,    ICF1,    reserved2,    reserved3: TBitField;  end;... If reserved0 and reserved1 in some CPU revision get some name, then reserved2 and reserved3 will not look that good. Maybe name them according to their bit position? Like this: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i   TTIFR1rec = bitpacked record    TOV1,    OCF1A,    OCF1B,    ReservedBit3,    ReservedBit4,    ICF1,    ReservedBit6,    ReservedBit7: TBitField;  end;That should stand the test of time. ---------------------------------------------------------------------- marcov · 2017-11-21 10:06 - I agree with Avra about reserved naming, though it is a minor thing - I don't like the bitnumbers getting potentially very general register looking names this way.  Some pre or suffix would be ok, avoid clashes and be more distinct.  - I still would like to at least have an option to also generate the masks. ---------------------------------------------------------------------- ccrause · 2017-11-21 19:53 marcov, avra, thanks for the feedback.  Changing the reserved bit naming is a non-issue; already changed to avra's suggestion.  Quote from: marcov on November 21, 2017, 11:06:13 am- I don't like the bitnumbers getting potentially very general register looking names this way.  Some pre or suffix would be ok, avoid clashes and be more distinct. Not sure what you are referring to, perhaps give an example? If you are referring to this:Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i const OCF1A = 1; then there shouldn't be name clashes with registers due to the bit naming convention used by Atmel. Quote from: marcov on November 21, 2017, 11:06:13 am- I still would like to at least have an option to also generate the masks. I will add this as an extra set of constants with say a prefix of mXXX or perhaps mskXXX. I don't like the s-prefix for the set element names, should I change this to e for element or maybe se for set element? ---------------------------------------------------------------------- avra · 2017-11-21 22:01 Quote from: ccrause on November 21, 2017, 08:53:53 pmI will add this as an extra set of constants with say a prefix of mXXX or perhaps mskXXX.+1 for mXXX Quote from: ccrause on November 21, 2017, 08:53:53 pmI don't like the s-prefix for the set element names, should I change this to e for element or maybe se for set elementI don't mind what prefix as long as it's a single letter. I would prefer X for extended over E for element, but that is really not that important. ---------------------------------------------------------------------- ccrause · 2017-12-08 20:20 A preview of the auto generated AVR controller files have been prepared. Note that there were some name clashes of different identifiers, hence I used s_ and m_ as prefixes for set element and bitmask names respectively.  Also note that at least fpc r37660 r37661 is required to compile the larger files such as atmega32u4.pp. ---------------------------------------------------------------------- avra · 2017-12-13 10:11 Quote from: ccrause on December 08, 2017, 09:20:57 pmA preview of the auto generated AVR controller files have been prepared.Your ImportATDF automation tool does a very nice job.  QuoteNote that there were some name clashes of different identifiers, hence I used s_ and m_ as prefixes for set element and bitmask names respectively.I still don't like e_ and m_ prefixes with underscores but I can live with them since it is pretty much subjective. What I really don't like is that it seams that you have decided to use such c-ish habbit all over. Here are some examples: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i uart_init1( ...);fpc_shr_qword(...);fpc_div_mod_word(...);spi_transfer(...);Huh, so many underscores and low cases feel like using some C lib. Is it possible to make it more like we are used with FPC/LAZ/DELPHI, please? I would also prefer single overloaded DivMod() which accepts different types instead of each being a completely separate (if they are intended for the user, after all): Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure fpc_div_mod_byte(Dividend, Divisor: byte; out result, remainder: byte);procedure fpc_div_mod_word(Dividend, Divisor: word; var result, remainder: word);procedure fpc_div_mod_dword(Dividend, Divisor: dword; var result, remainder: dword);function fpc_div_mod_qword(Dividend, Divisor: qword; out Remainder: qword): qword; I didn't find type helpers for byte/word/dword/qword. Something like we have discussed previously. Do you have plans to add them as standard at all? Since it is a 8-bit embedded world, assembly optimization will be needed in some of the libraries. It would be nice to decide what registers will never be used by the system and the system libraries, what registers would be used for function results, how to name register pairs, etc. I would suggest to make it compatible with AvrCo, and you can find more info in PDF already mentioned here (Section 11.2 Assembler - Keywords): https://forum.lazarus.freepascal.org/index.php/topic,38809.msg266019.h tml#msg266019 It would be of highest priority to look at GCC/Arduino register usage compatibility for this topic as there will be a need in the future to link to some C library. Functions to save/restore all registers or only system used ones would also be appreciated. I am not quite sure how good would FPC optional register optimization work for AVR, and if we can force specific variables to be stored in registers (if enough free registers are available). Have you looked into this topic yet? Pointers to internal and external ram, flash and eeprom would need to be treated somehow different. There are also AVRs with flash bigger then 64KB. Have you thought about such things yet? How did you manage to do this in examples: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i   pinport: byte absolute PORTB;It compiles on my standard FPC compiler only if I type adress $24 instead of PORTB. However I managed to overcome this issue on my side by defining const PORTBaddr = $24 in generated avr cpu unit and then using PORTBaddr instead of PORTB in both avr cpu unit and example code. I see that all examples follow flat workflow - pretty much GCC and Arduino way. While that is not bad at all, I am very spoiled by AvrCo way of doing things so let me give you a quick insight that might be used as a potential inspiration. AvrCo allows flat program workflow extended with interrupts when needed, but it also provides SysTick, Tasks and Processes. SysTick is a simple system interrupt (10ms by default but can be any period) extended with an optional user callback and used for system and drivers. No more constant polling for ADC readings, no more manual debouncing of inputs, manual matrix keyboard scanning, manual key autorepeat, we have various funtion timeouts, automatic 7seg and 14seg display refresh, automatic PWM or DAC output change, automatic soft and hard RTC handling with user callbacks, automatic handling of data collected from interrupt based drivers like pulse/freq counters or encoders, automatic step motor ramps, etc. Most drivers exploit SysTick so user code looks clean and without GCC like bloat we are used to. Drivers also have callbacks, and IO callbacks are specially usefull. For example, all character or graphical LCD functions are universal. There is example code for 8-9 display models, but if you want to use a not supported one, you just implement IO callbacks for your device, and positioning, drawing, text output and other functions immediatelly work out of the box. The same is for RTC and many other drivers. You can access serial and other types of communication directly like in GCC, but you can also use a interrupt based driver that stores characters into a buffer that you just need to poll to sea if there is anything to read. You might even sleep a process until data is available, since pipes and semaphores are implemented. There is also a round robin scheduler with cyclic tasks and processes with priorities. Tasks have a predefined maximum time for running, and they are killed if that max time is somehow reached. Processes are just temporary interrupted and they simply continue where they left on next schedule. This powerfull multitasking concept allows for example one or more communication processes, an IO task, main logic process, etc. Each as a separate identity easy to follow and develop. Only C based RTOS can match this. Whatever path you decide to go, I really think that you have already done a very nice job. Thumbs up! ---------------------------------------------------------------------- ccrause · 2017-12-13 19:43 Quote from: avra on December 13, 2017, 11:11:29 amQuoteNote that there were some name clashes of different identifiers, hence I used s_ and m_ as prefixes for set element and bitmask names respectively.I still don't like e_ and m_ prefixes with underscores but I can live with them since it is pretty much subjective. Any alternative suggestions? I would like to adopt a naming convention that clearly relate to the standard bit name, but also indicate how the alternative identifier differs (bitmask, set element). QuoteCode: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i uart_init1( ...);fpc_shr_qword(...);fpc_div_mod_word(...);spi_transfer(...);Huh, so many underscores and low cases feel like using some C lib. Is it possible to make it more like we are used with FPC/LAZ/DELPHI, please? I would also prefer single overloaded DivMod() which accepts different types instead of each being a completely separate (if they are intended for the user, after all): Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure fpc_div_mod_byte(Dividend, Divisor: byte; out result, remainder: byte);procedure fpc_div_mod_word(Dividend, Divisor: word; var result, remainder: word);procedure fpc_div_mod_dword(Dividend, Divisor: dword; var result, remainder: dword);function fpc_div_mod_qword(Dividend, Divisor: qword; out Remainder: qword): qword;The fpc_ type functions are used internally by the compiler (and needs to fit this pattern so that the compiler can locate these functions as needed).  The user would code e.g. a div b and the compiler would call the corresponding fpc_div_ function with the parameters rearranged as required.  The rest of the underscore use is in examples I adapted from C code, so you are quite correct in that it mimics typical C style. My intention with the examples was to show how typical tasks can be accomplished in FPC, not to write base libraries (perhaps much later, although I'm hoping others will jump in once the compiler support for AVR is good enough). QuoteI didn't find type helpers for byte/word/dword/qword. Something like we have discussed previously. Do you have plans to add them as standard at all? My thought was that these will be generic helpers, so will sit in a separate unit. Haven't done this yet since it should be "easy". QuoteSince it is a 8-bit embedded world, assembly optimization will be needed in some of the libraries. It would be nice to decide what registers will never be used by the system and the system libraries, what registers would be used for function results, how to name register pairs, etc. I would suggest to make it compatible with AvrCo  The compiler follows the avr-libc convention.  Register naming follows Atmel's nomenclature (r0 - r31 and X, Y, Z for the upper 6 register pairs). QuoteI am not quite sure how good would FPC optional register optimization work for AVR, and if we can force specific variables to be stored in registers (if enough free registers are available). Have you looked into this topic yet?A related discussion. I don't think binding a specific variable to a register is possible, but I don't know for sure. QuotePointers to internal and external ram, flash and eeprom would need to be treated somehow different. There are also AVRs with flash bigger then 64KB. Have you thought about such things yet?This is being debated.  It is currently possible to put data into flash or eeprom with the section modifier, but accessing the data requires some assembler at the moment. QuoteHow did you manage to do this in examples: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i   pinport: byte absolute PORTB;It compiles on my standard FPC compiler only if I type adress $24 instead of PORTB. However I managed to overcome this issue on my side by defining const PORTBaddr = $24 in generated avr cpu unit and then using PORTBaddr instead of PORTB in both avr cpu unit and example code.Issue fixed in FPC trunk. QuoteI see that all examples follow flat workflow - pretty much GCC and Arduino way. While that is not bad at all, I am very spoiled by AvrCo way of doing things so let me give you a quick insight that might be used as a potential inspiration. AvrCo allows flat program workflow extended with interrupts when needed, but it also provides SysTick, Tasks and Processes.  SysTick is a simple system interrupt (10ms by default but can be any period) extended with an optional user callback and used for system and drivers. No more constant polling for ADC readings, no more manual debouncing of inputs, manual matrix keyboard scanning, manual key autorepeat, we have various funtion timeouts, automatic 7seg and 14seg display refresh, automatic PWM or DAC output change, automatic soft and hard RTC handling with user callbacks, automatic handling of data collected from interrupt based drivers like pulse/freq counters or encoders, automatic step motor ramps, etc. Most drivers exploit SysTick so user code looks clean and without GCC like bloat we are used to. Drivers also have callbacks, and IO callbacks are specially usefull. For example, all character or graphical LCD functions are universal. There is example code for 8-9 display models, but if you want to use a not supported one, you just implement IO callbacks for your device, and positioning, drawing, text output and other functions immediatelly work out of the box. The same is for RTC and many other drivers. You can access serial and other types of communication directly like in GCC, but you can also use a interrupt based driver that stores characters into a buffer that you just need to poll to sea if there is anything to read. You might even sleep a process until data is available, since pipes and semaphores are implemented. There is also a round robin scheduler with cyclic tasks and processes with priorities. Tasks have a predefined maximum time for running, and they are killed if that max time is somehow reached. Processes are just temporary interrupted and they simply continue where they left on next schedule. This powerfull multitasking concept allows for example one or more communication processes, an IO task, main logic process, etc. Each as a separate identity easy to follow and develop. Only C based RTOS can match this. At this point I think it is important to get the basics implemented efficiently; else a lot of effort may be spent during library development to work around compiler limitations. Quote Whatever path you decide to go, I really think that you have already done a very nice job. Thumbs up!    Thanks.  I'm not a compiler dev so I don't really have any say in which direction FPC will go with AVR support. ---------------------------------------------------------------------- avra · 2017-12-14 13:13 Quote from: ccrause on December 13, 2017, 08:43:38 pmQuote from: avra on December 13, 2017, 11:11:29 amQuoteNote that there were some name clashes of different identifiers, hence I used s_ and m_ as prefixes for set element and bitmask names respectively.I still don't like e_ and m_ prefixes with underscores but I can live with them since it is pretty much subjective. Any alternative suggestions? I would like to adopt a naming convention that clearly relate to the standard bit name, but also indicate how the alternative identifier differs (bitmask, set element).Pascal users have already adopted single letter T prefix (as in TMyType) for type declarations, P prefix for pointers (as in PMyRecord), I prefix for interfaces (as in IMyInterface), and F prefix for fields (as in FMyField). I would exploit such habbit and naming convention, and simply extend it by defining X prefix for bits in a set (as xCF0A) and M prefix for bit masks (as mCF0A). And yes, I would prefer those two single letter prefixes to be lower case since that would visually more stand out during code completetion and ease distinction quite a bit. QuoteQuoteI didn't find type helpers for byte/word/dword/qword. Something like we have discussed previously. Do you have plans to add them as standard at all?My thought was that these will be generic helpers, so will sit in a separate unit.Well, initially I prefered individual type helpers for each set/record pair although that would bloat automatically generated cpu units a lot, but having a benefit to ease bit access and custom bit naming. However, after some thinking I might have found a solution so I could finally agree now that generic helper unit would be better. Here is an example of a solution. Let' say that we have a led on pin 5 of PORTB. Something like PORTBrec.PB5 := 1 would solve the problem, but naming that bit as MyLed and referencing it later in code as MyLed could not be made in a readable way. However, macros come to the rescue: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i {$MACRO ON}{$define MyLed := PORTBrec.PB5} // custom name alias  MyLed := 1; // using alias is more readable and intuitive compared to PORTBrec.PB5 := 1  if MyLed = 1 then    MyLed := 0; QuoteQuoteSince it is a 8-bit embedded world, assembly optimization will be needed in some of the libraries. It would be nice to decide what registers will never be used by the system and the system libraries, what registers would be used for function results, how to name register pairs, etc. I would suggest to make it compatible with AvrCo  The compiler follows the avr-libc convention.  Register naming follows Atmel's nomenclature (r0 - r31 and X, Y, Z for the upper 6 register pairs).That's fine with me. I would just flag about 6 register pairs as reserved for future use by the system. QuoteQuoteI am not quite sure how good would FPC optional register optimization work for AVR, and if we can force specific variables to be stored in registers (if enough free registers are available). Have you looked into this topic yet?A related discussion. I don't think binding a specific variable to a register is possible, but I don't know for sure.I do not see a problem with forcing variables to be stored into specific registers. A typical AT MEGA memory map starts with something like 0x0000 – 0x001F (registers R0 – R31). So all we need is to try it this way: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i var  R0: byte absolute $00; // these definitions should go to cpu unit  R1: byte absolute $01;  R2: byte absolute $02;  R3: byte absolute $03;  R4: byte absolute $04;  R5: byte absolute $05;  R6: byte absolute $06;  R7: byte absolute $07;  W0: word absolute $00;  W1: word absolute $02;  W2: word absolute $04;  W3: word absolute $06;  D0: dword absolute $00;  D1: dword absolute $04;  Q0: qword absolute $00;  // ... Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i var  MyByte: byte absolute R0; // these definitions go to user code  MyInt8: int8 absolute R1;  MyInt16: int16 absolute W1;  MyInt32: longint absolute D1;  MyFloat: single absolute D1; // on 8-bit cpu these can be even aligned to byteOf course we need to be extra carefull, but it is doable. I would also like to be able to define address after absolute keyword only on first variable, and then compiler takes care of all following variables having absolute keyword without address parameter. Unfortunatelly that is not possible with FPC, but sounds like a good candidate for a feature request. QuoteQuotePointers to internal and external ram, flash and eeprom would need to be treated somehow different. There are also AVRs with flash bigger then 64KB. Have you thought about such things yet?This is being debated.  It is currently possible to put data into flash or eeprom with the section modifier, but accessing the data requires some assembler at the moment.Using macros like {$define progmem := section '.progmem'} would beautify currently possible code mentioned in bugtracker "var x: byte; section '.progmem';". But even with such syntax section needs to be defined for each individual variable. I prefer AvrCo section syntax which has compiler defines valid for all variables until new section comes. Something like {$DATA} to assign the register area from $04 upto $1F, {$PDATA} to assign the IO fast access area from $20 upto $5F. {$IDATA} for area from $60 upto $25F. {$XDATA} for external sram memory (longer and slower machine commands often with wait states), {$EEPROM} for chip intern eeprom memory, and {$UDATA} for user defined area for which the programmer must supply a device driver. Address range is of course cpu dependent, and given example is for AVR 8515. As for SerialOut(ErrText), it is not a problem even with progmem and eeprom since AvrCo Write(SerOut, MyStringVarOrConst) function is quite general as it accepts any byte function instead of SerOut(), so reading from eeprom or progmem does not need to copy whole string to temporary buffer. Only one byte at a time is copied. ---------------------------------------------------------------------- ccrause · 2017-12-14 20:48 Quote from: avra on December 14, 2017, 02:13:13 pmPascal users have already adopted single letter T prefix (as in TMyType) for type declarations, P prefix for pointers (as in PMyRecord), I prefix for interfaces (as in IMyInterface), and F prefix for fields (as in FMyField). I would exploit such habbit and naming convention, and simply extend it by defining X prefix for bits in a set (as xCF0A) and M prefix for bit masks (as mCF0A). And yes, I would prefer those two single letter prefixes to be lower case since that would visually more stand out during code completetion and ease distinction quite a bit.So far e and m prefixes generate identifier clashes. s seems good to use for the set element names. QuoteI do not see a problem with forcing variables to be stored into specific registers. A typical AT MEGA memory map starts with something like 0x0000 – 0x001F (registers R0 – R31). So all we need is to try it this way: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i var  R0: byte absolute $00; // these definitions should go to cpu unit  R1: byte absolute $01;  // ...Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i var  MyByte: byte absolute R0; // these definitions go to user code Of course we need to be extra carefull, but it is doable. This concept does kind of work (except for r0: byte absolute 0;). The one problem remains the adopted ABI which in principle consume all general CPU registers. Another problem is the access to the underlying register via the variable - this requires LDS/STS instructions, which then needs to put the data into... some register . Probably useful for user code debugging tricks which dump register content, but not useful to speed up critical data access. QuoteI would also like to be able to define address after absolute keyword only on first variable, and then compiler takes care of all following variables having absolute keyword without address parameter. Unfortunatelly that is not possible with FPC, but sounds like a good candidate for a feature request.Has been possible in FPC trunk for a couple of months now. ---------------------------------------------------------------------- avra · 2017-12-15 20:13 Quote from: ccrause on December 14, 2017, 09:48:35 pmQuote from: avra on December 14, 2017, 02:13:13 pmPascal users have already adopted single letter T prefix (as in TMyType) for type declarations, P prefix for pointers (as in PMyRecord), I prefix for interfaces (as in IMyInterface), and F prefix for fields (as in FMyField). I would exploit such habbit and naming convention, and simply extend it by defining X prefix for bits in a set (as xCF0A) and M prefix for bit masks (as mCF0A). And yes, I would prefer those two single letter prefixes to be lower case since that would visually more stand out during code completetion and ease distinction quite a bit.So far e and m prefixes generate identifier clashes. s seems good to use for the set element names.I was advocating for more pascal like single letter prefix without underscore. That is not the case now. Quote from: ccrause on December 14, 2017, 09:48:35 pmQuoteI would also like to be able to define address after absolute keyword only on first variable, and then compiler takes care of all following variables having absolute keyword without address parameter. Unfortunatelly that is not possible with FPC, but sounds like a good candidate for a feature request.Has been possible in FPC trunk for a couple of months now.No, that's not what I meant. Maybe I didn't explain well. Here it is in code: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i   x: byte absolute $100;  y: word absolute; // this should automatically point to $101  z: float absolute; // this should automatically point to $103 That is not possible. I have just tried with today's trunk. ---------------------------------------------------------------------- ccrause · 2017-12-16 06:01 Quote from: avra on December 15, 2017, 09:13:40 pmQuote from: ccrause on December 14, 2017, 09:48:35 pmQuote from: avra on December 14, 2017, 02:13:13 pmPascal users have already adopted single letter T prefix (as in TMyType) for type declarations, P prefix for pointers (as in PMyRecord), I prefix for interfaces (as in IMyInterface), and F prefix for fields (as in FMyField). I would exploit such habbit and naming convention, and simply extend it by defining X prefix for bits in a set (as xCF0A) and M prefix for bit masks (as mCF0A). And yes, I would prefer those two single letter prefixes to be lower case since that would visually more stand out during code completetion and ease distinction quite a bit.So far e and m prefixes generate identifier clashes. s seems good to use for the set element names.I was advocating for more pascal like single letter prefix without underscore. That is not the case now. The reason I started using underscores was to avoid identifier clashes.  I'm in favour of your suggestion, I just need to go through a couple of iterations of picking prefixes, generate units, compile all units. ---------------------------------------------------------------------- ccrause · 2017-12-16 06:03 Quote from: avra on December 15, 2017, 09:13:40 pmCode: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i   x: byte absolute $100;  y: word absolute; // this should automatically point to $101  z: float absolute; // this should automatically point to $103 That is not possible. I have just tried with today's trunk. Ah, I see.  That is indeed not possible with current compiler.