;************************************************************************** ; arch/z80/src/ez80/ez80_vectors.asm ; ; Copyright (C) 2008 Gregory Nutt. All rights reserved. ; Author: Gregory Nutt <spudmonkey@racsa.co.cr> ; ; Redistribution and use in source and binary forms, with or without ; modification, are permitted provided that the following conditions ; are met: ; ; 1. Redistributions of source code must retain the above copyright ; notice, this list of conditions and the following disclaimer. ; 2. Redistributions in binary form must reproduce the above copyright ; notice, this list of conditions and the following disclaimer in ; the documentation and/or other materials provided with the ; distribution. ; 3. Neither the name NuttX nor the names of its contributors may be ; used to endorse or promote products derived from this software ; without specific prior written permission. ; ; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ; "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS ; FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE ; COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, ; INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, ; BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS ; OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED ; AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ; LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ; ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ; POSSIBILITY OF SUCH DAMAGE. ; ;************************************************************************** ;************************************************************************** ; Constants ;************************************************************************** NVECTORS EQU 64 ; max possible interrupt vectors ;* Bits in the Z80 FLAGS register ***************************************** EZ80_C_FLAG EQU 01h ; Bit 0: Carry flag EZ80_N_FLAG EQU 02h ; Bit 1: Add/Subtract flag EZ80_PV_FLAG EQU 04h ; Bit 2: Parity/Overflow flag EZ80_H_FLAG EQU 10h ; Bit 4: Half carry flag EZ80_Z_FLAG EQU 40h ; Bit 5: Zero flag EZ80_S_FLAG EQU 80h ; Bit 7: Sign flag ;************************************************************************** ; Global Symbols Imported ;************************************************************************** xref _ez80_startup xref _up_doirq ;************************************************************************** ; Global Symbols Exported ;************************************************************************** xdef _ez80_reset xdef _ez80_initvectors xdef _ez80_handlers xdef _ez80_rstcommon xdef _ez80_initvectors xdef _ez80_vectable ;************************************************************************** ; Macros ;************************************************************************** ; Define one reset handler ; 1. Disable interrupts ; 2. Dlear mixed memory mode (MADL) flag ; 3. jump to initialization procedure with jp.lil to set ADL rstvector: macro di rsmix jp.lil _ez80_startup endmac rstvector ; Define one interrupt handler irqhandler: macro vectno ; Save AF on the stack, set the interrupt number and jump to the ; common reset handling logic. ; Offset 8: Return PC is already on the stack push af ; Offset 7: AF (retaining flags) ld a, #vectno ; A = vector number jp _ez80_rstcommon ; Remaining RST handling is common endmac irqhandler ;************************************************************************** ; Reset entry points ;************************************************************************** define .RESET, space = ROM segment .RESET _ez80_reset: _rst0: rstvector _rst8: rstvector _rst10: rstvector _rst18: rstvector _rst20: rstvector _rst28: rstvector _rst30: rstvector _rst38: rstvector ds %26 _nmi: retn ;************************************************************************** ; Startup logic ;************************************************************************** define .STARTUP, space = ROM segment .STARTUP .assume ADL=1 ;************************************************************************** ; Interrupt Vector Handling ;************************************************************************** _ez80_handlers: irqhandler 0 handlersize equ $-_ez80handlers irqhandler 1 irqhandler 2 irqhandler 3 irqhandler 4 irqhandler 5 irqhandler 6 irqhandler 7 irqhandler 8 irqhandler 9 irqhandler 10 irqhandler 11 irqhandler 12 irqhandler 13 irqhandler 14 irqhandler 15 irqhandler 16 irqhandler 17 irqhandler 18 irqhandler 19 irqhandler 20 irqhandler 21 irqhandler 22 irqhandler 23 irqhandler 24 irqhandler 25 irqhandler 26 irqhandler 27 irqhandler 28 irqhandler 29 irqhandler 30 irqhandler 31 irqhandler 32 irqhandler 33 irqhandler 34 irqhandler 35 irqhandler 36 irqhandler 37 irqhandler 38 irqhandler 39 irqhandler 40 irqhandler 41 irqhandler 42 irqhandler 43 irqhandler 44 irqhandler 45 irqhandler 46 irqhandler 47 irqhandler 48 irqhandler 49 irqhandler 50 irqhandler 51 irqhandler 52 irqhandler 53 irqhandler 54 irqhandler 55 irqhandler 56 irqhandler 57 irqhandler 58 irqhandler 59 irqhandler 60 irqhandler 61 irqhandler 62 irqhandler 63 ;************************************************************************** ; Common Interrupt handler ;************************************************************************** _ez80_rstcommon: ; Create a register frame. SP points to top of frame + 4, pushes ; decrement the stack pointer. Already have ; ; Offset 8: Return PC is already on the stack ; Offset 7: AF (retaining flags) ; ; IRQ number is in A push hl ; Offset 6: HL ld hl, #(3*3) ; HL is the value of the stack pointer before add hl, sp ; the interrupt occurred (3 for PC, AF, HL) push hl ; Offset 5: Stack pointer push iy ; Offset 4: IY push ix ; Offset 3: IX push de ; Offset 2: DE push bc ; Offset 1: BC ; At this point, we know that interrupts were enabled (or we wouldn't be here ; so we can save a fake indicationn that will cause interrupts to restored when ; this context is restored ld bc, #EZ80_PV_FLAG ; Parity bit. 1=parity odd, IEF2=1 push bc ; Offset 0: I with interrupt state in carry di ; (not necessary) ; Call the interrupt decode logic. SP points to the beggining of the reg structure ld hl, #0 ; Argument #2 is the beginning of the reg structure add hl, sp ; push hl ; Place argument #2 at the top of stack ld bc, #0 ; BC = reset number ld c, a ; Save the reset number in C push bc ; Argument #1 is the Reset number call _up_doirq ; Decode the IRQ ; On return, HL points to the beginning of the reg structure to restore ; Note that (1) the arguments pushed on the stack are not popped, and (2) the ; original stack pointer is lost. In the normal case (no context switch), ; HL will contain the value of the SP before the arguments were pushed. ld sp, hl ; Use the new stack pointer ; Restore registers. HL points to the beginning of the reg structure to restore ex af, af' ; Select alternate AF pop af ; Offset 0: AF' = I with interrupt state in carry ex af, af' ; Restore original AF pop bc ; Offset 1: BC pop de ; Offset 2: DE pop ix ; Offset 3: IX pop iy ; Offset 4: IY exx ; Use alternate BC/DE/HL pop hl ; Offset 5: HL' = Stack pointer after return exx ; Restore original BC/DE/HL pop hl ; Offset 6: HL pop af ; Offset 7: AF ; Restore the stack pointer exx ; Use alternate BC/DE/HL pop de ; Offset 8: Return address ld sp, hl ; Set SP = saved stack pointer value before return push de ; Set up for reti exx ; Restore original BC/DE/HL ; Restore interrupt state ex af, af' ; Recover interrupt state jp po, nointenable ; Odd parity, IFF2=0, means disabled ex af, af' ; Restore AF (before enabling interrupts) ei ; yes reti nointenable: ex af, af' ; Restore AF reti ;************************************************************************** ; Vector Setup Logic ;************************************************************************** _ez80_initvectors: ; Initialize the vector table ld iy, _ez80_vectable ld ix, 4 ld bc, 4 ld b, NVECTORS xor a, a ; Clear carry ld hl, handlersize ld de, _ez80_handlers sbc hl, de ; Length of irq handler in hl ld d, h ld e, l ld hl, _ez80_handlers ; Start of handlers in hl ld a, 0 $1: ld (iy), hl ; Store IRQ handler ld (iy+3), a ; Pad to 4 bytes add hl, de ; Point to next handler push de ld de, 4 add iy, de ; Point to next entry in vector table pop de djnz $1 ; Loop until all vectors have been written ; Select interrupt mode 2 im 2 ; Interrupt mode 2 ; Write the address of the vector table into the interrupt vector base ld hl, _ez80_vectable >> 8 ld i, hl ret ;************************************************************************** ; Vector Table ;************************************************************************** ; This segment must be aligned on a 512 byte boundary anywhere in RAM ; Each entry will be a 3-byte address in a 4-byte space define .IVECTS, space = RAM, align = 200h segment .IVECTS ; The first 64 bytes are not used... the vectors actually start at +0x40 _ez80_vecreserve: ds 64 _ez80_vectable: ds NVECTORS * 4