xv6 revisited…

I was hoping to do more with this, but things are going other ways in life.  Anyways a while back I had touched on xv6, a MIT teaching tool and semiport of Unix v6 to the i386!  The best part about it, is that it is SMALL…

I’ve been playing with it the last day on the latest version of Qemu and hit a snag with its SMP support (yes it does have that!) so I played with it, and couldn’t figure it out so I had to turn it off.. It is something ACPI related, and probably along the reason why Windows x64 doesn’t run on new Qemu either..

I’ve built the cross compiling environment needed (A bare elf compiler/linker/assembler) and managed to smash enough of it into a single directory that you won’t need MinGW installed, but can rather invoke ‘build.bat’ which will compile link, dd the disk image, and launch Qemu.

I’ve had trouble with mkfs so… you’ll have to live with a prebuilt root image.

If you want to build your own cross compiling toolchain, there is a good guide here on the OSWiki.  Naturally you’ll want my previous post on some snags I ran into on MinGW if you do choose that as your target environment.

What I’d love to do is port newlib, and see just how useful this xv6 could become..  I would imagine adding signals (well beyond kill) may allow things like bash 1.x to run, and maybe gcc itself.. Which would be cool.

You can download my work here.  Check it out, it’s cool!

building a cross compiler under MinGW snag in collect2

rm -f collect2.exe
gcc -DCROSS_COMPILE -DIN_GCC     -g -O2  -DHAVE_CONFIG_H  -o collect2.exe collect2.o tlink.o hash.o intl.o underscore.o version.o  obstack.o       -ladvapi32 ../libiberty/libiberty.a
collect2.o: In function `handler':
C:\MinGW\msys\1.0\src\gcc-2.95.3\gcc/collect2.c:527: undefined reference to `kill'
collect2.o: In function `scan_prog_file':
C:\MinGW\msys\1.0\src\gcc-2.95.3\gcc/collect2.c:2269: undefined reference to `pipe'
C:\MinGW\msys\1.0\src\gcc-2.95.3\gcc/collect2.c:2292: undefined reference to `fork'
collect2: ld returned 1 exit status
make[1]: *** [collect2.exe] Error 1
make[1]: Leaving directory `/usr/src/gcc-2.95.3/gcc'
make: *** [all-gcc] Error 2

Ugh, isn’t that annoying? Well it turns out from the mailing list

The mingw32-hosted GCCs does not need ‘collect2.exe’ hence
set USE_COLLECT2= nothing (empty) in the <gcc_obj_dir>/gcc/Makefile

This needs to be fixed in GCC mainlne.

Regards.
Nitin.

And the other half….

fixincl.c:316: error: `SIGQUIT' undeclared (first use in this function)
fixincl.c:316: error: (Each undeclared identifier is reported only once
fixincl.c:316: error: for each function it appears in.)
fixincl.c:323: error: `SIGALRM' undeclared (first use in this function)
fixincl.c: In function `internal_fix':
fixincl.c:808: warning: implicit declaration of function `pipe'
fixincl.c:816: warning: implicit declaration of function `fork'
fixincl.c:845: warning: implicit declaration of function `sleep'
fixincl.c:860: warning: implicit declaration of function `fcntl'
fixincl.c:860: error: `F_DUPFD' undeclared (first use in this function

Which is fixed by changing

STMP_FIXINC = stmp-fixinc

into

STMP_FIXINC =

Oops!



Quake1 & MS-DOS

And because I had a request for it, here is a 7zip containing a makefile, and source suitable for building quake under MS-DOS.

I sourced it from the Doom makefile, and cross built it under OS X… It builds in under 5 seconds using all 4 cpu’s on my OS X box with my OS X to MSDOS DJGPP cross compiler…. I had forgotten that the gpl’d source included MS-DOS support.. I had taken the video part from Chi Hoang’s DOS port of DOOM and gotten it to run until I remembered.. Oh well a few hours wasted.

So there it is, Quake1 built on a mac, and running on DOSBox on a PC.....

And speaking of Quake, it’s on sale too!

But just for today, on steam…..

Cross compiling for MS-DOS (DJGPP) from OS X

So building on DOOM, I thought I’d try to build a djgpp cross compiler from my main OS X box, as compiling under DOSBox is… just too slow. Luckily Delorie has a page on building a cross compiler.

I started out with binutils-2.9.1, just as he does, with a few things thrown in…

First I had to run configure like this, as OS X didn’t exist back then, let alone x64 cpu’s..
./configure --target=i586-pc-msdosdjgpp --host=i386-netbsd --prefix=/usr/local/djgpp
Next the following error is thrown…

strerror.c:463: error: conflicting type qualifiers for ‘sys_nerr’

So I just edited libiberty/strerror.c, and commented out the following line.

Next up was a strange error in gas/targ-cpu.h

targ-cpu.h:374: error: array type has incomplete element type
targ-cpu.h:378: error: previous declaration of ‘flag_16bit_code’ was here

I simply commented out the lines.

Then later while compiling gas/write.c it bombs out because of an undefined type.. One of which was commented out in targ-cpu.h . The easiest fix is to go to the start of the relax_align procedure and just add in the definition:

extern const struct relax_type md_relax_table[];

Next up was gcc. I couldn’t get 2.8.1 to build, instead I built gcc-2.95.3.

I had to configure gcc like this:
./configure --target=i586-pc-msdosdjgpp --host=i386-netbsd --prefix=/usr/local/djgpp
And it threw the same error as binutils… with the same fix (commenting out the line in libiberty/strerror.c).

strerror.c:465: error: conflicting type qualifiers for ‘sys_nerr’

I also had an error pop up like this:

./config/i386/i386.c:142:22: error: macro “strcat” requires 2 arguments

And again I just commented it out.

Under OSX the makeinfo parts crashed, so I simply removed them from the makefile. With a little more tweaking the cross compiler was ready!

REMEMBER TO FOLLOW DJ’s steps too!

The cool thing is that now I can run make with the -j4 flags allowing gcc to run on each of the cpu cores letting me build doom in under 3 seconds!

i586-pc-msdosdjgpp-gcc -O2 -DNORMALUNIX dos/doomdef.o dos/doomstat.o dos/dstrings.o dos/i_system.o dos/i_sound.o dos/i_video.o dos/i_net.o dos/tables.o dos/f_finale.o dos/f_wipe.o dos/d_main.o dos/d_net.o dos/d_items.o dos/g_game.o dos/m_menu.o dos/m_misc.o dos/m_argv.o dos/m_bbox.o dos/m_fixed.o dos/m_swap.o dos/m_cheat.o dos/m_random.o dos/am_map.o dos/p_ceilng.o dos/p_doors.o dos/p_enemy.o dos/p_floor.o dos/p_inter.o dos/p_lights.o dos/p_map.o dos/p_maputl.o dos/p_plats.o dos/p_pspr.o dos/p_setup.o dos/p_sight.o dos/p_spec.o dos/p_switch.o dos/p_mobj.o dos/p_telept.o dos/p_tick.o dos/p_saveg.o dos/p_user.o dos/r_bsp.o dos/r_data.o dos/r_draw.o dos/r_main.o dos/r_plane.o dos/r_segs.o dos/r_sky.o dos/r_things.o dos/w_wad.o dos/wi_stuff.o dos/v_video.o dos/st_lib.o dos/st_stuff.o dos/hu_stuff.o dos/hu_lib.o dos/s_sound.o dos/z_zone.o dos/info.o dos/sounds.o dos/i_main.o \
-o dos/dosdoom

real 0m1.174s
user 0m2.626s
sys 0m0.679s

How’s that for fast?

For any curious OS X 64bit users out there you can download my binary toolchain here.

I would imagine that if you stuck with versions of binutils & gcc that build on your platform you too should be able to build a MS-DOS DJGPP cross compiler. And there is nothing like native 64bit tools for building for DOSBox… Oh and DOOM runs just fine, although I guess screen shots of the cross compiled exe is… redundant.

OpenWatcom for the DEC Alpha

Someone had contacted me about running some Fortran programs on the DEC Alpha with Windows NT. Now I know that DEC had released some compilers for the Alpha, the Digital Visual Fortran thing which some people still sell for around $600 USD.

OUCH.

But luckily a friend mentioned that I should look at the source code for Open Watcom.

So, I figure for the hell of it, I’ll show how to build a Dec Alpha cross compiler for both C & Fortran. First I’m using Open Watcom 1.8, the current ‘release’ version. You are on your own for older or newer versions.

First install Open Watcom 1.8, with whatever your host is (I’m running on win64, so I’m using the win32 install), and set the target for 32bit NT. We will need the headers so this is the easiest way to ensure your Watcom can make NT exes.

Next you are going to need the file owaxp0401.zip. This is a pre-compiled version of the compiler & libraries for the DEC Alpha. All we need from this is the libaxp directory, which you can just unzip to your Watcom directory.

Now we’ll need to copy some files to satisfy the build process.

C:\WATCOM\binnt>copy wcl386.exe bwcl386.exe
C:\WATCOM\binnt>copy wlib.exe bwlib.exe
C:\WATCOM\binnt>copy wrc.exe bwrc.exe

Ok, now with that out of the way, run c:\watcom\owsetenv.bat to setup your environment, and now let’s extract the source to 1.8. I’m just going to use c:\temp as a place to put it. Also you will have to edit the setvars.bat file, and change the following:

set OWROOT=c:\temp\ow18src
set WATCOM=c:\watcom
set DOC_BUILD=0

Now I suppose you could save this into a batch file, and kick that off, and this will build the needed libraries, then the C compiler.

cd c:\temp\OW18src\bld\builder\nt386
wmake
cd c:\temp\ow18src\bld\dwarf\dw\osi386\
wmake
cd c:\temp\OW18src\bld\yacc\nt386
wmake
copy yacc.exe \WATCOM\binnt\byacc.exe
cd c:\temp\OW18src\bld\re2c\nt386
wmake
copy re2c.exe \WATCOM\binnt\re2c.exe
cd c:\temp\ow18src\bld\cg\risc\axp\nt386\
wmake
cd c:\temp\ow18src\bld\sdk\rc\wres\flat386\mf_r
wmake
cd c:\temp\ow18src\bld\cfloat\osi386
wmake
cd c:\temp\ow18src\bld\as\alpha\inline\osi386\
wmake
cd c:\temp\ow18src\bld\owl\osi386\
wmake

Now this will build the cross compiler…

cd c:\temp\OW18src\bld\cc\wcl\nt386.axp
wmake
copy wclaxp.exe \WATCOM\binnt
cd c:\temp\OW18src\bld\cc\nt386.axp
wmake
copy wccaxpc.exe \WATCOM\binnt\wccaxp.exe
copy wccdaxpc.dll \WATCOM\binnt\wccdaxp.dll
cd c:\temp\OW18src\bld\as\alpha\nt386
wmake
copy wasaxp.exe \WATCOM\binnt

Now for the Fortran 77 compiler. Please note that the default flags include -we which will cause the compiler to error if there is a warning. And as luck would have it, one function doesn’t declare a prototype… So you can either remove the -we flat from the mif file, or fix the c file… The choice is yours.

cd c:\temp\OW18src\bld\f77\wfl\nt386.axp
wmake
copy wflaxp.exe \WATCOM\binnt
cd c:\temp\OW18src\bld\f77\wfc\nt386.axp
wmake
copy wfcaxp.exe \WATCOM\binnt
attrib c:\temp\OW18src\bld\f77\f77lib\flags.mif -r
notepad c:\temp\OW18src\bld\f77\f77lib\flags.mif

Do a search and replace on -we and replace it with nothing…

cd c:\temp\OW18src\bld\f77\f77lib\winnt.axp\_s
wmake
copy flib.lib \WATCOM\libaxp

With all that out of the way, let’s build some test programs…

Let’s start with hello.f for the Fortran compiler.

C234567
program hello
print *, ‘Hello!’
end

c:\temp>wflaxp hello.f
Open Watcom F77 Alpha AXP Compile and Link Utility Version 1.8
Portions Copyright (c) 1990-2002 Sybase, Inc. All Rights Reserved.
Source code is available under the Sybase Open Watcom Public License.
See http://www.openwatcom.org/ for details.
wfcaxp hello.f
Open Watcom FORTRAN 77 Alpha AXP Optimizing Compiler Version 1.8
Portions Copyright (c) 1984-2002 Sybase, Inc. All Rights Reserved.
Source code is available under the Sybase Open Watcom Public License.
See http://www.openwatcom.org/ for details.
hello.f: 3 statements, 40 bytes, 1 extensions, 0 warnings, 0 errors

Open Watcom Linker Version 1.8
Portions Copyright (c) 1985-2002 Sybase, Inc. All Rights Reserved.
Source code is available under the Sybase Open Watcom Public License.
See http://www.openwatcom.org/ for details.
loading object files
searching libraries
creating a Windows NT(AXP) character-mode executable

c:\temp>

Watcom Fortran cross on Dec Alpha

Watcom Fortran cross on Dec Alpha

Ok, now that’s enough for now…! Later I’ll show how to build these compilers so they’ll run on the Dec Alpha.

Microsoft eMbedded Visual C++ 4.0

Well I was looking for a way to cross compile to the MIPS and also if I could use my old Platform builder 2.11… Anyways Platform builder has cross compilers, but no libraries, I figured you need the eMbeded Visual C++.. And as luck has it, you can download it right here!. Also you’ll probably want service pack 4.(local mirror), and don’t forget the code TRT7H-KD36T-FRH8D-6QH8P-VFJHQ

System Requirements

  • Supported Operating Systems: Windows 2000; Windows XP
  • Microsoft Windows® 2000 Professional SP2, Microsoft Windows 2000 Server SP2, or Microsoft Windows XP Professional
  • A desktop computer with a Pentium-II class processor, 450 MHz or faster
  • 96 MB (128 MB recommended) memory for Windows 2000 Professional or Windows XP Professional. 192 MB (256 MB recommended) memory for Windows 2000 Server.
  • 200 MB hard disk space
  • CD-ROM drive
  • VGA or higher-resolution monitor. A Super VGA (800 x 600 or larger) monitor is recommended.
  • Mouse or compatible pointing device

If your machine is NOT up to this kind of capability, then you can download the older eMbedded Visaul C++ 3.0, that will run on Windows NT 4.0 (i386 of course). Purdue also had a nice walkthrough on installing the 3.0 tool kit.

I DO recommend that you install IIS on your cross compiling machine, as it’s an easy way to move your object files to the MIPS host for linking.

It is worth noting that Visual C++ 4.0’s emulator will NOT run under Virtual PC.. They use the same call set, and it thinks VPC is Windows CE… I know it’s confusing.

I would imagine everyone could run this. Well if they were so inclined.. Well the installation is pretty simple but now for the ‘fun’ stuff.

First let’s download the source code to Quake.. ID software has been most kind to provide the Quake engine under the GPL!. So we can use it for a MIPS cross compile test.. (As far as I know there is no Dec Alpha cross compiler, but there is a PowerPC.. Anyone use a PowerPC NT machine?). You can download it here. .This went nowhere, as it turns out WindowsCE and Windows NT use different models for floating point, and are incompatible.

Ok with your embedded tools installed, we are now going to merge our Visual C++ MIPS CD so we use it for libraries & include files.. Since we are all going to use the same compiler it’ll be somewhat easy.. I’m using the tools out of “C:\Program Files\Microsoft eMbedded C++ 4.0\EVC\WCE400”

11/27/2001. 03:00 AM........ 1,073,152 C1XX_MP.DLL
11/27/2001. 03:00 AM.......... 581,632 C1_MP.DLL
11/27/2001. 03:00 AM........ 1,056,768 C2_MP.DLL
11/27/2001. 03:00 AM........... 69,632 CLMIPS.EXE
06/13/2001. 03:00 AM.......... 180,276 MSPDB60.DLL

To make it “feel” like visual c++ 2.0 I’m going to put them in the c:\msvc20\bin directory on my HOST pc (Vista Pro x64).. Then I simply copy the include & lib directory from the MIPS Visual C++ CD into the corresponding directories on my host.. We are ALMOST there.

The next thing I did was to grab an intel copy of Visual C++ 2.0 (I almost be dammed near all of them can do this..) and take it’s linker.. The linker out of the embedded tools is obsessed with the WindowsCE subsystem which won’t help us at ALL.

09/16/1994. 01:00 PM........... 67,584 DBI.DLL
09/16/1994. 01:00 PM........... 12,980 LINK.ERR
09/16/1994. 01:00 PM.......... 420,352 LINK.EXE

Go ahead and place those files into the c:\msvc20\bin directory.

Now we just need to create a simple batch file to keep our environment in order:

set LIB=c:\msvc20\lib
set PATH=c:\msvc20\bin;%path%
set include=c:\msvc20\include

Save that to something like mipvars.cmd, and run it & we should be ready to start compiling!

To test the cross compiler I’m going to build a SIMPLE program that has 2 files.

hi.c


#include <stdio.h>

extern int bob(void);

void main(void)
{
printf("%d",bob());
}

bob.c

int bob(void)
{
return 3;
}

Ok, now we compile it like so:

C:\msvc20>clmips *.c -o bob.exe
Microsoft (R) C/C++ Optimizing Compiler Version 12.20.9419 for MIPS R-Series
Copyright (C) Microsoft Corp 1984-2001. All rights reserved.

bob.c
hi.c
Generating Code...
Microsoft (R) 32-Bit Incremental Linker Version 2.50
Copyright (C) Microsoft Corp 1992-94. All rights reserved.

/out:bob.exe
/out:bob.exe
bob.obj
hi.obj
LINK : error LNK1104: cannot open file "corelibc.lib"

Oh no trouble!. Because this was all ripped from the embeded tools it wants to think it has corelibc not libc.. But we can cheat, just copy libc.lib to corelibc.lib and I’ve also copied rpcndr.lib to coredll.lib to satisfy the linker.. Now when we re-compile:

C:\msvc20>clmips *.c -o bob.exe
Microsoft (R) C/C++ Optimizing Compiler Version 12.20.9419 for MIPS R-Series
Copyright (C) Microsoft Corp 1984-2001. All rights reserved.

bob.c
hi.c
Generating Code...
Microsoft (R) 32-Bit Incremental Linker Version 2.50
Copyright (C) Microsoft Corp 1992-94. All rights reserved.

/out:bob.exe
/out:bob.exe
bob.obj
hi.obj

That’s right, we got an executable!. Now if you run it on your x86(or x64) host you’ll get this:

c:\msvc20\bob.exe is not a valid Win32 application.

And of course, since you installed IIS on your HOST (or cross compiling VM) you can connect to it from your MIPS VM, download the exe & run it.

MIPS cross compile
MIPS cross compile

I’m kind of surprised it worked.. It does go to show though, that somewhere inside Microsoft they have some COOL cross compiler technology, it’s just too bad they didn’t make it into an easy package for the RISC stuff.. But now that the MIPS is coming back to life via Qemu, and NT 4.0 can be had for $5 a retail box on ebay, I figure it’s worth this much for those people who can find Visual C++ for MIPS/RISC.

easy68k & sozobon

Easy68k

I know this is a little weird to follow, but I thought it was somewhat interesting. Anyways I’ve been reading up on some CP/M stuff, and found some interesting m68k stuff. There is this really cool m68k simulator/test environment called easy68k. Ok so the 68000 isn’t exactly the hottest chip, but for anyone that’s used a Mac, Amiga, Atari ST, SEGA Genesis, or old SUN the m68000 was the end all be all CPU. Anyways you can download the easy68k simulator from here:

http://www.easy68k.com/

Now I’ve never been really all that good with assembly. I know one day I should learn, but until then, there is higher level languages, and of course the best ‘medium’ level language C. Back in the day the ‘sozobon’ compiler was somewhat portable, and a good & easy 16 bit C compiler. Now as far as I know there really hasn’t been any activity on this since 1991, so it’s getting hard to find, and of course the archived copies I found needed LZH.. You can find some archived copies here:

http://umich.edu/~archive/atari/Languages/Sozo2/

Since I didn’t want to go thru a big ordeal, I found an extracted copy of the sources here:

http://cd.textfiles.com/crawlycrypt1/program/compiler/sozobon/

Building the sozobon compiler

Using wget I pulled down the source code. It’s worth noting that unlike GCC this is SMALL… although it only targets the 68000 cpu. The only source that I’m using is the actual C compiler. I suppose if I were better I could map the simulator, and setup the assembler & linker to target the environment all the way… However for now I’m just interested in showing the relationship between a compiler, to the assembler. Now the source is old enough that it uses the reserved word inline in gunk.c I simply changed it to Xinline. I’ve attached a diff for those who like diff’s however as you can see it’s really simple, I just renamed them, so they don’t conflict.


--- gunk.c Fri Feb 22 05:33:34 1991
+++ gunk-fix.c Mon Mar 9 14:35:33 2009
@@ -37,7 +37,7 @@
int (rewri)(); / rewrite function */
};

-int m_unfold(), unfold(), m_cast(), cast(), m_inline(), inline();
+int m_unfold(), unfold(), m_cast(), cast(), m_inline(), Xinline();
int m_hardas(), hardas(), m_fcmp(), fcmp(), m_md_shf(), md_shf();
int m_eident(), eident(), m_incdec(), incdec(), m_fldas(), fldas();

@@ -48,7 +48,7 @@
{m_eident, eident},
{m_incdec, incdec},
{m_hardas, hardas},
- {m_inline, inline}, /* must cast before inline /
+ {m_inline, Xinline}, /
must cast before inline */
{m_fcmp, fcmp},
{m_fldas, fldas},
{0}
@@ -424,7 +424,7 @@
return 0;
}

-inline(np)
+Xinline(np)
NODEP np;
{
register NODEP nmp, cmap;
@@ -782,7 +782,7 @@
register NODEP tp;

spar1 = "%fpcmp";
- inline(np);
+ Xinline(np);

tp = copyone(np);
tp->n_left = np->n_left;

Now with that out of the way, you should be able to build with the make.unx


% make -f make.unx
gcc -DUNIX -O -c d2.c
gcc -DUNIX -O -c decl.c
gcc -DUNIX -O -c expr.c
gcc -DUNIX -O -c fix.c
gcc -DUNIX -O -c fun.c
gcc -DUNIX -O -c g2.c
gcc -DUNIX -O -c gen.c
gcc -DUNIX -O -c gsub.c
gcc -DUNIX -O -c gunk.c
gcc -DUNIX -O -c main.c
main.c:424: warning: 'optnl' was declared implicitly 'extern' and later 'static'
main.c:417: warning: previous declaration of 'optnl'
gcc -DUNIX -O -c md.c
gcc -DUNIX -O -c nodes.c
gcc -DUNIX -O -c out_st.c
gcc -DUNIX -O -c p2.c
gcc -DUNIX -O -c pre.c
gcc -DUNIX -O -c tok.c
gcc -DUNIX -O -c subs_c.c
gcc -o xhcc d2.o decl.o expr.o fix.o fun.o g2.o gen.o gsub.o gunk.o main.o md.o nodes.o out_st.o p2.o pre.o tok.o subs_c.o

Writing hello world!

OK, with the compiler built, let’s write a simple C program. I’ve setup a simple main, and calls to a ‘putc’ and an ‘exit’ that currently don’t do anything. We will have to fix that in the assembly source.. but for now it’s nice as it sets up a place holder.



char MESSAGE[]="this is a message";
void putc(c)
char *c;
{

}
void exit()
{}

void main()
{
int j;
j=0;
putc(MESSAGE);
exit();
}

Now we can compile the source file (x.c) and use the -S flag, so it only outputs an assembly source, that we can then massage to work with easy68k.


% ./xhcc -S x.c ; cat x.s
.data
.globl _MESSAGE
_MESSAGE:
.dc.b $74,$68,$69,$73,$20,$69,$73,$20,$61,$20,$6d
.dc.b $65,$73,$73,$61,$67,$65
.dc.b 0
.text
.globl _putc
_putc:
bra L1
L0:
;var 4 8 _c
L2:
unlk a6
rts
L1:
link a6,#-0
bra L0
.globl _exit
_exit:
bra L4
L3:
L5:
unlk a6
rts
L4:
link a6,#-0
bra L3
.globl _main
_main:
bra L7
L6:
;var 2 -2 _j
clr.w -2(a6)
move.l #_MESSAGE,-(sp)
jsr _putc
add.w #4,sp
jsr _exit
L8:
unlk a6
rts
L7:
link a6,#-2
bra L6
.data

As you can see from the source below the following changes were made:

-Added the ORG $1000
-Changed the formatting of the _MESSAGE into a format that easy68k’s assembler likes.
-Removed all the .globl statements.
-Renamed the _main section to START & and add the end start tags.
-Populated the exit procedure with the ‘exit’ code from easy68k’s example
-Changed putc to use the d0 register instead of d6, and added the print string code from easy68k.


ORG $1000

_MESSAGE dc.b $74,$68,$69,$73,$20,$69,$73,$20,$61,$20,$6d
dc.b $65,$73,$73,$61,$67,$65
dc.b 0

_putc:
bra L1
L0:
;var 4 8 _c
move.b #14,d0
trap #15

L2:
unlk a0
rts
L1:
link a0,#-0
bra L0

_exit:
bra L4
L3:
L5:
unlk a6
rts
L4:
move.b #9,d0
trap #15
link a6,#-0
bra L3

START:
bra L7
L6:
;var 2 -2 _j
clr.w -2(a6)
move.l #_MESSAGE,-(sp)
jsr _putc
add.w #4,sp
jsr _exit
L8:
unlk a6
rts
L7:
link a6,#-2
bra L6
end start

conclusion

Now you can run the code in the simulator, and watch it enter the ‘start’ section, call the putc with the address of _MESSAGE, return to the main, and then call the _exit procedure, which calls the sim68k exit program interrupt. I’ll leave this as an exercise to the read for any real value…. I just thought it was cool, that without really learning any assembly I was able to write a basic ‘hello world’ type program in an hour….

Amiga Days

Do you remember the Commodore Amiga?

I certainly do!

While I was busy fiddling with my Commodore 64, a friend of mine got an Amiga in high school. The 64 was cool, but I was simply blown away by the Amiga. To say there was a gulf between the 8 bit machine, and the quasi 32/16 bit machine would be a massive understatement. His Amiga 2000 could do all kinds of neat things, from talk, run IBM XT software at 100% speed via a “bridge board”, not to mention play super snazzy games. It took me a few years to save up to buy my very own Amiga 500, and once I was ready I didn’t have enough money for a bus ride home, so I walked the FIVE miles home toting my Amiga! I was so happy to say the least!! (At least it was summer, it was flat, and there weren’t any tropical waves/hurricanes around…)

While there are a few emulation alternatives for running the old m68000 software on all kinds of machines, I’m going to talk about AROS today.

AROS is to AmigaDOS what Wine is to Windows. Once it became clear that Commodore was going to die, and that AmigaDOS and the Amiga were lost a few brave people decided that they had to take matters into their own hands. Sadly there was lots of in fighting, a tradition of the comp.sys.amiga.advocacy news group where some people get too tied into little details and let little things (like the rise of Microsoft Windows) pass them by. At any rate, Aaron Digulla knuckled down, and start to write a bug for bug clone of AmigaDOS 3.1 in C to run on the IBM PC. The result of which is AROS. It currently will either run hosted on Linux/NetBSD or natively on the i386. There is a port to the Amd64 undergoing right now. AROS even has SDL support.

So this got me thinking..

What if I were to remove all the OpenGL calls from GLFrontier, and ran it as a strictly 2d app on AROS?

So I took the first step, and I trimmed out the OpenGL support from Tom’s fix of Frontier, so it’s completely SDL 2d friendly, and cross compiled it to AROS. I built the first pass on MinGW, and got frame rates of upwards of 1000 on Vista 64!

Now for the fun part of building an AROS version. While there is now a native GCC for AROS it cannot compile the assembly listing from GLFrontier.. I suspect it’s a heap overflow. This means you have to cross compile. I have cygwin installed in a Windows 2000 VM I use with Virtual PC 2007. I’m not sure if cygwin installs on Vista, let alone Vista 64, however I do suspect it MAY have issues… I keep my dev stuff in a VM so I can move it around without losing my settings.

I downloaded and unpacked the following files into my cygwin installation:

i386-aros-cross-gcc-3.3.1-cygwin.zip

libsdl.a

And the SDL include directory from cygwin.. I think its SDL version 1.2

I did have to find all the ‘exe’ files and make sure they were chmoded +x as the compiler would not run (chmod +x /usr/local/bin/exe /usr/local/i386-aros/bin/ /usr/local/lib/gcc-lib/i386-aros/3.3.1/*exe ). Once you are ready you should be able to build files with

i386-aros-gcc

I’m not sure how to build stripped files, but I suspect it’s out there somewhere. At any rate, I did this to compile my SDL 2d version of FrontierGL:

$ cd as68k

$ make
gcc -O2 -g -Wall -c -o output.o output.c
gcc -O2 -g -Wall -c -o output_c.o output_c.c
gcc -O2 -g -Wall -c -o output_i386.o output_i386.c
output_i386.c:981:1: warning: “_S” redefined
In file included from output_i386.c:6:
/usr/include/ctype.h:35:1: warning: this is the location of the previous definition
output_i386.c: In function x_loadea':
output_i386.c:1373: warning: 'out_reg' might be used uninitialized in this function
output_i386.c: In function
x_loadval’:
output_i386.c:1474: warning: ‘reg3’ might be used uninitialized in this function
output_i386.c:1474: warning: ‘out_reg’ might be used uninitialized in this function
gcc -O2 -g -Wall -c -o as68k.o as68k.c
as68k.c: In function `asm_pass1′:
as68k.c:663: warning: ‘size’ might be used uninitialized in this function
as68k.c:671: warning: ‘coutput_label’ might be used uninitialized in this function
gcc -O2 -g -Wall -c -o dict.o dict.c
gcc -O2 -g -Wall output.o output_c.o output_i386.o as68k.o dict.o -o as68k

$ cd ..

$ as68k/as68k.exe –output-i386 fe2.s
Pass 1
Pass 2
Done! 539337 bytes and 759 relocations.

$ i386-aros-gcc -c fe2.s.S

$ i386-aros-gcc -O2 -I /usr/local/i386-aros/sys-include/sdl -c audio.c
audio.c: In function Audio_Init':
audio.c:334: warning: passing arg 5 of
SDL_LoadWAV_RW’ from incompatible pointer type

$ cd src

$ i386-aros-gcc -O2 -I /usr/local/i386-aros/sys-include/sdl -c hostcall.c

$ i386-aros-gcc -O2 -I /usr/local/i386-aros/sys-include/sdl -c input.c

$ i386-aros-gcc -O2 -I /usr/local/i386-aros/sys-include/sdl -c keymap.c

$ i386-aros-gcc -O2 -I /usr/local/i386-aros/sys-include/sdl -c main.c

$ i386-aros-gcc -O2 -I /usr/local/i386-aros/sys-include/sdl -c screen.c
screen.c: In function `draw_control_panel’:
screen.c:274: warning: assignment makes integer from pointer without a cast

$ i386-aros-gcc -O2 -I /usr/local/i386-aros/sys-include/sdl -c shortcut.c

$ i386-aros-gcc *.o ../fe2.s.o -lsdl -o ../frontier

$ cd ..

$ file frontier
frontier: ELF 32-bit LSB relocatable, Intel 80386, version 1 (SYSV), not stripped

$ i386-aros-size frontier
text data bss dec hex filename
2580672 2036 1422076 4004784 3d1bb0 frontier

*REMEMBER as68k has to actually run on the host machine, so it needs to be native, you cannot use a cross compiler for that. However you do cross compile it’s output.

Naturally you’ll now want to run your exe!

For testing the binaries you’ll need some kind of Aros system, I recommend WinAROS, it’s a pre-built Qemu package, so the disk will work on all kinds of platforms. You can download it here: WinAros Developer

This is a pretty snazzy setup, I recommend booting into a 32bit depth display option, however you will want to modify the default script to look like this at the last line:

qemu.exe -L . -m 256 -localtime -boot c -hda WinArosHD.img -no-kqemu -net nic -net user

The next thing you’ll want to do is enable the networking. I don’t know why it’s disabled by default, but with a few moments in the CLI, and edit you can have it running:

To get the network running you have to go into Extras:Networking/Stacks/AROSTCP/db and edit static-routes, netbd-myhost, and interfaces.

First edit interfaces and uncomment the line that has device prm-rtl8029 and change the IP to 10.0.2.15

Second edit netbd-myhost and make it look like this:
HOST 10.0.2.15 arosbox.arosnet arosbox
DOMAIN arosnet 10.0.2.
NAMESERVER 10.0.2.3

Third edit static-routes and change the address to 10.0.2.2

Last add the following line to your user-startup
Execute Extras:Networking/Stacks/AROSTCP/S/startnet.

Now reboot. Open a shell and verify that you have a connection with “ifconfig -a”
You can also try to ping a website, but you might not get any return packets because of QEMU’s built in firewall. You should at least see the ip address for the site you ping. Or ping 10.0.2.2 to make sure you network is communicating with Qemu.

Now for the final moment, put your exe on a web server, and simply use wget to get it! I’d recommend zipping up your work directory, so it includes the ‘bin’ file, and the structure that GLFrontier expects. I like the zip file format as WinAROS includes unzip.

I do the following from AROS

Wget http://192.168.1.10/front.zip
Unzip front.zip

It’s that easy! Now you can either ‘cd’ or click on your frontier, and away it should go!

The video is a bit wonky in that it seems to only work in 8 bit or 24bit depths. So far I’ve only tested this in WinArosDeveloper.

It actually works, the keyboard is buggy as hell, but you can play with the mouse. The first key code seems to work, then it gets stuck, so I recommend the ‘enter’ key so you can thrust…

I’ve published my zip up to The AROS Archives with any luck when it’s there I’ll update it with a link to it. In the mean time, I’ll provide a dump of the screen.c that I fixed to remove the OpenGL support. Naturally blogspot will screw up the formatting, however it should work…

#include
#include “main.h”
#include “../m68000.h”
#include “screen.h”

/* new stuff */
enum RENDERERS use_renderer = R_OLD;
int len_main_palette;
unsigned short MainPalette[256];
unsigned short CtrlPalette[16];
int fe2_bgcol;
int mouse_shown = 0;
unsigned long logscreen, logscreen2, physcreen, physcreen2;
unsigned long VideoBase;
unsigned char *VideoRaster;
unsigned int MainRGBPalette[256];
unsigned int CtrlRGBPalette[16];
int screen_w=320;
int screen_h=200;
BOOL bGrabMouse = FALSE;
BOOL bInFullScreen = FALSE;
SDL_Surface *sdlscrn;

static const unsigned char font_bmp[] = {
0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x2,0x80,0x80,0x80,0x80,0x80,0x0,
0x80,0x0,0x0,0x2,0xa0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4,0x0,0x50,
0xf8,0x50,0x50,0xf8,0x50,0x0,0x0,0x6,0x20,0xf0,0xa0,0xa0,0xa0,0xa0,0xf0,0x20,
0x0,0x5,0x0,0xc8,0xd8,0x30,0x60,0xd8,0x98,0x0,0x0,0x6,0xa0,0x0,0xe0,0xa0,
0xa0,0xa0,0xe0,0x0,0x0,0x4,0x80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x2,
0xc0,0x80,0x80,0x80,0x80,0x80,0x80,0xc0,0x0,0x3,0xc0,0x40,0x40,0x40,0x40,0x40,
0x40,0xc0,0x0,0x3,0x0,0x0,0x20,0xf8,0x50,0xf8,0x20,0x0,0x0,0x6,0x0,0x0,
0x40,0xe0,0x40,0x0,0x0,0x0,0x0,0x4,0x0,0x0,0x0,0x0,0x0,0x0,0x80,0x80,
0x0,0x2,0x0,0x0,0x0,0xc0,0x0,0x0,0x0,0x0,0x0,0x3,0x0,0x0,0x0,0x0,
0x0,0x0,0x80,0x0,0x0,0x2,0x0,0x8,0x18,0x30,0x60,0xc0,0x80,0x0,0x0,0x6,
0xe0,0xa0,0xa0,0xa0,0xa0,0xa0,0xe0,0x0,0x0,0x4,0x40,0xc0,0x40,0x40,0x40,0x40,
0xe0,0x0,0x0,0x4,0xe0,0x20,0x20,0xe0,0x80,0x80,0xe0,0x0,0x0,0x4,0xe0,0x20,
0x20,0xe0,0x20,0x20,0xe0,0x0,0x0,0x4,0x80,0x80,0xa0,0xa0,0xe0,0x20,0x20,0x0,
0x0,0x4,0xe0,0x80,0x80,0xe0,0x20,0x20,0xe0,0x0,0x0,0x4,0xe0,0x80,0x80,0xe0,
0xa0,0xa0,0xe0,0x0,0x0,0x4,0xe0,0x20,0x20,0x20,0x20,0x20,0x20,0x0,0x0,0x4,
0xe0,0xa0,0xa0,0xe0,0xa0,0xa0,0xe0,0x0,0x0,0x4,0xe0,0xa0,0xa0,0xe0,0x20,0x20,
0xe0,0x0,0x0,0x4,0x0,0x0,0x0,0x80,0x0,0x80,0x0,0x0,0x0,0x2,0x0,0x0,
0x0,0x80,0x0,0x0,0x80,0x80,0x0,0x2,0xe0,0x0,0xe0,0xa0,0xa0,0xa0,0xa0,0x0,
0x0,0x4,0x0,0x0,0xe0,0x0,0xe0,0x0,0x0,0x0,0x0,0x4,0xc0,0x0,0xe0,0xa0,
0xe0,0x80,0xe0,0x0,0x0,0x4,0xe0,0x20,0x20,0xe0,0x80,0x0,0x80,0x0,0x0,0x4,
0xfe,0x82,0xba,0xa2,0xba,0x82,0xfe,0x0,0x0,0x8,0xf0,0x90,0x90,0x90,0xf0,0x90,
0x90,0x0,0x0,0x5,0xf0,0x90,0x90,0xf8,0x88,0x88,0xf8,0x0,0x0,0x6,0xe0,0x80,
0x80,0x80,0x80,0x80,0xe0,0x0,0x0,0x4,0xf8,0x48,0x48,0x48,0x48,0x48,0xf8,0x0,
0x0,0x6,0xf0,0x80,0x80,0xe0,0x80,0x80,0xf0,0x0,0x0,0x5,0xf0,0x80,0x80,0xe0,
0x80,0x80,0x80,0x0,0x0,0x4,0xf0,0x80,0x80,0x80,0xb0,0x90,0xf0,0x0,0x0,0x5,
0x90,0x90,0x90,0xf0,0x90,0x90,0x90,0x0,0x0,0x5,0xe0,0x40,0x40,0x40,0x40,0x40,
0xe0,0x0,0x0,0x4,0xf0,0x20,0x20,0x20,0x20,0x20,0xe0,0x0,0x0,0x4,0x90,0xb0,
0xe0,0xc0,0xe0,0xb0,0x90,0x0,0x0,0x5,0x80,0x80,0x80,0x80,0x80,0x80,0xe0,0x0,
0x0,0x4,0x88,0xd8,0xf8,0xa8,0x88,0x88,0x88,0x0,0x0,0x6,0x90,0xd0,0xf0,0xb0,
0x90,0x90,0x90,0x0,0x0,0x5,0xf0,0x90,0x90,0x90,0x90,0x90,0xf0,0x0,0x0,0x5,
0xf0,0x90,0x90,0xf0,0x80,0x80,0x80,0x0,0x0,0x5,0xf0,0x90,0x90,0x90,0x90,0xb0,
0xf0,0x18,0x0,0x5,0xf0,0x90,0x90,0xf0,0xe0,0xb0,0x90,0x0,0x0,0x5,0xf0,0x80,
0x80,0xf0,0x10,0x10,0xf0,0x0,0x0,0x5,0xe0,0x40,0x40,0x40,0x40,0x40,0x40,0x0,
0x0,0x3,0x90,0x90,0x90,0x90,0x90,0x90,0xf0,0x0,0x0,0x5,0x90,0x90,0x90,0xb0,
0xe0,0xc0,0x80,0x0,0x0,0x5,0x88,0x88,0x88,0xa8,0xf8,0xd8,0x88,0x0,0x0,0x6,
0x88,0xd8,0x70,0x20,0x70,0xd8,0x88,0x0,0x0,0x6,0x90,0x90,0x90,0xf0,0x20,0x20,
0x20,0x0,0x0,0x5,0xf0,0x10,0x30,0x60,0xc0,0x80,0xf0,0x0,0x0,0x5,0xa0,0x0,
0xa0,0xa0,0xa0,0xa0,0xe0,0x0,0x0,0x4,0x0,0x80,0xc0,0x60,0x30,0x18,0x8,0x0,
0x0,0x6,0xe0,0xa0,0xa0,0xe0,0xa0,0xa0,0xe0,0x80,0x80,0x4,0xe0,0xa0,0xe0,0x0,
0x0,0x0,0x0,0x0,0x0,0x4,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf8,0x0,0x6,
0xa0,0x0,0xe0,0x20,0xe0,0xa0,0xe0,0x0,0x0,0x4,0x0,0x0,0xe0,0x20,0xe0,0xa0,
0xe0,0x0,0x0,0x4,0x80,0x80,0xe0,0xa0,0xa0,0xa0,0xe0,0x0,0x0,0x4,0x0,0x0,
0xc0,0x80,0x80,0x80,0xc0,0x0,0x0,0x3,0x20,0x20,0xe0,0xa0,0xa0,0xa0,0xe0,0x0,
0x0,0x4,0x0,0x0,0xe0,0xa0,0xe0,0x80,0xe0,0x0,0x0,0x4,0xc0,0x80,0x80,0xc0,
0x80,0x80,0x80,0x0,0x0,0x3,0x0,0x0,0xe0,0xa0,0xa0,0xa0,0xe0,0x20,0xe0,0x4,
0x80,0x80,0xe0,0xa0,0xa0,0xa0,0xa0,0x0,0x0,0x4,0x80,0x0,0x80,0x80,0x80,0x80,
0x80,0x0,0x0,0x2,0x40,0x0,0x40,0x40,0x40,0x40,0x40,0xc0,0x0,0x3,0x80,0x80,
0xb0,0xe0,0xe0,0xb0,0x90,0x0,0x0,0x5,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x0,
0x0,0x2,0x0,0x0,0xf8,0xa8,0xa8,0xa8,0xa8,0x0,0x0,0x6,0x0,0x0,0xe0,0xa0,
0xa0,0xa0,0xa0,0x0,0x0,0x4,0x0,0x0,0xe0,0xa0,0xa0,0xa0,0xe0,0x0,0x0,0x4,
0x0,0x0,0xe0,0xa0,0xa0,0xa0,0xe0,0x80,0x80,0x4,0x0,0x0,0xe0,0xa0,0xa0,0xa0,
0xe0,0x20,0x30,0x4,0x0,0x0,0xc0,0x80,0x80,0x80,0x80,0x0,0x0,0x3,0x0,0x0,
0xc0,0x80,0xc0,0x40,0xc0,0x0,0x0,0x3,0x80,0x80,0xc0,0x80,0x80,0x80,0xc0,0x0,
0x0,0x3,0x0,0x0,0xa0,0xa0,0xa0,0xa0,0xe0,0x0,0x0,0x4,0x0,0x0,0xa0,0xa0,
0xe0,0xc0,0x80,0x0,0x0,0x4,0x0,0x0,0x88,0xa8,0xf8,0xd8,0x88,0x0,0x0,0x6,
0x0,0x0,0xa0,0xe0,0x40,0xe0,0xa0,0x0,0x0,0x4,0x0,0x0,0xa0,0xa0,0xa0,0xa0,
0xe0,0x20,0xe0,0x4,0x0,0x0,0xf0,0x30,0x60,0xc0,0xf0,0x0,0x0,0x5,0x81,0x8d,
0xe1,0xa0,0xa0,0xa0,0xa0,0x0,0x0,0x9,0x2,0x1a,0xc2,0x80,0xc0,0x40,0xc0,0x0,
0x0,0x8,0xfe,0xfc,0xf8,0xfc,0xfe,0xdf,0x8e,0x4,0x0,0x7,0x7f,0x3f,0x1f,0x3f,
0x7f,0xfb,0x71,0x20,0x0,0x8,0x4,0x8e,0xdf,0xfe,0xfc,0xf8,0xfc,0xfe,0x0,0x8,
0x20,0x71,0xfb,0x7f,0x3f,0x1f,0x3f,0x7f,0x0,0x7,0xff,0x81,0x81,0x81,0x81,0x81,
0x81,0xff,0x0,0x9,0x0,0x0,0xe0,0x80,0x80,0x80,0xe0,0x40,0xc0,0x4,0x60,0x0,
0xe0,0xa0,0xe0,0x80,0xe0,0x0,0x0,0x4,0xc0,0x0,0xa0,0xa0,0xa0,0xa0,0xe0,0x0,
0x0,0x4,0x40,0xa0,0x40,0x40,0x40,0x40,0x40,0x0,0x0,0x4,0x40,0xa0,0xe0,0x20,
0xe0,0xa0,0xe0,0x0,0x0,0x4,0x40,0xa0,0xe0,0xa0,0xa0,0xa0,0xe0,0x0,0x0,0x4,
0x40,0xa0,0xe0,0xa0,0xe0,0x80,0xe0,0x0,0x0,0x4,0xe0,0x0,0xa0,0xa0,0xa0,0xa0,
0xe0,0x0,0x0,0x4,0xc0,0x0,0xe0,0x20,0xe0,0xa0,0xe0,0x0,0x0,0x4,0xe0,0xa0,
0xa0,0xa0,0xe0,0xa0,0xa0,0x0,0x0,0x4,0xc0,0xa0,0xa0,0xc0,0xa0,0xa0,0xc0,0x0,
0x0,0x4,0xe0,0x80,0x80,0x80,0x80,0x80,0xe0,0x0,0x0,0x4,0xc0,0xa0,0xa0,0xa0,
0xa0,0xa0,0xc0,0x0,0x0,0x4,0xe0,0x80,0x80,0xe0,0x80,0x80,0xe0,0x0,0x0,0x4,
0xe0,0x80,0x80,0xe0,0x80,0x80,0x80,0x0,0x0,0x4
};

static inline void read_m68k_vertex (int st_vptr, int output[3])
{
output[0] = STMemory_ReadLong (st_vptr);
output[1] = STMemory_ReadLong (st_vptr+4);
output[2] = -STMemory_ReadLong (st_vptr+8);
}

struct ZNode {
unsigned int z;
struct ZNode *less, *more;
void *data;
};

#define MAX_OBJ_DATA (2<<17)
static unsigned char obj_data_area[MAX_OBJ_DATA];
static int obj_data_pos;
#define MAX_ZNODES 1000
static struct ZNode znode_buf[MAX_ZNODES];
static int znode_buf_pos;
static struct ZNode *znode_start;
static struct ZNode *znode_cur;

enum NuPrimitive {
NU_END,
NU_TRIANGLE,
NU_QUAD,
NU_LINE,
NU_BEZIER_LINE,
NU_TEARDROP,
NU_COMPLEX_SNEXT,
NU_COMPLEX_START,
NU_COMPLEX_END,
NU_COMPLEX_INNER,
NU_COMPLEX_BEZIER,
NU_TWINKLYCIRCLE,
NU_PLANET,
NU_CIRCLE,
NU_CYLINDER,
NU_BLOB,
NU_OVALTHINGY,
NU_POINT,
NU_2DLINE,
NU_MAX
};

#define MAX_QUEUED_STRINGS 200
struct QueuedString {
int x, y, col;
unsigned char str[64];
} queued_strings[MAX_QUEUED_STRINGS];
int queued_string_pos;
static bool no_znodes_kthx;

/*********PROTOTYPES****************/
static void _BuildRGBPalette (unsigned int *rgb, unsigned short *st, int len);
static void draw_3dview (struct ZNode *node);
static int DrawChar (int col, int xoffset, char *scrline, int chr);
static void Nu_DrawPrimitive (void *data);
static inline int znode_rdlong (void **data);
static void add_node (struct ZNode **node, unsigned int zval);
static void znode_insert (struct ZNode *node, unsigned int zval);
static inline void end_node ();
static inline void znode_databegin ();
static inline void znode_wrlong (int val);

int DrawStr (int xpos, int ypos, int col, unsigned char *str, bool shadowed)
{
int x, y, chr;
char *screen;

x = xpos;
y = ypos;

if ((y > 192) || (y<0)) return x;
set_line:
screen = LOGSCREEN2;
screen += SCREENBYTES_LINE * y;

while (*str) {
chr = *(str++);

if (chr < 0x1e) {
if (chr == ‘\r’) {
y += 10;
x = xpos;
goto set_line;
}
else if (chr == 1) col = *(str++);
continue;
} else if (chr == 0x1e) {
/* read new xpos */
x = *(str++);
x *= 2;
continue;
} else if (chr < 0x20) {
/* Read new position */
x = *(str++);
x *= 2;
y = *(str++);
goto set_line;
}

//if (x > 316) continue;

if (shadowed) {
DrawChar (0, x+1, screen+SCREENBYTES_LINE, chr-0x20);
}
x = DrawChar (col, x, screen, chr-0x20);
}

return x;
printf (“DrawStr [%s]\n”,str);
return 0;
}

void Nu_PutColoredPoint()
{}

void Nu_ComplexSNext()
{}
void Nu_DrawComplexSNext()
{}

void Nu_DrawComplexStart()
{}
void Nu_DrawComplexEnd()
{}

void Nu_ComplexStartInner()
{}
void Nu_DrawComplexStartInner()
{}
void Nu_ComplexBezier()
{}
void Nu_DrawComplexBezier()
{}

void draw_control_panel()
{
unsigned int *pal;
// Lock surface if needed
if (SDL_MUSTLOCK(sdlscrn))
if (SDL_LockSurface(sdlscrn) < 0)
return;

// Declare a couple of variables
int y, x, yofs, ofs;

// Draw to screen
yofs = 0;
pal=MainRGBPalette;
for (y = 0; y < screen_h; y++)
{
if(y==168)pal=CtrlRGBPalette; //bottom has differnet palette
for (x = 0, ofs = yofs; x < screen_w; x++, ofs++)
{
//((unsigned int*)sdlscrn->pixels)[ofs] = pal[VideoRaster[ofs]];

switch (sdlscrn->format->BytesPerPixel)
{
case 1: // 8-bpp
{
Uint8 *bufp;
bufp = (Uint8 *)sdlscrn->pixels + y*sdlscrn->pitch + x;
*bufp =(Uint8*) pal[VideoRaster[ofs]];
}
break;
case 2: // 15-bpp or 16-bpp
{
Uint16 *bufp;
bufp = (Uint16 *)sdlscrn->pixels + y*sdlscrn->pitch/2 + x;
*bufp = pal[VideoRaster[ofs]];
}
break;
case 3: // 24-bpp mode, usually not used
{
Uint8 *bufp;
bufp = (Uint8 *)sdlscrn->pixels + y*sdlscrn->pitch + x * 3;
if(SDL_BYTEORDER == SDL_LIL_ENDIAN)
{
bufp[0] = pal[VideoRaster[ofs]];
bufp[1] = pal[VideoRaster[ofs]] >> 8;
bufp[2] = pal[VideoRaster[ofs]] >> 16;
} else {
bufp[2] = pal[VideoRaster[ofs]];
bufp[1] = pal[VideoRaster[ofs]] >> 8;
bufp[0] = pal[VideoRaster[ofs]] >> 16;
}
}
break;
case 4: // 32-bpp
{
Uint32 *bufp;
bufp = (Uint32 *)sdlscrn->pixels + y*sdlscrn->pitch/4 + x;
*bufp = pal[VideoRaster[ofs]];
}
break;
}

}
//yofs += sdlscrn->pitch / 4;
yofs += sdlscrn->pitch / sdlscrn->format->BytesPerPixel;
}

// Unlock if needed
if (SDL_MUSTLOCK(sdlscrn))
SDL_UnlockSurface(sdlscrn);

// Tell SDL to update the whole screen
SDL_UpdateRect(sdlscrn, 0, 0, screen_w, screen_h);

//printf(“draw_control_panel\n”);
}

void Nu_DrawScreen()
{
_BuildRGBPalette (MainRGBPalette, MainPalette, len_main_palette);
_BuildRGBPalette (CtrlRGBPalette, CtrlPalette, 16);
//printf (“Frame: %d znodex.\n”,znode_buf_pos);
//draw_3dview (znode_start);
if (mouse_shown) {
SDL_ShowCursor (SDL_ENABLE);
mouse_shown = 0;
} else {
SDL_ShowCursor (SDL_DISABLE);
}
draw_control_panel();
//set_main_viewport();

//printf(“Nu_DrawScreen\n”);

}

void Nu_PutBezierLine()
{}
void Nu_DrawBezierLine()
{}

void Nu_3DViewInit()
{
queued_string_pos = 0;
//printf (“3dviewinit()\n”);
znode_buf_pos = 0;
//printf (“%d bytes object data\n”, obj_data_pos);
obj_data_pos = 0;

znode_start = NULL;
znode_cur = NULL;
no_znodes_kthx = FALSE;
}
void Nu_InsertZNode()
{
unsigned int zval = GetReg (4);
if (use_renderer == R_OLD) return;
if (no_znodes_kthx) return;
if (znode_start == NULL) {
add_node (&znode_start, zval);
} else {
znode_insert (znode_start, zval);
}
}

void Nu_PutCircle()
{}
void Nu_DrawCircle()
{}

void Nu_PutOval()
{}
void Nu_DrawOval()
{}

void Nu_PutCylinder()
{}
void Nu_DrawCylinder()
{}

void Nu_QueueDrawStr()
{}
void Nu_IsGLRenderer()
{
SetReg(0,0);
}

void Nu_PutPlanet()
{}
void Nu_DrawPlanet()
{}

void Nu_Put2Line()
{}
void Nu_Draw2Line()
{}

void Nu_PutQuad()
{}
void Nu_DrawQuad()
{}

void Nu_GLClearArea()
{}
void Nu_PutBlob()
{use_renderer=R_OLD;}
void Nu_DrawBlob()
{}

void Nu_Put2DLine()
{}
void Nu_Draw2DLine()
{}

void Nu_PutLine()
{}
void Nu_DrawLine()
{}

void Nu_UnInit()
{}

void Nu_PutTeardrop()
{}
void Nu_DrawTeardrop()
{}

void Nu_PutPoint()
{
printf(“Nu_PutPoint\n”);
}
void Nu_DrawPoint()
{}

void Nu_PutTwinklyCircle()
{}
void Nu_DrawTwinklyCircle()
{}

void Nu_ComplexStart()
{}

void Nu_PutTriangle()
{}
void Nu_DrawTriangle()
{}

void Nu_ComplexSBegin()
{}

void Nu_ComplexEnd()
{}

void Nu_32ViewInit()
{}

void Screen_ToggleRenderer ()
{
use_renderer = R_OLD;
}

void change_vidmode(void);

void Screen_Init(void)
{
change_vidmode();
SDL_WM_SetCaption(PROG_NAME, “Frontier”);
SDL_EventState(SDL_MOUSEMOTION, SDL_ENABLE);
SDL_EventState(SDL_MOUSEBUTTONDOWN, SDL_ENABLE);
SDL_EventState(SDL_MOUSEBUTTONUP, SDL_ENABLE);
SDL_ShowCursor(SDL_ENABLE);
use_renderer=R_OLD;
printf(“Screen_Init\n”);
}

void change_vidmode (void)
{
const SDL_VideoInfo *info = NULL;
int modes;

info = SDL_GetVideoInfo ();

assert (info != NULL);

modes = SDL_SWSURFACE;// SDL_ANYFORMAT | (bInFullScreen ? SDL_FULLSCREEN : 0 );

if ((sdlscrn = SDL_SetVideoMode (screen_w, screen_h,
info->vfmt->BitsPerPixel, modes)) == 0) {
fprintf (stderr, “Video mode set failed: %s\n”, SDL_GetError ());
SDL_Quit ();
exit (-1);
}
printf(“change_vidmode %d x %d %d deep\n”,screen_w,screen_h,info->vfmt->BitsPerPixel);
}

void Screen_UnInit(void)
{}
void Screen_ToggleFullScreen()
{
}

static void _BuildRGBPalette (unsigned int *rgb, unsigned short *st, int len)
{
int i;
int st_col, r, g, b;

for (i=0; i>4;
rgb[i] = 0xff000000 | (b<<16) | (g<<8) | (r);
}
}

static int DrawChar (int col, int xoffset, char *scrline, int chr)
{
const char *font_pos;
char *pix;
int i;

font_pos = font_bmp;
font_pos += (chr&0xff)*10;
scrline += xoffset;

if (xoffset < 0) {
font_pos += 9;
return xoffset + *font_pos;
}

for (i=0; i<8; i++, font_pos++, scrline += SCREENBYTES_LINE) {
pix = scrline;
if (xoffset > 319) continue;
if (*font_pos & 0x80) *pix = col;
pix++;
if (xoffset+1 > 319) continue;
if (*font_pos & 0x40) *pix = col;
pix++;
if (xoffset+2 > 319) continue;
if (*font_pos & 0x20) *pix = col;
pix++;
if (xoffset+3 > 319) continue;
if (*font_pos & 0x10) *pix = col;
pix++;
if (xoffset+4 > 319) continue;
if (*font_pos & 0x8) *pix = col;
pix++;
if (xoffset+5 > 319) continue;
if (*font_pos & 0x4) *pix = col;
pix++;
if (xoffset+6 > 319) continue;
if (*font_pos & 0x2) *pix = col;
pix++;
if (xoffset+7 > 319) continue;
if (*font_pos & 0x1) *pix = col;
}
/* width of character */
font_pos++;
i = *font_pos;
return xoffset + i;
}
/*
* znode_start is the head of a btree of znodes, each with a linked list
* of GL display lists to draw (in list order).
*
* Draw this crap starting from biggest value znodes.
*/
static void draw_3dview (struct ZNode *node)
{
if (node == NULL) return;
if (node->more) draw_3dview (node->more);

if (use_renderer) {
printf (“Z=%d “, node->z);
Nu_DrawPrimitive (node->data);
}

if (node->less) draw_3dview (node->less);
printf(“draw_3dview\n”);
}

typedef void (*NU_DRAWFUNC) (void **);
NU_DRAWFUNC nu_drawfuncs[NU_MAX] = {
NULL,
&Nu_DrawTriangle,
&Nu_DrawQuad,
&Nu_DrawLine,
&Nu_DrawBezierLine,
&Nu_DrawTeardrop,
&Nu_DrawComplexSNext, // 6
&Nu_DrawComplexStart,
&Nu_DrawComplexEnd,
&Nu_DrawComplexStartInner, // 9
&Nu_DrawComplexBezier,
&Nu_DrawTwinklyCircle,
&Nu_DrawPlanet,
&Nu_DrawCircle,
&Nu_DrawCylinder,
&Nu_DrawBlob,
&Nu_DrawOval,
&Nu_DrawPoint,
&Nu_Draw2DLine
};

static void Nu_DrawPrimitive (void *data)
{
int fnum;

for (;;) {
fnum = znode_rdlong (&data);
//fprintf (stderr, “%d “, fnum);
if (!fnum) return;
nu_drawfuncs[fnum] (&data);
}
}

static inline int znode_rdlong (void **data)
{
int val = *((int*)(*data));
(*data) += 4;
return val;
}

static void add_node (struct ZNode **node, unsigned int zval)
{
assert (znode_buf_pos < MAX_ZNODES);
/* end previous znode display list!!!!!!! */
if (znode_cur) end_node ();

*node = znode_cur = &znode_buf[znode_buf_pos++];
znode_cur->z = zval;
znode_cur->less = NULL;
znode_cur->more = NULL;
znode_databegin ();
}

static inline void end_node ()
{
znode_wrlong (0);
}

static void znode_insert (struct ZNode *node, unsigned int zval)
{
if (zval > node->z) {
if (node->more) {
znode_insert (node->more, zval);
} else {
add_node (&node->more, zval);
}
} else {
if (node->less) {
znode_insert (node->less, zval);
} else {
add_node (&node->less, zval);
}
}
}

static inline void znode_databegin ()
{
znode_cur->data = &obj_data_area[obj_data_pos];
}

static inline void znode_wrlong (int val)
{
*((int*)(obj_data_area+obj_data_pos)) = val;
obj_data_pos+=4;
}

psim, the PowerPC simulator

Psim is one of those great peices of software that has been long sice forgotten. In every copy of GDB since 4.14 it has been sitting there dormant. What is it? Well it’ll emulate various PowerPC systems to some degree (GXemul & Qemu are better now) but what is cool is the ‘run’ program. Simply put, any system that can run GDB can run powerpc NetBSD statically linked EXE’s! Now isn’t that exciting!

Now I know you’ll want to build your own copy of the ‘run’ program, and then setup a cross compile enviroment so that you, to can produce NetBSD PowerPC executables. I’m assuming that you are not on a PowerPC running NetBSD, since this whole excersize would be… redundant.

For this example I’m using OpenBSD 4.0 on the i386. You will need a real unixy envioment for this. MinGW isn’t good enough, cygwin however is. BSD/Linux will work too.

Ok first let’s start with building the run program. I’m going to download my GDB from ftp://ftp.gnu.org/ .

Gdb 5.3

Unpack it somewhere, and then run the following commadn to configure GDB.

./configure --enable-sim-powerpc --target=powerpc-unknown-eabi --prefix=/usr/local/psim

 

You will need to replace or update the sim/ppc/emul_netbsd.c program to include system calls up to 300, and make sure that 279 is setup to do_fstat. Otherwise you will be unable to run any programs. This is also a good excersize to see how libraries interact with the simulator so you can add your own native interfaces, for things like OpenGL, SDL….

 

Now we are ready to build it.. You could use -O0 in your CFLAGS to build it quicker, but it will result in a slower run times.. If you have issues with this you will want to use those flags so it doesnt take forever to be building this thing. Otherwise a simple ‘make;make install’ will suffice.

Next up is binutils. I’m using version 2.17

Binutils 2.17

Again download and unpack this somewhere (/usr/src?) Then run the following to configure your binutils


./configure --target=powerpc-unknown-netbsd --prefix=/usr/local/psim

Since execution time here isn’t as critical as the emulator, and I want to hurry it along I’m going to use the following command to build & install:


make CFLAGS=’-O0 -pipe’ ;make install

On OpenBSD 4.1 the install fails, and I had to manually copy the binutils applications into /usr/local/psim/powerpc-unknown-netbsd-bin

Before you build gcc you will want to populate your directory with headers & libraries from NetBSD 1.4 get the compiler package and copy the usr/lib files to /usr/local/psim/powerpc-unknown-netbsd/lib and the usr/include files to /usr/local/psim/include . I get my includes & lib files from here ( ftp://ftp.netbsd.org/pub/NetBSD/NetBSD-archive/NetBSD-1.4/macppc/binary/sets/comp.tgz )

Gcc 3.3

You may need to do some special tweaking to this source to get it to run correctly
Optionally running make with CFLAGS=-O0 may speed your compliation.

You know the drill by now. Download, unpack and configure as follows:


./configure --target=powerpc-unknown-netbsd --prefix=/usr/local/psim --disable-shared --enable-languages="c" --disable-threads --disable-intl

Now make the compiler as follows. Note that I’m only interested in the C compiler. I haven’t even looked at C++/ObjectiveC…

You will need to add /usr/local/psim/bin into your path, as Gcc 3.3 will expext to be able to call powerpc-unknown-netbsd-ld/ar/ranlib etc while building itself.

export PATH=$PATH:/usr/local/psim/bin

Next I would comment out the following line from gcc/builtins.c

builtins.c:2864:// error (“__builtin_saveregs not supported by this target”);

Now we can build the compiler

make CFLAGS=’-O0 –pipe’

Now before we get all giddy, lets test this thing out!

cd into the gcc directory, and lets make a simple c program… hello world is a good starting place.

use xgcc to compile it, and this will test your c compiler.

#include <stdio.h>
void main(void)
{
printf("hello from PowerPC\n");
}

bash-2.05a$ xgcc hello.c -o hello

hello.c: In function main':hello.c:2: warning: return type ofmain’ is not `int’

bash-2.05a$ file hello

hello: ELF 32-bit MSB executable Version 1

bash-2.05a$ ./hello

bash: ./hello: cannot execute binary file

Ok the executable that we have just created is NOT for our native platform, but for the PowerPC.. So lets kick in the emulator! If you didn’t patch your emul_netbsd.c you’ll get this:


% /usr/local/psim/bin/powerpc-unknown-eabi-psim hello

do_call() os_emul call 279 out-of-range

 

However if you did, this is what you’ll get!
% /usr/local/psim/bin/powerpc-unknown-eabi-psim hello
hello from PowerPC

On my computer the installation of gcc gets retarded so I manually copy the files to the right places.


cp xgcc to /usr/local/psim/bin/powerpc-unknown-netbsd-gcc

mkdir -p /usr/local/psim/lib/gcc-lib/powerpc-unknown-netbsd/3.3/

cp cc1 /usr/local/psim/lib/gcc-lib/powerpc-unknown-netbsd/3.3/

cp crtsaveres.o /usr/local/psim/lib/gcc-lib/powerpc-unknown-netbsd/3.3/

Building cross compilers is always involved, but hopefully this will help someone.