Notices
ECU Flash

[Dev/Disassembly] The beginners' guide to Evo ECU table lookups

Thread Tools
 
Search this Thread
 
Old Sep 23, 2009, 03:03 PM
  #1  
Evolved Member
Thread Starter
iTrader: (2)
 
logic's Avatar
 
Join Date: Apr 2003
Location: Berkeley, CA
Posts: 1,022
Likes: 0
Received 5 Likes on 4 Posts
[Dev/Disassembly] The beginners' guide to Evo ECU table lookups

I've seen a bit of confusion lately regarding how table data is looked up in the Evo ECU (some of it from me ), so I decided to spend a bit of time actually reading through the table and axis lookup routines to see if I can formalize both the format of the tables and their headers for documentation purposes, and get a better idea of what was going on with a couple of wacky things in 96940011. (I'm still not entirely sure I understand what's going on there, but hey, at least this might be somewhat useful for others.)

This is purely targeted at new developers (non-developers won't know what the heck I'm talking about, and older developers will already know this). If you really care about this stuff, required reading is the SuperH software manual (PDF link); you might not be able to grok all of it at once, but you should definitely understand what registers are, how memory is accessed, and have a basic understanding of the SH2 assembly language. The disassembler of choice for those of us working on the Evo ECU is IDA Pro; you'll definitely need something like that if you want to make any sense of this.

So, here we go:

The beginners' guide to Evo ECU table lookups

EcuFlash provides an XML file for each ROM, which defines a bunch of tables (1D, 2D, and 3D) that can be edited by the user. Every 2D or 3D table is indexed by one or two "axis" values; it's how you look up values in the table. By way of example, the High Octane Fuel Map has both RPM and Load axes; to look up a value in the table, you first look up the current engine speed (RPM) and calculated load, and the AFR target value you're looking for is where the two intersect on the table. (2D works the same way, but there's only one dimension to worry about.)

The XML tells you where in the ROM the table and axis table data is located. Back to our example, the High Octane Fuel Map table in 96530006 is listed as being at address "33bd", with the "Engine Load" axis as being at address "68b0" and the RPM axis at address "6888". If you pull those up in IDA Pro, you'll see the data listed there, just as EcuFlash promised, but that's not the whole story; if you've ever done this, you'll notice that IDA doesn't have any code or data references listed for those ROM addresses. Every table, and every "axis table", has a header attached to it, just before the data an end-user of EcuFlash normally edits. That header data is used by a set of standard routines that every Evo ROM provides to assist in performing lookups, and the address of that header is what IDA ends up generating code and data references to.

By understanding how the ECU performs lookups in tables, it can help you to both understand when you're looking at code that performs table lookups (thus helping you locate new tables), and help you understand why you get back the values you do when the ECU performs a table lookup.

To get to the value in a table, you have to first look up the axis positions. The axis table header, just prior to the data itself, defines an address to store lookup results in, followed by the address of "current value" of that axis. For example, if the table axis is "RPM", second address is where the current vehicle RPM is stored in memory. The next word defines the number of elements in the axis, and then the axis data follows.

So, axis tables look like this:
  • A long word for the result address.
  • A long word for the value to look up.
  • A word for the length of the axis.
  • A series of words, as long as the length, containing the axis data.
Axis lookup is done by calling the routine at sub_CC6. You tell sub_CC6 where the axis header is by assigning its address to r4.

For 2D tables, you perform one axis lookup; for 3D tables, you perform two. The result of each call to sub_CC6 is a value stored in that axis' "result address"; it's the position in the axis that most closely (rounding down) matches the current value of the axis (ie. the position on an RPM axis that most closely matches the current engine speed).

Once you have the axis positions back from sub_CC6, you need to look up the actual table value. For byte-width tables, you call sub_C28; for word-width tables, sub_E02.

The table header has some similarities to the axis header. The first byte (or word, for sub_E02) determines whether the table has two dimensions (0x2) or three (0x3). The second byte (or word) is a global "adder" that is added to any value returned from the table. Next, a long word describes where the position on the X-axis is stored in memory (returned from sub_CC6); in a 3D table, an additional long word is included, as well as a one-byte value denoting the length of a row. After that, the table data follows, either in word (for sub_E02) or byte (sub_C28) form.

So, tables look like this:
  • A byte (or word, for word-sized tables) for the number of dimensions: 2 = 2D, 3 = 3D.
  • A byte (or word, for word-sized tables) for a value "added" to all values returned from the table.
  • A long word for the position on the X-axis.
  • Optionally, a long word for the position on the Y-axis in a 3D table.
  • Optionally, a byte (or word, for word-sized tables) for the length of each row in a 3D table.
  • A series of words or bytes containing the table data.
Note that the X and Y position addresses must either match the result addresses from the axis tables, or match a pair of addresses that you have manually copied the axis lookup results into.

Just like with axis lookups, you set r4 to the address of the table you want to perform the look-up in. When control is returned, r0 contains an interpolated value based on how "close" the axis values were to a labelled position on the axis.

So, if you see calls to sub_CC6 when reading through your disassembly of a ROM, it's an indication that an axis lookup is being performed, and if you see calls to sub_C28 or sub_E02, there's a table lookup happening. Looking at the lines of code leading up to that for any assignments to register r4 will tell you where the axis or table headers are located. Normally, the code right after a call to sub_C28 or sub_E02 will assign r0 to some memory address (or eventually get there, by bouncing it around from register to register), which you can log via the MUT table if you want to keep an eye on the value, and can give you an idea of what other code that uses that value is doing (for example, code that deals with the result from a High Octane Fuel Map lookup is probably involved in fueling).

Hopefully, this can help some newer folks get started with understanding one of the most common activities ECU code participates in.

Last edited by logic; Sep 24, 2009 at 08:45 AM. Reason: Added table spec notes for word-width tables.
Old Sep 23, 2009, 03:03 PM
  #2  
Evolved Member
Thread Starter
iTrader: (2)
 
logic's Avatar
 
Join Date: Apr 2003
Location: Berkeley, CA
Posts: 1,022
Likes: 0
Received 5 Likes on 4 Posts
Reserved for future use. Like, say, if mrfred or tephra wants to explain how the head-exploding interpolating div1/rotcl action in sub_6A2 and friends works.

Last edited by logic; Sep 23, 2009 at 03:06 PM.
Old Sep 23, 2009, 04:02 PM
  #3  
Evolved Member
iTrader: (17)
 
Jack_of_Trades's Avatar
 
Join Date: Jun 2007
Location: Opelika,AL
Posts: 3,523
Likes: 0
Received 2 Likes on 1 Post
Its awesome you're doing this, though I highly suggest screenshots with labeling to become immensely easier for users to 'paint the picture' in their heads as they read. Two thumbs up though. I haven't tried disassembling in over a year but I'd love there to be a tutorial so I can get further with it.
Old Sep 23, 2009, 09:47 PM
  #4  
Evolved Member
iTrader: (4)
 
Raceghost's Avatar
 
Join Date: Dec 2001
Location: Out West
Posts: 1,034
Received 21 Likes on 21 Posts
Can I ask what language the ROM is written in. I did take some Language Engineering classes for C++, Visual Basic, Java, Cobol just to name a few, and I havent quite figured it out yet. No pro by any meens, just curious so I can dive in a little.

EDIT: It almost seems as the though the stock ECU is an ARRAY, or a cube. Several little storage addresses. I see there are reference pointers to locations in addresses, that will hold data, and then ECU Flash edits that or calculates utilizing that, etc.

So is it more database and Query when you dissasemble? SQL and databases were not my strong point when it came to these pointers, reference pointers, arrays, etc.

Thanks again.

Last edited by Raceghost; Sep 23, 2009 at 09:52 PM.
Old Sep 23, 2009, 10:30 PM
  #5  
EvoM Guru
iTrader: (6)
 
tephra's Avatar
 
Join Date: Feb 2007
Location: Melbourne, Australia
Posts: 9,486
Received 66 Likes on 42 Posts
Logic - there are byte AND word tables:

byte tables have byte sized header fields and data, word tables have word sized header field and data.

also after the 2 or 3 header field for a 2d or 3d table there is a additive value, this is used for the timing tables - ie 0x14 = +20 onto whatever data is looked up.
Old Sep 23, 2009, 11:25 PM
  #6  
Evolved Member
iTrader: (22)
 
codgi's Avatar
 
Join Date: Aug 2004
Location: Seattle, WA
Posts: 2,491
Received 41 Likes on 37 Posts
Originally Posted by Raceghost
Can I ask what language the ROM is written in. I did take some Language Engineering classes for C++, Visual Basic, Java, Cobol just to name a few, and I havent quite figured it out yet. No pro by any meens, just curious so I can dive in a little.
Its SH2 assembly that its written in. It wouldn't really matter though, since at the end of the day for any programming language which compiles its output eventually into machine language (see not Java/C#) you could always reverse engineer it back to assembly of some sort. Whether that assembly is exactly the same as what the language actually produced initially isn't too relevant really.

EDIT: It almost seems as the though the stock ECU is an ARRAY, or a cube. Several little storage addresses. I see there are reference pointers to locations in addresses, that will hold data, and then ECU Flash edits that or calculates utilizing that, etc.

So is it more database and Query when you dissasemble? SQL and databases were not my strong point when it came to these pointers, reference pointers, arrays, etc.

Thanks again.
Not quite. If you take a look at the tuning software for aftermarket ECUs they often represent the data in a table format. The stock ECU is no different, but the tables are only one part of it. Its how the routines use those tables and other variables that tends to lead to the bigger discoveries on this forum.

The real thing you need here is time and patience and you will be able to contribute as well. I only have the time when I am on vacation and then I don't have the patience .

Last edited by codgi; Sep 23, 2009 at 11:28 PM.
Old Sep 23, 2009, 11:27 PM
  #7  
Evolved Member
iTrader: (22)
 
codgi's Avatar
 
Join Date: Aug 2004
Location: Seattle, WA
Posts: 2,491
Received 41 Likes on 37 Posts
Originally Posted by tephra
Logic - there are byte AND word tables:

byte tables have byte sized header fields and data, word tables have word sized header field and data.

also after the 2 or 3 header field for a 2d or 3d table there is a additive value, this is used for the timing tables - ie 0x14 = +20 onto whatever data is looked up.
Is this just basically an offset?
Old Sep 24, 2009, 06:04 AM
  #8  
Evolved Member
Thread Starter
iTrader: (2)
 
logic's Avatar
 
Join Date: Apr 2003
Location: Berkeley, CA
Posts: 1,022
Likes: 0
Received 5 Likes on 4 Posts
Originally Posted by tephra
byte tables have byte sized header fields and data, word tables have word sized header field and data.
You know, I mentioned that (both word- and byte-length data sections, depending on whether you call sub_CC6 or sub_E02), then didn't bother reading too closely through sub_E02 to see if the headers were organized any differently, as they didn't seem to be at first glance. I'll get that updated when I get to work.

I spent quite a bit of time searching, and didn't see any axis tables that weren't word-length, and didn't notice any byte-sized code for reading them; as far as you know, are there any non-word-width axis tables? I just assumed they would have added a routine for that to go along with the ones for parsing the main tables, but I couldn't find it.

Originally Posted by tephra
also after the 2 or 3 header field for a 2d or 3d table there is a additive value, this is used for the timing tables - ie 0x14 = +20 onto whatever data is looked up.
Argh, that was in my notes, and got missed in my cut-and-paste to this post. Again, I'll get that updated in about a couple of hours.

Originally Posted by codgi
Is this just basically an offset?
Kind of. It's basically just a number that's added to any value looked up in the table prior to return. (Hmm, I need to check the assembly again to see if that's a signed value or not; if it is, it would mean you could subtract as well.)
Old Sep 24, 2009, 06:08 AM
  #9  
EvoM Guru
iTrader: (6)
 
tephra's Avatar
 
Join Date: Feb 2007
Location: Melbourne, Australia
Posts: 9,486
Received 66 Likes on 42 Posts
Old Sep 24, 2009, 07:31 AM
  #10  
Evolved Member
Thread Starter
iTrader: (2)
 
logic's Avatar
 
Join Date: Apr 2003
Location: Berkeley, CA
Posts: 1,022
Likes: 0
Received 5 Likes on 4 Posts
Originally Posted by Jack_of_Trades
I highly suggest screenshots with labeling to become immensely easier for users to 'paint the picture' in their heads as they read.
Agreed, although I don't have a windows version of IDA handy, and I suspect screenshots from the linux console version won't be very useful to most folks here.

Honestly, this has me thinking that we really need an "intro to disassembly" topic, or series of topcs. Something that incorporates what acamus' onload.idc script does automatically for you (generating disassembled code from the interrupt vector table and from various jump tables in Mitsu's code; labeling registers, the MUT table, and other well-known chunks of code and memory; creating RAM/ROM/register segments; etc) along with some basics on SH assembly (stuff that's different from what people might have traditionally run into, like how delayed branching affects instruction execution order) and maybe some discussions of the hardware (how Mitsu uses the SCI interface, etc).

Teaching assembly language is a little out-of-scope, but even if you've worked in a version of assembly before, you might not have worked with an embedded system like this, which makes it a little like learning a new language. (That was my problem originally; I'd done plenty of 6502/65C02 assembly as a child, and a bit of x86 assembly here and there, but never on a small platform like this where the hardware is exposed as directly as it is; there was always an OS for me to interact with instead.)

My main interest here is in helping more people get involved in this stuff in a substantial way. When someone like jcsbanks gets tired of his Evo and moves on to a more interesting project, we end up with a large knowledge gap that others have to step in and fill, and there's not a lot of "others" right now (imagine if tephra had decided to get a nice reliable econocar after his IX accident, rather than getting an X). Without new people getting interested in how the ECU works, new development is eventually going to slow down or stop as the "early adopters" move on to other projects.

(RomRaider/Enginuity is a great example of that problem, you just don't see a lot of new development happening anymore; at least, not in public, and certainly not a lot of ECU-side code development. Mind you, they run a higher risk of bricking their ECUs if something isn't quite right, which raises the bar for people who want to get involved; we're pretty lucky in that respect, it's tough to render our ECUs unbootable. )
Old Sep 24, 2009, 08:00 AM
  #11  
Evolved Member
iTrader: (1)
 
ziad's Avatar
 
Join Date: Apr 2007
Location: Melbourne
Posts: 529
Likes: 0
Received 1 Like on 1 Post
hmm i will most definately look at this thread tomorrow (currently brain is sleepy) and only earlier this week i was talking to Tephra about its done
Old Sep 24, 2009, 09:08 AM
  #12  
Evolved Member
Thread Starter
iTrader: (2)
 
logic's Avatar
 
Join Date: Apr 2003
Location: Berkeley, CA
Posts: 1,022
Likes: 0
Received 5 Likes on 4 Posts
Originally Posted by tephra
byte tables have byte sized header fields and data, word tables have word sized header field and data.
Yep, you're right, my eyes were glossing over the fact that word-sized table definition locations were being treated as long words. It doesn't help that there aren't a lot of examples of word-sized tables in 96530006 (and no 3D examples that I can find). I've fixed the text to match reality, thanks for catching that!

Do you know if there's a byte-sized version of the axis table lookup routine?

Originally Posted by tephra
also after the 2 or 3 header field for a 2d or 3d table there is a additive value, this is used for the timing tables - ie 0x14 = +20 onto whatever data is looked up.
Fixed. I'd actually mentioned it in the text, but not the spec'd list. Bah.

I'd really like to see all the common routines and data up to 0x1500 documented better; since they're exactly the same across all VII through IX roms, it'd be a big leg up for someone new getting up to speed.
Old Sep 24, 2009, 01:27 PM
  #13  
Evolved Member
iTrader: (32)
 
R/TErnie's Avatar
 
Join Date: Aug 2003
Location: WAR EAGLE!
Posts: 5,380
Likes: 0
Received 6 Likes on 6 Posts
You've got me hooked. Thank you for your efforts in explaining this.
Old Sep 24, 2009, 11:51 PM
  #14  
Evolved Member
iTrader: (22)
 
codgi's Avatar
 
Join Date: Aug 2004
Location: Seattle, WA
Posts: 2,491
Received 41 Likes on 37 Posts
Originally Posted by logic
Kind of. It's basically just a number that's added to any value looked up in the table prior to return. (Hmm, I need to check the assembly again to see if that's a signed value or not; if it is, it would mean you could subtract as well.)
Fair enough .
Old Sep 29, 2009, 09:22 PM
  #15  
Evolved Member
iTrader: (1)
 
ziad's Avatar
 
Join Date: Apr 2007
Location: Melbourne
Posts: 529
Likes: 0
Received 1 Like on 1 Post
umm is there a way to get a dissassembly of say 88590015 so i can get an idea and start on 96260009 umm email is ziad at mztec dot org...or if someone already has partial/full one for 96260009... tephra is apparently a little busy


Quick Reply: [Dev/Disassembly] The beginners' guide to Evo ECU table lookups



All times are GMT -7. The time now is 08:13 PM.