DEV Community

Cover image for DOS on WII
Zvika Meiseles
Zvika Meiseles

Posted on

DOS on WII

So, the kids out-grew their Nintendo WII and moved on to Xbox (or Netflix). What's an electronics-hoarder like myself supposed to do?

There is an old saying: "If you love it then you should have run DOOM on it", so I set out to do that, and more. And while I'm at it, why not take the scenic route?

NOTE: I will not cover how to jailbreak and install homebrew.

Choosing a Linux distribution

Looking at the raw computing power, the WII should have no problem running Linux:

  • PowerPC CPU running at 729 MHz
  • ATI Hollywood GPU running at 243 MHz
  • 88 MB of memory (ouch!)
  • WiFi 802.11b/g
  • USB, Audio, Video, blah blah blah

There are a few linux distributions ported to the WII, and I went through a couple before choosing.
The 1st time I got the WII to boot was using WiiToo. It is a Gentoo based system, so it is very flexible.
However, I found that it requires quite a bit of work to update it on the little WII, both on my side (it's a very old version, dating back to 2009) and on Wii's side, since Gentoo is all about compiling-from-source.

So I moved on, looking for a binary-package-based distribution. and I found Whiite, which is a Debian 5 (Lenny) distribution. But soon I found, again, that it is hard to get a 2009-ish system up-to-date.

After taking a short break, I came back to the project and found Wii-Linux-NGX and I knew this was the one!
Based on Debian 8, updated in 2017 - finally, something to work with.

We will start with the base system, as detailed in Wii-Linux-NGX.
After we successfully boot, we will start the post-installation setup.

change default root password

$ passwd

configure Wifi

$ /root/whiite-ez-wifi-config

rename the network adapter device name

  • edit /etc/network/interfaces
    • wlan0 -> wlan1

we really need to enable swap, because compilation, which we will get to a little later, won't work with 88MB or RAM. also, we will use the actual /tmp partition on the sd-card.

enable swap (in /etc/fstab)

/dev/mmcblk0p3 swap swap defaults 0 0

disable tmpfs on /tmp by commenting the line /tmpfs . . . in /etc/fstab
and enable swap

$ swapon -a

next, enable remote ssh access, because working with a keyboard in front of the TV is sub-optimal.
we'll use RSA keys and not passwords. feel free to skip this part

  • allow root remote login with password

    • edit /etc/ssh/sshd_config PermitRootLogin yes

    $ service ssh restart

  • login remotely

    • create /root/.ssh/authorized_keys
    • copy RSA/DSA public keys to it
  • revert changes to /etc/ssh/sshd_config

    $ service ssh restart

now we can log out, login remotely from a normal laptop, and move-on.

next step - update the system. a lot has changed since 2017.
for starters - the PPC repositories have been archived, so we need to point our system to the new location

PowerPC APT repositories have moved, so add the new locations to /etc/apt/sources.list

  deb http://archive.debian.org/debian/ jessie main
  deb http://ftp.ports.debian.org/debian-ports unstable main
  deb http://ftp.ports.debian.org/debian-ports unreleased main
  deb http://ftp.ports.debian.org/debian-ports experimental main

and engage

  $ apt update
  $ apt upgrade

next, install additional packages.
specifically, xorg and build tools, since we're going to have to compile stuff from source code

$ apt install libpng12-0 libstdc++6 libx11-6 zlib1g gcc patch autoconf automake libtool libsdl1.2-dev libsdl-sound1.2-dev libsdl-net1.2-dev make g++ xorg lightdm git

thinking ahead, we're going to have a few non-root users for running our software.
we will have a separate user for each software: DOSBox, ScummVM and DOOM.

since most of these are SDL based, we're going to have to grant these users low-level access to the keyboard, mouse, audio and video.
1st, allow console access to dedicated group

  $ addgroup --system console 
  $ chgrp console /dev/console
  $ chmod g+rw /dev/console

and add our dosbox user

  $ useradd -m -U dosbox
  $ usermod -a -G console dosbox
  $ usermod -a -G tty dosbox
  $ usermod -a -G video dosbox
  $ usermod -a -G input dosbox
  $ usermod -a -G audio dosbox

Building dosbox

building dosbox from source is pretty straightforward.
the only caveat is the build time on the WII hardware: ~1.5 hours.
it is also the reason we had to enable swap, or gcc would fail compiling some of the more complex source files.

  $ wget https://netix.dl.sourceforge.net/project/dosbox/dosbox/0.74-3/dosbox-0.74-3.tar.gz
  $ tar -xzf dosbox-0.74-3.tar.gz
  $ cd dosbox-0.74-3
  $ ./autogen
  $ ./configure
  $ make install

Building ScummVM

as with dosbox, this is pretty straightforward but takes (a little more than) a while.

  $ wget https://www.scummvm.org/frs/scummvm/2.1.1/scummvm-2.1.1.tar.gz
  $ LDFLAGS="-Wl,--no-keep-memory"  ./configure
  $ make install

Running DOOM

Now, of course I could just run DOOM via dosbox, but since the source code is available, I decided to compile and run it.

I started with the Linux SDL port of the doom code, but it turned out to have 2 major issues, and a minor one:

  1. it would not compile on a PPC CPU
  2. it was not full-screen
  3. it would not compile and run on a pure 64bit system

while #1 and #2 are crucial for our end goal, issue #3 was for debugging purposes only - it was easier developing the code on my laptop than on the WII, mainly due to compilation times.
the code changes can be seen in detail in the github repo, but I will explain the changes in high level.

adding PPC support

This was a small issue with the code when __BIG_ENDIAN__ precompiler directive is defined.

64bit support

This task turned out to be more than "just compile as 64bit".
The code was very old and new GCC versions throw warnings and errors about

  • implicit int variables
  • string literals being cast to pointers

the 64bit part was a simple matter of not assuming

sizeof(void*) == sizeof(int) == 4

full-screen

the SDL 1.2 port was running doom in its native, awesome 90's resolution of 320x200, but the WII's video is aimed at pre-HDMI televisions, so the native resolution is 576x516.
the code changes are localized to a single file i_sdl_video.c.
the original code in I_InitGraphics used

SDL_SetVideoMode(320, 200, 8, SDL_SWSURFACE)

to initialize the the display-buffer, and then pointed the doom code to draw directly into it

screens[0] = (byte*) (screen->pixels);

we will modify the code to use 2 separate buffers - the screen will be initialized to our native resolution, and another buffer for doom to draw into, which is 320x200.
1st, modify the video mode

screen = SDL_SetVideoMode(576, 516, 8, SDL_SWSURFACE);
...
virt_screen = SDL_CreateRGBSurface(SDL_SWSURFACE, 320, 200, 8, 0, 0, 0, 0);
screens[0] = (byte*) (virt_screen->pixels);

now that we have both screens set up, we will need to modify the screen update routine I_FinishUpdate.
right before the original code, we will copy the image into the screen with scaling

scale(virt_screen, screen);
SDL_Flip(screen);

for the scaling algorithm, I decided to go with a very simple algorithm, for 2 reasons:

  1. speed
  2. consistency

I wanted the copying to be as computationally-simple as possible, and give consistent results (e.g. no "random" offsets).
the scaling math is pretty simple:
576 = (4*2+1)*64
516 ~= 500 = (3+2)*100
this means that horizontally, we will copy
4 times: 1 bytes --> 2 bytes, and another 1-->1
vertically, we will duplicate 1 line 3 times, then 1 line 2 times.

static const int xmap[] = {2, 2, 2, 2, 1};
static const int ymap[] = {3, 2};
// *i - axis index
// *d - axis destination
// *s - axis source
for(yi = yd = ys = 0; ys < 200; ++ys) {
   for(xi = xd = xs = 0; xs < 320; ++xs) {
      // duplicate source pixel into destination line
      memset(PIXEL(dst, xd, yd), *PIXEL(src, xs, ys), xmap[xi]);
      xd += xmap[xi];
      // point to next destination pixel (after duplications)
      xi = (xi + 1) % SIZEOF_ARRAY(xmap);
   }
   // duplicate line as many times as required
   // -1 for the line we drew above
   for (y = 1; y < ymap[yi]; ++y)
      memcpy(PIXEL(dst, 0, yd+y), PIXEL(dst, 0, yd), 576);
   // point to next line (after duplications)
   yd += ymap[yi];
   yi = (yi + 1) % SIZEOF_ARRAY(ymap);
}

in order to run doom you'll need to download the WAD files, and then

export DOOMWADDIR=~/doom.wad.directory/
./sdl_doom/linux/sdl_doom

and voila!

WII running doom on Linux, 40" TV

old-skool DOS tools

ScummVM running all the oldies

finishing touches

for each application, we will have a dedicated user that will auto-run the application when logging on.

in order to accomplish that, we will simply add the relevant lines to each user's ~/.bashrc , e.g.

dosbox
exit

the modified code is available here

GitHub logo zvikam / sdl_doom

SDL port of the linuxxdoom-1.10

Top comments (1)

Collapse
 
francescobianco profile image
Francesco Bianco

Good job!! You just miss to mention the Vintage Package Manager
github.com/francescobianco/vintage