📄 c62.h62
字号:
.if ($symcmp(SPFLAG, "NOSP") == 0)
ldw *+SP[even_ones], SPA ; CODE
.eval even_ones, C62_spoffset
.else
ldw *++SP[even_ones], SPA ; CODE
.endif
nop 4 ; CODE
.endif ; if !(amask = bmask = cmask = 0)
.endm
;
;# ======== C62_restoresp ========
;
;#
;# Preconditions:
;# none
;#
;# Postconditions:
;# none
;#
;
C62_restoresp .macro offset, tempreg
.eval offset * STD_TARGWORDMAUS, num
mvkl num, :tempreg:
mvkh num, :tempreg:
add SP, :tempreg:, SP
.endm
;
;# ======== C62_save ========
;
; This macro conditionally saves registers onto the stack, depending
; on ABMASK and CMASK. Typically, use of this macro is balanced with
; use of the C62_restore macro with the same mask values.
;
; C62_save ABMASK, CMASK
;
; ABMASK - Mask of A and B registers to save
; CMASK - Mask of control registers to save
;
; 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 save. This is
; then rounded up to the nearest even number, and the SP is
; adjusted once up front, with all subsequent "stores" 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 "pushes".
;
; Uses two lowest numbered A registers in ABMASK for an A-side stack
; frame pointer and a temporary A register. If no A registers specified
; in ABMASK, registers A0 & A1 are saved and used. If only register A0
; is specified, register A1 is also saved and used. If a register other
; than A0 is specified, register A0 and that one are saved and used.
;
; For the B-side, the lowest numbered B register in ABMASK is used, and
; if no B register is specified, register B0 is saved and used.
;
;#
;# Preconditions:
;# none
;#
;# Postconditions:
;# none
;#
;
C62_save .macro ABMASK, CMASK
.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 0, creg_next
.eval ABMASK & 0x0000ffff, amask
.eval (ABMASK >> 16) & 0xffff, bmask
.eval bmask & ~(C62_B15 >> 16), bmask ; don't save B15
.eval CMASK, cmask
;
; .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
.if (a_bitcount = 0)
.eval C62_A0 | C62_A1, amask
.eval a_bitcount + 2, a_bitcount
.elseif (a_bitcount = 1)
.if (amask & C62_A0)
.eval amask | C62_A1, amask
.eval a_bitcount + 1, a_bitcount
.else
.eval amask | C62_A0, amask
.eval a_bitcount + 1, a_bitcount
.endif
.endif
; make sure at least one B register is specified
.if (bmask = 0)
.eval (C62_B0 >> 16) & 0xffff, bmask
.eval b_bitcount + 1, b_bitcount
.endif
.eval a_bitcount + b_bitcount + c_bitcount, ones
.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 - 1, offset
; 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
.if (amask = 0) | (bmask = 0)
.if (a_bitcount > 0)
.asg amask, mask
.asg A, reg
.asg TMPB, tmpreg
.elseif (b_bitcount > 0)
.asg bmask, mask
.asg B, reg
.asg TMPA, tmpreg
.elseif (cmask > 0)
; both amask and bmask = 0
FIRST_BIT_NUM cmask, bitn_c
BIT_NUM_2_CREG bitn_c, creg0
.endif
.endif
stw SPA, *SP--[even_ones] ; CODE
mv SP, SPA ; CODE
.if (mask = 0)
.if (bitn_c = -1)
; both amask and bmask non-zero
stw TMPB, *+SPB[offset] ; CODE
|| stw TMPA, *+SPA[offset - 1] ; CODE
.else
; both amask and bmask = 0
stw TMPB, *+SPB[offset] ; CODE
|| stw TMPA, *+SPA[offset - 1] ; CODE
|| mvc creg0, TMPB ; CODE
.endif
.else
; one of amask or bmask is 0, but not both
FIRST_BIT_NUM mask, bitn_next
stw TMPB, *+SPB[offset] ; CODE
|| stw TMPA, *+SPA[offset - 1] ; CODE
|| mv :reg::bitn_next:, tmpreg ; CODE
.asg 0, mask
.endif
.eval offset - 2, offset
;
; This loop handles when both A and B registers need saving
;
.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
.if !(((a_bitcount = 1) & (b_bitcount > 2)) | ((b_bitcount = 1) & (a_bitcount > 2)))
;
; At this point, one of the following is true:
; 1. a_bitcount & b_bitcount > 1
; 2. a_bitcount & b_bitcount = 1
; 3. a_bitcount = 1 & b_bitcount = 2
; 4. a_bitcount = 2 & b_bitcount = 1
; In cases 2-4 this is the last iteration of the loop
;
stw b:bitn_b:, *+SPB[offset] ; CODE
|| stw a:bitn_a:, *+SPA[offset - 1] ; CODE
.eval offset - 2, offset
.eval a_bitcount - 1, a_bitcount
.eval b_bitcount - 1, b_bitcount
.else
;
; Either a_bitcount or b_bitcount equals 1, but not both.
; The one != 1 is > 2.
; We're going to exit the loop after this, knowing we'll
; also be doing the next loop at least twice.
;
.if (b_bitcount = 1)
.asg amask, mask
.asg A, reg
.asg TMPB, tmpreg
.elseif (a_bitcount = 1)
.asg bmask, mask
.asg B, reg
.asg TMPA, tmpreg
.else
.emsg "Bad macro logic"
.break
.endif
FIRST_BIT_NUM mask, bitn_next
stw b:bitn_b:, *+SPB[offset] ; CODE
|| stw a:bitn_a:, *+SPA[offset - 1] ; CODE
|| mv :reg::bitn_next:, tmpreg ; CODE
.eval offset - 2, offset
.eval a_bitcount - 1, a_bitcount
.eval b_bitcount - 1, b_bitcount
.break
.endif
.else
.break
.endif
.endloop
.if (a_bitcount > 0)
.asg amask, mask
.asg A, reg
.asg TMPB, tmpreg
.elseif (b_bitcount > 0)
.asg bmask, mask
.asg B, reg
.asg TMPA, tmpreg
.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 (mask != 0)
.if (bitcount > 1)
FIRST_BIT_NUM mask, bitn_0
.eval mask & ~(1 << bitn_0), mask
FIRST_BIT_NUM mask, bitn_1
.eval mask & ~(1 << bitn_1), mask
.eval bitcount - 2, bitcount
.if (bitcount > 1)
FIRST_BIT_NUM mask, bitn_next
;;;;;;;; already done by previous iteration of this loop or previous loop
;;;;;;;; mv :reg::bitn_0:, tmpreg ; CODE
stw tmpreg, *+SPB[offset] ; CODE
|| stw :reg::bitn_1:, *+SPA[offset - 1] ; CODE
|| mv :reg::bitn_next:, tmpreg ; CODE
.else
.if (bitcount = 0) & (c_bitcount > 0)
FIRST_BIT_NUM cmask, bitn_c
BIT_NUM_2_CREG bitn_c, creg0
;;;;;;;; already done by previous iteration of this loop or previous loop
;;;;;;;; mv :reg::bitn_0:, tmpreg ; CODE
stw tmpreg, *+SPB[offset] ; CODE
|| stw :reg::bitn_1:, *+SPA[offset - 1] ; CODE
|| mvc creg0, TMPB ; CODE
.else
;;;;;;;; already done by previous iteration of this loop or previous loop
;;;;;;;; mv :reg::bitn_0:, tmpreg ; CODE
stw tmpreg, *+SPB[offset] ; CODE
|| stw :reg::bitn_1:, *+SPA[offset - 1] ; CODE
.endif
.endif
.eval offset - 2, offset
.else
; last iteration of this loop
FIRST_BIT_NUM mask, bitn_0
.eval mask & ~(1 << bitn_0), mask
.if (c_bitcount > 0)
FIRST_BIT_NUM cmask, bitn_c
BIT_NUM_2_CREG bitn_c, creg0
stw :reg::bitn_0:, *+SP[offset] ; CODE
|| mvc creg0, TMPB ; CODE
.else
stw :reg::bitn_0:, *+SP[offset] ; CODE
.endif
.eval offset - 1, offset
.break
.endif
.endif
.endloop
.if (c_bitcount > 0) & (bitn_c = -1)
FIRST_BIT_NUM cmask, bitn_c
BIT_NUM_2_CREG bitn_c, creg0
mvc creg0, TMPB ; CODE
.endif
;
; This loop handles the control registers
;
.loop
.if (c_bitcount > 1)
FIRST_BIT_NUM cmask, bitn_c
BIT_NUM_2_CREG bitn_c, creg0
.eval cmask & ~(1 << bitn_c), cmask
FIRST_BIT_NUM cmask, bitn_c
BIT_NUM_2_CREG bitn_c, creg1
.eval cmask & ~(1 << bitn_c), cmask
.eval c_bitcount - 2, c_bitcount
.if (c_bitcount > 0)
FIRST_BIT_NUM cmask, bitn_next
BIT_NUM_2_CREG bitn_next, creg_next
;;;;;;;; already done by previous iteration of this loop or previous loop
;;;;;;;; mvc creg0, TMPB ; CODE
mvc creg1, TMPB ; CODE
|| mv TMPB, TMPA ; CODE
stw TMPA, *+SPA[offset] ; CODE
|| stw TMPB, *+SPB[offset - 1] ; CODE
|| mvc creg_next, TMPB ; CODE
.else
;;;;;;;; already done by previous iteration of this loop or previous loop
;;;;;;;; mvc creg0, TMPB ; CODE
mvc creg1, TMPB ; CODE
|| mv TMPB, TMPA ; CODE
stw TMPA, *+SPA[offset] ; CODE
|| stw TMPB, *+SPB[offset - 1] ; CODE
.endif
.eval offset - 2, offset
.elseif (c_bitcount = 1)
FIRST_BIT_NUM cmask, bitn_c
BIT_NUM_2_CREG bitn_c, creg0
.eval cmask & ~(1 << bitn_c), cmask
.eval c_bitcount - 1, c_bitcount
;;;;;;;; already done by previous iteration of this loop or previous loop
;;;;;;;; mvc creg0, TMPB ; CODE
stw TMPB, *+SPB[offset] ; CODE
.eval offset - 1, offset
.break
.else
.break
.endif
.endloop
.endif ; if !(amask = bmask = cmask = 0)
.endm
.endif ; if C62_ is not defined
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -