Start with VHDL synthesis examples
Example:
IM 5 ; push 5 onto the stack
LOADSP 20 ; push value at memory location SP+20
ADD ; pop 2 values on the stack and push the result
The choice of opcodes is intimately tied to the GCC toolchain capabilities.
/* simple program showing some interesting qualities of the ZPU toolchain */
void bar(int);
int j;
void foo(int a, int b, int c)
{
a++;
b+=a;
j=c;
bar(b);
}
foo:
loadsp 4 ; a is at memory location SP+4
im 1
add
loadsp 12 ; b is now at memory location SP+12
add
loadsp 16 ; c is now at memory location SP+16
im 24 ; «j» is at absolute memory location 24.
; Notice how the ZPU toolchain is using link-time relaxation
; to squeeze the address into a single no-op
store
im 22 ; the fn bar is at address 22
call
im 12
return ; 12 bytes of arguments + return from fn
Name | Opcode | Description | Definition |
BREAKPOINT | 00000000 | The debugger sets a memory location to this value to set a breakpoint. Once a JTAG-like debugger interface is added, it will be convenient to be able to distinguish between a breakpoint and an illegal(possibly emulated) instruction. | No effect on registers |
IM | 1xxx xxxx |
Pushes 7 bit sign extended integer and sets the a «instruction decode interrupt mask» flag(IDIM).
If the IDIM flag is already set, this instruction shifts the value on the stack left by 7 bits and stores the 7 bit immediate value into the lower 7 bits. Unless an instruction is listed as treating the IDIM flag specially, it should be assumed to clear the IDIM flag. To push a 14 bit integer onto the stack, use two consequtive IM instructions. If multiple immediate integers are to be pushed onto the stack, they must be interleaved with another instruction, typically NOP. |
pc <= pc + 1
|
STORESP | 010x xxxx | Pop value off stack and store it in the SP+xxxxx*4 memory location, where xxxxx is a positive integer. | Fix! |
LOADSP | 011x xxxx | Push value of memory location SP+xxxxx*4, where xxxxx is a positive integer, onto stack. | Fix! |
ADDSP | 0001 xxxx | Add value of memory location SP+xxxx*4 to value on top of stack. | Fix! |
EMULATE | 001x xxxx | Push PC to stack and set PC to 0x0+xxxxx*32. This is used to emulate opcodes. See zpupgk.vhd for list of emulate opcode values used. zpu_core.vhd contains reference implementations of these instructions rather than letting the ZPU execute the EMULATE instruction | Fix! |
PUSHPC | emulated | Pushes program counter onto the stack. | Fix! |
POPPC | 0000 0100 | Pops address off stack and sets PC | Fix! |
LOAD | 0000 1000 | Pops address stored on stack and loads the value of that address onto stack. | Fix! |
LOAD | 0000 1000 |
Pops address stored on stack and loads the value of that address onto stack.
Bit 0 and 1 of address are always 0. |
Fix! |
STORE | 0000 1100 |
Pops address, then value from stack and stores the value into the memory location of the address.
Bit 0 and 1 of address are always 0 |
Fix! |
PUSHSP | 0000 0010 | Pushes stack pointer. | Fix! |
POPSP | 0000 1101 | Used to allocate/deallocate space on stack for variables or when changing threads. | Fix! |
ADD | 0000 0101 | Pops two values on stack adds them and pushes the result | Fix! |
AND | 0000 0110 | Pops two values off the stack and does a bitwise-and & pushes the result onto the stack | Fix! |
OR | 0000 0111 | Pops two integers, does a bitwise or and pushes result | Fix! |
NOT | 0000 1001 | Bitwise inverse of value on stack | Fix! |
FLIP | 0000 1010 | Reverses the bit order of the value on the stack, i.e. abc->cba, 100->001, 110->011, etc. | Fix! |
NOP | 0000 1011 | No operation | Fix! |
Fix! add emulated instructions! Listed in zpupkg.vhd | 001x xxxx | Fix!! | Fix! |
Address | Name | Description |
0x000 | Reset |
1.When the ZPU boots, this is the first instruction to be executed.
2.The stack pointer is initialised to maximum RAM address |
0x020 | Interrupt | This is the entry point for interrupts. |
0x040- | Emulated instructions | Emulated opcode 34. Note that opcode 32 and opcode 33 are not normally used to emulate instructions as these memory addresses are already used by boot vector, GCC registers and the interrupt vector. |
Address |
Type |
Name |
Description |
0x080A0000 |
Write |
ZPU enable |
Bit [31:1] Not used Bit [0] Enable ZPU operations 0 ZPU is held in Idle mode 1 ZPU running |
0x080A000C |
Read/ Write |
ZPU UART to ARM7 TX NOTE! ZPU side |
Bit [31:9] Not used Bit [8] TX buffer ready (valid on ready) 0 TX buffer not ready (full) 1 TX buffer ready Bit [7:0] TX byte (valid on write) |
0x080A0010 |
Read |
ZPU UART to ARM7 RX NOTE! ZPU side |
Bit [31:9] Not used Bit [8] RX buffer data valid 0 TX buffer not valid 1 TX buffer valid Bit [7:0] RX byte (when valid) |
0x080A0014 |
Read/ Write |
Counter(1) |
Bit [0] Reset counter (valid for write) 0 N/A 1 Reset counter Bit [1] Sample counter (valid for write) 0 N/A 1 Sample counter Bit [31:0] Counter bit 31:0 |
0x080A0018 |
Read |
Counter(2) |
Bit [31:0] Counter bit 63:32 |
0x080A0020 |
Read / Write |
Global_Interrupt_mask |
Bit [31:1] Not used Bit [0] Global intr. Mask 0 Interrupts enabled 1 Interrupts disabled |
0x080A0024 |
Write |
UART_INTERRUPT_ENABLE |
Bit [31:1] Not used Bit [0] UART RX interrupt enable 0 Interrupt disable 1 Interrupt enable |
0x080A0028 |
Read Write |
UART_interrupt |
Bit [31:1] Not used Bit [0] UART RX interrupt pending (Read) 0 No interrupt pending 1 Interrupt pending Bit [0] Clear UART interrupt (Write) 0 N/A 1 Interrupt cleared |
0x080A002C |
Write |
Timer_Interrupt_enable |
Bit [31:1] Not used Bit [0] Timer interrupt enable 0 Interrupt disable 1 Interrupt enable |
0x080A0030 |
Read / Write |
Timer_interrupt |
Bit [31:2] Not used Bit [0] Timer interrupt pending (Read) 0 No interrupt pending 1 Interrupt pending Bit [1] Reset Timer counter (Write) 0 N/A 1 Timer counter reset Bit [0] Clear Timer interrupt (Write) 0 N/A 1 Interrupt cleared |
0x080A0034 |
Write |
Timer_Period |
Bit [31:0] Interrupt period (write) Number of clock cycles between timer interrupts NOTE! The timer will start at Timer_Periode value and count down to zero, and generate an interrupt |
.0x080A0038 |
Read |
Timer_Counter |
Bit [31:0] Timer counter (read)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
To trigger an interrupt, the interrupt signal must be asserted. The ZPU does not define any interrupt disabling mechanism, this must be implemented by the interrupt controller and controlled via memory mapped IO.
Interrupts are masked when the IDIM flag is set, i.e. with consequtive IM instructions.
The ZPU has an edge triggered interrupt. As the ZPU notices that the interrupt is asserted, it will execute the interrupt instruction. The interrupt signal must stay asserted until the ZPU acknowledges it.
When the interrupt instruction is executed, the PC will be pushed onto the stack and the PC will be set to the interrupt vector address (0x20).
Note that the GCC compiler requires three registers r0,r1,r2,r3 for some rather uncommon operations. These 32 registers are mapped to memory locations 0x0, 0x4, 0x8, 0xc. The default interrupt vector at address 0x20 will load the value of these memory locations onto the stack, call _zpu_interrupt and restore them.
See zpu/hdl/zpu4/test/interrupt/ for C code and zpu/hdl/example/simzpu_interrupt.do for simulation example.