Archiv verlassen und diese Seite im Standarddesign anzeigen : Schnelle Multiplikation von Bytes
Hi!
Da ich sehr viele Multiplikationen ausführen muss, kommt es sehr auf die Geschwindigkeit an. Wenn ich es über Bitverschieben mache, ist es langsamer, als die herkömliche Multiplikation.
Gibt es noch eine andere Möglichkeit schnell zu multiplizieren?
Gruß,
Rasmus
Schneller geht es über den in neueren AVR eingebauten Hardware-MUL ASM Befehl.
BASCOM-AVR verwendet automatisch diesen, falls der Prozessor über einen solchen verfügt.
Einen AVR verwenden mit dem Befehl MUL in den ASM-Befehlen wird hier einiges bringen.
Welche unterstützen denn den MUL Befehl?(Ich verwende einen ATmega32)
Gruß,
Rasmus
dennisstrehl
01.06.2006, 15:17
Der AtMega32 besitzt so einen Multiplikator (steht im Datenblatt auf der ersten Seite, 6. oder 7. Zeile) ("On-Chip Two-Cycle Hardware Multiplier")
MfG
Was ja heißen würde, das noch schnellere Multiplikationen nicht möglich sind, oder? Gibt es noch einen anderen AVR der das schneller kann, bzw einen schnelleren Befehl?
Gruß,
Rasmus
dennisstrehl
01.06.2006, 15:51
Gehen dir 2 Takte nicht schnell genug?
Hups, ich sehe gerade, du proggst in Basic, da läuft das natürlich nicht 100% effektiv.
Aber im Grunde gibt es unter den AVRs nix schnelleres, da müsstest du wenn dann auf ARM / DSPs umsteigen
Ja, einen ARM habe ich auch schon in Erwägung gezogen.
Wie groß ist denn ungefähr die Leistungssteigerung (wenn ich zb den H2148 von Phillips nehme)?
Gruß,
Rasmus
Rage_Empire
01.06.2006, 16:51
wie wäre es mit Megas, die bis 20MHz laufen? wären immerhin 4Mips mehr.
Hmm, ich denke mal die Multiplikation von 2 Bytes dürfte im ARM archtekturbedingt länger dauern (also mehr Takte).
Aber das heißt ja das ein ARM gar nicht schneller ist!
Welcher Chip ist denn dann am geeignetsten?
Einer mit einem möglichst hohen Prozessortakt?
Gruß,
Rasmus
Also ich weiss ja nicht, was du genau vorhast, allerdings kommt mir eine Multiplikation innerhalb von nur 2 Takten doch schon sehr schnell vor.
Das es mit Bascom defakto länger dauern dürfte, könnte unter anderem am Programmierstil des User und an gewissen Bascomtypischen Eigenheiten liegen.
Im Übrigen ist der Takt des Rechenwerks an sich sicherlich ein Maßstab für die Geschwindigkeit an sich. Allerdings darf man dabei nicht die Pheripherie aus den Augen lassen. Den was nützt mir ein Takt von 1 GHz, wenn der Rest des Systems über einen Bus angebunden wird, der nur 10MHz schafft ... (vorsicht Übertreibung).
Des weiteren sollte man sich vor Augen füren, das 32 Bit nicht automatisch schneller sind wie 8 Bit.
Grüße,
da Hanni.
Habe gerade mal bei Reichelt einen Atmelchip mit bis zu 60MHZ gefunden ( AT 89C51ED2 PDIP), ist wohl der schnellste AVR, oder gibt es noch schnellere?
Ja 2 Takte ist schnell, aber was ja dann wirklich heißt, je höher die Taktrate, desto mehr Multiplikationen.
Gruß,
Rasmus
Der AT89C51ED2 ist im übrigen ein 8051er Derivat. Diese haben wieder andere Vor- & Nachteile.
Ich übrigen ist dieses kein AVR.
Grüße.
da Hanni.
Achso :-(. Das heißt entweder ich finde mich mit den maximal 20 MHZ ab, oder ich muss nen FPGA nehmen und den mit Verilog oder so programmieren.
Gruß,
Rasmus
wobei du dich immernoch darüber ausschweigst, wofür du soooo furchtbar schnelle Multiplikationen brauchst.
Achso sry, es geht um eine Verschlüsselung.
Tjo, für sowas könnte man tatsächlich einen ARM nehmen ... es gibt da so einige Typen, die beherrschen z.B. AES von Haus aus via Hardware (z.B. die AT91SAM7XC Reihe). Wesentlich schneller als damit wirst du wahrscheinlich nicht bekommen.
Grüße,
da Hanni.
SprinterSB
01.06.2006, 18:55
Bist du sicher, daß du die Zeit beim Multiplizieren verlierst? Und nicht etwa sonst im Programm, weil es den µC nicht optimal ausnutzt?
Mit dem mul-Befehl schafft man 500000 Multiplikationen pro Sekunde und Takt (in MHz gemessen). Das ist natürlich die reine Multiplikation ohne Beschaffen/Speichern/Verarbeiten der Werte.
Wie lange dauern denn 100000 Multiplikationen bei dir?
Ich brauche für 1 Million Multiplikationen ca 4,7 Sekunden. Also schnell ist das ganze schon, aber eben nicht schnell genug ;-).
Gruß,
Rasmus
SprinterSB
01.06.2006, 19:27
Bei welchem Takt. Bezogen auf 1MHz?
***EDIT***
BTW: AT 89C51ED2 ist kein AVR, sondern ein 8051-Derivat, vermutlich mit interner Taktteilung durch 12...
Rage_Empire
01.06.2006, 19:48
also, die MHz-Zahl kannste mal ganz schnell vergessen, weil die sagt über die schnelligkeit von rechenoperationen am wenigsten aus. Ich weiß ja nicht um welchen faktor du es schneller benötigst. in bascom kann man auch asm-routinen ohne probleme einfügen. ich weiß ja nicht, ob 4Mips, die ich oben genannt habe vollkommen ausreichen. immerhin sind 4Mips 4milionen Befehle pro sekunde (bei avrs).
Vieleicht sind deine Multipliziergeschichten auch einfach nur umständlich, aber ich weiß ja nicht worum es geht.
Oftmals liegt das Problem nicht in der Leistung sondern in der Logik des Programmierers(keine Kritik, nur eine feststellung die ich auch schon bei mir manchmal machen musste)
Ach ja, deine FPGA-Geschichte solltest du dir ganz aus dem Kopf schlagen.....das ist zu viel aufwand und benötigt vieles an wissen und erfahrung(glaub mir). Wenn alles nichts bringt, nimm dein PC oder eine Slot-CPU.
***EDIT***
BTW: AT 89C51ED2 ist kein AVR, sondern ein 8051-Derivat, vermutlich mit interner Taktteilung durch 12...
Wählbar zwischen 6 und 12 ... wenn ich das richtig aus dem Datenblatt heraus interpretiere.
Hmm .. und bei den 4,7 sek für 1 Mio Multiplikationen wäre wirklich mal der Takt interessant ... normalerweise würde ich bei der "Performance" von 1 oder 2 MHz ausgehen ... es sei denn es ist wirklich etwas umsändlich gecodet.
Grüße,
da Hanni.
Ne 16MhZ, ist nur ne For Next schleife und dadrin eine Zahl die mit einer anderen Multipliziert wird, und in einer Variable gespeichert wird.
Vielleicht liegt es am Timerinterrupt mit dem ich die Zeit messe.
Gruß,
Rasmus
Nimm mal in diesem Fall WinAVR zum proggen.
Bascom beherscht kein Registerrechnen, d.h. alle Variablen werden ständig aus dem RAM nachgeladen.
Ist total irre. Schau die mal das Mathe-Beispiel auf der Seite https://www.roboternetz.de/wissen/index.php/Codevergleich_AVR-Compiler an. Ich kann das aus eigener Erfahrung bestätigen.
Rage_Empire
01.06.2006, 22:49
timerinterrupt? hoffentlich weißt du, das Bascom erst alle Register vor der ISR sichert, was viel Zeit kostet. Abhilfe schafft der Befehl NOSAVE, aber man sollte schon wissen, wie und was.
Ich finde es jedenfalls falsch gleich von Bascom abzuraten....
Jedenfalls sollte man schon wissen, wie Bascom vorgeht!
So! Ich habe jetzt mal mit Stopuhr gestoppt(AVR Resetet und gleichzeitig Uhr gestartet)
Für 10 Millionen Multiplikationen hat er 41,31 Sekunden gebraucht.
Mein Code:
$regfile = "m32def.dat"
$crystal = 16000000
$baud = 38400
Dim A As Byte
Dim N As Integer
Do
For N = 0 To 10000000
A = 5 * 2
Next
Print "Fertig"
Loop
Da ich noch nie was mit WinAVR gemacht habe würde ich mich freuen wenn jemand auch mit dem Mega32 und 16MhZ im Prinzip den gleichen Code ausführen lässt und mal die Zeit postet. Dann würde man sehen welche Sprache nun schneller ist ;-), bzw. für so welche Aufgaben besser geeignet ist.
Gruß,
Rasmus
also, die MHz-Zahl kannste mal ganz schnell vergessen, weil die sagt über die schnelligkeit von rechenoperationen am wenigsten aus.
Aber die MHz geben ja die Taktzeiten vor. Und jede Operation benötigt mind. einen Takt. Also, je mehr MHz, desto kürzer die Taktzeiten, desto schneller die Operation!
Und 4MIPS mehr bei 4MHz mehr bekräftigt ja meine Aussage.
Allerdings wären es nicht 4MIPS mehr wenn eine Multipliaktion 2 Takte benötigt, sondern nur 2MIPS mehr im vergleich zu 16MHz.
Bei 16MHz und 2 Takten pro Multiplikation wären also theoretisch 8.000.000 Multiplikationen pro Sekunde möglich. (und somit auch 8MIPS!)
Was deine Rechnung aus dem Beispiel ausbremst ist schonmal die Schleife. Zum einen braucht sie selber auch Zeit zum ausführen. Zum anderen läuft sie bei 10.000.000 was schon um einiges mehr ist als die 8 Bit die der AVR auf einmal verarbeitet. Damit werden schonmal mehr Takte für die Schleife benötigt, als wenn sie nur bis 255 durchlaufen würde. Du kannst N ja mal als Byte deklarieren und den Zeitunschied messen.
Später im Programm wirst du das Problem haben, das du ja nicht nur jedesmal 5*2 rechnen willst. Die Zahlen müssen ja auch erstmal irgendwo herkommen.
WinAVR mag eine Lösung sein. Der Syntax ist ähnlich. Du kannst es dir ja mal runterladen und den Code so eingeben.
Aber wenn du wirklich noch das letzte rausholen willst/musst, wäre es sicherlich besser wenn du dich mehr mit Assembler beschäftigst.
Du kannst ja im Simulator nachvollziehen, welcher Programmschritt wieviele Takte benötigt. Da siehst du dann in Bascom die Schwachstelle und kannst dir überlegen, nur bestimmte Teile in Assembler zu schreiben.
Nach dem ersten Start kurz bevor die Schleife anfängt zu zählen, sind schon 12300 Takte und 0,76875mS vorbei. Die kann man aber kaum beeinflussen. Aber ich denke beim Start kann man mit denen Leben.
Wenn die Schleife erstmal zählt, werden pro Durchgang 53 Takte benötigt. Nur die Multiplikation zeigt bei mir 3 Takte an. Ich denke, das ist annehmbar.
Die restlichen 50 Benötigt also die Schleife.
Wenn N "nur" ein Byte ist, sind es nur noch 19 Takte pro Durchgang. Ein Simples DO - LOOP braucht nur 6 Takte!
So, jetzt hab ich doch deine Arbeit gemacht. Wollte ich eigentlich garnicht ;)
Aber hier sieht man ganz gut, das es nicht drauf ankommt, wie schnell gerechnet wird, sonder der restliche dazugehörige Code auch mit beachtet werden muss.
Dim A As Byte
Dim N As Integer
Do
A = 5 * 2
Incr N
Loop Until N = 10000000
Braucht nur 52 Takte und ist schonmal ein Takt schneller.
Ich gebe zu, ich habe nicht dazu beigetragen, dein Problem zu lösen, aber ich habe es hoffentlich geschafft, klar zu machen, das in diesem Fall nicht die Multiplikation das Problem ist/war.
hmmm...
Der Integer frisst, wenn ich mich nicht täusche, ziemlich viel Recourcen was letztendlich extrem Zeitraubend sein wird. Haste schonmal ausgetestet wie Du den umschiffen könntest?
Also die Werte zum Beispiel in in einen 16 Bit Counter und ein Byte reinschreiben lassen => Overflow Flag vom Counter für das Byte zum Zählen nutzen oder anstatt dessen zwei Counter miteinander verketten?!?
Is nur so ne Idee weil ich mich noch nicht weiter damit beschäftigt hab.
Das Beispiel A = 5 * 2 ist viel zu theoretisch, da hier keine Register bemüht werden.
Bascom macht daraus:
5E: E08A LDI R24,0x0A Load immediate
5F: 93800060 STS 0x0060,R24 Store direct to data space
oder auf deutsch A=10 :-)
Nur die Multiplikation zeigt bei mir 3 Takte an.
genau 1 Takt für LDI und 2 Takte für STS = 3 Takte :oops:
Achso sry, es geht um eine Verschlüsselung.
Zeig mal etwas Code. Verschlüsselung erfordert wohl etwas mehr, als eine Byte-Multiplikation mit einem Integer-Inkrement.
Das Beispiel A = 5 * 2 ist viel zu theoretisch, da hier keine Register bemüht werden.
Eben, das wird sowas von wegoptimiert...
Es hat mich wirklich interessiert, wie lange das mit gcc etwa dauern könnte, hier ein Pseudocode mit Mega8 und 16 MHz:
uint8_t zahlen[] = { 1,2,3,4,5,6,7,8,9,0 };
uint32_t loop = 10000000;
uint8_t resultat;
uint8_t a = 0;
uint8_t b = 9;
uart_init();
while(loop){
resultat = zahlen[a] * zahlen[b];
a++;
b--;
if (a == 10) a=0;
if (b == 0 ) b=9;
loop--;
}
Naja, sinnlos...
Nach etwa 14 Sekunden war er damit fertig...
Gruß Sebastian
Du warst zu schnell, wollte noch zur Info den gesamten Bascom-Assembler posten für die drei Zeilen:
For N = 0 To 10000000
A = 5 * 2
Next
; For N = 0 To 10000000
+00000043: E080 LDI R24,0x00 Load immediate
+00000044: E090 LDI R25,0x00 Load immediate
+00000045: E6A1 LDI R26,0x61 Load immediate
+00000046: E0B0 LDI R27,0x00 Load immediate
+00000047: 938D ST X+,R24 Store indirect and postincrement
+00000048: 939C ST X,R25 Store indirect
loc_49:
+00000049: E840 LDI R20,0x80 Load immediate
+0000004A: E956 LDI R21,0x96 Load immediate
+0000004B: E968 LDI R22,0x98 Load immediate
+0000004C: E070 LDI R23,0x00 Load immediate
+0000004D: E6A1 LDI R26,0x61 Load immediate
+0000004E: E0B0 LDI R27,0x00 Load immediate
+0000004F: 910D LD R16,X+ Load indirect and postincrement
+00000050: 911D LD R17,X+ Load indirect and postincrement
+00000051: FB17 BST R17,7 Bit store from register to T
+00000052: F41E BRTC PC+0x04 Branch if T flag cleared
+00000053: EF2F SER R18 Set Register
+00000054: EF3F SER R19 Set Register
+00000055: C002 RJMP loc_58 Relative jump
loc_56:
+00000056: 2722 CLR R18 Clear Register
+00000057: 2733 CLR R19 Clear Register
loc_58:
+00000058: 940E0090 CALL 0x00000090 Call subroutine
+0000005A: F01C BRLT loc_5E Branch if less than, signed ;Adr=
+0000005B: F011 BREQ loc_5E Branch if equal
+0000005C: 940C0067 JMP loc_67 Jump
; A = 5 * 2
loc_5E:
+0000005E: E08A LDI R24,0x0A Load immediate
+0000005F: 93800060 STS 0x0060,R24 Store direct to data space
10: Next
+00000061: E6A1 LDI R26,0x61 Load immediate
+00000062: E0B0 LDI R27,0x00 Load immediate
+00000063: 940E006F CALL loc_6F Call subroutine
+00000065: 940C0049 JMP loc_49 Jump
loc_67:
+00000067: ; SCHLEIFENENDE -> WEITER IM CODE
; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦
loc_6F:
+0000006F: 91ED LD R30,X+ Load indirect and postincrement
+00000070: 91FC LD R31,X Load indirect
+00000071: 9631 ADIW R30,0x01 Add immediate to word
+00000072: 93FC ST X,R31 Store indirect
+00000073: 93EE ST -X,R30 Store indirect and predecrement
+00000074: 9508 RET Subroutine return
das sind dann 26 Words in der Schleife
und jetzt mal in WinAVR:
uint32_t n;
uint8_t a;
for (n=0; n < 10000000; n++)
{
a=TCNT0; //damit der Compiler es nicht wegoptimiert
}
; for (n=0; n < 10000000; n++)
+0000005C: E020 LDI R18,0x00 Load immediate
+0000005D: E030 LDI R19,0x00 Load immediate
+0000005E: E040 LDI R20,0x00 Load immediate
+0000005F: E050 LDI R21,0x00 Load immediate
; a=TCNT0;
loc_60:
+00000060: B782 IN R24,0x32 In from I/O location
+00000061: 5F2F SUBI R18,0xFF Subtract immediate
+00000062: 4F3F SBCI R19,0xFF Subtract immediate with carry
+00000063: 4F4F SBCI R20,0xFF Subtract immediate with carry
+00000064: 4F5F SBCI R21,0xFF Subtract immediate with carry
+00000065: 3820 CPI R18,0x80 Compare with immediate
+00000066: E986 LDI R24,0x96 Load immediate
+00000067: 0738 CPC R19,R24 Compare with carry
+00000068: E988 LDI R24,0x98 Load immediate
+00000069: 0748 CPC R20,R24 Compare with carry
+0000006A: E080 LDI R24,0x00 Load immediate
+0000006B: 0758 CPC R21,R24 Compare with carry
+0000006C: F398 BRCS loc_60 Branch if carry set
das sind dann 12 Words in der Schleife
Rage_Empire
02.06.2006, 08:23
Die schleife frisst viel, egal mit was compiliert wird. Zudem Hat es Marco schon angesprochen, daß der Ablauf ja nicht nur die Multiplikation abarbeitet.
Wie e-fan schon geschildert würde ich auch versuchen mit 8bit-Schlaufen manuel zu arbeiten, welche ineinander greifen....denn....2schlaufen von 8bit sind schon 65025, nochmal 8 bit wären 16581375!
Also 3 Schlaufen a 8Bit. Und wenns richtig schnell werden soll am besten ASM!
@-tomas
Auch eine Multiplikation von A = A*2 und danach A = 2 dauert nicht mal 1/20 länger.
Werde dann wohl am besten Bascom nehmen und ASM Routinen für die Berechnungen.
Gruß,
Rasmus
wie ich schon sagte, alles zu theoretisch ( A = A*2)
Du müsstes mal den Codeausschnitt oder den Algorithmus zeigen.
ASM Routinen für die Berechnungen
gute Idee, da Bascom in ASM direkt die Bascom-Variablen ansprechen kann:
Hier mal ein Codeschnipsel für eine NoSave-ISR mit zwei Variablen in den verschiedenen Schreibweisen (Pointer etc)
Config Timer0 = Timer , Prescale = 1024 'Takt: 64µs
On Timer0 Timer_irq Nosave 'Timerüberlauf ISR
Const Timervorgabe = 0
Dim Ueberlauf As Byte 'wegen Assembler als Byte
Timer_irq:
'Nosave ISR -> save used register
push r24
in r24,sreg
push r24
'Timer0 laden
ldi r24, Timervorgabe
!out Tcnt0 , R24
'Set Ueberlauf
ldi r24, $01
sts {Ueberlauf}, r24
'restore used register
pop r24
!out sreg,r24
pop r24
Return
Danke!
Ich denke mal C und ASM-Rechenroutinen oder Bascom und ASM-Rechenroutinen machen keinen großen Unterschied, oder?
Bin gerade erst in das Projekt eingestiegen und soll jetzt die Umsetzung auf nem AVR Realisierung. Werde hier dann demnächst mal in diesem Thread berichten wie das Projekt verläuft.(Muss jetzt erstmal Robocup machen ;-) ).
Gruß,
Rasmus
Hier mal in Assembler, weniger als 3,3 sekunden O:)
.include "m32def.inc"
.def temp = r16
.def temp2 = r17
.def temp3 = r18
.def counter1 = r20
.def counter2 = r21
.def counter3 = r22
init:
ldi temp, 0xff ;Ausgänge schalten um das Ende mit
out DDRB, temp ;einer LED mitzuteilen
out PortB, temp
ldi counter1, 128 ;24bit Zahl (=1000000)
ldi counter2, 150
ldi counter3, 152
start:
ldi temp, 5 ;Werte laden
ldi temp2, 2
multiplikation:
mul temp, temp2 ;multiplizieren
dec counter1 ;Schleife abarbeiten
brne multiplikation
dec counter2
brne multiplikation
dec counter3
brne multiplikation
fertig:
cbi PortB, 2 ;LED an um Ende zu singalisieren
ende:
rjmp ende
Zu multiplizierende Werte in temp und temp2 laden, das Ergebniss steht dann in r0 und r1.
Das Ergebniss könnte man dann auch gleich verarbeiten, nach erfolgter multiplikation kurze subroutine aufrufen und wieder zurückspringen.
.include "m32def.inc"
.def temp = r16
.def temp2 = r17
.def temp3 = r18
.def counter1 = r20
.def counter2 = r21
.def counter3 = r22
init:
ldi temp,high(RAMEND) ;Stack einrichten
out SPH,temp
ldi temp,low(RAMEND)
out SPL,temp
ldi temp, 0xff ;Ausgänge schalten um das Ende mit
out DDRB, temp ;einer LED mitzuteilen
out PortB, temp
ldi counter1, 128 ;24bit Zahl (=1000000)
ldi counter2, 150
ldi counter3, 152
start:
ldi temp, 5 ;Werte laden
ldi temp2, 2
multiplikation:
mul temp, temp2 ;multiplizieren
rcall subroutine ;Ergebniss auswerten
;schneller wäre es die subroutine gleich hier auszuführen
dec counter1 ;Schleife abarbeiten
brne multiplikation
dec counter2
brne multiplikation
dec counter3
brne multiplikation
fertig:
cbi PortB, 2 ;LED an um Ende zu singalisieren
ende:
rjmp ende
;===========================
subroutine:
;hier kann man etwas mit dem in r0 und r1 stehenden Ergebniss machen
ldi temp, 4 ;neue Werte laden
inc temp2
ret ;zurück zum rechnen
Allerdings braucht das dann schon 9 Sekunden.
Wie weit wird denn das Ergebniss verarbeitet?
das sollte auf jeden fall auch in Assembler erfolgen, sonst werden aus den 3,3 Sekunden 3,3 Minuten :-(
Gruß,
Sven
SprinterSB
02.06.2006, 19:14
Es hat mich wirklich interessiert, wie lange das mit gcc etwa dauern könnte, hier ein Pseudocode mit Mega8 und 16 MHz:
uint8_t zahlen[] = { 1,2,3,4,5,6,7,8,9,0 };
uint32_t loop = 10000000;
uint8_t resultat;
uint8_t a = 0;
uint8_t b = 9;
uart_init();
while(loop){
resultat = zahlen[a] * zahlen[b];
a++;
b--;
if (a == 10) a=0;
if (b == 0 ) b=9;
loop--;
}
Naja, sinnlos...
Nach etwa 14 Sekunden war er damit fertig...
Gruß Sebastian
Wobei auch hier das wesentliche in der Tonne landet: result wird nirgends verwendet, also von gcc wegoptimiert...
Wobei auch hier das wesentliche in der Tonne landet
Stimmt, wobei irgendwoher müssen die 14 Sekunden kommen.
Aber wie man schon oben gesagt hat wird die meiste Zeit dafür draufgehen, die Daten zu besorgen und zu speichern/weiterverarbeiten und nicht für das nackte rechnen :-)
Gruß Sebastian
So! Ich habe jetzt mal mit Stopuhr gestoppt(AVR Resetet und gleichzeitig Uhr gestartet)
Für 10 Millionen Multiplikationen hat er 41,31 Sekunden gebraucht.
Dieser Assemblerschnippsel benötigtmit halbwegs realistischen Bedingungen ca: 9,4 sek (so um die 150 Mio Takte).
Anzeige wenn fertig mittels LED an PIN PD0
Halbwegs realistisch heisst:
Ich hole mir die 2 Faktoren aus dem Speicher und das 16 Bit ergebniss wandert auch dort hin.
Das Halbwegs kommt übrigens daher, das 10 Mio Multiplikationen doch schon leicht übertrieben sind. Denn:
1. alleine für die Faktoren würde man so ca: 19 MB Ram benötigen.
2. nur für die Ergebnisse ebenfalls.
Also, wenn man mit dem Mega mal ebend 38 MB externen RAM angesteuert bekommt ist das sicherlich kein Problem.
;
; Definitionsfile
.include "m32def.inc"
;
; Registeraliase
.def temp = r16
.def fak1 = r17
.def fak2 = r18
.def count1 = r20
.def count2 = r21
.def count3 = r22
.cseg
.org 0x00
;
; ISR Vektoren
jmp isr_reset ; Reset
.org 0x2A
;
; HW Initialisierung
isr_reset:
ldi temp, high(RAMEND) ; Stackpointer
out SPH, temp
ldi temp, low(RAMEND)
out SPL, temp
ldi temp, 0xFF ; alle ungenutzten Ports -> Eingang + Pullup
out PORTA, temp
out PORTB, temp
out PORTC, temp
out PORTD, temp
ldi temp, 1 ; Pin D0 -> Ausgang +H
out DDRD, temp
;
; Definierte Werte schaffen
ldi ZH, high(SRAM_START)
ldi ZL, low(SRAM_START)
ldi temp, 2
st Z, temp
ldi temp, 5
std Z+1, temp
; Main Loop
loop_init:
ldi count3, 0x98
ldi count2, 0x96
ldi count1, 0x7F
loop:
ld fak1, Z
ldd fak2, Z+1
mul fak1, fak2
std Z+2, r0
std Z+3, r1
subi count1, 1
sbci count2, 0
sbci count3, 0
brne loop
cbi PORTD, 0
break
jmp loop_init
Grüße,
da Hanni.
Wobei auch hier das wesentliche in der Tonne landet
Stimmt, wobei irgendwoher müssen die 14 Sekunden kommen.
Aber wie man schon oben gesagt hat wird die meiste Zeit dafür draufgehen, die Daten zu besorgen und zu speichern/weiterverarbeiten und nicht für das nackte rechnen :-)
Die meiste Zeit geht fürs Datenholen und den Loop drauf ...
Faktoren holen: 4 Takte
Multiplikation: 2 Takte
Ergebnis sichern: 4 Takte
der Loop: 5 Takte
man sieht, es läppert sich zusammen ... von 15 Takten die diese Schleife je Durchlauf braucht gehen mal eben 13 für den Rest drauf, was mal eben einen Anteil von 86% an der Gesamtzeit ist.
Grüße,
da Hanni.
Powered by vBulletin® Version 4.2.5 Copyright ©2024 Adduco Digital e.K. und vBulletin Solutions, Inc. Alle Rechte vorbehalten.