-
VGA Timing Improvements
09/16/2016 at 17:55 • 0 commentsHaving grown weary of swapping my main monitor back-and-forth between the dev computer and the project board, I decided to invest in an inexpensive ($35) 7" vga monitor off ebay from china. After about a month, it arrived, and I eagerly plugged it in. And... nothing... (sigh). I was able to get it to display a little bit by fiddling with the controls but it was still way off screen to the left and unuseable. Hmm.
Up to this point I have been using a video driver which I had borrowed hacked upon to make signals that would also be compatible with VGA multisync, but also some integral multiple of the archaic 384x192 resolution of the TRS-80 model I (which is too low for modern things). Truthfully, and I am chagrined to admit that I did less calculating and measuring than fiddling with constants until it worked. Since this project started as a lark, and since it had worked on the few monitors I had tested, I didn't really think that much about it. But, now, OK, maybe we need to check our assumptions with the oscilloscope and some standards.
OK, so the current video is not exactly any standard mode, but it is most close to SVGA 800x600/60 Hz. I generate it by tripling the vertical lines and doubling the horizontal pixels to 768x576. So, I decided to close the gap to 800x600 with some blanked lines (handled in the frame gen state machine) and the horizontal doesn't strictly matter: there's some blank to the right that you don't really notice unless you want to, and all the more so because monitors these days are usually widescreen anyway, so there's already plenty of blankness. (Strictly, there is an old VESA mode of 768x576 which would be perfect, but I have a doubt that would be supported on cheap monitors like the one I got. Anyway, the dot clock in that mode is 34.96 MHz, as opposed to 40 MHz for 800x600 which is an integral divisor of the PIC32 system clock (80MHz)).
So, having meansured, the vertical look good at about 59 Hz, and the horizontal looks good at about 37 KHz. The vertical sync was wildly out-of compliance at 54.8 us (instead of 105.6). That's easy, there's a constant which defines the number of horizontal lines which was 2 and now is 4 so it's good now at about 108.8 usec.
The horizontal sync looked good at 3.8 usec (spec calls for 3.2), but the horizontal back porch is wildly out of spec at 1.6 us (spec says 2.2 usec). This almost certainly explains why the video is hopelessly off the screen to the left; that 1 us is 40 pixels! How to fix?
OK, the video generation is done mostly using hardware peripherals: 3 SPI for pixel data, 3 DMA to feed the SPIs with no CPU overhead, a Timer set to count up and recycle once per raster line, and an Output Compare unit to generate horizontal sync pulses based on the counter value in the Timer. Also, the rising edge of the Output Compare (end of horz sync) is what triggers the SPI to start, because the 3 SPI are configured into 'frame slave mode' with the horz sync fed back into the frame start inputs. The SPI is in 32-bit mode, and is preloaded with a value of '0', and is clocked at sysclock/4 = 20MHz (since I'm doubling the physical horizontal resolution from 384 to 768, I halve the dot clock rate to make each pix twice as long). The DMA starts clocking out the actual frame buffer once that initial '0' has been sent.
There is a short ISR entered at the rollover of the timer (i.e. at the beginning of the horizontal sync pulse) which drives a state machine that bit-bangs the vertical sync, and sets up the DMA to point to the current fame buffer line. All this preparatory happens while the sync is low, with negligible CPU overhead. The time-critical magic happens under hardware control for all three color planes, in sync, when the Output Compare goes high (i.e. the end of the horizontal sync pulse). Meanwhile the CPU is off tending to other stuff, not to be bothered again for about 27 usec.
All this is great, except that the horizontal back porch (i.e., the quite time after hsync ends, and before pixel data begins) is really being generated by that initial 32-bit '0' being loaded into the SPI. 32 bits @ 20 MHz is the 1.6 us I am seeing for the current back porch. I need another 600 ns, which is 30 pixels. The problem is, this is not a constant I can change easily with the current code -- you can't preload two words into the SPI. I need to do some surgery.
The first attempt was simply to pad the frame buffer with an extra word (32 bits is close enough to the 30 bits I technically need), and always keep that word 0, and adjust all the frme buffer routines to consider this value. This took a fair amount of hacquery, but I got it in, and made the number of words a #define sao I can tweak it with ease. It works fine now, and my cheap monitor locks onto the signal and I can now see the full TRS-80 screen. But I really dislike this solution because I am wasting precious RAM. At one word per raster line per colour plane, I am wasting 2.3 KiB! Yikes! But it is a baseline.
For the second attempt, I am using an additional Output Compare (I had two spares) configured just like the horz sync one, but with a larger compare value (so it triggers at the end of the back porch). This works great and I get my RAM back! However, there is a problem: the frame sync must come in from a physical pin (not internally routed in silicon), and those are already wired to the Output Compare for horz sync, and not to the new one (D4). Sigh. I don't mind cutting traces on my board, but I doubt anyone else will want this to be a requirement to play with the software with an off-the-self board.
So, alas, for now I am stuck wasting the 2.KiB. I guess it's not the end of the world, since I have it there to waste, but it doesn't make me particularly happy about it. But, if I ever decide to make my own board for this project, I will then have the opportunity to take this better approach now that I've figured it out.
-
Finally finished with FDC....
09/06/2016 at 21:13 • 0 commentsOK, I think I am truly done with the FDC emulation now. My problem in TRSDOS 2.7 formatting turned out to be due to the (emulated) disk interrupt coming in way sooner than (actual code of) TRSDOS expected during the 'writing system information' phase, and because the TRSDOS 2.7 ISR does not ack the fdc IRQ any more (unknown why they dropped this). The net result is that during that phase, a 'restore' is done to seek to track 0, and the IRQ is issued immediately (because we're virtual hardware), but the TRSDOS is not in a position to ever acknowledge that interrupt, so it infinite loops re-interrupting itself.
This implementation defect is probably masked in the real world, because the 'restore' would take a finite amount of time, which would allow the code to move forward a few instructions to reach the point where it is polling the status bit, which does clear the irq. So, I introduced a 'deferred' interrupt request on Type I commands (seeks, etc) to simulate the non-zero amount of time that the FDC would take to execute the commands.
So now that can be considered 'done' I hope. Now it's time for some serial port emulation. My intent is to use the USB CDC as my serial port, rather than the physical UARTS. I'm a little bit concerned, though. The USB involves code execution, which might slow down the emulator too much. If so, then I have at least two choices: 1) invoke the code only periodically, instead of every pass through the cyclic executive loop, and 2) punt on USB and use the hardware ports. I really hope I can get the USB option working, though. The hardware UART would probably mean needing some more parts -- probably a FTDI interface board -- and really I don't want to add any more parts since I've got a perfectly serviceable USB connector on-board already.
-
"It's the little things" -- FDC formatting (write track) now working
09/02/2016 at 17:50 • 0 commentsOK, after spending some quality time with the disassembler, disassembling TRSDOS 2.3 FORMAT/CMD, and stepping through the emulator, I found a bug: I failed to invert a bit being used in an AND mask. Obviously this caused all the other bits to be reset, one of which was 'Track 0 detect'. So.... a one-character ('~') fix, but hours of debugging. It's the little things, no?
So, I'm formatting in TRSDOS 2.3 and LDOS 5.3.1 in single, double, mixed, 1 and 2 sides, and semi-arbitrary number of tracks. And I can reformat (oh that failed too, for coincidentally a different AND mask reason - there I forgot to mask off some flags from an offset value).
So, I am nearly done with this FDC journey. TRSDOS 2.7 is not formatting properly for some reason. Well, it's formatting, per se, but hangs at 'writing system information'. I can verify that the disk image is properly formatted at that point, but the directory track is not written and the track 0 'mixed density' track has not been reformatted. Hmm. Well, I guess I should probably download and test other OSs as well -- NewDOS, UltraDOS, MultiDOS come to mind. Hopefully they work as is.
One additional challenge with 2.7 is that it does not reference the 'system' files (the OS) in the directory, like previous versions, and all other OSs do. I am guessing that this is either to free those directory slots for the user, or perhaps less charitably, to make reverse-engineering more difficult. So, disassembling that OS will be an extra challenge just in setting up to disassemble it. Fortunately, I had written a tool to dump the floppy image in a low-level form (basically, a sorted extraction of the sector images with hexdump and some drive metadata about them). So I will first 'disassemble' the floppy to find the 'hidden' OS 'files', and then go back and forth between that and the code disassembly following from boot until I can glean how 2.7 is put together. Sounds like slow going, alas. Fortunately, I am Number 5's nemesis, and I love to disassemble!
LDOS has definitely become my go-to OS, so I could possibly punt, but I really want to get these last cases put to bed (so that I can be put to bed) and move on to other things. Namely:
* along the way I implemented Newclock-80 emulation. It seemed trivial to do -- and it was -- but what is not trivial is that a hardware RTC was a fancy thing in 1980. None of the OS recognize it out-of-box, and require patches to actually make use of it. I did find a patch for LDOS 5.1.3, but not 5.3.1. Most of that patch is reuseable with simple ORG changes, but the last thing is an internal routine named 'PACKIT', which I cannot find in the 5.3.1 code. So I need to spend some more time with the disassembly to see what I can do about it, which means also understanding the surrounding code better, as well.
* serial port emulation. The USB serial is in-place, but I need to implement the emulator parts and wire it to it.
* depending on mood, I may do hard drive and printer. I can easily punt on those for a while.
* more important is porting it all to the new hardware platform. As mentioned before, this is going to be a little more work than I initially had expected, but c'est la vie, it's required. I'll miss the color, though.
-
FDC Read/Write working
09/02/2016 at 06:55 • 0 commentsOK, short update. The FDC emulation seems to be working correctly for sector reads and writes, in single and double density, both Percom and RadioShack doublers. Tested wtih TRSDOS 2.3, 2.7, LDOS 5.3.1 (and less aggressively with NewDOS/80).
Testing/debugging incurred a bit more work than expected, since the various DOSes use different techniques for different things; e.g. some use a loop counter to time index hole passings, and others use the interrupt-driven 'heartbeat' counter. (In the latter case I wasted a couple days debugging in the desktop development app only to eventually discover I had not implemented the heartbeat interrupt in that environment. sigh. Most of that time was spent disassembling the OS to figure out why it specifically was unhappy, so at least I got some pleasant disassembly time in....) Another one was detection of the disk density -- LDOS was reporting double density disks as single density because it tries to figure it out by reading the dir track first as single-density, then if it fails, retries as double density. But my virtual floppy implementation was reporting 'success' on reading sectors without considering that a single density FDC cannot read double density magnetics. So I needed to add some logic to make those reads fail; and then LDOS behaved as expected.
I did implement also ReadTrack and WriteTrack. I had been dreading these, but they wound up being fairly easy. I also think they work correctly -- at least in the virtual floppy implementation. However, I can't break out the champagne yet (well, maybe some of the cheap stuff), because I still have some issue whereby FORMAT is not working (which is what uses those commands). In LDOS I get a formatted disk, however, every other track (odd) is single density. LDOS is indeed explicitly requesting to change FDC's, but obviously it should not be, so "why?". I disassembled the double density driver, and that looks sane (or rather my understanding seems sane relative to what the disassembly showed). Anyway, the driver issues controller select changes based upon a bit in a byte in a structure. There are 10 of these, and I think collectively they are called the 'Device Control Table' ('DCT'). All the operations I have seen use the IY register to be the 'this' pointer referencing the target device's structure instance, and in this case +3 is the bitfield I mentioned. It uses bitmask 0x40 to indicate single(0)/double(1) density.
Stepping in the debugger, I can see this value flapping wildly between, say 0x4c, and 0x04. WTF? this should be stable since it represents the characteristics of the drive. I also note that IY is wildly off in the weeds at 0x656f, and I know that normally the DCT is at 0x4700 + nDevice*10. Hmm. Corruption of CPU state? Jeez, I would think I would have seen the effects of a bug of that nature long before I got down to the execution of an entered command for formatting a disk. But maybe -- read/write track do alloc new, special, structures (the track image and state data), and write does alter memory.
Anyway, I did a cursory disassembly of FORMAT/CMD and it seems it makes a copy of the DCT entry for some reason, so the IY value is not completely insane, but I need to understand why it's flapping in the wind.
Also, TRSDOS 2.3 is not formatting, either. This is significant because it is a single-density-only OS, and is blythely unaware of 'selecting disk controllers' -- that's so 1980! -- so it's not a density thing. Also TRSDOS 2.7 hangs at 'analyzing disk' before getting into formatting at all.
All this smells like 'status register infidelity', so I guess there's going to be more disassembly and single stepping in my future. Single-stepping; hmm. If there is a 'Texas two-step', is there a 'Wisconsin one-step'?
Anyway, on the plus side, sector reads and writes to already-formatted floppy images seem to work just fine, which is the 90+% use-case. So it's quite usable. Still, I must have this feature because I prefer that the emulated environment not have 'forbidden' uses.
-
Cursory Look at 2nd Platform
08/20/2016 at 19:10 • 0 commentsToday I took a cursory look at the candidate second hardware platform (since as I mentioned it appears that the one I originally used, the UBW32-MCC is not generally available in-market anymore). The candidate I am currently looking at is the Olimex Duinomite Mini.
Well, studying the schematic, it turns out the pin assignment is wildly different, so it definitely will not be able to take the firmware images I have built for the UBW32 version as-is. This isn't the end-of-the-world, but I will have to do some mundane project reconfiguration to build the two different images. A little more disappointing, though, is that the Duinomite is monochrome only. No color VGA (I was wondering how the color planes were so well-aligned -- they're hardwired together). This will incur some work for me since I had gutted the video and previously threw out the monochrome support. Again, not the end-of-the-world, and anyway the firmware for that board is on github, so I should be able to do that fairly quickly.
Anyway, my source has become a bit of a mess, so it will give me an opportunity to tidy it up. On the other hand, code tidying is not quite as fun as feature implementation.... :(
-
FDC somewhat working; w00t!
08/20/2016 at 03:32 • 0 commentsOK, I can boot TRSDOS 2.3 and 2.7 via single density and double density DMK images, also with Percom and Radio Shack doublers. That code is checked in.
It's quite far from 'done' though; I have not implemented the read address (do I really need to?), read track, and write track commands. Those are necessary for formatting disks. I intend to, but I can punt on that a little while, I guess, by formatting disk images in another emulator (e.g. trs32). But the other stuff seems to work correctly. (Well, 'write sector' probably needs more thorough testing).
DMK only at this point. Maybe I'll do JV1/3 later, but it's not a priority for me relative to getting the other stuff working fer shur.
So, it's a start!
-
Getting back to FDC emulation
08/14/2016 at 20:59 • 0 commentsI'm now getting back to floppy emulation after being busy with other things for some time. Now I am in the thick of ancient Western Digital datasheets from the 70s, disassembled TRSDOS (I know of course this has been done myriad times in the past 40 years, but I actually really like disassembling), and of course, looking at other folks existing code.
For starters I'm just going to support the 'DMK' disk format, because it's the richest. Maybe later I'll support the others.
One thing I noticed in passing is that it seem Dontronics is no longer carrying the UBW32-MCC board (well, as best as I can infer based on it being out-of-stock for sometime), which I used to conveniently mount the various peripheral connectors onto the UBW32 for this project. One could fabricate their own, of course, since the design is open source, but I am thinking about instead porting the whole thing to the Olimex DuinoMite-Mini board. Aside from those being still in-production, it's also much cheaper (about USD$ 20, versus ~ $60+ if you did it my original way), and you wouldn't have to solder anything at all. I imagine this would be convenient for the casually interested. One thing I notice is that there is no DS1307 RTC - rather the on-chip clock is supported, but on that particular board there is no provision for battery. :( So it will be more authentic like the old-days where you have to enter the date and time upon power on haha.
I wish there was something like that board with the PIC32MZ on it. I could use the extra speed and memory. I don't know if they fixed the huge list of bugs on that chip, but those bugs don't really affect my this project's requirements. If there was, then I might be able to pull off a Model 4 or maybe even a Model II (but where to get floppy images?), and with a higher resolution video.
-
Faster video emu
01/08/2016 at 02:06 • 0 commentsAs mentioned, the code for the 'drivers' was used, with permission, from various sources. In particular, I used video code from the Maximite project (I tweaked it for my TRS-80 native resolution (which further required a line-tripling hack for modern monitors) and discarded a bunch that were for features I didn't need). It worked great and was a huge help. One nagging problem was with video performance.
For the most part, it worked good enough. I could tell with my developer's eye that it was a little sluggish, but that sluggishness was quickly compensated for in subsequent non-video activities (the speed throttling tries to keep the emulated cpu's clock's error function at zero, so if an emulated operation takes a longer than expected time, subsequent instructions execute faster than expected until it catches up). So, for all practical uses, it was perfectly fine. But there was a pathological case: that of switching between normal and wide character mode.
The TRS-80 had a 'wide character' mode, which was rarely used. I mean, who would want to reduce an already constrained 64x16 text display to 32x16? Well, one program did, one of my faves: SpaceWarp. SpaceWarp used the wide character mode as a visual effect by rapidly switching between normal and wide to simulate a 'starquake' when you drove into a star (OK, a period. It was ASCII art.) This worked on the original hardware because the wide character feature was implemented in hardware -- it had no software burden -- but here we had to do a full screen repaint pixel-by-pixel when switching modes.
Anyway, long story short (too late, I know): the new code is fast enough to make this unusual effect work.
OK. Maybe I should get back to work on either emulating the WD1771/91 or making BogoDOS....
-
Just posted here...
01/05/2016 at 21:14 • 0 commentsThis project's formal 'blog' is recorded in the source repository (under what fossil calls 'events'), and is what I primarily maintain, but I'll post stuff here occasionally as well if I think to do it, and if its sufficiently significant.
This project was functionally complete in March of 2015, which was my goal. At that time, I just wanted to get cassette (simulation) working. I am now itching to get floppy working in one form or another, so I've come back to this. I can either:
a) take the traditional route, and emulate the FDC. Then I use all the various disk image files out there. Or,
b) take the non-traditional route, and make a 'bogo DOS' which makes the native filesystem of the SD card look like a TRS-DOS filesystem in the emulation.
Option 'a' will give the highest fidelity emulation (and support programs with funky copy protection schemes *(cough)*"SuperUtility"*(cough)*, but option 'b' will give me an opportunity to bang out some Z80 assembler once again, and indulge my dangerous addiction to disassembly/reverse-engineering. Natually, I presently lean towards option 'b'.
After I do that, it's on to serial. Actually, I already have USB CDC in-place, though it is presently unused. I have a kooky plan for what to do with the serial emulation.... But let me not distract myself now from finishing FDC [em|sim]ulation....