Thursday, 28 February 2013

Ken Shiriff's blog

I've raised awareness of this blog over at CPCwiki, but it's well worth checking out Ken Shiriff's blog.

Just recently, he's been looking at the PLA that deals with the decoding of 8085 opcodes, and has an excellent way of presenting the 8085 instruction set in Octal:

As the Z80 is a very close relative, I'd say it's well worth keeping an eye out on this very well written blog. The technical discussion of the 8085 undocumented flags is outstanding - he reverse engineers the flags from looking at a photo of the silicon, translates that into gates, works out why the existing documentation is wrong and what the flags can be used for.

It's worth remembering that the 8085 is somewhat different to the Z80, however. It's still a fascinating chip to look at and by looking at the differences between the two and how they diverged from a common ancestor is very revealing.

Tuesday, 5 February 2013

Reading the FAT the BASIC way...

So, I've knocked together a simple SD card interface... There's a state machine which initialises the card (works with MMC, SD and SDHC), reads the partition table and then exposes a simple byte-wise interface, handling all the sector blocking stuff automatically. You simply pass in the sector and offset, assert begin_read and the card layer asserts data_ack when the data is available to be read on data_out. Then deassert begin_read and wait for data_ack to deassert before continuing.

I've just made a very simple interface from this to the CPC. Writing to &FAD0 shifts a byte into the sector address and resets the sector offset. Reading from &FAD0 asserts begin_read and returns data_ack in the top bit. Reading from &FAD1 fetches the data input and de-asserts begin_read. Simples!

I need to build a FAT layer on top of this and then I can build the DSK image layer on top of that. But for now, I just wanted to get to work on the DSK layer code, so I'm going to use the interface so far to read the file into RAM.

Monday, 21 January 2013

ROM and RAM banking

Just made a quick video this morning which demonstrates the newly added ROM and RAM bank features.
Previously I was emulating just 64KB of RAM and copying ROM images into the spare RAM. Now, the flash ROM is accessed in-place allowing me to expose the extra RAM as an expansion board.

Friday, 11 January 2013

Sounds and tapes and clocks, oh my!

So, with a bit of experimentation I discovered that dropping R19 down to about 8000 ohm fixes the tape input. Not only are the tape signal high/low bars equally sized now , it also sounds right when it's loading instead of the weird "high frequency" noises in the previous video. Here's an updated schematic where I've just added a 47K resistor R61 in parallel with R19 to drop it to approximately the right value:

I've also been learning over the last week about the importance of clock domains, more specifically the scarceness of global clocks. It seems doing innocent things like this will introduce severe unpredictability:

    if rising_edge(hsync) then
        ...
        something <= '1';
        ...
    end if;
Obviously, this introduces a D flip-flop clocked on hsync. However, what this actually seems to do is put this into a pool of things that might be promoted to a global clock or might be routed all over the place. At first, everything seems to work fine and then suddenly, changing a small bit of code somewhere causes resources to be placed slightly differently which causes a different selection of clocks to be promoted to be global clocks.

Around the time I started using the DCM to generate a 32MHz clock from the standard 16MHz clock, I'd forced most of important clocks to be globals using BUFG, but I hadn't realised how unpredictable all the innocent looking clocks like the one above would be. Something trivial like changing the RAM banking logic would cause glitches in the CRTC (e.g. bit 2 of the width register always being set) or even complete screen failure.

So, what's the solution? It actually turns out that if you stick to only ever using a small number of clocks (there's 8 global clock lines on all the Spartan 3 chips), then everything works completely as expected. Replacing the multitude of clocks actually turns out to be remarkably easy, e.g.

    if rising_edge(clk32) then
        if hsync='1' and hsync'last_value='0' then
            ...
            something <= '1';
            ...
        end if;
    end if;
It turns out that you end up needing very few clocks. I've gone from having too many clocks that the assignments were random, to only 5 clocks in total: 32MHz, 32MHz @ 180°, 16MHz, 1MHz (for CRTC/PSG) and 4MHz (for Z80).

The best result of this is that this fixing these clock issues also fixed a critical problem with the sound emulation. I'd noticed some glitches before with a couple of songs, e.g. the fantastic Hyperdragon by Reed/Fairlight, but I hadn't ever managed to figure out what was wrong. What was happening was due to this clock issue the first sample in each envelope was actually played with the volume of the last sample in that envelope. This was due to audio clock no longer being a global clock, so the audio events had stopped being precisely synchronised and the envelope counter was being reset 1/16 envelope period after it was being used. So, BASIC which didn't use envelopes was fine and most songs sounded fine, but some of the drum effects sounded very odd in others. I'll upload a video of this soon, but my phone just ran out of battery as I was recording a demo for the blog...

Friday, 28 December 2012

More tape loading analysis

Digging into some occasional read errors reveals that the on pulses are shorter than the off pulses:

For your interest, here's the circuit for the tape input:

I've also been fixing up some audio glitches - the tone pitches were all an octave too high, which is now fixed, and the white noise generator still doesn't seem to be working correctly.

Sunday, 23 December 2012

Tape loading

So, something I've been meaning to test ever since I designed this board back in March and got them made up in April is the tape input. So here is Rampage running on the emulator and loaded from real tape:

Since the first prototype, I've been pretty busy and not had much chance to work on the emulator and whenever I did get a chance I was stuck because the flash chip on the board didn't seem to work properly. There's a bunch of reason why it might not work - it might be dodgy soldering, although I reworked all the soldering on the FPGA pins and flash chip pins a number of times, and testing it with my scope suggests it should work. It could be the chip itself which is dead (2 of the 3 boards seem to have dead flash) or it could even just be because I forgot pull-up resistors. Reading the datasheet, these don't seem to be required, but who knows...

Anyway, the other day, I knocked up a small daughter board with a flash chip from a different manufacturer and that all seems to work fine, so I'm able to carry on with the testing I could have been doing 6 months ago!

Here's a close up of the board taken with a decent camera rather than my camera phone and also the emulator running 1943 (also loaded from tape):

Saturday, 27 October 2012

Too much going on!

I feel a bit guilty that I've neglected my FPGA project for a while now...

As you know, I kind of put the emulator project on hold early on in the summer so I could focus on my demo for Sundown. Well, that's been and gone, but after winning the old school compo at Sundown and getting a PC-FX as my prize, I spent about a month doing nothing but trying to get some code running on that. Then, I went to the really fun poolside demoparty at Main and since then I've been looking into raymarching and WebGL...

Today, I had another look at the FPGA project. I thought I'd broken the JTAG scan again when I was trying to demo it at Sundown and something wasn't working, but it looks like there's a "feature" of the USB serial democode that causes a timeout to happen if the host isn't reading the AVR chip... and so my JTAG code was running at about 2 bits per second unless the virtual serial port was connected to. I've managed to speed this up a bit and so now the timeout overhead is only about 80%, but it's still something I'd like to fix properly.