joeylib2/src/port/atarist/fillCircle.s

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.)