.MACPACK generic

.autoimport

.importzp tmp1, tmp2

.export _init_interrupt_controller
.export _enable_irq
.export _disable_irq
.export _send_eoi

.import irq_int, nmi_int

IRQ_CMD_ADDR    = $effc
IRQ_DAT_ADDR    = $effd

IRQ_CMD_MASK    = $e0
IRQ_REG_MASK    = $1f
IRQ_CMD_READIRQ = $00
IRQ_CMD_ENABLE  = $20
IRQ_CMD_TYPE    = $40
IRQ_CMD_EOI     = $ff

IRQ_VECTOR = $220
NMI_VECTOR = $222

.code

; void init_irq();
; mask all IRQs, set all type to edge.
.proc _init_interrupt_controller
    lda #<irq_int
    sta IRQ_VECTOR
    lda #>irq_int
    sta IRQ_VECTOR+1

    lda #<nmi_int
    sta NMI_VECTOR
    lda #>nmi_int
    sta NMI_VECTOR+1

    ldx #$20    ; enable
    ldy #00
    jsr cmd_all
    ldx #$40    ; edge type
    ldy #$00
    jsr cmd_all
    rts

cmd_all:        ; Send the same value to all 32 bytes
    txa
    add #$10
    sta tmp1
loop:
    txa
    sta IRQ_CMD_ADDR
    tya
    sta IRQ_DAT_ADDR
    inx
    cpx tmp1
    blt loop
    rts
.endproc


; void enable_irq(uint8_t type, uint8_t irqnum);
; in A: 
.proc _enable_irq
    ; Decide which byte we need to modify by dividing by 8 (>> 3)
    pha
    lsr
    lsr
    lsr         ; A is now bytesel
    sta tmp2    ; tmp2 is now bytesel
    add #IRQ_CMD_ENABLE
    sta IRQ_CMD_ADDR
    lda IRQ_DAT_ADDR
    sta tmp1
    pla
    and #$07     ; A is now 0-7
    tax
    inx         ; X is now 1-8
    lda #$01
L1: dex
    beq L2
    asl
    bra L1  
L2: pha         ; Push bit mask to stack
    ora tmp1    ; A is now 1 << (0-7) | enable
    sta IRQ_DAT_ADDR


    lda tmp2
    add #IRQ_CMD_TYPE
    sta IRQ_CMD_ADDR
    lda IRQ_DAT_ADDR
    sta tmp1
    jsr popa    ; A is now type
    beq bit0
bit1:           ; set `bit` to 1
    pla
    ora tmp1
    bra L3
bit0:           ; set `bit` to 0
    pla
    eor #$ff
    and tmp1
L3: sta IRQ_DAT_ADDR
    rts

.endproc

; TODO this is mostly the same as enable, why copy?
.proc _disable_irq
    ; Decide which byte we need to modify by dividing by 32 (>> 5)
    pha
    lsr
    lsr
    lsr         ; A is now bytesel
    add #IRQ_CMD_ENABLE
    sta IRQ_CMD_ADDR
    lda IRQ_DAT_ADDR
    sta tmp1
    pla
    and $07     ; A is now 0-7
    tax
    inx         ; X is now 1-8
    lda #$01
L1: dex
    beq L2
    asl
    bra L1  
L2: eor #$ff    ; Invert to set enable to 0
    and tmp1    ; a is now ~(1 << (0-7)) & enable
    sta IRQ_DAT_ADDR
    rts
.endproc

; This should accept irqnum later.
; void send_eoi();
.proc _send_eoi
    lda #IRQ_CMD_EOI
    sta IRQ_CMD_ADDR
    lda #$1
    sta IRQ_DAT_ADDR
    rts
.endproc

