module Z80::Utils::SinCos::Macros
Z80::Utils::SinCos Macros¶ ↑
Public Instance Methods
Creates a subroutine that generates a full SinCosTable from a quarter sines table obtainable from neg_sintable256_pi_half_no_zero_lo.
sincos-
An address of
SinCostable as a label or an integer. sintable-
Address of a
neg_sintable256_pi_half_no_zero_losines table. Can be alabel,hlregister or alabelpointer. - NOTE
-
sincosmust be an address aligned to 256 bytes (the lowest 8 bits of a 16-bitsincosaddress must be0).
The SinCosTable size is 1024 bytes.
Mofifies: af, bc, de, hl, af', bc', de', hl'.
# File lib/z80/utils/sincos.rb, line 181 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 sine table, 256-based angle, negated, and fractional parts only values.
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 92 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 a routine that calculates an address of a SinCos table entry for a given angle in the a register and returns it in the th|tl register pair.
The expected angle [0,256) translates to radians in the following way:
α = PI * angle / 128 angle = α * 128 / PI
th and tl should be a unique pair of any 8-bit registers, except a.
a = ABCDEFGH (binary) tl = ABCDEF00, th = 000000GH + INT (sincos / 256)
sincos-
An address of
SinCostable, must be aligned to 256 bytes or an 8-bit register holding the MSB of theSinCosaddress. The LSB ofsincosaddress must be0.
Options:
mask-
An optional 8-bit register holding a preloaded mask value:
0xFC(0b11111100).
T-states: 30|27|24.
Mofifies: af, th, tl.
# File lib/z80/utils/sincos.rb, line 132 def sincos_from_angle(sincos, th=h, tl=l, mask:nil) raise ArgumentError, "sincos_from_angle: invalid th, tl arguments" unless th != tl && [th, tl].all? {|t| register?(t) && t.bit8? && t != a } 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 100 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