AVR embedded: Typecast bei Multiplikation?

Rund um die LCL und andere Komponenten
Antworten
Timm Thaler
Beiträge: 1224
Registriert: So 20. Mär 2016, 22:14
OS, Lazarus, FPC: Win7-64bit Laz1.9.0 FPC3.1.1 für Win, RPi, AVR embedded
CPU-Target: Raspberry Pi 3

AVR embedded: Typecast bei Multiplikation?

Beitrag von Timm Thaler »

Bei Multiplikation auf dem AVR musste man Typecasts einsetzen, wenn der Bereich überschritten wurde. Mit

vadc, ad_cal, val : uint16;
val := uint32(vadc) * ad_cal div 4096;

wurde eine Multiplikation mit 32 Bit Zwischenergebnis durchgeführt, ohne den ersten Typecast nur mit 16 Bit.

Jetzt hab ich das gerade wieder in Arbeit, und da wird auch mit

val := vadc * ad_cal div 4096;

vadc und ad_cal auf 32 Bit aufgeblasen und ein fpc_mul_longint mit 32 Bit Ergebnis aufgerufen.

Auf der einen Seite ist das natürlich schön, auf der anderen Seite verwirrt mich das:

1. Seit wann ist das so?
2. Bleibt das zuverlässig so? Denn es wäre ja blöd, die Routinen jetzt daraufhin zu schreiben, und dann erfolgt die Multiplikation wieder nur mit 16 Bit.
3. Wie erreiche ich eine vereinfachte Multiplikation, wenn ich nur 16 Bit im Ergebnis brauche und dafür schneller als fpc_mul_longint sein will?

Timm Thaler
Beiträge: 1224
Registriert: So 20. Mär 2016, 22:14
OS, Lazarus, FPC: Win7-64bit Laz1.9.0 FPC3.1.1 für Win, RPi, AVR embedded
CPU-Target: Raspberry Pi 3

Re: AVR embedded: Typecast bei Multiplikation?

Beitrag von Timm Thaler »

Achso: AVR ist ATmega328P, FPC ist trunk mit Version 3.3.1-r41349.

Benutzeravatar
kupferstecher
Beiträge: 418
Registriert: Do 17. Nov 2016, 11:52

Re: AVR embedded: Typecast bei Multiplikation?

Beitrag von kupferstecher »

Deine Frage kann ich dir nicht direkt beantworten, aber Untenstehendes ist im FreePascal Reference Guide zu finden.

Nach meinem Verständnis sollte für die Multiplikation der Fall 3b) gelten, das Multiplikationsergebnis also ein uInt16 sein (bei der Variante ohne expliziten Cast). Das neue Verhalten wäre dann ein Bug?

Zu deiner Frage 3. Mir ist nicht ganz klar, wie dein 16bit-Ergebnis aussehen soll, d.h. welche 16bit aus dem Ergebnis für dich relevant sind. Durch 4096 entspricht ja 12 geshifteten Bit. Eine explizite Möglichkeit wäre vielleicht eine Multiplikation mit 16 (oder 4bit linksshift) und dann mit hi() die höheren 16bit des Ergebnisses zu nehmen. Also:
vadc, ad_cal, val : uint16;
val := Hi(uint32(vadc) * ad_cal * $10);

As a pascal compiler, Free Pascal does automatic type conversion and upgrading in expressions
where different kinds of integer types are used:
1.
Every platform has a "native" integer size, depending on whether the platform is 8-bit, 16-bit,
32-bit or 64-bit. e.g. On AVR this is 8-bit.
2.
Every integer smaller than the "native" size is promoted to a signed version of the "native" size.
Integers equal to the "native" size keep their signedness.
3.
The result of binary arithmetic operators (+, -, *, etc.) is determined in the following way:
(a)
If at least one of the operands is larger than the native integer size, the result is chosen
to be the smallest type that encompasses the ranges of the types of both operands. This
means that mixing an unsigned with a smaller or equal in size signed will produce a
signed type that is larger than both of them.
(b)
If both operands have the same signedness, the result is the same type as them. The
only exception is subtracting (-): in the case of unsigned-unsigned subtracting produces
a signed result in FPC (as in Delphi, but not in TP7).
(c)
Mixing signed and unsigned operands of the "native" int size produces a larger signed
result. This means that mixing longint and longword on 32-bit platforms will produce
an int64. Similarly, mixing byte and shortint on 8-bit platforms (AVR) will produce a
smallint.

Timm Thaler
Beiträge: 1224
Registriert: So 20. Mär 2016, 22:14
OS, Lazarus, FPC: Win7-64bit Laz1.9.0 FPC3.1.1 für Win, RPi, AVR embedded
CPU-Target: Raspberry Pi 3

Re: AVR embedded: Typecast bei Multiplikation?

Beitrag von Timm Thaler »

kupferstecher hat geschrieben:Nach meinem Verständnis sollte für die Multiplikation der Fall 3b) gelten, das Multiplikationsergebnis also ein uInt16 sein (bei der Variante ohne expliziten Cast).


Schlimmer noch: Es hängt anscheinend davon ab, wie optimiert wird.

Ich hab mal ein altes Projekt kompiliert, und da macht der Compiler bei vergleichbarer Berechnung eine Hardware-Multiplikation mit 16 Bit (es werden auch nur 16 Bit benötigt). Also entweder optimiert der Compiler hier auf Größe: Wird fpc_mul_longint nur einmal benötigt, ist hardware-mul platzsparender und er nimm dieses, wird fpc_mul_longint eh mehrmals benötigt, nimmt er dieses. Oder der Compiler ist mittlerweile so intellent, dass er erkennt ob das Ergebnis in 16 oder 32 Bit gebraucht wird.

Allerdings war das eine für AVR51 (ATmega1284), das andere mit AVR5 (ATmega328) kompiliert, das sollte aber in dem Fall keinen Einfluss haben.

Ich werde wohl nicht umhinkommen, mal ein paar Tests mit verschiedenen Datentypen und Größen zu machen.

kupferstecher hat geschrieben:Durch 4096 entspricht ja 12 geshifteten Bit.


Das spielt hier keine Rolle, das war nur ein Beispiel. Ich habe eine Multiplikation 16 x 16 Bit und ein Zwischenergebnis mit > 16 Bit.

Antworten