📄 c64.h64
字号:
.else
.emsg "Bad register name in C64_set - :reg:"
.endif
.endloop
ab_mask .set abmask
c_mask .set cmask
.endm
;
;# ======== C64_disableIER ========
;
; Disable interrupts using mask
; IEMASK - Interrupt Enable mask
; REG0, REG1 - temporary registers used to set IER
;
;#
;# Preconditions:
;# none
;#
;# Postconditions:
;# none
;#
;
C64_disableIER .macro IEMASK, REG0, REG1
.if ($symlen(":IEMASK:") == 0)
.emsg "C64_disableIER: IEMASK, REG0, and REG1 operands missing."
.elseif ($symlen(":REG0:") == 0)
.emsg "C64_disableIER: REG0 and REG1 operands missing."
.elseif ($symlen(":REG1:") == 0)
.emsg "C64_disableIER: REG1 operand missing."
.else
b disableIER_label? ; Protect IER from interrupt
|| mvkl :IEMASK:, :REG1:
mvc ier, :REG0:
mvkh :IEMASK:, :REG1:
xor -1, :REG1:, :REG1:
and :REG1:, :REG0:, :REG0:
mvc :REG0:, ier
disableIER_label?:
.endif
.endm
;
;# ======== C64_enableIER ========
;
; Enable interrupts using mask
; IEMASK - Interrupt Enable mask
; REG0, REG1 - temporary registers used to set IER
;
;#
;# Preconditions:
;# none
;#
;# Postconditions:
;# none
;#
;
C64_enableIER .macro IEMASK, REG0, REG1
.if ($symlen(":IEMASK:") == 0)
.emsg "C64_enableIER: IEMASK, REG0, and REG1 operands missing."
.elseif ($symlen(":REG0:") == 0)
.emsg "C64_enableIER: REG0 and REG1 operands missing."
.elseif ($symlen(":REG1:") == 0)
.emsg "C64_enableIER: REG1 operand missing."
.else
b enableIER_label? ; Protect IER from interrupt
mvc ier, :REG0:
mvkl :IEMASK:, :REG1:
mvkh :IEMASK:, :REG1:
or :REG1:, :REG0:, :REG0:
mvc :REG0:, ier
enableIER_label?:
.endif
.endm
;
;# ======== FIRST_BIT_NUM ========
; Returns the bit number of the lowest 1 bit in 32-bit register.
; Returns 32 if none set.
;
;#
;# Preconditions:
;# none
;#
;# Postconditions:
;# none
;#
;
FIRST_BIT_NUM .macro MASK, BITNUM
.asg 0, BITNUM
.eval MASK, regmask
.loop 32
.if (regmask & 1)
.break
.endif
.eval regmask >> 1, regmask
.eval BITNUM + 1, BITNUM
.endloop
.endm
;
;# ======== NUM_BITS ========
; Returns the number of 1 bits in a 32-bit register.
;
;#
;# Preconditions:
;# none
;#
;# Postconditions:
;# none
;#
;
NUM_BITS .macro MASK, BITCOUNT
.asg 0, BITCOUNT
.eval MASK, regmask
.loop 32
.if (regmask & 1)
.eval BITCOUNT + 1, BITCOUNT
.endif
.eval regmask >> 1, regmask
.endloop
.endm
;
;# ======== BIT_NUM_2_CREG ========
; Maps the control register bitmask assignments to names.
;
;#
;# Preconditions:
;# none
;#
;# Postconditions:
;# none
;#
;
BIT_NUM_2_CREG .macro BITNUM, CREG
.if ((1 << BITNUM) = C64_AMR)
.asg amr, CREG
.elseif ((1 << BITNUM) = C64_CSR)
.asg csr, CREG
.elseif ((1 << BITNUM) = C64_IER)
.asg ier, CREG
.elseif ((1 << BITNUM) = C64_IST)
.asg istp, CREG
.elseif ((1 << BITNUM) = C64_IRP)
.asg irp, CREG
.elseif ((1 << BITNUM) = C64_NRP)
.asg nrp, CREG
.else
.emsg "Bad bit in C64_CMASK"
.break
.endif
.endm
;
;# ======== C64_restore ========
;
; This macro conditionally restores registers from the stack, depending
; on AMASK, BMASK and CMASK. Typically, use of this macro balances use of the
; C64_save macro with the same mask values.
;
; C64_restore AMASK, BMASK, CMASK
;
; AMASK - Mask of A registers to restore
; BMASK - Mask of B registers to restore
; CMASK - Mask of control registers to restore
;
; Currently, this macro is largely complicated by the fact that you
; can't have an assembly construct like the following:
; .if (bitcount > 1)
; || mv A4, B0
; .endif
; The assembler complains about an illegal mnemonic. Without the
; ability to generate code as above, many places in this macro are
; greatly more complicated since they must now look ahead.
;
; We need to maintain 8-byte stack alignment.
; The method chosen is to count the number of bits in the masks,
; thereby giving you the number of registers to restore. This is
; then rounded up to the nearest even number, and the SP is
; adjusted once at the end, with all previous "loads" being
; offset into that frame. Since the pre-processor is doing all
; the counting, this turns out to be equally efficient to the
; C6x method involving "pops".
;
; Uses two lowest numbered A registers in AMASK for an A-side stack
; frame pointer and a temporary A register. If no A registers specified
; in AMASK, registers A0 & A1 are used. If only register A0 is specified,
; register A1 is also used. If a register other than A0 is specified,
; register A0 and that one are used.
;
; For the B-side, the lowest numbered B register in BMASK is used as a
; temporary B register, and if no B register is specified, register B0
; is used.
;
;#
;# Preconditions:
;# none
;#
;# Postconditions:
;# none
;#
;
C64_restore .macro AMASK, BMASK, CMASK, SPFLAG
.sslist
.asg 0, mask
.asg 0, bitn_a
.asg 0, bitn_b
.asg -1, bitn_c
.asg 0, bitn_0
.asg 0, bitn_1
.asg 0, bitn_next
.asg 0, bitcount
.asg 0, a_bitcount
.asg 0, b_bitcount
.asg 0, c_bitcount
.asg 0, creg0
.asg 0, creg1
.asg -1, cr0_offset
.asg -1, cr1_offset
.asg 0, nop_count
.eval AMASK, amask
.eval BMASK, bmask
.eval bmask & ~(C64_B15), bmask ; don't restore B15
.eval CMASK, cmask
.eval 0, C64_spoffset
;
; .mexit was causing errors since the rest of the macro
; was getting expanded even though it wasn't used. Instead
; of .mexit, turn the 'if' test around to control inclusion
; of the rest of the macro.
;
.if !((amask = 0) & (bmask = 0) & (cmask = 0))
;
; Count 1 bits in masks
;
NUM_BITS amask, a_bitcount
NUM_BITS bmask, b_bitcount
NUM_BITS cmask, c_bitcount
; make sure at least two A registers are specified
NUM_BITS amask, a_bitcount
.if (a_bitcount = 0)
.eval C64_A0 | C64_A1, amask
.eval a_bitcount + 2, a_bitcount
.elseif (a_bitcount = 1)
.if (amask & C64_A0)
.eval amask | C64_A1, amask
.eval a_bitcount + 1, a_bitcount
.else
.eval amask | C64_A0, amask
.eval a_bitcount + 1, a_bitcount
.endif
.endif
; make sure at least one B register is specified
.if (bmask = 0)
.eval (C64_B0) , bmask
.eval b_bitcount + 1, b_bitcount
.endif
.eval a_bitcount + b_bitcount + c_bitcount, ones
.eval a_bitcount + b_bitcount, ab_count ; if ab_count is even
; behavior differ
.eval ones + 1, tmp_ones ; align to even
.eval tmp_ones & 0xfffffffe, even_ones ; number of words
.eval even_ones * 4, words
.eval even_ones / 2, half ; split the frames in half
.eval half, boffset ; use as B frame Offset
.eval boffset - 1, aoffset ; use as A frame Offset
; -1 for SPA
; assign A-side stack frame pointer and temp A register
FIRST_BIT_NUM amask, bitn_a
.eval amask & ~(1 << bitn_a), amask
.asg a:bitn_a:, SPA
FIRST_BIT_NUM amask, bitn_a
.eval amask & ~(1 << bitn_a), amask
.asg a:bitn_a:, TMPA
.eval a_bitcount - 2, a_bitcount
; assign B-side stack frame pointer and temp B register
FIRST_BIT_NUM bmask, bitn_b
.eval bmask & ~(1 << bitn_b), bmask
.asg b:bitn_b:, TMPB
.asg SP, SPB
.eval b_bitcount - 1, b_bitcount
; C64_save saves the B temp register before the A temp register
.eval boffset, tmpb_offset
.eval boffset -1, boffset
.eval aoffset, tmpa_offset
.eval aoffset -1, aoffset
mv SP, SPA ; CODE
addaw SPA, half, SPA ; move SP into SPA then add half to SPA
;
; Try to set up some advanced loads for control registers
; to reduce load latency
;
.eval a_bitcount + b_bitcount, bitcount
.if (c_bitcount > 1)
.if (ab_count & 0xfffffffe)
.eval aoffset+boffset - bitcount - 1, cr0_offset
.eval cr0_offset, cr1_offset
.eval 4 - bitcount, nop_count
ldw *+SPB[cr0_offset+half], TMPB ; CODE
|| ldw *+SPA[cr1_offset-half], TMPA ; CODE
.else
.eval aoffset+boffset - bitcount + 1, cr0_offset
.eval cr0_offset - 1, cr1_offset
.eval 4 - bitcount, nop_count
ldw *+SPB[cr0_offset], TMPB ; CODE
|| ldw *+SPA[cr1_offset], TMPA ; CODE
.endif
.elseif (c_bitcount = 1)
.if (ab_count & 0xfffffffe)
.eval aoffset+boffset - bitcount, cr0_offset
.eval 4 - bitcount, nop_count
ldw *+SPB[cr0_offset+half], TMPB ; CODE
.else
.eval aoffset+boffset - bitcount+1, cr0_offset
.eval 4 - bitcount, nop_count
ldw *+SPB[cr0_offset], TMPB ; CODE
.endif
.endif
;
; This loop handles when both A and B registers need restoring
;
.loop
.if (a_bitcount > 0) & (b_bitcount > 0)
FIRST_BIT_NUM amask, bitn_a
FIRST_BIT_NUM bmask, bitn_b
.eval amask & ~(1 << bitn_a), amask
.eval bmask & ~(1 << bitn_b), bmask
ldw *+SPB[boffset], b:bitn_b: ; CODE
|| ldw *+SPA[aoffset], a:bitn_a: ; CODE
.eval boffset - 1, boffset
.eval aoffset - 1, aoffset
.eval a_bitcount - 1, a_bitcount
.eval b_bitcount - 1, b_bitcount
.else
.break
.endif
.endloop
.if (a_bitcount > 0)
.asg amask, mask
.asg A, reg
.elseif (b_bitcount > 0)
.asg bmask, mask
.asg B, reg
.endif
;
; we enter this loop when there are only registers from either
; A or B remaining (but not both).
;
NUM_BITS mask, bitcount
.loop
.if (bitcount > 0)
FIRST_BIT_NUM mask, bitn_next
.eval mask & ~(1 << bitn_next), mask
.eval bitcount - 1, bitcount
.if (aoffset >= boffset)
ldw *+SP[aoffset+half], :reg::bitn_next: ; CODE
.eval aoffset - 1, aoffset
.else
ldw *+SP[boffset], :reg::bitn_next: ; CODE
.eval boffset - 1, boffset
.endif
.else
.break
.endif
.endloop
;
; Restore the control registers
;
.if (cr0_offset != -1)
FIRST_BIT_NUM cmask, bitn_0
BIT_NUM_2_CREG bitn_0, creg0
.eval cmask & ~(1 << bitn_0), cmask
.if (nop_count > 0)
nop :nop_count: ; CODE
.endif
.if (cr1_offset = -1)
mvc TMPB, creg0 ; CODE
.eval c_bitcount - 1, c_bitcount
; if even then it must live in a ptr so decrement aoffset
; if odd then it must exist in b ptr so decrement boffset
.if (ab_count & 0xfffffffe)
.eval aoffset - 1, aoffset
.else
.eval boffset - 1, boffset
.endif
.else
; already set up first register immediately above
FIRST_BIT_NUM cmask, bitn_1
BIT_NUM_2_CREG bitn_1, creg1
.eval cmask & ~(1 << bitn_1), cmask
mvc TMPB, creg0 ; CODE
|| mv TMPA, TMPB ; CODE
mvc TMPB, creg1 ; CODE
.eval c_bitcount - 2, c_bitcount
; if even then it must live in a ptr so decrement aoffset
; if odd then it must exist in b ptr so decrement boffset
.if (ab_count & 0xfffffffe)
.eval aoffset - 1, aoffset
.else
.eval boffset - 1, boffset
.endif
.endif
.endif
.loop
.if (c_bitcount > 1)
FIRST_BIT_NUM cmask, bitn_0
BIT_NUM_2_CREG bitn_0, creg0
.eval cmask & ~(1 << bitn_0), cmask
FIRST_BIT_NUM cmask, bitn_1
BIT_NUM_2_CREG bitn_1, creg1
.eval cmask & ~(1 << bitn_1), cmask
.eval c_bitcount - 2, c_bitcount
ldw *+SPB[boffset], TMPB ; CODE
|| ldw *+SPA[aoffset], TMPA ; CODE
nop 4 ; CODE
mvc TMPB, creg0 ; CODE
|| mv TMPA, TMPB ; CODE
mvc TMPB, creg1 ; CODE
.eval aoffset - 1, aoffset
.eval boffset - 1, boffset
.elseif (c_bitcount = 1)
FIRST_BIT_NUM cmask, bitn_c
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -