Sonic and Sega Retro Message Board: Z80: help identifying an algorithm - Sonic and Sega Retro Message Board

Jump to content

Hey there, Guest!  (Log In · Register) Help
Page 1 of 1
    Locked
    Locked Forum

Z80: help identifying an algorithm or at least one of its corequisite conditions

#1 User is offline Andlabs 

Posted 27 October 2013 - 08:10 AM

  • 「いっきまーす」
  • Posts: 2175
  • Joined: 11-July 08
  • Gender:Male
  • Project:Writing my own MD/Genesis sound driver :D
  • Wiki edits:7,061
Code:

ROM:198D ; =============== S U B R O U T I N E =======================================
ROM:198D
ROM:198D
ROM:198D sub_198D:                               ; CODE XREF: ROM:1061p
ROM:198D                                         ; sub_1343+17p ...
ROM:198D                 ld      h, 1            ; 100h
ROM:198F                 ld      a, b            ; a = b - c
ROM:1990                 sub     c
ROM:1991                 jr      nc, loc_199E    ; if a xxx 0 goto loc
ROM:1993                 neg                     ; a = -a
ROM:1995                 srl     a               ; a >>= 1 (a /= 2)
ROM:1997                 ld      c, a            ; c = a
ROM:1998                 add     a, b            ; a += b
ROM:1999                 ld      l, a            ; a = (100h)[a]
ROM:199A                 ld      a, (hl)
ROM:199B                 ld      l, c            ; a -= (100h)[c]
ROM:199C                 sub     (hl)            ; alternatively, swap b and c, then do the below
ROM:199D                 ret
ROM:199E ; ---------------------------------------------------------------------------
ROM:199E
ROM:199E loc_199E:                               ; CODE XREF: sub_198D+4j
ROM:199E                 srl     a               ; a >>= 1 (a /= 2)
ROM:19A0                 ld      b, a            ; b = a
ROM:19A1                 add     a, c            ; a += c
ROM:19A2                 ld      l, a            ; a = (100h)[a]
ROM:19A3                 ld      a, (hl)
ROM:19A4                 ld      l, b            ; a -= (100h)[b]
ROM:19A5                 sub     (hl)
ROM:19A6                 ret
ROM:19A6 ; End of function sub_198D


Data at 100h:

ROM:0100                 db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1
ROM:0100                 db 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4
ROM:0100                 db 5, 5, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 9, 9, 9, 0Ah, 0Ah
ROM:0100                 db 0Ah, 0Bh, 0Bh, 0Ch, 0Ch, 0Dh, 0Dh, 0Eh, 0Eh, 0Fh, 0Fh
ROM:0100                 db 10h, 10h, 11h, 11h, 12h, 12h, 13h, 13h, 14h, 14h, 15h
ROM:0100                 db 15h, 16h, 17h, 17h, 18h, 19h, 19h, 1Ah, 1Ah, 1Bh, 1Ch
ROM:0100                 db 1Ch, 1Dh, 1Eh, 1Eh, 1Fh, 20h, 21h, 21h, 22h, 23h, 24h
ROM:0100                 db 24h, 25h, 26h, 27h, 27h, 28h, 29h, 2Ah, 2Bh, 2Bh, 2Ch
ROM:0100                 db 2Dh, 2Eh, 2Fh, 30h, 31h, 31h, 32h, 33h, 34h, 35h, 36h
ROM:0100                 db 37h, 38h, 39h, 3Ah, 3Bh, 3Ch, 3Dh, 3Eh, 3Fh, 40h, 41h
ROM:0100                 db 42h, 43h, 44h, 45h, 46h, 47h, 48h, 49h, 4Ah, 4Bh, 4Ch
ROM:0100                 db 4Dh, 4Eh, 4Fh, 51h, 52h, 53h, 54h, 55h, 56h, 57h, 59h
ROM:0100                 db 5Ah, 5Bh, 5Ch, 5Dh, 5Fh, 60h, 61h, 62h, 64h, 65h, 66h
ROM:0100                 db 67h, 69h, 6Ah, 6Bh, 6Ch, 6Eh, 6Fh, 70h, 72h, 73h, 74h
ROM:0100                 db 76h, 77h, 79h, 7Ah, 7Bh, 7Dh, 7Eh, 7Fh, 81h, 82h, 84h
ROM:0100                 db 85h, 87h, 88h, 8Ah, 8Bh, 8Dh, 8Eh, 90h, 91h, 93h, 94h
ROM:0100                 db 96h, 97h, 99h, 9Ah, 9Ch, 9Dh, 9Fh, 0A0h, 0A2h, 0A4h
ROM:0100                 db 0A5h, 0A7h, 0A9h, 0AAh, 0ACh, 0ADh, 0AFh, 0B1h, 0B2h
ROM:0100                 db 0B4h, 0B6h, 0B7h, 0B9h, 0BBh, 0BDh, 0BEh, 0C0h, 0C2h
ROM:0100                 db 0C4h, 0C5h, 0C7h, 0C9h, 0CBh, 0CCh, 0CEh, 0D0h, 0D2h
ROM:0100                 db 0D4h, 0D5h, 0D7h, 0D9h, 0DBh, 0DDh, 0DFh, 0E1h, 0E2h
ROM:0100                 db 0E4h, 0E6h, 0E8h, 0EAh, 0ECh, 0EEh, 0F0h, 0F2h, 0F4h
ROM:0100                 db 0F6h, 0F8h, 0FAh, 0FCh, 0FEh


The given function takes b and c as input and produces a as output.

This is a sound driver, and at this point in the program I come across a structure like

    db command_byte
    db unknown_parameter
    dw jump_table_target_1
    dw jump_table_target_2
    dw jump_table_target_3
    ...
jump_table_target_1:
    db command_bytes...


unknown_parameter is loaded into b and some other value is loaded into c; the result is the index into the jump table.

I am trying to determine one of the following two things:
1) Is unknown_parameter the size of the jump table? Or in other words, is b the upper bound of a?
2) What does this function do? I have no idea...
Thanks.
This post has been edited by Andlabs: 27 October 2013 - 08:14 AM

#2 User is offline ValleyBell 

Posted 27 October 2013 - 10:40 AM

  • Posts: 204
  • Joined: 08-September 10
  • Gender:Male
  • Project:researching SMPS sound drivers
  • Wiki edits:10
Something from a sound driver ... interesting.

Let's begin with the table at 100h: It's a simple lookup table for 256 squared values between 0 and 1.
You can recreate the table with this code:

for (idx = 0x00; idx < 0x100; idx ++)
{
	value = (idx / 256.0) * (idx / 256.0);
	LUT[idx] = floor(value * 256.0);
}


I'm not sure what prupose the actual function has, but it does this:

float sub_198D(float param_b, float param_c)
{
	val_low = abs(param_b - param_c) / 2;
	val_high = (param_b + param_c) / 2;
	return (val_high * val_high) - (val_low * val_low);
}
(float = register / 256.0 and vice versa.)

If I would need to guess, I'd say it has something to do with modulation. (Just because squares don't make much sense anywhere except for frequencies.)

#3 User is offline Andlabs 

Posted 27 October 2013 - 11:27 AM

  • 「いっきまーす」
  • Posts: 2175
  • Joined: 11-July 08
  • Gender:Male
  • Project:Writing my own MD/Genesis sound driver :D
  • Wiki edits:7,061
All right; trial and error on your float code shows me that yes b is the upper bound, which gives me the answer to 1)... except Ican't reproduce it with the original Z80 code, unless I transcribed the code wrong...?

I'm also unsure what's going on here, since the c parameter doesn't seem to be set anywhere; there's another function elsewhere that divides it by 2 (it's a 16-bit value and the low byte is used as c here), so I'm assuming there's still a block of code I haven't come across (or it's set subtly).
This post has been edited by Andlabs: 27 October 2013 - 11:27 AM

#4 User is offline ValleyBell 

Posted 27 October 2013 - 11:55 AM

  • Posts: 204
  • Joined: 08-September 10
  • Gender:Male
  • Project:researching SMPS sound drivers
  • Wiki edits:10
You have indeed a tiny error in your code.
if int8(a) >= 0 { goto loc_199E }

If you set b = 224 and c = 64 you get 224-64 = 160 or 0x90. Treat this as int8 and you get -96.
The Z80 calculates 224 - 64 and gets 160, but since the calculation doesn't underflow, the carry flag stays at 0. (Your line equals "jr p, loc_199E")
It checks, if B-C >= 0, that's equal to (C < B).

For reference, here is the non-float version of my code:
Private Function DoFunc(ByVal ParamB As Byte, ByVal ParamC As Byte) As Byte

	Dim IdxLow As Byte
	Dim IdxHigh As Byte
	
	If ParamB >= ParamC Then
		' loc_199E
		IdxLow = (ParamB - ParamC) \ 2
		IdxHigh = IdxLow + ParamC
		'IdxHigh = ParamB/2 + ParamC/2
		'IdxLow  = ParamB/2 - ParamC/2
		DoFunc = ValArr(IdxHigh) - ValArr(IdxLow)
	Else
		IdxLow = (ParamC - ParamB) \ 2
		IdxHigh = IdxLow + ParamB
		'IdxHigh = ParamB/2 + ParamC/2
		'IdxLow  = ParamC/2 - ParamB/2
		DoFunc = ValArr(IdxHigh) - ValArr(IdxLow)
	End If

End Function
(Yes, I often test things in Visual Basic 6. "\" means "integer divide")

#5 User is offline Andlabs 

Posted 27 October 2013 - 12:41 PM

  • 「いっきまーす」
  • Posts: 2175
  • Joined: 11-July 08
  • Gender:Male
  • Project:Writing my own MD/Genesis sound driver :D
  • Wiki edits:7,061
Ah okay; carry flag is something I can never remember :argh: Thanks

I'll leave this question open if anyone wants to try figuring out what mathematical thing this is doing; when I figure out where else this function is used I will update. Thanks again!

#6 User is offline Andlabs 

Posted 28 October 2013 - 10:00 PM

  • 「いっきまーす」
  • Posts: 2175
  • Joined: 11-July 08
  • Gender:Male
  • Project:Writing my own MD/Genesis sound driver :D
  • Wiki edits:7,061
I can now tell you the function is mainly used for volume calculations. Here's what seems to happen:

For each operator
    x = current operator TL ^ 0x7F
    If the current operator IS an output operator/slot
        x = this function(b = x, c = an external parameter loaded by the 68000; I think it's the global volume and it's 0xFF by default and 0xFF or 0x00 otherwise)
        x = this function(b = x, c = current channel volume (set by an effect command))
    LoadTL(x ^ 0x7F) (to set back to TL)


My best guess is that this is a linear->log (linear->exponential?) conversion function with built-in max()...
This post has been edited by Andlabs: 28 October 2013 - 10:37 PM

Page 1 of 1
    Locked
    Locked Forum

1 User(s) are reading this topic
0 members, 1 guests, 0 anonymous users