EEC V file conversion
-
- Posts: 235
- Joined: 2023 Sep 06, 13:11
- Location: Charlotte NC , USA
- Vehicle Information: 1999 Ford Ranger with 2000 Explorer v8 swap, FLN0
2003 Ford F150 Harley Davidson, Built 5.4L SOHC with 3.4L Whipple and Built 4R100
Re: EEC V file conversion
Just when I thought I was starting to wrap my head around it. Lol. Ford!! I am a Ford tech at a dealer so I do know the complexity they put into everything. And the info that they withhold even from dealer level techs. I had no idea about the !INV! Thing. I haven’t seen that yet while walking through the code. It starts to get a little confusing for me after a while trying to keep track of where to go next and where I came from and if I should go back or forward while following the code. I am even having issues following along in the strategy docs at times but I’m guessing that’s because they aren’t the docs for the strategy I’m actuallly working with? At least I hope. lol. I’ll wrap my head around your comments and see if I can finally get it. What I am getting is that 9a4 is not an actual address, it’s a pointer in the preceding subroutine, is that correct?
-
- Posts: 320
- Joined: 2021 Feb 16, 15:53
- Location: Victoria, BC, Canada
- Vehicle Information: 1994 Flarside, XLT, 351w E4OD
SD48b, Quarter Horse, Burn2
Re: EEC V file conversion
In the msg file will show errors and invalid information.
Using the EQE3 bin, I get
I put the following in my dir:
And get the correct output in the lst.
What is interesting, is the msg file shows this:
And I get this in the lst, which is correct?:
Using the EQE3 bin, I get
Code: Select all
Invalid opcode at 1e8f6 [5]
Code: Select all
sym 22 "StackPtr2" # auto
SYM 09A4 "P0400STATE" #UY
sym 02060 "I0_HSO_0" # auto
What is interesting, is the msg file shows this:
Code: Select all
sym 0fd44 "Sub_0fd44"
sym 109a4 "P0400STATE"
sym 1206a "Func_1206a"
Code: Select all
83111: 10,00 rombk 0
83113: ef,cb,b4 call 0e5e1 Sub_0e5e1 (
83116: a4,09 #arg 1 P0400STATE,
83118: 05 #arg 2 5 );
83119: 91,40,89 orb R89,40 B6_R89 = 1;
-
- Posts: 88
- Joined: 2023 Oct 22, 22:13
- Location: New Zealand
- Vehicle Information: Several Kit cars, Ford (Europe), EEC-IV, TVR Vixen, Tasmin (a.k.a Wedge),
Engine - Cologne 2.8 V6 (Europe) catch code 'AA'.
EEC_Disassembler https://github.com/tvrfan/EEC-IV-disassembler
Re: EEC V file conversion
To all -
!!INV!! is a SAD backstop when it thinks it has encountered an illegal opcode. I'll say this up front - it should never happen if bin is disassembled correctly. But there are still bugs/holes in SAD. Mostly the !INV! occurs when subroutine arguments are calculated incorrectly. But there are a few other situations where it can happen also.
In several places SAD uses a BEST GUESS, and it ain't always right. It still misses some code here and there, and I know that data can be missed entirely in some cases. This is why I have all those user commands, so that you can override, and hopefully fix the problem.
Ford software engineers did some clever stuff which works well and speeds things up. (I say this as an IT designer) They also came up with designs which allow them to change calibrations for testing, allows for 'limp home' modes, 'learning' and 'autocorrect' for sensor fails. That's bloody good, frankly. But for disassembling the code, these tricks can be a real PITA to try to pick apart and interpret correctly with another program.
A few examples -
encoded addresses - Ford use 4 types (so far) of encoded address, where they squeeze a [base+index] into one word. SAD handles these correctly from V4. (This trick uses the RBASE registers).
Subroutine Arguments - SAD has to actually emulate/run the code for these, as the tricks don't work in a 'static' scan (= going through the code like a plain list) in CARD for example there is a truly HORRIBLE piece of code in an args extract (in the decode sense, I mean). I'm still not certain the emulate works correctly for every bin.
Vector Lists (background task list, test list, etc). This is a list of subroutine addresses, which are 'called' in sequence. It's not always obvious where the list ends, which means SAD can pick up a faulty address. I know this happens in a couple of bins. A9L actually has some DATA in the middle of its pointer list which doesn't help either.
'lookup' lists. (A list of pointers) In some bins it appears that some tables and functions are referenced by a list of pointers. They use an index (base address + index) instead of a plain address. As SAD scans the code in a 'static' way it will only get one of the list items. I haven't got a neat way to handle this one yet.
Functions and tables and some other code tricks - I have the concept of a 'fingerprint match' in SAD, which identifies blocks of code which do a particular job, like say the function lookup routines. These do work, and can handle small variations in the code, but now and then I see another variation which does NOT work, so I must add a new fingerprint.
Tables - sometimes SAD gets the sizes wrong - I'm still trying to come up with a method to try to sort out what the table looks like (i.e. rows and columns).
And there's more..... that gives you an idea of where SAD is at...and why it's still ongoing.
So please don't assume everything it prints is always 100% right ....maybe 90% ??.
After an !INV! SAD will stop that block, as a safety thing, but next code block (i.e. jumped to or called) will be right again.
!!INV!! is a SAD backstop when it thinks it has encountered an illegal opcode. I'll say this up front - it should never happen if bin is disassembled correctly. But there are still bugs/holes in SAD. Mostly the !INV! occurs when subroutine arguments are calculated incorrectly. But there are a few other situations where it can happen also.
In several places SAD uses a BEST GUESS, and it ain't always right. It still misses some code here and there, and I know that data can be missed entirely in some cases. This is why I have all those user commands, so that you can override, and hopefully fix the problem.
Ford software engineers did some clever stuff which works well and speeds things up. (I say this as an IT designer) They also came up with designs which allow them to change calibrations for testing, allows for 'limp home' modes, 'learning' and 'autocorrect' for sensor fails. That's bloody good, frankly. But for disassembling the code, these tricks can be a real PITA to try to pick apart and interpret correctly with another program.
A few examples -
encoded addresses - Ford use 4 types (so far) of encoded address, where they squeeze a [base+index] into one word. SAD handles these correctly from V4. (This trick uses the RBASE registers).
Subroutine Arguments - SAD has to actually emulate/run the code for these, as the tricks don't work in a 'static' scan (= going through the code like a plain list) in CARD for example there is a truly HORRIBLE piece of code in an args extract (in the decode sense, I mean). I'm still not certain the emulate works correctly for every bin.
Vector Lists (background task list, test list, etc). This is a list of subroutine addresses, which are 'called' in sequence. It's not always obvious where the list ends, which means SAD can pick up a faulty address. I know this happens in a couple of bins. A9L actually has some DATA in the middle of its pointer list which doesn't help either.
'lookup' lists. (A list of pointers) In some bins it appears that some tables and functions are referenced by a list of pointers. They use an index (base address + index) instead of a plain address. As SAD scans the code in a 'static' way it will only get one of the list items. I haven't got a neat way to handle this one yet.
Functions and tables and some other code tricks - I have the concept of a 'fingerprint match' in SAD, which identifies blocks of code which do a particular job, like say the function lookup routines. These do work, and can handle small variations in the code, but now and then I see another variation which does NOT work, so I must add a new fingerprint.
Tables - sometimes SAD gets the sizes wrong - I'm still trying to come up with a method to try to sort out what the table looks like (i.e. rows and columns).
And there's more..... that gives you an idea of where SAD is at...and why it's still ongoing.
So please don't assume everything it prints is always 100% right ....maybe 90% ??.
After an !INV! SAD will stop that block, as a safety thing, but next code block (i.e. jumped to or called) will be right again.
-
- Posts: 88
- Joined: 2023 Oct 22, 22:13
- Location: New Zealand
- Vehicle Information: Several Kit cars, Ford (Europe), EEC-IV, TVR Vixen, Tasmin (a.k.a Wedge),
Engine - Cologne 2.8 V6 (Europe) catch code 'AA'.
EEC_Disassembler https://github.com/tvrfan/EEC-IV-disassembler
Re: EEC V file conversion
CARD.......an explanation of how the best designs/plans get wrecked....
this is an example of a HORRIBLE code trick from a disassembly point of view. And maybe a primer on how arguments are extracted.
See if you can work out how these actually do their job...
Up until jsa sent me the CARD bin, I had a 'static' (fingerprint') matcher for args.
After all, most bins use variations of the same code to get arguments. e.g. A9L
this worked well, and this code appears often across bins.
Fixed type A9L - get 2 bytes from caller subroutine ...
Variable args A9L - get specified number of args from caller subroutine.........
And then their multibank equivalents - (xdt2 bin)
NB. this looks a lot more complicated but it's mostly for fiddling with banks.
This gets 4 bytes from caller subroutine.
and its xdt2 variable equivalent -
NB. again a lot of fiddling to get the bank(s) right, but it does same job as 77be above
and then jsa sent me THIS - and the air went blue (Do you say this in USA, or
is it more like "swears like a trooper?")
446a - - - - WHAT THE F**K is THAT ??!!!! AAARRGGGHHHH !!!!!!
And I knew then I had to throw away all my work on the fingerprint type arg getters.
real shame as they had worked just fine up to now... I had to 'emulate' the code.
Emulate is to set up enough conditions to actually run the code as if it is for real,
but you can 'fake' it quite a lot. But I needed to have a 'fake stack' and have it
built correctly for each 'call' of subroutine, (and some more as it turned out)
Later I also found a bin (which I can't find right now, but it's saved somewhere) which
gets 2 extra bytes if top bit of first argument byte is set...)
So I had to rework a whole bunch of SAD code to do this.
(true answer is 4456 gets 4 args, 4459 gets 6 args)
this is an example of a HORRIBLE code trick from a disassembly point of view. And maybe a primer on how arguments are extracted.
See if you can work out how these actually do their job...
Up until jsa sent me the CARD bin, I had a 'static' (fingerprint') matcher for args.
After all, most bins use variations of the same code to get arguments. e.g. A9L
this worked well, and this code appears often across bins.
Fixed type A9L - get 2 bytes from caller subroutine ...
Code: Select all
Get_par:
3695: cc,38 pop R38 R38 = pop(); # This subroutine's return addr
3697: cc,3a pop R3a R3a = pop(); # Caller subroutine's return addr
3699: b2,3b,3c ldb R3c,[R3a++] R3c = [R3a++];
369c: b2,3b,3d ldb R3d,[R3a++] R3d = [R3a++]; # 3c, 3d from caller
369f: c8,3a push R3a push(R3a); # restore caller address (+2)
36a1: c8,38 push R38 push(R38); # restore this return address
Code: Select all
77c2: cc,3c pop R3c R3c = pop(); # this subroutines return address
77c4: b2,3d,3a ldb R3a,[R3c++] R3a = [R3c++]; # Get count of bytes required
77c7: cc,42 pop R42 R42 = pop(); # Get Caller's return address
77c9: b2,43,3b ldb R3b,[R42++] R3b = [R42++];
77cc: c6,17,3b stb R3b,[R16++] [R16++] = R3b; # get byte from caller
77cf: e0,3a,f7 djnz R3a,77c9 R3a--;
if (R3a != 0) goto 77c9; # Get no of bytes into dest. addr
77d2: c8,42 push R42 push(R42);
77d4: c8,3c push R3c push(R3c); # and push modded returns back.
NB. this looks a lot more complicated but it's mostly for fiddling with banks.
This gets 4 bytes from caller subroutine.
Code: Select all
82f93: a3,20,02,36 ldw R36,[R20+2] R36 = [StackPtr+2];
82f97: a3,20,04,3a ldw R3a,[R20+4] R3a = [StackPtr+4];
82f9b: f2 pushp push(PSW);
82f9c: fa di interrupts OFF;
82f9d: 18,02,37 shrb R37,2 R37 >>= 2;
82fa0: b0,37,11 ldb R11,R37 BANK_Select = R37;
82fa3: b2,3b,36 ldb R36,[R3a++] R36 = [R3a++];
82fa6: b2,3b,37 ldb R37,[R3a++] R37 = [R3a++];
82fa9: b2,3b,38 ldb R38,[R3a++] R38 = [R3a++];
82fac: b2,3b,39 ldb R39,[R3a++] R39 = [R3a++];
82faf: b1,11,11 ldb R11,11 Data_Bank = 1;
Stack_Bank = 1;
82fb2: f3 popp PSW = pop();
82fb3: c3,20,04,3a stw R3a,[R20+4] [StackPtr+4] = R3a;
NB. again a lot of fiddling to get the bank(s) right, but it does same job as 77be above
Code: Select all
8a526: a2,20,40 ldw R40,[R20] R40 = [StackPtr];
8a529: 18,02,41 shrb R41,2 R41 >>= 2;
8a52c: c4,11,41 stb R41,R11 BANK_Select = R41;
8a52f: a3,20,02,40 ldw R40,[R20+2] R40 = [StackPtr+2];
8a533: b2,41,3e ldb R3e,[R40++] R3e = [R40++];
8a536: c3,20,02,40 stw R40,[R20+2] [StackPtr+2] = R40;
8a53a: a3,20,04,40 ldw R40,[R20+4] R40 = [StackPtr+4];
8a53e: 18,02,41 shrb R41,2 R41 >>= 2;
8a541: b0,41,11 ldb R11,R41 BANK_Select = R41;
8a544: a3,20,06,46 ldw R46,[R20+6] R46 = [StackPtr+6];
8a548: b2,47,3f ldb R3f,[R46++] R3f = [R46++];
8a54b: c6,27,3f stb R3f,[R26++] [R26++] = R3f;
8a54e: e0,3e,f7 djnz R3e,8a548 R3e--;
if (R3e != 0) goto 8a548;
8a551: b1,11,11 ldb R11,11 Data_Bank = 1;
Stack_Bank = 1;
8a554: c3,20,06,46 stw R46,[R20+6] [StackPtr+6] = R46;
is it more like "swears like a trooper?")
446a - - - - WHAT THE F**K is THAT ??!!!! AAARRGGGHHHH !!!!!!
Code: Select all
Sub_4456:
4456: f8 clc CY = 0;
4457: 20,01 sjmp 445a goto 445a;
Sub_4459:
4459: f9 stc CY = 1;
445a: cc,18 pop R18 R18 = pop();
445c: b2,19,1a ldb R1a,[R18++] R1a = [R18++];
445f: b2,19,1b ldb R1b,[R18++] R1b = [R18++];
4462: b2,19,1c ldb R1c,[R18++] R1c = [R18++];
4465: b2,19,1d ldb R1d,[R18++] R1d = [R18++];
4468: d3,05 jnc 446f if (CY = 1) {
446a: c9,fa,40 push 40fa push(Sub_40fa);
446d: 20,02 sjmp 4471 goto 4471; }
446f: c8,18 push R18 push(R18);
4471: 91,02,2c orb R2c,2 R2c |= 2;
Sub_40f8:
40f8: cc,18 pop R18 R18 = pop();
Sub_40fa:
40fa: ae,19,14 ldzbw R14,[R18++] wR14 = y[R18++];
40fd: b2,19,17 ldb R17,[R18++] R17 = [R18++];
4100: c8,18 push R18 push(R18);
real shame as they had worked just fine up to now... I had to 'emulate' the code.
Emulate is to set up enough conditions to actually run the code as if it is for real,
but you can 'fake' it quite a lot. But I needed to have a 'fake stack' and have it
built correctly for each 'call' of subroutine, (and some more as it turned out)
Later I also found a bin (which I can't find right now, but it's saved somewhere) which
gets 2 extra bytes if top bit of first argument byte is set...)
So I had to rework a whole bunch of SAD code to do this.
(true answer is 4456 gets 4 args, 4459 gets 6 args)
-
- Posts: 5051
- Joined: 2021 Feb 15, 12:23
- Location: Metairie, LA
- Vehicle Information: Work Truck
'19 F-150 3.3L
Re: EEC V file conversion
no need to throw it away just have it as an option to not label args at the top of the directive
/done
/done
-
- Posts: 88
- Joined: 2023 Oct 22, 22:13
- Location: New Zealand
- Vehicle Information: Several Kit cars, Ford (Europe), EEC-IV, TVR Vixen, Tasmin (a.k.a Wedge),
Engine - Cologne 2.8 V6 (Europe) catch code 'AA'.
EEC_Disassembler https://github.com/tvrfan/EEC-IV-disassembler
Re: EEC V file conversion
Nice idea, but SAD has to work out how many arg bytes there are, to avoid !INV and/or it going off into fantasy land, as args are often valid opcode numbers (but trash...). I did wonder if it was possible somehow to guess how many arg bytes...but can't think of any way that works.
An issue with v4 , trying to sort this out..........
An issue with v4 , trying to sort this out..........
Code: Select all
0e8dc: ef,6a,08 call 0f149 Sub_0f149 (); # this should have 9 following bytes ......
0e8df: c8,09 push R108 push(R108);
0e8e1: dc,09 jvt 0e8ec if (OVT = 1) {
0e8e3: 90,0a,5b orb R5b,Ra R5b |= IO_Status;
0e8e6: 08,80,ef shrw R1ee,R80 R1ee >>= R80; # should be opcode ef ...call <something>
0e8e9: 66,06,ef ad2w R1ee,[R6] R1ee += [IO_Timer]; }
0e8ec: 93,09,f3,f0,a3 orb Ra3,[R8+f0f3] Ra3 |= [INT_Mask+1f0f3];
0e8f1: 20,02 sjmp 0e8f5 goto 0e8f5;
0e8f3: 3e,a3,20 jb B6,Ra3,0e916 if (B6_Ra3 = 1)
0e8f6: 04 !INV!
0e8f7: 26,f2 sjmp 0e7eb
-
- Posts: 274
- Joined: 2021 Feb 16, 15:46
- Location: Australia
- Vehicle Information: 95 Escort RS Cosworth
2.0 YBP
CARD / QUIK / COSY / ANTI
GHAJ0
SMD-190 / SMD-490 EEC-IV
Binary Editor
ForDiag
Re: EEC V file conversion
This spreadsheet lays out the code from L83108 linearly to keep track of the Stack, SFR11 and relevant registers.BOOSTEDEVERYTHING wrote: ↑2023 Nov 15, 16:29 Please help me understand the arg code a little better?
Code: Select all
83113: ef,cb,b4 call 0e5e1 Sub_0e5e1 ( 83116: a4,09 #arg 1 9a4, 83118: 05 #arg 2 5 ); 83119: 91,40,89 orb R89,40 EGR_MON = 1;
I've gone as far as confirming the arg quantities and sizes, further work is required to understand the sub totally.
I will say that it looks like fault code handling code, as others have said. The spreadsheet is 'emulating' the code, one might say, as SAD needs to do to successfully handle args.
BIN's typically contain a list of strategy supported fault codes. These can be used as a means of confirming assumptions about parts of the disassembly. If you find fault handling code comparing values for fault code 112, you know it is Air Charge Temp or Intake Air Temp.
Fault code 112 & 113 are typically supported in strategies, so one can search LST for 12,01 and 13,01 to quickly track down that list. Once the list address is know, 16be6 for EQE3, then LST can be searched for 6BE6. Subs using 6BE6 can be worked through to find payloads and scalars. This approach requires solid understanding of the 8061/5 workings, so a bit heavy for someone getting started. One gets used to rereading the manuals to confirm details.
These are links to posts elsewhere that have other spreadsheets working through different arg methods. It'd be worth reviewing to enhance your understanding.
http://eectuning.org/forums/viewtopic.p ... 60#p136055
http://eectuning.org/forums/viewtopic.p ... 20#p136291
These two entries can be added to your DIR in appropriate places.
Code: Select all
SYM 16BE6 "FAULT_CODE_LIST" # Address to list of strategy supported fault codes
WOR 16BE6 16D5D
-
- Posts: 274
- Joined: 2021 Feb 16, 15:46
- Location: Australia
- Vehicle Information: 95 Escort RS Cosworth
2.0 YBP
CARD / QUIK / COSY / ANTI
GHAJ0
SMD-190 / SMD-490 EEC-IV
Binary Editor
ForDiag
Re: EEC V file conversion
BOOSTEDEVERYTHING wrote: ↑2023 Nov 15, 16:29 I first tried it at address 9a4, but obviously it is not correct because it does not define it in the lst file when i put that in the dir file.
These go in DIR as a starting point.BOOSTEDEVERYTHING wrote: ↑2023 Nov 30, 08:18
For this one I was just trying to name the 9a4 address as p0400state. so I put this in my dir file.
But it doesn't seem to want to name that 9a4 address in the argument. I does appear elsewhere in the lst file, not as an arg, and names it as p0400state. Not sure what I am doing wrong. Is there something I am missing?Code: Select all
SYM 09A4 "P0400STATE" #UY
Code: Select all
SYM 9A4 "FM_9A4" # W # Failure management
SUB 0E5E1 "Sub0E5E1_FM" :WN :Y
That would look like
DIR
Code: Select all
SYM 9A4 "FM_9A4" # W # Failure management
arg 83116 83117 :WN
arg 83118 83118 :Y
SUB 0E5E1 "Sub0E5E1_FM"
If Sub_Oe5E1 is called and the loop counter arg is a value other than 3, we will need to use the arg command instead of adding options to the sub command. I've also searched LST for INV to make sure my sub command with options does not stuff the disassembly.
I've decided to name the word arg but not the byte arg. The byte arg goes on to be compared to values such as 8 and 9, so it is likely some sort of event count. That count could be an inline scalar which will have a name.
CATCH 22, 5 conflicts with the name for Special Function Register 5.
This has been an ongoing discussion with TVRfan for ever.
Multipliers, dividers, fault code numbers, in line parameters, addresses, etc, all conflict because the hex values match for symbol names.
The latest proposal for SAD V5 is to retain SYmbol Multiple as it is now, but add SYmbol siNgle to name 5 for address 83118.
Something like;
Code: Select all
SYN 5 83118 "thingo_count"
LST 4.07.16B
Code: Select all
83113: ef,cb,b4 call 0e5e1 Sub0E5E1_FM (
83116: a4,09 #arg 1 FM_9A4,
83118: 05 #arg 2 5 );
-
- Posts: 274
- Joined: 2021 Feb 16, 15:46
- Location: Australia
- Vehicle Information: 95 Escort RS Cosworth
2.0 YBP
CARD / QUIK / COSY / ANTI
GHAJ0
SMD-190 / SMD-490 EEC-IV
Binary Editor
ForDiag
Re: EEC V file conversion
That is SAD indicating that the disassembly is going wrong.
Hopefully the DIR I posted earlier has eliminated any that might occur.
Put something like this in DIR and see if it generates !Inv!
Not tried it but you can mess around with it.
Code: Select all
SUB 0E5E1 "Sub0E5E1_Stuffed" :WN :WN :WN
I am even having issues following along in the strategy docs at times but I’m guessing that’s because they aren’t the docs for the strategy I’m actuallly working with?
Yes that can be the case.
-
- Posts: 274
- Joined: 2021 Feb 16, 15:46
- Location: Australia
- Vehicle Information: 95 Escort RS Cosworth
2.0 YBP
CARD / QUIK / COSY / ANTI
GHAJ0
SMD-190 / SMD-490 EEC-IV
Binary Editor
ForDiag
Re: EEC V file conversion
I get fill for that address.wwhite wrote: ↑2023 Dec 01, 11:49 In the msg file will show errors and invalid information.
Using the EQE3 bin, I getCode: Select all
Invalid opcode at 1e8f6 [5]
Code: Select all
179e6 -> 1ffff = 0xff ## fill ##
Edit: SAD bug, see post earlier in the thread.