NMK004 dumping notes TODO: - Write documentation for opncap-pc usage DONE: [2014.08.22'14:49] - Hook up some probes to YM2203 [2014.08.22'15:07] - Hook up probes to my Saleae clone to test the ROM [2014.08.22'15:51] - Modify program ROM to automatically go into test mode when booted [2014.08.22'20:07] - Write a testing trojan ROM [2014.08.23'02:40] - Setup FPGA to log YM2203 writes [2014.08.23'05:45] - Make FPGA logger write a packet count to $00000 [2014.08.23'07:16] - Create a 'training' ROM for calibration [2014.08.23'08:33] - Write tool to convert logged YM2203 writes to dumped data [2014.08.23'10:45] - Add command line specification of channel addresses to PC tool [2014.08.23'12:01] - Add 'resuming' binary filenames to command line (and support loading+backup) [2014.08.23'13:06] - Write and test initial trojan ROM by hand to dump some small amount of ROM in the beginning [2014.08.23'15:28] - Make tool support multiple sets of data [2014.08.23'16:xx] - Write tool to generate trojan ROMs [2014.09.05'16:08] - Break out NMK004 stuff from OPNCAP software [2014.09.08'01:08] - DUMP IT [2014.09.12'01:43] - Make trogen not require a base ROM [2014.09.12'20:38] - Write up blog post/s [2014.09.12'21:05] - Write more in-depth information on opncap-fpga's behavior [2014.09.12'21:14] - Clean up opncap-pc a lot --------{{ Working notes/log }}-------- {{ DAY CHANGED TO 2014.08.22 }} [12:23] About to get started, finishing my coffee then going to move the supergun and TV into my room. [12:24] Going to listen to NMK004-based music while I work for motivation. First up: Black Heart. [14:36] Just spent a bit getting my setup together. EPROM eraser had EPROMs jamming it up, had to dismantle it to get them out and get the tray to slide again. Whatever. Setting up the EPROM burner's drivers/software right now. [14:38] Gonna hook up the probes now. [14:49] Probes hooked up, setting up Saleae Logic analyzer now. Also going to burn a test ROM (black heart sound ROM) real quick. [14:53] Actually let's do Vandyke. I love that soundtrack. Probably will sound weird due to sample differences, but w/e. [14:58] Already got Black Heart, whatever. Let's just go. [15:07] Ok, the Saleae can log YM2203 easy, Black Heart ROM works fine, boom. Next I want to make it so I don't need to do that stupid combo on reset. [15:08] That means I should go get IDA! [15:13] Oh wait I don't have it for Windows... :| Guess I'll just make due with the MAME debugger :V [15:22] Code checking for P2 A+B on start @ $5A8. `(IN2 & 3000) == 0, continue, else goto $60A` [15:23] Skip A+B patch: `5A8: 4E71 4E71 4E71 4E71 4E71 4E71 4E71` [15:28] Code for P1 input sequence @ $5D4. [15:28] Skip input sequence patch: `5E0: 4E71 4E71 4E71 4E71 4E71 4E71 4E71 4E71 4E71 4E71 4E71 4E71 4E71` [15:51] Hacked quick-test ROMs complete. [15:52] Time to write a testing trojan ROM! [16:05] Valid 'timing' is within .66667 us [16:09] Starting to write other sections here [16:59] Finished writing a bunch of information on the tables, and wrote out attack vectors. [17:01] Going to write a simple jumper code into the ROM, let's see if we can jump to the target and have it work... [17:16] Didn't work. Instead it's just playing the codes as samples??? [17:26] Setting up the demo ROM now, putting stuff in "easy" places. Gotta set up some simple test commands. [17:27] Going to have it test-dump some simple easy data. [18:03] Demo ROM is done, time to test. [18:06] I was afraid of this... the contents of the LA's dump is mostly 'padding' stuff and the data can't be found within it... [20:06] Ok, figured it out; I really do have to pay attention to all of the strobes. Not going to be able to pick out the data with the LA though, there's too much stuff and I only have 8 lines to analyze with. Time to write FPGA code. [20:09] Need to install Quartus II still, oops. [23:50] Starting on wiring and writing VHDL now. {{ DAY CHANGED TO 2014.08.23 }} [00:05] Wiring complete, VHDL time now~ [00:45] Finished writing initial probably non-compiling code, attempting compile now. [00:45] Oh right, VHDL uses /= for "not-equal" [01:00] Got it compiling pretty quick, but it's not advancing the write pointer at all... [01:03] Added some debug LEDs, not helping much... my counter advancement logic is probably fucked a bit [01:07] Still dunno what the deal is... [02:24] Seems like it mostly works :D Need to bother to pull the data out of SRAM real quick... [02:26] I'll implement the "usable address" filter first I think. [02:33] Wow, the filter removed all "upkeep" poke noise. PSG pokes are only done when channels are playing! [02:33] Dumping out saved data from the test now, we'll see how correct it is... [02:39] It's totally valid! It has a bunch of duplicate and screwy copies, but mostly valid! [02:39] Going to clean up the output before doing anything more. [02:56] Ok, cleaned up a bit. Probably won't be able to get any better. Further cleaning can be done host-side. [02:57] Fears are confirmed, PSG tone is 12bit, PSG volume is 4bit. Grr. [03:00] oh actually, I might be able to extract from the volume table anyways by looking just at timings. [03:00] it's only 8 bits this time, so no 9+ hour dumps [03:00] and the huge stride of the volume table means a lot could be dumped at once [03:08] hm... volume length 0 is the same as 1 [03:08] but provided I dump each section twice, as I'd have to (length and actual volume are interlaced) [03:08] I can retrieve the actual length byte :) [03:10] I think I'm confirmed that I'll attack the PSG volume table. [03:11] Dump rate can be 3x as fast as "normal" due to 3 PSG channels. wheeeeeeeee [03:22] Going to make a private Git repository with the current code. [03:34] Code uploaded. Half-considering bed, but I get the feeling I wouldn't sleep much anyways with all this caffeine in me. [03:40] Writing PC tool to analyze dumped data. [04:08] Changed transaction check in FPGA code to use rising_edge(opn_cs_n), should remove stupid "bad" transactions [04:52] Got tons of the PC tool done, but crashes when I try it. Installing GDB in msys2 now. [05:02] Nothing printf debugging couldn't fix. Forgot that realloc doesn't take a pointer to a pointer. [05:10] Ok, the crunched data looks spot on. Time to split the code up a bit. [05:20] Nicely split, now I need to write some analysis stuff so that I can extract data. [05:21] First just make it print out the data nicely. [05:43] Modified FPGA code to write out the packet count [05:59] Modified code works great, lowering the sample rate seems to have helped out with glitching too [06:00] Going to push up the current PC code now, since it can properly parse the output [06:46] Wrote up a good training ROM I think, now burning it and then going to test it. [06:56] Ok, training makes stuff easier. When having all sets dump out, each set starts with the note setting, then first volume setting [07:04] Verified that 0 length is same as 1 length. First volume setting is ~2500 ticks shorter due to optimization or something [07:16] Now have a test ROM+dump with a "normal" case, including "find the 00/01" [08:01] Got the dumper program to properly analyze all of the output, on 3 channels. [08:02] Next on the list is to make it "recombine" the data. [08:33] Recombination is working well! I want to make it now support loading and saving these files. [08:34] Also would be good to have address specification on command line! [08:40] Going to clean up this log a bit now, then probably shower. I feel a bit grody. [10:45] Added address specification on command line. [11:21] While debugging some weird issue, I noticed a new behavior! Volume tables wrap every $100 bytes!!! [11:21] This could be used HEAVILY in our favor! Now we know that we can't run off into the sticks! We get $80 dumped sectors per volume table. [11:39] Actually it seems $7F is a bit glitchy... let's just cut it at $7F then... [11:45] No it's not, I'm a fucking toolbag. [11:53] Hrm I guess it actually is... weird. [12:01] I think we're about ready to try pointing a ROM at the internal ROM. After lunch. [12:42] Just started the internal ROM dump attempt. Let's see where this goes~ [13:04] Holy shit it worked, and it worked _FAST_. Maybe 2 minutes for the full set. [13:04] Since we're only doing $7F, we need to start the next on $FC. [13:05] Need to develop a way to dump more than a single volume table per ROM. Should be easy I think. Needs support in the tool though. [13:45] I like showing off, I think. [14:26] Starting to add support for multiple tables. [14:40] I think the new support should work, doing a dump right now though. [15:27] I think we've got some memory corruption going on, but I've worked around it. Multi-dumps work now~ [15:28] Last up, a ROM generator. [16:46] Oops, don't remember when I finished that. Was quick anyways. Started dumping a multi-dump. [16:46] Turns out we may not have enough space for an 8-fer, 6 at the least is ok though. [16:47] 100110111010001011 is the bit pattern after 6. [16:57] After dumping 7, looks like we would have been able to fit a 7th. [16:59] Even 8 probably would have fit. [17:03] Confirmed 8 will fit. Woohoo. {{ DAY CHANGED TO 2014.08.24 }} [13:49] Need to find a new place to put my setup, my bed wasn't a good spot. [13:49] Shortened to length of each volume table's "valid" area; no reason to get greedy. {{ DAY CHANGED TO 2014.09.04 }} [17:50] I want to get back to this. Let's write some documentation first though. [17:52] Finished cleaning up this log. Let's write documentation in the OPNCAP repository as markdown. [18:40] Started on documentation, including pinouts and stuff. Gotta get some food now though. [19:40] Back, going to continue on documentation [22:59] About done with what I wanted to document. I want to split up OPNCAP and the NMK004 stuff now though... :< [22:59] I'll do that tonight, and maybe work on actually dumping tomorrow. [23:10] All pushed up. {{ DAY CHANGED TO 2014.09.05 }} [13:06] Didn't do the splitting last night, going to start on that now. [14:26] Actually I'm doing documentation AND splitting. [14:54] I now feel satisfied with quality of documentation. Back to work on splitting. [16:08] Ok, splitting is complete, documentation is pretty much done. [18:41] Writing blog post now. [19:34] Blog post posted. [22:39] Tomorrow I will dump the ROM after moving the CRT to my room. {{ DAY CHANGED TO 2014.09.06 }} [17:31] Writing more words. Welp. {{ DAY CHANGED TO 2014.09.07 }} [01:09] Progress is slow. Will is low. Maybe I should actually go do the dump. [01:09] I can't ride this wave of writing forever. It's starting to get a bit stale even. I probably should just do the dump already. Should rebuild my setup somewhere. Kitchen table? Sounds good. [01:10] Kitchen will be uncomfortable... maybe I should see if I can manage to put stuff on my desk. Maybe do some rearranging. [01:16] Yes, rearranging my desk is a great idea. Doing so now. [13:45] Holy fuck it's hot. Let's hope I feel like doing the dump now. [13:56] Sure do. Let's trogen a ROM real quick. [14:13] Started the dump a few minutes ago, into second bank now. [14:20] Started third bank now. [14:26] Started 4th bank. [14:35] Started 5th [14:42] Started 6th, just over half full now. [14:50] Starting 7th. [14:56] Starting 8, hopefully we will not overflow the SRAM... [15:02] The dump is done. let's extract it now. [15:11] Extracted. Gonna watch the rest of GCCX before continuing on. [15:44] Ok, let's reconstruct. [15:53] Turns out we have some bugs :V fixin' [15:56] First set of missing data: $209-$240 [15:57] Next: $396-$3C0, more at $47A-$480 [15:58] Again at $5E6-$600, more at $763-$780 [15:59] These errors are all around mismatching nibs... [16:24] Fixed it, got a good dump of $900 bytes, now doing 89ABCDEF. [16:29] Starting 9. [16:36] Starting A. [16:42] Starting B. [16:52] Starting C. [16:59] Starting D. Almost half full. [17:00] ACTUALLY I SUCK COCKS IT FILLED RIGHT THE FUCK UP. [17:02] Something's blowing this right the fuck up. Ack. [17:05] Sectors D and E seem to be mostly 0s, which is blowing up my storage method. Let's try to just skip them for now. grr. [17:06] Re-dumping 8. [17:12] Re-dump 9. [17:15] Off to dinner. [18:04] back, time to dump A. [18:10] Starting B dump [18:17] I might as well skip C-F because they'll be messed up due to D/E. [18:17] Extraction time I guess. [19:23] Burned ROM for set 10-17 [19:32] Starting 10. [19:38] Now 11. [19:53] Now 12. [20:00] Now 13. [20:18] Now 14. [20:26] Now 15. [20:33] Now 16. [20:41] Now 17. [20:48] Done with that set. Extraction now. [20:58] Extracted. Burning next ROM. [21:00] Starting 18. [21:06] 19 [21:20] 1A [21:26] 1B [21:33] 1C [21:39] 1D [21:47] 1E [21:52] Holy crap I hope this doesn't overload... :| [21:53] need to extract on next go. will cut the dump if I think it's about to overload. [21:53] ha... that was close. time to extract [22:00] Ok, extracted, dumping the last sector now then. [22:06] Done. I just realized I didn't need that because lol 0x900 per ROM. [22:07] Gonna extract it anyways. [22:23] Ok, let's hack my hack ROM to be a lot shorter. then I probably just record one at a time... [22:27] LET'S GO [22:28] Dumping C [22:34] C is done, let's hope D won't overflow. [22:34] Goddamn that's fast ;_; [22:35] Oh god I'm dead [22:36] Welp. I cut it short, let's analyze after extraction [23:00] Yup, works great. w [23:11] Extracted E, dumping F now. I kinda wanna re-do it though, have E dump until where I know F ends, then do F. Combined 2x is so much easier to deal with... [23:19] Redoing it so I can have EF combined. [23:25] Just realized I fucked up the hacked ROM. gdi [23:26] Whatever. Resuming on F. {{ DAY CHANGED TO 2014.09.08 }} [00:28] Combining and finishing the dump now... :O [00:46] Hory shit pisssssssss it seemed to have worked. Wow. [01:08] Welp. Now what. [01:09] Guess I should write blog posts. Or maybe make the ROM do stuff in MAME. [01:10] For now, I'm gonna chill out, drink my beer and watch some GCCX. [20:59] Finally compiled, sound was certainly too fast. Should be clocked at 3MHz, not 8. [21:02] For reference, here are the unverified nibs: 0FBF 13FF 165A 1AA0 1B94 1BAE 1D32 1E83 [21:41] Found the data sheet for the MCU. Let's dissect! [21:41] The mystery word at EFFE is actually two bytes that get loaded into the MCU's internal regs. EFFE -> TREG0, EFFF -> TREG1 TREG0 = b@EFFE TREG1 = b@EFFF TREG2 = $7D TREG3 = $7D T4MOD = $06 TREG4 = $1234 TREG5 = $1234 TRUN = $23 [21:48] $EFFC gets copied into RAM $FF30 [21:49] $EFFA.b is used at DE7, loaded into C [21:56] $EFFB.b is used as a loop count for a null-wait? used at E39 [21:57] $EFFA.b is used a loop count actually, for the outer loop around EFFB. weird [22:16] $FF30 is used as some counter loop {{ DAY CHANGED TO 2014.09.09 }} [01:06] Messing with volumes now, PSG:0.50,FM:1.20,OKI:0.10 seems right for td at least [01:12] Mustang sounds good with that too. [01:16] Black Heart as well. Gonna try some Yoshio Nagashima stuff now. [01:26] I thought Vandyke was messed up, but that's correct there too. [01:29] In-game still sounds really weird... need to check PCB :| [01:30] Holy fuck those cavemen really do sound horribly fucked up on a real board... oh well [01:32] Strahl soundtrack: http://www.nicovideo.jp/watch/sm10732832 [01:37] holy fuck that guitar shouldn't actually be a guitar [01:37] What the fuck kind of sorcery is this!? [02:01] I'm declaring it a possibly bad dump and moving on. [02:29] Or I'm not. It's actually a banking issue. Yay! [02:53] I think I figured out the banking algorithm. I think I'll look through the MCU code if I can verify [02:55] If it's true, I gotta fix up a bunch of ROM defs ~_~ [03:21] Nope, it's just some address line twiddles on Strahl. Still annoying. [03:38] I feel confident that this is all working, going to let Macaw stream it. [12:50] So, Strahl was messed up again in the version I sent, made a stupid typo. Now it's fixed [12:51] Going to dump Hacha Mecha Fighter bootleg. [12:59] 7 came out and dumped easy. 8 refused to leave its socket without serious work, and the chipID is wrong. [12:59] Dumped 8 regardless, data looks right... [13:36] Weird weird issues. I've sent Haze the ROMs, I don't feel like dealing with it right now. [13:36] Going to start writing next blog post/s, and collecting stuff together. [13:39] Actually, let's get comments on nanoblogger working first. [15:46] Ok cool, comments are a go. I think I'll start with the write-up about my first attempt first. [18:04] Done writing blog003 for the most part, I just need some people to proof it first, then good to go. {{ DAY CHANGED TO 2014.09.10 }} [05:18] Fixed the IRQ issue, need to see what the nmi_w poke actually does. [22:33] Let's do some cleanup and merge in Haze's stuff for hachamfb [22:47] Merged in Haze's stuff, let's make sure hachamfb works now [23:08] Yup, everything's working all good. [23:18] In Haze's notes, he mentions that there is a timer counting at $FF30 and when that expires, sound gets killed. [23:19] $FF30 is that value copied from $EFFC.... [23:24] There's a function to reload the value at $79, and a function that decrements the counter (and a bunch of stuff) at $82. [23:25] If $FF30 reaches zero in that function, it pushes 1 to P4 and jumps to 0. (code at $A7) [23:28] Function at $82 is jumped to by $38 (INTT1 handler). [23:32] Function at $79 is jumped to by $18 (NMI handler). [23:33] P4 is the port poked whenever weird stuff happens, let's look at what can be written to it. [23:33] It's a 4-bit port set to output only, is exposed on the MCU's pins. *breaks out the tester* [23:36] On each iteration of $82, P4.3 is flipped [23:37] On init, P4.0 does 0,1,0 at $188 code [23:40] That seems to be all. Let's probe those pins then! [23:41] P4.3 is NC... [23:42] P4.0 is a through via [23:49] I can't find where the via ends... [23:52] Found it! IC108.2 [23:54] That IC is a dual positive-edge-triggered D-type flipflop (74ls74) [23:55] That pin is D1, Q1=.5, /Q1=.6 [23:58] /Q1 Goes to IC109.12, another 74ls74, this time D2. {{ DAY CHANGED TO 2014.09.11 }} [00:03] Q2 goes to IC110.1, is a 74ls86 (OR gate) [00:04] Output goes to: IC107.1 (74hc04), a hex inverter [00:07] Probe ran out of battery. [00:12] Output of 107.2 goes to 109.3, D2 [00:21] Q2 to IC107.9, and that output goes to the 68k's /HALT+/RESET line [00:27] Final result: P4.0 will force a 68k reset when raised high. [00:30] Sent Haze a PM about this, now let's trace NMI [00:35] NMI goes to IC82.8 (74hc04) [00:37] IC82.9 goes to via under IC77, then IC24.6 (NMK005) [00:47] Well that... sucks. Maybe the NMI poke is done by the 68k? [00:50] From a quick debug in MAME, that certainly seems the case. Every half-frame it raises and lowers NMK005_BASE+17's bit0. [01:06] Doing final cleanup before sending the final to Haze! [01:50] Archiving up the full source... [17:51] Haze hooked it up for the most part, apparently Black Heart doesn't poke that byte? Will check it out. [17:51] Haze did send his source tree for it hooked up, let's try to fix it. [17:59] Yup, Haze had it all hooked up, just also added the old hack back. [18:52] Ok, Black Heart indeed resets. let's check it out [19:10] Wow, I can't find anything that could possibly kick the NMI O_o [19:46] UPL Gravedigger confirms that the $80016 port is indeed the sound CPU NMI. Now why is it not triggered... [20:08] From looking at a decent PCB pic of Gomorrah, the same pin seems connected to the NMI. So why isn't the game poking it? [20:16] Hurr, of course it's MAME incompetence. IRQ2 kicks the NMI on those games, and is not hooked up at all in MAME. [21:00] Sent Haze all my stuff, hopefully he'll be able to hook up the IRQs as I mentioned. [21:12] Looking at the possible invalids, only $FBF could matter. [21:19] Huh... it almost sounds like Gomorrah's music is too low pitch. PCB recording please. [21:25] Yup, definitely. [21:31] Simple fix, the pin7 setting was wrong. {{ DAY CHANGED TO 2014.09.12 }} [00:32] Hmm. [00:34] I'm gonna make trogen not require a base ROM. [01:43] Trogen now cleaned up, and documentation is improved. [02:06] Haze got back to me, apparently working on the timings made stuff worse, but he made a macro so it should be easier to change now [02:06] He also added a driver-specific hack to make bio-ship paladin/stuff work. [02:14] Gonna try to fix up the timings I think [02:31] Dunno what he meant about the timings making stuff worse, but I'm gonna see why bioship takes so long to poke the NMI [02:35] It only pokes it every $400 vblanks??? [02:42] Seems good enough for the demo, but during gameplay it resets... [02:52] I have no idea... maybe the TLCS-90 emulation is too fast? [03:02] I don't think it's worth me spending any more time delaying the release for this. [03:02] Going to bed now, tomorrow I will write blog post 4. [12:43] Haze added sprite buffering and cleaned up the timings a bit. Let's look it over. [15:00] Needs another frame of sprite buffering, but otherwise it's good and I approve. MAME changes are done then. [15:16] Starting on post 4. [20:07] Finished and posted. That feels great. Guess I should start on post 5, not gonna post it until tomorrow though. [20:38] And the last post is done. [20:38] Gotta do all that cleanup on OPNCAP still though ;_; [20:54] Finishing up the opncap-fpga documentation first. [21:04] Finished the opncap-fpga docs. [21:18] I'm done. It's over. I'll release these notes along with everything else, because why not. [21:19] Huzzah... --------{{ Reconstruction log }}-------- trap15@wildsnail /c/Users/trap15/fpgadev/nmk004-trojan.git/opnrom $ ./opnrom.exe ../../../projects/nmk004/dumps/01234567.bin ../../../projects/nmk004/final/nmk004.bin ../../../projects/nmk004/final/nmk004_mask.bin 0 Reset chan 0x1004081c0: base:0000 sets:0 lastprog:0 Reset chan 0x1004087e0: base:FFFF sets:0 lastprog:0 Reset chan 0x100408e00: base:00C0 sets:0 lastprog:0 Reset chan 0x1004081c0: base:00BF sets:0 lastprog:96 Reset chan 0x1004087e0: base:0180 sets:0 lastprog:96 Reset chan 0x100408e00: base:017F sets:0 lastprog:96 Reset chan 0x1004081c0: base:0240 sets:0 lastprog:96 Reset chan 0x1004087e0: base:023F sets:0 lastprog:96 Reset chan 0x100408e00: base:0300 sets:0 lastprog:96 Reset chan 0x1004081c0: base:02FF sets:0 lastprog:96 Reset chan 0x1004087e0: base:03C0 sets:0 lastprog:96 Reset chan 0x100408e00: base:03BF sets:0 lastprog:96 Reset chan 0x1004081c0: base:0480 sets:0 lastprog:96 Reset chan 0x1004087e0: base:047F sets:0 lastprog:96 Reset chan 0x100408e00: base:0540 sets:0 lastprog:96 Reset chan 0x1004081c0: base:053F sets:0 lastprog:96 Reset chan 0x1004087e0: base:0600 sets:0 lastprog:96 Reset chan 0x100408e00: base:05FF sets:0 lastprog:96 Reset chan 0x1004081c0: base:06C0 sets:0 lastprog:96 Reset chan 0x1004087e0: base:06BF sets:0 lastprog:96 Reset chan 0x100408e00: base:0780 sets:0 lastprog:96 Reset chan 0x1004081c0: base:077F sets:0 lastprog:96 Reset chan 0x1004087e0: base:0840 sets:0 lastprog:96 Reset chan 0x100408e00: base:083F sets:0 lastprog:96 trap15@wildsnail /c/Users/trap15/fpgadev/nmk004-trojan.git/opnrom $ ./opnrom.exe ../../../projects/nmk004/dumps/89AB.bin ../../../projects/nmk004/final/nmk004.bin ../../../projects/nmk004/final/nmk004_mask.bin 0x900 Reset chan 0x1004081c0: base:0900 sets:0 lastprog:0 Reset chan 0x1004087e0: base:08FF sets:0 lastprog:0 Reset chan 0x100408e00: base:09C0 sets:0 lastprog:0 Reset chan 0x1004081c0: base:09BF sets:0 lastprog:96 Reset chan 0x1004087e0: base:0A80 sets:0 lastprog:96 Reset chan 0x100408e00: base:0A7F sets:0 lastprog:96 Reset chan 0x1004081c0: base:0B40 sets:0 lastprog:96 Reset chan 0x1004087e0: base:0B3F sets:0 lastprog:96 Reset chan 0x100408e00: base:0C00 sets:0 lastprog:96 Reset chan 0x1004081c0: base:0BFF sets:0 lastprog:96 Reset chan 0x1004087e0: base:0CC0 sets:0 lastprog:96 Reset chan 0x100408e00: base:0CBF sets:0 lastprog:96 trap15@wildsnail /c/Users/trap15/fpgadev/nmk004-trojan.git/opnrom $ ./opnrom.exe ../../../projects/nmk004/dumps/CD.bin ../../../projects/nmk004/final/nmk004.bin ../../../projects/nmk004/final/nmk004_mask.bin 0xD80 Reset chan 0x1004081c0: base:0D80 sets:0 lastprog:0 Reset chan 0x1004087e0: base:0D7F sets:0 lastprog:0 Reset chan 0x100408e00: base:0E40 sets:0 lastprog:0 Reset chan 0x1004081c0: base:0E3F sets:0 lastprog:96 Reset chan 0x1004087e0: base:0F00 sets:0 lastprog:96 Reset chan 0x100408e00: base:0EFF sets:0 lastprog:96 trap15@wildsnail /c/Users/trap15/fpgadev/nmk004-trojan.git/opnrom $ ./opnrom.exe ../../../projects/nmk004/dumps/EF.bin ../../../projects/nmk004/final/nmk004.bin ../../../projects/nmk004/final/nmk004_mask.bin 0xFC0 Reset chan 0x1004081c0: base:0FC0 sets:0 lastprog:0 Reset chan 0x1004087e0: base:0FBF sets:0 lastprog:0 Reset chan 0x100408e00: base:1080 sets:0 lastprog:0 Reset chan 0x1004081c0: base:107F sets:0 lastprog:96 mismatching nib! 1 Adr0FBF,0. old:8, new:0 new code is more likely, writing. old:6, new:E Reset chan 0x1004087e0: base:1140 sets:0 lastprog:96 Reset chan 0x100408e00: base:113F sets:0 lastprog:96 trap15@wildsnail /c/Users/trap15/fpgadev/nmk004-trojan.git/opnrom $ ./opnrom.exe ../../../projects/nmk004/dumps/1_01234567.bin ../../../projects/nmk004/final/nmk004.bin ../../../projects/nmk004/final/nmk004_mask.bin 0x1200 Reset chan 0x1004081c0: base:1200 sets:0 lastprog:0 Reset chan 0x1004087e0: base:11FF sets:0 lastprog:0 Reset chan 0x100408e00: base:12C0 sets:0 lastprog:0 Reset chan 0x1004081c0: base:12BF sets:0 lastprog:96 Reset chan 0x1004087e0: base:1380 sets:0 lastprog:96 Reset chan 0x100408e00: base:137F sets:0 lastprog:96 Reset chan 0x1004081c0: base:1440 sets:0 lastprog:96 Reset chan 0x1004087e0: base:143F sets:0 lastprog:96 mismatching nib! 2 Adr13FF,0. old:E, new:F new code is more likely, writing. old:6, new:F Reset chan 0x100408e00: base:1500 sets:0 lastprog:96 Reset chan 0x1004081c0: base:14FF sets:0 lastprog:96 Reset chan 0x1004087e0: base:15C0 sets:0 lastprog:96 Reset chan 0x100408e00: base:15BF sets:0 lastprog:96 Reset chan 0x1004081c0: base:1680 sets:0 lastprog:96 Reset chan 0x1004087e0: base:167F sets:0 lastprog:96 mismatching nib! 2 Adr165A,0. old:F, new:E old code is more likely, skipping. old:E, new:7 Reset chan 0x100408e00: base:1740 sets:0 lastprog:96 Reset chan 0x1004081c0: base:173F sets:0 lastprog:96 Reset chan 0x1004087e0: base:1800 sets:0 lastprog:96 Reset chan 0x100408e00: base:17FF sets:0 lastprog:96 Reset chan 0x1004081c0: base:18C0 sets:0 lastprog:96 Reset chan 0x1004087e0: base:18BF sets:0 lastprog:96 Reset chan 0x100408e00: base:1980 sets:0 lastprog:96 Reset chan 0x1004081c0: base:197F sets:0 lastprog:96 Reset chan 0x1004087e0: base:1A40 sets:0 lastprog:96 Reset chan 0x100408e00: base:1A3F sets:0 lastprog:96 mismatching nib! 2 Adr1AA0,0. old:F, new:E old code is more likely, skipping. old:E, new:7 trap15@wildsnail /c/Users/trap15/fpgadev/nmk004-trojan.git/opnrom $ ./opnrom.exe ../../../projects/nmk004/dumps/1_89ABCDE.bin ../../../projects/nmk004/final/nmk004.bin ../../../projects/nmk004/final/nmk004_mask.bin 0x1B00 Reset chan 0x1004081c0: base:1B00 sets:0 lastprog:0 Reset chan 0x1004087e0: base:1AFF sets:0 lastprog:0 Reset chan 0x100408e00: base:1BC0 sets:0 lastprog:0 Reset chan 0x1004081c0: base:1BBF sets:0 lastprog:96 mismatching nib! 1 Adr1B94,0. old:F, new:E old code is more likely, skipping. old:D, new:6 mismatching nib! 1 Adr1BAE,0. old:F, new:E old code is more likely, skipping. old:D, new:6 Reset chan 0x1004087e0: base:1C80 sets:0 lastprog:96 Reset chan 0x100408e00: base:1C7F sets:0 lastprog:96 Reset chan 0x1004081c0: base:1D40 sets:0 lastprog:96 Reset chan 0x1004087e0: base:1D3F sets:0 lastprog:96 mismatching nib! 2 Adr1D32,0. old:F, new:E old code is more likely, skipping. old:E, new:7 Reset chan 0x100408e00: base:1E00 sets:0 lastprog:96 Reset chan 0x1004081c0: base:1DFF sets:0 lastprog:96 Reset chan 0x1004087e0: base:1EC0 sets:0 lastprog:96 Reset chan 0x100408e00: base:1EBF sets:0 lastprog:96 mismatching nib! 0 Adr1E83,0. old:E, new:F new code is more likely, writing. old:7, new:D Reset chan 0x1004081c0: base:1F80 sets:0 lastprog:96 Reset chan 0x1004087e0: base:1F7F sets:0 lastprog:96 Reset chan 0x100408e00: base:2040 sets:0 lastprog:96 --------{{ Chosen attack vector }}-------- - PSG volume table - Dumps 4+8 bits at a time. - Might even be able to extract length from the data... - Length 0 and 1 are the same, but we can work around this. - Has a large range of entries per ROM I think - Might take a bit, but being 8bit lengths, shouldn't be too crazy - Could multiplex on the channels too, since we're not actually looking at the output sound --------{{ Possible attack vectors }}-------- - PSG note table - Dumps 12 bits at a time, needs two passes to get both bytes - Only has a range of 16 entries each ROM. - PSG volume table - Dumps 4+8 bits at a time. - Might even be able to extract length from the data... - Length 0 and 1 are the same, but we can work around this. - Has a large range of entries per ROM I think - Might take a bit, but being 8bit lengths, shouldn't be too crazy - Could multiplex on the channels too, since we're not actually looking at the output sound - FM note table - Dumps 16 bits at a time - Only has a range of 16 entries each ROM. - Note length table - Dumps 16 bits at a time - Has a range of 128 entries each ROM. - Can take FOREVER - OKI sample table - Not very usable... - FM modulation table - Can dump 8 bits a time (16 bits if careful) - Tricky to use - Has a HUGE range of entries each ROM. - Can be accidentally interrupted by specific values... - Probably not usable... - Timer2 tables - Unknown what timer2 even does, so not too helpful - $EFFE pointer - Might be a code pointer - Would take some investigation... - Could be the jackpot though - Or... not... wat fak --------{{ Formatting }}-------- TLCS-90 CPU Everything is in little endian! Can we do unaligned access then? Seems like ROM is used as an overlay. Address map is probably something like this: Addr. | Size. | Description ------|-------|----------------- $0000 | $2000 | Internal ROM/RAM $2000 | $B000 | External ROM, no address shifting (so $EFF0 on accessed address is $EFF0 on ROM) $F000 | $0EC0 | External stuff I thought it was starting at $4000, but black heart uses stuff at $2xxx, and has data starting there. Hacktables: EFE8: Note length: C000 EFEE: PSG volume: C040 C060,C080,C0A0,C0C0,C0E0 EFF2: PSG note: C100 EFF0: Cmds: D000 Vol0: AA,01, 55,02, AA,03, 55,04, AA,00, 55,05, AA,FF Notelen0: $80 Cmd0: D100 -320a Cmd1: D200 -325d 6: D210 7: D250 8: D290 $00 27654 $01 30251 $02 60479 $04 120958 $08 241917 $10 483835 $20 967666 $40 1935328 $80 3870666 $FF 7711080 $10 483836 D210: Set volume table 0 Note $00, length entry 0 End D250: Set volume table 1 Note $01, length entry 0 End D290: Set volume table 2 Note $02, length entry 0 End Pointer table @ $EFE0 Addr. | Description ------|----------------- $EFE0 | OKI-A's sample table, 16bit | Index here is sample number to play | Taken as bitfield: | 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00 | | Sample number |F.| Vol. |Bank | Chan| | F. will force the sample to be played, even if the channel is playing something. | - Vandyke: 4109 | - TDragon: 4E0E | - B.Heart: 2E09 $EFE2 | OKI-B's sample table | See OKI-A's sample table info | - Vandyke: 4189 | - TDragon: 4F0E | - B.Heart: 2F09 $EFE4 | FM modulation table, 16bit | Is a table of pointers to real modulation tables. | Index here is modulation table number-1. | First value in each table is timer. | Too complex to do anything decent with. | - Vandyke: 4209 | - TDragon: 498A | - B.Heart: 2AA3 $EFE6 | FM note period table | Index here is FM note's bottom 4 bits. | Note period = result | ((octave + (note>>4)) << 11) | - Vandyke: 40D9 | - TDragon: 4DDE | - B.Heart: 2DD9 $EFE8 | Note length table, 16bit | Index is 7bits. | Table of length to wait for next note. | - Vandyke: 4419 | - TDragon: 47CE | - B.Heart: 28E7 | - HACKED: C000 $EFEA | Note subtimer table A, 16bit | Index is 7bits. | Table of FM's timer2 durations. | - Vandyke: 4459 | - TDragon: 48AC | - B.Heart: 29C5 $EFEC | Note subtimer table B, 16bit | Index is 7bits. | Table of FM's timer2 durations. | - Vandyke: 4499 | - TDragon: NULL | - B.Heart: NULL $EFEE | PSG volume table, 16bit | Is a table of pointers to real volume tables. | Index here is "volume shape", so this is used for enveloping. | Each table is a pair of volume (8bit) and length (8bit). | Data is written to $08+ch, but is only the bottom 4 bits? :/ | - Vandyke: 42DF | - TDragon: 4A66 | - B.Heart: 2B7F | - HACKED: C040 $EFF0 | Command table, 16bit | Is a table of pointers to each code's command list. | Index here is the code. | If top 8 bits of the command list pointer is 0, is just a single OKI sample | - Vandyke: 44D9 | - TDragon: 500E | - B.Heart: 3009 | - HACKED: D000 $EFF2 | PSG note table, 16bit | Index here is PSG note's bottom 4 bits, result is LSR by top 4 bits. | Only bottom 12 bits written? :/ | - Vandyke: 40F1 | - TDragon: 4DF6 | - B.Heart: 2DF1 | - HACKED: C100 $EFF4 | ? | - Vandyke: NULL | - TDragon: NULL | - B.Heart: NULL $EFF6 | ? | - Vandyke: NULL | - TDragon: NULL | - B.Heart: NULL $EFF8 | Information pointer??? | - Vandyke: EF00 | - TDragon: EF00 | - B.Heart: EF00 $EFFA | ? | - Vandyke: 05 | - TDragon: 01 | - B.Heart: 01 $EFFB | Waits required for bankswitch logic | - Vandyke: 20 | - TDragon: 20 | - B.Heart: 20 $EFFC | Watchdog timer length | - Vandyke: 1000 | - TDragon: 0800 | - B.Heart: 0800 $EFFE | Base tempo (in clocks/16) | - Vandyke: 013B | - TDragon: 013B | - B.Heart: 013B