module Z80::Utils::SinCos::Macros
Z80::Utils::SinCos
Macros
¶ ↑
Public Instance Methods
Creates a subroutine that generates a full SinCosTable
from a quarter sinus table obtainable from neg_sintable256_pi_half_no_zero_lo
.
sincos
-
Address of a
SinCos
table as a label or an integer. sintable
-
Address of a
neg_sintable256_pi_half_no_zero_lo
sinus table. Can be alabel
,hl
register or alabel
pointer. - NOTE
-
sincos
must be an address on a 256 byte boundary (lower byte ofsincos
address must be0
); reserve 1024 bytes.
Mofifies: af
, bc
, de
, hl
, af'
, bc'
, de'
, hl'
.
# File lib/z80/utils/sincos.rb, line 163 def create_sincos_from_sintable(sincos, sintable:hl) isolate do sincos0 addr 0, SinCos ld hl, sintable unless sintable == hl ld b, 64 xor a # -sin256(0) == -0 jr skip_aget aloop ld a, [hl] # -sin256(64-b) inc hl skip_aget ex af, af ld a, 64 sub b # a = angle (1-63) exx ld b, a # save angle (1-63) ld a, 64 add b # a + 64: cos256(a + 64) == -sin256(a) call to_sincos scf call put_cos ld a, 128 add b # a + 128: sin256(a + 128) == -sin(a) call to_sincos scf call put_sin ld a, 192 sub b # 192 - a: cos256(192 - a) == -sin256(a) call to_sincos scf call put_cos xor a sub b # (256) - a: sin256(-a) == -sin256(a) call to_sincos scf call put_sin ex af, af # -sin256(a) neg # sin256(a) ex af, af ld a, b # a: sin256(a) call to_sincos # CF=0 call put_sin ld a, 64 sub b # 64 - a: cos256(64-a) == sin256(a) call to_sincos # CF=0 call put_cos ld a, 128 sub b # 128 - a: sin256(128 - a) == sin256(a) call to_sincos # CF=0 call put_sin ld a, 192 add b # a + 192: cos256(a+192) == sin256(a) call to_sincos # CF=0 call put_cos exx djnz aloop ld hl, 256 ld [sincos0[0].cos + sincos], hl # cos256(0) == 1 ld [sincos0[64/4].sin + sincos], hl # sin256(64) == 1 ld h, -1 ld [sincos0[128/4].cos + sincos], hl # cos256(128) == -1 ld [sincos0[192/4].sin + sincos], hl # sin256(192) == -1 ret put_cos inc hl inc hl put_sin ex af, af # sin(a) ld [hl], a # lower sin256 byte inc hl ex af, af # save sin sbc a # 0 or -1 depending on CF ld [hl], a # higher sin256 byte ret to_sincos sincos_from_angle sincos ret end end
Returns an array of 63 bytes containing the first quarter sinus table, 256-based angle, negated, fractional parts only.
for a in 1..63 -> (-256 * sin(PI * a / 128)) & 0x00FF
Suitable for create_sincos_from_sintable
macro.
# File lib/z80/utils/sincos.rb, line 88 def neg_sintable256_pi_half_no_zero_lo (1..63).map{|a| (-Math.sin(Math::PI*a.to_f/128.0)*256.0).truncate & 0xff } end
Creates code that returns an address of SinCos
entry for a given 256-based angle in the register a
.
For each angle: a <= llllllhh; th => MSB SinCos
address + 000000hh, tl => llllll00
sincos
-
Address of
SinCos
table, must be aligned to 256 bytes or an 8-bit register holding MSB of theSinCos
address. LSB ofsincos
address must be0
.
Options:
mask
-
An pptional 8-bit register holding preloaded mask value:
0xFC
(0b11111100
).
T-states: 30|27|24.
Mofifies: af
, th
, tl
.
# File lib/z80/utils/sincos.rb, line 118 def sincos_from_angle(sincos, th=h, tl=l, mask:nil) raise ArgumentError, "sincos must be a direct address" if pointer?(sincos) if immediate?(sincos) sincos = sincos.to_i raise ArgumentError, "sincos address must be aligned to 256 bytes" unless (sincos & 0x00FF).zero? end raise ArgumentError, "invalid mask argument" unless mask.nil? or (register?(mask) and mask.bit8? and ![a, th, tl, sincos].include?(mask)) mask = 0b11111100 if mask.nil? isolate do if register?(sincos) raise ArgumentError, "invalid sincos register" unless sincos.bit8? and ![a, th, tl].include?(sincos) ld th, a anda mask ld tl, a xor th add sincos ld th, a else select(sincos & 0x00FF, &:zero?).then do |_| ld th, a anda mask ld tl, a xor th add sincos >> 8 ld th, a end.else do raise ArgumentError, "sincos address must be aligned to 256 bytes" end end end end
Returns a SinCosTable
descriptors.
Example:
sincos data SinCosTable, sincos_table_descriptors
# File lib/z80/utils/sincos.rb, line 96 def sincos_table_descriptors (0..255).map do |a| a = ((a & 0x3F) << 2) | ((a & 0xC0) >> 6) sin = (Math.sin(Math::PI*a.to_f/128.0)*256.0).truncate cos = (Math.cos(Math::PI*a.to_f/128.0)*256.0).truncate {sin: sin, cos: cos} end end