AVR - Strings direkt aus Flash lesen

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut

Re: AVR - Strings direkt aus Flash lesen

Beitragvon Mathias » 4. Okt 2017, 17:39 Re: AVR - Strings direkt aus Flash lesen

Code: Alles auswählen
procedure TextStr;
begin
  asm  db $5,'Hallo'   { Längenbyte und der Text selbst }
end;

Sowas kommt mir sehr bekannt vor, bei Turbo-Pascal, hat man nur 64KB für Konstanten zu Verfügung.
Das Programm selbst, konnte den ganzen Heap nutzen.

Ich hatte mal einen ganze Font so abgespeichert:
Code: Alles auswählen
procedure CharTab; assembler;
asm                         
 db    0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
 db    0,   0, 126, 129, 165, 129, 129, 189, 153, 129, 126,   0,   0,   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
............


Der Zugriff habe ich dann par ASM gelöst:
Code: Alles auswählen
procedure LoadoldChar; assembler;  { Lädt Zeichensatz aus ROM }
asm
        push    bp
        push    ds
        mov     ax, 1130h
        mov     bh, 02h
        int     10h
        mov     si, bp
        mov     di, offset CharTab
        mov     cx, 1792
        mov     ax, es
        mov     bx, ds
        mov     ds, ax
        mov     es, bx
        rep     movsw
        pop     ds
        pop     bp
end;

Dazumal musste man noch recht basteln. :wink:
Die Lösung mit dem Pointer ist auch sehr gut.
Mit Lazarus sehe ich gün
Mit Java und C/C++ sehe ich rot
Mathias
 
Beiträge: 3047
Registriert: 2. Jan 2014, 17:21
Wohnort: Schweiz
OS, Lazarus, FPC: Linux (die neusten Trunc) | 
CPU-Target: 64Bit
Nach oben

Beitragvon Timm Thaler » 5. Okt 2017, 13:13 Re: AVR - Strings direkt aus Flash lesen

Ich habe mit den Angaben aus dem bugtracker forum nochmal rumprobiert:

Code: Alles auswählen
var
  dispbuf : string[32];
const
  text00 : string[32] = 'MyDisplayText...' +
                        '.......... start'; section '.progmem';
var
  sptr, tptr : pchar;
 
  sptr := @text00; 
  tptr := @dispbuf;
  copy_pgm_string(sptr, tptr, 32)// String von Flash in Buffer
 
procedure copy_pgm_string(psrc, pto : pchar; len : uint8);
label
  loop;
var
  lo_psrc, hi_psrc, lo_pto, hi_pto : uint8;
begin
  lo_psrc := uint16(psrc) and $FF;
  hi_psrc := uint16(psrc) shr 8;
  lo_pto := uint16(pto) and $FF;
  hi_pto := uint16(pto) shr 8;
  asm
    ldd r30, lo_psrc
    ldd r31, hi_psrc
    ldd r26, lo_pto
    ldd r27, hi_pto
    ldd r16, len
    inc r16
    loop:
    lpm r0, Z+
    st X+, r0
    dec r16
    brne loop
  end['r0','r16','r26','r27','r30','r31'];
end;


Funktioniert!

Allerdings erzeugt die Übergabe der Adressen noch reichlich Overhead.

Code: Alles auswählen
 402:   8a 83          std   Y+2, r24   ; 0x02 <= hier werden die Adressen in die Prozedur übergeben
 404:   9b 83          std   Y+3, r25   ; 0x03
 406:   6c 83          std   Y+4, r22   ; 0x04
 408:   7d 83          std   Y+5, r23   ; 0x05
 40a:   4e 83          std   Y+6, r20   ; 0x06
 40c:   2a 81          ldd   r18, Y+2   ; 0x02
 40e:   2f 83          std   Y+7, r18   ; 0x07
 410:   3a 81          ldd   r19, Y+2   ; 0x02
 412:   4b 81          ldd   r20, Y+3   ; 0x03
 414:   58 e0          ldi   r21, 0x08   ; 8
 416:   21 2d          mov   r18, r1
 418:   55 23          and   r21, r21
 41a:   21 f0          breq   .+8         ;  0x424
 41c:   46 95          lsr   r20
 41e:   37 95          ror   r19
 420:   5a 95          dec   r21
 422:   e1 f7          brne   .-8         ;  0x41c
 424:   38 87          std   Y+8, r19   ; 0x08
 426:   2c 81          ldd   r18, Y+4   ; 0x04
 428:   29 87          std   Y+9, r18   ; 0x09
 42a:   3c 81          ldd   r19, Y+4   ; 0x04
 42c:   4d 81          ldd   r20, Y+5   ; 0x05
 42e:   58 e0          ldi   r21, 0x08   ; 8
 430:   21 2d          mov   r18, r1
 432:   55 23          and   r21, r21
 434:   21 f0          breq   .+8         ;  0x43e
 436:   46 95          lsr   r20
 438:   37 95          ror   r19
 43a:   5a 95          dec   r21
 43c:   e1 f7          brne   .-8         ;  0x436
 43e:   3a 87          std   Y+10, r19   ; 0x0a
 440:   ef 81          ldd   r30, Y+7   ; 0x07 <= hier stehen sie endlich in den richtigen Registern
 442:   f8 85          ldd   r31, Y+8   ; 0x08
 444:   a9 85          ldd   r26, Y+9   ; 0x09
 446:   ba 85          ldd   r27, Y+10   ; 0x0a
 448:   0e 81          ldd   r16, Y+6   ; 0x06


Das geht doch bestimmt eleganter...?
Timm Thaler
 
Beiträge: 361
Registriert: 20. Mär 2016, 22:14
OS, Lazarus, FPC: Win7-64bit Laz1.6 FPC3.0.0, Raspbian Jessie Laz1.6 FPC3.0.0 | 
CPU-Target: Raspberry Pi 3
Nach oben

Beitragvon Mathias » 5. Okt 2017, 17:03 Re: AVR - Strings direkt aus Flash lesen

Code: Alles auswählen
end['r0','r16','r26','r27','r30','r31'];

Was macht diese Zeile ?
Oder sollte die Kommentar sein ?
Mit Lazarus sehe ich gün
Mit Java und C/C++ sehe ich rot
Mathias
 
Beiträge: 3047
Registriert: 2. Jan 2014, 17:21
Wohnort: Schweiz
OS, Lazarus, FPC: Linux (die neusten Trunc) | 
CPU-Target: 64Bit
Nach oben

Beitragvon Socke » 5. Okt 2017, 19:22 Re: AVR - Strings direkt aus Flash lesen

Ist das hier effizienter?
Code: Alles auswählen
var
  lo_psrc, hi_psrc, lo_pto, hi_pto : uint8;
begin
  lo_psrc := lo(uint16(psrc));
  hi_psrc := hi(uint16(psrc));
  lo_pto := lo(uint16(pto));
  hi_pto := hi(uint16(pto));
  // ...
end;


Edit:
Man kann das Hin- und Hergeschiebe auch komplett eleminieren:
Code: Alles auswählen
procedure copy_pgm_string(psrc, pto : pchar; len : uint8);
type
  // Struktur zum Zugriff auf die einzelnene Bytes
  TUInt16Struct = packed record
    l: uint8;
    h: uint8;
  end;
var
  // es kann kein direkter Zugriff auf die Record-Elemente erfolgen
  // daher muss jedes Byte einen separaten Namen erhalten
  s: TUInt16Struct absolute psrc;
  lsrc: Uint8 absolute s.l;
  hsrc: Uint8 absolute s.h;
  t: TUInt16Struct absolute pto;
  lto: Uint8 absolute t.l;
  hto: Uint8 absolute t.h;
label
  loop;
begin
  asm
    ldd r30, lsrc
    ldd r31, hsrc
    ldd r26, lto
    ldd r27, hto
    ldd r16, len
    inc r16
    loop:
    lpm r0, Z+
    st X+, r0
    dec r16
    brne loop
  end['r0','r16','r26','r27','r30','r31'];
end;
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein
Socke
 
Beiträge: 2374
Registriert: 22. Jul 2008, 18:27
Wohnort: Köln
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 8.1/Debian GNU/Linux/Raspbian | 
CPU-Target: 32bit x86 armhf
Nach oben

Beitragvon FPK » 5. Okt 2017, 19:55 Re: AVR - Strings direkt aus Flash lesen

Timm Thaler hat geschrieben:Das geht doch bestimmt eleganter...?


Assembler und Pascal in einem Unterprogramm nicht mischen, da gibt der Optimierer schnell auf. Einfach direkt auf r20 bis r25 zurgreifen.
FPK
 
Beiträge: 30
Registriert: 21. Mai 2008, 18:38
Wohnort: Erlangen

Beitragvon Timm Thaler » 5. Okt 2017, 20:56 Re: AVR - Strings direkt aus Flash lesen

FPK hat geschrieben:Assembler und Pascal in einem Unterprogramm nicht mischen, da gibt der Optimierer schnell auf. Einfach direkt auf r20 bis r25 zurgreifen.


Das hätte ich auch gern gemacht, aber woher weiss ich wie r20 bis r25 zugeordnet werden, und ob das immer gleich bleibt?
Timm Thaler
 
Beiträge: 361
Registriert: 20. Mär 2016, 22:14
OS, Lazarus, FPC: Win7-64bit Laz1.6 FPC3.0.0, Raspbian Jessie Laz1.6 FPC3.0.0 | 
CPU-Target: Raspberry Pi 3
Nach oben

Beitragvon Timm Thaler » 5. Okt 2017, 21:20 Re: AVR - Strings direkt aus Flash lesen

Mathias hat geschrieben:Was macht diese Zeile ?


In the assembler block modified registers have to be published to the compiler in the end statement, so that the compiler can take care of pushing or avoiding registers. The resulting code is more effective than pushing registers manually inside the asm section. Modified but unpublished registers may leed to malfunction.

Code: Alles auswählen
asm
  ldi r20,35        //r20 modified
  ldi r21,12        //r21 modified
end['r20','r21'];   //publish modified registers to compiler
 

http://wiki.freepascal.org/AVR_Programming#Inline_assembler
Timm Thaler
 
Beiträge: 361
Registriert: 20. Mär 2016, 22:14
OS, Lazarus, FPC: Win7-64bit Laz1.6 FPC3.0.0, Raspbian Jessie Laz1.6 FPC3.0.0 | 
CPU-Target: Raspberry Pi 3
Nach oben

Beitragvon Socke » 6. Okt 2017, 10:24 Re: AVR - Strings direkt aus Flash lesen

Timm Thaler hat geschrieben:
FPK hat geschrieben:Assembler und Pascal in einem Unterprogramm nicht mischen, da gibt der Optimierer schnell auf. Einfach direkt auf r20 bis r25 zurgreifen.

Das hätte ich auch gern gemacht, aber woher weiss ich wie r20 bis r25 zugeordnet werden, und ob das immer gleich bleibt?

Soweit ich das gesehen habe, müsste mein Code von Oben das umsetzen.
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein
Socke
 
Beiträge: 2374
Registriert: 22. Jul 2008, 18:27
Wohnort: Köln
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 8.1/Debian GNU/Linux/Raspbian | 
CPU-Target: 32bit x86 armhf
Nach oben

Beitragvon Timm Thaler » 6. Okt 2017, 11:29 Re: AVR - Strings direkt aus Flash lesen

Socke hat geschrieben:Soweit ich das gesehen habe, müsste mein Code von Oben das umsetzen.


Besser, aber nicht optimal. Naja, wenn man optimal will muss man wahrscheinlich alles in ASM machen.

Code: Alles auswählen
procedure copy_pgm_string(psrc, pto : pchar);
label
  loop;
begin
  asm
    mov r26, r22
    mov r27, r23
    mov r30, r24
    mov r31, r25
    lpm r0, Z+
    st X+, r0
    mov r16, r0
    loop:
    lpm r0, Z+
    st X+, r0
    dec r16
    brne loop
  end['r0','r16','r26','r27','r30','r31'];
end;


kompiliert zu:

Code: Alles auswählen
GH_INIT_ss_COPY_PGM_STRINGsPCHARsPCHAR:
   push   r29
   push   r28
   push   r16
   in   r28,61
   in   r29,62
   subi   r28,6
   sbci   r29,0
   in   r0,63
   cli
   out   62,r29
   out   63,r0
   out   61,r28
   std   Y+2,r24
   std   Y+3,r25
   std   Y+4,r22
   std   Y+5,r23
CPU AVR5
   mov   r26,r22
   mov   r27,r23
   mov   r30,r24
   mov   r31,r25
   lpm   r0,z+
   st   x+,r0
   mov   r16,r0
.Lj9:
   lpm   r0,z+
   st   x+,r0
   dec   r16
   brne   .Lj9
CPU AVR5
   subi   r28,-6
   sbci   r29,-1
   in   r0,63
   cli
   out   62,r29
   out   63,r0
   out   61,r28
   pop   r16
   pop   r28
   pop   r29
   ret
 


Und Dein Code:

Code: Alles auswählen
procedure copy2_pgm_string(psrc, pto : pchar);
label
  loop;
type
  // Struktur zum Zugriff auf die einzelnene Bytes
  TUInt16Struct = packed record
    l: uint8;
    h: uint8;
  end;
var
  // es kann kein direkter Zugriff auf die Record-Elemente erfolgen
  // daher muss jedes Byte einen separaten Namen erhalten
  s: TUInt16Struct absolute psrc;
  lsrc: Uint8 absolute s.l;
  hsrc: Uint8 absolute s.h;
  t: TUInt16Struct absolute pto;
  lto: Uint8 absolute t.l;
  hto: Uint8 absolute t.h;
begin
  asm
    ldd r30, lsrc
    ldd r31, hsrc
    ldd r26, lto
    ldd r27, hto
    lpm r0, Z+
    st X+, r0
    mov r16, r0
    loop:
    lpm r0, Z+
    st X+, r0
    dec r16
    brne loop
  end['r0','r16','r26','r27','r30','r31'];
end;


kompiliert zu:

Code: Alles auswählen
GH_INIT_ss_COPY2_PGM_STRINGsPCHARsPCHAR:
   push   r29
   push   r28
   push   r16
   in   r28,61
   in   r29,62
   subi   r28,6
   sbci   r29,0
   in   r0,63
   cli
   out   62,r29
   out   63,r0
   out   61,r28
   std   Y+2,r24
   std   Y+3,r25
   std   Y+4,r22
   std   Y+5,r23
CPU AVR5
   ldd   r30,Y+2
   ldd   r31,Y+2
   ldd   r26,Y+4
   ldd   r27,Y+4
   lpm   r0,z+
   st   x+,r0
   mov   r16,r0
.Lj12:
   lpm   r0,z+
   st   x+,r0
   dec   r16
   brne   .Lj12
CPU AVR5
   subi   r28,-6
   sbci   r29,-1
   in   r0,63
   cli
   out   62,r29
   out   63,r0
   out   61,r28
   pop   r16
   pop   r28
   pop   r29
   ret
 


Mit den paar unnötigen st, ld muss man wohl leben.
Timm Thaler
 
Beiträge: 361
Registriert: 20. Mär 2016, 22:14
OS, Lazarus, FPC: Win7-64bit Laz1.6 FPC3.0.0, Raspbian Jessie Laz1.6 FPC3.0.0 | 
CPU-Target: Raspberry Pi 3
Nach oben

Beitragvon Socke » 6. Okt 2017, 16:16 Re: AVR - Strings direkt aus Flash lesen

Timm Thaler hat geschrieben:
Socke hat geschrieben:Soweit ich das gesehen habe, müsste mein Code von Oben das umsetzen.


Besser, aber nicht optimal. Naja, wenn man optimal will muss man wahrscheinlich alles in ASM machen.

Okay, du hast mich überzeugt :oops:

Timm Thaler hat geschrieben:Mit den paar unnötigen st, ld muss man wohl leben.

Bringt der Prozedur-Modifier nostackframe bzw. assembler etwas? Dann muss ggf. zwar noch mehr in Assembler geschrieben werden, aber damit solltest du volle Kontrolle über den dann nicht mehr veränderten Assembler-Code haben.
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein
Socke
 
Beiträge: 2374
Registriert: 22. Jul 2008, 18:27
Wohnort: Köln
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 8.1/Debian GNU/Linux/Raspbian | 
CPU-Target: 32bit x86 armhf
Nach oben

• Themenende •
Vorherige

Zurück zu Freepascal



Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 1 Gast

porpoises-institution
accuracy-worried