Trap/Interrupt vector table

A project log for YGREC8

A byte-wide stripped-down version of the YGREC16 architecture

Yann Guidon / YGDESYann Guidon / YGDES 01/04/2018 at 08:590 Comments

Update 20200711 : Some aspects are obsolete and superseded, such as the MOV opcode value...

Typically : the YGREC8 starts running at address 0. That's where programs are usually located.

Another special address is FFh : that's the INV vector code, the invalid instruction. Typically, uninitialised Flash or PROM reads as all-1s, so running into uninitialised regions will return an opcode of FFFFh, which is MOV PC FFh. It's a jump to FFh where, normally, there is the same FFFFh value, which loops there endlessly.

External IRQ signals will be provided (one day) and they require specific addresses. They could be stored in the IO space (as constants or not) and fetched whenever the request happens.

But what is interesting here is the software traps. There is no such thing, actually, but implementing memory bounds for the stack for example, would be nice. However nothing distinguishes the SRAM regions and there is no such thing as a dedicated HW stack. So we have to check in SW. There is no bound check instruction but we have conditional jumps on Zero, Carry and Sign.

Zero is pretty useful : if a stack grows down, we can easily check if there is an overflow. If the stack grows up, the same is true, it detects the wrap-around from FFh to 00h.

Conveniently, the sign flag can work the same, if you want to restrict the stack to only one half of the memory bank. You can define the zone from 00h to 7FH, or 80h to FFh, and detect overflow when the sign bit changes.

No comparison needed, so a check is just :

MOV PC 0 IFP ; when the last decrement went from 80h to 7Fh 


MOV PC 0 IFN ; when the last increment went from 7Fh to 80h

 The same principle applies for the IFC, IFNC, IFZ and IFNZ conditions.

OK, it's a crude boundary check that consumes only one instruction and one cycle without any special adaptation. It won't save any

But where to jump ? Address 0 is the reset vector, so the program will restart without indication that something wrong happened. And going to -1 (FFh) is not very useful either.

The conditional MOV PC allows a range from -4 to +3 so there are 6 other addresses to jump to, and they can contain a long jump to actual code.

So you can have the following source code:

.org 0
  MOV PC EntryPoint; // reset vector
  MOV PC ErrorRoutine1;
  MOV PC ErrorRoutine2;
  MOV PC ErrorRoutine3;

  ; your application goes here

.org FCh
  MOV PC ErrorRoutine4;
  MOV PC ErrorRoutine5;
  MOV PC ErrorRoutine6;
  MOV PC INV routine; // Process the INV instruction

As a consequence, the hardware traps and external IRQs should be mapped outside of this  -4..+3 range, for example starting at address 4.

It looks a bit similar to the PIC16 architecture, except that there is no mirrored vector table...

The following "idiom" shows a non-leaf function that tests for stack overflow :

.org 0
  MOV PC EntryPoint; // Reset vector
  MOV PC StackOverflow;

  CALL D1 Nested

   ; send an error message

  ADD A1 1 ; push
  MOV PC 1 IFZ ; jump to vector 1 if detecting a wraparound from FFh to 00h

 ; do some actual work, like
  CALL D1 Nested2 ; another non-leaf function

  ADD A1 -1 ; pop