bits in bytes und umgekehrt...

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

@jens:
Ich denke auch, dass Du gerade die low level Sachen wie Registerabstraktion mit Flaghandling und die Adressierungsmodi über den ganzen möglichen Wertebereich testen solltest. Wenn Du mit intensiven Tests erst auf op-Codeebene einsteigst, könnte ein kleiner Fehler im low level-Bereich unerkannt bleiben bzw. nur noch schwer zurückverfolgbar sein. Wenn dieser Unterbau stimmt, sind die op-Codes mit Tests reine Fleissarbeit.

Ist der Chip eigentlich fehlerfrei gewesen? Evtl. funktioniert Dein Emulator am Ende besser als das Original und muss entsprechend "kaputt gepatcht" werden, damit Originalsoftware so wie damals läuft. ;)
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Mir ist kein Bug bekannt. Beim Ursprünglichen ApplyPy Projekt war es allerdings wirklich so z.B.:
https://github.com/jtauber/applepy/blob ... py#L80-L84

Ein Test mit SUBA ist auch fertig und gleich einen Fehler im OP-Code behoben: https://github.com/jedie/DragonPy/commi ... b85763fb12

Unittests mache ich eigentlich gern nicht ganz Low-Level, obwohl es ja "unit" heißt. Auf der einen Seite schließt man mit einen Test der höher ansetzt mehr Code mit ein. Also man testet mehr. Auf der anderen Seite ist es schwieriger den eigentlichen Bug zu lokalisieren...
Aber ich teste lieber mehr auf einmal, als viele Code-Teile überhaupt nicht zu testen.

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Hab nochmal zwei Fragen zum konvertieren von C nach Python.

Einmal für SEX:

Code: Alles auswählen

WREG_A = (RREG_B & 0x80) ? 0xff : 0;
das hab ich daraus gemacht:

Code: Alles auswählen

        if b & 0x80 == 0:
            self.accu_a.set(0x00)

Und das andere ist für DAA und komplexer:

Code: Alles auswählen

				unsigned tmp = 0;
				if ((RREG_A&0x0f) >= 0x0a || REG_CC & CC_H) tmp |= 0x06;
				if (RREG_A >= 0x90 && (RREG_A&0x0f) >= 0x0a) tmp |= 0x60;
				if (RREG_A >= 0xa0 || REG_CC & CC_C) tmp |= 0x60;
				tmp += RREG_A;
				WREG_A = tmp;
				// CC.C NOT cleared, only set if appropriate
				CLR_NZV;
				SET_NZC8(tmp);
und das hab ich daraus gemacht:

Code: Alles auswählen

        tmp = 0
        a = self.accu_a.get()
        cc = self.cc.get()

        if (a & 0x0f) >= 0x0a or cc & self.cc.H:
            tmp |= 0x06

        if a >= 0x90 and (a & 0x0f) >= 0x0a:
            tmp |= 0x60

        if a >= 0xa0 or cc & self.cc.C:
            tmp |= 0x60

        new_value = tmp + a
        self.accu_a.set(new_value)
Als erstes ist mir erstmal wichtig das das selbe herraus kommt. Dann, wie man es einfacher in Python umsetzten kann.
Kann da jemand helfen?

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Sirius3
User
Beiträge: 18253
Registriert: Sonntag 21. Oktober 2012, 17:20

@jens: das erste sieht für mich aus wie

Code: Alles auswählen

self.accu_a.set(b & 0x80 and 0xff)
Das zweite sieht richtig aus, würde ich aber so schreiben:

Code: Alles auswählen

a = self.accu_a.get()
cc = self.cc.get()

tmp = (cc & self.cc.H and 0x06) | (cc & self.cc.C and 0x60)
if a & 0x0f >= 0x0a:
    tmp |= 0x06 if a<0x90 else 0x66
elif a >= 0xa0:
    tmp |= 0x60
self.accu_a.set(a + tmp)
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Hab nochmal eine Ähnliche Frage:

Der Code aus XRoar (siehe: https://github.com/jedie/XRoar/blob/mas ... mon.c#L295 ) brauche ich in Python:

Code: Alles auswählen

#define N_EOR_V ((REG_CC & CC_N)^((REG_CC & CC_V)<<2))
case 0xe: cond = !(N_EOR_V || REG_CC & CC_Z); break; // BGT, LBGT
Zusammengefasst ist es doch:

Code: Alles auswählen

!(((REG_CC & CC_N)^((REG_CC & CC_V)<<2)) || REG_CC & CC_Z)
Vereinfacht also:

Code: Alles auswählen

!((N^V)<<2) || Z)
oder?

Code der eigentlich das selbe machen soll, aus 6809.js (siehe: https://github.com/maly/6809js/blob/master/6809.js#L781 ):

Code: Alles auswählen

(!((CC&F_NEGATIVE) ^ ((CC&F_OVERFLOW)<<2) || (CC&F_ZERO)))
ist vereinfacht das:

Code: Alles auswählen

!(N ^ (V<<2) || Z)
oder?
Ist da die Klammern falsch gesetzt?



In Python habe ich aktuell das:

Code: Alles auswählen

if not ((self.cc.N ^ self.cc.V) == 1 or self.cc.Z == 1):
    self.program_counter = ea

Der Text zu BGT lautet allerdings:
Causes a branch if the N (negative) bit and V (overflow) bit are either both set or both clear and the Z (zero) bit is clear.
Das heißt doch aber einfach nur das:

Code: Alles auswählen

if self.cc.N == self.cc.V and self.cc.Z == 0:
    self.program_counter = ea
Entspricht das dem C Code von XRoar?

EDIT: Merke gerade not ((self.cc.N ^ self.cc.V) == 1 or self.cc.Z == 1) ist das selbe wie self.cc.N == self.cc.V and self.cc.Z == 0 nur viel komplizierter ausgedrückt ;)

EDIT2: Und not ((self.cc.N ^ self.cc.V) | self.cc.Z) führt ebenfalls zum selben Ergebnis.

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
MagBen
User
Beiträge: 799
Registriert: Freitag 6. Juni 2014, 05:56
Wohnort: Bremen
Kontaktdaten:

Mit Numpy:

Code: Alles auswählen

import numpy as N

bits = 2**N.arange(7,-1,-1)

class Foo(object):
    def status_from_byte(self, status):
        self.flag_E, \
        self.flag_F, \
        self.flag_H, \
        self.flag_I, \
        self.flag_N, \
        self.flag_Z, \
        self.flag_V, \
        self.flag_C = N.bitwise_and(status, bits)!=0
        
    def status_as_byte(self):
        return self.flag_C | \
            self.flag_V << 1 | \
            self.flag_Z << 2 | \
            self.flag_N << 3 | \
            self.flag_I << 4 | \
            self.flag_H << 5 | \
            self.flag_F << 6 | \
            self.flag_E << 7
        
f = Foo()
 
for i in xrange(255):
    f.status_from_byte(i)
    i2 = f.status_as_byte()
    print i, i2
    assert i == i2
a fool with a tool is still a fool, www.magben.de, YouTube
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

jens hat geschrieben:Das heißt doch aber einfach nur das:

Code: Alles auswählen

if self.cc.N == self.cc.V and self.cc.Z == 0:
    self.program_counter = ea
Das hast du doch selber hergeleitet. Ausgehend von deinem ersten Stück Python-Code:

Code: Alles auswählen

not ((self.cc.N ^ self.cc.V) == 1 or self.cc.Z == 1
Da ``== 1`` in deime Fall ``== True`` entspricht:

Code: Alles auswählen

not ((self.cc.N ^ self.cc.V) or self.cc.Z
Da ein xor von zwei Bits nichts anderes ist als Ungleich:

Code: Alles auswählen

not ((self.cc.N != self.cc.V) or self.cc.Z
Und dann kannst du noch das not reinziehen:

Code: Alles auswählen

self.cc.N == self.cc.V and not self.cc.Z
Und schon hast du deinen Ausdurck.
Das Leben ist wie ein Tennisball.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Danke euch. Numpy werde ich z.Z. aber nicht nutzten. Optimierungen kommen, wenn es denn mal einwandfrei laufen würde ;)
EyDu hat geschrieben:Und dann kannst du noch das not reinziehen:

Code: Alles auswählen

self.cc.N == self.cc.V and not self.cc.Z
Stimmt, aber IMHO ist if self.cc.N == self.cc.V and self.cc.Z == 0: direkter zu verstehen, oder nicht?

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Finde ich nicht. Ein == 0 würde ich bei Bool'schen Ausdrücken so nie verwenden und ist ist mir in der Form auch noch niemals begegnet.
Das Leben ist wie ein Tennisball.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

In meinem Falle sind es allerdings wirklich 1 und 0 und nicht True / False ;)

Vielleicht ändere ich das irgendwann mal oder nicht, mal sehen...

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

@jens:
Die zusätzliche == 0|1 ist für die Register unsinnig, da Du ja hoffentlich mit den Registern nur boolsche Operationen machst. Dann ist doch egal, was konkret in der Variable drinsteckt, solange das wahr/falsch korrekt abgebildet wird. (Ich hätt da wahrscheinlich von Anfang an mit True/False gearbeitet.)
Bei dem nach `and` umgestellten Ausdruck würde ich die Z-Prüfung noch nach links nehmen. Die Testung auf 0 ist idR schneller, kA ob das bei Python auch eine Rolle spielt, trotzdem dürfte die Prüfung schneller sein als das (N==V) wegen 1 vs. 2 Variablenlookups.
Antworten