Lazarus

Programming => Operating Systems => Embedded => Topic started by: devport on December 23, 2019, 11:48:19 am

Title: light pascal
Post by: devport on December 23, 2019, 11:48:19 am
Hello,
I was wondering if it is possible to use FPC (not object-oriented) without ballast in the form of system.pas etc.? The clean program weighs over 4kB from the very beginning, which with a memory size of 32kB is a large percentage of use.

I tried to replace the system.pas files with my versions, but the compiler constantly calls some structures that it uses.

the goal is to achieve output file ~ 1kB maybe less.
in ARM
Title: Re: light pascal
Post by: marcov on December 23, 2019, 01:06:33 pm
I assume the avr embedded targets are fairly tight ?

Title: Re: light pascal
Post by: MarkMLl on December 23, 2019, 01:34:45 pm
I was thinking that referring to them as a template might be a good starting point.

MarkMLl
Title: Re: light pascal
Post by: marcov on December 23, 2019, 01:40:27 pm
For the desperate there is also

https://www.muppetlabs.com/~breadbox/software/tiny/teensy.html

but there they also bypass binutils and resort to assembler directly.
Title: Re: light pascal
Post by: six1 on December 23, 2019, 01:50:13 pm
...but marcov,
his statement at the end is:
Here, at last, we have honestly gone as far as we can go. There is no getting around the fact that the 45th byte in the file, which specifies the number of entries in the program header table, needs to be non-zero, needs to be present, and needs to be in the 45th position from the start of the ELF header. We are forced to conclude that there is nothing more that can be done.

...can't belive it will be 45... it must be 42   :D


none insiders must read this:
https://en.wikipedia.org/wiki/Phrases_from_The_Hitchhiker%27s_Guide_to_the_Galaxy#Answer_to_the_Ultimate_Question_of_Life,_the_Universe,_and_Everything_(42)
Title: Re: light pascal
Post by: MarkMLl on December 23, 2019, 03:07:01 pm
Quote
The King then read from his book: "Rule forty-two. _All persons more
than a mile high to leave the court_."

Non-insiders should give precedence to "Alice in Wonderland" which has been around rather longer :-)

MarkMLl
Title: Re: light pascal
Post by: devport on December 23, 2019, 03:10:26 pm
OK, I came to some conclusions without having to get rid of system.pas files etc.

The use of STR in the program increases the size by an average of 4kB !!! (at least that's how I observe)

Using the string variable in function passing increases the result code by ~ 800B once. I must use VAR (reference) reduce the amount of generated code.

In general, I come to the conclusion that most of the optimizations should be kept on my side, not the compiler. So the compiler does as I command it.
Title: Re: light pascal
Post by: marcov on December 23, 2019, 05:50:09 pm
Note that such growth tapers off quickly once all language string helper have been used.

Any way, it is hard to suggest anything since you don't explain what exactly you need it for.
Title: Re: light pascal
Post by: devport on December 23, 2019, 07:07:26 pm
I have written a similar program in C for uC Cortex-M0. And my point is that in Pascal I haven't even achieved half of the functionality, and I'm already exceeding 5kB Flash more than the one written in C.

It worries me very much
I am slowly beginning to come to the conclusion that Pascal is not suitable for writing in microcontrollers.
 :(

I have big problems writing in this language ... I do the same thing as in C, and yet I encounter Hard Fault more often than I did in C.

For example:
Code: Pascal  [Select][+][-]
  1. function Int_To_Str(buf : PChar; x : smallint):word;
  2. var
  3.   buff : array[0..5] of char;
  4.   p : PChar;
  5.   size : longint;
  6.  value : smallint;
  7. begin
  8.   Result := 0;
  9.   p := @buff;
  10.   value := x;
  11.   size := longint(buf);
  12.  
  13.   if(value < 0) then begin
  14.     buf^ := '-';
  15.     Inc(buf);
  16.     value := -value;
  17.   end;
  18.  
  19.   if(value = 0) then begin
  20.     buf^ := '0';
  21.     Inc(buf);
  22.     exit;
  23.   end;
  24.  
  25.   while(value > 0) do begin
  26.     p^ := char(value mod 10 + Ord('0'));
  27.     value := value div 10;
  28.     inc(p);
  29.   end;
  30.  
  31.   while p <> @buff do begin
  32.     dec(p);
  33.     buf^ := p^;
  34.     inc(buf);
  35.   end;
  36.  
  37.   size := longint(buf)- size;
  38.   Result := word(size);
  39. end;

If Call where
Code: Pascal  [Select][+][-]
  1. var
  2. st : string;
  3. begin
  4.  Int_To_Str(@st, 20);  
  5. end.

i get Hard Fault in line " buf^ := p^ "
Any attempt to write to 'buf ^' results in an error.
In C compiller this function it works.

STR I don't want to use because it weighs a lot :/ and requires heapmgr.pas (more kB)
Title: Re: light pascal
Post by: MiR on December 23, 2019, 07:23:49 pm
I think you are on the right track now, if you really want to bring down code size you have to check your every move and it's costs.

Strings are very expensive both as ansistrings (possible for e.g. arm, mips targets), there you will in most cases need to add heapmgr (Hint! Hint!) to make them properly work and the code for handling them is quite complex (--> big)
and also as shortstrings (avr) where they consume 256 bytes of precious ram on your stack for every function call that uses strings. Take a look at a function that concats two strings and returns the result, and while doing that say goodbye to 768 bytes of precious stack....

Also, for example using classes also increases code size, they need heapmgr and precious RAM is also used by VMT's when virtual methods are used.

The list goes on, when you want to keep codesize down you need to always check the generated assembler code and prepare for surprises :) 

The question I always ask myself is WHY people today choose severely cpu and memory limited chips for freepascal...

I can understand it from the educational aspect, you learn a lot when trying to squeeze complex code into 32kb of Flash, but how many of the people using such a small system actually want to go through this learning curve?

There are quite capable and cheap boards out there in the sub-10$ range that offer 64-128kb of flash (look for STM32F103C8T6 or maple mini) and come with a stlinkv2 compatible debugger, there are even more capable boards with STM32F4 Chips (search for STM32F411CEU6) with 128kb RAM and 512kb Flash or ATSAMD21 Boards like Arduino-Zero or clones.

Thoses Chipsets eat through most of the limitations that come with todays freepascal, they have enough flash for some not so optimized code and they have enough CPU power to easily execute the complex string methods in freepascal.

Please do not misunderstand me, I like the smell of freshly generated assembler output of fpc, but I ask myself does everybody want to start that hard?

One could argue that AVR chips and older Arm Chips are easier to understand because of less complexity, but is this really true?
Me, I do not think so, you can also start simple with newer arm or mips chips, but there's a lot more (like DMA, advanced timers) that comes in handy once you have mastered the basics and start with the more challenging stuff.
But until that point you have already had a lot of fun with blinking LED's, OLED-Displays or whatever without hitting the out of RAM/Flash-Memory wall even once.

Michael
Title: Re: light pascal
Post by: marcov on December 23, 2019, 07:31:59 pm
I have written a similar program in C for uC Cortex-M0. And my point is that in Pascal I haven't even achieved half of the functionality, and I'm already exceeding 5kB Flash more than the one written in C.

With such constraints you indeed need to lay off the automated types. (though I would avoid textual I/O in microcontrollers in general)

Quote
It worries me very much
I am slowly beginning to come to the conclusion that Pascal is not suitable for writing in microcontrollers.

Pascal and C are nearly equivalent in theoretical performance. The difference is more in the amount and quality of compilers and what their optimization targets are.

Free Pascal's Object Pascal is like C++. It is high level language, but the lowlevel (in C++ case: C) still lives there.

Just like that, rock bottom Pascal is like C without macros. (iow #define only for constants).

You will need to learn to adjust the level

Quote
I have big problems writing in this language ... I do the same thing as in C, and yet I encounter Hard Fault more often than I did in C.

It could be a compiler bug, but 9 to 10 this is some mistake you made. If you are less proficient in embedded Pascal that can happen. Stay critical and try to isolate the problem. It could be as little as translating char  buff[5] into array[0..5] of char; {1 char more!}


Title: Re: light pascal
Post by: valdir.marcos on December 23, 2019, 07:45:13 pm
I have written a similar program in C for uC Cortex-M0. And my point is that in Pascal I haven't even achieved half of the functionality, and I'm already exceeding 5kB Flash more than the one written in C.
With such constraints you indeed need to lay off the automated types. (though I would avoid textual I/O in microcontrollers in general)
Quote
It worries me very much
I am slowly beginning to come to the conclusion that Pascal is not suitable for writing in microcontrollers.
Pascal and C are nearly equivalent in theoretical performance. The difference is more in the amount and quality of compilers and what their optimization targets are.
Free Pascal's Object Pascal is like C++. It is high level language, but the lowlevel (in C++ case: C) still lives there.
Just like that, rock bottom Pascal is like C without macros. (iow #define only for constants).
You will need to learn to adjust the level
Quote
I have big problems writing in this language ... I do the same thing as in C, and yet I encounter Hard Fault more often than I did in C.
It could be a compiler bug, but 9 to 10 this is some mistake you made. If you are less proficient in embedded Pascal that can happen. Stay critical and try to isolate the problem. It could be as little as translating char  buff[5] into array[0..5] of char; {1 char more!}
Could PicPas example help this discussion?
PicPas, Pascal compiler for Microchip PIC
https://forum.lazarus.freepascal.org/index.php/topic,36595.0.html
https://github.com/t-edson/PicPas
Title: Re: light pascal
Post by: devport on December 23, 2019, 07:46:48 pm
However, I will not give up without a fight yet. : P
I will learn the behavior of the Pascal compiler and correct my code first.
Title: Re: light pascal
Post by: devport on December 23, 2019, 07:53:51 pm
PicPas, For me, this is a good approach to programming microcontrollers. I thought about it myself in the context of ARM Cortex ;D
Title: Re: light pascal
Post by: MarkMLl on December 23, 2019, 08:32:20 pm
To be honest, I don't think it's fair comparing Pascal against C on account of the implicit complexity (support for finally blocks etc.) that Pascal carries around even if strings etc. aren't used.

It's only marginally fair to compare Pascal against C++ (with managed strings support) on account of the flexibility that C/C++ have to recompile stuff rather than making do with precompiled "one size fits all" units.

MarkMLl
Title: Re: light pascal
Post by: lucamar on December 23, 2019, 08:33:39 pm
i get Hard Fault in line " buf^ := p^ "
Any attempt to write to 'buf ^' results in an error.

The notation something^ applies only to a pointer: it's meant to dereference it. Your buf variable, though, is an array: you should access/set it by using an index into the array, as in:
buf[x] := p^

In C it's different because an "array" is almost exactly the same as a pointer.
Title: Re: light pascal
Post by: valdir.marcos on December 23, 2019, 08:37:22 pm
I have written a similar program in C for uC Cortex-M0. And my point is that in Pascal I haven't even achieved half of the functionality, and I'm already exceeding 5kB Flash more than the one written in C.
With such constraints you indeed need to lay off the automated types. (though I would avoid textual I/O in microcontrollers in general)
Quote
It worries me very much
I am slowly beginning to come to the conclusion that Pascal is not suitable for writing in microcontrollers.
Pascal and C are nearly equivalent in theoretical performance. The difference is more in the amount and quality of compilers and what their optimization targets are.
Free Pascal's Object Pascal is like C++. It is high level language, but the lowlevel (in C++ case: C) still lives there.
Just like that, rock bottom Pascal is like C without macros. (iow #define only for constants).
You will need to learn to adjust the level
Quote
I have big problems writing in this language ... I do the same thing as in C, and yet I encounter Hard Fault more often than I did in C.
It could be a compiler bug, but 9 to 10 this is some mistake you made. If you are less proficient in embedded Pascal that can happen. Stay critical and try to isolate the problem. It could be as little as translating char  buff[5] into array[0..5] of char; {1 char more!}
Older and simpler Pascal implementations prior to Free Pascal would be more appropriate to beat C results in this case?
Title: Re: light pascal
Post by: MarkMLl on December 23, 2019, 09:32:43 pm
Older and simpler Pascal implementations prior to Free Pascal would be more appropriate to beat C results in this case?

No, because Pascal has always- from day one- had up-level addressing and better handling of strings than C has.

I think it would be interesting, though, if there were some way of /completely/ disabling "Delphi-style" strings, and running FPC (with a subset of units/packages) with only "classical" Pascal strings (size predeclared, length in element

MarkMLl
Title: Re: light pascal
Post by: marcov on December 23, 2019, 10:36:54 pm
Older and simpler Pascal implementations prior to Free Pascal would be more appropriate to beat C results in this case?

First, there is no universal "C". Some C compilers optimize for size (e.g. Keile), some not.

And no. My remark was primarily about using the optimal subsets, and only secondarily about compiler selection. If you use the wrong subset (e.g. TP4 has a string[] and goes back to 1989 or so), then you still will be bulky.
Title: Re: light pascal
Post by: FPK on December 24, 2019, 12:21:31 am
*sigh* again the myth of the large binaries. An empty program for avr25 results in

<fpc trunk for avr> -Wpattiny28 tavr.pp -O4
Free Pascal Compiler version 3.3.1 [2019/12/24] for avr
Copyright (c) 1993-2019 by Florian Klaempfl and others
Target OS: Embedded
Compiling tavr.pp
Assembling program
Linking tavr
2 lines compiled, 0.0 sec, 38 bytes code, 0 bytes data

The 38 bytes come from the interrupt handlers.
Title: Re: light pascal
Post by: MarkMLl on December 24, 2019, 09:35:14 am
*sigh* again the myth of the large binaries. An empty program for avr25 results in
...
Linking tavr
2 lines compiled, 0.0 sec, 38 bytes code, 0 bytes data

The 38 bytes come from the interrupt handlers.

No myth at all: his complaint was about ARM. Somebody else made the point that perhaps comparing with AVR would be worthwhile.

MarkMLl
Title: Re: light pascal
Post by: Thaddy on December 24, 2019, 09:46:58 am
No myth at all: his complaint was about ARM. Somebody else made the point that perhaps comparing with AVR would be worthwhile.

MarkMLl
ARM embedded has similar sizes. But don't expect a Raspberry Pi with a full Debian as embedded. It will have the same overhead that comes with a full OS.
That's a trap less experienced programmers always fall into,
Title: Re: light pascal
Post by: MarkMLl on December 24, 2019, 10:10:14 am
@Thaddy: Good point.

MarkMLl
Title: Re: light pascal
Post by: PascalDragon on December 24, 2019, 10:36:06 am
I think it would be interesting, though, if there were some way of /completely/ disabling "Delphi-style" strings, and running FPC (with a subset of units/packages) with only "classical" Pascal strings (size predeclared, length in element
  • , absolute limit of 256 8-bit characters) and possibly with no compiler support for finalisation blocks and exceptions. /If/ that could be done, then it would be possible to compare against say TP5 and against various Modula-2 compilers which as I understand it had well-regarded optimisation (because the user was giving the compiler a bit more information about what he was trying to do).
You don't need some way to disable Delphi-style strings, because if you don't use them, then the compiler and linker won't include the corresponding functionality (this is especially true for the embedded target). Same for implicit exception frames: if you don't use managed types then the implicit frames won't be generated.
Also for the embedded target one can explicitely decide which features should be enabled when compiling the RTL (take a look at $fpcdir/rtl/embedded/system.cfg), thus avoiding that it's used by accident.

i get Hard Fault in line " buf^ := p^ "
Any attempt to write to 'buf ^' results in an error.

The notation something^ applies only to a pointer: it's meant to dereference it. Your buf variable, though, is an array: you should access/set it by using an index into the array, as in:
buf[x] := p^

In C it's different because an "array" is almost exactly the same as a pointer.
Take a look at the code again. buf is an input argument of type PChar and p is a pointer to the local array buff.

*sigh* again the myth of the large binaries. An empty program for avr25 results in

<fpc trunk for avr> -Wpattiny28 tavr.pp -O4
Free Pascal Compiler version 3.3.1 [2019/12/24] for avr
Copyright (c) 1993-2019 by Florian Klaempfl and others
Target OS: Embedded
Compiling tavr.pp
Assembling program
Linking tavr
2 lines compiled, 0.0 sec, 38 bytes code, 0 bytes data

The 38 bytes come from the interrupt handlers.

The point you mentioned is empty program. But once users start to use more features that size obviously increases. So they need to monitor what they use so that they don't break any size constraints.
Title: Re: light pascal
Post by: lucamar on December 24, 2019, 11:41:35 am
i get Hard Fault in line " buf^ := p^ "
Any attempt to write to 'buf ^' results in an error.

The notation something^ applies only to a pointer: it's meant to dereference it. Your buf variable, though, is an array: you should access/set it by using an index into the array, as in:
buf[x] := p^

In C it's different because an "array" is almost exactly the same as a pointer.
Take a look at the code again. buf is an input argument of type PChar and p is a pointer to the local array buff.

Oops! You're right, of course. I mistook buff and buf :-[
Title: Re: light pascal
Post by: julkas on December 24, 2019, 11:47:32 am
*sigh* again the myth of the large binaries. An empty program for avr25 results in

<fpc trunk for avr> -Wpattiny28 tavr.pp -O4
Free Pascal Compiler version 3.3.1 [2019/12/24] for avr
Copyright (c) 1993-2019 by Florian Klaempfl and others
Target OS: Embedded
Compiling tavr.pp
Assembling program
Linking tavr
2 lines compiled, 0.0 sec, 38 bytes code, 0 bytes data

The 38 bytes come from the interrupt handlers.
I think without real life project (working code) we can't make objective discussion.
Title: Re: light pascal
Post by: Hartmut on December 24, 2019, 12:13:25 pm
Also for the embedded target one can explicitely decide which features should be enabled when compiling the RTL (take a look at $fpcdir/rtl/embedded/system.cfg), thus avoiding that it's used by accident.

In FPC 3.0.4 I did not find a system.cfg in this folder, but a rtl.cfg. Do you mean this?
Title: Re: light pascal
Post by: julkas on December 24, 2019, 12:27:50 pm
Also for the embedded target one can explicitely decide which features should be enabled when compiling the RTL (take a look at $fpcdir/rtl/embedded/system.cfg), thus avoiding that it's used by accident.

In FPC 3.0.4 I did not find a system.cfg in this folder, but a rtl.cfg. Do you mean this?
Check trunk
Title: Re: light pascal
Post by: devport on December 24, 2019, 12:51:43 pm
OKEY

Gentlemen, and perhaps Lady's, I have already partly understood the operation of the FPC compiler and this action is beginning to suit me. I wouldn't want to create an unnecessary storm here. From now on, I check 2x how the code I write affects the size of the output.
It was my inexperience with this compiler that gave rise to this topic. I apologize in advance.
Title: Re: light pascal
Post by: MarkMLl on December 24, 2019, 12:59:41 pm
It was my inexperience with this compiler that gave rise to this topic. I apologize in advance.

Don't. Unless it really is an FAQ, raising an issue which results in core developers updating the rest of us on the state of the art is always valuable.

MarkMLl
Title: Re: light pascal
Post by: PascalDragon on December 24, 2019, 02:09:07 pm
Also for the embedded target one can explicitely decide which features should be enabled when compiling the RTL (take a look at $fpcdir/rtl/embedded/system.cfg), thus avoiding that it's used by accident.

In FPC 3.0.4 I did not find a system.cfg in this folder, but a rtl.cfg. Do you mean this?
In 3.0.4 it's indeed the rtl.cfg. For trunk that was changed to system.cfg which is used to compile the System unit and rtl.cfg which is used for the remainder of the RTL (currently only used for i8086 to ensure that smartlinking is enabled) as the enabled features are now stored in the System unit.
Title: Re: light pascal
Post by: FPK on December 24, 2019, 11:33:59 pm
*sigh* again the myth of the large binaries. An empty program for avr25 results in

<fpc trunk for avr> -Wpattiny28 tavr.pp -O4
Free Pascal Compiler version 3.3.1 [2019/12/24] for avr
Copyright (c) 1993-2019 by Florian Klaempfl and others
Target OS: Embedded
Compiling tavr.pp
Assembling program
Linking tavr
2 lines compiled, 0.0 sec, 38 bytes code, 0 bytes data

The 38 bytes come from the interrupt handlers.

The point you mentioned is empty program.

Of course, I did so, because this is the example people typically use trying to make their point.
Title: Re: light pascal
Post by: julkas on December 25, 2019, 10:37:46 am
OKEY
From now on, I check 2x how the code I write affects the size of the output.
My first working FPC AVR target port (without strings, advanced records, heap, ...) http://elm-chan.org/fsw/ff/00index_p.html  - hex image size is ~ 9k vs C ~ 2 - 4k.
Title: Re: light pascal
Post by: FPK on December 25, 2019, 04:32:06 pm
OKEY
From now on, I check 2x how the code I write affects the size of the output.
My first working FPC AVR target port (without strings, advanced records, heap, ...) http://elm-chan.org/fsw/ff/00index_p.html  - hex image size is ~ 9k vs C ~ 2 - 4k.

Not unlikely for a first try. Pascal is not C and some innocent looking code might pull in unwanted parts of the RTL. I hope you checked the map file for such problems?
Title: Re: light pascal
Post by: Laksen on December 25, 2019, 05:31:51 pm
Did you use trunk? The newest doesn't pull in exception handling for divisions/modulus by constants for example
Title: Re: light pascal
Post by: devport on December 25, 2019, 05:48:11 pm
I'm using build from December 22, 2019
Title: Re: light pascal
Post by: julkas on December 25, 2019, 07:25:02 pm
Did you use trunk? The newest doesn't pull in exception handling for divisions/modulus by constants for example
Code: Text  [Select][+][-]
  1. $  ppcrossavr.exe -i
  2. Free Pascal Compiler version 3.3.1
  3.  
  4. Compiler date      : 2019/09/22
  5. Compiler CPU target: avr
  6.  
Any reason for update?
Title: Re: light pascal
Post by: Thaddy on December 26, 2019, 08:54:55 am
2019/09/22 is not exactly new is it? Trunk is a moving target and if you want to use it, plz compile on a daily basis, not three monthly.
Title: Re: light pascal
Post by: julkas on January 01, 2020, 02:32:37 pm
2019/09/22 is not exactly new is it? Trunk is a moving target and if you want to use it, plz compile on a daily basis, not three monthly.
After update -
Code: Text  [Select][+][-]
  1. $  ppcrossavr.exe -i
  2. Free Pascal Compiler version 3.3.1
  3.  
  4. Compiler date      : 2020/01/01
  5. Compiler CPU target: avr
  6.  
Code: Text  [Select][+][-]
  1. 2120 lines compiled, 0.4 sec, 9694 bytes code, 539 bytes data
  2.  

Any hint, advice?

Happy New Year to great Pascal community !

BTW - Careful with whitespaces on Windows !
Title: Re: light pascal
Post by: FPK on January 01, 2020, 03:35:15 pm
Pascal is not C and some innocent looking code might pull in unwanted parts of the RTL. I hope you checked the map file for such problems?
Title: Re: light pascal
Post by: Laksen on January 01, 2020, 04:04:44 pm
Show the code that generates that much
Title: Re: light pascal
Post by: julkas on January 01, 2020, 04:10:48 pm
Show the code that generates that much
https://github.com/JulStrat/pff/tree/devop/examples/arduino
Title: Re: light pascal
Post by: d.ioannidis on January 09, 2020, 10:41:14 pm
Did you use trunk? The newest doesn't pull in exception handling for divisions/modulus by constants for example
< snip >
Any reason for update?

Well for this example, a TX-only software ( bit-bang'ed ) UART for attiny85 I had ( if I remember correctly, don't have a 3.0.4 ppcrossavr handy ) approx. ~20% size reduction :

Code: Pascal  [Select][+][-]
  1. // bit bang'ing Software-UART TX example
  2. //
  3. // Adapted / Ported from
  4. //
  5. // a tiny software UART TX for the AVR ATtiny
  6. // https://marcelmg.github.io/software_uart/
  7.  
  8. program fp_attiny85_test;
  9.  
  10. {$MODE OBJFPC}
  11. {$MACRO ON}
  12. {$INLINE ON}
  13. {$LONGSTRINGS OFF}
  14. {$WRITEABLECONST OFF}
  15.  
  16. // Timer interrupt service routine name.
  17. {$DEFINE TIMER_INT := 'TIMER0_COMPA_ISR'}
  18.  
  19. // Change these to use another pin.
  20. {$DEFINE TX_PORT    := PORTB }
  21. {$DEFINE TX_PIN     := 0     }
  22. {$DEFINE TX_DDR     := DDRB  }
  23. {$DEFINE TX_DDR_PIN := 0     }
  24.  
  25. uses
  26.   intrinsics;
  27.  
  28. // Read directly from flash and not from SRAM.
  29. // HAS_LPMX also means that movw is available.
  30. {$if defined(CPUAVR_HAS_LPMX)}
  31. const
  32.   HelloWorldStr: string[14] = 'Hello World ! '; section '.progmem';
  33.   FPCStr: string[22] = 'Free Pascal Rocks !!! '; section '.progmem';
  34.  
  35.   function read_progmem_byte(constref v: byte): byte; assembler; nostackframe;
  36.   asm
  37.     MOVW    ZL, r24
  38.     LPM     r24, Z
  39.   end;
  40.  
  41.   function read_progmem_str(constref s: shortstring): ShortString;
  42.   var
  43.     len, i: byte;
  44.   begin
  45.     len := read_progmem_byte(byte(s[0]));
  46.     setlength(Result, len);
  47.     for i := 1 to len do
  48.       Result[i] := char(read_progmem_byte(byte(s[i])));
  49.   end;
  50. {$ENDIF}
  51.  
  52.   procedure AtomicWrite(var Value: word; new_value: word);
  53.   var
  54.     b: byte;
  55.   begin
  56.     b := avr_save;
  57.     Value := new_value;
  58.     avr_restore(b);
  59.   end;
  60.  
  61.   function AtomicRead(var Value: word): word;
  62.   var
  63.     b: byte;
  64.   begin
  65.     b := avr_save;
  66.     Result := Value;
  67.     avr_restore(b);
  68.   end;
  69.  
  70. var
  71.   // Used as a TX shift register.
  72.   tx_shift_reg: word;
  73.  
  74.   function UART_tx(constref ACharacter: char): boolean;
  75.   var
  76.     local_tx_shift_reg: word;
  77.   begin
  78.     Result := True;
  79.     local_tx_shift_reg := AtomicRead(tx_shift_reg);
  80.  
  81.     // Check if sending the previous character is not yet finished.
  82.     // Transmission is finished when tx_shift_reg = 0.
  83.     if local_tx_shift_reg <> 0 then
  84.       Result := False
  85.     else
  86.     begin
  87.  
  88.       // Fill the TX shift register with the character to be sent and
  89.       // the start & stop bits (start bit (1<<0) is already 0).
  90.       local_tx_shift_reg := (word(ACharacter) shl 1) or (1 shl 9);
  91.       AtomicWrite(tx_shift_reg, local_tx_shift_reg);
  92.  
  93.       // Start Timer0 with a prescaler of 8.
  94.       TCCR0B := (1 shl CS0 + 1);
  95.     end;
  96.   end;
  97.  
  98.   procedure UART_tx_str(constref AString: ShortString);
  99.   var
  100.     iLen, x: byte;
  101.   begin
  102.     iLen := Length(AString);
  103.     x := 1;
  104.     while (iLen >= x) do
  105.       // Send the next character after the
  106.       // the previous character transmission is finished.
  107.       if UART_tx(AString[x]) then
  108.         Inc(x);
  109.   end;
  110.  
  111.   procedure UART_init;
  112.   begin
  113.     // Set TX pin as output.
  114.     TX_DDR := TX_DDR or (1 shl TX_DDR_PIN);
  115.     TX_PORT := TX_PORT or (1 shl TX_PIN);
  116.  
  117.     // Set Timer0 to CTC mode.
  118.     TCCR0A := (1 shl WGM0 + 1);
  119.  
  120.     // Enable output compare 0 A interrupt.
  121.     TIMSK := TIMSK or (1 shl OCF0A);
  122.  
  123.     // Set compare value to 103 to achieve a 9600 baud rate (i.e. 104µs),
  124.     // together with the 8MHz/8=1MHz Timer0 clock.
  125.     {NOTE: since the internal 8MHz oscillator is not very accurate, this value can be tuned
  126.       to achieve the desired baud rate, so if it doesn't work with the nominal value (103), try
  127.       increasing or decreasing the value by 1 or 2 }
  128.     OCR0A := 103;
  129.   end;
  130.  
  131.   procedure TIMER0_COMPA_ISR; public Name TIMER_INT; Interrupt;
  132.   begin
  133.     // Output LSB of the TX shift register at the TX pin.
  134.     if (tx_shift_reg and 1) = 1 then
  135.       TX_PORT := TX_PORT or (1 shl TX_PIN)
  136.     else
  137.       TX_PORT := TX_PORT and not (1 shl TX_PIN);
  138.  
  139.     // Shift the TX shift register one bit to the right.
  140.     tx_shift_reg := (tx_shift_reg shr 1);
  141.  
  142.     // If the stop bit has been sent, the shift register will be 0
  143.     // and the transmission is completed, so we can stop & reset Timer0.
  144.     if tx_shift_reg = 0 then
  145.     begin
  146.       TCCR0B := 0;
  147.       TCNT0 := 0;
  148.     end;
  149.   end;
  150.  
  151.   // Generated by delay loop calculator
  152.   // at http://www.bretmulvey.com/avrdelay.html
  153.  
  154.   // Delay 4 000 000 cycles
  155.   // 500ms at 8.0 MHz
  156.   procedure _delay_loop; assembler; nostackframe;
  157.   label
  158.     L1;
  159.   asm
  160.     LDI     r18, 21
  161.     LDI     r19, 75
  162.     LDI     r20, 191
  163.   L1:
  164.     DEC     r20
  165.     BRNE    L1
  166.     DEC     r19
  167.     BRNE    L1
  168.     DEC     r18
  169.     BRNE    L1
  170.     NOP
  171.   end;
  172.  
  173. begin
  174.   UART_init;
  175.  
  176.   // Enable Global Interrupts.
  177.   avr_sei;
  178.  
  179.   repeat
  180. // Read directly from flash and not from SRAM.
  181. // HAS_LPMX also means that movw is available.
  182. {$if defined(CPUAVR_HAS_LPMX)}
  183.     UART_tx_str(read_progmem_str(HelloWorldStr));
  184.     UART_tx_str(read_progmem_str(FPCStr));
  185. {$elseif}
  186.     UART_tx_str('Hello World ! ');
  187.     UART_tx_str('Free Pascal Rocks !!! ');
  188. {$endif}
  189.     _delay_loop;
  190.   until False;
  191. end.    

Project build options

Code: Pascal  [Select][+][-]
  1. -Tembedded
  2. -Pavr
  3. -MObjFPC
  4. -Scghi
  5. -CX
  6. -Os4
  7. -gt
  8. -Xs
  9. -XX
  10. -l
  11. -vewnhibq
  12. -Fi..\lib\avr-embedded
  13. -Fu..\source
  14. -Fu.
  15. -FU..\lib\avr-embedded
  16. -FE..\bin
  17. -o..\bin\fp_attiny85_test
  18. -a
  19. -al
  20. -Xe
  21. -Xm
  22. -Sm
  23. -CpAVR25
  24. -WpATTINY85
  25. -XPavr-
  26. -FDG:\Programming\dimitris\tools\avr8-gnu-toolchain\bin
  27. -dF_CPU:=8000000
  28.  


and avrsize reports :

Code: Pascal  [Select][+][-]
  1. Compile Project, Mode: Release, OS: embedded, CPU: avr, Target: G:\Programming\dimitris\Projects\fp_attiny85_test\bin\fp_attiny85_test: Success, Hints: 1
  2. fp_attiny85_test.lpr(131,13) Hint: Local proc "TIMER0_COMPA_ISR" is not used
  3. Project: Executing command after: Success
  4. AVR Memory Usage
  5. ----------------
  6. Device: attiny85
  7.  
  8. Program:     626 bytes (7.6% Full)
  9. (.text + .data + .bootloader)
  10.  
  11. Data:          2 bytes (0.4% Full)
  12. (.data + .bss + .noinit)

FPC Compiler builded with OPT="-O1 -CX -XX" :
Code: Pascal  [Select][+][-]
  1. FPC executable:
  2. Compiler=G:\Programming\dimitris\tools\fpc-trunk\bin\x86_64-win64\fpc.exe
  3. Options=
  4. CompilerDate=5/1/2020 20:00:02
  5. RealCompiler=G:\Programming\dimitris\tools\fpc-trunk\bin\x86_64-win64\ppcrossavr.exe
  6. RealCompilerDate=8/1/2020 20:18:24
  7. RealTargetOS=embedded
  8. RealTargetCPU=avr
  9. RealCompilerInPath=G:\Programming\dimitris\tools\fpc-trunk\bin\x86_64-win64\ppcrossavr.exe
  10. Version=3.3.1
  11. CfgFilename=G:\Programming\dimitris\tools\fpc-trunk\bin\x86_64-win64\fpc.cfg
Title: Re: light pascal
Post by: julkas on January 13, 2020, 03:10:30 pm
*sigh* again the myth of the large binaries. An empty program for avr25 results in

<fpc trunk for avr> -Wpattiny28 tavr.pp -O4
Free Pascal Compiler version 3.3.1 [2019/12/24] for avr
Copyright (c) 1993-2019 by Florian Klaempfl and others
Target OS: Embedded
Compiling tavr.pp
Assembling program
Linking tavr
2 lines compiled, 0.0 sec, 38 bytes code, 0 bytes data

The 38 bytes come from the interrupt handlers.

Try following -
Code: Pascal  [Select][+][-]
  1. program tt;
  2.  
  3. var
  4.   x: DWORD;
  5.  
  6. begin
  7.   x := x div 17;
  8. end.  

Result - I think it's not acceptable
Code: Text  [Select][+][-]
  1. $ ppcrossavr.exe -Tembedded -Cpavr5 -vi -aln -Wpatmega328p -XPavr- -O3 -Xm tt.pas
  2. Target OS: Embedded
  3. Compiling tt.pas
  4. Assembling tt
  5. Linking tt
  6. 7 lines compiled, 0.1 sec, 1814 bytes code, 50 bytes data
Title: Re: light pascal
Post by: FPK on January 13, 2020, 09:08:13 pm
Whether it is acceptable or not does not matter. div handling with all it's infrastructure needed in object pascal is that big. FPC generates an ldi, three moves and a call for the div.

Of course, one could cheat and implement some special tailored div. procedure for such useless benchmarks so the exception handling infrastructure is left out but this makes no difference in real world programs.
Title: Re: light pascal
Post by: d.ioannidis on January 13, 2020, 09:46:02 pm
Hi,

  AFAIU, even Atmel in AVR200: Multiply and Divide Routines (http://ww1.microchip.com/downloads/en/AppNotes/doc0936.pdf) for unsigned  8-bit  division ( optimized for size) report "Code Size (Words) 14" for their algorithm ....

  Also someone more experienced than me, said "...scaling calculations so that divisions are done with powers of 2 are popular on 8 bitters because shifts are much simpler than division." .

  You'll notice it if you change the value 17 with 32, 64 etc ...

Code: Pascal  [Select][+][-]
  1. Free Pascal Compiler version 3.3.1 [2020/01/12] for avr
  2. Copyright (c) 1993-2019 by Florian Klaempfl and others
  3. Target OS: Embedded
  4. Compiling tt.lpr
  5. tt.lpr(11,8) Warning: Variable "x" does not seem to be initialized
  6. Assembling tt
  7. Linking tt
  8. 12 lines compiled, 0.2 sec, 218 bytes code, 0 bytes data
  9. 1 warning(s) issued




  regards,
Title: Re: light pascal
Post by: ccrause on January 14, 2020, 01:23:34 pm
Whether it is acceptable or not does not matter. div handling with all it's infrastructure needed in object pascal is that big. FPC generates an ldi, three moves and a call for the div.
8< ...

I agree that the safety of using Pascal should not be sacrificed, but I would like to suggest that more compact error handling could be implemented for AVR, see e.g. the suggestion in issue 35754 (https://bugs.freepascal.org/view.php?id=35754).  Basically, remove exception raising code, since exception handling support is not enabled anyway.
Title: Re: light pascal
Post by: julkas on January 14, 2020, 02:30:16 pm
Whether it is acceptable or not does not matter. div handling with all it's infrastructure needed in object pascal is that big. FPC generates an ldi, three moves and a call for the div.
8< ...

I agree that the safety of using Pascal should not be sacrificed, but I would like to suggest that more compact error handling could be implemented for AVR, see e.g. the suggestion in issue 35754 (https://bugs.freepascal.org/view.php?id=35754).  Basically, remove exception raising code, since exception handling support is not enabled anyway.

rtl/embedded/system.cfg -
Code: Text  [Select][+][-]
  1. # does not require extra memory, neither code nor data
  2. # in programs not using e. g. writeln based I/O which is the common case for AVR
  3. #ifdef CPUAVR
  4. -SfOBJECTS
  5. -SfEXCEPTIONS
  6. -SfCLASSES
  7. -SfRTTI
  8. # AVR6 has normally more memory, so enable more functions
  9. #ifdef CPUAVR6
  10. -SfANSISTRINGS
  11. -SfWIDESTRINGS
  12. -SfDYNARRAYS
  13. -SfTHREADING
  14. -SfVARIANTS
  15. -SfOBJECTS
  16. -SfCOMMANDARGS
  17. -SfRANDOM
  18. -SfRESOURCES
  19. #endif
  20. #endif
So exception handling enabled or disabled?
Title: Re: light pascal
Post by: ccrause on January 14, 2020, 04:12:30 pm
Whether it is acceptable or not does not matter. div handling with all it's infrastructure needed in object pascal is that big. FPC generates an ldi, three moves and a call for the div.
8< ...

I agree that the safety of using Pascal should not be sacrificed, but I would like to suggest that more compact error handling could be implemented for AVR, see e.g. the suggestion in issue 35754 (https://bugs.freepascal.org/view.php?id=35754).  Basically, remove exception raising code, since exception handling support is not enabled anyway.

rtl/embedded/system.cfg -
Code: Text  [Select][+][-]
  1. # does not require extra memory, neither code nor data
  2. # in programs not using e. g. writeln based I/O which is the common case for AVR
  3. #ifdef CPUAVR
  4. -SfOBJECTS
  5. -SfEXCEPTIONS
  6. -SfCLASSES
  7. -SfRTTI
  8. # AVR6 has normally more memory, so enable more functions
  9. #ifdef CPUAVR6
  10. -SfANSISTRINGS
  11. -SfWIDESTRINGS
  12. -SfDYNARRAYS
  13. -SfTHREADING
  14. -SfVARIANTS
  15. -SfOBJECTS
  16. -SfCOMMANDARGS
  17. -SfRANDOM
  18. -SfRESOURCES
  19. #endif
  20. #endif
So exception handling enabled or disabled?

Let me rephrase: According to the Wiki: To enable the RTL to raise exceptions instead of generating runtime errors, use the SysUtils unit in your program. (https://wiki.freepascal.org/Exceptions)
SysUtils unit is not included in the list of units for AVR in Makefile (https://svn.freepascal.org/cgi-bin/viewvc.cgi/trunk/rtl/embedded/Makefile?view=markup#l386) => there is no point currently to check if an exception should be raised for AVR in the RTL error handling code.

Of course the easiest solution right now to reduce the size of the RTL error handling portion of the code is to comment out -SfEXCEPTIONS in system.cfg and rebuild RTL.
Title: Re: light pascal
Post by: Laksen on January 14, 2020, 05:33:44 pm
Ahh, yeah div still pulls in the exception handling. I actually thought that had been changed, as in have generic *_checkoverflow versions that do division by zero checking. When dividing by a positive non-zero constant there can never be overflows, and this is usually what is used on AVR (divide/mod by 10 for int<>string conversion)
Title: Re: light pascal
Post by: julkas on January 14, 2020, 05:53:47 pm
Ok. I will rebuild cross compiler and report results. Thanks.
Title: Re: light pascal
Post by: julkas on January 18, 2020, 02:10:23 pm
After disabling
-SfEXCEPTIONS
-SfCLASSES
in rtl/embedded/system.cfg code size reduced by 1K -
Code: Text  [Select][+][-]
  1. 2057 lines compiled, 0.5 sec, 7174 bytes code, 388 bytes data
  2.  
Title: Re: light pascal
Post by: julkas on January 19, 2020, 12:16:17 pm
Strange output. I have disabled  CLASSES, EXCEPTIONS - 
Code: Text  [Select][+][-]
  1. $ ppcrossavr.exe -i
  2. Free Pascal Compiler version 3.3.1
  3.  
  4. Compiler date      : 2020/01/18
  5. Compiler CPU target: avr
  6.  
  7. Supported targets (targets marked with '{*}' are under development):
  8.   embedded: Embedded
  9.  
  10. Supported CPU instruction sets:
  11.   AVR1,AVR2,AVR25,AVR3,AVR31,AVR35,AVR4,AVR5,AVR51,AVR6
  12.  
  13. Supported FPU instruction sets:
  14.   NONE,SOFT,LIBGCC
  15.  
  16. Supported inline assembler modes:
  17.   STANDARD
  18.   GAS
  19.  
  20. Recognized compiler and RTL features:
  21.   HEAP,INITFINAL,RTTI,CLASSES,EXCEPTIONS,EXITCODE,ANSISTRINGS,WIDESTRINGS
  22.   TEXTIO,CONSOLEIO,FILEIO,RANDOM,VARIANTS,OBJECTS,DYNARRAYS,THREADING
  23.   COMMANDARGS,PROCESSES,STACKCHECK,DYNLIBS,SOFTFPU,OBJECTIVEC1,RESOURCES
  24.   UNICODESTRINGS
  25.  
Title: Re: light pascal
Post by: ccrause on January 19, 2020, 03:07:31 pm
Strange output. I have disabled  CLASSES, EXCEPTIONS - 
Code: Text  [Select][+][-]
  1. Recognized compiler and RTL features:
  2.   HEAP,INITFINAL,RTTI,CLASSES,EXCEPTIONS,EXITCODE,ANSISTRINGS,WIDESTRINGS
  3.   TEXTIO,CONSOLEIO,FILEIO,RANDOM,VARIANTS,OBJECTS,DYNARRAYS,THREADING
  4.   COMMANDARGS,PROCESSES,STACKCHECK,DYNLIBS,SOFTFPU,OBJECTIVEC1,RESOURCES
  5.   UNICODESTRINGS
  6.  
That is the list of features the compiler knows of.  It does not mean that the system unit was compiled with those features enabled.
Title: Re: light pascal
Post by: julkas on January 19, 2020, 03:16:14 pm
Strange output. I have disabled  CLASSES, EXCEPTIONS - 
Code: Text  [Select][+][-]
  1. Recognized compiler and RTL features:
  2.   HEAP,INITFINAL,RTTI,CLASSES,EXCEPTIONS,EXITCODE,ANSISTRINGS,WIDESTRINGS
  3.   TEXTIO,CONSOLEIO,FILEIO,RANDOM,VARIANTS,OBJECTS,DYNARRAYS,THREADING
  4.   COMMANDARGS,PROCESSES,STACKCHECK,DYNLIBS,SOFTFPU,OBJECTIVEC1,RESOURCES
  5.   UNICODESTRINGS
  6.  
That is the list of features the compiler knows of.  It does not mean that the system unit was compiled with those features enabled.
OK. How read / output enabled compiler features ? Simple question. I need only enabled compiler features.

ppcrossavr.exe -ir current output -
Code: Text  [Select][+][-]
  1. HEAP
  2. INITFINAL
  3. RTTI
  4. CLASSES
  5. EXCEPTIONS
  6. EXITCODE
  7. ANSISTRINGS
  8. WIDESTRINGS
  9. TEXTIO
  10. CONSOLEIO
  11. FILEIO
  12. RANDOM
  13. VARIANTS
  14. OBJECTS
  15. DYNARRAYS
  16. THREADING
  17. COMMANDARGS
  18. PROCESSES
  19. STACKCHECK
  20. DYNLIBS
  21. SOFTFPU
  22. OBJECTIVEC1
  23. RESOURCES
  24. UNICODESTRINGS
  25.  




Title: Re: light pascal
Post by: ccrause on January 19, 2020, 04:15:39 pm
Whether a feature is available or not is not known by the compiler, since the feature support is included (or not) depending on the features enabled when the RTL was compiled.  The RTL supported features are available as compile time macros.  To see this add command line option -va when compiling a unit or program.  The compiler will then list the available features for the current subarch RTL.  Below I have copied the feature macros displayed after the compiler loaded the system unit when compiling one of my AVR projects:

Code: Text  [Select][+][-]
  1. Debug: [0.051] (SYSTEM)   (10056) Finished loading unit SYSTEM
  2. Debug: [0.051] Searching file adctest.pp... found
  3. Debug: [0.051] Searching file adctest.pp... found
  4. Debug: [0.051] /home/christo/fpc/fpc-avr/src/examples/adc4809/adctest.pp(3,5)  (3101) Macro defined: FPC_HAS_FEATURE_HEAP
  5. Debug: [0.051] /home/christo/fpc/fpc-avr/src/examples/adc4809/adctest.pp(3,5)  (3101) Macro defined: FPC_HAS_FEATURE_RTTI
  6. Debug: [0.051] /home/christo/fpc/fpc-avr/src/examples/adc4809/adctest.pp(3,5)  (3101) Macro defined: FPC_HAS_FEATURE_TEXTIO
  7. Debug: [0.051] /home/christo/fpc/fpc-avr/src/examples/adc4809/adctest.pp(3,5)  (3101) Macro defined: FPC_HAS_FEATURE_FILEIO
  8. Debug: [0.051] /home/christo/fpc/fpc-avr/src/examples/adc4809/adctest.pp(3,5)  (3101) Macro defined: FPC_HAS_FEATURE_OBJECTS
  9. Debug: [0.051] (ADCTEST)  (10057) Registering new unit OBJPAS

This way you can test whether a feature is supported before trying to use it in code:
Code: Pascal  [Select][+][-]
  1. type
  2.   {$if defined(FPC_HAS_FEATURE_CLASSES)}
  3.   TTest = class
  4.     procedure foo;
  5.   end;
  6.   {$elseif defined(FPC_HAS_FEATURE_OBJECTS)}
  7.   TTest = object
  8.     procedure foo;
  9.   end;
  10.   {$else}
  11.     {$fatal 'Either CLASSES or OBJECTS must be supported for this to compile'}
  12.   {$endif}
Title: Re: light pascal
Post by: julkas on January 19, 2020, 05:47:47 pm
Thanks. -va option is very useful.
TinyPortal © 2005-2018