cassemblyopcode68hc11hi-tech-c

How to fix 68HC11 Compiler from making invalid JMP/BRA codes


I am compiling C code for programming an EPROM for a device. The compiler being used is the Hi-Tech C Compiler. I believe it is version 7.80.

When I (Re-)Make my code, it produces a Binary (*.BIN) file for flashing to the EPROM.

I have found that the compiled code often comes with one single line in the Assembly that breaks the code and causes the device to shut off whenever it is reached. It seems as though the Compiler is changing a Branch-Always (BRA) statement to erroneously do BRA 0, which when converted to hex opcodes gets converted to JMP 0000 by the compiler. This causes the code to reach an unexpected area of the code and thus the device shuts off.

When re-Making the code, this erroneous branch is always in the same place. However I find that if I make small changes to the code, a different BRA call gets this exact same corruption.

I am now at the point where I feel like I need to dig into the *.BIN file itself, find the erroneous BRA/JMP call, and fix it manually. The issue with this is that whenever I make changes to the code and then make a new Binary file, I will need to track down this erroneous BRA/JMP call, calculate what the correct opcodes would be for the BRA call that should be there, and edit it myself. I would much rather not have to do this every time I make a change as this can take up a lot of time.

Here is an example of the erroneous BRA call and the code around it. I am sorry but I cannot provide the full source code for this as it is for a proprietary system but I can share the Assembly and hex codes around the issue.

Equivalent C code with added note on where the erroneous BRA/JMP is happening:

if ( variable > 5.5 )
{
    printf( "Variable is: %f", variable );
    // right here is where the BRA 0 is in the Assembly (JMP 0000 in hex). It should be branching to function_call() below, but it is not
}
else
{
    if ( variable < 5.4 )
    {
        // bunch of code in here
    }
    else
    {
        // if/else in here with some printf() calls
    }
}

function_call();

This is from the compiled *.AS assembly file:

    tsy
    ldx 3,y
    pshx
    ldx 1,y
    pshx
    ldx #u189
    bra 0

The above bra 0 assembly is invalid. In this particular case as per the labels within the Assembly file, it should be bra l28 (note, this is L28, with a lower-case L, to avoid confusion. It is a label that is defined lower in the Assembly code, where this branch should be going to).

This results in the following hexadecimal opcode:

18 30 CD EE 03 3C CD EE 01 3C CE F6 DD 7E 00 00 

The following excerpt is from the *.LST Listing file.

 758    03E0' 18 30                 tsy
 759    03E2' CD EE 03              ldx 3,y
 760    03E5' 3C                    pshx
 761    03E6' CD EE 01              ldx 1,y
 762    03E9' 3C                    pshx
 763    03EA' CE 005D'              ldx #u189
 764    03ED' 7E 0000               bra 0

As can be seen, it converts the bra 0 to JMP 0000 (7E 0000).

I would like to find a solution that will definitively resolve this situation such that the compiler will no longer corrupt a random BRA mnemonic within the assembly that does not require me to dig through the binary file, find the JMP call, and manually fix it every time I change the code.

To clarify, I understand that BRA 0 is not the same as JMP 0000, however the Compiler is for unknown reasons (1) putting BRA 0 in the Assembly file instead of BRA l28 which is what it should be, and (2) converting this to JMP 0000 when creating the binary file.


Solution

  • Unfortunately at this stage the only solution I have found has been a workaround to manually edit and fix the Assembly rather than a definitive fix that stops the issue from happening in the first place.

    Here are the steps that I took to manually work around the issue.

    1. Re-Make the code. This will compile new OBJ files and link them to create the Binary (*.BIN) file
    2. Open the resulting Binary file (*.BIN) within some form of Hex Editor (I use HxD)
    3. Search for the following hexadecimal values: 7E0000. 0x7E is the opcode for JMP to an absolute address in 68HC11. If found, continue on. If not found, the code should be fine
    4. Open each Code file (*.C) and compile them out to Assembly (*.AS) files and optionally Listing (*.LST) files
    5. Search through each Assembly (or Listing) file to find BRA 0 (note that the whitespace there is a tab character). Once found, continue
    6. Determine the correct label that this line of Assembly should be branching to. This step can be quite difficult and I was using the wrong label at first.
    7. Open the Assembly file with the erroneous BRA 0 in it and change it to branch to the correct label, i.e. BRA L8
    8. With the Assembly file still open, compile it into an Object (*.OBJ) file. This will use the updated (and hopefully correct) branch label
    9. Make the code. Do not re-make. This will pick up that only the new Object file has changed and it will use it to create a new Binary file. This time it will not have the erroneous JMP0000
    10. Optionally (but recommended) check the resulting Binary (*.BIN) file to ensure that it no longer has the hexadecimal values 7E0000