305 lines
10 KiB
ArmAsm
305 lines
10 KiB
ArmAsm
| Atari ST word-interleaved planar jlFillCircle -- 68000 hand-rolled.
|
|
|
|
|
| Bresenham midpoint circle, 4 horizontal spans per Bresenham iter,
|
|
| paired by shared x-range so leftMask/rightMask are computed once
|
|
| per pair:
|
|
| Pair A: x in [cx-bx, cx+bx], rows y = cy+by, cy-by
|
|
| Pair B: x in [cx-by, cx+by], rows y = cy+bx, cy-bx
|
|
|
|
|
| Caller MUST guarantee the bounding box (cx-r, cy-r) (cx+r, cy+r)
|
|
| is fully on-surface. Off-surface circles fall back to the C walker.
|
|
|
|
|
| Phase 10 final: 16-way color dispatch at the OUTER loop. Each color
|
|
| variant has its own Bresenham body where SPAN_BODY inlines a hard-
|
|
| coded 4-plane mask RMW (no btst, no bsr/rts). Saves ~120 cyc per
|
|
| applyMask call (was ~180 via bsr applyMask with runtime btst on d7).
|
|
|
|
|
| ABI: cdecl. d2-d7/a2-a6 callee-save.
|
|
|
|
|
| void surface68kStFillCircle(uint8_t *base,
|
|
| uint16_t cx, uint16_t cy,
|
|
| uint16_t r, uint8_t color);
|
|
|
|
.text
|
|
|
|
|
|
.equ SP_FC_SAVED, 44
|
|
.equ SP_FC_LOCAL, 8
|
|
.equ SP_FC_OFF, (SP_FC_SAVED + 4 + SP_FC_LOCAL)
|
|
.equ SP_FC_BASE, SP_FC_OFF + 0
|
|
.equ SP_FC_CX, SP_FC_OFF + 4 + 2
|
|
.equ SP_FC_CY, SP_FC_OFF + 8 + 2
|
|
.equ SP_FC_R, SP_FC_OFF + 12 + 2
|
|
.equ SP_FC_COLOR, SP_FC_OFF + 20 + 3
|
|
|
|
|
|
| ---- COMPUTE_PAIR_MASKS macro -----------------------------------
|
|
| Input: d0.w = left, d1.w = right
|
|
| Output: 0(sp) leftMask, 2(sp) rightMask, 4(sp) numGroups,
|
|
| 6(sp) groupFirstByteOff
|
|
| Trashes: d0, d1
|
|
|
|
.macro COMPUTE_PAIR_MASKS
|
|
move.w %d0,0(%sp) | stash left
|
|
move.w %d1,2(%sp) | stash right
|
|
move.w %d0,%d1
|
|
lsr.w #4,%d1 | groupFirst
|
|
move.w %d1,%d0
|
|
lsl.w #3,%d0 | groupFirstByteOff
|
|
move.w %d0,6(%sp)
|
|
move.w 2(%sp),%d0
|
|
lsr.w #4,%d0 | groupLast
|
|
sub.w %d1,%d0 | numGroups
|
|
move.w %d0,4(%sp)
|
|
| leftMask via LUT[bitFirst]; a5 = _gStLeftMaskLut base
|
|
move.w 0(%sp),%d0
|
|
and.w #15,%d0
|
|
add.w %d0,%d0
|
|
move.w (%a5,%d0.w),%d1
|
|
move.w %d1,0(%sp)
|
|
| rightMask via LUT[bitLast]; a6 = _gStRightMaskLut base
|
|
move.w 2(%sp),%d0
|
|
and.w #15,%d0
|
|
add.w %d0,%d0
|
|
move.w (%a6,%d0.w),%d1
|
|
move.w %d1,2(%sp)
|
|
.endm
|
|
|
|
|
|
| ---- APPLY_MASK_INLINE macro ------------------------------------
|
|
| 4-plane mask RMW with HARDCODED color. a4 advances by 8 (postinc).
|
|
| Inputs: d0.w = mask, a4 = group ptr
|
|
| Trashes: d1 (notMask scratch)
|
|
|
|
.macro APPLY_MASK_INLINE color
|
|
move.w %d0,%d1
|
|
not.w %d1
|
|
.if ((\color) & 1)
|
|
or.w %d0,(%a4)+
|
|
.else
|
|
and.w %d1,(%a4)+
|
|
.endif
|
|
.if ((\color) & 2)
|
|
or.w %d0,(%a4)+
|
|
.else
|
|
and.w %d1,(%a4)+
|
|
.endif
|
|
.if ((\color) & 4)
|
|
or.w %d0,(%a4)+
|
|
.else
|
|
and.w %d1,(%a4)+
|
|
.endif
|
|
.if ((\color) & 8)
|
|
or.w %d0,(%a4)+
|
|
.else
|
|
and.w %d1,(%a4)+
|
|
.endif
|
|
.endm
|
|
|
|
|
|
| ---- SPAN_BODY macro --------------------------------------------
|
|
| Render one row span. Color hardcoded.
|
|
| Input: d0.w = y (signed)
|
|
| a3 = base, d5 = loLong, d6 = hiLong
|
|
| masks at 0..7(sp): leftMask, rightMask, numGroups, groupFirstByteOff
|
|
| Trashes: d0, d1, a4
|
|
|
|
.macro SPAN_BODY color
|
|
| a4 = base + y*160 + groupFirstByteOff
|
|
| y*160 via shared _gStRowOffsetLut (a2 holds lut base).
|
|
| byteOff (y*160 + groupFirstByteOff) fits in 16 bits
|
|
| (max 31992), so word-only ops + .w-indexed lea.
|
|
add.w %d0,%d0 | y * 2 (word index)
|
|
move.w (%a2,%d0.w),%d0 | d0 = y * 160
|
|
add.w 6(%sp),%d0 | + groupFirstByteOff
|
|
lea 0(%a3,%d0.w),%a4
|
|
| numGroups in d1
|
|
move.w 4(%sp),%d1
|
|
tst.w %d1
|
|
bne.s .Lsb_multi\@
|
|
| single-group: combinedMask = leftMask & rightMask
|
|
move.w 0(%sp),%d0
|
|
and.w 2(%sp),%d0
|
|
APPLY_MASK_INLINE \color
|
|
bra.w .Lsb_done\@
|
|
.Lsb_multi\@:
|
|
| leading mask. APPLY_MASK_INLINE postinc-advances a4 by 8.
|
|
| APPLY trashes d1, so reload numGroups after.
|
|
move.w 0(%sp),%d0
|
|
APPLY_MASK_INLINE \color
|
|
move.w 4(%sp),%d1
|
|
subq.w #1,%d1 | d1 = numMid
|
|
beq.s .Lsb_skipMid\@
|
|
.Lsb_midLoop\@:
|
|
move.l %d5,(%a4)+
|
|
move.l %d6,(%a4)+
|
|
subq.w #1,%d1
|
|
bne.s .Lsb_midLoop\@
|
|
.Lsb_skipMid\@:
|
|
| trailing mask
|
|
move.w 2(%sp),%d0
|
|
APPLY_MASK_INLINE \color
|
|
.Lsb_done\@:
|
|
.endm
|
|
|
|
|
|
| ---- CO_BODY macro: per-color full Bresenham loop body ----------
|
|
|
|
.macro CO_BODY color
|
|
.Lfc_loop_\color:
|
|
cmp.w %d3,%d2
|
|
bcs.w .Lfc_done
|
|
|
|
| --- Pair A: x range = (cx - bx, cx + bx)
|
|
move.w SP_FC_CX(%sp),%d0
|
|
move.w %d0,%d1
|
|
sub.w %d2,%d0
|
|
add.w %d2,%d1
|
|
COMPUTE_PAIR_MASKS
|
|
|
|
| Span A1: y = cy + by
|
|
move.w SP_FC_CY(%sp),%d0
|
|
add.w %d3,%d0
|
|
SPAN_BODY \color
|
|
|
|
| Span A2: y = cy - by
|
|
move.w SP_FC_CY(%sp),%d0
|
|
sub.w %d3,%d0
|
|
SPAN_BODY \color
|
|
|
|
| --- Pair B: x range = (cx - by, cx + by)
|
|
move.w SP_FC_CX(%sp),%d0
|
|
move.w %d0,%d1
|
|
sub.w %d3,%d0
|
|
add.w %d3,%d1
|
|
COMPUTE_PAIR_MASKS
|
|
|
|
| Span B1: y = cy + bx
|
|
move.w SP_FC_CY(%sp),%d0
|
|
add.w %d2,%d0
|
|
SPAN_BODY \color
|
|
|
|
| Span B2: y = cy - bx
|
|
move.w SP_FC_CY(%sp),%d0
|
|
sub.w %d2,%d0
|
|
SPAN_BODY \color
|
|
|
|
| --- Bresenham step
|
|
addq.w #1,%d3
|
|
tst.w %d4
|
|
bgt.s .Lfc_decBx_\color
|
|
add.w %d3,%d4
|
|
add.w %d3,%d4
|
|
addq.w #1,%d4
|
|
bra.w .Lfc_loop_\color
|
|
.Lfc_decBx_\color:
|
|
subq.w #1,%d2
|
|
add.w %d3,%d4
|
|
add.w %d3,%d4
|
|
sub.w %d2,%d4
|
|
sub.w %d2,%d4
|
|
addq.w #1,%d4
|
|
bra.w .Lfc_loop_\color
|
|
.endm
|
|
|
|
|
|
.globl _surface68kStFillCircle
|
|
|
|
_surface68kStFillCircle:
|
|
movem.l %d2-%d7/%a2-%a6,-(%sp)
|
|
lea -SP_FC_LOCAL(%sp),%sp
|
|
|
|
| base, color
|
|
move.l SP_FC_BASE(%sp),%a3
|
|
moveq #0,%d7
|
|
move.b SP_FC_COLOR(%sp),%d7
|
|
|
|
| LUT bases. a5/a6 = mask LUTs (used by COMPUTE_PAIR_MASKS).
|
|
| a2 = shared _gStRowOffsetLut (used by SPAN_BODY for y*160).
|
|
| All three LUTs are the shared definitions in lineSpan.s;
|
|
| reference them absolute (single source of truth).
|
|
lea _gStLeftMaskLut,%a5
|
|
lea _gStRightMaskLut,%a6
|
|
lea _gStRowOffsetLut,%a2
|
|
|
|
| loLong = ((c&1)?0xFFFF0000:0) | ((c&2)?0x0000FFFF:0)
|
|
moveq #0,%d5
|
|
btst #1,%d7
|
|
beq.s .Lfc_lo1
|
|
move.w #-1,%d5
|
|
.Lfc_lo1:
|
|
btst #0,%d7
|
|
beq.s .Lfc_lo0
|
|
ori.l #0xFFFF0000,%d5
|
|
.Lfc_lo0:
|
|
| hiLong = ((c&4)?0xFFFF0000:0) | ((c&8)?0x0000FFFF:0)
|
|
moveq #0,%d6
|
|
btst #3,%d7
|
|
beq.s .Lfc_hi3
|
|
move.w #-1,%d6
|
|
.Lfc_hi3:
|
|
btst #2,%d7
|
|
beq.s .Lfc_hi2
|
|
ori.l #0xFFFF0000,%d6
|
|
.Lfc_hi2:
|
|
|
|
| Bresenham init: bx=r, by=0, err=1-bx
|
|
move.w SP_FC_R(%sp),%d2
|
|
moveq #0,%d3
|
|
moveq #1,%d4
|
|
sub.w %d2,%d4
|
|
|
|
| Dispatch on color (low 4 bits) -> 16 specialized loops.
|
|
| Use a4 (gets overwritten in SPAN_BODY's first lea) as
|
|
| dispatch scratch since a2 now holds yLut for the body.
|
|
and.w #0x0F,%d7
|
|
move.w %d7,%d0
|
|
add.w %d0,%d0
|
|
add.w %d0,%d0 | * 4 for bra.w table
|
|
lea .Lfc_table(%pc),%a4
|
|
jmp 0(%a4,%d0.w)
|
|
|
|
.Lfc_table:
|
|
bra.w .Lfc_loop_0
|
|
bra.w .Lfc_loop_1
|
|
bra.w .Lfc_loop_2
|
|
bra.w .Lfc_loop_3
|
|
bra.w .Lfc_loop_4
|
|
bra.w .Lfc_loop_5
|
|
bra.w .Lfc_loop_6
|
|
bra.w .Lfc_loop_7
|
|
bra.w .Lfc_loop_8
|
|
bra.w .Lfc_loop_9
|
|
bra.w .Lfc_loop_10
|
|
bra.w .Lfc_loop_11
|
|
bra.w .Lfc_loop_12
|
|
bra.w .Lfc_loop_13
|
|
bra.w .Lfc_loop_14
|
|
bra.w .Lfc_loop_15
|
|
|
|
CO_BODY 0
|
|
CO_BODY 1
|
|
CO_BODY 2
|
|
CO_BODY 3
|
|
CO_BODY 4
|
|
CO_BODY 5
|
|
CO_BODY 6
|
|
CO_BODY 7
|
|
CO_BODY 8
|
|
CO_BODY 9
|
|
CO_BODY 10
|
|
CO_BODY 11
|
|
CO_BODY 12
|
|
CO_BODY 13
|
|
CO_BODY 14
|
|
CO_BODY 15
|
|
|
|
|
|
.Lfc_done:
|
|
lea SP_FC_LOCAL(%sp),%sp
|
|
movem.l (%sp)+,%d2-%d7/%a2-%a6
|
|
rts
|
|
|
|
|
|
| (leftMaskLut/rightMaskLut now live in lineSpan.s as the shared
|
|
| _gStLeftMaskLut / _gStRightMaskLut, referenced absolute above.)
|