First Generation DSM EPROM Editing

Last Update: 1/15/05



General Notes

Rev Limiter

Idle Speed (target)

Fuel Cut

Injector Size Compensation (Global)

Injector Deadtime

MAF Compensation

Open-Loop Fuel Map

Timing Map

Extended Fuel and Timing Maps

Simple Stutterbox

"Octane" Reset

Closed Loop Range

Double MAF Hz Logging

IPW Cap Removal

General Notes

This page in intended to be a guide so that all of the current information about the DSM EPROM can be presented in a clear manner such that anyone who wishes can do their own rom editing.  The majority of this information comes from the findings of the DSM-ECU list, which can be found at

Before you begin, read through these general notes to get an idea for what is happening, and what you need to do in order to have desirable results.

The 1g DSM EPROM ECU uses a 28 pin EPROM and a processor based on the Motorola 68HC11, but with additional opcodes.  As such, there is no program that can fully disassemble the entire code.  Important sections have been done, but since everything has to be looked over and edited the process is very tedious.

All of the information and addresses below are based on the E931 EPROM, which comes in the 91+ turbo manual transmission cars.  A lot of the code and the general information may still apply to other variations, but there are no guarantees.

The code will be on a 32k chip, with approximately the first half of it blank.  This is the proper way to burn a chip, and as such the addresses will apply to that setup.  These addresses apply if you load the memory into a hex editor; keep in mind that for the processor, the EPROM chip begins at C000 and ends at FFFF.

Need to contact me?  Click here to send me an e-mail

return to top


Rev Limiter

Address: 727A

The processor compares (CPX) the value stored at this address to the current engine speed, in order to determine whether or not to cut the fuel and spark.  If we want to raise the rev limiter, we will lower the value at this address according to the following formula:

Rev Limit = 3750000 / X

Such that X is the decimal value of the two bytes at 727A and 727B.

7000 0218

7500 01F4

7600 01ED

7800 01E1

8000 01D5

8200 01C9

8500 01B9

The code in the area of the rev limiter will look as follows:

01 45 8C 01 F4 24 05 03

return to top


Idle Speed

Address: 7EC0-7EC1

The base idle speed is contained within a map found at the addresses 7EC0 and 7EC1.  The idle speed at operating temperature is:

Idle Speed = X * 8

Such that X is the decimal value of each of the two bytes (they will be the same).

750 5F

768 60

775 61

800 64

850 6A

900 70

950 - 77

The code in that area will look as follows:

08 0A 0C 60 60 80 93 A3 B3 C0 D3

Note that since GVR-4's have a higher base idle speed, they will have the two "60" bytes replaced with "66."

return to top


Fuel Cut

Address: 559A

Fuel cut is initiated when the calculated airflow goes over a set value, which is set at the address 559A.  By increasing this to the maximum value possible (FF) fuel cut will be pushed off.

Another, possibly better, solution is to change the code in that area so that the ECU doesn't cut fuel regardless of the status of the airflow.  This can be done by changing the "24" at 559B (which is a BCC code, or a branch when the airflow is greater than the value of 559A) to "21," which is a simple branch never code.

The code in the area looks like this:

02 D6 57 C1 A0 24 05 C6 28

return to top


Injector Size Compensation

Address: 599F

The injector compensation is a global fuel control value located in the one byte at 599F.  It works simply by correcting the injector pulsewidth for whatever size injectors the ECU is programmed for; this is a linear multiplier.  In order to reduce the pulsewidth for larger injectors, you want to reduce this location.  If you double the injectors size, you cut this in half, etc.

Here are some sample settings:

Size - Decimal - Hex

450 74d 4A

510 65d 41

550 61d 3D

600 56d 38

650 51d 33

660 50d - 32

700 48d 30

750 44d 2C

800 42d 2A

850 39d 27

The code around the compensation byte looks like this:

05 05 05 05 DD 5C C6 4A BD EB 6A FD

This code is from the E931 ECU, but it seems as though other ECU's (Mirage, JDM) have a very similar structure.

return to top


Fuel Injector Deadtime

Address: 7CE7 - 7CED

The injector deadtime map compares the deadtime of the fuel injectors to the battery voltage.  The first byte of the map is 4.7 volts, the second point is 7.0 volts, then 9.34v, 11.68v, 14.0v, 16.35v, and 18.7v.  The decimal value of each byte refers to the deadtime of the injectors, divided by 24 microseconds.

The stock map is "A9 58 30 23 1B 17 13"

If you wanted to add 200 microseconds of deadtime, you would add 8 to each of the values on the map, since 200 / 24 = 8.

For 550's, you want about 150-175 us more deadtime.  660's will be above 200, usually around 225 or 250.  However, these settings will vary from car to car, and between different types of injectors.

return to top


MAF Compensation

Address: 7B6E - 7B82

The MAF compensation map is what the ECU refers to in order to correct the airflow signal coming in from the mass airflow meter.  This code also allows you to install a 2g MAF and have the ECU compensate for it properly, or to compensate for hacked MAFs, or aftermarket MAFs that do not have quite the same airflow curve as the stocker.

The stock MAS compensation code is:

5B 5B 59 59 60 65 6C 6E 6E 6F 73 76 7A 81 82 84 87 85 7F 7A 7F

This will vary if the car is a GVR-4, for example, because they have a slightly different MAF.

The MAF compensation code is essential a correction map, based on airflow.  The airflow (Hz) points for each of the values are as follows:

0, 25, 50, 75, 100, 125, 150, 175, 200, 225, 250, 275, 300, 400, 500, 600, 800, 1000, 1200, 1400, 1600.

So, for example, if you wanted to increase the airflow signal from zero to 75Hz input by 20%, you would increase the first 4 values in the map by 20%.


Since one of the most popular changes is from a 1g MAF to a 2g MAF, this is how you want to change the code:

First, the map needs to be changed to:

85 85 A8 B6 BE C3 C8 CC D0 D4 D7 DA DC E3 E6 E8 EB EA EA E8 E7

NEXT, you need to change another byte the serves as a multiplier.  This byte is located at the address 5669, and the stock value at this point is "64" hex.  For a 2g MAS, change that to "40" hex.

In addition, in order to make sure the timing and fuel maps still line up, you need to change the value at 549A from "5E86" (1g) or "62B9" (GVR-4), to the 2g value which is "7A03."

return to top


Fuel Map

Address: 7C3F - 7CE6

The fuel map at the above address is a fuel enrichment for open-loop operation.  When you go into open loop, the ECU goes to the table and finds the correct value based on engine speed and load (airflow / rev).  Then, it multiplies the pulsewidth by the value in that box, and then divides by 80h (128 decimal).  As such, if the value in the box is 80h, then there will be no fuel compensation and the A/F ratio will still be 14.7:1.  If the value in the box is FF (256 decimal) then the overall multiplier will be 2 (256/128) and there will be twice as much fuel, for an A/F ratio of 7.35:1.

The rpm axis on the fuel map begins at 500 rpm, and increases in 500 rpm increments to 7000 rpm (500, 1000, 1500, 2000, 2500, 3000, 3500, 4000, 4500, 5000, 5500, 6000, 6500, 7000).

The load points are the same as listed below for the timing map.

return to top


Timing Map

Address: 7D48 - 7E07

The timing map is broken down into 12 airflow levels, and 16 rpm breakpoints.  The first byte, 7D48, is the lowest airflow level at 750 rpm, and the next byte is the lowest airflow level at 1000 rpm, and so on and so fourth.  The engine speed values for the map are as follows:

750, 1000, 1250, 1500, 1750, 2000, 2500, 3000, 3500, 4000, 4500, 5000, 5500, 6000, 6500, 7000.

The other "axis" of the timing map is load, based on airflow per engine revolution.  In stock form, this goes up to 2.06 grams of airflow per engine revolution, but the slope is not exactly linear.  The values of the load axis are as follows:

0.25, 0.38, 0.50, 0.63, 0.75, 0.94, 1.13, 1.50, 1.69, 1.88, 2.06.

The value of each byte is simply the timing advance (total timing assuming base is 5 degrees BTDC) plus 10 decimal, converted to hex.  Thus, to convert from the ECU code to advance, you convert to decimal and then subtract 10.

return to top


Extended Timing and Fuel Maps

A solution has been devised, which will allows anyone with a 1g EPROM ECU to run timing and fuel maps that have twice the load range than the stock maps; the stock maps are easily maxxed out at around 15 psi of boost, meaning that car running more than that are running on the highest airflow level all of the time.

This modification is actually fairly easy, but due to the fact that it requires full replacement of the maps (the replacement maps are included), a separate guide has been written to make this possible.  You can reach this guide here.


return to top


Simple Stutterbox

For a simple stutterbox, you can use the following code.  This code will jump from the stock rev limiter to an unused part of the chip, where it will then check to see if the car is moving.  If the car is stopped, you get a stutterbox, and if the car is moving then you get the regular rev limiter.  This means you do not need a clutch switch.

At the stock rev limiter location (7279), you replace the three bytes that were "8C 01 F4" with "BD CF 50."  Then, you go up to the line that starts with 4F50, and add the following code:

"96 C6 81 75 22 04 8C 01 F4 39 8C 02 EE 39"

This is how the code works:

7279: BD CF50  JSR 4F50; Instead of stock rev limiter CPX, jump to 4F50


4F50: 96 C6  LDAA L00C6; Load speed sensor to accumulator A

4F52: 81 75   CMPA $0075; Compare speed sensor to 75h (check if car is moving)

4F54: 22 04   BHI 4F5A; If car is stopped, skip next instruction (go to 4F5A)

4F56: 8C 01F4  CPX $01F4; 7500 rpm rev limiter

4F59: 39        RTS;    If car is NOT stopped (moving), go back to stock code, no stutter

4F5A: 8C 02EE  CPX $02EE; 5000 rpm stutter if car is stopped

4F5D: 39       RTS; Return to 4F59, which returns to stock code

return to top


Stutterbox with No Lift to Shift (NLTS)

Instead of using the simple stutterbox code above, you can use slightly more complex code in order to have both stutterbox and no lift to shift.

You will use the same values at 7279 as above, but just for clarity:

7279: BD CF50  JSR 4F50; Instead of stock rev limiter CPX, jump to 4F50

Then, at 4F50, you will want to use the following code:

4F50	96 C6	   LCAA	L00C6	; load speed sensor into accum. A
4F52	81 75	   CMPA	$0075	; test if car is moving
4F54	23 04	   BLS		; if car is moving skip next 4
4F56	8C 03 A9	   CPX  $02EE	; car is stopped launch stutter (5000 rpm)
4F59	39	   RTS		; return from subroutine
4F5A	96 06	   LDAA	L0006	; load clutch bit into accum. A 
4F5C	85 20	   BITA	$0020	; accumulate with 0020h
4F5E	27 04	   BEQ		; if clutch is in go to NLTS
4F60	8C 01 F4         CPX  $01F4	; clutch is up stock rev limiter
4F63	39	   RTS		; return from subroutine
4F64	8C 02 AA	   CPX  $02AA                 ; NLTS stutter RPM (5500 rpm)
4F67	39	   RTS		; return from subroutine	
Note that you can change the stutter, NLTS, and rev limiter speeds, using the formula found in the rev limiter section (here).
Thanks to Dan Loncher to helping to develop and test this code.

return to top


Octane Map Set & Skip

The stock code contains a feature which has been nicknamed the "octane value."  Basically, the if the ECU sees a knock sum over 5, it reduces the maximum amount of timing advance you can have.  It saves this in long term memory, and it can only go away of you have less than 3 knock sum, in which case it will taper away slowly.

If you use good gas and keep track of what it happening with the car, then there is no reason to keep this feature.  It is mainly designed as a protection against something happening to the car (such as using 87 octane fuel, or something breaking) so that the ECU can reduce the timing level to help keep stuff from blowing up.  All TMO chips set the octane to the maximum possible each time you started the car, this code just goes a step beyond that and gives you maximum octane all the time.

The octane corrections start at address 5B9D.  Starting with this byte, use the following code:

"86 FF 97 52 7E DB F3"

The code works as follows:

5B9D: 86 FF   LDAA $00FF; Load 255d (max) to A

5B9F: 97 52    STAA L0052; Store 255d (FFh) to octane (mem address 52)

5BA1: 7E DBF3  JMP DBF3; Jump to DBF3 (skip octane calculations, go to timing start)

Note that this renders the rest of the code between 5BA4 and 5BF3 useless; you can use it for other features if you wish.

UPDATE:  Jeff B. on DSM-ECU uses the following simple method to update the octane (to 255, the max) on every start:

    "Just change the byte at $D0B5 from $2C to $28. This bumps the
    warmboot address back 4 bytes to $D0DE which resets the octane byte
    to 255 during a coldboot. now it will reset octane on a cold or warm

If you don't want to mess around with the timing code, this is a better option.


return to top


High Speed Closed Loop

Address: 7BDC - 7BDD, 7BE6-7BE7

There addresses refer to the last two bytes on two seperate 10 byte maps.  The first map is a map of airflow per rev values, in 500 rpm intervals.  As such, the last two values (4500 and 5000 rpm) have a value of zero, and the ECU will go into open loop at that point.  By changing the cutoff point (raising it), you can have the car stay in closed loop.

The second map is throttle position, in the same 500 rpm intervals.

It has been suggested (Jeff O.) that you not only raise the two last bytes from zero, but that you also increase the last value on the stock map so that it is higher like the rest of the values.

Update: If you want to know the values in the map, the formulas to calculate them are really easy.

For the throttle position, the value in the map can be converted to decimal, and then divided by 255.  For example, if the map value is 80, that converts to 128 decimal, which divided by 255 is 0.50.  That means that 80h is equal to 50% throttle.

The airflow per rev map can be converted to grams of airflow per engine revolution, by converting the values to decimal and then dividing by 128.  For example, a map value of "A0" converts to 160 decimal, which when divided by 128 is equal to 1.25.  Therefore, A0 in the map is equal to 1.25 grams of airflow per engine revolution.


return to top


Increased MAF Hz Logging Range

As you all know, the 1g datalogger is limited to being able to see only 1606 MAF Hz; this is not due to a limitation of the MAF or of the ECU, but simply a limitation due to the amount of data that the ECU can transfer to the logger.

There is a small amount of code that can be changed slightly, so that you can datalog up to 3212 Hz (double the stock range).  If this is done, there are modified versions of the MMCd datalogging program that support this option, or you can just mentally multiply the airflow on your normal logger by 2 to see the true value.

Two bytes need to be changed for this to work correctly.  First, at 53DA, there is a byte with the value "B4."  If you change that value to "B3," the airflow will be divided in half before it is sent to the logger, doubling your logging range.

Second of all, you need to change the "low airflow check" code at 732A from "08" to "04," to reflect the fact that the airflow is now half of what it used to be.

So, "B3" is stored at 53DA, and "04" is stored at 732A.


return to top

Removal of Airflow Per Rev / IPW Cap

For reasons unbeknownst to me, the stock ECU code contains a segment which caps the airflow per rev (and therefore the injector pulsewidth).  This section seems to have no purpose, so ECU tuners have been eliminating it

The code responsible for this is located from 73A6 to 73B5, and can simply be No-op'd.  In order words, replace all of the bytes from 73A6 to 73B5 with the hex value "01."

For reference, these values are as follows:

D6 A0 4F 05 05 05 87 A2 11 04 1D 8D 24 02 DD 8D


return to top