Assembler und gcc

#1308067
Lesenswert?

Ich möchte ein Logikanalysator bauen. Die Routine zum abfragen der Ports 
möchte ich in Assembler als eine eigene Datei programmieren. Wie komme 
ich in C an die 100 Byte Variablen? Wie in C auf Prog zugreifen?

Anlegen in Assembler mit:  tab:        .Byte  100
Aufruf und Zugriff in C ?
Moderator Persönliche Seite #1308321
Lesenswert?

otto schrieb:

> Die Manual-libc ist bestandteil von winavr,bin aber nicht klar gekommen.

Womit denn genau nicht?

Gerade bei IO-Ports bringt das Ausweichen auf Assembler übrigens
nicht viel.  Das lohnt eher bei esoterischen Operationen, die von
C schlecht abgedeckt werden, wie vielleicht einer Multiplikation
zweier 8-bit-Zahlen zu einem 16-bit-Ergebnis (C würde beide zuvor
auf 16 bits ausdehnen und dann multiplizieren).
#1308394
Lesenswert?

Also ich möchte eine hohe Abtastrate erzielen.
1 Takt zum lesen vom Port  | 2 Takte zum speichern im Sram | 1 Takt für 
Sprung wenn nicht gleich (breq) macht 4 Takte pro Lauf. Bei 20 MHz 
gleich 5 Mhz also 200 n/s Abtastrate. Für C habe ich keine 
Berechnungsgrundlage.Hast Du so etwas? Wie schnell wäre ich, wenn ich 
alles in C schreibe mit Zeiger auf Puffer dann erhöhen,speichern und 
vergeilechen.

Ich find in der Manual-libc nicht die Übergabe, sowie Aufruf,habe mich 
schon doof geklickt. Ist es viel Text mir mitzuteilen wie es geht?
#1308428
Lesenswert?

Wenn dir nicht was extrem cleveres einfällt, wirst du den Compiler kaum 
schlagen:
1
// Ziemlich exakt, was du angedeutet hast:
2
uint8_t *foo(uint16_t len, uint8_t *buffer) {
3
  uint8_t *tmp = buffer;
4
  while(tmp != buffer+len ){
5
    *tmp++ = PINB;
6
  }
7
  return buffer;
8
}
1
foo:
2
  movw r18,r22; return-wert sichern
3
  add r18,r24
4
  adc r19,r25
5
  cp r22,r18
6
  cpc r23,r19
7
  breq .L15
8
  movw r30,r22
9
.L17:
10
  in r24,35-0x20
11
  st Z+,r24
12
  cp r30,r18
13
  cpc r31,r19
14
  brne .L17
15
.L15:
16
  movw r24,r22
17
  ret
Wenn 'len' garantiert immer < 256 ist, könnte man den Vergleich des 
Highbytes weglassen...</Schnapsidee>

hth, Jörg
#1308514
Lesenswert?

Hallo,

ich will Dir nicht den Spaß verderben, aber 100 Werte nutzen praktisch 
nichts. Für ein halbwegs nutzbares Ergebnis brauchst Du mindest 4, 
besser 8-10 Takte für ein zu sampelndes Ereignis.
Bei 1k Speicher wären also z.B. bei serieller Übertragung ca. 100 Bit 
halbwegs auswertbar. Das bedingt aber eine Triggerlogik, die den 
Zeitpunkt dazu auch erkennt.

8 Kanäle mit Pre-/Posttrigger-Sample und Auswertung der Triggerdaten 
habe ich bis 1MHz Samplerate bei 16MHz Takt für einen Mega16 hier, 
Auswertung auf dem PC mit der Software von LoLa, Samplebuffer 1,75kB.
Ist allerdings komplett in ASM.

Ansonsten
http://www.avr.roehres-home.de/logikanalyzer/index.html
falls es Dich interessiert.

Gruß aus Berlin
Michael
#1308535
Lesenswert?

Auftritt: die Hassliebe der (Gcc-) C-Programmierer, der inline-Asm
1
void store(uint8_t *buf) {
2
  uint8_t num = 100;
3
  uint8_t tmp;
4
  asm volatile ("L_%=:              \n\t"
5
           "in   %[reg], %[pins]    \n\t"
6
           "st   %[ptr]+, %[reg]    \n\t"
7
           "dec  %[cnt]             \n\t"
8
           "brne L_%=b              \n\t"
9
        : [reg] "=&r" (tmp), [ptr] "+e" (buf)
10
        : [cnt] "r" (num), [pins] "I" (_SFR_IO_ADDR(PINB))
11
        :"memory"
12
        );
13
}
Ich bin mir aber nicht 100% sicher, dass z.B. "st z+, r" so korrekt 
übersetzt wird (und ich hab keine Lust zum testen/simulieren).

hth, Jörg
Gast #1308542
Lesenswert?

>Ich find in der Manual-libc nicht die Übergabe, sowie Aufruf,habe mich
>schon doof geklickt. Ist es viel Text mir mitzuteilen wie es geht?

Definition im Assembler-File:
>* .global (or .globl) declares a public symbol that is visible to the linker 
>(e.g. function entry point, global variable)

also:
*.s
1
.global tab
2
tab:       .BYTE 100

*.c
1
extern unsigned char tab[100];

oder umgekehrt, definition im C-File:
>* .extern declares a symbol to be externally defined; this is effectively a 
>comment only, as gas treats all undefined symbols it encounters as globally 
>undefined anyway

*.c
1
unsigned char tab[100];

*.s
1
.extern tab

Oliver
#1308581
Lesenswert?

So etwas tolles habe ich noch nicht gesehen, aber für mich zuviel 
Aufwand.Ich möchte nur die Zeiten zwischen 8 Signalen beweisen, bzw. 
Prellen aufspüren.Ein Beispiel wäre ein LCD Display das die Signale zum 
richtigen Zeitpunt bekommt.usw. Aber Deine Sache ist Markt reif. Super 
Aufmachung tolle Software.Ich muß Zugegeben das hier nur Pegel abgefragt 
werden und vom analysieren weit weg ist.
Persönliche Seite #1308584
Lesenswert?

Jörg G. schrieb:
> Auftritt: die Hassliebe der (Gcc-) C-Programmierer, der *inline-Asm*
> Ich bin mir aber nicht 100% sicher, dass z.B. "st z+, r" so korrekt
> übersetzt wird (und ich hab keine Lust zum testen/simulieren).

Da fehlt glaub ein a, sonst gibt das r30+ oder so anstatt z+.
1
void store (uint8_t *buf) 
2
{
3
  uint8_t num = 100;
4
  asm volatile ("0:"                      "\n\t"
5
           "in   __tmp_reg__, %[pins]"    "\n\t"
6
           "st   %a[ptr]+, __tmp_reg__"   "\n\t"
7
           "dec  %[num]"                  "\n\t"
8
           "brne 0b"
9
        : [ptr] "+e" (buf)
10
        : [num] "r" (num), [pins] "I" (_SFR_IO_ADDR(PINB))
11
        :"memory"
12
        );
13
}

Johann
Persönliche Seite #1308587
Lesenswert?

Oliver schrieb:

> Definition im Assembler-File:
>>* .global (or .globl) declares a public symbol that is visible to the linker
>>(e.g. function entry point, global variable)
>
> also:
> *.s
>
1
> .global tab
2
> tab:       .BYTE 100
3
>
>
> *.c
>
1
> extern unsigned char tab[100];
2
>

Nicht eher so?
1
.data
2
.global tab
3
tab:       .skip 100

Ansonsten ist tab nur ein Byte, das zu 100 initialisiert ist...

Johann
Moderator Persönliche Seite #1308800
Lesenswert?

Hans Otto schrieb:

> ptr = &tab;

Wofür denn das?

Aber s. o., du schlägst den Compiler ohnehin nur minimal mit so'nem
primitiven Beispiel:

foo.c:
1
#include <avr/io.h>
2

3
uint8_t tab[100];
4

5
void
6
fill_buf(void)
7
{
8
        uint8_t i;
9
        uint8_t *p;
10

11
        for (i = 100, p = tab; i != 0; i--)
12
                *p++ = PIND;
13
}

Generierter Assemblercode:
1
.global fill_buf
2
        .type   fill_buf, @function
3
fill_buf:
4
/* prologue: function */
5
/* frame size = 0 */
6
        ldi r30,lo8(tab)
7
        ldi r31,hi8(tab)
8
.L2:
9
        in r24,41-32
10
        st Z+,r24
11
        ldi r24,hi8(tab+100)
12
        cpi r30,lo8(tab+100)
13
        cpc r31,r24
14
        brne .L2
15
/* epilogue start */
16
        ret
17
        .size   fill_buf, .-fill_buf
18
        .comm tab,100,1

Damit siehst du dann auch gleich die notwendige Syntax für den
Assemblercode...

Dass du ihn überhaupt schlägst, dürfte an den teilweise für den AVR
nicht mehr so guten ,,besonders schlauen'' Optimierungen liegen, die
GCC 4.3 offensichtlich vorrangig für unsere Desktop-Maschinen mit
ihren registermäßig verkrüppelten Prozessoren vornimmt: um die
Variable i nicht in einem Register führen zu müssen, wird der
Vergleich lieber auf die letzte zu beschreibende Adresse implementiert.
Ältere GCC-Versionen verhalten sich da sehr wahrscheinlich noch
besser (beim AVR).
Persönliche Seite #1308909
Lesenswert?

Wenn es um Geschwindigkeit geht, fällt vor allem auf, daß rund 50% der 
Zeit in der Schlaufe vertrödelt werden.

Wir schreiben also folgendes C-Programm:
1
#include <stdint.h>
2

3
extern void scan (uint8_t*);
4

5
uint8_t scan_buf[SCAN_SIZE];
6

7
int main()
8
{
9
    scan (scan_buf);
10
    return 0;
11
}

Die Funcktion scan() ist in Assembler implementiert. Sie expandiert ein 
Makro, das SCAN_SIZE mal den Port liest und den Wert speichert:
1
#include <avr/io.h>
2

3
.macro _SCAN cnt
4
.if (\cnt > 0)
5
    in   r24, _SFR_IO_ADDR (PINB)
6
    st   z+, r24
7
    _SCAN (\cnt)-1
8
.endif
9
.endm
10

11
.text
12
.global scan
13
scan:
14
    movw r30, r24
15
    _SCAN(SCAN_SIZE)
16
    ret

Übersetzt wird das dann zB per
1
avr-gcc -mmcu=atmega8 -c -Os scan.c -DSCAN_SIZE=100 -o scan.o
2
avr-gcc -mmcu=atmega8 -c scan-asm.S -DSCAN_SIZE=100 -o scan-asm.o
3
avr-gcc -mmcu=atmega8 scan.o scan-asm.o -o scan.elf
4
avr-objdump -d scan.elf > scan.lst
und liegfert ein Ergebnis wie angehängt.

Johann
Angehängte Dateien:

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren