📄 arch_a.s
字号:
;
; ---------------------------------------------------------------
.proc _p_pos_intContextSwitch
; -- swap context variable --
; posCurrentTask_g = posNextTask_g
lda _posNextTask_g
ldx _posNextTask_g+1
sta _posCurrentTask_g
stx _posCurrentTask_g+1
; -- restore context of next task --
; load sp = posCurrentTask_g
sta sp
stx sp+1
; load new csp
ldy #$00
lda (sp),y
tax
txs
; load new dsp to temp
iny
lda (sp),y
sta _saved_sp
iny
lda (sp),y
sta _saved_sp+1
; copy cstack frame from dstack when slow task is detected
; test task->cstacknbr
ldy #$05
lda (sp),y
cmp #snbr_sflag
bne ics05
; get ptr to save area on dstack
; ptr1 = task->dstackroot - csp
dey
lda (sp),y
sta ptr1+1
dey
lda (sp),y
; tsx - x has still the value of sp
stx ptr1
sec
sbc ptr1
sta ptr1
bcs ics06
dec ptr1+1
ics06:
; calculate count of bytes to copy
txa
tay
and #cstacksize - 1
eor #cstacksize - 1
beq ics05
tax
; copy bytes
ics07:
lda (ptr1),y
sta $0101,y
iny
dex
bne ics07
ics05:
jmp return_from_irq
.endproc
; ---------------------------------------------------------------
;
; Return from interrupt (finally do a context switch)
;
; This function does:
; - restore the zeropage environment
; - return from interrupt (=context switch) OR
; - call original C64 timer interrupt and do the ctx switch
;
; Note:
; - _saved_sp must point to original sp
; - sp must point to current task environment
;
; ---------------------------------------------------------------
.proc return_from_irq
; get ptr: sp = task->savedzp
lda sp
clc
adc #$07
sta sp
bcc rfi01
inc sp+1
rfi01:
; store zero page content
ldy #zpsize-3
rfi02:
lda (sp),y
sta sp+2,y
dey
bpl rfi02
; set dsp
lda _saved_sp
ldx _saved_sp+1
sta sp
stx sp+1
; back to next context
lda _doorgirq
bne rfi03
pla
tay
pla
tax
pla
rti
;C64: call original irq handler if requested
rfi03:
lda #$00
sta _doorgirq
jmp (_orgC64irqvect)
.endproc
; ---------------------------------------------------------------
;
; Timer interrupt service routine
;
; Steps that are performed:
; 1. save flags and CPU registers to processor stack
; 2. if we are not yet in an interrupt (_posInInterrupt_g == 0),
; we save the context of the current task:
; - save processor stack pointer
; - save data stack pointer
; - save current zeropage environment
; - save processor stack frame into data stack
; if the currently running task has no own
; dedicated processor stack
; 3. call _c_pos_intEnter
; 4. call _c_pos_timerInterrupt
; 5. call original interrupt handler (C64 only)
; 6. call _c_pos_intExit
; 7. restore last context and return from interrupt
;
; ---------------------------------------------------------------
.proc p_timerisr
;-> This code is left out on a C64, since it is
; already done by the isr in the kernal
; pha
; txa
; pha
; tya
; pha
; -- test if we are not in an interrupt --
; Note:
; On C64 posInInterrupt_g is always 0.
; With the CC65 compiler we have a stack problem:
; When this ISR is interrupted, the stack will be destroyed.
; So we optimize this code for C64 w/ CC65: simply remove it.
; lda _posInInterrupt_g
; bne tmi02
; -- save context of current task --
; save sp
lda sp
ldy sp+1
sta _saved_sp
sty _saved_sp+1
; get ptr: sp = task->cstackptr
lda _posCurrentTask_g
ldy _posCurrentTask_g+1
sta sp
sty sp+1
ldy #$00
; store current csp: *sp = csp
tsx
txa
sta (sp),y
; get ptr: sp = task->dstackptr
iny
; store current dsp: *sp = dsp
lda _saved_sp
sta (sp),y
iny
lda _saved_sp+1
sta (sp),y
; x = task->cstacknbr
ldy #$05
lda (sp),y
tax
; get ptr: sp = task->savedzp
lda sp
clc
adc #$07
sta sp
bcc tmi00
inc sp+1
tmi00:
; store zero page content
ldy #zpsize-3
tmi01:
lda sp+2,y
sta (sp),y
dey
bpl tmi01
; copy cstack frame to dstack when slow task is detected
; test task->cstacknbr
cpx #snbr_sflag
bne tmi02
; get ptr to save area on dstack
; ptr1 = task->dstackroot - csp
lda _posCurrentTask_g
ldy _posCurrentTask_g+1
sta sp
sty sp+1
ldy #$04
lda (sp),y
sta ptr1+1
dey
lda (sp),y
tsx
stx ptr1
sec
sbc ptr1
sta ptr1
bcs tmi03
dec ptr1+1
tmi03:
; calculate count of bytes to copy
txa
tay
and #cstacksize - 1
eor #cstacksize - 1
beq tmi02
tax
; copy bytes
tmi04:
lda $0101,y
sta (ptr1),y
iny
dex
bne tmi04
tmi02:
; Set up a data stack for the isr.
; This is required for the CC65 compiler.
lda #<(_isrstack + (isrstacksize - 1))
ldx #>(_isrstack + (isrstacksize - 1))
sta sp
stx sp+1
; -- pico]OS interrupt code --
; call pico]OS: c_pos_intEnter()
jsr _c_pos_intEnter
; get character from keyboard buffer
.IF NOS_KEYINPUT
lda KEY_COUNT
beq tmi05
dec KEY_COUNT
lda KEY_BUF
ldx KEY_BUF+1
stx KEY_BUF
jsr pusha
jsr _c_nos_keyinput
tmi05:
.ENDIF
; call pico]OS: c_pos_timerInterrupt()
jsr _c_pos_timerInterrupt
; only C64: remember to call original timer irq handler
inc _doorgirq
; call pico]OS: c_pos_intExit()
jsr _c_pos_intExit
; -- leave interrupt --
; we must restore the zeropage environment here
; get ptr
lda _posCurrentTask_g
ldx _posCurrentTask_g+1
sta sp
stx sp+1
; load dsp to temp
ldy #$01
lda (sp),y
sta _saved_sp
iny
lda (sp),y
sta _saved_sp+1
; return
jmp return_from_irq
.endproc
; ---------------------------------------------------------------
;
; Initialize timer interrupt.
;
; This function is special to the C64.
; The timer is executed 60 times per second.
; The ISR will divide it down to 30 timer interrupts per second.
;
; ---------------------------------------------------------------
.proc _p_start_timer
; disable interrupts
php
sei
; save original interrupt vector
lda C64IRQVECT
ldx C64IRQVECT+1
sta _orgC64irqvect
stx _orgC64irqvect+1
; set new vector
lda #<mytimerisr
ldx #>mytimerisr
sta C64IRQVECT
stx C64IRQVECT+1
; clear flag
lda #$00
sta _doorgirq
.IF NOS_KEYINPUT
; clear keyboard buffer
sta KEY_COUNT
.ENDIF
; enable interrupts and return
plp
rts
; timer interrupt service routine
mytimerisr:
; divide timer ticks by 2
inc _tmrdiv
lda _tmrdiv
lsr
bcc orgisr
; call timer isr 30 times per second
jmp p_timerisr
orgisr:
jmp (_orgC64irqvect)
.endproc
; ---------------------------------------------------------------
; UVAR_t p_pos_findbit (const UVAR_t bitfield, UVAR_t rrOffset)
; ---------------------------------------------------------------
.proc _p_pos_findbit
ldy #$00
lda (sp),y
tax
iny
lda (sp),y
;accu = bitfield
;x = offset
stx ptr1 ;store to temp. memory
inx
clc
offsetLoop:
ror
dex
bne offsetLoop
ldx ptr1
bcs bitFound
nextBitLoop:
inx
ror
bcc nextBitLoop
bitFound:
txa
cmp #8
bcs correctOffset
; return a
jmp incsp2
correctOffset:
sbc #9
; return a
jmp incsp2
.endproc
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -