Ich hab nun den IRQ branch gemerged.
Nun ist es möglich die Geschwindigkeit zu drosseln. Über ein "config" Menü kann man Parameter dazu einstellen:
Von einem "realtime" timeing ist es allerdings noch weit weg. Das wird auch IMHO nie richtig funktionieren, denke ich mal...
Emulator in Python...
- jens
- Python-Forum Veteran
- Beiträge: 8502
- Registriert: Dienstag 10. August 2004, 09:40
- Wohnort: duisburg
- Kontaktdaten:
v0.3.0 ist raus: https://pypi.python.org/pypi/DragonPyEmulator/0.3.0
Änderungen:
Änderungen:
Change Display Queue to a simple Callback
Reimplement Multicomp 6809 and SBC09
Many code refactoring and cleanup
- jens
- Python-Forum Veteran
- Beiträge: 8502
- Registriert: Dienstag 10. August 2004, 09:40
- Wohnort: duisburg
- Kontaktdaten:
DragonPy läuft auch in ReactOS:
1:1 -> http://www.jensdiemer.de/static/jensdie ... eactOS.png
Aber warum auch nicht?
1:1 -> http://www.jensdiemer.de/static/jensdie ... eactOS.png
Aber warum auch nicht?
- jens
- Python-Forum Veteran
- Beiträge: 8502
- Registriert: Dienstag 10. August 2004, 09:40
- Wohnort: duisburg
- Kontaktdaten:
Auch hier mal ein Status-Update...
Wegen der Froscon hab ich noch im Vorfeld einige Änderungen vorgenommen:
Die Installation ist nun einfacher, gerade für Windows.
Denn die nötigen ROM Dateien werden nun per Python runtergeladen und entpackt.
Vorher waren es einfacher .sh scripte, die unter Windows natürlich nicht funktionierten
Die Downloads werden nach wie vor per SHA Checksum geprüft.
Wie man es Installiert, siehe README:
Wer kann eigentlich mal das ganze unter MacOSX testen?!? Und eine Anleitung dazu einsenden?!?
Dann gibt es ja neu, die "starter GUI":
und aktuell ist der "Freeze" Bug behoben. Der trat hin und wieder auf, wenn man den "Speed Limit" also den Echtzeitmodus aktivierte...
Wegen der Froscon hab ich noch im Vorfeld einige Änderungen vorgenommen:
Die Installation ist nun einfacher, gerade für Windows.
Denn die nötigen ROM Dateien werden nun per Python runtergeladen und entpackt.
Vorher waren es einfacher .sh scripte, die unter Windows natürlich nicht funktionierten
Die Downloads werden nach wie vor per SHA Checksum geprüft.
Wie man es Installiert, siehe README:
- Linux: https://github.com/jedie/DragonPy#installation
- Windows: https://github.com/jedie/DragonPy#windows
Wer kann eigentlich mal das ganze unter MacOSX testen?!? Und eine Anleitung dazu einsenden?!?
Dann gibt es ja neu, die "starter GUI":
und aktuell ist der "Freeze" Bug behoben. Der trat hin und wieder auf, wenn man den "Speed Limit" also den Echtzeitmodus aktivierte...
- jens
- Python-Forum Veteran
- Beiträge: 8502
- Registriert: Dienstag 10. August 2004, 09:40
- Wohnort: duisburg
- Kontaktdaten:
Ja, da hast du sicherlich recht. Es gibt noch einiges an Optimierungspotential.jerch hat geschrieben:@jens:
Alles innerhalb Deiner self.get_and_call_next_op Methode ist "busy loop", d.h. jeder kleine Zusatzaufwand summiert sich auf. Und von da absteigend hast Du immernoch self.-Zugriffe drin, diese sind halt teurer als lokale. Was spricht dagegen, den äusseren Zustand per Parameter an den lokalen Namensraum mitzugeben (siehe memory-Übergabe im Bsp. oben)?
Bei Deiner Registerimplementation nutzt Du u.a. getter und setter-Methoden. Die sind deutlich teurer in CPython als der direkte lesende/schreibende Attributzugriff. Da die Registermanipulation die Hauptarbeit der CPU ist, wirkt sich das massiv aus.
Ich vermute, dass Du mit Umstellung auf lokale Namen und direkten Attributzugriff die Cyclerate der CPython-Version etwa verdoppelt könntest.
Ich hab mal mit https://github.com/ymichael/cprofilev nachgesehen:
Alles Werte nach: 225213360 function calls (225053689 primitive calls) in 489.819 seconds:
Ordered by: cumulative time
Code: Alles auswählen
ncalls tottime percall cumtime percall filename:lineno(function)
12541/11961 0.052 0.000 487.153 0.041 /usr/lib/python3.4/tkinter/__init__.py:1485(__call__)
8240 0.122 0.000 485.559 0.059 /home/jens/DragonPy_env/src/dragonpy/dragonpy/core/gui.py:241(cpu_interval)
8240 0.073 0.000 485.027 0.059 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu6809.py:404(run)
8240 8.553 0.001 484.876 0.059 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu6809.py:333(burst_run)
12512 0.063 0.000 483.947 0.039 /usr/lib/python3.4/tkinter/__init__.py:533(callit)
8255100 25.451 0.000 476.791 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu6809.py:272(get_and_call_next_op)
8403598/8255100 20.331 0.000 371.806 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu6809.py:288(call_instruction_func)
15549487 66.446 0.000 149.411 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu6809.py:535(read_pc_byte)
2254891 7.468 0.000 54.801 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/instruction_call.py:537(relative_ea)
16584767 33.130 0.000 50.417 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/MC6809_registers.py:37(increment)
646331 2.206 0.000 42.781 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/instruction_call.py:136(direct_word_X_read16)
668298 2.237 0.000 38.780 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/instruction_call.py:365(indexed_A_read8)
1792270 11.384 0.000 36.726 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu6809.py:592(get_ea_indexed)
2254891 9.770 0.000 35.719 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu6809.py:756(get_ea_relative)
709969 3.198 0.000 29.866 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu6809.py:1709(instruction_CMP16)
20645223/20638957 27.729 0.000 28.087 0.000 /home/jens/DragonPy_env/src/dragonpy/dragonpy/components/memory.py:191(read_byte)
27069837 27.168 0.000 27.168 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/MC6809_registers.py:98(set_flag)
1931097 6.406 0.000 26.688 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu6809.py:561(get_ea_direct)
1010482 4.428 0.000 26.634 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu6809.py:1517(instruction_LD8)
1897318 5.883 0.000 25.682 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/MC6809_registers.py:293(update_NZ_8)
26651989 25.038 0.000 25.038 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/MC6809_registers.py:31(get)
355525 1.643 0.000 22.798 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/instruction_call.py:50(direct_ea_read8_write8)
843845 4.508 0.000 22.251 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/MC6809_registers.py:329(update_NZVC_8)
21038722 22.019 0.000 22.019 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/MC6809_registers.py:81(set)
614495 2.060 0.000 20.639 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/instruction_call.py:455(indexed_ea_X)
357440 1.230 0.000 20.088 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/instruction_call.py:289(immediate_A_read8)
41281/40419 1.656 0.000 19.682 0.000 {method 'call' of 'tkapp' objects}
734403 4.039 0.000 19.604 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/MC6809_registers.py:335(update_NZVC_16)
1 0.000 0.000 19.125 19.125 /home/jens/DragonPy_env/src/dragonpy/basic_editor/editor.py:189(command_load_file)
698567 2.273 0.000 19.040 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu6809.py:712(get_m_indexed)
...
Code: Alles auswählen
ncalls tottime percall cumtime percall filename:lineno(function)
15549487 66.446 0.000 149.411 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu6809.py:535(read_pc_byte)
16584767 33.130 0.000 50.417 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/MC6809_registers.py:37(increment)
20645223/20638957 27.729 0.000 28.087 0.000 /home/jens/DragonPy_env/src/dragonpy/dragonpy/components/memory.py:191(read_byte)
27069837 27.168 0.000 27.168 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/MC6809_registers.py:98(set_flag)
8255100 25.451 0.000 476.791 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu6809.py:272(get_and_call_next_op)
26651989 25.038 0.000 25.038 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/MC6809_registers.py:31(get)
21038722 22.019 0.000 22.019 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/MC6809_registers.py:81(set)
8403598/8255100 20.331 0.000 371.806 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu6809.py:288(call_instruction_func)
14943248 14.632 0.000 14.632 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/MC6809_registers.py:101(get_flag)
1792270 11.384 0.000 36.726 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu6809.py:592(get_ea_indexed)
2254891 9.770 0.000 35.719 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu6809.py:756(get_ea_relative)
2885523 9.441 0.000 15.200 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/MC6809_registers.py:197(set_N8)
2893451 9.213 0.000 14.940 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/MC6809_registers.py:177(set_Z8)
2068990 8.881 0.000 15.147 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/MC6809_registers.py:270(clear_NZV)
8240 8.553 0.001 484.876 0.059 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu6809.py:333(burst_run)
1578248 8.419 0.000 14.731 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/MC6809_registers.py:276(clear_NZVC)
2254891 7.468 0.000 54.801 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/instruction_call.py:537(relative_ea)
1931097 6.406 0.000 26.688 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu6809.py:561(get_ea_direct)
1897318 5.883 0.000 25.682 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/MC6809_registers.py:293(update_NZ_8)
1684193 5.427 0.000 8.761 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/MC6809_registers.py:187(set_Z16)
1661084 5.426 0.000 9.744 0.000 /home/jens/DragonPy_env/src/dragonpy/dragonpy/components/memory.py:227(read_word)
843845 4.508 0.000 22.251 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/MC6809_registers.py:329(update_NZVC_8)
1010482 4.428 0.000 26.634 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu6809.py:1517(instruction_LD8)
2428999 4.375 0.000 5.602 0.000 /home/jens/DragonPy_env/src/dragonpy/dragonpy/components/memory.py:242(write_byte)
734403 4.039 0.000 19.604 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/MC6809_registers.py:335(update_NZVC_16)
1233863 3.955 0.000 6.414 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu6809.py:2116(instruction_BNE)
1069682 3.515 0.000 5.663 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/MC6809_registers.py:207(set_N16)
919873 3.242 0.000 5.041 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/MC6809_registers.py:237(set_V8)
709969 3.198 0.000 29.866 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu6809.py:1709(instruction_CMP16)
2517144 3.182 0.000 3.182 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/utils/bits.py:20(is_bit_set)
...
Code: Alles auswählen
ncalls tottime percall cumtime percall filename:lineno(function)
12541/11961 0.052 0.000 487.153 0.041 /usr/lib/python3.4/tkinter/__init__.py:1485(__call__)
8240 0.122 0.000 485.559 0.059 /home/jens/DragonPy_env/src/dragonpy/dragonpy/core/gui.py:241(cpu_interval)
8240 0.073 0.000 485.027 0.059 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu6809.py:404(run)
8240 8.553 0.001 484.876 0.059 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu6809.py:333(burst_run)
12512 0.063 0.000 483.947 0.039 /usr/lib/python3.4/tkinter/__init__.py:533(callit)
8255100 25.451 0.000 476.791 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu6809.py:272(get_and_call_next_op)
8403598/8255100 20.331 0.000 371.806 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu6809.py:288(call_instruction_func)
15549487 66.446 0.000 149.411 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu6809.py:535(read_pc_byte)
2254891 7.468 0.000 54.801 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/instruction_call.py:537(relative_ea)
16584767 33.130 0.000 50.417 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/MC6809_registers.py:37(increment)
646331 2.206 0.000 42.781 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/instruction_call.py:136(direct_word_X_read16)
668298 2.237 0.000 38.780 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/instruction_call.py:365(indexed_A_read8)
1792270 11.384 0.000 36.726 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu6809.py:592(get_ea_indexed)
2254891 9.770 0.000 35.719 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu6809.py:756(get_ea_relative)
709969 3.198 0.000 29.866 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu6809.py:1709(instruction_CMP16)
20645223/20638957 27.729 0.000 28.087 0.000 /home/jens/DragonPy_env/src/dragonpy/dragonpy/components/memory.py:191(read_byte)
27069837 27.168 0.000 27.168 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/MC6809_registers.py:98(set_flag)
1931097 6.406 0.000 26.688 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu6809.py:561(get_ea_direct)
1010482 4.428 0.000 26.634 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu6809.py:1517(instruction_LD8)
1897318 5.883 0.000 25.682 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/MC6809_registers.py:293(update_NZ_8)
26651989 25.038 0.000 25.038 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/MC6809_registers.py:31(get)
355525 1.643 0.000 22.798 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/instruction_call.py:50(direct_ea_read8_write8)
843845 4.508 0.000 22.251 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/MC6809_registers.py:329(update_NZVC_8)
21038722 22.019 0.000 22.019 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/MC6809_registers.py:81(set)
614495 2.060 0.000 20.639 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/instruction_call.py:455(indexed_ea_X)
357440 1.230 0.000 20.088 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/instruction_call.py:289(immediate_A_read8)
41281/40419 1.656 0.000 19.682 0.000 {method 'call' of 'tkapp' objects}
734403 4.039 0.000 19.604 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu_utils/MC6809_registers.py:335(update_NZVC_16)
1 0.000 0.000 19.125 19.125 /home/jens/DragonPy_env/src/dragonpy/basic_editor/editor.py:189(command_load_file)
698567 2.273 0.000 19.040 0.000 /home/jens/DragonPy_env/src/mc6809/MC6809/components/cpu6809.py:712(get_m_indexed)
...
@jens:
In der Auflistung sieht man recht gut, wieviel Zeit in den Registern verbracht wird. Ohne Änderung der internen API könntest Du z.B. die komplexen Registermethoden optimieren und immernoch lesbar bleiben - Beispiel: Das allein wird allerdings nicht soviel bringen, auch ist im Sinne der Lokalität das self.H störend. Deutlich effektiver wäre es, die Attribut-/Methoden-Lookups lokal vorzuhalten oder ganz loszuwerden. Das ginge aber nur mit API-Änderung der Register-Objekte und entsprechender Anpassung auf Callerebene. Damit würde aber auch der Code unpythonischer, was Du wahrscheinlich nicht möchtest.
In der Auflistung sieht man recht gut, wieviel Zeit in den Registern verbracht wird. Ohne Änderung der internen API könntest Du z.B. die komplexen Registermethoden optimieren und immernoch lesbar bleiben - Beispiel:
Code: Alles auswählen
def set_H(self, a, b, r):
if self.H == 0:
r2 = (a ^ b ^ r) & 0x10
self.H = 0 if r2 == 0 else 1
# kannst Du auch schreiben als
def set_H(self, a, b, r):
if not self.H and ((a ^ b ^ r) & 0x10):
self.H = 1
- jens
- Python-Forum Veteran
- Beiträge: 8502
- Registriert: Dienstag 10. August 2004, 09:40
- Wohnort: duisburg
- Kontaktdaten:
Ja, "dot-names" zu "kürzen" bringt schon was: https://gist.github.com/jedie/015d3cb9de25eb7f0188
Hab gerade mal was probiert: https://github.com/6809/MC6809/commit/b ... 182381cL15
Am Ende kommt allerdings nicht all zu viel dabei rum. Aber in diesem Fall, ist es eh generierter code...
Hab gerade mal was probiert: https://github.com/6809/MC6809/commit/b ... 182381cL15
Am Ende kommt allerdings nicht all zu viel dabei rum. Aber in diesem Fall, ist es eh generierter code...
@jens:
Ich hab mal ein wenig mit Deinem CPU-Code rumprobiert - im Ergebnis konnte ich in CPython 2.7 die Cycles von 850.000 auf 1.300.000 bringen. Folgendes hat die Sache beschleunigt:
- Ersetzen der getter/setter durch direkten Attributzugriff am cc-Register für die einzelnen Bits (ohne API-Change, ~50% des Speedups)
- Umstellen der cc-Register-Methoden auf 1-2 Zeiler (kein API-Change, ~20% des Speedups)
- Umstellen aller lesenden Registerzugriffe von `.get()` auf `.value` in der CPU-Klasse (~20% des Speedups)
- Umstellen des Speichers von Bytearray auf eine Liste (~10% des Speedups)
Ich vermute, dass Du durch Entfernen der vielen lokalen Zwischenvariablen in den Instruktionen-Methoden noch etwas einsparen könntest. Mehr als 1.500.000 cycles/s sind aber wahrscheinlich nicht zu schaffen ohne größeren Umbau an den Registern (ist immer noch die "Hauptlast").
Edit:
Und `pypy -m MC6809.cli benchmark` läuft mit 12 Mio. cycles/s.
Ich hab mal ein wenig mit Deinem CPU-Code rumprobiert - im Ergebnis konnte ich in CPython 2.7 die Cycles von 850.000 auf 1.300.000 bringen. Folgendes hat die Sache beschleunigt:
- Ersetzen der getter/setter durch direkten Attributzugriff am cc-Register für die einzelnen Bits (ohne API-Change, ~50% des Speedups)
- Umstellen der cc-Register-Methoden auf 1-2 Zeiler (kein API-Change, ~20% des Speedups)
- Umstellen aller lesenden Registerzugriffe von `.get()` auf `.value` in der CPU-Klasse (~20% des Speedups)
- Umstellen des Speichers von Bytearray auf eine Liste (~10% des Speedups)
Ich vermute, dass Du durch Entfernen der vielen lokalen Zwischenvariablen in den Instruktionen-Methoden noch etwas einsparen könntest. Mehr als 1.500.000 cycles/s sind aber wahrscheinlich nicht zu schaffen ohne größeren Umbau an den Registern (ist immer noch die "Hauptlast").
Edit:
Und `pypy -m MC6809.cli benchmark` läuft mit 12 Mio. cycles/s.
- jens
- Python-Forum Veteran
- Beiträge: 8502
- Registriert: Dienstag 10. August 2004, 09:40
- Wohnort: duisburg
- Kontaktdaten:
Die ganzen .get() / .set() methoden, wollte ich eh weg machen... Während der Entwicklungsphase waren sie allerdings hilfreich. Allerdings weiß ich auch nicht mehr warum
Kannst du einen Pull-Request machen?!?
Laufen die Unittests noch durch?
btw. die API ist jetzt nicht in Stein gemeißelt. Ich hab eh Änderungen mit den Mixin-Klassenaufteilung, siehe WIP-branch: https://github.com/6809/MC6809/compare/split_cpu
Kannst du einen Pull-Request machen?!?
Laufen die Unittests noch durch?
btw. die API ist jetzt nicht in Stein gemeißelt. Ich hab eh Änderungen mit den Mixin-Klassenaufteilung, siehe WIP-branch: https://github.com/6809/MC6809/compare/split_cpu
@jens:
Die Tests laufen noch durch, musste nur fürs Entfernen von `.get` die Tests anpassen. Natürlich ist die coverage gesunken, da mein hinzugefügter Kram nicht abgedeckt ist. Achso - irgendwo hatte ich einen Bug gefunden, ich glaube es war in EXG (habs leider nicht protokolliert). Fehlt da der Test zu?
Die Tests laufen noch durch, musste nur fürs Entfernen von `.get` die Tests anpassen. Natürlich ist die coverage gesunken, da mein hinzugefügter Kram nicht abgedeckt ist. Achso - irgendwo hatte ich einen Bug gefunden, ich glaube es war in EXG (habs leider nicht protokolliert). Fehlt da der Test zu?
- jens
- Python-Forum Veteran
- Beiträge: 8502
- Registriert: Dienstag 10. August 2004, 09:40
- Wohnort: duisburg
- Kontaktdaten:
Ich hab es nun auch so eingerichtet, das die DragonPy tests, ebenfalls mit laufen. Doch ich hatte nicht damit gerechnet, das die Test-Abdeckung damit nicht besser wird. Naja, heißt ja nur, das alleine die Tests in MC6809 schon gut sind
EXG bei dein pull request (nur MC6809 tests):
https://coveralls.io/builds/3429967/sou ... 9.py#L1367
EXG mit den DragonPy tests zusammen:
https://coveralls.io/builds/3442782/sou ... 9.py#L1466
EXG ist abgedeckt.jerch hat geschrieben:irgendwo hatte ich einen Bug gefunden, ich glaube es war in EXG (habs leider nicht protokolliert). Fehlt da der Test zu?
EXG bei dein pull request (nur MC6809 tests):
https://coveralls.io/builds/3429967/sou ... 9.py#L1367
EXG mit den DragonPy tests zusammen:
https://coveralls.io/builds/3442782/sou ... 9.py#L1466
Ja sorry es war auch nicht EXG sondern Deine Helfermethode `_convert_differend_width` dazu. Da stimmten Deine Docstring-Beschreibung nicht mit dem Verhalten überein. Für die Konvertierung der Registerinhalte von 16 auf 8 Bit war Deine Korrektur ein `src_value = src_value | 0xff00`. Das macht aber nicht, was der Docstring beschreibt. Es führte zu keinem Fehler in den Tests, da die Register das beim Speichern in der `.set`-Methode auf 8 Bit korrigiert haben.
- jens
- Python-Forum Veteran
- Beiträge: 8502
- Registriert: Dienstag 10. August 2004, 09:40
- Wohnort: duisburg
- Kontaktdaten:
Ah! Interessante Information...jerch hat geschrieben:Ja sorry es war auch nicht EXG sondern Deine Helfermethode `_convert_differend_width` dazu. Da stimmten Deine Docstring-Beschreibung nicht mit dem Verhalten überein. Für die Konvertierung der Registerinhalte von 16 auf 8 Bit war Deine Korrektur ein `src_value = src_value | 0xff00`. Das macht aber nicht, was der Docstring beschreibt. Es führte zu keinem Fehler in den Tests, da die Register das beim Speichern in der `.set`-Methode auf 8 Bit korrigiert haben.
Die DocStrings kommen ursprünglich aus den Dokumentationen. siehe: https://github.com/6809/MC6809/blob/mas ... op_docs.py
Es ist nicht auszuschließen, das die Dokumentation falsch ist. Hatte auch schon früher ein paar kleine Fehler gefunden...
Zu EXG hatte ich auch einen extra Thread, hier: http://archive.worldofdragon.org/phpBB3 ... &hilit=EXG
Genau mit der Frage, was passiert, wenn 16 und 8 Bit hin und her Transferiert wird...
Wenn ich den Dump richtig interpretiere, ist das hohe Byte bei 8 -> 16 Bit immer 0xff, und 16 -> 8 lädt das untere Byte. Heisst die Register werden vorher "geeinst" und der Wert bitaddiert. Gibts eigentlich einen speziellen Grund, warum die Registerbits vorher auf eins gesetzt werden? Hätte ja erwartet, dass die genullt werden.
- jens
- Python-Forum Veteran
- Beiträge: 8502
- Registriert: Dienstag 10. August 2004, 09:40
- Wohnort: duisburg
- Kontaktdaten:
Keine Ahnung. Ich hab es auch immer noch nicht auf dem echten Computer nach geprüft...jerch hat geschrieben:Gibts eigentlich einen speziellen Grund, warum die Registerbits vorher auf eins gesetzt werden? Hätte ja erwartet, dass die genullt werden.
Allerdings ist es so, das beim "nullen" die unittests nicht durchlaufen. z.B. der mit der CRC32 Berechnung.
Von daher gehe ich davon aus, das es so richtig ist.
Allerdings ist mit dennoch ein Fehler aufgefallen! Das Konvertieren von 16Bit zu einem 8Bit, führt zu einem falschen Ergebnis!
Zumindest intern in der Methode. Hinterher ist es IMHO egal, weil ein 8Bit Register beim setzten, eh den Wert abschneidet.
Dazu kommt noch, das der DocString falsch war...
Siehe: https://github.com/6809/MC6809/commit/5 ... a052ec73e9
EDIT: Mir ist noch aufgefallen, das der aktuelle code ein wenig umständlich ist. Deswegen: https://github.com/6809/MC6809/commit/2 ... 0dfcf40c10
Kannst du deinen Pull aktualisieren?
- jens
- Python-Forum Veteran
- Beiträge: 8502
- Registriert: Dienstag 10. August 2004, 09:40
- Wohnort: duisburg
- Kontaktdaten:
@jerch: ich hab mir jetzt dein https://github.com/6809/MC6809/pull/1/files näher angesehen...
Was mir nicht gefällt sind die ganzen & register.BASE
Dann hab ich mich gefragt, was ist eigentlich schneller:
oder:
Hab timeit angeworfen:
Also, wenn ein Überlauf nicht so häufig vorkommt, dann ist die if-Variante schneller.
Ich gehe einfach mal davon aus, das es in der Praxis nicht so oft vor kommt.
Deswegen hab ich mal einen Testlauf mit dem Benchmark gemacht.
Dazu hab ich den 'master' branch genommen und https://github.com/6809/MC6809/blob/5da ... py#L63-L91 noch abgeändert.
Also diese beiden Varianten gegeneinander Verglichen:
Leider schwanken die Benchmark Werte so stark, das man keine genaue Aussage treffen kann
Was mir nicht gefällt sind die ganzen & register.BASE
Dann hab ich mich gefragt, was ist eigentlich schneller:
Code: Alles auswählen
if n>0xff:
x = n & 0xff
else:
x = n
Code: Alles auswählen
x = n & 0xff
Code: Alles auswählen
from timeit import Timer
import sys
# TEST_DATA = [0xff] * 10000
# TEST_DATA += [0x100] * 10000
# test1: 1.441sec
# test2: 1.434sec
TEST_DATA = [0xff] * 20000
TEST_DATA += [0x100] * 2000
# test1: 1.139sec
# test2: 1.593sec
def test1():
for n in TEST_DATA:
if n>0xff:
x = n & 0xff
else:
x = n
def test2():
for n in TEST_DATA:
x = n & 0xff
if __name__ == "__main__":
def timeit(func, number):
name = func.__name__
sys.stdout.write("%20s: " % name)
sys.stdout.flush()
t = Timer("%s()" % name, setup="from __main__ import %s" % name)
print("%.3fsec" % t.timeit(number))
number = 1000
timeit(test1, number)
timeit(test2, number)
Ich gehe einfach mal davon aus, das es in der Praxis nicht so oft vor kommt.
Deswegen hab ich mal einen Testlauf mit dem Benchmark gemacht.
Dazu hab ich den 'master' branch genommen und https://github.com/6809/MC6809/blob/5da ... py#L63-L91 noch abgeändert.
Also diese beiden Varianten gegeneinander Verglichen:
Code: Alles auswählen
class ValueStorage8Bit(ValueStorage):
def set(self, v):
if v > 0xff:
v = v & 0xff
self.value = v
return v # e.g.: r = operand.set(a + 1)
class ValueStorage16Bit(ValueStorage):
def set(self, v):
if v > 0xffff:
v = v & 0xffff
self.value = v
return v # e.g.: r = operand.set(a + 1)
Code: Alles auswählen
class ValueStorage8Bit(ValueStorage):
def set(self, v):
v = v & 0xff
self.value = v
return v # e.g.: r = operand.set(a + 1)
class ValueStorage16Bit(ValueStorage):
def set(self, v):
v = v & 0xffff
self.value = v
return v # e.g.: r = operand.set(a + 1)
Leider schwanken die Benchmark Werte so stark, das man keine genaue Aussage treffen kann
Ja das ist nicht hübsch und auch der Grund, warum ich mit ctypes Typen rumprobiert hatte.
Bitte nimm die Änderungen nicht zu ernst, das sind größtenteils quick&dirty Ersetzungen, um die Flaschenhälse im profiling zu bessern. In einem zweiten Ansatz habe ich auch die generierten Instruktionen durch eine einfachere Abstraktion ersetzt, was aber nicht mehr viel bringt. Ein Ansatz mit Megaloop bringt auch nichts, dafür fehlt Python ein switch-statement in O(1). Das Funktionsmapping ist da schon das beste und auch viel lesbarer. Wenn ich dazu komm, räum ich die Änderungen nochmal auf und leg es ins Repo. Dann kannst Du schauen, ob Du was davon übernehmen willst.
Bitte nimm die Änderungen nicht zu ernst, das sind größtenteils quick&dirty Ersetzungen, um die Flaschenhälse im profiling zu bessern. In einem zweiten Ansatz habe ich auch die generierten Instruktionen durch eine einfachere Abstraktion ersetzt, was aber nicht mehr viel bringt. Ein Ansatz mit Megaloop bringt auch nichts, dafür fehlt Python ein switch-statement in O(1). Das Funktionsmapping ist da schon das beste und auch viel lesbarer. Wenn ich dazu komm, räum ich die Änderungen nochmal auf und leg es ins Repo. Dann kannst Du schauen, ob Du was davon übernehmen willst.
- jens
- Python-Forum Veteran
- Beiträge: 8502
- Registriert: Dienstag 10. August 2004, 09:40
- Wohnort: duisburg
- Kontaktdaten:
Ich hab nun den "mixin" CPU branch in "master" gemerged.
https://github.com/6809/MC6809/commit/3 ... d742516562
Außerdem hab ich ein paar deiner Vorschläge aufgenommen. z.B. ein Teil der CC Register Klasse und den Verzicht auf .get():jerch hat geschrieben:Bitte nimm die Änderungen nicht zu ernst, das sind größtenteils quick&dirty Ersetzungen, um die Flaschenhälse im profiling zu bessern.
https://github.com/6809/MC6809/commit/3 ... d742516562
- jens
- Python-Forum Veteran
- Beiträge: 8502
- Registriert: Dienstag 10. August 2004, 09:40
- Wohnort: duisburg
- Kontaktdaten:
So und die CC Register direkt in die CPU einpflanzen per mixin hab ich nun mit https://github.com/6809/MC6809/commit/b ... 719df9cbd7 angegangen...
Jetzt muß ich allerdings DragonPy anpassen...
Jetzt muß ich allerdings DragonPy anpassen...