I was mulling over another ad-hoc SPC ROM format for these CPU-only tests, something like <load addr> <exec addr> <code...>, listing why the SPC file format wasn't viable and only for music, but reversed when I realized that the SPC file format is exactly the right thing.
* SPC programs in SPC format, always.
* Do optimizations in tools, rather than format. Quick-upload development can have SPC RAM cleared in advance, and then upload only non-zero portion of SPC, for quick turn-around when developing.
* This format can be run on any SPC player.
* Does a little more than we need, but we can just specify that for tests in this format, only a few fields need to be parsed (initial RAM data and PC, nothing more). Other fields will be valid, so these aren't pseudo-SPC files.
Test programs
* Depend as little as possible on initial conditions: RAM contents, PC, nothing more. Rest is trivial to initialize and easy for incomplete SPC emulators to ignore (e.g. unimplemented DSP).
* Output result in multiple ways: beep codes (for SPC player testing), console output over I/O ports (for running on SNES/development with serial output from SNES), and to $6000 in memory (for CPU-only emulators).
* 64K+ size not a problem in SNES packaging of tests since smallest legal SNES ROM is 128K. Since test programs are mostly zero bytes and a little bit of code, these test ROMs compress where disk space is an issue.
Multi-tests: rejected
In the past I made test ROMs that ran multiple tests in one. I'm abandoning these for all platforms, starting with SPC-700 as I revamp my tests.
* No way to bundle every test for platform into one ROM, so you still have to make an automated test runner, or manually run multiple test ROMs.
* Multi-tests add complexity that cross the line between manageable and unmanageable. Unmanageable doesn't just mean mentally impossible to work with, but that the mental and coding work necessary to keep it working when improving the test framework is not justified by the benefit of supporting multi-tests.
* Test envirnment is different for multi-tests, since previous tests have run, and some tests can't work with it.
* Diagnostic output typically was altered or lessened in multi-tests.
* Extra build scripts. Test roms should be dead-simple to assemble; multi-tests were never such.
From my own personal experience, the SPC format isn't all that hot.
It does not capture 100% of the available state that we now know about. It was basically an emulator save state of ZSNES, and has no real structure, just a binary blob. (It's not even a good music format: had reads from $2140-3 been optionally logged, it could have supported streaming audio games.)
I don't know why jwdonal is writing an SMP-only emulator. The only other device to use this CPU was a Sony VCR. Either you're writing an SPC player or an SNES emulator. For the former, SPC-only test ROMs would certainly help a lot. For the latter, it'd only hurt, as you'd have no obvious output for diagnostics other than pass/fail sound effects. You can of course make up a fake stdout register, if someone really wants to use your tests.
From the perspective of size, 64K should be enough for anybody('s test ROMs), however you won't be able to write CPU<>SMP interaction test ROMs anymore.
If it were imperative to target the SMP directly, bypassing the CPU, I'd rather see a 64K block of data, and absolutely nothing else (no header, no registers, no I/O values, no checksums, nothing.) Execution would begin at 0x0000, all registers would act exactly as if the chip were just power cycled. The IPLROM would be provided by the emulator (and wouldn't even be used unless the test program accessed it on its own.) This would be much easier to add support to in an emulator, and much easier to wrap in a simple "uploader" to run in a standard emulator (eg cat uploader.sfc test.smp > test.sfc) And if you go this route, you could repurpose a special meaning for $f4-f7 (eg set f4-f6 to "DBG", and now f7 acts like stdout), which the CPU "wrapper" program could catch to print diagnostics, and a standalone SMP emulator could easily support for printing to the console.
This format would also be more agnostic: it'd be pure SMP, no DSP regs to unserialize/skip inside the SPC file.
If you did go with this, the comm protocol should be a bit fancier, and have things like an 'end execution' signal, so you could compare the stdout value to a cached "expected" value, support pure binary data, etc.
byuu wrote:
I don't know why jwdonal is writing an SMP-only emulator.
For the same reason anyone makes a 6502 simulator. One reason is to automate unit tests on individual parts of a music engine.
Quote:
And if you go this route, you could repurpose a special meaning for $f4-f7 (eg set f4-f6 to "DBG", and now f7 acts like stdout)
One little problem: how do you distinguish "byuu and blargg" from "byu and blarg"? There needs to be some way for the program on the SMP to "clock" character output.
Quote:
If you did go with this, the comm protocol should be a bit fancier, and have things like an 'end execution' signal
This EOF marker can be either 0x00 (NUL, which terminates a C string) or 0x1A (^Z, which terminates a CP/M or MS-DOS text file), or a special code sent on $F6.
byuu wrote:
The only other device to use this CPU was a Sony VCR.
Although the chip is certainly rare, I think this
doc and the fact the chip is supported in
this IDE shows that it had some more applications besides just SNES and a VCR. A number of VCRs, at least, as there are 9 VCR-on-chip parts listed in the doc.
SPC is great for test ROMs (in addition OF COURSE to a .sfc-packaged version). They don't need its initial state feature, and if you're not writing a SNES emulator, you are pretty much writing some kind of SPC player. As detailed above, the SPC-based test ROMs output as beep codes, console output over the I/O ports (which the SNES wrapper decodes in real-time and prints on screen), and $6000 text output. This allows maximum flexibility in observing the results in various environments, without demanding any features beyond what an SPC player supports.
SPC as a format for SNES music isn't complete and lacks a precise specification of how things are restored and the timing of the last critical things, but fortunately those don't matter for this purpose. If one is just writing SPC parsing for these upcoming test ROMs, one will only need to parse the initial PC and RAM contents, making it little less trivial than parsing some custom format. This is a win all around. I suppose my
"romless" format inspired this, and before that my proposal for an
iNES-based NSF alternative.
> A number of VCRs, at least, as there are 9 VCR-on-chip parts listed in the doc.
Oh, well in that case ... :P
(I actually would like to emulate the SMP interrupt support. Been considering wiring up a physical switch onto the SMP's IRQ line to try and see how the behavior would even work, eg where the interrupt vector address is stored.)
> If one is just writing SPC parsing for these upcoming test ROMs, one will only need to parse the initial PC and RAM contents, making it little less trivial than parsing some custom format.
Well, seems you've already made up your mind before posting once again. Didn't expect us to agree, but at the very least your ideas do intrigue me to implement my own "RAM loader" formats for quick testing, should I ever get around to updating my test ROMs (verging on 8 - 10 years old.)
byuu wrote:
(I actually would like to emulate the SMP interrupt support. Been considering wiring up a physical switch onto the SMP's IRQ line to try and see how the behavior would even work, eg where the interrupt vector address is stored.)
I tried a while back and could never get one to fire, but I might have done it wrong.
byuu wrote:
Well, seems you've already made up your mind before posting once again. Didn't expect us to agree, but at the very least your ideas do intrigue me to implement my own "RAM loader" formats for quick testing, should I ever get around to updating my test ROMs (verging on 8 - 10 years old.)
Yeah, I was only posting so the ideas behind it might be useful to someone else, and in case anyone had any arguments that could compel me to do things differently. I should have made it clear that I wasn't opening the choice of format I used to debate or anything.
This is working nicely too. The tool to extract a custom format for sending to the SNES is trivial; it just starts at the end and works backwards until it hits a non-zero byte, and does the same for the beginning (skipping the $f0-$ff region), then packages up that chunk into a format with the load address and execution address on the beginning, as well as a header signature and CRC for the SNES to check. The CRC needed a custom tool anyway.
tepples wrote:
Quote:
And if you go this route, you could repurpose a special meaning for $f4-f7 (eg set f4-f6 to "DBG", and now f7 acts like stdout)
One little problem: how do you distinguish "byuu and blargg" from "byu and blarg"? There needs to be some way for the program on the SMP to "clock" character output.
Heh. You could have a zero byte signal a divider. But really, I have a protocol that uses another register to signal when a character is ready, and the SPC also waits first if the host has its busy flag set. Using a single register would run into meta-stability issues, where the host reads the register just as it's being changed. Or maybe you could get around that by just re-reading it once you find it's changed, as it'll be stable by that time. So a single-register protocol is probably viable if one wanted to do it.
Quote:
Quote:
If you did go with this, the comm protocol should be a bit fancier, and have things like an 'end execution' signal
This EOF marker can be either 0x00 (NUL, which terminates a C string) or 0x1A (^Z, which terminates a CP/M or MS-DOS text file), or a special code sent on $F6.
Yeah, I use 0x1a. My old Tandy 102 added this to the end of text files, and my text capture tool watched for this, so I naturally started using it for the console output as well. It's a nice way to signal the text capture to stop, so that the next tool in the script can run, like a binary capture.
As for program ending, there's another I/O register value that signals when the program is busy, and when it's done (with its result code, where 0=success, otherwise error code).
> I tried a while back and could never get one to fire, but I might have done it wrong.
I'm near-certain the behavior isn't directly exposed to software at all. If you mean you tried strobing the raw pins on the SMP chip to force one, then that is discouraging. There's no other reason to have SLEEP+STOP instructions, unless there is IRQ support inside this thing.
> I should have made it clear that I wasn't opening the choice of format I used to debate or anything.
Which is of course fine. I do the same thing myself frequently.
byuu wrote:
I don't know why jwdonal is writing an SMP-only emulator.
Umm...huh? Who ever said I was writing an SMP-only emulator? Not sure where you got that from - not to mention it would be pretty boring. I'm writing an SPC player. I'm just implementing one component at a time and verifying each as I go (e.g. implement SPC-700 core, verify, implement S-SMP wrapper around SPC-700 core, verify, implement DSP register interface, verify, implement DSP processing logic, verify, etc). I think that's pretty typical as far as single-person system development goes. This makes development much easier because you know your building atop a rock solid foundation when adding more features.
Test ROMs that can run and verify a specific sub-block of the SPC player without requiring numerous other features to already be implemented is a huge plus. For example, an SPC-700 core test ROM that requires a nearly 100% implementation of the SMP + DSP + 65816 + PPUs + rendering to already be implemented in order to work properly or see any results is totally pointless - and can also be very difficult and time consuming to figure out exactly where the bug is since the system is more complex. I think Blargg's approach to having three different methods of outputting results is extremely effective in this regard.
byuu wrote:
(I actually would like to emulate the SMP interrupt support. Been considering wiring up a physical switch onto the SMP's IRQ line to try and see how the behavior would even work, eg where the interrupt vector address is stored.)
While the SPC-700 processor core does have interrupt support, neither the IRQ nor NMI pins are brought out to any of the pins on the S-SMP wrapper. They are both tied off to their inactive levels internally (i.e. inside the S-SMP chip). You can see the entire schematic and pinout of the device
here. So what/where is this "IRQ line" that you're hooking up to?
The main motivation for switching to a headered format was flexibility in where the code was loaded. Before I had posted some binary files of code that had to be loaded at a specific address. I had since changed where the code was located (now near the end of memory). Rather than have more brittle external information ("if file is larger than X bytes, load it here instead"), I figured I'd add a header with load and execution addresses. But then I realized that SPC does exactly this already, with some other fields that can be ignored/placated. The loading code has no important difference besides file offsets: load header, read execution address, load RAM data, start executing. It's even simpler since the load address is always zero. And the only extra thing needed for the SPC to be usable on SPC players is the beep result code. Since all the output methods could be done without requiring said hardware (i.e. test won't hang if hardware isn't there), this would give me SPC files that could be used with just a CPU, in an SPC player, and loaded by a SNES ROM. The SNES ROM doesn't need to do full SPC loading since these tests only use a subset of functionality, so the loader code is simple, not that involved stuff for playing SPC files on a SNES.
blargg wrote:
Since all the output methods could be done without requiring said hardware (i.e. test won't hang if hardware isn't there), this would give me SPC files that could be used with just a CPU, in an SPC player, and loaded by a SNES ROM.
IMHO, I think this is a fantastic approach to creating test ROMs. It also means the test ROMs have great re-use applications because as the developer slowly adds more and more features they will be able to see the results via the other output methods. For example, right now, I only have the SMP implemented so I rely on checking the result code and result string being written to $6000/$6004. Later on, when I finish implementing the DSP I can run the test again and make sure I get the same result, but now I can listen for the result via the beeps and make sure the tones sound correct. Even further down the line once I implement the CPU<->SMP I/O port interface I can run the test a third time and check the result using that output method while at the same time verifying that my SMP I/O port implementation works properly. It's a win all around.
My take on the output methods:
* $6000 - CPU emulator, nothing more.
* DSP beeps - SPC player, where sound is the only output
* I/O - SNES wrapper, FPGA implementation, automation
The $6000 interface requires extra features not found on hardware/normal emulators, so I see it as a concession for when getting a CPU emulator working. It's also easy to see the output in a debugger's memory viewer. Of course test ROMs aren't useful when building the CPU; a test log of a CPU test ROM is necessary, and I hope to release that along with the CPU test ROMs I'm working on.
The I/O port output is the "cleanest" output, because it uses normal channels of communication (e.g. it could be implemented with a stock SPC-700 module connected to hardware). It's better than sound because it's easily automated into a unit test framework.
Sound is a poor, information-limited approach, but all one can rely on in an SPC player.
blargg wrote:
The $6000 interface requires extra features not found on hardware/normal emulators...
The $6000 interface is great for FPGA implementations if you run your FPGA code in a simulator first - a lot of people don't simulate their code though and instead just program the FPGA and debug from there. But for those that do simulate their FPGA code before targetting the actual hardware (like good boys should
) in a simulator the $6000 interface is great because you can just set a "watchpoint" (using software debugger jargon) on that particular memory location and watch for any changes. Perfect for a CPU-only implementation and is exactly how I used it.
jwdonal wrote:
While the SPC-700 processor core does have interrupt support, neither the IRQ nor NMI pins are brought out to any of the pins on the S-SMP wrapper. They are both tied off to their inactive levels internally (i.e. inside the S-SMP chip). You can see the entire schematic and pinout of the device
here. So what/where is this "IRQ line" that you're hooking up to?
Oh, darn. Was hoping they left the pin on the chip but just tied to ground or something.
So ... anyone want to try partial decapping and tapping the line directly on the die with a tungsten needle?
According to that Sony datasheet, the SPC700 series have up to 4 external interrupt sources and 19 internal sources, with 15 vectors (so some of the sources must share vectors). The block diagram on page 13 (page 14 of the PDF) shows NMI, INT0, INT1 and INT2 pins going into the interrupt controller block, along with inputs from the timers, serial ports, and just about every other peripheral block on the chip. The controller presumably handles masking and priority between all 20-odd sources and determines a vector based on the highest-priority source. In other words, interrupts are nothing at all like a 6502, they're vastly more sophisticated and more like, well, a microcontroller.
Interrupts are pretty much the first thing you redesign when turning a CPU into a MCU. Compare interrupts on the NEC V25/V35 to a standard x86, the architecture they're based on. Or compare the Game Boy CPU, the Z80, and the i8085 to the i8080, which all three are based on. Interrupts are totally different on each of them (although the Z80 and 8085 both support the 8080 interrupt model for backwards compatibility).
Most likely Sony removed the interrupt controller completely from the S-SMP to bring down the transistor count. If there was an interrupt controller on the thing, you'd figure they'd at least hook the timers up to it rather than force you to poll them.
Really, the Break Instuction shared the same vector as TCall 0, with the diffference that you had to use RTI rather than RET to return. I bet all the other interrupts shared vectors with the TCall instructions, on the processors that supported these interrupts. Really wish they would have at least kept IO port interrupts and timer interrupts, as I am sure the processor could have been that much more powerful with these interrupts.