-
Content Count
7,205 -
Joined
-
Last visited
-
Days Won
8
Content Type
Profiles
Member Map
Forums
Blogs
Gallery
Calendar
Store
Everything posted by Tursi
-
>A072 is not that instruction in the screenshot you posted... Show me a screenshot on the breakpoint. >A070 is the address causing the warning, that you didn't expect to be executing. How did the PC get there, is the question I think needs to be answered.
-
Okay, I understand what you are saying, but you didn't provide enough of the software for us to analyze the problem. Put a breakpoint at >A070, and then you can see a trace of exactly how it got there. That usually solves the question.
-
Didn't we go over this in another thread some time ago? So first off - assume that the reported PC might be late - it's reporting the program counter when the access happens... there's a good chance the instruction was already parsed and the PC incremented. Looking at the code, we can see that >A072 is unlikely, but >A070 looks pretty likely. So is it right? Is the interrupt mask 2 when VDP is read at >A070? That's all the warning is telling you. "There seems to be no side effects"... when you access the VDP with interrupts enabled, then 60 times a second there is a chance that the console interrupt will take control and potentially corrupt your VDP address. If your code takes a full millisecond to execute, then pure chance says that 15 times out of 16 it will run just fine. The nature of software when the VDP address unexpectedly changes means that there's a good chance you won't even notice as the end user about half the time, so now we're saying you won't notice at least 30 times out of 32. Most access blocks are faster than a millisecond, meaning the odds of actually being hit are even smaller. But race conditions are bad, and eventually, they always get hit. The warning is in the emulator because it's bad practice, and you probably shouldn't do it. But if you do do it, then don't blame the emulator if it breaks - whether it breaks in emulation or on hardware. Of course, as implemented the warning isn't perfect. It doesn't check whether the VDP interrupt bit is enabled in the VDP for instance. It probably could also check the console interrupt control flags - I think if you turn off all the built in routines it's probably okay. But it's just safer to protect your VDP access. For a sense of what happens when you don't respect the interrupt, go look at some of the ColecoVision threads. On that machine the VDP interrupt is non-maskable, so pretty much every new programmer runs into strange corruption issues, and ends up working around them with sleeps and fragile balancing acts, hoping to win the race every frame. But it's just a warning.
-
My old design called for a FT2232, but that was just the first one I found and it was easy to attach. (I got some test samples but never got around to wiring them though... ) The LED was just based on the assumption you'd want a power LED on there anyway, since it's a popular mod, so why not have fun with it? I'm only CV myself, though, haven't touched an Adam since they were still available in K-Mart.
-
My requests: USB Serial UART on port 00 for printf debug support. Software could receive from it for input too. RGB LED on another port just for fun.
-
People always shortcount the number ever made on EBay anyway
-
Team Pixelboy News Bulletin - December 25th 2019
Tursi replied to Pixelboy's topic in ColecoVision / Adam
I think we've found the issue with Sky Jaguar and maybe the others too. Probably be a few days before a new release of the Coleco core. If it actually works for people I'll share what we found (no point getting hopes up, just saying it in case anyone is still working on it ). -
Short? No.
-
Team Pixelboy News Bulletin - December 25th 2019
Tursi replied to Pixelboy's topic in ColecoVision / Adam
(Pixelboy, feel free to kick us out of your thread, I just noticed we're hijacking ) -
Team Pixelboy News Bulletin - December 25th 2019
Tursi replied to Pixelboy's topic in ColecoVision / Adam
Thanks for looking at that, Kiwi. It's interesting that Sky Jaguar sometimes worked on /reset/, that was something that I did not try. I can discount some of your theory though. The Phoenix screen only shows up for titles that do not skip the BIOS screen - that is, on a standard ColecoVision they would show the "COLECOVISION PRESENTS" screen and sit there for however many seconds. SkyJaguar skips that. It's also impossible to overrun the VDP on the Phoenix, because the F18A can handle all reads and writes at bus speed, and does not need dedicated CPU access slots. But, the "sometimes works on reset" does imply a race condition somewhere. Let me add that to my analysis notes. -
Team Pixelboy News Bulletin - December 25th 2019
Tursi replied to Pixelboy's topic in ColecoVision / Adam
I dunno, didn't Opcode once say he was slightly interested in doing such a port, giving him eternal rights? I remember offering up my image converter for that... It'd be nice though. I had promised to see whether my hardware works, but my real life is just insanely dense, and I haven't even got any hardware set up right now for any retro system. 😕 -
Team Pixelboy News Bulletin - December 25th 2019
Tursi replied to Pixelboy's topic in ColecoVision / Adam
Yes, you can't be wrong on the internet. -
Team Pixelboy News Bulletin - December 25th 2019
Tursi replied to Pixelboy's topic in ColecoVision / Adam
Some of these issues get thrown at me - and I've only seen the Sky Jaguar issue. It wasn't immediately obvious. The problem with these bugs is that they require us to first reverse engineer the game software to determine why they don't work, since we can't get the source code. After a certain amount of investment I have to stop until more information is available. Since it works on real hardware, what we have to look for in these cases is something that is done in an unusual manner, to see if that unusual setting or sequence also works on the clone. It's the same thing as with writing and debugging an emulator. (Unfortunately, in this case my emulator has no issues! ) You're welcome to extend my analysis... Maybe I missed something or got something outright wrong! skyjaguar.txt -
Team Pixelboy News Bulletin - December 25th 2019
Tursi replied to Pixelboy's topic in ColecoVision / Adam
Reading back, it looks like you /are/ talking about reading from SD. So yes, SD only supports normal 32k carts and Megacarts up to 512k. A 512k megacart is unable to access the last 32k, because that RAM is reserved for the SGM (even if the SGM is not in use). There's not much out there that needs it all - I was able to patch Wizard of Wor by moving the last few pages to unused ones. I'm not sure if paging would work well.. SD cards are fast but the access time to start streaming is substantial. I /can/ tell you that no amount of paging will make Dragon's Lair work, when I was first designing the hardware for that I evaluated SD and Compact Flash as well, and there was no CPU time available for the setup. (Maybe with a co-processor though...) To clarify other questions above - Running from the cartridge port emulates the port hardware, so the Phoenix doesn't care about the cartridge size or even the banking scheme in use - if it did then the Opcode carts wouldn't work, and they do. -
Team Pixelboy News Bulletin - December 25th 2019
Tursi replied to Pixelboy's topic in ColecoVision / Adam
It does not... cartridges run from the cartridge just like they are supposed to. So the banking scheme in use and the size should have no impact. It's only loading from SD that has limitations. -
There you go! And yeah, that first cartridge is always fun.
-
Yes and no... my own emulator, Classic99, has been multithreaded for probably 20 years. But, it's also emulating a computer that is slightly unusual in that its VDP is de-synchronized from the CPU, having completely separate clocks. A single threaded emulator is absolutely the best way to guarantee correct sync between your components. It's certainly the easiest to code. Once again, the operating system gets in your way - even if you trigger another system to start operating "now", there's no way to know when it actually starts to. If you need to guarantee the sync of two components, a single thread is the most reliable way to do it. It's kind of non-intuitive, but because most systems run their various components off a shared clock, the timing between the components is predictable. The ColecoVision Z80 and VDP will always run at the same offset, while on the TI the ratio between the CPU and the VDP can vary from machine to machine. Even with all that though, you can still take advantage of multi-core. For instance, maybe running the VDP needs to happen in lockstep with the emulation (depending on how precise you want to be), but the video display doesn't remotely resemble the television the VDP expects anymore. So you can run your display loop in a separate thread without any real heartache. Same with sound, no reason to care what phase the 48Khz audio output is in with respect to the emulated sound chip, since it didn't even have a sample rate. Offloading those things can certainly help. Dealing with OS services, menu systems, all that benefits from multicore as well. I will always disagree with any assertion that claims there's only one way to solve a problem, but even in my emulator I've often considered dropping back to single threaded just to reclaim some sanity. But I'm stubborn.
-
Lots of good advice above. More generically: - you now know that the bug is caused by something that is initialized by loading via editor assembler that is NOT initialized from your program directly - you have verified that the VDP registers do not appear to be that something The most likely other cause remains the EA Utilities not existing in low RAM, but we can see that your program counter (PC) is still up in high memory. Look at the running disassembly - does it look like your program is running or is it off in hyperspace? Breakpoint (F1) and make sure that the code you see looks familiar. If your program is running, then you can assume the screen corruption is not caused by a software crash - that leaves only video memory not being initialized as expected. So as noted above - check that your VDP tables contain the expected data. Don't overlook Home Automation's comment about the first instruction of your program. When you use EA#3, you start at a label which can be anywhere in the program. When you use EA#5, the first byte loaded is the first executed statement (SFIRST and SLOAD are the same), so if you have any BSS or DATA at the beginning, just insert a "B @start" (or whatever label) before them.
-
Coco won't work well on real colecovision
Tursi replied to Serguei2's topic in ColecoVision Programming
Be wary with sprinkling disable_nmi() around. At least in the version of the code I have, it does so by disabling interrupts at the VDP, which itself is an operation that can be interrupted. By default, this is still okay, it looks like the NMI will be off by the time that function call completes, but if you have a user nmi() function, and that function does /any/ VDP work, then it is possible for the write to the VDP register to be corrupted and interrupts will NOT be disabled. It's best not to mess around with the NMI - take control of it and know when in your program it's going to occur, and ensure that point is safe. I'd recommend either all your VDP work inside the NMI handler - it's impossible for it to be interrupted there. Barring that, if your frame rate supports it, invert your paradigm and leave the NMI /disabled/ most of the time, enabling it only at fixed points in your loop. Particularly if you wait for it to occur before continuing, then the disable will always be safe. It's hard to get right. "NMI" is a non-maskable interrupt, meaning that any operation can be interrupted by it unless you can turn it off at the source (the VDP), and a lot of Coleco software tries to balance things "just right" instead of working that basic fact of life into the design. Looking through your code, it's generally pretty good. I'd recommend sprinkling some comments through it. The delay()s all need to go, unless they are for game reasons (but they are all around VDP access, so I suspect it's just trying to do the balancing act I mentioned above). The balancing act will always eventually fall down - especially with aging hardware and now clones, you can't count on 100% exact timing from machine to machine. There are only three conditions on the ColecoVision that it's safe to access the VDP, and some of this depends on how the NMI handler was written: 1) the interrupt bit in VDP register 1 is turned off. When it's off, the NMI line is never activated. This is what disable_nmi() does. You can still poll the VDP status register to see if it's time to perform vertical blank operations. Note that writing to a VDP register is an unsafe operation (it takes two writes), so you have to turn it off in a safe way. The Coleco BIOS starts a game with it off. 2) The NMI is still in progress. Once the VDP activates the NMI line, it can't trigger again until the NMI has been cleared by reading the VDP status register. This means that you can safely do as much VDP work as you want inside the NMI, as long as you do it before reading the status register. It can even be multiple frames. As soon as you read the status register, though, all bets are off - it can even fire again on the very next instruction, depending on how late you clear it. 3) The interrupt has just happened. After an NMI triggers, you know that it will be at least 16ms until it happens again. It's important to note this time starts when the interrupt occurs, not when you clear it by reading the status register. If you know the timing of your software very well, you can safely put VDP activity inside that 16ms window. However, this is a still a race - in fact it is by definition. You are trying to finish your VDP work before that 16ms window closes. My library (which I'm not recommending, just commenting) uses the second option. I have a flag that controls whether the NMI handler is allowed to process the NMI - when it's set to disable, the NMI still happens (it's non-maskable, when it happens, it happens!), but no VDP access occurs. Thus, the status register is not read and the NMI is technically still happening. When my software is ready to resume, the enable function checks if it missed anything, and performs the processing at that point. Anyway, a long way of saying you should plan your software around the NMI. Coco's loop looks pretty straight forward, I'd consider putting all the VDP access together and hiding it inside a single "disable_nmi()/enable_nmi()" block rather than putting that everywhere. You can do the same with your init code (the prints, rle's, etc, bunch them together if you can). If you can do the writes immediately after the NMI occurs, then you also get the benefit that most changes will occur offscreen - no tearing. That's what the interrupt is for - to tell you that the VDP just finished drawing a frame. If you can't reorganize your code, then the disable/work/enable blocks should work. Remember that ALL VDP operations need to be protected - all register writes, all memory writes, and all memory reads. (The status register read is the one exception, but if you manually read that, you will have different conflicts with the NMI...) -
FPGAs are "magic", and like all magic things, they are attributed abilities that don't make sense if you just think it through. Let me ramble for a moment about hardware, emulators, and FPGA reproductions. I'll oversimplify for the sake of comparison, so let's try to stay out of the weeds. So what's hardware to a console? The ColecoVision is a Z80 CPU, a 9929 VDP, an SN sound chip, a replaceable game ROM, and a host of associated circuitry and switches to link it all together. We also have to remember the television, since without it we can't really see anything happening. It has a base clock of roughly 3.5MHz, which means that three and a half million times per second, something happens. Even better, every piece does its bit at the same time, with no concern for the rest of the system except through the very specific links. So we could say that 3,500,000 times per second, at least 4 things happen. (I said this was simplified ). What's an emulator? Well, in this case it's a piece of software meant to reproduce the behaviour of a piece of hardware. Software doesn't look anything like hardware. It operates generally as a series of numeric expressions (math, compare) examined one at a time. Technically, you can do anything in software that you can do in hardware, but while a hardware transistor can switch in nanoseconds, the software reproduction of that transistor needs a lot more time - requiring instructions to fetch the data to compare against, decide whether to switch, and activate the switch itself. Back when emulation was becoming a thing, this could reasonably take microseconds - which sounds great but is a factor of a thousand times slower. Modern top of the line hardware is pretty fast, but we're dropping back to smaller hardware like PIs again, and even top of the line stuff suffers due to complex cache systems and the worst enemy of emulation: the operating system. The OS really doesn't want to give one piece of software attention three and a half million times per second. So, software emulation makes compromises. The raw circuits are not emulated, only their final result. In many cases, this greatly reduces the amount of work needed. (For instance, you can handle the sound chip at 44,000 times per second rather than counting every clock at 3.5M. The sound chip doesn't act on most of those clocks anyway!) To make the operating system happy, larger blocks of time are processed in a batch. For instance, an emulator might process an entire frame in one go - that's about 16ms and means the OS only needs to give it attention 60 times a second. The emulation can only process one thing at a time, rather than all circuits in parallel (modern multicore changes this but most emulators are still single threaded). This can produce timing issues - especially if a chip is emulated for a block of time, and then the next chip, etc. And finally - the operation of the circuits may not be fully understood. The software emulation will only be as good as the skill and understanding of the programmer who reproduces it. What is an FPGA then? An FPGA is basically a giant switchboard. Using a description language like VHDL, input that resembles code is assembled into a circuit inside the FPGA. It's not terribly unlike those old spring-clip electronics trainers where you clip the wires to different sections of the board. Because it's a real circuit, the switching times are very fast - sometimes not as fast as the original circuit but a lot closer than the software can be. Furthermore, because its a real circuit, everything runs at the same time, just like it's supposed to. This means that an accurate FPGA reproduction can be cycle-accurate, indistinguishable from the original. But it's usually not. First, it doesn't solve the understanding of the circuit. There are few machines, even today, that are completely understood to the transistor level. The CV is definitely not one of them! Without that understanding, there is always the chance of getting some edge case wrong. FPGAs have a limited amount of circuitry - and the prices go up fast. So the designer may be forced to trim a design in order to fit in the hardware that they have. A human has to translate an understanding of those circuits to the hardware description language - meaning both misconceptions and outright mistakes can make it in there. Finally, and most relevant - modern reproductions pretty much never reproduce the original machine on purpose. Nobody is looking for a ColecoVision replacement that outputs YCrCb 15khz analog video, they want upscaled HDMI. Cartridges - nice gimmick, but we want to load from SD card. How about new controllers or USB? These modern systems need to be integrated into the old design in a way that works as close as possible to the original, but there's no prior art to work from. I dunno, something like that.
-
And now I've finished a major re-org of the code and I think it's ready to call first release, though maybe beta since nobody but me has used it yet. First, the SFX player for the TI SN is complete, so it now has feature parity with the old toolchain. Getting SFXs working smoothly required a few little tweaks here and there, as well as in the compressor to make multiple songs work correctly with the new empty streams, but it's all doing the right thing now. I ported the old test app to verify SFX. With the basic TI functionality in place, I created a linkable library and moved all the example projects into a 'samples' folder. The Makefile for the library will go out and build all the samples as well, and I cleaned up the spare files in each folder to make the example more clear. I also wrote up a quick readme file to document the methods in the library. All up on github, you'll find the lib here: https://github.com/tursilion/vgmcomp2/tree/master/Players/libtivgm2 Sample programs: https://github.com/tursilion/vgmcomp2/tree/master/Players/Samples EXEs: https://github.com/tursilion/vgmcomp2/tree/master/dist Getting there. The TODO list is still long, but really only the ColecoVision player is a big one, the rest should overwhelm me merely with numbers.
-
On Friday I ran my test suite and discovered that the various tweaks and improvements I'd made had broken pretty much everything, so today I finished an overhaul of the RLE compression and tested on all the songs, finally working again. Most of the bugs were in the test code, which is why it worked, but as the test code got tighter more things were tripped. Anyway, all working now. I made two small changes to the file format. One probably was obvious but the tools didn't really support it before - you can have an empty stream simply by setting the stream pointer to 0. This means songs that (for instance) don't have a drum beat don't need to waste 4 bytes per second ticking off a silent volume channel. The improvement is small but it's there. The second was to change the reference of the backref offset. Rather than being an offset from the beginning of the file, it's now an offset from the current file position. This let me remove the need to pass the start of the file around just for this single case, and made the TI code slightly faster to boot (adding a register rather than adding the value at an address ), and let me remove the last piece of code that was tying the "common" code block to a particular player. I added a sample project showing the SN and SID playing together - Wonder Boy rather than Castlevania, but I don't think I'll take it any further. Same concept would let you run on the ForTI though, if you had a song that needed it. Anyway, it was a bit discordant so I don't think I'll force anyone to run it, but it shows the concept works and it's in the repo. Also a video here: https://lbry.tv/@tursilion:1/VGMComp-Progress-SN-and-SID:0
-
The guy FarmerPotato posted says he's using Shiru's VGM Music Maker, I wonder if that's the same one? I haven't looked at it for many years but I was under the impression it was really good. However it doesn't seem to be on his download page anymore... according to a forum post from 2012: "Looks like Shiru removed both the VGM Music Maker and TFM Music Maker due to a misunderstanding in a topic and hasn't posted since July. viewtopic.php?p=16101&highlight=#16101" People ruin everything.
-
I didn't see anyone else mention it, so maybe they already know you aren't using them, but if you are, the most common reason that coverting from EA#3 to EA#5 fails is that you don't have the Editor/Assembler routines in memory when you start from EA#5. So when you BLWP @VSBW, for instance, there IS no VSBW, and you jump off to empty code and crash. The easy fix is just to load the EA routines as an extra source file, so you have (for instance) your three program files plus one to low RAM for the utilities. There are a few copies of a pre-made file for that floating around the forums. If it's not that, then yeah, as noted above you have made some assumption about the state of the hardware. Make sure your program sets every register in the VDP and initializes any memory it uses to appropriate values (ie: don't assume they are zero). You should probably also load the character set yourself - but in fairness THAT doesn't usually become an issue till you move to cartridge. Usually it's the VDP setup. Check the registers in the Classic99 debugger and you should quickly see if they are different.
-
Cool, thanks! Yeah, there's no reason to expect the two chips to have the same output level. There will be tools for balancing manually, I guess, but I'd also guess few people will use the combination. But I figured I'd provide it.
