[fpc-pascal] Pascal Ardiono (avr) library

Joost van der Sluis joost at cnoc.nl
Sun Apr 4 12:50:30 CEST 2021



Op 03-04-2021 om 20:42 schreef Florian Klämpfl via fpc-pascal:
> 
> 
>> Am 03.04.2021 um 19:49 schrieb Joost van der Sluis via fpc-pascal <fpc-pascal at lists.freepascal.org>:
>>
>> Hi all,
>>
>> During some spare free time I've ported parts of the Arduino AVR library to Free Pascal. So now it is possible to use things like 'DigitalWrite' and 'Delay'.
>>
>> More info here: https://lazarussupport.com/introducing-pasduino-the-pascal-avr-arduino-library/
> 
> You write that the assembler is far from ideal. Did you notice any problems in particular? Because in general it’s not that bad as long as one keeps in mind that one is working on a 8 bit systems where e.g. 32 bit integers hurt.

I came across some issues while doing this, but I can not remember all 
of them.

One thing is constant-propagation in combination with auto-inlining. It 
would be really nice when calling PinMode with two constant parameters, 
would only lead to setting the constant value at two memory locations. 
(Between avr_save and avr_restore) Yes, then I have to change the 
parameters to const, and add {$WRITEABLECONST OFF} to the Arduino unit.

I doubt many (if any) compiler will/can do this. But that would be 
ideal. (I think we need the concept Gareth calls 'pure functions' for this)

Another thing is the less-then-ideal use of registers, at least in my 
eyes, but it could be that I miss something.

Take this function:

procedure THardwareSerial.SerialEnd;
begin
   // wait for transmission of outgoing data
   //Flush();

   Fucsrb^ := Fucsrb^ and not (1 shl RXEN0);
   Fucsrb^ := Fucsrb^ and not (1 shl TXEN0);
   Fucsrb^ := Fucsrb^ and not (1 shl RXCIE0);
   Fucsrb^ := Fucsrb^ and not (1 shl UDRIE0);

   // clear any received data
   //FRXBufferHead := FRXBufferTail;
end;

The 4 statements could be converted into 1. But I agree with the 
compiler that this is not done, as reading and writing to a memory 
location this way should be considered 'volatile'.

Leads to this, my comments prefixed with JvdS:

.section .text.n_hardwareserials_sthardwareserial_s__ss_serialend,"ax"
.globl	HARDWARESERIALs_sTHARDWARESERIAL_s__ss_SERIALEND
HARDWARESERIALs_sTHARDWARESERIAL_s__ss_SERIALEND:
	# Register r24,r25,r18 allocated
# [224] begin
	mov	r18,r24
	# Register r24 released
# Var $self located in register r18:r25

JvdS: self in r18:r25? Strange combination?

	# Register r30 allocated
	mov	r30,r18
	# Register r31 allocated
	mov	r31,r25

# Now self is in Z.

	# Register r19 allocated
	ldd	r19,Z+18
	# Register r20 allocated
	ldd	r20,Z+19
	# Register r31 released
# [228] Fucsrb^ := Fucsrb^ and not (1 shl RXEN0);

JvdS: Here we override Z. After this is points to Fucsrb^

	mov	r30,r19
	# Register r31 allocated
	mov	r31,r20
	# Register r21 allocated
	ld	r21,Z
	andi	r21,-17
	# Register r19,r20 released
	st	Z,r21
	# Register r21,r31 released

JvdS: Now we do exactly the same again? This could all be skipped!

	mov	r30,r18
	# Register r31 allocated
	mov	r31,r25
	# Register r19 allocated
	ldd	r19,Z+18
	# Register r20 allocated
	ldd	r20,Z+19
	# Register r31 released
# [229] Fucsrb^ := Fucsrb^ and not (1 shl TXEN0);
	mov	r30,r19
	# Register r31 allocated
	mov	r31,r20
	# Register r21 allocated
	ld	r21,Z
	andi	r21,-9
	# Register r19,r20 released
	st	Z,r21

JvdS: And again.....

	# Register r21,r31 released
	mov	r30,r18
	# Register r31 allocated
	mov	r31,r25
	# Register r19 allocated
	ldd	r19,Z+18
	# Register r20 allocated
	ldd	r20,Z+19
	# Register r31 released
# [230] Fucsrb^ := Fucsrb^ and not (1 shl RXCIE0);
	mov	r30,r19
	# Register r31 allocated
	mov	r31,r20

<<cut>>

Isn't it at least a good practice to store self at Y. So we have Z free 
for other calculations and can access members directly using ldd (),y+().

But maybe that's difficult?

Regards,

Joost.


More information about the fpc-pascal mailing list