0

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.

Deluril
  • 13
  • 1
  • 5
  • What C instruction generates the assembly code? (Feel free to change names etc - it won't make any difference). Also, were there any warnings raised around that area? It looks like the compiler might not have fixed up the generated code for some reason. Is there any way you can "re-phrase" the instruction to go through a different route? – Mike Jun 18 '19 at 07:10
  • That is very strange, because `BRA 0` is not all the same as `JMP 0000`. The first is an unconditional branch relative to the program counter, and `BRA 0` should have *no effect* since the displacement is `0`. The second is an absolute jump to address `0000`. It's unclear why you think the branch should be the minimum possible (`128` which is in effect `-128`). – Weather Vane Jun 18 '19 at 07:14
  • @Mike The C code around it is a simple if/else statement. I'll edit in equivalent code. No warnings were made at all that I can see, the compiler just made the code and said done. Could you elaborate on what you mean by "re-phrase" the instruction? I have tried to make small edits to the code to try to get it to take a different path, but the "bra 0" then appears elsewhere. – Deluril Jun 18 '19 at 07:23
  • @WeatherVane I understand that `BRA 0` is different to `JMP 0000`, but the compiler is making that conversion for an unknown reason. I did some manual calculation and it should be more along the lines of `BRA 113` (0x71). – Deluril Jun 18 '19 at 07:26
  • @WeatherVane It took me a while to figure out your comment my supposedly stating that the branch should be going to 128. It is actually L28 (with a lower-case L), which is a defined label lower within the Assembly file. My apologies for the confusion, it's just how it is presented to me in the Assembly file. (I've added clarification on this to my question). – Deluril Jun 18 '19 at 07:45
  • 1
    I don't know why a two-byte instruction should be converted into a three-byte one. One possibility for the `JMP 0000` is that it awaits a linker fix-up from a separate table. – Weather Vane Jun 18 '19 at 08:00
  • @WeatherVane Would there be some form of option I might be missing within the Make process that might get it to do the fix-up, if that might be the case? At the least I have the options to "Re-link" the project and also to edit the Linker options. Would it be beneficial for me to share the Linker options within my question? I've not asked a question like this before so I am unsure what all information to include and what could be relevant to this issue, as it's an odd one that's puzzled me for some time. – Deluril Jun 18 '19 at 08:12
  • I've not used the Hi-Tech tool chain for a very long time. – Weather Vane Jun 18 '19 at 08:35
  • 2
    Hang on. Bra 0 is not the same as JMP 0. Branches are relative to the current position so Bra 0 is equivalent to JMP *+0 - 0 bytes from the current PC position. Bra 0 is usually an un-optimised placeholder for an unused else condition. – Mike Jun 18 '19 at 08:46
  • 3
    This looks a bit like you took an object file and flashed it onto your device instead of first linking it to resolve all these references. – fuz Jun 18 '19 at 09:51
  • @Mike Yeah, hence my confusion. 1: `BRA 0` shouldn't be getting used to begin with. 2: `BRA 0` mnemonic should not be getting resolved to `JMP 0000` opcode. As for an unused else condition, this is a jump directly after finishing code within an if-check as per my example above that I edited in, so I'm confused as to why this is happening. I'll try playing with the optimisation settings since you mentioned it, will edit in results into the question tomorrow. @fuz I can confirm that I am flashing the *.BIN file it makes after compiling & linking. I don't think I can flash an object file to this. – Deluril Jun 18 '19 at 12:47
  • What are you make steps? With GNU tools failing to link the the code would result in wrong branch targets, does that also apply to Hi-Tech? – Timothy Baldwin Jun 18 '19 at 16:04
  • 1
    $7E is the opcode for JMP (2 byte, absolute) so I guess whatever generated the code renamed the opcode to BRA. Misleading but okay, I suppose. The JMP should be there to go to the end of the outer condition but it looks like it's a bug in the compiler which forgot to fix up the destination address. Is there a newer version of the compiler or an alternative compiler you could try? – Mike Jun 18 '19 at 17:55
  • I've got a _workaround_ for now where the compiler can give me a valid file. But it's not a solution that resolves _why_ the Compiler is doing what it is doing to fix it. 1: Re-Make the code, 2: Open Guilty.c file, 3: Compile into *.AS file, 4: Open *.AS file, 5: Change `BRA 0` to use correct label (turns out it was `L8` it should `BRA` to), 6: Save file, 7: Compile *.AS file into *.OBJ file, 8: "Make" code. It will pick up the updated *.OBJ file and use that to make the code. This results in the final code not having the bad JMP. Unsure if this counts as an answer as there is still an issue? – Deluril Jun 19 '19 at 05:36
  • @Mike I've tried to find one in the past to no success. Hi-Tech now only does Compilers for MicroChip products. If anyone has recommendations on a different 68HC11 compiler I could use, I'm all ears. – Deluril Jun 19 '19 at 05:38
  • I've not used it but the Gnu compilers tend to be pretty well debugged. (https://www.gnu.org/software/m68hc11/). Since you know where the bug occurs, you could just try compiling to assembler to see if it still produces bad code. – Mike Jun 19 '19 at 06:16
  • @Mike Unfortunately it looks like the site you linked still exists but the Installer files etc are no longer available there. I might see if I can source them elsewhere. I have actually previously looked at that exact site in the past (about a year ago) and ran into this problem before, but I'll try it again. – Deluril Jun 19 '19 at 07:55

1 Answers1

0

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
Deluril
  • 13
  • 1
  • 5