3
\$\begingroup\$

I'm trying to jump to a specific address in HI-TECH compiler and the address is given dynamically.

I tried using asm() function but it looks like the argument must be a constant char[]. Is there another solution to jump to an address using goto or another function like goto_address(address) in CCS Compiler?

I tried this:

long address = 0xA20;
char addr[15];
sprintf(addr, "goto %s", address)
asm(addr); // Here argument error.

Thanks.

\$\endgroup\$
5
  • \$\begingroup\$ I'm curious to know which compiler would consider that valid syntax. \$\endgroup\$ Commented Oct 31, 2014 at 15:24
  • \$\begingroup\$ Have you tried to change the program counter register? \$\endgroup\$ Commented Oct 31, 2014 at 15:29
  • \$\begingroup\$ Hello @Bruno Ferreira. No, and I don't know how do it. May you help me? Thanks. \$\endgroup\$
    – 788498
    Commented Oct 31, 2014 at 15:32
  • \$\begingroup\$ What microcontroller are you using? \$\endgroup\$ Commented Oct 31, 2014 at 15:33
  • \$\begingroup\$ PIC 18F4550 in HI-TECH c compiler. \$\endgroup\$
    – 788498
    Commented Oct 31, 2014 at 15:36

4 Answers 4

3
\$\begingroup\$

This is the kind of thing most easily done in assembler.

If you need to do this regularly, you can create a assembler subroutine that follows the C subroutine linkage conventions. This would take a 24 bit argument that is the address to jump to. Remember to have the subroutine pop its own return address from the stack before doing the jump. The subroutine would write bits 23:16 of the address to PCLATU, bits 15:8 to PCLATH, and then bits 7:0 to PCL. That last instruction will actually do the jump, so everything else needs to be set up properly before the write to PCL.

\$\endgroup\$
2
  • \$\begingroup\$ Hello @Olin-Lathrop. What could be the difference using TOS registry? Thank you. \$\endgroup\$
    – 788498
    Commented Nov 5, 2014 at 5:29
  • \$\begingroup\$ I have no idea that a "TOS registry" is supposed to be. \$\endgroup\$ Commented Nov 5, 2014 at 13:33
2
\$\begingroup\$

The asm() directive you're trying to use is supposed to be used to 'embed' a single, properly formatted, assembler instruction - written as a C-style string of characters.

In other words, something like asm(" BCF 0,3" );

The compiler looks at that string during compile time and inserts that exact assembler instruction into your code - that's why its asking you for a constant char[] - it has to be a correctly formatted constant string when your code is compiled. So what you're trying to do by building the string with sprintf during execution can't ever work.

In addition, if you look at the description of the GOTO assembler instruction for your PIC, you'll see that it takes a constant fixed value as the address to jump to. The address forms a part of the instruction at compile time and you can't change it on-the-fly during execution.

What you're trying to do might be better served using function pointers. See C coding design - function pointers? . But you'll need to be careful about managing & not mangling the stack.

\$\endgroup\$
2
\$\begingroup\$

You are very confused between what happens at compile time vs. what happens at run time. The argument to asm() must be a string that is fully specified at compile time. If the address value is only known at run time, then you need to come up with a sequence of instructions that can take a run-time value and copy it to the PC.

One of the most direct ways to do this on most architectures — and I believe this will work on PIC18 — is to PUSH the address value onto the return stack and then execute a RETURN instruction.

\$\endgroup\$
6
  • 1
    \$\begingroup\$ A simple GOTO instruction should be enough. But your solution (as well as mine) also implies the problem of passing the address value to inline assembly. \$\endgroup\$
    – Dzarda
    Commented Oct 31, 2014 at 16:01
  • 1
    \$\begingroup\$ @Dzarda: No, the PIC18 GOTO requires that the address be known at compile time. Passing a run-time value from regular C code to asm() code (and back again) is covered in the documentation. \$\endgroup\$
    – Dave Tweed
    Commented Oct 31, 2014 at 16:05
  • \$\begingroup\$ Are you sure about GOTO being a compile-time construct? According to the documentation, it is a normal two-word instruction, with its own encoding, etc. (see here technology.niagarac.on.ca/staff/mboldin/18F_Instruction_Set/…) \$\endgroup\$
    – Dzarda
    Commented Oct 31, 2014 at 16:13
  • 1
    \$\begingroup\$ Creating a call stack location, writing a address to it, then executing RETURN will work on a PIC 18, but it's not the preferred way. The best way on a PIC 18 is to write the address to PCLATU:PCLATH:PCL. Make sure to write PCL last, as that actually causes the jump. PCLATU and PCLATH need to be set properly before PCL is written. \$\endgroup\$ Commented Oct 31, 2014 at 16:35
  • 2
    \$\begingroup\$ @Dzarda: Read the datasheet, in particular the GOTO instruction description. The address that GOTO goes to is encoded into the instruction itself. This is not something that can be changed reasonably at run time. (You can actually write to program memory at run time, but this is a slow process, can only be done a limited number of times, and requires erasing a larger block of memory than just the two instruction words of the GOTO. This is really not how you want to jump to a dynamically determined address.) \$\endgroup\$ Commented Oct 31, 2014 at 16:42
2
\$\begingroup\$

In order to do a computed goto you can change the program counter.

On the PIC18F4550 the program counter is composed of 3 registers, PCU (bits 20:16), PCH (bits 15:8) and PCL (bits 7:0).

Only the PCL can be written directly. In order to change the value off all the registers simultaneously you have to write to the PCLATU, PCLATH and PCL registers as explained on the section 5.1.1 of the datasheet.

First you should write the most significant bits to PCLATU and PCLATH, then you write the least significant bits to the PCL, this also copies the PCLATU and PCLATH to PCU and PCH respectively.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.