| 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 = leftMaskLut 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 = rightMaskLut 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). lea leftMaskLut(%pc),%a5 lea rightMaskLut(%pc),%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 .align 2 | leftMaskLut[i] = (1 << (16 - i)) - 1, indexed by bitFirst (0..15) leftMaskLut: .word 0xFFFF, 0x7FFF, 0x3FFF, 0x1FFF .word 0x0FFF, 0x07FF, 0x03FF, 0x01FF .word 0x00FF, 0x007F, 0x003F, 0x001F .word 0x000F, 0x0007, 0x0003, 0x0001 | rightMaskLut[i] = ~((1 << (15 - i)) - 1), indexed by bitLast (0..15) rightMaskLut: .word 0x8000, 0xC000, 0xE000, 0xF000 .word 0xF800, 0xFC00, 0xFE00, 0xFF00 .word 0xFF80, 0xFFC0, 0xFFE0, 0xFFF0 .word 0xFFF8, 0xFFFC, 0xFFFE, 0xFFFF