Moin, ich mach hier gerade erste Versuche mit gemischtem Code aus C und Assembler. Beim "Inlinen" muß ich dem Compiler sagen welche Register ich zerschmettere, gilt das auch für Assembleraufrufe aus C heraus? Irgendwie hab ich das Gefühl ich zerschieße alles was rumliegt. Allerdings stürzt der ATMega nicht ab sondern holpert seltsam umher...
Stell' mal 'nen Schild: Vorsicht Stufe dann hört das Stolpern auf. Ich benutze das Studio 4. Unter "Help->avr-lib Reference Manual" findest Du Beispiele (Example Projects) zur Zusammenarbeit von C und S. Unter den FAQ findest Du auch einen Artikel zum Thema: "What registers are used by the C compiler?" Keine Ahnung, ob sich die obigen Komponenten bei den derzeitigen Versionen noch so vorhanden sind.
Joachim ... schrieb: > Beim "Inlinen" muß ich dem Compiler sagen welche Register ich > zerschmettere Deinem Geholpere nach zu urteilen, würde ich dir empfehlen, erst einmal einen riesegroßen Bogen um den Inlineassembler zu machen. Der ist ein mächtiges Werkzeug, aber absolut nicht anfängertauglich. Mit an Sicherheit grenzender Wahrscheinlichkeit brauchst du ihn auch gar nicht, sondern hast vielleicht nur vergessen, die Optimierung des Compilers einzuschalten.
Joachim ... schrieb: > ich mach hier gerade erste Versuche mit gemischtem Code aus C und > Assembler. Beim "Inlinen" muß ich dem Compiler sagen welche Register ich > zerschmettere, gilt das auch für Assembleraufrufe aus C heraus? Da mußt du dich selbst drum kümmern. > Allerdings stürzt der ATMega nicht ab sondern holpert seltsam umher... Das ist wenigstens mal eine der kreativeren unter den nutzlosen Fehlerbeschreibungen. Übrigens: Was hat die Frage eigentlich mit dem Betreff zu tun?
Joachim ... schrieb: > ich mach hier gerade erste Versuche mit gemischtem Code aus C und > Assembler. Diese Aufgabe ist unlösbar, weil: 1. Um sowas zu können, mußt Du beides (C, Asm) exzellent beherrschen. 2. Kannst Du aber C, dann besteht überhaupt kein Anlaß mehr, Assembler hinzu zu mixen. Dann schreibst Du ganz einfach alles in C. Peter
Ja... hm... ich hab deswegen nix gepostet weil ich glaube das es keinen Sinn macht weil der Fehler wohl nicht direkt im Code liegt. Im Simulator funktionieren die Code-Schnipsel wie sie sollen. Wenn ich es dann verwurste passieren aber bizarre Dinge die keinen Sinn ergeben. Hab hier AVR-Studio 6 und habe Code der mit dem AVR Assembler geschrieben wurde auf gcc übersetzt. Schon das war mit viel Kopfschütteln begleitet. Und jetzt passieren wieder so komische Sachen. Hab jetzt noch zusätzlich das Status-Register gepusht, es wird aber nicht besser. Der Code an sich funktioniert wenn auch die Kommentare sich auf ältere Zeilen beziehen. Lediglich die beiden: lsl r24 ; port for 6522 address x2 lsl r24 ; port for 6522 address x2 werfen alles durcheinander. Wenn ich die Multiplikation x4 stattdessen in main() durchführe dann geht's.
1 | |
2 | syncronize_PHI2_wrt: |
3 | push r1 |
4 | push r0 |
5 | in r0, 0x3f |
6 | push r0 |
7 | push r22 |
8 | push r24 |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | ;part 1 synchronisation macro |
16 | ; next instruction after macro is at tcnt=7, OC2=1 |
17 | ; |
18 | ; you are here | at end of macro |
19 | ; _ _ _ _ _ _ _V_ _ _ |
20 | ; Phi2 _ _| |_ _ _ _ _ _ _ _| |
21 | ; |
22 | ; tcnt 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 |
23 | ; |
24 | ; 500ns/phase, 62.5ns/count |
25 | |
26 | phi2_syncloop_wrt: |
27 | |
28 | lsl r24 ; port for 6522 address x2 |
29 | lsl r24 ; port for 6522 address x2 |
30 | out _SFR_IO_ADDR(PORTC), r24 |
31 | lds r0, TCNT0 ; in r0, 0xB2; TCNT0 |
32 | sbic _SFR_IO_ADDR(PINB),4 ;sbic PIND,7 sbic pind,7 ;wait for phi2 low |
33 | rjmp phi2_syncloop_wrt |
34 | ldi r30,lo8(gs(phi2_synctable_wrt)); ldi zlo,lo8(phi2_synctable) |
35 | ldi r31,hi8(gs(phi2_synctable_wrt)); ldi zhi,hi8(phi2_synctable) |
36 | add r30,r0 ;calculate offset cycles |
37 | ijmp |
38 | |
39 | ;.if ((PC & 0xff) > 0xf8 ) ;keep table on same page - avoid adc zh,zero ...AVR Ssyntax |
40 | .if ( ( __AVR_2_BYTE_PC__ & 0xff) > 0xf8 ) ;keep table on same page - avoid adc zh,zero |
41 | .align 8 ; new page |
42 | ;.org ((__AVR_2_BYTE_PC__ + 0x100) & 0xff00 ...AVR Ssyntax |
43 | .endif |
44 | |
45 | phi2_synctable_wrt: ;delay -1 cycle for each count in tcnt |
46 | nop ;0/1 - tcnt=0/OC2=1 |
47 | nop ;1/1 |
48 | nop ;2/1 |
49 | nop ;3/1 |
50 | nop ;4/1 |
51 | nop ;5/1 |
52 | nop ;6/1 |
53 | ; next 7/1 - output to next cycle, input from previous cycle |
54 | ; |
55 | ;part 2 synchronized write |
56 | ; |
57 | ; output data valid + |
58 | ; address valid + | |
59 | ; after sync + | | |
60 | ; | | _ _ _ _ _ _ _|_ _ _ _ _ _ _ |
61 | ; chip select _ _|_ _|_ _| | |_ _ _ |
62 | ; _ _ _ _V_ | _ _V_ _ _ _ _ _ |
63 | ; Phi2 |_V_ _ _ _ _ _ _| |_ _ _ _ |
64 | ; |
65 | ; tcnt 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 |
66 | ; |
67 | ;.macro phi2_wrt |
68 | |
69 | cbi _SFR_IO_ADDR(PORTC),7 ;R/W ;7/1 generate R/-W - tcnt=7/OC2=1 |
70 | sbi _SFR_IO_ADDR(PORTC),6 ;CS = 1 ;1/0 CS strobe high >300ns before phi2 |
71 | nop2 ;3/0 |
72 | nop2 ;5/0 |
73 | nop ;7/0 |
74 | out _SFR_IO_ADDR(PORTD),r22 ;Data out ;0/1 precharge data to be written |
75 | nop; out dbusddr,allon ???? ;1/1 write data valid 125 ns after phi2 le |
76 | nop2 ;2/1 |
77 | nop2 ;4/1 |
78 | nop2 ;6/1 |
79 | cbi _SFR_IO_ADDR(PORTC),6 ;CS = 0 ;0/0 end strobe 60ns after phi2 te |
80 | |
81 | ; out dbusddr,zero ;data hold ends |
82 | |
83 | pop r24 |
84 | pop r22 |
85 | pop r0 |
86 | out 0x3f, r0 |
87 | pop r0 |
88 | pop r1 |
89 | ret |
Joachim ... schrieb: > Beim "Inlinen" muß ich dem Compiler sagen welche Register ich > zerschmettere Der Compiler ist das ganz leidenschaftslos. Sobald er das Schlüsselwort "asm" sieht, klinkt er sich einfach aus. Für ihn haben alle (Status-/) Register nach dem Assembleraufruf den alten Wert. Alles, was Du zerstörst, mußt Du auch selber sichern. Joachim ... schrieb: > gilt das auch für Assembleraufrufe aus C heraus? Es gelten die Aufrufkonventionen des C-Compilers. Einige Register sind zerstörbar, andere müssen gesichert werden. Peter
Erzähl dochmal, was das überhaupt werden soll. Dann sieht man bestimmt viel klarer. Man übersetzt nicht zeilenweise Assembler in C. Man übersetzt nur die Funktionsweise. Peter
>Man übersetzt nicht zeilenweise Assembler in C Ich hab nicht Assembler in C übersetzt sondern AVR Assembler-Dialekt in vom gcc lesbaren Dialekt (kann man das so sagen?). Was mich halt wundert, ist, daß das r24 scheinbar so kritisch ist. Oder zB die vielen nops; wenn der Compiler da was wegoptimiert stimmt die Tabelle die ich zur Synchronisation benötige nimmer. Ich denke aber das ist es nicht - es scheint als ob der Fehler von ausserhalb kommt. Aufgerufen wird mit: extern void syncronize_PHI2_wrt(unsigned char, unsigned char); // 6522 addr, 6522 data im asm-File findet sich entsprechend: .global syncronize_PHI2_wrt ; The assembly function must be declared as global Die Register zur Übergabe sind: // 1. unsigned char : R24 // 2. unsigned char : R22 Also alles eingentlich so wie es auf dem Kochrezept steht. Wenn ich nach dem Initialisieren des 6522 dann alle paar zehntel Sekunden nen Bitmuster für ein Hello-World-Lauflicht auf den Port lege verschluckt sich das ganze. syncronize_PHI2_wrt(VIA_IOR_A, 0x01); wait(); syncronize_PHI2_wrt(VIA_IOR_A, 0x02); wait(); syncronize_PHI2_wrt(VIA_IOR_A, 0x04); wait(); syncronize_PHI2_wrt(VIA_IOR_A, 0x08); wait(); wait() ist zum debuggen nur ein _delay_ms(100);
Joachim ... schrieb: > Wenn ich nach dem Initialisieren des 6522 dann alle paar zehntel > Sekunden nen Bitmuster für ein Hello-World-Lauflicht auf den Port lege Dann ist es doch völliger Unsinn, auf 62ns genau sein zu wollen. Machs in C und gut is. Man verrennt sich da gerne mal in unnötig umständliche Lösungen. Nicht die genaueste Lösung ist die beste, sondern die ausreichende. In 99,9% wo der Assemblerprogrammierer meint, mit Zyklen knausern zu müssen, trifft das nicht zu. Aber um das einzuschätzen, müßte man eben die eigentliche Aufgabe kennen. Um in C etwas auf 62ns genau auszugeben, würde ich völlig anders vorgehen. Man setzt den Write-Pin auf einen Output-Compare-Pin und den schaltet dann der Timer auf 1 Zyklus genau. Die Software muß nur alles vorher vorbereitet haben. Ganz ohne Assembler-Gefrickel. Man kann sogar 100 Ausgänge exakt gleichzeitg ausgeben. Man kaskadiert einfach entsprechend viele 74HC595 und setzt mit dem Output-Compare-Pin den Registertakt. Peter
Schnauf. Schnaubb... Peter! Es geht wieder wie so oft am Eingangsthema vorbei. 62 oder 62.5ns, das ist nicht der Punkt. Ich teile einfach 16MHz durch 16 und muß in den Low-Pegel eines 1MHz Taktes springen. Der ist 500ns lang, davon müssen wir noch vorne und hinten zuammen etwa 100ns abziehen (setup time), dann bleiben noch ca 400ns. Das funktioniert alles. Wenn ich das multiplizieren in C löse funktioniert der Code. Nur wenn ich die ASM- Verschiebebefehle 'lsl' einflechte funktioniert es nicht. Mir geht's nicht um einen Workaround. Ich möchte einfach herausfinden was in diesem speziellen Fall quer läuft.
Joachim ... schrieb: >>Man übersetzt nicht zeilenweise Assembler in C > Ich hab nicht Assembler in C übersetzt sondern AVR Assembler-Dialekt in > vom gcc lesbaren Dialekt (kann man das so sagen?). Fast. Der Code wird nicht vom GCC ausgewertet, sondern vom GNU-Assembler (gas), hier also avr-as. > Was mich halt wundert, ist, daß das r24 scheinbar so kritisch ist. Ist es nicht. Die Funktion ist keine ISR und - R24 muss nicht gesichert / restauriert werden - R22 muss nicht gesichert / restauriert werden - R0 muss nicht gesichert / restauriert werden - SREG muss nicht gesichert / restauriert werden (Ausser evtl. I-Flag) - R1 muss nicht gesichert und nur bei Überschreiben wieder auf 0 gesetzt werden, etwa wenn ein MUL verwendet wurde. Siehe ABI http://gcc.gnu.org/wiki/avr-gcc#Register_Layout > wenn der Compiler da was wegoptimiert Es ist Assembler-Code, der Compiler bekommt ihn nie zu sehen. > es scheint als ob der Fehler von ausserhalb kommt. Wenn ISRs aktiv sind, erzeugen die einen riesigen Jitter, der die Timing-Sequenz komplett unbrauchbar macht. Beachte auch Effekte wie parasitäre Port-Kapazitäten etc., das kann die Signale um mehrere Ticks verziehen.
Joachim ... schrieb: > Ich teile einfach 16MHz durch > 16 und muß in den Low-Pegel eines 1MHz Taktes springen. Der ist 500ns > lang, davon müssen wir noch vorne und hinten zuammen etwa 100ns abziehen > (setup time), dann bleiben noch ca 400ns. Das funktioniert alles. Bloß weiß hier keiner, warum Du das so kompliziert machst und was "funktioniert" bedeutet. Joachim ... schrieb: > Nur wenn ich die > ASM- Verschiebebefehle 'lsl' einflechte funktioniert es nicht. Und wieder, keiner weiß, was "nicht funktioniert" oder "holpern" bedeutet. Ein Funktionieren kann man erst prüfen, wenn man den Sinn hinter dem ganzen versteht. Du steckst da drin, wir aber nicht. Wir sehen nur ein merkwürdiges klitze kleines Teilchen irgendeines unbekannten Codes mit unbekannter Funktion. Joachim ... schrieb: > Mir geht's nicht um einen Workaround. Mir auch nicht, sondern um Lösungen. Aber dazu muß man erstmal das Problem kennen. Andere im Nebel stochern lassen, bringt Dich bestimmt nicht weiter. Peter
Mein lieber Peter, ich schätze deine Kompetenz und deine große Erfahrung. Wirklich. Aber wir wollen jetzt nicht ausdiskutieren was "funktionieren" oder "funktionieren nicht" bedeutet, oder? Denn dann können wir auch diskutieren ob eine "0" eine "1" ist... Ich seh' schon - da muß ich alleine durch. Übrigens, in den Ascii-Skizzen zum Code ist praktisch alles enthalten worum es geht. Mehr hatte ich nicht bekommen. Aber wie gesagt - das alles hat mit dem Problem nichts zu tun. Ich brech jetzt ab. Vielleicht liegt's ja an mir. Johann: Danke für die Hinweise auf die Register. Ich hatte ähnliches vermutet, war mir aber überhaupt nicht sicher. Danke an die anderen Helfer. E N D E
Joachim ... schrieb: > Aber wir wollen jetzt nicht ausdiskutieren was "funktionieren" oder > "funktionieren nicht" bedeutet, oder? Doch, genau das will er, denn "funktioniert nicht" ist als Fehlerbeschreibung unzureichend. Erwartest du auch, daß dein Arzt eine Diagnose stellt, wenn du ihm am Telefon sagst, daß dir was weh tut, ohne weitere Angabe, was, wo und in welcher Situation?
Joachim ... schrieb: > Aber wir wollen jetzt nicht ausdiskutieren was > "funktionieren" oder "funktionieren nicht" bedeutet, oder? Doch. Wenn Du in die Werkstatt gehst und sagst, "mein Auto funktioniert nicht" und Du verschweigst, dass lediglich der elektrische Scheibenheber kaputt ist, dann muss derjenige in der Werkstatt ziemlich lange suchen. > Ich brech jetzt ab. Vielleicht liegt's ja an mir. Ja, es liegt eindeutig an Dir. Besser wäre es gewesen, den konkreten "funktionierenden" C-Code (also die Multiplikation und das drumherum) dem "nicht funktionierendem" Assemblercode gegenüberzustellen. Dann hätte das jeder mit C-Compiler bzw. Assembler nachstellen können und evtl. auch erklären können, warum der Assembler-Code nicht 1:1 das macht, was Dein C-Code tut. EDIT: Einfach ein paar Aufrufe der völlig unbekannten Funktion syncronize_PHI2_wrt() in ein Posting zu klatschen, ohne zu erklären, was die mit dem geposteten Assembler-Code zu tun hat, grenzt an Unverschämtheit.
Frank M. schrieb: > Einfach ein paar Aufrufe der völlig unbekannten Funktion > syncronize_PHI2_wrt() in ein Posting zu klatschen, ohne zu erklären, was > die mit dem geposteten Assembler-Code zu tun hat, grenzt an > Unverschämtheit. Naja, die "völlig unbekannte Funktion syncronize_PHI2_wrt()" ist der gepostete Assembler-Code, wie man an dessen erster Zeile erkennen kann. Zum Rest deines Postings gebe ich dir recht.
Rolf Magnus schrieb: > Naja, die "völlig unbekannte Funktion syncronize_PHI2_wrt()" ist der > gepostete Assembler-Code, wie man an dessen erster Zeile erkennen kann. Ich meinte aber die C-Variante, die ich hier vermisse, damit man auch einen Soll-Ist-Vergleich machen kann. > Zum Rest deines Postings gebe ich dir recht. Danke :-)
Frank M. schrieb: > Einfach ein paar Aufrufe der völlig unbekannten Funktion > syncronize_PHI2_wrt() in ein Posting zu klatschen, ohne zu erklären, was > die mit dem geposteten Assembler-Code zu tun hat, grenzt an > Unverschämtheit. Die "unbekannte Funktion" steht in Assembler: Beitrag "Re: Multiplizieren geht schief" Allerdings erzeugt der seltsame Prolog einen Offset, der vermutlich bei der Synchronisation zu beachten ist — was aber nicht gemacht wird? Um genau solche Dinge verstehen zu können, braucht es eine bessere Beschreibung von seiten des OP; z.B verstehe ich nicht, was passiert wenn R24 durch die LSL leer wird (und bleibt). Ohne solche Erklärungen kann man hier bestenfalls Anmerkungen zur Syntax machen, aber das kann der avr-as auch...
Der Fehler wird wohl das hier sein, zumindest sehe ich keinen Sinn darin: Joachim ... schrieb: > phi2_syncloop_wrt: > lsl r24 ; port for 6522 address x2 > lsl r24 ; port for 6522 address x2 ... > rjmp phi2_syncloop_wrt Letzendlich ist das Problem, daß man sich nicht die Mühe macht, in Worten zu beschreiben, was abgehen soll. Eine Beschreibung ist nicht nur für andere da. Sie ist vor allem für den Programmierer selber, den Durchblick zu behalten! Naja, etwas Beschreibung ist ja da, aber wohl zu wenig. Zum Verstehen muß man wohl das Datenblatt diese komischen 6522 lesen. Ich würde lieber erst gar keine Chips aus dem Museum einsetzen. Zu der umständlichen Programmierung kommt noch die schwere und teure Beschaffung hinzu. Manche Leute schreiben über jede Funktion einen Header, was sie machen soll. Ich finde das gut. Peter
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.