All I want is to decipher the bit fields in that element table at 0x176ab in the program ROM.grauw wrote:Vampirefrog, it’s the OPL4 linux driver, it’s existing for ages. Not sure if it came from an official vendor, or some Linux dev who got provided the official data, or retrieved the table data from the SoundEdge software or by disassembling the SoundEdge drivers, or just manually build the table, could be anything. Could try to find and disassemble the SoundEdge Windows driver if you want a second data point.
TG100 sample ROMS
Technical discussion which is not directly related to VGM files. Talk about Hardware and Software.
Moderator: Staff
- vampirefrog Offline
- Webmaster
- Posts: 1508
- Joined: 2014-01-28, 5:51:54
- vampirefrog Offline
- Webmaster
- Posts: 1508
- Joined: 2014-01-28, 5:51:54
Okay so here's how it works.
- The instrument table at 0x10410 has the following data (this is what I've figured out so far):
- Instrument uses two elements (bool)
- Level (volume) for element 1 and 2
- Detune for element 1 and 2
- Pan for element 1 and 2
- Name (8 chars, space padded)
- Region group ID for both elements
Each entry in the table starts with 16 bytes that hold Level, Detune, two elements bool, and other stuff I haven't figured out yet.
Next 8 bytes is the name
Next comes a pair of 36 bytes, one for each element
First two bytes use only the lower 4 bits to select the region group
Within these 36 byte chunks are also Pan bytes (pan goes from L7 to R7)
The Region group ID is an index into the table at 0x1841C (I might be off by a couple of bytes). That table has the start index into the region table at 0x176ab. The next index in the same table is the next start index, you can use that to compute the number of entries used.
So to view the samples used by an instrument, go to the instrument table at 0x10410, go to bytes 24 and 25 for element 1, and 60 and 61 for element 2 (if the first byte of the entry is 1, which means it uses the second element). Put those bytes together and you have an index into the table at 0x1841C. Read the value there (let's call it N) and count N entries, or N*9 bytes from the start of the region table at 0x176ab. You select the region you're interested in, depending on which key you're playing, and you have the sample number, which is an index into the sample rom table, which is at its beginning.
See this spreadsheet for more details.
- The instrument table at 0x10410 has the following data (this is what I've figured out so far):
- Instrument uses two elements (bool)
- Level (volume) for element 1 and 2
- Detune for element 1 and 2
- Pan for element 1 and 2
- Name (8 chars, space padded)
- Region group ID for both elements
Each entry in the table starts with 16 bytes that hold Level, Detune, two elements bool, and other stuff I haven't figured out yet.
Next 8 bytes is the name
Next comes a pair of 36 bytes, one for each element
First two bytes use only the lower 4 bits to select the region group
Within these 36 byte chunks are also Pan bytes (pan goes from L7 to R7)
The Region group ID is an index into the table at 0x1841C (I might be off by a couple of bytes). That table has the start index into the region table at 0x176ab. The next index in the same table is the next start index, you can use that to compute the number of entries used.
So to view the samples used by an instrument, go to the instrument table at 0x10410, go to bytes 24 and 25 for element 1, and 60 and 61 for element 2 (if the first byte of the entry is 1, which means it uses the second element). Put those bytes together and you have an index into the table at 0x1841C. Read the value there (let's call it N) and count N entries, or N*9 bytes from the start of the region table at 0x176ab. You select the region you're interested in, depending on which key you're playing, and you have the sample number, which is an index into the sample rom table, which is at its beginning.
See this spreadsheet for more details.
- vampirefrog Offline
- Webmaster
- Posts: 1508
- Joined: 2014-01-28, 5:51:54
Here is a capture from the chip:
sync word is 0xeeee, every 9 words
data is samples (1/44100 of a second) then D0-D7 and A0-A3
It goes out of sync sometimes, so I'm not sure what's up. I'm still trying to figure it out. Capture was made with a 3000000 baud rate and a FT232 board. I am not sure what the results should look like, so can someone check if the data is good?
I've logged since turn on of the device up to playing the demo song until the end.
sync word is 0xeeee, every 9 words
data is samples (1/44100 of a second) then D0-D7 and A0-A3
It goes out of sync sometimes, so I'm not sure what's up. I'm still trying to figure it out. Capture was made with a 3000000 baud rate and a FT232 board. I am not sure what the results should look like, so can someone check if the data is good?
I've logged since turn on of the device up to playing the demo song until the end.
- Attachments
-
- foo.cap.gz
- (1.32 MiB) Downloaded 316 times
Not sure if I can make much sense of this unless /CS (/GEW8) and /WR is logged as well. I see there is 32 bytes of data between each 0xEE,0xEE sequence.
An example sequence looks like this (there are 8 four byte sequences per sync word and not 9):
So the "ff,f8" part in the first line is the data present on the bus?. I think that you could actually get rid of the "samples" part, as timing is not something we're too concerned about now, just the data instead.
An example sequence looks like this (there are 8 four byte sequences per sync word and not 9):
Code: Select all
a6 03 ff f8
72 0b 00 fb
a2 03 ff f8
d6 07 94 eb
82 06 00 fb
a4 03 ff f8
d0 0c 00 fb
a4 03 ff f8
- vampirefrog Offline
- Webmaster
- Posts: 1508
- Joined: 2014-01-28, 5:51:54
Here are the connections:
/WR - PD15
/CS - PE1
D0-D7 - PD0-PD7
A0-A3 - PD8-PD11
NC - PD13,PD14
/RD - PD12
I am triggering on /WR, and checking if /CS is low in the interrupt handler. Here is the ISR:
/WR - PD15
/CS - PE1
D0-D7 - PD0-PD7
A0-A3 - PD8-PD11
NC - PD13,PD14
/RD - PD12
I am triggering on /WR, and checking if /CS is low in the interrupt handler. Here is the ISR:
Code: Select all
static int mark = 0;
void exti15_10_isr(void) {
if((GPIOE_IDR & GPIO1) == 0) { // Check /CS (PE1)
uint16_t w = timer_get_counter(TIM1);
TIM1_CNT = 0; // reset counter
_write(1, (char *)&w, 2);
w = GPIOD_IDR; // get the whole 16 bits
_write(1, (char *)&w, 2);
mark++;
if(mark == 8) {
w = 0xeeee;
_write(1, (char *)&w, 2);
mark = 0;
}
}
exti_reset_request(EXTI15);
}
- vampirefrog Offline
- Webmaster
- Posts: 1508
- Joined: 2014-01-28, 5:51:54
Ok here's another capture, this time in binary and with a marker for every write. you'll notice that the second byte of data always has the 0x80 bit set, that's because it's /RD.
At the beginning it goes out of sync at some point then it seems to be ok.
Edit: I've fixed the timing code. I was counting up to 3773 at the mcu's clock, which is 168MHz in this case. I've changed it to prescale by 3810 and count up to 65535. This way the timing should be for real. 168000000 / 3810 = 44094.5. Reattached another log. I've noticed that when I hit play on the demo song, it freezes up a bit, I assume the CPU is doing some intensive work and not sending any data to the YM chippo.
Edit 2: Perhaps if we can figure out which messages to ignore, I can reduce the log's size.
Edit 3: I can also log VGM data directly, not sure which commands though.
At the beginning it goes out of sync at some point then it seems to be ok.
Code: Select all
void exti15_10_isr(void) { // trigger on /WR (PD15)
uint16_t w;
if((GPIOE_IDR & GPIO1) == 0) { // check if /CS is on
w = 0xeeee; // marker
_write(1, (char *)&w, 2); // send marker
w = TIM1_CNT; // get samples since last ISR call
TIM1_CNT = 0; // reset timer to zero
_write(1, (char *)&w, 2); // send samples
w = GPIOD_IDR; // get D0-D7, A0-A3, /RD, NC, NC, /WR
_write(1, (char *)&w, 2); // send data
}
exti_reset_request(EXTI15);
}
Edit 2: Perhaps if we can figure out which messages to ignore, I can reduce the log's size.
Edit 3: I can also log VGM data directly, not sure which commands though.
- Attachments
-
- foo.cap.gz
- (309.75 KiB) Downloaded 307 times
- vampirefrog Offline
- Webmaster
- Posts: 1508
- Joined: 2014-01-28, 5:51:54
- ValleyBell Offline
- Posts: 4823
- Joined: 2011-12-01, 20:20:07
- Location: Germany
It's actually emulating 3 of the 16 possible addresses.
I looked at your captured data and made a list of commands and how often they occoured:The first byte is A0-A3/RD/WR, the second byte is D0-D7. The last column is how many times the commands were captured. (in decimal)
It doesn't make sense to be, though. I think there should be a more commands.
I looked at your captured data and made a list of commands and how often they occoured:
Code: Select all
80 18 x3104
82 00 x2330
83 FE x3104
84 03 x109044
86 00 x473003
86 01 x3107
86 AF x3107
87 00 x2325
88 04 x3167
88 3D x35
8B 03 x3104
8B 09 x954
8C 05 x227465
8D AF x701
8D F2 x431
8E 02 x3107
8E 05 x3107
8F 09 x609
8F 8B x3167
8F AF x880
8F C4 x366
8F CC x11
8F CE x45
8F EE x36
8F EF x1524
It doesn't make sense to be, though. I think there should be a more commands.
I think it might be a good idea to enter the TG100 test program and do a capture while executing test #10. It will play a tone on all 28 channels sequentially.
And, yes, I made a similar program to analyze the log and get pretty much the same results as Valley Bell. It seems like there are only 26 unique commands in the log.
And, yes, I made a similar program to analyze the log and get pretty much the same results as Valley Bell. It seems like there are only 26 unique commands in the log.
- vampirefrog Offline
- Webmaster
- Posts: 1508
- Joined: 2014-01-28, 5:51:54
Okay, so I thought that 0x80 bit being set was a little weird, since the code was meant to read it while it was low. It's actually /CS, not /RD. The ISR is a bit slow and reads just after the /CS and /WR lines have gone back to high state, so all that data was bogus. I'll make it so it uses a DMA to read the GPIO port instead, perhaps that'll make it more responsive. This is on an STM32F4 board, here's what it looks like: http://www.ebay.com/itm/STM32F4Discover ... SwOyJX-NcZ
If you look on the scope, you'll see the top signal, yellow, comes a bit after the middle one (cyan). Top is an output pin from the micro, middle is /CS and bottom is /WR.
If you look on the scope, you'll see the top signal, yellow, comes a bit after the middle one (cyan). Top is an output pin from the micro, middle is /CS and bottom is /WR.
So I made a small breakthrough in reversing the program ROM.
Looking at the MAME source, I found out that the YMW258/MultiPCM maps channels in a slightly unusual way. In MAME the channel map table looks like this
i found an equivalent table in the program rom at 0x14e10 to used to convert logical channel numbers to physical (how the chip recognizes them).
This led me to find the write to chip function
(There are also variations of this function to only set the channel and to write data to a register.)
Just like the MAME MultiPCM core, this only uses three addresses to set the channel number, register number and to write the data.
Looking at the MAME source, I found out that the YMW258/MultiPCM maps channels in a slightly unusual way. In MAME the channel map table looks like this
Code: Select all
const int32_t multipcm_device::VALUE_TO_CHANNEL[32] =
{
0, 1, 2, 3, 4, 5, 6 , -1,
7, 8, 9, 10,11,12,13, -1,
14,15,16,17,18,19,20, -1,
21,22,23,24,25,26,27, -1,
};
Code: Select all
ROM:94E10 ChannelMapTable:.byte 0, 1, 2, 3, 4, 5, 6, 8! 0
ROM:94E10 .byte 9, 0xA, 0xB, 0xC, 0xD, 0xE, 0x10, 0x11! 8
ROM:94E10 .byte 0x12, 0x13, 0x14, 0x15, 0x16, 0x18, 0x19, 0x1A! 0x10
ROM:94E10 .byte 0x1B, 0x1C, 0x1D, 0x1E! 0x18
Code: Select all
ROM:81F6A GEW8GetChannelWrite: ! near ! CODE XREF: sub_8264A+25p
ROM:81F6A mov:g.w r4, @-sp
ROM:81F6C
ROM:81F6C loc_81F6C: ! CODE XREF: GEW8GetChannelWrite+5j
ROM:81F6C btst.b #0:8, @unk_800:8 ! check busy flag?
ROM:81F6F bne loc_81F6C:8
ROM:81F71 mov:g.b @unk_3957:16, r4
ROM:81F75 extu.b r4
ROM:81F77 add:q.w #-2, sp
ROM:81F79 stc.b ep, @sp
ROM:81F7B ldc.b #9:8, ep
ROM:81F7E ! assume ep:9
ROM:81F7E mov:g.b @(0x4E10:16,r4), r4 ! Convert channel number to physical
ROM:81F82 ldc.b @sp, ep
ROM:81F84 ! assume ep:nothing
ROM:81F84 add:q.w #2, sp
ROM:81F86 mov:s.b r4, @unk_801:8 ! set channel
ROM:81F88 jsr SmallDelay:16
ROM:81F8B mov:s.b r0, @unk_802:8 ! set register number
ROM:81F8D jsr SmallDelay:16
ROM:81F90 mov:s.b r1, @unk_800:8 ! write data
ROM:81F92 mov:g.w @sp+, r4
ROM:81F94 rts
ROM:81F94 ! End of function GEW8GetChannelWrite
Just like the MAME MultiPCM core, this only uses three addresses to set the channel number, register number and to write the data.
- vampirefrog Offline
- Webmaster
- Posts: 1508
- Joined: 2014-01-28, 5:51:54
- vampirefrog Offline
- Webmaster
- Posts: 1508
- Joined: 2014-01-28, 5:51:54
Okay, I've managed to configure the DMA controller, here's the code for anyone curious, and a new capture. Unfortunately I'm still struggling to get timing information in there (trying to configure a second DMA stream triggered by the same signal to read a timer counter), but I think the data is probably less bogus this time. It starts before the demo song and ends after it.
The capture file format is now: 0xeeee, then 16 words of data. The wiring is now, from LSB to MSB: D0-D7, A0-A3, /RD, /CS, NC, NC. To read the file, ignore words with /CS high. These are captured by DMA, so they should be closer to the truth. I have no way of checking currently, would need a 16 channel logic analyzer.
The capture file format is now: 0xeeee, then 16 words of data. The wiring is now, from LSB to MSB: D0-D7, A0-A3, /RD, /CS, NC, NC. To read the file, ignore words with /CS high. These are captured by DMA, so they should be closer to the truth. I have no way of checking currently, would need a 16 channel logic analyzer.
- Attachments
-
- tg100.c
- (4.32 KiB) Downloaded 279 times
-
- foo.cap.gz
- (2.62 MiB) Downloaded 265 times
- vampirefrog Offline
- Webmaster
- Posts: 1508
- Joined: 2014-01-28, 5:51:54
Here are some more captures, this time with timing. I am using one DMA transfer, without much buffering, but it seems to work well. I was hoping to use DMA entirely but I couldn't figure it out.
Included are test mode 10, startup, idle state and demo song.
Included are test mode 10, startup, idle state and demo song.
- Attachments
-
- startup.cap.gz
- (15.89 KiB) Downloaded 262 times
-
- idle.cap.gz
- (6.7 KiB) Downloaded 267 times
-
- demosong.cap.gz
- (309.28 KiB) Downloaded 274 times
-
- testmode.cap.gz
- (425 Bytes) Downloaded 246 times
- vampirefrog Offline
- Webmaster
- Posts: 1508
- Joined: 2014-01-28, 5:51:54
Here is another capture. It is a few midi notes. See if you can recognize the song.
With this one I've cleared the top bits of the second byte, so it's purely D0-D7 and A0-A3
With this one I've cleared the top bits of the second byte, so it's purely D0-D7 and A0-A3
- Attachments
-
- notes.cap.gz
- (20.51 KiB) Downloaded 268 times