* * *

Author Topic: AVR microcontroller unit format  (Read 9343 times)

ccrause

  • Full Member
  • ***
  • Posts: 118
Re: AVR microcontroller unit format
« Reply #30 on: November 05, 2017, 08:48:04 pm »
Thaddy, the toggle code in the type helper doesn't look great with the AVR compiler (it actually looks wrong):
Code: Pascal  [Select]
  1.   ADCSRA.Toggle(ADIE);
  2.   ae:   21 2d           mov     r18, r1
  3.   b0:   33 e0           ldi     r19, 0x03       ; 3
  4.   b2:   41 e0           ldi     r20, 0x01       ; 1
  5.   b4:   33 23           and     r19, r19
  6.   b6:   19 f0           breq    .+6             ; 0xbe <PASCALMAIN+0x20>
  7.   b8:   44 0f           add     r20, r20
  8.   ba:   3a 95           dec     r19
  9.   bc:   e9 f7           brne    .-6             ; 0xb8 <PASCALMAIN+0x1a>
  10.   be:   24 2b           or      r18, r20
  11.   c0:   30 91 7a 00     lds     r19, 0x007A
  12.   c4:   23 27           eor     r18, r19
  13.   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]
  1.   ADCSRA := ADCSRA >< [ADIE];
  2.   a2:   20 91 7a 00     lds     r18, 0x007A
  3.   a6:   38 e0           ldi     r19, 0x08       ; 8
  4.   a8:   23 27           eor     r18, r19
  5.   aa:   20 93 7a 00     sts     0x007A, r18

Edit: compiled with -O3
« Last Edit: November 05, 2017, 08:57:56 pm by ccrause »

Thaddy

  • Hero Member
  • *****
  • Posts: 6346
Re: AVR microcontroller unit format
« Reply #31 on: November 05, 2017, 10:13:03 pm »
@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]
  1.         eor     r4,r1,r0
Skipped loading, though, and did not profile yet.
« Last Edit: November 05, 2017, 10:25:29 pm by Thaddy »
I am enjoining wine, not whine....

ccrause

  • Full Member
  • ***
  • Posts: 118
Re: AVR microcontroller unit format
« Reply #32 on: November 06, 2017, 07:15:30 am »
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 bits
  • I 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) construct
  • I 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

  • Hero Member
  • *****
  • Posts: 1297
    • Additional info
Re: AVR microcontroller unit format
« Reply #33 on: November 15, 2017, 03:37:05 pm »
    • Many people in this thread indicated a preference for a more Object Pascal interface to the registers and bits
    +1

    Quote
    • I 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.

    Quote
    • 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) construct
    Only people copying some C code snippet might prefer to use such code. I would not make such change to avoid confusion for them.

    Quote
    • I 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.

    Quote
    • 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.
    code generator?

    I have just seen question about usage of volatile in another thread: https://forum.lazarus.freepascal.org/index.php/topic,38961.msg266000.html. 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: Volatility
    • Page 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 eeprom
    • Page 62: Definition of locked variables which will have interrupts disabled on access
    • Page 182: Boot vectors and boot traps
    • Page 41: Comparison with Delphi types
    • Page 39: Timers
    • Page 37: Semaphores and pipes
    • Page 54: Fuses
    • Page 69: Processes and Tasks
    • Page 77: Interrupts, Traps and Exceptions
    • Page 167: SysTick
    • Page 172: WatchDog
    • Page 195: Multitasking
    ct2laz - Conversion between Lazarus and CodeTyphon
    bithelpers - Bit manipulation for standard types
    pasettimino - Siemens S7 PLC lib

    Thaddy

    • Hero Member
    • *****
    • Posts: 6346
    Re: AVR microcontroller unit format
    « Reply #34 on: November 15, 2017, 04:05:19 pm »
    I have just seen question about usage of volatile in another thread: https://forum.lazarus.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....
    I am enjoining wine, not whine....

    ccrause

    • Full Member
    • ***
    • Posts: 118
    Re: AVR microcontroller unit format
    « Reply #35 on: November 20, 2017, 09:19:28 pm »
    So this is my first try at the fancy code generator:
    Code: Pascal  [Select]
    1. {$bitpacking on}{$packset 1}{$packenum 1}
    2. type
    3.   TBitField = 0..1;
    4.  
    5. var
    6.   PINB: byte absolute $23;  // Port B Input Pins
    7.   DDRB: byte absolute $24;  // Port B Data Direction Register
    8. type
    9.   TPORTBset = bitpacked set of (sPB0, sPB1, sPB2, sPB3, sPB4, sPB5, sPB6, sPB7);
    10.   TPORTBrec = bitpacked record
    11.     PB0,
    12.     PB1,
    13.     PB2,
    14.     PB3,
    15.     PB4,
    16.     PB5,
    17.     PB6,
    18.     PB7: TBitField;
    19.   end;
    20. var
    21.   PORTB: byte absolute $25;  // Port B Data Register
    22.   PORTBset: TPORTBset absolute $25;
    23.   PORTBrec: TPORTBrec absolute $25;
    24. const
    25.   PB0 = 0;
    26.   PB1 = 1;
    27.   PB2 = 2;
    28.   PB3 = 3;
    29.   PB4 = 4;
    30.   PB5 = 5;
    31.   PB6 = 6;
    32.   PB7 = 7;
    An example of a sparse register:
    Code: Pascal  [Select]
    1. type
    2.   TTIFR1set = bitpacked set of (sTOV1, sOCF1A, sOCF1B, sICF1=5);
    3.   TTIFR1rec = bitpacked record
    4.     TOV1,
    5.     OCF1A,
    6.     OCF1B,
    7.     reserved0,
    8.     reserved1,
    9.     ICF1,
    10.     reserved2,
    11.     reserved3: TBitField;
    12.   end;
    13. var
    14.   TIFR1: byte absolute $36;  // Timer/Counter Interrupt Flag register
    15.   TIFR1set: TTIFR1set absolute $36;
    16.   TIFR1rec: TTIFR1rec absolute $36;
    17. const
    18.   TOV1 = 0;  // Timer/Counter1 Overflow Flag
    19.   OCF1A = 1;  // Output Compare Flag 1A
    20.   OCF1B = 2;  // Output Compare Flag 1B
    21.   ICF1 = 5;  // Input Capture Flag 1
    I 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

    • Hero Member
    • *****
    • Posts: 2017
    Re: AVR microcontroller unit format
    « Reply #36 on: November 21, 2017, 03:29:52 am »
    I have just seen question about usage of volatile in another thread: https://forum.lazarus.freepascal.org/index.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

    • Hero Member
    • *****
    • Posts: 1297
      • Additional info
    Re: AVR microcontroller unit format
    « Reply #37 on: November 21, 2017, 10:45:06 am »
    So this is my first try at the fancy code generator:
    Code: Pascal  [Select]
    1. ...
    2.   PORTB: byte absolute $25;  // Port B Data Register
    3.   PORTBset: TPORTBset absolute $25;
    4.   PORTBrec: TPORTBrec absolute $25;
    5. ...
    I still prefer single letter prefix like sPORTB and rPORTB over PORTBset and PORTBrec, but these are also fine.

    Code: Pascal  [Select]
    1. ...
    2.   TTIFR1rec = bitpacked record
    3.     TOV1,
    4.     OCF1A,
    5.     OCF1B,
    6.     reserved0,
    7.     reserved1,
    8.     ICF1,
    9.     reserved2,
    10.     reserved3: TBitField;
    11.   end;
    12. ...
    13.  
    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]
    1.   TTIFR1rec = bitpacked record
    2.     TOV1,
    3.     OCF1A,
    4.     OCF1B,
    5.     ReservedBit3,
    6.     ReservedBit4,
    7.     ICF1,
    8.     ReservedBit6,
    9.     ReservedBit7: TBitField;
    10.   end;
    That should stand the test of time.
    « Last Edit: November 21, 2017, 10:57:56 am by avra »
    ct2laz - Conversion between Lazarus and CodeTyphon
    bithelpers - Bit manipulation for standard types
    pasettimino - Siemens S7 PLC lib

    marcov

    • Global Moderator
    • Hero Member
    • *****
    • Posts: 6323
    Re: AVR microcontroller unit format
    « Reply #38 on: November 21, 2017, 11:06:13 am »
    - 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

    • Full Member
    • ***
    • Posts: 118
    Re: AVR microcontroller unit format
    « Reply #39 on: November 21, 2017, 08:53:53 pm »
    marcov, avra, thanks for the feedback.  Changing the reserved bit naming is a non-issue; already changed to avra's suggestion.
     
    - 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]
    1. const OCF1A = 1;
    then there shouldn't be name clashes with registers due to the bit naming convention used by Atmel.
    - 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

    • Hero Member
    • *****
    • Posts: 1297
      • Additional info
    Re: AVR microcontroller unit format
    « Reply #40 on: November 21, 2017, 11:01:43 pm »
    I will add this as an extra set of constants with say a prefix of mXXX or perhaps mskXXX.
    +1 for mXXX

    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
    I 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.
    ct2laz - Conversion between Lazarus and CodeTyphon
    bithelpers - Bit manipulation for standard types
    pasettimino - Siemens S7 PLC lib

    ccrause

    • Full Member
    • ***
    • Posts: 118
    Re: AVR microcontroller unit format
    « Reply #41 on: December 08, 2017, 09:20:57 pm »
    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.
    « Last Edit: December 09, 2017, 05:29:14 am by ccrause »

    avra

    • Hero Member
    • *****
    • Posts: 1297
      • Additional info
    Re: AVR microcontroller unit format
    « Reply #42 on: December 13, 2017, 11:11:29 am »
    A preview of the auto generated AVR controller files have been prepared.
    Your ImportATDF automation tool does a very nice job.  8-)

    Quote
    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.
    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]
    1. uart_init1(...);
    2. fpc_shr_qword(...);
    3. fpc_div_mod_word(...);
    4. 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?
    :'( :-[ :-X ::)

    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]
    1. procedure fpc_div_mod_byte(Dividend, Divisor: byte; out result, remainder: byte);
    2. procedure fpc_div_mod_word(Dividend, Divisor: word; var result, remainder: word);
    3. procedure fpc_div_mod_dword(Dividend, Divisor: dword; var result, remainder: dword);
    4. 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.html#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]
    1.   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!   :D 8-) :D
    « Last Edit: December 13, 2017, 11:47:46 am by avra »
    ct2laz - Conversion between Lazarus and CodeTyphon
    bithelpers - Bit manipulation for standard types
    pasettimino - Siemens S7 PLC lib

    ccrause

    • Full Member
    • ***
    • Posts: 118
    Re: AVR microcontroller unit format
    « Reply #43 on: December 13, 2017, 08:43:38 pm »
    Quote
    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.
    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).

    Quote
    Code: Pascal  [Select]
    1. uart_init1(...);
    2. fpc_shr_qword(...);
    3. fpc_div_mod_word(...);
    4. 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]
    1. procedure fpc_div_mod_byte(Dividend, Divisor: byte; out result, remainder: byte);
    2. procedure fpc_div_mod_word(Dividend, Divisor: word; var result, remainder: word);
    3. procedure fpc_div_mod_dword(Dividend, Divisor: dword; var result, remainder: dword);
    4. 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).
    Quote
    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?
    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".

    Quote
    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
      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).
    Quote
    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?
    A related discussion. I don't think binding a specific variable to a register is possible, but I don't know for sure.
    Quote
    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?
    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.
    Quote
    How did you manage to do this in examples:
    Code: Pascal  [Select]
    1.   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.

    Quote
    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.
    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!   :D 8-) :D
    Thanks.  I'm not a compiler dev so I don't really have any say in which direction FPC will go with AVR support.
    « Last Edit: December 13, 2017, 08:45:38 pm by ccrause »

    avra

    • Hero Member
    • *****
    • Posts: 1297
      • Additional info
    Re: AVR microcontroller unit format
    « Reply #44 on: December 14, 2017, 02:13:13 pm »
    Quote
    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.
    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.

    Quote
    Quote
    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?
    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]
    1. {$MACRO ON}
    2. {$define MyLed := PORTBrec.PB5} // custom name alias
    3.   MyLed := 1; // using alias is more readable and intuitive compared to PORTBrec.PB5 := 1
    4.   if MyLed = 1 then
    5.     MyLed := 0;

    Quote
    Quote
    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
      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.

    Quote
    Quote
    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?
    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]
    1. var
    2.   R0: byte absolute $00; // these definitions should go to cpu unit
    3.   R1: byte absolute $01;
    4.   R2: byte absolute $02;
    5.   R3: byte absolute $03;
    6.   R4: byte absolute $04;
    7.   R5: byte absolute $05;
    8.   R6: byte absolute $06;
    9.   R7: byte absolute $07;
    10.   W0: word absolute $00;
    11.   W1: word absolute $02;
    12.   W2: word absolute $04;
    13.   W3: word absolute $06;
    14.   D0: dword absolute $00;
    15.   D1: dword absolute $04;
    16.   Q0: qword absolute $00;
    17.   // ...

    Code: Pascal  [Select]
    1. var
    2.   MyByte: byte absolute R0; // these definitions go to user code
    3.   MyInt8: int8 absolute R1;
    4.   MyInt16: int16 absolute W1;
    5.   MyInt32: longint absolute D1;
    6.   MyFloat: single absolute D1; // on 8-bit cpu these can be even aligned to byte
    Of 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.

    Quote
    Quote
    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?
    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.
    « Last Edit: December 14, 2017, 02:34:23 pm by avra »
    ct2laz - Conversion between Lazarus and CodeTyphon
    bithelpers - Bit manipulation for standard types
    pasettimino - Siemens S7 PLC lib

     

    Recent

    Get Lazarus at SourceForge.net. Fast, secure and Free Open Source software downloads Open Hub project report for Lazarus