Intel Disassembly

by Michael Decipha Ponthieux
Posted: 2015-03-08
Last Updated: 2021-04-06
If you are considering performing disassembly I highly recommend to check out the Hardware Support List first to make sure that you are not disassembling a strategy that may not be needed.

Binary Files

In most cases, the only method of retrieving a clean unmodified bin is to extract the bin from the ecu. See the Getting Started write up for specifics. Tomas Tomin also offers hardware for reading ECU's, more info can be had on his FORDIAG.CZ forum.
Direct link to downloading ForDiag Software HERE

Padding (filler) and Bank Order

Before we can even begin to discuss the disassembly process we must first have a valid bin we can disassemble. This in itself can be extremely difficult before even beginning disassembly due to the fact that some software uses a full size bin of 64k per bank where the first 8192 bytes (0x2000 hex) of each bank is padded with null filler, whilst most software uses a non-padded bin of 56k per bank (224k 4 bank file). To fuel the fire, some software will swap banks 8 and 9 while saving the bin. This can make getting a true unaltered bin for disassembly very difficult. For reference a binary size chart is below.

Binary File Sizes
10x 8 00032 768 32 k
10x E 00057 34456 k
10x10 00065 536 64 k
20x16 00090 112 88 k
20x1C 000114 688112 k
20x20 000131 072128 k
20x36 000221 184216 k
40x38 000229 376224 k
40x40 000262 144256 k

Identify Bank Order

Bank order can easily be identified by the beginning bytes of each bank. It is often easy to search for the ascii string to quickly find it.
Bankhex codeascii
0FF,FA,27,FE,...,60,20,63` c
9FF,FA,27,FE,...60,20,65,...` e

Flat Memory Addressing

For reference, I have attached a quick reference table or a "cheat sheet" if you will, that will break down the memory differences between various size bin files and how to get to the actual flat addressing the binary is referencing. This table can be used to cross calculate memory addressing between the more common iterations of bank layouts and file sizing.

Note: 4 Bank EEC-V 256k binaries include the RAM (usually all filler =0xFF) 4 bank bin files are truly 216k with the end of bank 1 being used for RAM.
Quick Reference Conversion Chart from 256k [0-1-8-9] Addressing to many common formats.
256k [0-1-8-9]
224k [0-1-9-8]
216k [0-1-9-8]224k [1-8-0-9]
112k [1-8]
0 2 xxx0 xxx0 xxx1C xxx-
0 4 xxx2 xxx2 xxx1E xxx-
0 A xxx8 xxx8 xxx24 xxx-
0 C xxxA xxxA xxx26 xxx-
0 D xxxB xxxB xxx27 xxx-
0 E xxxC xxxC xxx28 xxx-
0 F xxxD xxxD xxx29 xxx-
1 2 xxxE xxxE xxx0 xxx0 xxx
1 3 xxxF xxxF xxx1 xxx1 xxx
1 4 xxx10 xxx10 xxx2 xxx2 xxx
1 5 xxx11 xxx11 xxx3 xxx3 xxx
1 7 xxx13 xxx13 xxx5 xxx5 xxx
1 8 xxx14 xxx14 xxx6 xxx6 xxx
1 B xxx17 xxx17 xxx9 xxx9 xxx
1 D xxx19 xxx19 xxxB xxxB xxx
1 E xxx1A xxx- C xxxC xxx
1 F xxx1B xxx- D xxxD xxx
2 2 xxx2A xxx28 xxxE xxxE xxx
2 5 xxx2D xxx2B xxx11 xxx11 xxx
2 7 xxx2F xxx2D xxx13 xxx13 xxx
2 F xxx37 xxx35 xxx1B xxx1B xxx
3 2 xxx1C xxx1A xxx2A xxx-
3 3 xxx1D xxx1B xxx2B xxx-
3 5 xxx1F xxx1D xxx2D xxx-
3 7 xxx21 xxx1F xxx2F xxx-
3 9 xxx23 xxx21 xxx31 xxx-
3 C xxx26 xxx24 xxx34 xxx-
3 F xxx29 xxx27 xxx37 xxx-

<<<----- How to Swap Bank Order ------>>>

Most hex editing software like HHD's Hex Editor will not let you cut and insert paste instead paste overwrites so you have to do this as detailed.
PCMflash / Kess 224k [1-8-0-9] Files
to 256k [0-1-8-9] QHfrom 256k [0-1-8-9] QHto 216k [0-1-9-8]to 224k [0-1-9-8]
  • add null filler infront each bank 0x8192 bytes at
    0, 10000, 20000, 30000
  • add 65,536 at 0x000000
  • cut 0x30000 to 3ffff
  • paste at 0x0
  • banks are now ordered 0-1-8-9
  • clear all null filler by setting it to 0xff
  • to move 0 in front 9 do the following:
  • goto 30000 insert 65536
  • goto 0
  • cut 0 to ffff
  • goto 20000
  • paste at 20000
  • remove filler 30000 - 31fff; 20000-21fff; 10000 - 11fff; 0 - 1fff
  • del c000 to dfff
  • move 8 to end;
  • cut c000 to 19fff
  • add 57344 bytes at end
  • paste at 28000
  • move 0 to front;
  • fix c000 == ff
  • cut c000 to 19fff
  • add 57344 bytes at front
  • paste at 0
  • do all listed for
    216k file
    add 8192 bytes at 1a000
    then fill 1a000 to 1bfff
    216k [0-1-9-8] Files
    to 256k [0-1-8-9] QHfrom 256k [0-1-8-9] QHto PCMflash/Kess 224k [1-8-0-9]
    byte 0 should be 0xff, if not set it
  • insert 8192 at 0
  • fill 0-1fff
  • insert 8192 at 10000
  • fill 10000-11fff
  • insert 16384 at 1e000
  • ---> fill 1e000 to 21fff
  • insert 8192 at 30000
  • fill 30000 to 31fff
  • ---> [0198]; cut 20000 to 2ffff
  • insert 65536 at end
  • paste at end (30,000)
  • del fillers
  • swap 8 and 9 by doing:
  • insert 57344 at 1c000
  • cut 38000 to end
  • paste at 1c000
  • del 1a000 to 1bfff
  • add 8192 at 1a000 and fill 1a000 to 1bfff
  • --- 0198 needs to be 1809
  • move 8 to front;
  • insert 57344 bytes at 0
  • cut 38000 to end
  • paste at 0
  • move 1 to front;
  • insert 57344 bytes at 0
  • cut 2a000 to 37fff
  • paste at 0
  • Misc [8-1-0-9] Files
    to 256k [0-1-8-9] QHfrom 256k [0-1-8-9] QHto PCMflash/Kess 224k [1-8-0-9]
    Values below are not where they belong, need to fin.

    256k [0,1,8,9] (TunerPro Read) ---> 224k [0,1,9,8] (typical)

    You need to do 2 steps, 1st- remove filler, then swap banks 8 and 9.
    REMEMBER to always delete filler starting at the highest address and work down.
    fill 00030000 - 00031fff
    fill 00020000 - 00021fff
    fill 00010000 - 00011fff
    fill 0 - 1fff
    Now that you have a 224k bin you can simply swap banks 9 and 8 same as outlined above in the 224k details.
    • insert 57,344 bytes (0xE000) at 0x1C000
    • Cut 0x38000 [FF FA 27] to the end 0x46000
    • Then paste bank 9 there at 0x1C000, If done correctly, 0x1C000 will now have FF FA 27
    • Lastly, verify your bin stops at 0x37FFF for a max file size of 38,000 / 224 kb.

    256k Bin [0,1,9,8] (typ. but w/ flr added) ---> [0,1,8,9] (needed for QH)

    • For a 256k bin add 65,536 bytes at 0x20,000 then
    • cut 0x40000 to the end of the ROM
    • paste it at 0x20000, which will now have FF FA 27

      256k Bin [8,1,0,9] ---> [0,1,8,9] (needed for QH)

      If banks 0 and 8 are swapped:
    • insert 131072 bytes at 0,
    • cut 40000 - 4ffff
    • paste at 0, then
    • cut 30000 - 3ffff
    • paste at 10000

      Be sure to always set the null filler to 0xFF to clear it
      fill 0 - 1fff
      fill 00010000 - 00011fff
      fill 00020000 - 00021fff
      fill 00030000 - 00031fff

    224k Bin [0,1,9,8] (typical)---> [0,1,8,9]

    If you have a 224k bin file with banks ordered 0,1,9,8 as is most common, to swap banks 9 and 8 simply:
    • CUT address 0x2A000 (which will start with FF FA E7) all the way to the end of the rom 0x37FFF and paste it at 0x1C000
      If your hex editor will not let you cut and paste,
    • insert 57,344 bytes (0xE000) at 0x1C000
    • Cut 0x38000 [FF FA 27] to the end 0x46000
    • Then paste bank 9 there at 0x1C000, If done correctly, 0x1C000 will now have FF FA 27
    • Lastly, verify your bin stops at 0x37FFF for a max file size of 38,000 / 224 kb.

    224k [8-1-0-9] (database read) ---> 256k [0-1-8-9] (QH / TunerPro)

    • add null filler infront each bank 0x8192 bytes at (2a000, 1c000, e000, 0)
    • add 65,536 at 0x000000
    • cut 0x30000 to 3ffff, paste at 0x0, banks now ordered 0-8-1-9
    • add 65,536 at 0x10,000
    • cut 0x30000 to 0x3ffff, paste at 0x10000, banks are now ordered 0-1-8-9
    • lastly, go FF out the null filler

    224k [1-8-0-9] (PCMflash / KESS) ---> 224k [0-1-9-8] (224k typical)

    • cut 0x0 to 0x1bfff
    • insert 114,688 at 0xE000
    • paste at 0xE000
    • cut 0x1c000 to 29fff
    • goto end of rom
    • add 57,344
    • paste
    • banks are now ordered 0-1-9-8

    224k [8-1-0-9] ---> 224k [0-1-9-8] (224k typical)

    • add 57,344 bytes at 0
    • cut 0x2a000 to 0x37fff and paste at 0
    • banks now ordered 0-8-1-9
    • add 57,344 bytes at the end of the binary 0x38000
    • cut 0xe000 to 0x1bfff and paste it at 0x2a000
    • banks now ordered 0-1-9-8

    256k >> 112k (readout of 2 bank conversion)

    • delete 0x00000 to 0x11FFF
    • delete 0xe000 to 0xffff
    • delete 0x1c000 to 0x2bfff (end of rom)

    112k >> 128k

    • add 8192 bytes of filler at 0000e000, fill 0000e000 to 0000FFFF with 0xff =
    • add 8192 bytes of filler at 00000000, fill 00000000 to 00001FFF with 0xff =

    112k >> 256k (needed for QH)

    • add 73,728 bytes of filler at 0, fill 0 to 00011FFF with 0xff =
    • add 8192 bytes of filler at 20,000 fill 20,000 to 21,FFF with 0xff =
    • save file and close, then re-open file
    • add 65,536 bytes of filler at end of ROM 30,000
    • fill 30,000 to 3F,FFF with 0xff =

    SAD - Semi-Automatic Disassembler

    Now that we have a valid bin its time to run it through the disassembler. For this example I will be using FBFG2 (2004 Mustang GT) and AJAQ3 (95 Ford Ranger) There's a few disassemblers out there for the Intel 8061/8065 processors but the two most used are the Bill Lawrence Disassembler that has been around since the late 90s and the much much more recent SAD - Semi Automatic Disassembler by Andy "TVRFAN". The Bill Lawrence disassembler has been updated over the years and works flawlessly. The newer SAD Disassembler does a lot of the work for you and is much easier for the beginner to use. Not only that, its updated by the author so we can simply tell him any problem we have and he's pretty good about fixing it. A+++ in my book, the less work we have to do the better!!! So to begin, create a new folder named "disassembly" just to keep everything organized. Toss your extracted stock tune in there and name your binary file stock.bin, be sure to also toss in there a shortcut to the SAD executable.

    Run the Disassembler
    Now is the time to run your binary through the disassembler. Simply drag and drop the bin file over the SAD executable and it will begin.

    SAD - _msg.txt - Messages

    First things first, open up the message file stock_msg.txt and make sure theres no major errors. Scroll on down to the 2nd rbase list toward the end of the messages file. Now click just above it and scroll back up to the top, hold down the Shift button and Press A to select all of it and press backspace, you'll now see the rbase list at the top of the msgs file in notepad. Now scroll on down to the end of the subroutine list just beaneath it and deleted everything after the end of the subroutine list. You can do a simple Ctrl + F and pop up the find type in "---" and delete the entire line that those comments are noted. Now save the file as stock_dir.txt You now have a directive file to begin tinkering.

    Directive File

    The directive file is where you will assign labels to addresses you decode, this will make it MUCH EASIER to do disassembly since you can very easily see the PID name where a value is being used. The following is a quick cheat list of the temporary registers used in most EEC-V's. Copy and paste the following into your xxxx_dir.txt file at the top of the list just beneath the rbase parameters and before the subroutines:

    SYM 24 "temp0l"
    SYM 25 "temp0h"
    SYM 26 "temp1l"
    SYM 27 "temp1h"
    SYM 28 "temp2l"
    SYM 29 "temp2h"
    SYM 2A "temp3l"
    SYM 2B "temp3h"
    SYM 2C "temp4l"
    SYM 2D "temp4h"
    SYM 2E "temp5l"
    SYM 2F "temp5h"
    SYM 30 "temp6l"
    SYM 31 "temp6h"
    SYM 32 "temp7l"
    SYM 33 "temp7h"
    SYM 34 "tmp1l"
    SYM 35 "tmp1h"
    SYM 36 "tmp2l"
    SYM 37 "tmp2h"
    SYM 38 "tmp3l"
    SYM 39 "tmp3h"
    SYM 3A "tmp4l"
    SYM 3B "tmp4h"
    SYM 3C "tmp5l"
    SYM 3D "tmp5h"
    SYM 3E "tmp6l"
    SYM 3F "tmp6h"
    SYM 40 "tmp7l"
    SYM 41 "tmp7h"
    SYM 42 "tmp8l"
    SYM 43 "tmp8h"
    SYM 44 "tmp9l"
    SYM 45 "tmp9h"
    SYM 46 "tmp0l"
    SYM 47 "tmp0h"
    SYM 48 "fgtmp0l"
    SYM 49 "fgtmp0h"
    SYM 4A "fgtmp1l"
    SYM 4B "fgtmp1h"
    SYM 4C "fgtmp2l"
    SYM 4D "fgtmp2h"
    SYM 4E "fgtmp3l"
    SYM 4F "fgtmp3h"
    SYM 50 "fgtmp4l"
    SYM 51 "fgtmp4h"
    SYM 52 "fgtmp5l"
    SYM 53 "fgtmp5h"

    SAD - _lst.txt - Listing

    Now go back to SAD and click View >> Output File (or just open the stock_lst.txt file it created). Your disassembly listing should now be opened in notepad. At this time your probably wondering, where do I begin? Well that depends on who you ask, many start at the beginning and work their way through the code, me personally, I'm rather impatient and like to jump right to the good stuff as quickly as possible. The most important function in a Mass Air ECU is the Mass Air Flow transfer curve, so I jump straight to it :) The MAF transfer is VERY EASY to find. AFAIK, in all strategies (at least all that I've worked on) the MAF lookup code is identical. In your listing file, go up top and click on search and type in "LSSI_C". You want to keep searching until you find where interrupts have been disabled right before the LSSI is read. If it has, directly beneath LSSI_C you will see LSSI_B and LSSI_A being read as well and interrupts re-enabled. If you scroll down just below that a few operands, you will see a call to the interpolation routine.

    Here is an example of the maf lookup in a 2 bank strategyHere is an example of the maf lookup in a 4 bank strategy
    Note that it is showing the outdated SAD disassembly listing.
    2 Bank MAF Routine 4 Bank MAF Routine

    Verify MAF Transfer

    On 2 bank ecu's, the call will have the function number in it being called, in the example above SAD automatically named the maf transfer function "Func16", you can verify that is the actual MAF transfer by going to that function number and looking at its values. For 4 bank ecu's the lookup routine will have the maf transfer address loaded into register 36 before the call is made. You can go to that address (2250 in the example above) and verify it is correct as well. In both cases the MAF function will be 30 rows long and start with an FF FF and end with an 00 00. Congrats! you've just found the most important function in the ecu!

    The y axis of the maf transfer is the airmass flow. Depending on your strategy the airmass flow hex to lbs equation is affected by the processor speed. The table below lists the ecu clock speeds and their typical conversion.

    ECU Clock Speed

    ECU Clock Speed - XTALHPS

    Directive and Comments Files

    Now that we know the maf transfer's address we can add that to the directive file along with the maf voltage register and name the maf and interpolation routines. In your disassembly folder where your tune is saved, right-click >> new text document, name it stock_dir.txt, while your at it create a stock_cmt.txt file as well.


    In your directive file, you will want to assign the maf a name so it will automatically be labelled in the code, this will make life MUCH easier. To do so, you simply open up your newly created stock_dir.txt text file with notepad and enter the following.
    func12250 122c7"func_MAF_Transfer":WV+12800:WV+1024

    For detailed information reference SAD.pdf for a full breakdown of the disassemblers functions.

    The following quick reference charts are to quickly find the end address of a function and table to input in your directive file.
    Table End Address
    TblY RowsxX Cols
    Table Size
    Decimal SizeHex Size
    Tbl10x12byte(*2)(120-1)= 11977
    Tbl10x10byte(*2)(100-1)= 9963
    Tbl9x11byte(*2)(99-1)= 9862
    Tbl8x12byte(*2)(96-1)= 955F
    Tbl8x10byte(*2)(80-1)= 794F
    Tbl6x12byte(*2)(72-1)= 7147
    Tbl6x6WORD(*4)(72-1)= 7147
    Tbl6x6byte(*2)(36-1)= 3523
    Tbl5x5byte(*2)(25-1)= 2418
    Function End Address
    Function Size
    Decimal SizeHex Size
    Func30WORD(*4)(120-1)= 11977
    Func13WORD(*4)(52-1)= 5133
    Func12WORD(*4)(48-1)= 392F
    Func12byte(*2)(24-1)= 2317
    Func10WORD(*4)(40-1)= 3927
    Func10byte(*2)(20-1)= 1913
    Func8WORD(*4)(32-1)= 311F
    Func8byte(*2)(16-1)= 15F
    Func7WORD(*4)(28-1)= 271B
    Func7byte(*2)(14-1)= 13D
    Func6WORD(*4)(24-1)= 2317
    Func6byte(*2)(12-1)= 11B
    Func5WORD(*4)(20-1)= 1913
    Func5byte(*2)(10-1)= 99
    Func4WORD(*4)(16-1)= 15F
    Func4byte(*2)(8-1)= 77
    ***Add HEX size to Start address to find end address.


    In your comments file, you want to put notes as to what each line of code is doing, that way you can very easily work on the code without having to decipha what you've already deciphered. This will make the process MUCH easier in the long run especially when you walk away from the code for a while and jump back in it months later. So open up your newly created stock_cmt.txt text file with notepad and enter the following.
    09e20|MAF Subroutine
    09e66// MAF Transfer Function
    12250// MAF Transfer Function


    Now that you've updated the comments and directive file, re-run SAD and check out the labels you've made. You will now see that its much easier to follow the code with comments and labels instead of memory address locations. Get used to re-running the disassembler, you will be repeating the disassembler indefinitely to resolve addresses to labels to make the process much easier.

    Understanding Opcodes

    Now that we have a segment of known code, we can go through and discuss the operation codes and what exactly the calculator "ecu" is doing. The following is a listing of the Intel 8096 opcodes adjusted for the 8061/8065 instruction set. The following data is the best known information available, there are no known publically released or available 8061/8065 instruction sets, thus the following was adapted from 8096 over the years.

    8065 Opcodes
    Obvious, any of the bank opcodes will not apply to single bank binaries.

    The following is a very simplified list of the more common opcodes dummied down explaining what they do / how they work. It's most helpful if you are creating your own code or hacking away at the code. As you can infer, its aimed more toward the C / C++ programmers. For those not savvy in C and C++, anytime you see a bang "!" it means false / not (I.E. the result equates to ==0), any value other than 0 will return true.

    HEX OpcodeC++Operation Comments
    00 SKIPjump 1 location, kin to NOP, basically a NopNopjumps over 1 byte or "skips" the next byte, usually the following byte is a clear carry
    01reg CLRWreg = 0sets 2 bytes to 0 clears word
    05reg DECWreg--reg = reg - 1 used to decrease a value during loops
    07reg INCWreg++increases value by 1 increments a word, 0++ = 1 not 2
    08bitreg SHRWreg /= bit07 = / 128; 04 = /16 bit 7 = 10000000 in binary; usually used with /10 to convert from word scaling to byte for table lookup
    09bitreg SHLWreg *= bit 07 = *128
    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 == 1 dec

    0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 == 2048 dec; when bit shifted 11 you effectively *2048
    0abitreg ASRWreg /= bit 03 = /8
    0cbitreg SHRDWreg /= bit 05 = /32; 0a = /1024 0x400
    0dbitreg SHLDWregL *= bit 07 = *128
    10xx RBANKBank = xxReference Bank for next address
    11reg CLRBreg = 0clears byte of data
    17reg INCBreg++increments value by 1 increments one byte
    20jj SJMPjump forwardjump forward jj locationsE7 is a GOTO / JUMP for direct addressing
    22jj SJMPjump forward +200jump forward jj locations THEN jump +200
    23jj SJMPjump forward +300jump forward jj locations THEN jump +300
    24jj SJMPjump back -400jump forward jj THEN jumpBACK -400
    26jj SJMPjump back -200jump forward jj THEN jumpBACK -200
    27jj SJMPjump backjump forwards jj locations THEN jump back -100
    28jj SCALLcall addresspushes current address to stack then jumps forwards jj
    29jj SCALLcall address +100does the same as 28 but then jumps +100 more
    2ajj SCALLcall address +200""
    2bjj SCALLcall address +300""
    2fJ3 SCALLscall lower address -J3
    J3 Subtraction Addresses
    14 = -EC
    1c = -e4
    2f = -d1
    4f = -b1
    7b = -85
    8b = -75
    b2 = -4e
    ba = -46
    c9 = -37
    d4 = -2c
    30regjj JNBif !Bit 0if bit0=0 then jj (up to 0x80) signed jump, if exceeds 7F jump backwards
    31regjj JNBif !Bit 1if bit1=0 then jj (up to 0x80) signed jump, if exceeds 7F jump backwards
    32regjj JNBif !Bit 2if bit2=0 then jj (up to 0x80) signed jump, if exceeds 7F jump backwards
    33regjj JNBif !Bit 3if bit3=0 then jj (up to 0x80) signed jump, if exceeds 7F jump backwards
    34regjj JNBif !Bit 4if bit4=0 then jj (up to 0x80) signed jump, if exceeds 7F jump backwards
    35regjj JNBif !Bit 5if bit5=0 then jj (up to 0x80) signed jump, if exceeds 7F jump backwards
    36regjj JNBif !Bit 6if bit6=0 then jj (up to 0x80) signed jump, if exceeds 7F jump backwards
    37regjj JNBif !Bit 7if bit7=0 then jj (up to 0x80) signed jump, if exceeds 7F jump backwards
    38regjj JBif Bit 0if bit0=1 then jj (up to 0x80) signed jump, if exceeds 7F jump backwards
    39regjj JBif Bit 1if bit1=1 then jj (up to 0x80) signed jump, if exceeds 7F jump backwards
    3aregjj JBif Bit 2if bit2=1 then jj (up to 0x80) signed jump, if exceeds 7F jump backwards
    3bregjj JBif Bit 3if bit3=1 then jj (up to 0x80) signed jump, if exceeds 7F jump backwards
    3cregjj JBif Bit 4if bit4=1 then jj (up to 0x80) signed jump, if exceeds 7F jump backwards
    3dregjj JBif Bit 5if bit5=1 then jj (up to 0x80) signed jump, if exceeds 7F jump backwards
    3eregjj JBif Bit 6if bit6=1 then jj (up to 0x80) signed jump, if exceeds 7F jump backwards
    3fregjj JBif Bit 7if bit7=1 then jj (up to 0x80) signed jump, if exceeds 7F jump backwards
    45xxyyreg3reg2 AD3Wreg2 = [reg3 + yyxx]
    4bptrofreg2reg SB3Wreg = reg2 - [ptr+of] used to subtract a minimum from a current value
    57reg2of2of1adr2 AD3Breg2= ad + [(reg2-1) + of1of2] used to follow up with comparison usually 0quick way to make sure value is greater than 0
    5creg3reg2reg ML3Breg = reg2 * reg3 used to multiply byte registers and save the result as a word
    64reg2reg AD2Wreg += reg2
    65xxyyreg AD2Wreg += yyxx simply does addition on words sister is 75 for byte, subtraction is the opcode 69
    66reg2reg AD2Wreg += [reg2] saves the value of reg2 and then increments reg2
    69xxyyreg SB2Wreg -= yyxx subtraction for words addition is the opcode 65
    6dxxyyreg ML2Wreg *= yyxx simple multiplication for words division is the opcode 8C
    71hexreg AN2B reg (hex)bit=false both the current and hex bit have to be equivalent for the resulting bit to be set true, think of this as AND(1) if both bits are 1 the resulting bit is 1disables / turns off a bit
    fe = bit 0 off
    fd = bit 1 off
    fb = bit 2 off
    f7 = bit 3 off
    ef = bit 4 off
    df = bit 5 off
    bf = bit 6 off
    7f = bit 7 off
    75hexreg AN2B reg += hex adds HEX to reg sister is 65 for word
    7creg2reg ML2Breg *= reg2 multiplies 2 bytes used to multiply a byte by another byte register
    7dxxreg ML2Breg *= xx simple multiplication of a byte by X value used for simple arithmetic
    88regreg2 CMPWreg2, reg compare reg, reg2If reg2=0, instead of R0, just 0 will be compared
    89xxyyreg CMPWreg, yyxx
    8areg2reg CMPWreg, [reg2-1] compare reg, to reg2-1instead of comparing to reg2 and reg2+ (for word) it compares to reg2- and reg2
    8bptrofreg CMPWreg, [ptr+of]
    8creg2reg DIVWreg = regL /= reg2 divides a long by a word this may not be simple division
    90reg2reg ORB reg |= reg2 used to OR compare 2 different bytes
    91hexreg ORB reg ^ HexBits if either the current or hex bit is set, the result is a set bit ; think of this as OR1, if either bit is 1 the resulting bit is 1 used to turn on flags and pins
    1 = bit 0 on
    2 = bit 1 on
    4 = bit 2 on
    8 = bit 3 on
    10 = bit 4 on
    20 = bit 5 on
    40 = bit 6 on
    80 = bit 7 on
    92[ptr]reg ORB reg |= [ptr] used to OR compare 2 different bytes
    93ptrofsreg ORB reg |= ptr+ofs used to OR compare 2 different bytes
    94reg2reg1 XORBreg1 ^ reg2 exclusive OR, think of this as a difference compare, if the bits are not equal the resulting bit is 1, if both bits are equivalent the resulting bit is 0 changes its state and flips it back
    95hexreg XORBreg ^ HexBits toggles a bit changes its state and flips it back
    97ptrofsreg XORBreg = reg^[ptr+ofs] toggles a bit changes its state and flips it back
    98reg2reg CMPB(signed)
    99xxreg CMPBreg, xx
    9aR[ptr]reg CMPBreg, [Rptr] compares byte to pointer
    9bptrofreg CMPBreg,[ptr+of] reg 0 will compare to 0
    a0reg2reg LDWreg = reg2
    a1xxyyreg LDWreg = yyxx could be val or pointer
    a2reg2reg1 LDBreg1 = [reg2-1]; then reg2++ takes the value at that address, then the next loop increments reg2 used to get to the next address in an array
    a3ptrofreg LDWreg = [ptr+of] special function only0xC3 will flip the register and address
    a3ptr(-1)xxyyreg LDWreg = [ptr(-1) + yyxx] loads a RAM value to a scratch register used to compare RAM
    a4reg2reg ADCWreg += reg2 + CY add sum of reg2 and carry to reg
    a5xxyyreg ADCWreg += yyxx + CY add sum of yyxx and carry to reg yyxx is often set to 0000 to get carry only
    acreg2reg LDZBWreg = reg2
    adxxreg LDZBWreg = xx
    b0reg2reg reg = [reg2] (signed)
    b1xxreg LDBreg = xx (byte)
    b301xxyyreg LDBreg = [yyxx] copies the value out that memory [address]
    b3ptrofsreg LDBreg = [ptr+ofs]
    b3ptr(-1)ofs00reg LDBreg = [ptr+ofs] loads a byte of RAM into a scratch register used to get at an index
    b3reg2(-1)AxxAyyreg LDBreg = [ [reg2 + [AyyAxx]] loads a byte of offset ram into a scratch register used in a loop to copy a list
    bcxxreg int
    bdxxreg LDSBWreg = SSxx loads a word with a signed byte, bits 8 through 15 will be filled with the value of bit 7, either all 0 or all 1's
    c2ptrxx STW[address++] = xx loads xx into pointer address, not into this actual address usually used for loops to clear data
    c301xxyyreg2 STW[yyxx] = reg2 used to get to the upper RAM addresses 0xF000 0xA3 01 will flip the operand and register
    c3ptrofreg2 STW[ptr+of] = reg2 used to get to the lower RAM addresses 0x1000 special function only
    c3ptr(-1)of00reg2 STWreg2 = [ptr(-1)+of] used to save a scratch register to a RAM address
    c6ptrxx STB[address++] = xx loads xx into pointer address, not into this actual address usually used for loops to clear data
    c7ptrof0 STB[(ptr+of] = 0 if xx==0 then no reg2 check used to clear a ram address
    c7ptr(-1)ofxxreg2 STB[(ptr-1)+of] = reg2 note the ptr-1 to get lower address
    c9xxyy PUSHWyyxx puts value of x1x2 at top of stack array
    cbptrof PUSHW[ptr+of] puts value at address on the top of the stack array
    cbptrof POP[ptr+of] removes value at the top of the stack array and saves it into the address
    d1jj if <= reciprocol is > inverse opcode is DB
    d2jj if (signed) > reciprocol is <= inverse opcode is DE
    d3jj if < recipricol is >= inverse opcode is D9
    d5jj if (!overflow) jumps if overflow==0
    d6jj if (signed) >= jumps if >= inverse opcode is DA
    d7jj JNEif != jumps if != inverse opcode is DF
    d9jj if > recipricol is <= inverse opcode is D3
    dajj if (signed) <= jumps if <= inverse opcode is D6
    dbjj if >= jumps if < inverse opcode is D1
    dejj if (signed) < reciprocol is >= inverse opcode is D2
    dfjj if == jumps if == inverse opcode is D7
    e0regjj reg--, if !=0, then jj, then jj-100 decrements reg (for loop) if !=0, jump forward jj then jump back -100used for FOR loops
    e7jjj2 JUMPjump jj then j2 jumps forward jj then jumps again j2
    efjjj2 CALLjump forward jj then j2 pushes current address to stack, then jumps forward jj then jumps again j2
    f0 RETcall stack return address returns to the top address of the stack
    f2 pushp (PSW)save PSW saves the processor state word used to save the PSW for fiddling with the stack (passing args)
    f3 popp (PSW)restore PSW returns the processor state word back to normal MUST be followed by a return 0xF0, this is used to restore the psw after args are passed
    f8 clear carry
    fb EIenable interrupts
    ff NOPno output jump self (do nothing), kin to SKIP burns a clock tic, useful for accurate repetitve timing

    J2 Jump Addresses

    <----Negative Jumps---->
    <----Positive Jumps---->
    You get the idea.
    Note: Jumps are words that roll over within the same bank, a jump to 1XXXX will result in the 1 being omitted.

    2's Complement Math

    To understand bits, you need to understand how a byte is structured. A byte is a single register of data with a value from 0-255. A byte consists of 8 bits which is 8 "switches" in binary being that in binary you only have a value of 1 or 0, I.E. switch on (1) or off (0), or true (1) or false (0). 2s complement math can easily be broken down by understand the bits position and value. In a byte, the lowest bit (right most - bit 0) has a multiplier of 1. The first bit has a multiplier of 2, the 2nd bit a multiplier of 4, the 3rd bit a multiplier of 8, the fourth bit a multiplier of 16, the fifth bit a multiplier of 32, the sixth bit a multiplier of 64 and the final seventh bit a multiplier of 128.

    So to break this down, we can do a few examples to make it easier to understand.

    Subroutine / Function Arguments

    Some operations in the ecu such as doing interpolation look up or setting fault codes are very redundant, and to prevent an excessive amount of functions to do the same task, the ecu passes arguments to a function so it can carry out the task. Think of it as being variables modifying variables. In the RZAS0 binary there are only 3 functions that accepts these variable of variables "arguments". To define arguments in your directive file, simply go to the function or subroutine address and add : Y O +2 or : Y O +6. The # defines how many bytes are omitted after the function call and not used as code, that way the disassembler doesn't try to disassemble it. At this point, its not important whether the arguments are words or bytes, whats most important is that the disassembler can decipher code from arguments so you get a clean listing. For example in cbaza, you would have the following line in your directive file

    subr 0717c "subr_717c" : Y O +4

    which tells the disassembler anytime 0x717c subroutine is called to omit the followig 4 bytes since they are arguements and not code.

    Definition File

    A definition file is basically the same across all software. It maps the memory locations to human readable values. In order to add a parameter to your definition file there are a minimum of 6 values you will need to know.

    PIDgood to have but a good name will suffice if need be
    Byte / Wordbyte (1 byte = =8 bits) or word (2 bytes == 16 bits)
    Signed / Unsignedsigned allows negative numbers
    Equation for example: x/2
    Input/UnitLoad, ECT, ACT, VSBAR, etc..
    TIP: I HIGHLY RECOMMEND to add your parameters to your definition file in order by memory address to keep them organized. Doing so will help prevent you from accidentally inputting the wrong address, it also makes it significantly easier to navigate, modify, and update your definition file and will save you thousands of hours.

    Categories / Levels

    I used to use the following categories as I found it was most effective for me back then.

    However, in November of 2018 I completely revamped these as witnessed in the latest RZASA xdf. I find its significantly improved.
    1Airmost commonly un-altered air parameters
    2Emissionsmost purge and cat related parameters
    3MAF / MAP / BAP<---
    4Axle / VSS / Chassisratios axle etc...
    5Fan <---
    6Fuelfuel tables and modifiers including PERLOAD
    8DFSO / Failsafe Cooling <---
    9Cranking / Startup<---
    10Injectorinjector parameters
    11OL / CLswitches flags and threhsolds to set status
    12Pumpreturn and returnless params
    13Transienttransient fuel
    14Idle / Dashpot<---
    15Knock Sensorall knock sensor related
    16o2 / HEGObias amplitude and all o2 sensor related
    17RPM / Limitersall limiters
    18SecurityPATS disable sw and pats code
    19Sparkspark advance params including engine size SARCHG
    20Error Codesto quickly disable error codes
    21System / Fail-Safe / OBDall obd params
    22Scaling / Luggingall scaling functions
    23Temp / Voltageect / act threshold and alternator params
    24TP / WOTwot thresh and the like, any wot modifiers
    25Manual Transgear ratios for manual usually and reverse lockout params
    26Variable Camfor variable camshaft selections
    27Unusedparams not referenced in the strategy
    28A/C / Accessoriesa/c parameters and accessories like power steering params
    29Hardware / Switchesfor quick tune setup adjustment of hardware present
    30Console PIDscode modifying parameters not typically calibration constants, include all hacks here too
    31Auto Transauto parameters
    32Tuning / Engine / ConfigurationReference all of the important tuning variables here for ease of tuning.
    33Temporary / Unknownquick add scalars for testing purposes and what have you
    34Verifyany parameter you are unsure of being correct and need to verify or revisit
    35VID Blockaxle ratio and options VIN number and pats code
    36Catalytic Convertertypically the cat monitor parameters
    37TQ Modulationspark limiting switches and shift functions
    38EPC / TV Pressureengine tq table and slope and offset scalars
    39TCC / Torque Converter Clutchfor the tcc lock and unlock speeds and scalar clips
    40Shiftingfor quick auto adjustments
    41Dynotypically just the lock tcc and trans in gear patch/switch
    42Templatesinjector and maf quick load patches
    43Reference Datafor other strategy binaries loaded into tunerpro compare to copy values
    44Canister Purgecan purge emissions parameters
    45ECU Clock

    VID Block

    The VID block is typically stored in the same location on all binaries. The VID block should be added to your definition file to give you full access.
    VID Block Parameters
    CAL_IDFF063xFF06ASCIIthe strategy and two letter calibration identification
    PATS_CODEFF133xFF13HEXthe unique vehicle specific pats code
    TAGFF633xFF63ASCIITAG - contains ford copyright info such as year
    VINFF803xFF80ASCIIVIN - used for emissions testing and by some OBD-II scanners for vehicle info
    VID_ENABLESW3xFF95X42 (0xA2) == VID block enabled, 255 (0xFF) == VID Block disabled
    VID_REVMILE3xFF9AXvehicle tire revolutions per mile for information only, not used in any calcs
    VID_RT_AXLE3xFF9CX/1024rear end gear ratio used for vehicle speed calc when the vid gear axle ratio switch is enabled

    Important Addresses

    These addresses are typical in most all 4 bank ecu's.
    1x200ABIN_CHIP_IDcalibation id

    Quick Find Code Blocks

    The EEC's use the same code with tidbits of code added and removed over the years, this is what causes the different strategy names. Below is a quick reference chart of common code in most eec-v ecu's. This can be used as a cheat menu to quickly find segments of code your looking for specifically. This will be aimed more toward locatings payloads but it applies for calibration constants as well.
    Quick Reference Code
    KAMRF180,00,44or 65,80,00,44
    Dashpot Decay FN87968,3c,2call dashpot in routine
    UPDISCUPDATM in following routine
    TQM_SWGear Axle Ratio and Rev Mile to follow
    Pump_Voltagead,09,38RFS routine
    TP_OL_Threshold: 01,3e
    [code] JUMP_FRAC7c,35,34byte in code
    [code] xx09,04,30CL idle modulation
    [code] JUMP_MULT08,02,38
    fn012a0,37,46mbt routine
    hsf91,40,a1fan values
    crank pwb1,00,3a3rd or 4th from top, can find lambse values and a great many functions!!!
    P100037,2a,03mil sw and force good code


    The ecu calculates the checksum to verify the ROM is not corrupt. To calculate the checksum the following addresses are summed up, if their value equals 0, then the checksum is valid.
    Side note: The actual address the checksum is saved to is null since a correct checksum will return 0.
    I recommend rewriting the checksum calc routine to include the higher range on older 4 bank strategies instead of cross calculating.
    StrategyBank 0Bank 1Bank 8Bank 9ROM_TO
    4-BANK (newer)2000 - FFFF12000 - 1DFFF22000 - 2FFFF32000 - 3FEFF12004
    4-BANK (older)2000 - FFFF12000 - 19FFF22000 - 2FFFF32000 - 3FEFF12004
    CDAN42000 - FEFF12000 - 1FFFF1200A
    CBAZA2000 - FFFD200A
    GUFB2000 - 9FFF200A
    In all cases, the checksum is saved as an LSB 2-byte word using 2s compliment math.

    TunerPro Checksum Calc

    TunerPro will apply the checksum calcs STARTING with the FIRST ENTERED and working in order to the LAST ENTERED. The order they are added to the xdf is most important as the order they are displayed is not the order they are executed!!! Keep this in mind as you must ALWAYS enter in your checksum calcs in the correct order otherwise it will not function correctly.
    Special Instructions
    Special instructions include any background manipulation you need to complete to correctly calculate the checksum.
    These must be performed first (ENTERED FIRST) otherwise they will incorrectly excuted after the checksum has been calculated.
    TitleStartEndStoreStore SizeData SizeLSBPlug-inCalcComments
    XX --->Enter any Special Instructions first
    SumBank02000FFFF3FFF022LSBDefaultTWOsSum of bank 0
    SumBank1120001DFFF3FFF222LSBDefaultTWOsSum of Bank 1; Older Strats may only check up to 19FFF
    SumBank8220002FFFF3FFF422LSBDefaultTWOsSum of Bank 8
    SumBank9320003FEFF3FFF622LSBDefaultTWOsSum of Bank 9
    SumErr3FFF03FFF73FFF822LSBDefaultSumSum of All Banks
    SumOld12004120053FFFA22LSBDefaultSumCopy old checksum
    Checksum_ROM3FFF83FFFB1200422LSBDefaultSumSave New Checksum to ROM
    CleanupB32000320003FFFB11LSBDefaultSumSet Null filler back to FF==null
    CleanupA32000320003FFFA11LSBDefaultSumSet Null filler back to FF==null
    Cleanup932000320003FFF911LSBDefaultSumSet Null filler back to FF==null
    Cleanup832000320003FFF811LSBDefaultSumSet Null filler back to FF==null
    Cleanup732000320003FFF711LSBDefaultSumSet Null filler back to FF==null
    Cleanup632000320003FFF611LSBDefaultSumSet Null filler back to FF==null
    Cleanup532000320003FFF511LSBDefaultSumSet Null filler back to FF==null
    Cleanup432000320003FFF411LSBDefaultSumSet Null filler back to FF==null
    Cleanup332000320003FFF311LSBDefaultSumSet Null filler back to FF==null
    Cleanup232000320003FFF211LSBDefaultSumSet Null filler back to FF==null
    Cleanup132000320003FFF111LSBDefaultSumSet Null filler back to FF==null
    Cleanup032000320003FFF011LSBDefaultSumSet Null filler back to FF==null
    Note: 3x2061 typically contains 0x00 on most all EEC-Vs, this is needed to clear the checksum in order to correctly calculate the new.

    Equation (useable fractional digits)

    The following is a quick reference list for useable digits AFTER the decimal, this is important when creating a definition file so users can accurately change values without a loss of resolution.


    0.52^1X / 211typically vehicle speed
    0.252^2X / 40 (or ~2)0 (or ~1)typically spark or RPM, if RPM set decimals to 0
    0.1252^3X / 810 (or ~1)typically timers
    0.06252^4X / 16~0 (or 2)1RPM but also used for scaling =0, volts=2
    0.031252^5X / 3222usually Airmass but also idle speed or RPM
    XX / 502typically relative throttle voltage TPREL used for trans functions
    2^6X / 6422typically trans related specifically TP_REL
    2^7X / 12832typically lambse and tq
    2^8X / 25633 or ~0this is usually used for scaling and trans related, byte for egr fault timers
    2^9X / 51233typically accel rate or multiplier modifiers
    2^10X / 102443typically ratio, byte used for misfire rolavg fault filters
    2^11X / 204846typically dashpot, byte is only used for MAPSLOPE afaik
    2^12X / 409644typically isc airmass, byte is usually fn1353 hego bias
    2^13X / 81924usually hego bias
    XX / 128003typically voltage
    2^14X / 163844typically ratio related to trans
    2^15X / 3276835typically load but also duty cycle=3, gain=5
    2^16X / 655365typically timers
    2^17X / 1310726only XFREPT
    2^18X / 262144XXX
    2^19X / 5242886used for can purge flow
    2^20X / 10485766used for DASPTK, not sure of anything else
    2^21X / 2097152XXX
    2^22X / 41943047xx
    2^24X / 16777216XXX
    2^25X / 335544327typically fuel mass for injector breakpoint
    2^31X / 2147483648Xpayload only; maf clock tick/xx == maf on 27mhz ecu
    XX / 75497472003typically lbs/hr for injector slopes

    Multi-addressed variables

    Many scalars in the EEC-V's have multiple addresses to achieve the same value. This is due to the code actually having the value present rather than performing a look-up to a scalar. This makes the code more efficient. In these cases, I highly recommend using the PATCH type paramater in tunerpro and add all the addresses to the patch so they are all changed at once IF the value is enumerated. The Rear Hego Present scalar is a perfect example, in RZAS0 this scalar is reference in 21 different locations!!!!! You can simply assign the patch with a value of 0 to disable the hegos and a non-patched value of 2 to allow the rear hegos (stock h-pipe). This can be done for any switch type scalar. In dynamic scalars like the injector slopes for example, this cannot be done since the value must be inputted and numerous entries are needed. I denote the entries with a simple x / x for easy reference.


    A "Hack" is simply a modification to the code that was never intended to be performed. It is often common to swap operands when 'hacking' to make a function perform differently. When doing so, an enumerated value should be used, however, I have my own decipha exclusive equation I'll share below.

    Decipha Exclusive Equations / Elude Enumeration

    When adding new scalars for hacks, I use the following equation (this is a decipha exclusive) and not recommended
    (x-lower value) / [remainder of high-low]
    so lets say you have
    22610 stock value
    8584 is your new hacked value

    22610-8584 = 14026, This gives us an equation of:


    a value of 1 = 1*14026; 14026 + 8584 = 22610 (stock)
    a value of 0 = 0*14026; 00000 + 8584 = 8584 (hacked)

    thats how I make my scalar switches 0.000 and 1.000 to alter opcodes and what not, if using BE be sure to add at least 3 decimal places and limit the value range from 0 to 1 to prevent any corrupt values from accidentally being loaded. The decimals make it easy to see if the value is corrupt. If using TunerPro YOU CANNOT USE THIS EQUATION since TunerPro will not prevent someone from inserting decimals between 0 and 1. For TunerPro enumerations I recommend using the PATCH data type. Then just assign your data there with an enable/disable button simple enough.

    TunerPro Value Equation for Automated Hide / View

    When creating hacks such as moving or extending scaling function for more resolution you will need a new table parameter to show the new scaling of your new function. This can be tricky since users that do not have your patch enabled will be viewing the incorrect values. However, decipha has a fool-proof solution that will make it easier for everyone. Tunerpro has an excellent feature that allows you to reference a value for arithmetic. This will solve our patch/hack problems from causing the wrong scaling to be viewed. By creating two exact copies of the same table one with the old scaling (for reverse compatibility) and one with the new, you can use this equation to 0 out the table not in use. This will make it very easy to identify which table scaling is in use.

    so for example, lets say one of the bytes of your modified code is now 0x04 and the prior stock value was 0x00.
    The following equation will show you how I invert the value so high and low are swapped.

    For example lets say your actual table equation is:
    X / 128

    The following will hide and display the tables automatically based on your manipulated code

    Extended Table Equation Modifier
    Y==4; X / 128 * (Y / 4) = 1 = multiply the equation by 1 = correct viewing
    Y==0; X / 128 * (Y / 4) = 0 = multiply the equation by 0 = result is all 0s, table is 'hidden'

    To INVERT for Stock Table Equation Modifier
    Y==4; X / 128 * ((((Y -4) *-1) +0) / 4) == 0 == result is all 0s, table is 'hidden'
    Y==0; X / 128 * ((((Y -4) *-1) +0) / 4) == 1 == correct viewing

    Why the +0 ? So that the table doesn't display negative values

    Check out the FN904 Sealevel Spark Table and Extended Table in my GUFx def file to see it in action based on the FN071_EXT patch value.


    Datalogging can simplistically be broken down into 4 basics, 1- disrupting the code, 2- executing the patch code, 3- shadowing payloads, 4- parsing data with the QH With the new "Standardized" ADX datalogging its simplified significantly. This will prevent errors when jumping between strategies and makes it very easy to create datalogging support as well as maintaining your adx since you only keep one master file. The patch code stays consistent for all defs except for the raminit flag that you took out the console routine in order to call the patch code routine. Once you've located the console call routine, insert your CALL to your patch code address. If your console call routine is not within' bank 8 you will have to update the bank calls in the patch code. I have listed patch codes for the logging list and patch in different banks to make it easier to implement in the chart below for reference.

    This table below is outdated

    Strategy Datalogging Addresses
    DateStrategyBanksCode Address Code SizeList AddressList SizeRAMINIT FlgConfiguration (Console,Call,Call,List)
    2017-07-03GUFX18x DF401598x EE00128xx xx xxSingle Bank
    2017-07-03RZASA48x FF571690x FE0029871 EF 908 -> 8 -> X -> 0
    *2017-07-03CRAJ048x FF571690x FE0019471 EF 908 -> 8 -> X -> 0
    2017-07-03CVAF148x FF571690x FE00xx71 EF 908 -> 8 -> X -> 0
    2017-07-03FBFG248x FF571690x FF0020471 EF 928 -> 8 -> X -> 0
    2017-07-03FBGI048x FF571690x FE00xxx71 EF 928 -> 8 -> X -> 0
    OMAE24808 -> 8 -> X -> 0 ?
    CMAI64808 -> 8 -> X -> 0 ?
    *2017-06-09b code shadowed to 1x1F20 instead of C000, change of 3 bytes, 8xff5f from 0x00 to 0x20; 8xff60 from 0xc0 to 0x1f; 8xfff8 from 0xc0 to 0x1f

    Part 1 - RAM Addresses

    Payload List - in ADX due to DMA logging

    The following is the ORDERED list that MUST be used for the Standardized ADX to function correctly.

    NOTE: To skip over an parameter simply log 1F20. As for the ops list if you do not have the ddress for a bitmask then set the address to FFFE which will skip over that stacked bit to continue on with the remaining stacked bits.

    This list is outdated

    List A - Word Shadowing - Payload List addressing is posted above. See Strategy DataLogging Address Table Above
    ADX Offset
    PIDXX Address XXEquationUnits
    110BIDI Port A21F8Dflags-flagsflags
    109BIDI Port A11F8CflagsFFFFflagsflags
    108knk sensor spark adjustment1F8BSPKAD-xx
    107fuel pump voltage1F8AFP_INPUT_VLTFFFF/16Volts
    105mbt spark limit1F88SPK_M_B_T0E9A/128 sispkadv
    103bdl spark limit1F86SPK_BDL0E90/128 sispkadv
    101Fuel Level input1F84IF_FUEL_LVL02F8xx
    99Fuel tank pressure1F82TPR_ENGF1CCxx
    97Est Fuel Consumption1F80FLI_FUEL_SUM148E/33554432lb/m
    95deciphas enrichment fuel1F7ELOST_FUEL__AF112/32768Lambse
    93Feeback Spark1F7CSPK_ACTUALF0DE/4dBtdc
    91Calc pump fuel flow1F7AFP_FLOWRATEF322/16384
    89Fuel Rail Pressure1F78FIP_DELTAF0F2
    87modulated fuel pump dutycycle1F76FPUMP_DC1132/32768%duty
    86lost alternate fuel lambse1F75LOST_ALT_MUL/128lambse
    85cold fuel lambse adder1F74FUL_ADD_CLDFFFF/128Lambse
    83filtered Acceleration Rate1F72VS_RATE1274/ 512MPH/sec
    81inferred engine oil temp1F70INF_EOTF04Exx
    80flags (spark)1F6Fflags
    79Spark Source1F6ESPK_SOURCEFFFFxRef
    77inferred ambient temp1F6CINFAMB_KAM147exx
    75trans Input/Output Ratio1F6ASPD_RATIO1226/16384Slip Ratio
    73Trans oil temp1F68TOT02AC/8Temp F
    71Engine Tq into TCC1F66TQ_NETFFFF/ 0.5ft/lbs
    70flags (trans)1F65flags
    69Trans Line Pressure1F64TV_PRESFFFF/2psi
    68 MOVEDFN725A_ACT1F63spk_bdl_act_retard-xmoved as of 10-13-17
    67Gear Commanded1F62GR_CMFFFF/2Gear
    65OSS RPM1F60NOBART1264/4RPM
    63TCC PWM DutyCycle1F5EBCSDC1230/32768TCC_DTY
    61total fault codes stored1F5CNUM_CODESFFFFXX
    59hego2 voltage1F5AIEGO210164/64
    57driver side ltft1F58KAMRF207A6
    55driver side stft1F56LAM_FINAL20450
    53knk sensor 1 voltage1F54KNK_SNS1_CNTF14AXVolts?
    51transient fuel time const1F52EFUEL/TFC_TAU or TSIEF01B6512sec?
    49transient dynamic fuel trapped fraction1F50EFTRFF/TFC_DYNX or AEFUEL01B8512%
    48park drive lever position1F4FPDL-x/27=p;6=r;5=n;4=od;3=d;2=2;1=1
    47desired idle rpm1F4EDSDRPMFFFF/4rpm
    45injector pulse width1F4CFUELPW1012C/ 0.5pw (in ticks)
    44isc mode1F4BISCFLGXstate
    43throttle position flag1F4AAPTFFFFXstate
    41throttle position voltage1F48TP0122/64ADCnts
    40cyl head temp or iat2 (cobra/L/HD)1F47CHT or IAT2-xtemp F
    39battery voltage1F46VBATFFFF/16Volts
    36*vsbar is mph calculated from vss1F43VSBAR/2MPH
    35*vsbart is mph calculated from oss1F42VSBART_RTFFFF/2MPH
    33isc duty1F40ISCDTY012632768%Duty
    31dashpot airmass1F3EDASPOT1418/4096lbs/min
    29hego1 passenger1F3CIEGO11015C/64ADCnts?
    27passenger ltft1F3AKAMRF107A4256Err%
    25passenger bank1 STFT1F38LAM_FINAL1044E32768Lambda
    23dpfe / evp voltage1F36EPTBAR or IEVP (WBo2)014A/64ADCnts
    21raw maf voltage1F34IMAF or VMAF, or MAPOPE017E/64ADCnts, [Speed Density == /128 = MAPOPE (byte)]
    19inferred load (not PCT_LOAD)1F32TOTLDST or MAPF018/32768LOAD
    17filtered TP_REL for shifting1F30TP_SS_L or RATCHF38C/64ADCnts
    15percentage of load1F2EPERLOAD or MAPPA1372/32768%load
    13Filtered RPM1F2CNE03EA/4RPM
    11engine VE1F2ALOAD_FG or MAP0134/32768Load, [Speed Density == /8 = MAP (byte)]
    9spark advance1F28SAFTOT1794/4 (signed)dBtdc
    7airmass flow1F26AM134C/1024lbs/min
    6*inlet air temp1F25ACT/0.5 (signed)F
    5*engine coolant temp1F24ECTFFFF/0.5 (signed)F
    3CL idle isc correction1F22IPSIBR140E/4096lbs/min
    1engine run timer1F20ATMR1 or ATMR3_HI_RES15FE/8sec
    0null1F1Fnulldoes not existXoffset 0 - not in list but polled for superlogger offset
    *bytes listed in bold = Must be done per byte in List B

    REMEMBER: FFFF skips that address for byte or bitmask manipulation.
    and FFFE zeros that value for unlogged words.
    0x1F4F is set to be a value of 0 or 1 determined by the OL_DES flag done in the bits code.
    PDL needs to be moved.
    List B - Copy MSB to LSB for odd addesses.
    Again, start at the bottom and work up to the top, and most importantly, don't forget to put the Quad 0s to mark the end of the list and continue on to C.

    CHT or IAT211EF

    Part 3 - Bit Comparisons
    NOTE: Bits can only report when they are on, anything in the off state will
    not show an indicator so FFFE can zero out unlogged bytes/words/bits and not
    set an incorrect flag button.

    REMEMBER: 1FXX == offset to copy to
    Bit Flags Reference Values

    List C - Shadow and Stack BitFlags - 1F44, 1F45, 1F63, 1F65, 1F67, 1F6F
    Bit 7
    Bit 6
    Bit 5
    Bit 4
    Bit 3
    Bit 2
    Bit 1
    Bit 0
    Bit 7
    Bit 6
    Bit 5
    Bit 4
    Bit 3
    Bit 2
    Bit 1
    Bit 0
    Bit 7
    Bit 6
    Bit 5
    4580Hego 1 not switching
    Bit 4
    Bit 3
    Bit 2
    Bit 1
    Bit 0
    Bit 7
    Bit 6
    Bit 5
    Bit 4
    Bit 3
    Bit 2
    Bit 1
    Bit 0

    To summarize:

    first words are payload adresses - List A
    second bytes are copying high to low - List B <--- not any more, simply log a word
    3rd bits are copying bits flags to 0 - List C
    Note: Max Polling Limit of the QH is 102 bytes

    Below is outdated

    We saved the best for last, now that the patch is written we are ready to start requesting RAM addresses to poll. But not just so fast there young grasshoppah, it is very important that you keep track of the order in which you poll your addresses. If you have setup the patch code with registers in the correct order then you are done! Simply enable the datalogging patch code in your tune and use the DECIPHA.ADX datalogging file to datalog. The following is the ACTUAL functioning of the datalogging in detail for your knowledge.

    8065 REGISTERS are from 0x000 to 0x3FF, the QuarterHorse cannot access those addresses directly. Directly addressable RAM begins at 0x400 on up. Since you cannot access the ecu's REGISTERS directly, In order to datalog these registers you must write patch code to copy/shadow REGISTERS to MBUS where they are visible. For simplicity and to reduce errors, the majority of the QH_CONFIG can be reused from the available strategy files, but for the sake of understanding, I will break down exactly what is going on so you have a much better understanding of it and can write your own datalogging files for the strategy your working on. The QH Write Patch command is fairly simple once you know how it works.

    I highly recommend referencing the DECIPHA.ADX file to follow along. The following applies to the Quarterhorse from using Tunerpro RT.

    To follow along open up the ADX Editor in TunerPro and cruise on down to Commands >> QH_Configure QH for Payloads [QH_CONFIG] tab

    I highly recommend overwriting the raminit flg at the end of console routine and calling the patch code then using 0x1F20 to shadow for datalogging.

    < 0 > Configure QH for Payloads [QH_CONFIG]

    This is the actual list of steps IN ORDER that TunerPro will perform to datalog and MUST ALWAYS be in this exact order:

    TunerPro Command Structure
  • 1
  • (Pause for Data Rate) 100msec [WAIT]
  • 2
  • reQuest QH Packet
  • 3
  • Reply to Q - 400 msec (0x4F)

    < 1 > Pause for Data Rate

    Pause for Data Rate; just as it states, the QH must reply with its data rate before anything can function, its nothing more than a 100ms wait timeout

    < 2 > reQuest QH Packet - KEEP TRACK OF OFFSETS!!!!

    The order in which the addresses are polled below will determine the TunerPro offset for each VALUE so when it comes time to configuring the values you must keep track of the offset they are at. This is a VERY TEDIOUS PROCESS THEREFORE, If you poll your payloads in the order I have defined below then you can use my DECIPHA.ADX and the hard part is already done for you!!!!!!!! I recommend you log all the critical payloads I have defined below in the ordered layed out. You can then log any additional payloads as you desire AFTERWARDS. If doing so, be sure to you configure a new dashboard for your additional values.

    Also note, the QH has a hard poll limit of 109 bytes per query. I have created my TunerPro dash to be what I find the most efficient, I highly recommend you follow suit as it is a significant time investment to create an in depth dashboard. I will keep the RAM addresses here to personally keep track of the payloads and value offset but also for others to reference. If you look at the registers you'll see many are in the same location throughout most if not all strategies. This can give you a head start in many cases. If you do develop any datalogging support I highly encourage you to send me your logging list and I will add them to my listing. This way if I update the structure of the universal ADX I can update the logging list as well. It makes it significantly easier to manage updates as I can very quickly update 20+ logging lists on multiple strategy files by simply copy and pasting.
    NOTE: Only addresses in the 0x000 - 0x3FF range must be shadowed up above in the 2nd step of writing the patch code "INSERT Registers Payloads." I shadow all registers even upper memory which is directly accessible over the MBUS because it allows me to have a STANDARDIZED offset for any given payload.

    51 is the Query code in ASCii = Q
    0x6D is the sum of elements to poll, 0x6D = 109 bytes

    NOTE: 0x6D == 109 is the maximum bytes of data the QuarterHorse can poll per Query.

    0x01 0x01 0x1F 0x1F
    read 1 byte(s) from QHRam1 address 1F1F; this has an offset of 0 since it is the first address being queried
    keep in mind, the address requested will be polled in the order you query them
    If you've been paying attention your probably thinking right now, wtf decipha?? why 1F1F??, simple...
    With the addition of the SuperLogger all offsets get pushed out 1 byte, by omitting the first byte while
    polling with the non-superlogger, it keeps the same adx viable for use with and without!!!!!!

    Thus, 1F20 = offset byte 1

    More Examples of query commands:

    0x01 0x01 0x02 0xA8
    read 1 byte from ""RAM1"" address 02A8, this has an offset of byte 8 (which you don't need to know, but for more understanding, it's shadowed at 1xDD98)

    0x02 0x01 0x02 0xC0 = offset 9-10, since the prior address was only 1 byte, these byte will be placed in the next address, 1xDD99 to 1xDD9A

    0x01 0x01 0x03 0x6F = offset byte 1

    and so on and so fourth...
  • 8>Payloads - RAM ADDRESS LIST This is where the RAM Addresses are shadowed, reference the Payloads section for the list of RAM Addresses.
  • 9>Config Reply to Q request a reply and that patch code is complete, now its time to move on to the "Values" and add in the payloads, be mindful of your offsets and byte sizes!!!

    < 2 > Insert Register Payloads

    57 36 05 DF 9A 4E 00 78 00 ....CONTINUE ADDRESS LIST OF REGISTERS...

    0x57 is W in ASCii which is the QH command to WRITE
    0x36 is the # of RAM BYTES in HEX of the code to be copied to shadow memory ( 2 bytes taken per register )
    0x05 is the QH MEMORY SLOT to write the patch, see the table below for reference.

    QH Write Modes
    Note: 0x05 is to write up to a 256 bytes at a time, you can also write to 0x15 if you choose to write a patch for each byte!!!! Wayyy too time consuming to even be considered. Again, with 0x05 you can only write 256 bytes at a time, if your patch code is longer than that you'll need to split it up into more Send Commands.

    The QuarterHorse command mapping is listed in the table below for reference.
    01= QH Memory Bank 1
    05= ROM Bank 1
    15= ROM bank1 (1 byte)
    06= ROM Bank 8
    16= ROM bank8 (1 byte)
    07= Upper Memory (single bank tunes)
    0xYYHSB of address YYzz to write patch code
    0xZZLSB of address yyZZ to write patch code
    Note: single bank EEC-IV use bank 07 as the code goes at the top of RAM.

    Below is outdated

    0xFF00 is the actual ROM location where the ops list are to be written. for my patch, bank 8 is what we are going after. Keep in mind, this patch will most likely work for 99% of all 4 bank strategies but you MUST VERIFY this address contains null filler and no code. Note: Usually, only the inserting jump to patch code address would need to be updated to be within the main loop later down in "Step X - Write Patch Routine".

    These address are the RAM registers you wish to datalog, note that they are LSB first as thats how the Intel ECU accesses ROM.
    AC 02 // TOT

    IMPORTANT NOTE: make sure you do not shadow into RAM!!! RAM is from 1xE000 to 1xFFFF, shadowing in ram will corrupt the ecu and cause odd behavior!!! 1xE000 - 1xDF9A = 0x66 == 102 bytes, highly unlikely you'll ever have that many payloads in the 0x000 to 0x3FF range but noteworthy.

    Note: The addresses above are ONLY in the 0x000 to 0x3FF range where registers are inaccessible on the MBUS and must be shadowed. All addresses 0x400 and above will be read directly in Step 6

    < 3 > Reply to Q

    < 4 > Insert Jump to Patch Code / (BE - QHorse tab in XLS)

    For my code, I chose to 'splice' a jump to my new datalogging patch code routine at the tail end of the console routine (8xF66F), you can insert a jump wherever you wish or find most reasonable. I highly recommend using the console routine, it can very easily be found by searching for "= 2062" in your disassembly, you will see another scratch register being set to "= f0" directly beneath it for the rom pointers to be loaded. You want to go to the end of that routine where it 'returns' with the 0xF0 op-code. Usually just before that op-code there is a flag being set that is 3 bytes in length including the op-code. You can rewrite that line and jump to null filler at the end of bank 8 to execute the datalogging patch code. In RZASA, 8xFFDE is tail end of null filler at the end of bank 8. And 8xF66F is the console routine with the line that contains the code we will overwrite to jump to our new patch code routine.

    f66f: 71,ef,90 an2b R90,ef ATMR2_FLAG &= ef;
    ^^ must save the above and put it at the end of the shadowing patch routine so its executed.

    I will rewrite this with
    f66f: ef,6c,09 scall 8xFFDE
    so to do so we simply enter it in...

    0x57 0x03 0x06 0xF6 0x6F 0xEF 0x6C 0x09
    57 is W in ASCii = Write
    03 is the number of bytes to be written
    06 is the QH memory slot which corresponds with rom bank 8
    F6 6F is the ROM memory location 8xF66F to write the following code
    EF 6C 09 is the code to be written

    EF 6C 09 in intel disassembly is an 0xEF= call to +0x6C, so being that 8xF672 is the next location +0x6C = F6DE, and 0x09= +0x900; F6DE+0x900 = 8xFFDE is being called.

    < 5 > Reply to Q

    < 6 > Write Patch Routine

    I recommend using the console routine to execute your patch code. If you cannot do so for whatever reason, in mosy 4 bank defs, 8xFFDE is null filler at the very end of bank 8 where I recommend writing your patch code. This should work for all eec-v ecu's as code is not normally written to the very tail end of bank 8.

    57 20 06 FF DE A1 9A DF 42 8A 42 00 DF 13 A2 42 46 A2 46 44 65 00 C0 46 C2 46 44 65 02 00 42 27 E8 71 EF 90 F0

    57 is W=Write
    20 is the number of bytes to write (32 bytes == 0x20 in hex)
    06 is the QH memory slot == bank 8 from reference chart above,
    8xFFDE is where we are writing the following new subroutine we are creating for the patch code to execute within the rom's code
    0xA1 and onward is the actual patch code to write (0xA1 is the load word op-code in intel assembly)
    9A DF using Intel LSB == DF9A, this is the address where we wrote our register list of addresses to log

    Now you've reached the point where you need to actually start writing some patch code, or just reuse this.

    The following is the actual datalogging patch code in my decipha.adx file. Keep in mind, this can be reused on other strategies with only the shadowing address needing to be updated if changed.

  • Patch Code
  • This is the actual patch code written in Intel Assembly
    A1 9A DF 42 // r42 = DF9A // shadowing address
    8A 42 00 DF 13
    A2 42 46
    A2 46 44
    65 00 C0 46 // Offset Address 0xC000 is visible on the MBUS for shadowing
    C2 46 44
    65 02 00 42
    27 E8
    71 EF 90 // code overwritten in console routine to insert jump to new patch routine
    F0 // return back to console routine and execute normal ecu code flow

    Note: The datalogging offset 0xC000 is the ACTUAL QH RAM ADDRESS, there is no additional offset added and it IS NOT added to the Base Address!!!!
    Skip down to step 7
    The following is for reference only
    CBAZA Patch Code
    The following is how the cbaza patch code functions for datalogging for referece, special thanks to derek fenwick for creating this and sharing.

    d6d5: a1,08,d7,42 ldw R42,d708 R42 = d708; // list of registers to shadow to mbus
    d6d9: a2,43,14 ldw R14,[R42++] R14 = [R42++]; // 14 = register address
    d6dc: a2,14,1c ldw R1c,[R14] R1c = [R14]; // 1c = registers value
    d6df: c3,15,00,0d,1c stw R1c,[R14+d00] [R14+d00] = R1c; // shadowed =register+offset = value
    d6e4: 8a,42,00 cmpw 0,[R42] // check 0 to stop loop
    d6e7: d7,f0 jne d6d9 if (0 != [R42]) goto d6d9; // loop until reached end of list
    d6e9: a1,22,20,14 ldw R14,2022 R14 = 2022; // lost console code follows
    d6ed: 3c,24,01 jb B4,R24,d6f1 if (!B4_R24) {
    d6f0: fb ei enable ints; }
    d6f1: a1,f0,00,18 ldw R18,f0 R18 = f0;
    d6f5: b3,01,20,20,1a ldb R1a,[2020] R1a = [2020];
    d6fa: a2,15,1c ldw R1c,[R14++] R1c = [R14++];
    d6fd: c2,19,1c stw R1c,[R18++] [R18++] = R1c;
    d700: e0,1a,f7 djnz R1a,d6fa R1a--;
    if (R1a != 0) goto d6fa;
    d703: 71,ef,24 an2b R24,ef R24 &= ef;
    d706: f0 ret return;

    d707: ff fill

    d708: ac,00 // reg 0xac = start of register list to shadow

    d70a: b0,00, // register 0xb0 = 2nd register to shadow
    d728: 00,00 // end of register list
    d72a: 00,00 // end of register list

    SuperLogger Configuration

    ADX Header Config
    Connection Command:None
    Monitor Command:Harvest Data Macro
    Disconnect Command:None
    Pause Command:VersionFetch
    Unpause Command:VersionFetch
    TitleUnique IDDescriptionBaudHex CMD StringChecksumManually Sendable
    Set Accel Paramsetaccelparam00x41 0x01 0x2B 0x02Sum 0x6FN,N
    Set LogBut Active Startup Inactivesetlogbutactsu00x44 0x4F 0x61Sum 0xF4N,N
    DR: Configure PacketD_R_QH00x44 0x52 0xFF 0x00 0xC8 0x00 0x01 0x01 0x74 0x71Sum 0x44N,N
    readeepreqreadeepreq00x48 0x52 0x80 0x05 0x00Sum 0x1FN,N
    PT close lastbyteptlastbyteclos00x74None -
    SL DS Setup for PatchetcSLDS00x44 0x53 0x0A 0x0B 0x0C 0x0D 0x03 0xFE 0x00 0x51 0x4A 0x01 0x03 0x0D 0xB1 0x01 0x03 0x0D 0xB0 0x02 0x03 0x02 0x50 0x02 0x03 0x02 0x4E 0x02 0x03 0x02 0x5C 0x02 0x03 0x02 0x60 0x02 0x03 0x02 0x0A 0x02 0x03 0x02 0x0C 0x02 0x03 0x07 0xB4 0x02 0x03 0x07 0xB6 0x02 0x03 0x02 0x06 0x02 0x03 0x02 0x08 0x02 0x03 0x01 0x1C 0x02 0x03 0x01 0x1E 0x02 0x03 0x01 0x16 0x02 0x03 0x0D 0xAE 0x01 0x03 0x02 0x9F 0x01 0x03 0x02 0xBD 0x02 0x03 0x02 0x9A 0x02 0x03 0x0D 0xAA 0x01 0x03 0x0D 0xD0 0x02 0x03 0x01 0x26 0x01 0x03 0x02 0x11 0x02 0x03 0x01 0x8C 0x02 0x03 0x01 0x88 0x01 0x03 0x01 0x2F 0x01 0x03 0x01 0x66 0x02 0x03 0x01 0x5C 0x02 0x03 0x0D 0xB8 0x01 0x03 0x01 0x57 0x01 0x03 0x01 0x6B 0x02 0x03 0x01 0x54 0x01 0x03 0x0D 0xEE 0x01 0x03 0x0D 0xE7 0x01 0x03 0x0D 0x26 0x01 0x03 0x0D 0x27 0x01 0x03 0x0D 0xEC 0x01 0x03 0x0D 0xE9 0x01 0x03 0x0D 0x29 0x01 0x03 0x0D 0x28 0x01 0x03 0x0D 0x2E 0x01 0x03 0x0D 0xEF 0x02 0x03 0x02 0x52 0x02 0x03 0x02 0x58 0x02 0x03 0x02 0x56 0x01 0x03 0x02 0xDC 0x01 0x03 0x01 0x2C 0x02 0x03 0x01 0x68 0x02 0x03 0x0D 0xD2 0x01 0x03 0x02 0x88 0x01 0x03 0x01 0x93 0x02 0x03 0x01 0x8E 0x02 0x03 0x03 0x2A 0x02 0x03 0x03 0xA6 0x02 0x03 0x03 0x30 0x02 0x03 0x02 0x9C 0x02 0x03 0x01 0x6C 0x01 0x03 0x02 0x9E 0x02 0x03 0x01 0x24 0x02 0x03 0x07 0xE4 0x02 0x03 0x07 0xE6 0x02 0x03 0x07 0xE8 0x02 0x03 0x07 0xEA 0x02 0x00 0x01 0x03 0x2B 0x01 0x01 0x44 0x01 0x03 0xFF 0xFE 0x01 0x03 0x02 0x72 0x01 0x03 0x0D 0xC8 0x01 0x03 0x0D 0xC9 0x01 0x03 0x01 0x4D 0x01 0x03 0x01 0x48 0x02 0x03 0x01 0x14 0x02 0x03 0x01 0x12 0x02 0x03 0x01 0x80 0x01 0x03 0x0D 0xCB 0x24 0x4FSum 0x8BN,N
    SLSetupSimpleSetupSimple00x44 0x53 0x0A 0x0B 0x0C 0x0D 0x02 0x80 0x00 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x80 0x00 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01Sum 0xC7N,N
    Read Time Requestreadtimereq00x44 0x54 0x52 0x00 0x08Sum 0xF2n,n
    QH Patch Sendqhpatch00x57 0x3D 0x07 0x84 0xB2 0xA1 0xEE 0x84 0x42 0xA2 0x43 0x14 0xA2 0x14 0x1C 0xC3 0x15 0x00 0x0D 0x1C 0x8A 0x42 0x00 0xD7 0xF0 0xA1 0x22 0x20 0x14 0x3C 0x24 0x01 0xFB 0xA1 0xF0 0x00 0x18 0xB3 0x01 0x20 0x20 0x1A 0xA2 0x15 0x1C 0xC2 0x19 0x1C 0xE0 0x1A 0xF7 0x71 0xEF 0x24 0xA3 0x01 0xFC 0xFF 0x42 0xC3 0x01 0xFE 0xFF 0x42 0xF0 0x00Sum 0xA2n,n
    QH Patch Send 2patch200x57 0x21 0x07 0x84 0xEE 0xB0 0x00 0xAE 0x00 0xAA 0x00 0xD0 0x00 0xB8 0x00 0xEE 0x00 0xE6 0x00 0x26 0x00 0xEC 0x00 0xE8 0x00 0x28 0x00 0x2E 0x00 0xD2 0x00 0xC8 0x00 0xCA 0x00 0x00 0x00 0x00Sum 0x09n,n
    QH Config Singleqhsingleconfig00x51 0x4A 0x01 0x03 0x0D 0xB1 0x01 0x03 0x0D 0xB0 0x02 0x03 0x02 0x50 0x02 0x03 0x02 0x4E 0x02 0x03 0x02 0x5C 0x02 0x03 0x02 0x60 0x02 0x03 0x02 0x0A 0x02 0x03 0x02 0x0C 0x02 0x03 0x07 0xB4 0x02 0x03 0x07 0xB6 0x02 0x03 0x02 0x06 0x02 0x03 0x02 0x08 0x02 0x03 0x01 0x1C 0x02 0x03 0x01 0x1E 0x02 0x03 0x01 0x16 0x02 0x03 0x0D 0xAE 0x01 0x03 0x02 0x9F 0x01 0x03 0x02 0xBD 0x02 0x03 0x02 0x9A 0x02 0x03 0x0D 0xAA 0x01 0x03 0x0D 0xD0 0x02 0x03 0x01 0x26 0x01 0x03 0x02 0x11 0x02 0x03 0x01 0x8C 0x02 0x03 0x01 0x88 0x01 0x03 0x01 0x2F 0x01 0x03 0x01 0x66 0x02 0x03 0x01 0x5C 0x02 0x03 0x0D 0xB8 0x01 0x03 0x01 0x57 0x01 0x03 0x01 0x6B 0x02 0x03 0x01 0x54 0x01 0x03 0x0D 0xEE 0x01 0x03 0x0D 0xE7 0x01 0x03 0x0D 0x26 0x01 0x03 0x0D 0x27 0x01 0x03 0x0D 0xEC 0x01 0x03 0x0D 0xE9 0x01 0x03 0x0D 0x29 0x01 0x03 0x0D 0x28 0x01 0x03 0x0D 0x2E 0x01 0x03 0x0D 0xEF 0x02 0x03 0x02 0x52 0x02 0x03 0x02 0x58 0x02 0x03 0x02 0x56 0x01 0x03 0x02 0xDC 0x01 0x03 0x01 0x2C 0x02 0x03 0x01 0x68 0x02 0x03 0x0D 0xD2 0x01 0x03 0x02 0x88 0x01 0x03 0x01 0x93 0x02 0x03 0x01 0x8E 0x02 0x03 0x03 0x2A 0x02 0x03 0x03 0xA6 0x02 0x03 0x03 0x30 0x02 0x03 0x02 0x9C 0x02 0x03 0x01 0x6C 0x01 0x03 0x02 0x9E 0x02 0x03 0x01 0x24 0x02 0x03 0x07 0xE4 0x02 0x03 0x07 0xE6 0x02 0x03 0x07 0xE8 0x02 0x03 0x07 0xEA 0x01 0x03 0x01 0x44 0x01 0x03 0xFF 0xFE 0x01 0x03 0x02 0x72 0x01 0x03 0x0D 0xC8 0x01 0x03 0x0D 0xC9 0x01 0x03 0x01 0x4D 0x01 0x03 0x01 0x48 0x02 0x03 0x01 0x14 0x02 0x03 0x01 0x12 0x02 0x03 0x01 0x80 0x01 0x03 0x0D 0xCBSum 0x24n,n
    QH Config Single SimplifiedQHSIMPLE00x51 0x4A 0x01 0x03 0x0D 0xB1 0x01 0x03 0x0D 0xB0 0x02 0x03 0x02 0x50 0x02 0x03 0x02 0x4E 0x02 0x03 0x02 0x5C 0x02 0x03 0x02 0x60 0x02 0x03 0x02 0x0A 0x02 0x03 0x02 0x0C 0x02 0x03 0x07 0xB4 0x02 0x03 0x07 0xB6 0x02 0x03 0x02 0x06 0x02 0x03 0x02 0x08 0x02 0x03 0x01 0x1C 0x02 0x03 0x01 0x1E 0x02 0x03 0x01 0x16 0x02 0x03 0x0D 0xAE 0x01 0x03 0x02 0x9F 0x01 0x03 0x02 0xBD 0x02 0x03 0x02 0x9A 0x02 0x03 0x0D 0xAA 0x01 0x03 0x0D 0xD0 0x02 0x03 0x01 0x26 0x01 0x03 0x02 0x11 0x02 0x03 0x01 0x8C 0x02 0x03 0x01 0x88 0x01 0x03 0x01 0x2F 0x01 0x03 0x01 0x66 0x02 0x03 0x01 0x5C 0x02 0x03 0x0D 0xB8 0x01 0x03 0x01 0x57 0x01 0x03 0x01 0x6B 0x02 0x03 0x01 0x54 0x01 0x03 0x0D 0xEE 0x01 0x03 0x0D 0xE7 0x01 0x03 0x0D 0x26 0x01 0x03 0x0D 0x27 0x01 0x03 0x0D 0xEC 0x01 0x03 0x0D 0xE9 0x01 0x03 0x0D 0x29 0x01 0x03 0x0D 0x28 0x01 0x03 0x0D 0x2E 0x01 0x03 0x0D 0xEF 0x02 0x03 0x02 0x52 0x02 0x03 0x02 0x58 0x02 0x03 0x02 0x56 0x01 0x03 0x02 0xDC 0x01 0x03 0x01 0x2C 0x02 0x03 0x01 0x68 0x02 0x03 0x0D 0xD2 0x01 0x03 0x02 0x88 0x01 0x03 0x01 0x93 0x02 0x03 0x01 0x8E 0x02 0x03 0x03 0x2A 0x02 0x03 0x03 0xA6 0x02 0x03 0x03 0x30 0x02 0x03 0x02 0x9C 0x02 0x03 0x01 0x6C 0x01 0x03 0x02 0x9E 0x02 0x03 0x01 0x24 0x02 0x03 0x07 0xE4 0x02 0x03 0x07 0xE6 0x02 0x03 0x07 0xE8 0x02 0x03 0x07 0xEA 0x01 0x03 0x01 0x44 0x01 0x03 0xFF 0xFE 0x01 0x03 0x02 0x72 0x01 0x03 0x0D 0xC8 0x01 0x03 0x0D 0xC9 0x01 0x03 0x01 0x4D 0x01 0x03 0x01 0x48 0x02 0x03 0x01 0x14 0x02 0x03 0x01 0x12 0x02 0x03 0x01 0x80 0x01 0x03 0x0D 0xCBSum 0x24n,n
    Passthrough Beginptbegin00x70 0x70Sum 0xE0n,n
    d: Query for packetQUERY00x64None -n,n
    DOLI: Request Onboard StatusREQSTATUS00x44 0x4F 0x4C 0x49Sum 0x28n,n
    VV: Request VersionVER_REQ00x56 0x56None -n,n
    DOCYsendDOCYsend00x44 0x4F 0x43 0x59Sum 0x2Fn,n
    DOCNsendDOCNsend00x44 0x4F 0x43 0x4ESum 0x24n,n
    DOEsendDOEsend00x44 0x4F 0x45Sum 0xD8n,n
    DOLYsendDOLYSEND00x44 0x4F 0x4C 0x59Sum 0x38n,n
    DOLNsendDOLNSEND00x44 0x4F 0x4C 0x4ESum 0x2Dn,n
    DOLysendDOLySEND00x44 0x4F 0x4C 0x79Sum 0x58n,n
    DOLnsendDOLnSEND00x44 0x4F 0x4C 0x6ESum 0x4Dn,n
    DLsendDLSENDThis should set things up to log no ADC, do a 10:1 skip ratio for logging, and no conditional windows. So every 10th frame will get stored.00x44 0x4C 0x00 0x00 0x00 0x00 0x00Sum 0x90Y,Y
    Exit Passthroughexitpass00x45 0x78 0x69None -n,n
    TitleUnique IDDescriptionManually SendableMacros Repeat CountCommandEntry Repeat CountBOF,BOS
    AccelMacroaccelmacroY,Y1Set Accel Param
    Okay Response1
    Initialize SettingsInitY,Y1QH Config Macro
    Configure SL for Payload
    DL: Configure Onboad Logging Structure
    DOCN: Turn Compression Off
    DOLN: Disable Onboard Logging
    DOLn: Disable Background Polling1n,n
    Set Logbut ActiveMacsetlogbutactmaY,Y1Set LogBut Active Startup Inactive
    Okay Response1n,n
    Configure SL for PayloadCONFIGY,Y1Pause for Data Rate
    DR: Configure Packet
    Okay Response1n,n
    Read EEPreadeepmacY,Y1readeepreq
    SL SetupstringSLSTRINGY,Y1SL DS Setup for Patchetc
    Okay Response1n,n
    Passthrough StartptstartY,Y1Passthrough Begin
    Okay Response1n,n
    QH Config MacroqhconfigmacroY,Y1Passthrough Start
    QH Patch Send
    Okay Response
    QH Patch Send 2
    Okay Response
    QH Config Single
    1 Second Pause
    Okay Reponse
    Passthrough End / Version Fetch1n,n
    Passthrough End / Version FetchDISCONY,Y1Pause for Data Rate
    Exit Passthrough
    Bytes for Drain
    PT close lastbyte
    VV: Version Response1n,n
    QH Config Basicqhconfig basicY,Y1QH Config Single
    1 second Pause
    Okay Response
    SL Setup Simple MacroslsetmacsimpleY,Y1SLSetupSimple
    Okay Response1n,n
    ReadTime MacroreadmacY,Y1Read Time Request
    Pass-Patch-ReturnpasspatchY,Y1Passthrough Start
    QH Patch Send
    QH Patch Send 2
    Okay Response
    Passthorugh End / Version Fetch1n,n
    Poll Status MacroPOLLSTATUSY,Y1DOLI: Request Onboard Status
    DOLI: Retrieve Status1n,n
    DOE: Erase DataFlash Onboard MemoryERASE_DFY,Y1DOEsend
    1 Second Pause
    1 Second Pause
    1 Second Pause
    1 Second Pause
    1 Second Pause
    1 Second Pause
    1 Second Pause
    1 Second Pause
    1 Second Pause
    1 Second Pause
    1 Second Pause
    okay Response LongErase1n,n
    Monitor MacroMONITORn,n1Harvest Data Macro
    Poll Status Macro1n,n
    Harvest Data MacroHARVESTY,Y1d: Query for packet
    d: Harvest Packet
    Okay Response
    Pause for Data Rate1n,n
    HarvestBothharvestbothn,n1d: Harvest Packet
    d: Harvest Extras1n,n
    VersionFetchverfetchY,Y1VV: Request Version
    VV: Version Response1n,n
    DOCY: Turn Compression OnCOMPRESS_YY,Y1DOCYsend
    Okay Response1n,n
    DOCN: Turn Compression OffCOMPRESS_NY,Y1DOCNsend
    Okay Response1n,n
    DOLY: Enable Onboard LoggingONBOARD_YY,Y1DOLYsend
    Okay Response1n,n
    DOLN: Disable Onboard LoggingONBOARD_NY,Y1DOLNsend
    Okay Response1n,n
    DOLy: Enable Background PollingPOLLING_yY,Y1DOLysend
    Okay Response1n,n
    DOLn: Disable Background PollingPOLLING_nY,Y1DOLnsend
    Okay Response1n,n
    DL: Configure Onboard Logging StructureCONFIGURE_LOGSY,Y1DLsend
    Okay Response1n,n
    TitleUnique IDDescriptionBaudProcess DataPacket TypeHeaderFooterTimeoutBody SizePayload OffsetPayload Size
    Bytes for DrainDrainbytes0nStatic20303
    d: Harvest PacketPACKET0YStatic4001590159
    d: Harvest Extrasextraharv0YStatic40041041
    DOLI: Retrieve StatusGETSTATUS0YStatic40017017
    VV: Version ResponseVERSION_RESP0nStatic400202
    Okay ResponseOK0YStatic1000101
    Okay Response LongEraseOKLONG0NStatic100000101
    TitleUnique IDDescriptionBaudSilence LengthTimeout
    Pause for Data RateWAITThis timeout mS value can be adjusted to 100 for 10 samples per second.005
    1 Second Pause1SEC00800

    Important Ford Variables

    j1979_01_06SCP Lambse1 byte
    j1979_01_08SCP Lambse2 byte