I've been making steady progress on Mackerel-10 since initial board bringup. The most exciting development is a working Linux driver for the IDE interface. There's now a real /dev/hda device accessible and this comes with all of the built in tools and filesystem support from the kernel. After adding fdisk and mkfs to the Linux image, the IDE drive can be partitioned and mounted as a persistent storage device right from Linux. This is a huge step in improving the usability of the system and it's a milestone for the project as a whole.
Hardware Changes and Glue Logic
The hardware design of the IDE interface was mostly complete before I started work on the driver, but there were a few updates to get everything fully supported. While it's possible to use IDE devices without interrupts, the Linux driver interface requires a working interrupt from the drive. This interrupt pin was already routed to the CPLD, so I updated the interrupt control Verilog to handle the extra source.
The only sticking point on the wiring side was the missing second chip select line. IDE devices have two CS pins: CS0 and CS1. Only CS0 is required for basic functionality, but CS1 enables access to the alternate status register, a.k.a. the device control register. This register is needed to control interrupts on the drive. I did not have this pin connected to the CPLD, but it was connected to 5v through a pull-up, so I bodged a connection to one of the spare IO pins on the CPLD and updated the address decoding to make this device control register accessible to the CPU.
Writing a Linux IDE Driver
With the hardware and glue logic updated and tested in isolation, I started work on a Linux driver. There are a few different ways to implement IDE on Linux. The traditional (i.e. deprecated) way is to implement an ide_host and the associated functions for communicated with the drive(s). There's also a newer approach based on libata. This is a more modern solution, but it is not supported on m68k architecture, at least in the 4.4 kernel I'm running, so I implemented the traditional driver.
Conceptually, the IDE driver interface is pretty simple. There are a handful of operations that the driver needs to define and the driver requires an interrupt number. On Mackerel-10, the IDE interrupt is autovectored to IRQ number 3. Implementing the required functions is fairly straightforward. For example, here are the commands that read the status, execute IDE commands, and read blocks of data:
static u8 mackerel_ide_read_status(ide_hwif_t *hwif)
{
return MEM(MACKEREL_IDE_STATUS);
}
static void mackerel_ide_exec_command(ide_hwif_t *hwif, u8 cmd)
{
MEM(MACKEREL_IDE_COMMAND) = cmd;
}
static void mackerel_ide_input_data(ide_drive_t *drive, struct ide_cmd *cmd, void *buf, unsigned int len)
{
int i;
int count = (len + 1) / 2;
u16 *ptr = (u16 *)buf;
for (i = 0; i < count; i++)
{
ptr[i] = MEM16(MACKEREL_IDE_DATA);
}
}
The full driver code is available here: https://github.com/crmaykish/mackerel-uclinux-20160919/blob/master/linux/drivers/ide/mackerel-ide.c
Dirty Hacks
One issue remains with this driver. Normally, when an IDE interrupt is generated, the drive will assert the IRQ line and hold it until the CPU reads the status register. This clears the interrupt and normal operation resumes. For some reason, the interrupt on my system is never getting cleared. This means that after the first IDE interrupt, the driver just hangs and the system can't boot further.
I managed to "solve" this by reading the status register manually in the process_int() function in ints.c if the vector number matches the IDE IRQ number, but this is a total hack. I don't know why the driver is not doing this automatically. It's entirely possible there's an issue with my interrupt glue logic or something dumb I missed in the driver code itself. I need to figure this out, but my hack is working for now and the IDE driver is fully functional.
Other Hardware Updates
Lastly, I've made a few smaller changes to the hardware configuration. I removed the two SRAM chips and mapped the DRAM from 0x000000 to 0xF00000, so all 15MB of RAM are now served by DRAM. I'd like to do some benchmarking and see if repurposing the SRAM for the stack area would improve performance at all since it requires fewer CPU cycles to access compared to DRAM, but I haven't noticed any obvious changes in usability when running uClinux with only DRAM.
I've also been experimenting with the CPU clock speed as this translates directly to system performance. Using the 68010 rated for 10 MHz, I was able to run with a slight overclock to 12 MHz with the DRAM controller running at 24 MHz, but anything higher was causing instability. When I installed the M68SEC000 rated for 20 MHz, I was able to push all the way to 25MHz for the CPU clock and 50 MHz for the DRAM. This shows that the DRAM controller is not the bottleneck, but the 68010 I have just doesn't have much headroom. That's fine. There are other options like the 68HC000 which push the speeds higher, or I can just continue using the SEC on my adapter board. I still need to experiment with running the DRAM controller and CPU on independent clocks.
Getting Close
Mackerel-10 is really coming together as a fun little computer and a significant upgrade to Mackerel-08. Based on my original plan of adding DRAM and IDE support, it's complete. There are a few more software updates I'd like to make, including booting Linux from the IDE drive instead of relying on a ROMFS. I'm also planning another PCB revision to resolve some of the design issues and incorporate the bodges into the circuit properly.
I've started rough planning for the next iteration in the project, Mackerel-30, but I am having a lot of fun playing with Mackerel-10 and I'm not in a rush to mark it complete and move on just yet.
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.