Jump to content
John P

Can't Use Computed Goto

Recommended Posts

I'm going to call this a bug, although it doesn't exactly cause failure.

 

BoostC disdains to create a Switch-Case setup by manipulating the program counter. Instead it forces a long list of compare operations, which gets time-consuming if one of the last cases tests true. So I tried to write my own version, like this (I'm only showing the first 3 cases):

 

i = packet_out_count++;
pcl += i;
asm { // Jump table must fit within 256 byte block of addresses
goto POC0;
goto POC1;
goto POC2;
goto POC3;
goto POC4;
goto POC5;
goto POC6;
goto POC7;
goto POC8; // Send checksum
goto POC9; // Wait till complete, then release bus
return;
return; // P_O_C shouldn't have values 10-15
return;
return;
return;
return;
goto POC0; // Start packet
goto POC0x11;
goto POC2; // Send ID
goto POC0x13;
goto POC0x14;
goto POC0x15;
goto POC0x16;
goto POC0x17;
goto POC0x18;
goto POC0x19;
goto POC8; // Send checksum
}


POC0:
txreg = 0xFF;
return;
POC1:
txreg = cs = NORMAL;
return;
POC2:
txreg = MY_ID;
cs += MY_ID;
return;
POC3:
txreg = 4;
cs += 4;
return;

 

Apparently this only works if the list of GOTOs is in an asm{} construction, because otherwise the compiler assumes that only the first GOTO is accessible, and won't produce code for any of the others. In the asm{} setup, the code is generated, but then when the individual cases are reached, they produce highly inefficient code, like this (from the Disassembly Listing):

 

278:               POC0:
279: txreg = 0xFF;
064 30FF MOVLW 0xff
065 0099 MOVWF 0x19
280: return;
281: POC1:
282: txreg = cs = NORMAL;
067 3015 MOVLW 0x15
068 1283 BCF 0x3, 0x5
069 1303 BCF 0x3, 0x6
06A 00CB MOVWF 0x4b
06B 1283 BCF 0x3, 0x5
06C 1303 BCF 0x3, 0x6
06D 0099 MOVWF 0x19
283: return;
284: POC2:
285: txreg = MY_ID;
06F 30F6 MOVLW 0xf6
070 1283 BCF 0x3, 0x5
071 1303 BCF 0x3, 0x6
072 0099 MOVWF 0x19
286: cs += MY_ID;
073 30F6 MOVLW 0xf6
074 1283 BCF 0x3, 0x5
075 1303 BCF 0x3, 0x6
076 07CB ADDWF 0x4b, F
287: return;

 

You can see that there is a lot of totally unnecessary clearing of bits of the status register, every time a variable is used. It looks to me as if the compiler is punishing me for trying to use a work-around for something it didn't want to do! Surely this isn't intentional.

Share this post


Link to post
Share on other sites

John P,

 

I'm not seeing the problem.

Can you provide a complete compilable piece of code for a specific target device that can be compiled to demonstrate the problem?

 

Regards

Dave

Share this post


Link to post
Share on other sites

OK, thank you for taking an interest. Here is the routine in which I'm having the problem, and a 1-line main() function which calls this routine and does nothing else. Please understand that this version is made to compile but not run! It's for the PIC16F690 and I have version 7.20 of the compiler.

 

What I'm seeing is first, if the asm{} construction isn't used with my list of GOTOs, they don't compile. If I do use asm{}, it compiles but it's very inefficient in terms of the amount of code produced, and time to execute. What I think is wrong is that the number of sequences of BCF 0x3, 0x5 and BCF 0x3, 0x6 is hugely excessive--it seems to happen before any variable is accessed. Surely the compiler could be made to figure out which bank is in use so it wouldn't need to keep selecting bank 0!

 

If you want some background, what this routine does is send a data packet over a UART. It's a state machine which steps through the packet and sends a byte (or at the end, turns off the line driver) via a function call for each successive state, incrementing a counter each time. There are two packet types, and they're selected by starting the routine with the counter having the value 0 or 0x10. I don't like BoostC's way of implementing a Switch-Case construction, as that takes a highly variable amount of time to execute--less for the small numbers and more for the larger ones. I'd rather have the option to create a true computed GOTO, and if necessary I'll take the responsibility to make sure that the jump table stays in the same block of ROM.

 

 

#include   // device dependent interrupt definitions
// Processor is PIC16F690

#define bit_set set_bit
#define bit_clear clear_bit
#define bit_test test_bit

#define RESET_POWER 1
#define MY_ID 246
#define GOT_STATUSREQ 243
#define NORMAL 0x15 // Normal is 0x15 for a cab driver
#define PACKET_START 0xFF
#define C_D_TYPE 3

typedef unsigned char byte;

byte button10, pot10, button11, pot11; // Used in send_to_server()
byte packet_out_count;
byte cs, outgoing;
byte uptime[4];

/****************************************************************************
Sending data to server
****************************************************************************/
void send_to_server(void)
{
byte i;

if (bit_test(packet_out_count, 7)) // 0xFF has appeared as data, send second time
{
txreg = PACKET_START;
bit_clear(packet_out_count, 7);
return;
}

if (packet_out_count > 0x1A)
goto POC10; // Illegal count, cancel any packet in progress

i = packet_out_count++;
pcl += i;
asm { // Jump table must fit within 256 byte block of addresses
goto POC0;
goto POC1;
goto POC2;
goto POC3;
goto POC4;
goto POC5;
goto POC6;
goto POC7;
goto POC8; // Send checksum
goto POC9; // Wait till complete, then release bus
goto POC10;
goto POC10;
goto POC10; // P_O_C shouldn't have values 11-15
goto POC10;
goto POC10;
goto POC10;
goto POC0x10; // Start packet
goto POC0x11;
goto POC2; // Send ID
goto POC0x13;
goto POC0x14;
goto POC0x15;
goto POC0x16;
goto POC0x17;
goto POC0x18;
goto POC0x19;
goto POC8; // Send checksum
}

POC0:
txreg = PACKET_START;
return;
POC1:
txreg = cs = NORMAL;
return;
POC2:
txreg = MY_ID;
cs += MY_ID;
return;
POC3:
txreg = 4;
cs += 4;
return;
POC4:
txreg = pot10;
cs += pot10;
outgoing = (10 << 4) + button10; // Ensures that changes don't occur between bytes being sent
bit_clear(pot10, 7);
button10 = 0;
return;
POC5:
txreg = outgoing;
cs += outgoing;
return;
POC6:
txreg = pot11;
cs += pot11;
bit_clear(pot11, 7);
outgoing = (11 << 4) + button11;
button11 = 1;
return;
POC7:
txreg = outgoing;
cs += outgoing;
return;
POC8:
if (cs == PACKET_START)
cs--; // Send 0xFE instead of 0xFF
txreg = cs;
return;
POC9:
if (!bit_test(txsta, TRMT)) // Has last byte completed transmission?
packet_out_count--; // No, make sure we keep looking
return;
POC10:
bit_clear(portc, 2); // Release bus to server (portc.2)
bit_set(trisc, 3); // Release clamp TX line to USB converter
return;

POC0x10:
txreg = 0xFF;
return;
POC0x11: // Cases 0x10 and up are for status request
txreg = cs = GOT_STATUSREQ;
return;
POC0x13:
txreg = 6;
cs += 6;
return;
POC0x14:
cs += C_D_TYPE;
txreg = C_D_TYPE;
return;
POC0x15:
cs += uptime[0];
txreg = uptime[0];
if (uptime[0] == PACKET_START)
bit_set(packet_out_count, 7);
return;
POC0x16:
cs += uptime[1];
txreg = uptime[1];
if (uptime[1] == PACKET_START)
bit_set(packet_out_count, 7);
return;
POC0x17:
cs += uptime[2];
txreg = uptime[2];
if (uptime[2] == PACKET_START)
bit_set(packet_out_count, 7);
return;
POC0x18:
cs += uptime[3];
txreg = uptime[3];
if (uptime[3] == PACKET_START)
bit_set(packet_out_count, 7);
return;
POC0x19:
cs += RESET_POWER; // Not fooling with any other kind of reset
txreg = RESET_POWER;
return;

}

main()
{
send_to_server();
}

Share this post


Link to post
Share on other sites

Join the conversation

You are posting as a guest. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...

×
×
  • Create New...