这不是一个家庭作业问题,而是我正在开发的游戏。
我有两种16位RGB颜色,并希望根据其他六个四位数量改变它们的六个通道。算法简单但乏味;我正在通过一次做更多有用的工作来寻找优化它的方法。
高级概述:
#standardSQL
SELECT
(SELECT p.value FROM UNNEST(event_dim.params) p WHERE p.key = 'Purchased_item')
AS Purchased_item,
(SELECT p.value FROM UNNEST(event_dim.params) p WHERE p.key = 'Completed_levels')
AS Completed_levels,
...
指向四个颜色字节。 hl
,[hl] = %gggrrrrr
,[hl+1] = %0bbbbbgg
和[hl+2] = %GGGRRRRR
。 (这是两种颜色,[hl+3] = %0BBBBBGG
和rgb
。)RGB
指向三个delta字节。 bc
,[bc] = %hhhhaaaa
和[bc+1] = %ddddssss
。 (这是六个delta值,[bc+2] = %ppppqqqq
,h
,a
,d
,s
和p
。)如果我在注册表q
中隔离了 C 的颜色通道,并且delta值 D 在注册d
中,此例程将执行该对的变体:
e
到目前为止,我有一个将任何DV应用于任何颜色通道的通用例程;然后是三个隔离红色,绿色或蓝色通道并将特定DV应用于它们的例程;最后是一个主程序,它选出六个DV并用它们调用适当的通道修改程序。这已经足够了#34;但我确信还有改进的余地。执行速度似乎不是问题,但我希望减少代码大小(当然,删除冗余指令也会提高速度)。是否有任何asm位操作技巧会有所帮助?
这里是完整的代码:
VaryColorChannelByDV:
; d = color, e = DV
; a <- d + (e & %11) - (e >> 2), clamped to [0, 31]
ld a, e
and %11 ; a <- (e & %11)
add d ; a <- d + (e & %11)
srl e
srl e ; e <- e >> 2
sub e ; a <- d + (e & %11) - (e >> 2)
jr c, .zero ; a < 0, clamp to 0
cp 32
ret c ; 0 <= a < 32
ld a, 31 ; a >= 32, clamp to 31
ret
.zero
xor a
ret
答案 0 :(得分:9)
我现在能想出的最小值是57字节:
VaryColorsByDVs::
; hl = colors
; [hl+0] = gggr:rrrr
; [hl+1] = 0bbb:bbgg
; [hl+2] = GGGR:RRRR
; [hl+3] = 0BBB:BBGG
; bc = DVs
; [bc+0] = hhhh:aaaa
; [bc+1] = dddd:ssss
; [bc+2] = pppp:qqqq
ld a, 2 ; -floor($100/3)*6 mod $100
.next:
sla [hl]
inc hl
rl [hl]
.loop:
push af
rrca
ld a, [bc]
jr nc, .skip
swap a
inc bc
.skip:
rlca
ld d, a
and %00011000
ld e, a
ld a, d
rlca
rlca
and %00011000
add a, [hl]
jr nc, .noOverflow
or %11111000
.noOverflow:
sub e
jr nc, .noUnderflow
and %00000111
.noUnderflow:
dec hl
ld de, 5
.rotate:
add a, a
rl [hl]
adc a, d
dec e
jr nz, .rotate
inc hl
ld [hl], a
pop af
add a, 85 ; floor($100/3)
jr nc, .loop
ret z
inc hl
jr .next
修复Ped7g的注释只需要4个字节,总共61个字节:
VaryColorsByDVs::
; hl = colors
; [hl+0] = gggr:rrrr
; [hl+1] = 0bbb:bbgg
; [hl+2] = GGGR:RRRR
; [hl+3] = 0BBB:BBGG
; bc = DVs
; [bc+0] = hhhh:aaaa
; [bc+1] = dddd:ssss
; [bc+2] = pppp:qqqq
ld a, 2 ; -floor($100/3)*6 mod $100
.next:
sla [hl]
inc hl
rl [hl]
.loop:
push af
rrca
ld a, [bc]
jr nc, .skip
swap a
inc bc
.skip:
ld d, a
and %00001100
ld e, a
ld a, d
rlca
rlca
and %00001100
sub e
add a, a
jr nc, .positive
.negative:
add a, [hl]
jr c, .continue
and %00000111
db $38 ; jr c,
.positive:
add a, [hl]
jr nc, .continue
or %11111000
.continue:
dec hl
ld de, 5
.rotate:
add a, a
rl [hl]
adc a, d
dec e
jr nz, .rotate
inc hl
ld [hl], a
pop af
add a, 85 ; floor($100/3)
jr nc, .loop
ret z
inc hl
jr .next
答案 1 :(得分:3)
嗯...你应该给我们更多关于这些数据来自哪里的信息,如果你可以进一步预处理它们,因为+(d&3)-(d>>2)
看起来很不幸,如果可能的话我会尽量避免这种情况。实际上整个5:5:5 RGB的东西可能有点超过Z80的头部,但是如果你知道它对你有用,请继续(我在谈论我的ZX Spectrum经验,其中3.5MHz几乎没有足以操纵1位B&amp; W像素)。
但目前,您已经获得的内容可以通过删除两条ld
指令立即进行简化:
VaryColorChannelByDV:
...
add d
; ld d, a ; d <- d + (e & %11)
srl e
srl e
; ld a, d ;### A didn't change, still contains C + DV&3
sub e ; a <- d + (e & %11) - (e & %1100 >> 2)
...
如果您没有内存不足,可以创建256B查找表来钳制值,例如,您可以将h
或b
保存在表的高地址字节中,然后将a中的结果加载到l
或c
并由ld a,(hl/bc)
加以限制。这是4 + 7 t而不是那些jr/cp/ret/...
。你实际上只需要256个中的一些值,从-3到34(0..34和253..255),如果我没有计算错误(0 + 0 - 3是最小值,31 + 3) - 0是最大结果)。所以你仍然可以在地址&#34;页面内使用字节&#34;其他数据或代码为35..252。
我会尝试稍后整理一下,如果可能的话,尽量避免使用某些组件通用的东西,但我担心更好的输入数据格式可能会给你更大的提升,或者了解你的总体目标和所有约束(比如RGB中的顶部位总是0并且必须为0,或者可以是随机的结果,并且输入为0等等...每个细节通常会导致另一个被删除指令,在Z80上通常为4-11吨。