rosco_m68k: August Update

Time for another update on the rosco_m68k, my homebrew retro computer project. As always, regular updates can be found on hackaday, so please do check there for the details (and like/follow if you want to!) – this will be more of a digest of what’s been going on over the past couple months.

The Headline

So I guess the headline thing that’s been happening recently is that I’ve started working toward having a PCB manufactured for this thing. I realised I needed to press on with this after I took the breadboard in to work for a geek-out session with some of my awesome colleagues, and had a totally nerve-wracking commute with the breadboard (it survived, save for one current-limiting resistor which developed a loose connection).

So I started work on reducing the component count (more on that later) and actually designing a PCB. It’s now pretty-much ready to go off to OSHPark for manufacture (Yes, I could get it cheaper but I like purple and, y’know, yield) and looks like this:

(The real one will be purple…)

So that’s the hot-of-the-press headline (I finished it today), and I’ll update more once the boards are made. In the meantime, if you want more details, follow the project on Hackaday for (usually) weekly updates.

Lowering the component count?

In the original design of this computer, I went for a full 7400-series TTL design for all of the glue logic, and that was cool. I learnt a lot about designing with discreet logic gates, was forced to really think about the way I wanted my circuit to work, came to understand propagation delay in a way I didn’t before, and bought a lot more breadboard. That last point is important – fifteen 7400-series chips, while cool, take up a lot of physical space. And PCB fabs charge by the square inch.

It had been pointed out to me before (thanks, Ken!) that I could do with a couple of programmable logic devices what I was previously doing with ~fifteen discreet logic ICs, so I decided (in the interests of staying sane and solvent) to investigate. After a good bit of reading and learning, I’ve now replaced most of the 7400-series on the board with two ATF16V8QL (link to PDF) CPLDs.

This is a win in more than one respect – not only has it saved me board space but it’s made routing the PCB much easier, cut down the current draw of the board, fixed up some propagation delay issues and allowed me to (finally) fix the bug with the expansion select line. These chips were available at the time the CPU I’m using was released, are still in production today, and cost me around £1 each (delivered, based on 5-off, from Farnell in the UK). They’ve taken over all address decoding and IO glue logic, and I highly recommend them.

What About Software?

Things haven’t stood still on the software front – since my last blog I’ve fully integrated the MC68901, gotten timers and interrupts working, and made the UART work such that the computer can now talk over serial (via a CP2102 Serial-to-USB converter I had lying around). Work on an OS for this thing continues apace, and it already has some basic memory management, a fully async serial driver, and has been demonstrated with some (very) basic multitasking. My immediate plan is to implement a way to load software via serial (Zmodem) in the immediate term to make it so that, as I continue to develop the kernel, I don’t have to physically pull the ROMs to reprogram them.

It’s Going Well, Then?

I like to think it is, yeah. I’m having tons of fun, and this thing is starting to look like a product. Once the PCBs are made and I’ve done some more on the software, I think this thing will be at a point where other people might want one. Obviously it’s a 16/32-bit computer in a 64-bit era, but I kinda feel like it might make a great starting point for people wanting to really get to grips with bare-metal, without all the lies abstractions that modern architectures force on them.

The PCB design gets me to a point where the core computer is done, and the expansion connector I put in means I can continue to develop new bits without worrying about disturbing the ever-so-fragile connections on the existing breadboard. This will mean graphics, networking, and who knows what else.

And even if it never goes anywhere beyond the three prototypes I’m going to be building soon, I’ve learnt a hell of a lot from this project, and continue to do so every time I work on it – and that’s really all that matters, right?

As always, the rosco_m68k is open hardware/open source. The complete set of design, documentation and code can be found on Githib at https://github.com/roscopeco/rosco_m68k.

Using GCC as cross-compiler with x86_64 target

This post is a little rough, and is intended both as a memory aid for myself and as an example for anyone else who needs to know this stuff. I’ve recently decided to push toward x86_64 support in my toy/research OS project, and needed to build a GCC cross compiler for that target. In my case I already had an x86 cross compiler built, but I’ve tried to make the steps general for those that don’t.

These steps are tested with binutils 2.26.1 and GCC 6.1.0. I’m using those versions as they match the version of my x86 cross compiler – These steps might work with the more recent versions, but I can’t guarantee it. I will at some point update my cross compilers, at which point I’ll update these steps.

1. Go to your $HOME/src. Create first if needed.

# mkdir ~/src
# cd ~/src

2. Set up prefixes. PATH is only needed if not already set (e.g. this is your first cross compiler on this system).

# export PREFIX="$HOME/opt/cross"
# export TARGET=x86_64-elf
# export PATH="$PREFIX/bin:$PATH"

3. Configure, build and install binutils

# tar xf /path/to/downloaded/binutils-2.26.1.tar.gz
# mkdir build-binutils-x86_64
# cd build-binutils-x86_64
# ../binutils-2.26.1/configure --target=$TARGET --prefix="$PREFIX" --with-sysroot --disable-nls --disable-werror
# make && make install

4. Extract GCC

# cd ..
# tar xf /path/to/downloaded/gcc-6.1.0.tar.gz

Ensure libgcc is built with no redzone – Add this:

MULTILIB_OPTIONS += mno-red-zone
MULTILIB_DIRNAMES += no-red-zone

to the following (new) file:

gcc-6.1.0/gcc/config/i386/t-x86_64-elf

And then make sure GCC configure knows about the new config:

# vim gcc-6.1.0/gcc/config.gcc
/x86_64-\*-elf\*)

And insert:

tmake_file="${tmake_file} i386/t-x86_64-elf"

above the tm_file line.

5. Configure GCC

# mkdir build-gcc-x86_64
# cd build-gcc-x86_64
# ../gcc-x.y.z/configure --target=$TARGET --prefix="$PREFIX" --disable-nls --enable-languages=c,c++ --without-headers

6. Build GCC

# make all-gcc

Go make coffee/eat out at a restaurant/vacation in Barbados…

Note: If building with newer GCC (Found with 7.3.1), there’s an issue in the 6.1.0 source. If you see error:

error: ISO C++ forbids comparison between pointer and integer [-fpermissive]

relating to gcc/ubsan.c, then you’ll need to edit that file, and change line 1473 from:

|| xloc.file == '\0' || xloc.file[0] == '\xff'

to:

|| xloc.file[0] == '\0' || xloc.file[0] == '\xff'

7. Build libgcc

# make all-target-libgcc

8. Install GCC and libgcc

# make install-gcc
# make install-target-libgcc

9. Check the no-redzone libgcc is being used properly when -mno-red-zone is passed:

# x86_64-elf-gcc -mno-red-zone -print-libgcc-file-name

Should print (note the no-red-zone in the path):

$HOME/opt/cross/lib/gcc/x86_64-elf/6.1.0/no-red-zone/libgcc.a

10. Don’t forget to pass -mno-red-zone in LDFLAGS in the actual build!

Just checking in…

Wow, so my last post was September? That’s just not good blogging, and for that I apologise… There’s been a lot going on, but this is no time for excuses – I’m just posting this to let you all know that I’m still here, still writing code (lately, not as much as I’d like, but there you go) and I’m soon going to be making a start on the huge list of Open Source stuff that’s been building up over the past few months. Here are a few highlights of what’s in store:

  • Some awesome new stuff will be going into ORMDroid very soon, with some great contributions from Jacob Ferrero including one-to-many support. I can only apologise to Jacob for the time it’s taking to get these reviewed and merged!
  • Speaking or ORMDroid, it must be about time for that 1.0 release…
  • I’m planning to finally finish up Deelang. It still needs the new parser architecture sorting out, and some bug-fixes, plus some decent documentation. It’s been sitting there for too long, it needs to be pushed out the door!
  • I have some new code to put into Mink, including some rudimentary user-mode bootstrap code, along with a basic round-robin scheduler and other basic bits that will allow development to continue. A lot of this code is written, but still shockingly untested and even-more-shockingly out of version control!

Outside of Open Source, I still have to do something with retroify.me, a fact I was reminded of the other day when the domain name came up for renewal. The annoying thing there is that it’s done – I just need a reasonably-priced swag supplier who can print up cool T-shirts and the like for people to buy (any suggestions much appreciated!). We’ve also got an exciting new venture on the verge of private beta, which we hope to be launching as a commercial product later in the year.

So, all in all, exciting times. Now I just have to actually get on and do all this stuff.

Watch this space.

 

Creating a bootable hard-disk image with Grub2

Hard Disk Platter
Image courtesy of Wikimedia Commons.

Creating a Qemu hard-disk image that boots with Grub2 is, as it turns out, not too difficult. Unfortunately though, the steps you need to get it working are not completely obvious, and documentation is still pretty sparse (probably because Grub2 is still quite new). In this post I’ll run through how I got it working, and how I integrated it into my build.

I mentioned before how I had decided to start playing with OS development with Mink (which is now on Github, by the way). I’ve got a very simple kernel that does almost exactly nothing, and obviously I need to boot it up so I can test it as I add things. The obvious (and accepted) way to do this is to use some kind of virtual machine software to emulate the target computer (in my case, at the moment, that’s an x86 PC). I’m using Qemu.

Originally, I was using grub-mkrescue to create CDROM ISO images, and this worked fine for a while. Now, though, I’m getting to the point where I want to start implementing a disk driver, and filesystem support. To get started, I just want to implement simple IDE (i.e. PATA) support in the kernel – I don’t want to do ATAPI (which I’d need for the CDROM based setup) and I really don’t want to push off with an ISO9660 filesystem driver. I want read-write capability, so I’ve chosen to switch from the ISO build to a hard-disk image file, on which I’m using an ext2 filesystem.

So I spent much of today trying to get it to work. Googling the subject turned up a few links, but sadly nothing worked immediately, possibly because Grub2 is still being developed and has changed since the various tutorials were written. In the end I hacked up a solution based on bits from many different places, using the loopback device to mount the disk image, and then grub-install to actually install the bootloader. The configuration file I’d already put together for the ISO boot still works fine, and the final script I came up with is so short and simple, you’d never guess it took me the best part of a day to write!

Firstly, here’s mkimage.sh, which is the script that does the actual image creation:

# Create the actual disk image - 20MB
dd if=/dev/zero of=mink.img count=20 bs=1048576

# Make the partition table, partition and set it bootable.
parted --script mink.img mklabel msdos mkpart p ext2 1 20 set 1 boot on

# Map the partitions from the image file
kpartx -a mink.img

# sleep a sec, wait for kpartx to create the device nodes
sleep 1

# Make an ext2 filesystem on the first partition.
mkfs.ext2 /dev/mapper/loop0p1

# Make the mount-point
mkdir -p build/tmp/p1

# Mount the filesystem via loopback
mount /dev/mapper/loop0p1 build/tmp/p1

# Copy in the files from the staging directory
cp -r build/img/* build/tmp/p1

# Create a device map for grub
echo "(hd0) /dev/loop0" > build/tmp/device.map

# Use grub2-install to actually install Grub. The options are:
#   * No floppy polling.
#   * Use the device map we generated in the previous step.
#   * Include the basic set of modules we need in the Grub image.
#   * Install grub into the filesystem at our loopback mountpoint.
#   * Install the MBR to the loopback device itself.
grub2-install --no-floppy                                                      \
              --grub-mkdevicemap=build/tmp/device.map                          \
              --modules="biosdisk part_msdos ext2 configfile normal multiboot" \
              --root-directory=build/tmp/p1                                    \
              /dev/loop0

# Unmount the loopback
umount build/tmp/p1

# Unmap the image
kpartx -d mink.img

# hack to make everything owned by the original user, since it will currently be
# owned by root...
LOGNAME=`who am i | awk '{print $1}'`
LOGGROUP=`groups $LOGNAME | awk '{print $3}'`
chown $LOGNAME:$LOGGROUP -R build mink.img

Take away the comments, and that’s 15 lines… Just under two lines per hour – good thing I don’t work for IBM!

The comments pretty well explain what’s going on line-by-line, so I won’t go into much more depth here. The only things to note are that I use Fedora – on other system’s grub2-install is just called grub-install – and that on most systems, this will need to be run as root, so I added a small hack at the end to set the file ownership back to the original user once the image is created.

To integrate this into the build, I simply call it from the Makefile (I’ve included the older ISO build target here as well so you can see how it all works together):

# Generates the image staging area under build/img. This is
# the directory layout that is used to make the ISO or hard-disk
# images for emulators.
.PHONY: image-staging
image-staging: mink.bin grub2/grub.cfg
	$(MKDIR) build/img/boot/grub2
	$(CP) --parents $^ build/img/boot

# Generates the Grub2-based ISO - see bochsrc.txt for info.
# Requires grub2-mkrescue and xorriso be installed!
mink.iso: image-staging
	grub2-mkrescue -o mink.iso build/img# Generates a hard-disk image. See mkimage.sh.
mink.img: image-staging
	sudo sh mkimage.sh

(Thanks to tohtml.com for the syntax highlighting).

This should be pretty self-explanatory, so I won’t bore you with further details.

So there you have it – an easy way to make a Grub2-bootable hard-disk image as part of your build process. Of course you can do it manually by booting your virtual machine from a Linux live CD and installing grub to the hard drive, but if you want to automate it, feel free to use this (it’s under the MIT license, so please give credit where it’s due – see here).

Finally, in the event that Grub changes as it continues to evolve, please let me know in the comments and I’ll try to keep this post up-to-date.