Hallo,
ich versuche mich gerade am Reverse-Engineering von HCS12 Assembler und
würde mich sehr freuen ein wenig Starthilfe zu bekommen :-)
Zunächst scheint die CPU mit ihren fünf 16-Bit Registern und dem CCR
sehr übersichtlich zu sein, im Vergleich zu einer ARM-Basierenden, es
gibt aber dennoch einen großen Befehlssatz. Ich habe in meiner Jugend
(schwelm) mal Assembler auf einer Z80 CPU programmiert, das war
vergleichbar, ist aber schon so lange her das ich fast alles vergessen
habe.
Zum üben habe ich mir eine ISR aus dem Dump eines Fahrzeugmoduls auf dem
ein MC9S12DG werkelt ausgesucht um herauszufinden was die letztendlich
macht und wie. Die ISR wird nach dem Empfang einer CAN-Botschaft
ausgelöst. Eine ISR hat ja keine Parameter, d.H. sie muss alles was sie
benötigt aus der Umgebung (RAM, ROM) ziehen. Auch sollte eine ISR ja
möglichst kurz sein, was mich zur Annahme verleitet das hier die
empfangene Nachricht nur woanders abgelegt wird und über eine Semaphore
das Signal gesetzt wird das damit etwas geschehen soll.
Ich habe mir erstmal angeschaut worauf der Code alles zugreift. Das sind
neben den Registern des Chips natürlich Speicherstellen im RAM. Im (mir
nicht verfügbaren) Quellcode sind diese sehr wahrscheinlich als
"volatile" deklariert. Der Rest ist Zeiger- und Register-Arrithmetik.
Die Kommentare im folgenden Listing stammen größtenteils von mir, sind
also potentiell falsch ;-)
1
ROM_HI:C34D _CAN0_receive: ; DATA XREF: USER_VEC:FFB2↓o
2
ROM_HI:C34D leas -3,sp ; Load effective address into SP
3
ROM_HI:C34F brset byte_FSR_3161,#0x10,loc_ROM_HI_C386 ; Ignore remote frames (RTR Bit set)
4
ROM_HI:C354 ldab CAN0IDAC ; load "MSCAN Identifier Acceptance Control Register" into B
5
ROM_HI:C357 andb #7 ; mask out by bits found at 0x0007
Ja, du bist auf dem Holzweg.
LEAS -3SP bait ein Stackframe für 3 byte fur funktionslokale Variablen
auf, so wie in
1
interruptfunction()
2
{
3
wordidac;
4
charcnt;
5
6
idac=*(word*)CAN0IDAC;
7
cnt=3;
Es wird bei STAB nicht gepusht, sondern ein word dort hin gespeichert.
Und eine 3 in die char Variable davor.
PUSH heisst, dass der SP dabei verändert wird. Wird er bei STAB nicht.
"leas -3,sp"
Das ist doch eine Stackpointer-Manipulation, oder? Dabei wird dann im
Enteffekt die aktuelle im Stackpointer hinterlegte Adresse um 3
verringert, also wie "SP = SP - 3". Also wenn "SP = 0x1FF8" wäre, dann
wäre er nach "leas -3,sp" "SP = 0x1FF5".
Also anstelle einer push Operation mit Dummywerten wird dort einfach für
3 Byte "Platz" vom Stack gesichert, welcher sich ja auch im RAM
befindet.
"brset byte_FSR_3161,#0x10,loc_ROM_HI_C386"
müsste dann soviel bedeuten wie:
if( *(byte_FSR_3161) & 0x10 != 0) {
// handle non remote CAN frames (RTR not set)
}
:loc_ROM_HI_C386
Das hier ist doch ganz klar eine loop:
1
ldd #3 ; D = 3
2
std 0,sp ; *(SP) = D
3
4
loc_ROM_HI_C360:
5
ldd 0,sp ; D = *(SP)
6
lsld ; D = D * 2 // vermutlich ein offset in einem word-array
7
tfr d,y ; Y = D
8
ldd CAN0RXFG ; D = *(CAN0RXFG) // CAN-ID
9
andb #0xF8 ; D = D & 0b00000000 11111000
10
cpd -0x3B7,y ; // vergleiche die CAN-ID mit der in dem Array
11
beq loc_ROM_HI_C377 ; BREAK // bei Übereinstimmung verlasse die loop
12
ldy 0,sp ; Y = *(SP)
13
dey ; Y = Y -1
14
sty 0,sp ; *(SP) = Y
15
bge loc_ROM_HI_C360 ; while *(SP) >= 0
16
17
loc_ROM_HI_C377:
18
...
Sieht für mich so aus als wäre die Zählervariable (nennen wir sie mal
"i") hier auf SP[0] also am Fuß des Stacks.
Olli Z. schrieb:> Reverse-Engineering von HCS12 Assembler
Das macht keinen Spaß.
Es sind unheimliche viele teils merkwürdige Addressierungsarten möglich.
Z.B. indirekt indiziert, wahrscheinlich auch mit 8 oder 16 Bit Offset.
Was ich noch erinnere: Akkus A, B können multipliziert werden nach D.
Aber so eine Addition (oder gar Subtraktion) gibt es nicht.
Gruss