Say I have a value from a sensor 1-20. I would like to do a fast direct jump to one of 20 subroutines or functions (selected by the sensor value) without having to test my way trough a long list of if-then or select case.
(At this time I am looking for a way to select one of 20 tables for converting incoming data, the table used to be selected by the sensor value. Sensor value=1 then use table1, Sensor value=2 then use table2 etc)
In GCbasic what should I look for?
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
' ============================================================
' SensorBinaryDispatch.GCB – GCBASIC binary-tree dispatch
' Target : PIC16F877A (adjust chip/clock to suit your board)
'
' Worst case: 5 comparisons to reach any of 20 actions.
' A straight IF-THEN chain worst case would be 20 comparisons.
'
' Tree structure used:
'
' [<=10]
' / \
' [<=5] [<=15]
' / \ / \
' [<=2] [<=7] [<=12] [<=17]
' / \ / \ / \ / \
' 1 2 ... ... ...
'
' Each level halves the remaining range.
' Maximum depth = 5 levels for 20 items.
' ============================================================
#CHIP PIC16F877A, 20
#DEFINE USART_BAUD_RATE 9600
#DEFINE USART_TX_BLOCKING
Dim SensorValue As Byte
Dim RawInput As Byte
Dim ConvResult As Word
' ============================================================
' MAIN LOOP
' ============================================================
Main:
HSerPrint "Binary Dispatch Demo"
HSerPrintCRLF
Do
' Replace these two lines with your real sensor read
RawInput = RawInput + 1
If RawInput > 20 Then RawInput = 1
SensorValue = RawInput
' Bounds check
If SensorValue >= 1 And SensorValue <= 20 Then
GoSub DispatchAction
HSerPrint "Sensor="
HSerPrint Str(SensorValue)
HSerPrint " Result="
HSerPrint Str(ConvResult)
HSerPrintCRLF
Else
HSerPrint "ERROR: out of range"
HSerPrintCRLF
End If
Wait 250 ms
Loop
' ============================================================
' BINARY DISPATCH TREE
' Each node splits the remaining range in half.
' Worst case = 5 comparisons to reach any leaf.
'
' Level 1 : splits 1-20 into 1-10 / 11-20
' Level 2 : splits into 1-5/6-10 and 11-15/16-20
' Level 3 : splits into pairs of ~2-3
' Level 4 : final single-value checks
' ============================================================
DispatchAction:
If SensorValue <= 10 Then
'--- LEFT branch: values 1-10 ---
If SensorValue <= 5 Then
'--- LEFT-LEFT branch: values 1-5 ---
If SensorValue <= 2 Then
If SensorValue = 1 Then
GoSub Action1
Else
GoSub Action2
End If
Else
If SensorValue = 3 Then
GoSub Action3
Else If SensorValue = 4 Then
GoSub Action4
Else
GoSub Action5
End If
End If
Else
'--- LEFT-RIGHT branch: values 6-10 ---
If SensorValue <= 7 Then
If SensorValue = 6 Then
GoSub Action6
Else
GoSub Action7
End If
Else
If SensorValue = 8 Then
GoSub Action8
Else If SensorValue = 9 Then
GoSub Action9
Else
GoSub Action10
End If
End If
End If
Else
'--- RIGHT branch: values 11-20 ---
If SensorValue <= 15 Then
'--- RIGHT-LEFT branch: values 11-15 ---
If SensorValue <= 12 Then
If SensorValue = 11 Then
GoSub Action11
Else
GoSub Action12
End If
Else
If SensorValue = 13 Then
GoSub Action13
Else If SensorValue = 14 Then
GoSub Action14
Else
GoSub Action15
End If
End If
Else
'--- RIGHT-RIGHT branch: values 16-20 ---
If SensorValue <= 17 Then
If SensorValue = 16 Then
GoSub Action16
Else
GoSub Action17
End If
Else
If SensorValue = 18 Then
GoSub Action18
Else If SensorValue = 19 Then
GoSub Action19
Else
GoSub Action20
End If
End If
End If
End If
Return
' ============================================================
' ACTION SUBROUTINES
' Replace the body of each with your real lookup data.
' Each reads RawInput, writes result to ConvResult.
' ============================================================
Action1:
ConvResult = RawInput * 3 ReturnAction2: ConvResult = RawInput + 100 ReturnAction3: ConvResult = RawInput / 2 ReturnAction4: Select Case RawInput Case 1 : ConvResult = 412 Case 2 : ConvResult = 398 Case 3 : ConvResult = 521 Case 4 : ConvResult = 305 Case 5 : ConvResult = 477 Case Else : ConvResult = 0 End Select ReturnAction5: ConvResult = RawInput * RawInput
Return
Action6:
ConvResult = 255 - RawInput
Return
Action7:
ConvResult = RawInput + 50
Return
Action8:
ConvResult = RawInput * 10 ReturnAction9: ConvResult = RawInput << 1 ReturnAction10: ConvResult = RawInput >> 1 ReturnAction11: ConvResult = RawInput + 200 ReturnAction12: ConvResult = 300 - RawInput ReturnAction13: ConvResult = RawInput * 7
Return
Action14:
ConvResult = RawInput Mod 16
Return
Action15:
ConvResult = 1024
Return
Action16:
ConvResult = RawInput + 75
Return
Action17:
ConvResult = RawInput * 4 ReturnAction18: Select Case RawInput Case 1 : ConvResult = 1000 Case 2 : ConvResult = 1025 Case 3 : ConvResult = 1051 Case 4 : ConvResult = 1078 Case 5 : ConvResult = 1106 Case 6 : ConvResult = 1135 Case 7 : ConvResult = 1165 Case 8 : ConvResult = 1196 Case 9 : ConvResult = 1228 Case 10 : ConvResult = 1261 Case Else : ConvResult = 0 End Select ReturnAction19: ConvResult = RawInput * 15
Return
Action20:
ConvResult = RawInput + 512
Return
' ============================================================
' END OF PROGRAM
' ============================================================
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Thank you for your reply and example. I had a tree structure in mind, but I wondered if there was some way to direct jump based on value
AI:s gives all kinds of suggestions, but nothing I can make into sense looking in the GCbasic docs on how to realize it into code that will work.
-So there is no way using the sensor value to make a logic direct jump (jump table or what ever it might be called)?
Is that simply is not possible because the hardware in the 8-bit PIC chips etc does not support/assist it? Just so I get that clear and move on.
I can probably move the sensor data -> selection to my main loop and make copies of the program part that processes the data flowing through into my 32kHz clocked interrupt routine (using the part decided in the main loop). I can probably make this work if I re-think. This way the sensor data based decision does not need to be done 32000 times per second or more.
I have also an idea of converting the sensor data to logarithmic via a table and then fewer out values may be required for similar performance in my secret project (until finished). I can then make the tree structure smaller or maybe even get away without it.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Yes, the hardware is the core limitation. On an 8-bit PIC:
The program counter (PC) is not a general-purpose register you can freely load with a calculated address in the way a 16/32-bit CPU allows
There is a trick using ADDWF PCL (add W to the low byte of PC) in raw assembler to do a computed jump, but it's fragile — it only works within a 256-instruction page boundary, and GCBASIC's compiler manages PC layout itself so you can't safely exploit it
This is exactly why GCBASIC never implemented ON x GOSUB label1, label2... — it would be unreliable across different PIC variants and memory layouts
So yes — no safe direct jump table on 8-bit PIC in GCBASIC. You've hit a genuine hardware constraint, not a gap in your knowledge.
The ideas you're describing are the right engineering response:
Move the selection to the main loop — absolutely correct. Deciding which action/table to use based on sensor value is a slow, infrequent decision. Running a 5-comparison binary tree 32,000 times per second inside an ISR is wasteful when the sensor type probably changes rarely or never during a run. Set a variable like CurrentAction in the main loop, and your ISR just acts on it directly.
Logarithmic pre-conversion — this is a classic DSP technique and a very elegant solution. If your 20 possible output values compress well onto a log scale, you may find that 6-8 log-spaced values cover the perceptually or functionally important range just as well. That could reduce your tree to 3 levels and 3 comparisons worst case — or even allow a small SELECT CASE that the compiler handles efficiently.
Both ideas together — slow sensor-type selection in main loop, log-compressed fast lookup in the ISR — is a genuinely good architecture for a resource-constrained 8-bit system. Good luck with the project when you're ready to share it!
👍
1
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Say I have a value from a sensor 1-20. I would like to do a fast direct jump to one of 20 subroutines or functions (selected by the sensor value) without having to test my way trough a long list of if-then or select case.
(At this time I am looking for a way to select one of 20 tables for converting incoming data, the table used to be selected by the sensor value. Sensor value=1 then use table1, Sensor value=2 then use table2 etc)
In GCbasic what should I look for?
ready..... the fastest I can think of.
Thank you for your reply and example. I had a tree structure in mind, but I wondered if there was some way to direct jump based on value
AI:s gives all kinds of suggestions, but nothing I can make into sense looking in the GCbasic docs on how to realize it into code that will work.
-So there is no way using the sensor value to make a logic direct jump (jump table or what ever it might be called)?
Is that simply is not possible because the hardware in the 8-bit PIC chips etc does not support/assist it? Just so I get that clear and move on.
I can probably move the sensor data -> selection to my main loop and make copies of the program part that processes the data flowing through into my 32kHz clocked interrupt routine (using the part decided in the main loop). I can probably make this work if I re-think. This way the sensor data based decision does not need to be done 32000 times per second or more.
I have also an idea of converting the sensor data to logarithmic via a table and then fewer out values may be required for similar performance in my secret project (until finished). I can then make the tree structure smaller or maybe even get away without it.
Yes, the hardware is the core limitation. On an 8-bit PIC:
ADDWF PCL(add W to the low byte of PC) in raw assembler to do a computed jump, but it's fragile — it only works within a 256-instruction page boundary, and GCBASIC's compiler manages PC layout itself so you can't safely exploit itON x GOSUB label1, label2...— it would be unreliable across different PIC variants and memory layoutsSo yes — no safe direct jump table on 8-bit PIC in GCBASIC. You've hit a genuine hardware constraint, not a gap in your knowledge.
The ideas you're describing are the right engineering response:
Move the selection to the main loop — absolutely correct. Deciding which action/table to use based on sensor value is a slow, infrequent decision. Running a 5-comparison binary tree 32,000 times per second inside an ISR is wasteful when the sensor type probably changes rarely or never during a run. Set a variable like
CurrentActionin the main loop, and your ISR just acts on it directly.Logarithmic pre-conversion — this is a classic DSP technique and a very elegant solution. If your 20 possible output values compress well onto a log scale, you may find that 6-8 log-spaced values cover the perceptually or functionally important range just as well. That could reduce your tree to 3 levels and 3 comparisons worst case — or even allow a small
SELECT CASEthat the compiler handles efficiently.Both ideas together — slow sensor-type selection in main loop, log-compressed fast lookup in the ISR — is a genuinely good architecture for a resource-constrained 8-bit system. Good luck with the project when you're ready to share it!