Example (Advanced): Indexing semaphores
Some semaphore instructions can be used with the index register. This allows you to devise quite sophisticated schemes. The most likely use for indexing would be where you are writing a program that works on several identical channels, like maybe a 4-channel lighting control system.
The advantage of using indexed addressing is that the same code can be used for all 4 channels, with a huge reduction in the size of the code. The alternative would be to have 4 almost identical copies of the program running simultaneously. That can certainly be done, but becomes a headache if you need to make any changes.
The down-side is that the code becomes more complicated, and in particular that the planning of memory storage becomes absolutely crucial to the success.
In indexed semaphore instructions the index register is added to the base address argument (not to the semaphore number). That fits in very nicely with the concept that you use the index register as the channel number. Here are the memory allocation directives for a hypothetical 4-channel lighting control system:
;Start the indexed memory at location 76 (arbitrary!) Sems0 mEQU 76 ;Room for 8 semaphores Sems1 mEQU 77 ;Room for 8 semaphores Sems2 mEQU 78 ;Room for 8 semaphores Sems3 mEQU 79 ;Room for 8 semaphores CycleCount0 mEQU 80 ;A single byte variable CycleCount1 mEQU 81 ;A single byte variable CycleCount2 mEQU 82 ;A single byte variable CycleCount3 mEQU 82 ;A single byte variable ;Define the semaphore bits semA sEQU 0 semB sEQU 1 semC sEQU 2 semD sEQU 3 semE sEQU 4 ;Define outputs Lamp0 oEQU 10 Lamp1 oEQU 11 Lamp2 oEQU 12 Lamp3 oEQU 13
Given these definition, the following subroutine code will count down any non-zero cycle count for those channels whose semaphore D is true and turn on its output if it hits zero (probably a total nonsense operation, but what the heck!).
Nonsense:LoadI 4 ;Easier to work backwards, gets DEC'd B4 1st use
NonsLoop:
ItoX ;Test index register
RetIfZ ;R/ just did 0
DecI
iRecallS semD,Sems0 ;This will access bit D of byte Sems0+Index
GoIfF NonsLoop ;Loop back if the semaphore is false
iRecall CycleCount0 ;Get the I'th cycle counter
Push ;Make a duplicate
GoIfZ NonsLoop ;Loop back if already at zero
DecX
Push ;Make a duplicate
iStore CycleCount0 ;Save the new value
GoIfNZ NonsLoop ;Loop if non-zero
iON Lamp0 ;turn on the lamp
GoTo NonsL
oop ;Go and process the next one
A couple of points about this code:
- It is easier to do the loop as a count down loop with a test for 0 than a count up loop with a test for 3.
- It's easiest to do test for completion at the top of the loop, because the code loops back to that common point from 3 separate places. Hence, I is initialized to 4 rather than 3, because it gets decremented once before it is used for the first time.
- While several instructions refer to the channel 0 datum, they are all indexed so they actually access the I'th channel's data.