Sunday, February 18, 2007

Dynamic Code Generation and Image Files

An image based programming language like Factor stores executable code in an image file. When Factor starts up it loads the image and starts executing the code stored in it.

I wanted to explore some ideas with images and dynamic code generation so wrote a simple example on how to generate assembly, store it in an image and later load and run it. The same principle is used to generate machine code at runtime and execute it.

As a start I wanted to generate the equivalent of a simple function in the x86 architecture that returns an integer value. The equivalent of:
int func(void) { return 42; }
To see the assembly code this generates I used gcc to compile it and saved the temporary files:
gcc -c -save-temps test.c
The relevant part of the output was:
_func:
pushl %ebp
movl %esp, %ebp
movl $42, %eax
popl %ebp
ret
Using objdump I looked at the generated machine code with:
objdump -D test.o
Giving:
00000000 <_func>:
0: 55 push %ebp
1: 89 e5 mov %esp,%ebp
3: b8 2a 00 00 00 mov $0x2a,%eax
8: 5d pop %ebp
9: c3 ret
For the first simple test I just wrote some code that output the relevant bytes into a file called 'image.x86'. Now I needed a program to load and execute the code.

Allocating a memory area with 'malloc', loading the image into it, and then casting the memory pointer to a function pointer and calling it seems the obvious step but it won't work.

Modern CPUs distinguish between code and data. Code cannot be executed from within a memory area which is not marked as executable. We need to allocate a memory area specifically marked as being executable. The way to do this is different between operating systems. For this example I'm running on Windows and VirtualAlloc is the needed call:
void* allocate_code_buffer(int size) {
return VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
}

void free_code_buffer(void* addr) {
VirtualFree(addr, 0, MEM_RELEASE);
}

void flush_icache() {
FlushInstructionCache(GetCurrentProcess(), 0, 0);
}
Also needed is VirtualFree to free the memory area when we no longer need it. Modern CPUs also cache some memory areas. If the memory area where the generated code is stored is cached then our new code in that area won't be seen by the CPU unless we flush the cache. That's what 'FlushInstructionCache' does. This isn't actually needed on x86 machines but on ARM it is. Windows on x86 provides the function anyway and it's good practice to call it so the code is portable.

The following pseudo-ish code loads the image, and calls it:
void* load_image(FILE* file) {
void* image = 0;
image = allocate_code_buffer(1024);
fread(image, 1024, 1, file);
flush_icache();
return image;
}

typedef int (*entry_func)(void);

void run_image(void* image) {
entry_func func = (entry_func)image;

printf("Result is: %d\n", func());
}

FILE* file = fopen("image.x86", "rb");
void* image = load_image(file);
fclose(file);
run_image(image);
free_image(image);
Once the small C loader is written it can be used with any generated image files.

Real code is a bit more complicated than that simple function. It has branches and jumps. To handle this I made the image file format more structured. At the beginning is the size of the generated machine code, the machine code data itself and then some relocation records.

The runtime loaded in C loads the image data first, then walks through the relocation records patching up any references in the code to the address where the image was loaded. This needs to be done if there are any absolute jumps or references in the image to other parts of the image as the image could be loaded at a different address from where it was first generated.

The relocation records exist as a number of 'labels'. Each label contains the offset in the image file for that label, and a number of addresses that reference the label. Those references are updated to be the actual address of the label. Something like this:
void relocate_image(FILE* file, void* image) {
unsigned long num_labels = 0;
int i = 0;

fread(&num_labels, sizeof(num_labels), 1, file);
for(i=0;i<num_labels;++i) {
unsigned long offset = 0;
unsigned long num_references = 0;
int j = 0;

fread(&offset, sizeof(offset), 1, file);
fread(&num_references, sizeof(num_references), 1, file);
for(j=0;j<num_references;++j) {
unsigned long ref = 0;
unsigned char* bimage = (unsigned char*)image;
fread(&ref, sizeof(ref), 1, file);
*(bimage+ref)=bimage+offset;
}
}
}
I didn't fully implement jumps in this simple example but to prove the concept I do relocations for 'near relative' jumps. These could actually be computed before writing the image but I did it as part of the image relocation as I'd need to add that for absolute jumps later anyway.

I wrote some Javascript code to generate the machine code. It's not a full X86 assembler in Javascript, but just enough to generate the 3-4 instructions I use as a proof of concept. The Javascript to generate the machine code looks like this:
  var image = new Image(LITTLEENDIAN);
var assembler = new X86Assembler(image);
assembler.move(42, EAX)
.move(5, EBX)
.jmpNear("end")
.adc(EBX,EAX)
.label("end")
.ret();
image.save("image.x86");
This snippet generates code to load EAX with 42, EBX with 5, and jumps to the label 'end' which results in returning from the function. If you remove the jump, or comment it out, it adds the two numbers together before returning. The resulting image file can be run with the C loaded and prints out the integer value returned by this snippet (which is the result stored in the EAX register).

This assembler is very simple. It basically stores the generated bytes for each instruction in an array in the Image object. When saved the Image object writes the generated bytes and the relocation data if there is any.

The javascript code is in image.js, x86assembler.js, armassembler.js and generate.js. It can be run with the Rhino Javascript interpreter. The full distribution is in image1.tar.gz and includes the Rhino Javascript interpreter JAR file. A darcs repository with the code if you want to play with it and send patches is at:
darcs get http://www.bluishcoder.co.nz/repos/image1
A simple test run is:
java -jar js.jar generate.js
gcc -o run_image run.c
run_image image.x86
I also did an ARM version which can be tested on a Windows CE machine. I tested it on the Microsoft Windows Mobile 5 Emulator with run.c compiled with 'cegcc'. In that case I ran the test.arm image which is simple code generated with:
  var image = new Image(LITTLEENDIAN);

var assembler = new ARMAssembler(image);
assembler.moveRsRd(arm.SP, arm.IP)
.stmfd(arm.SP, [1,1,0,1,1,0,0,0,0,0,0,0,0,0,0,0])
.sub(arm.IP, arm.FP, 4)
.moveImmediate(42, arm.R3)
.moveRsRd(arm.R3, arm.R0)
.ldmfd(arm.SP, [1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0]);
image.save("image.arm");
This code returns '42' in the R0 register. It's exactly the code generated with the test function described before on x86, but for ARM, and I worked it out using the same compile/objdump method but using cegcc for the compiler.

It's an interesting exercise to generate this sort of thing from scratch to get an idea of how systems like Factor do it. An interesting approach might be to use Factor to generate small images for use on memory constrained devices with a tiny C runtime loader.

Although I haven't tried it this might work on Symbian devices as well. Symbian devices are ARM based but their applications are really DLLs that are loaded by the main phone application. By writing a DLL C loader that reads an executes the image file, or different images for each exposed virtual function from the DLL, you could bootstrap a simple Symbian program.

The code I wrote here is very much 'hack away until it worked' code. The assemblers in particular are ugly but it should be just enough to give you an idea of how it works if you want to go off and do something similar.

Categories: , ,

Saturday, February 17, 2007

Another Offline Web Application Example

Mark Finkle has put together a simple demonstration application that uses the offline APIs in Firefox, including source.

In other offline application news, John Resig has written about how the offline/online notifications work.

Categories:

Labels:

Friday, February 16, 2007

Factor on Windows Mobile 5

Slava has been working on porting Factor to the ARM CPU for running on a gumstix.

Windows Mobile 5 devices also use a chipset that uses the ARM architecture. Doug Coleman, another Factor contributor, has a Windows Mobile 5 device and was keen to get Factor running on it.

Between us we'd been trying out the various options to compile code on the device. The cegcc project has a gcc port that runs on Linux and Windows (using cygwin) and cross compiles to Windows CE, which Windows Mobile 5 is a version of.

They have two versions of the compiler. One is like 'mingw' in that it has very few special libraries and is expected to use the Windows CE API. The other 'cegcc' is comparable to cygwin in that it has libraries that implement many common Unix functions to make porting software easier.

I was able to get Factor to compile using the 'cegcc' compiler and I've committed the changes to my repository. This is very much a work in progress and does not have everything working. For example, stack guards aren't implemented so if you cause a stack underflow the program segfaults. Apart from this it can bootstrap an image in 'no-compile' mode and run basic factor words in the interpreter.

To build Factor using the patches in my repository you'll need 'cegcc'. I built cegcc from their SVN repository using cygwin but the downloads they make available should work too.

I created a 'windows-arm' build option in Factor. In Linux or Cygwin, with '/opt/cegcc/bin' on the path, use:
make windows-arm CC=arm-wince-cegcc-gcc
This will build the binary for the mobile device. You'll also need some DLL's to exist on the device. I've included these in the .zip file mentioned below.

On the device you'll need a console program. I used the console programs used for the old 'pocket-gcc' project. They can be obtained from various places. I got mine from mamaich's site in file pocketcon.rar. Install both CAB files on the device. As these are for an older WinCE version you also need to make a registry change. Change HKEY_LOCAL_MACHINE\Drivers\Console\OutputTo to be '0' (ie. the number zero). Running CMD will now give you a console.

Copy the entire Factor directory to the mobile device. Due to memory constraints it's best to have it on a storage card. Make sure the Factor directory has the 'f.exe' file that you built. Now you need a boot image. The 'arm' image can be generated from any Factor instance on any architecture. I generated it on a Windows machine with:
USE: image "arm" make-image
This generates boot.image.arm. Or you can download the one in the factor_wm5.zip file I've provided. That file also contains a pre-built 'f.exe' and the DLL's needed to run it.

With the contents of factor_wm5.zip in the Factor directory (which has 'core', 'libs', etc as subdirectories) (or your own generated boot and executable files) run a CMD console and change to the Factor directory. Run the following command:
f -i=boot.image.arm -no-native-io -no-compile -young=2 -aging=4 -codeheap=4
This will proceed to bootstrap an interpreter only Factor image.

The emulator has a limited amount of memory (and so too does the device I suspect) so to get things running I force very low amounts of memory using 'young', 'aging' and 'codeheap' options. You might need to play with these (the values are Megabytes) if you run out of memory.

Factor on Emulator
The bootstrap may take a while. It takes about 10 minutes on my laptop using the emulator. This will give you a factor.image. You can run it with:
f -young=2 -aging=4 -codeheap=4
You'll now be at a Factor prompt and can enter any Factor expression.

This is Factor running in 'interpreted' mode. Nothing is compiled. As a result it's quite slow and you can't call any FFI routines. When Slava finishes his ARM port then it'll become more useful. A screenshot of the emulator running Factor is here.

I don't actually have a Windows Mobile device so I've tested all this under Microsoft's emulator. The emulator runs under Windows and emulates the ARM CPU instructions so hopefully it's fairly accurate. Donations towards a device gratefully accepted :-)

For the emulator you'll need to get and install these files:
The emulator can map a directory on the hard drive of the host machine to act as the storage card. This is available in the options and is how I made the Factor directory available to it.

My repository with the patches to Factor is available with darcs:
darcs get http://www.bluishcoder.co.nz/repos/factor


Categories: ,

Wednesday, February 14, 2007

More on Firefox Offline Web App Support

Robert O'Callahan posts with more details on the offline support in Firefox. In a later post I'll go into more technical detail on how I used the features to add the offline support to Zimbra, along with the issues I faced. At the moment I'm working on adding the ability to edit drafts and have it updated on the server when you go back online.

Categories: ,

Labels:

Offline Zimbra with Firefox

In my new job at Mozilla I've been working on adding offline support to Zimbra as a proof of concept of the new Firefox offline capabilities.

Zimbra is heavily ajax based and gives a good idea of how difficult or easy it is to convert an existing application to use the offline support. For this first cut I made Zimbra work when the browser is in offline mode and provide the ability to browse the email folders, and view messages while offline that are held in the Inbox and Drafts folders.

The Firefox features used to enable offline operation were:
  • DOM Storage for storing emails and folder information. DOM Storage is an implementation of a WHATWG specification.
  • Offline Cache. A patch is available for Firefox that adds an offline cache specifically for web applications to store data (like images, pages, etc) that must be available while offline. Items are loaded in the cache using a rel="offline-resource" element on a <link> element.
  • JAR file Protocol. Firefox accepts JAR protocol URLs. These reference individual items in a JAR file and allow convenient bundling and caching of resources. For example, to reference the file /core/AjxCore.js in the ajax.jar file, the URL would be: jar:/zimbra/js/ajax.jar!/core/AjxCore.js
  • Offline Events. The browser has "offline" and "online" events that are triggered when the user chooses to go offline via the menu, or when network connectivity is lost. I modified Zimbra to listen for these events and display a status indicator showing whether it is in offline or online mode.
A screencast shows me logging into Zimbra, viewing some emails, going offline, the offline/online indicator and the availability of the emails while offline. It's available here: http://www.bluishcoder.co.nz/offlinezimbra.

It's the first screencast I've out together so hopefully it comes out ok. I used the excellent 'wink' tool.

Offline Zimbra
Categories: ,

Labels:

Tuesday, February 13, 2007

Factor to Javascript Compiler Makeover

I've made some changes to the way the Factor to Javascript compiler REPL works.

I used 'termlib' to make a terminal style interface for the REPL. Instead of entering Factor code, hitting submit, and waiting for the result, you can type in a listener style REPL, hit enter and get the result back. It works much better. History is available using the up and down arrow keys.

It does have a few rough edges. There's no copy and paste. And no multiline input. I'll fix these over time. Termlib is a nice library to use but be aware of the license restrictions if you want to use it:
This JavaScript-library is free for private and academic use. Please include a readable copyright statement and a backlink to http://www.masswerk.at in the web page. The library should always be accompanied by the "readme.txt" and the sample HTML-documents.

The term "private use" includes any personal or non-commercial use, which is not related to commercial activites, but excludes intranet, extranet and/or public net applications that are related to any kind of commercial or profit oriented activity.

For commercial use see http://www.masswerk.at for contact information.

Eventually I want to write the entire terminal code in Factor and compile it to Javascript but that's probably some time in the future.

I made a few other relatively minor changes. USE:, USING:. and IN: are supported. I also added 'print', 'write', '.' and '.s'. I will be adding more words and putting them in their correct vocabularies over time. I also have plans for better generated code and integrating with my comet library which hopefully won't be too far away.

Categories: ,

Sunday, February 11, 2007

Factor Compiler Transforms and Shuffle Words

Factor has a couple of different ways of automatically generating code. One of these is 'parsing words'. These are words that get run at parse time and can generate code that then gets compiled. I used this approach in the 8080 emulator to parse a domain specific language into Factor code:
INSTRUCTION: LD   SP,HL   ; opcode F9 cycles 06

Another approach is compiler transforms. These are similar to Common Lisp's define-compiler-macro construct.

They apply at compile time, producing code that gets run if the word is compiled. If the word is interpreted (ie. cannot be compiled) then the transformed code is not run.

Concatenative languages have combinators that can be used to run quotations in different ways on the stack. Words that have stack effects that vary depending on the words inputs are considered bad style and in Factor cannot be compiled. Instead they get run by the interpreter which leads to slower code. This leads to combinator words named like 'each-with', 'each-with2', 'each-with3', etc. Where the word performs the same basic action (iterate over a sequence calling a quotation on each item in it) but with a slight variation (the quotation also has access to 'n' number of items below the stack).

Most Factor combinators are implemented for up to 3 stack arguments since it's considered good style to not deal with more than 3. Sometimes though you need an 'each-with4' or 'map-with3' and they aren't available in the standard library. They can be difficult to implement correctly too.

Ideally I'd like a 'map-with' that takes the number on the stack. So these would be equivalent:
2 3 { 1 2 3 } [ * * ] map-with2
2 3 { 1 2 3 } [ * * ] 2 map-withn
Compiler transforms allows us to write code like this that transforms at compile time to code that can be compiled. By writing combinators in this form it allows efficient implementation of the common cases but allows falling back to the times when you need access to more stack items without having to write your own combinator.

For the example here I'm implementing 'dip'. This is a word from the Joy language that removes the topmost item on the stack, calls a quotation, then restores that item:
1 2 [ 5 + ] dip => 6 2
1 2 3 [ drop ] dip => 1 3
Joy has 'dip', 'dipd' and 'dipdd' where the latter two remove 2 and 3 items from the stack respectively, call the quotation and restore them.

Instead of writing separate implementations for these words I wrote one 'ndip' word which takes the number on the stack and does any number of 'dip' variants. So 'dip' is '1 ndip', dipd is '2 ndip' and dipdd is '3 ndip'. '4 ndip' and up is also catered for.

A simple implementation of 'ndip' won't compile as it has a variable stack effect depending on the inputs. To make a version that can compile I use compiler transforms. The first step is to write a word that generates the quotation that when called will do what 'ndip' should:
: [ndip] ( n -- quot )
[ dup [ [ swap >r ] % ] times \ call , [ \ r> , ] times ] [ ] make ;
Some examples of calling this word and the results are:
1 [ndip] => [ swap >r call r> ]
2 [ndip] => [ swap >r swap >r call r> r> ]
'ndip' itself can be implemented using this as:
: ndip ( quot n -- ) [ndip] call ; inline
This will work but is inefficient as it generates a quotation on each call and cannot be compiled:
: foo ( a b -- b ) [ drop ] 1 ndip ;
1 2 foo => 2
\ foo try-compile
\ foo compiled? => f
Compiler transforms are used to make 'ndip' compile. This is the transform for 'ndip':
\ ndip 1 [ [ndip] ] define-transform
This causes the quotation produced by '[ndip]' to be generated at compile time and used for the call to 'ndip'. If for some reason it can't be compiled (due to the quotation being passed to 'ndip' using constructs like i/o or continuations) then it falls back to the interpreted 'ndip' definition. Now the code works compiled:
: foo ( a b -- b ) [ drop ] 1 ndip ;
1 2 foo => 2
\ foo try-compile
\ foo compiled? => t
For it to compile the number passed to 'ndip' must be a literal. If it is not, then the interpreted definition of 'ndip' is again used. This means 'ndip' works in all cases and compiles when it can. Now 'dip, 'dipd', etc can be defined in terms of 'ndip':
: dip 1 ndip ; inline
: dipd 2 ndip ; inline
: dipdd 3 ndip ; inline
Should the user ever need a dipddddddd then they can just do an '8 ndip' as needed - no need to write a special case combinator.

One advantage of compiler transforms over parsing words is that a 'see' on the the 'dip' word shows the 'ndip' call. If we generated the code using a parsing word then 'see' would see the result of the parsing words generated code.

Ideally I'd like to write 'each-with', 'map-with', etc in terms of comnbinators like this to make the one off cases of needing 'map-with6' or 'keep4' easy to deal with. They don't often come up but when they do it's hard to work around. They most commonly occur when dealing with non Factor code like Win32 api calls.

Many of these API calls have large numbers of input and output parameters which can be hard to deal with. Sometimes you can work around it with good word design but it makes sense to me to have the Factor compiler do the work of generating all the possible cases when I need them rather than me handing coding them.

I've put 'ndip' in 'libs/shuffle' and will add any others there.

Categories:

Thursday, February 08, 2007

Concurrency via Generators in Javascript 1.7

Neil Mix, the author of Narrative Javascript, has a post about implementing concurrency in Javascript 1.7 using the new generators feature of the language.

His example is here and the threading code behind it is just 4K. The example requires Firefox 2.0 for the new Javascript 1.7 features.

Categories:

Monday, February 05, 2007

Firefox 3 talk at Kiwi Foo Camp

Rod Drury writes about Rob O'Callahan's talk at 'Kiwi Foo Camp' about Firefox 3.

A session with huuuuge implications first up today from Robert O’Callahan from Mozilla. He’s based in NZ but drives the rendering engine of Mozilla/FireFox. (Aside1: I think that it is completely cool that such a web significant thing is being built from a guys sun room in New Zealand - rocking!)


Categories:

Sunday, February 04, 2007

Emulating other Intel 8080 Based Arcade Games

I've done some refactoring of the Intel 8080 emulator I wrote in Factor and split the games out into separate libraries. ROM's can now be stored anywhere with the path to the root of the ROM directory set in the 'rom-root' variable.

Many of the 8080 based arcade games use similar hardware to Space Invaders. If they use a similar control mechanism and you don't mind non-perfect emulation (colours and sounds will be as per Space Invaders) it's easy to create an emulator if you have the ROM files.

The main thing you need to know is where the ROM files need to be loaded in the emulated RAM. For example, you can get a list of 8080 based games here. For this example I chose 'Balloon Bomber'.

You can find out where the ROM's need to be loaded by looking in MAME's drivers/8080bw.c file. Look for 'ROM_START( ballbomb )':
ROM_START( ballbomb )
/* 64k for code */
ROM_REGION( 0x10000, REGION_CPU1, 0 )
ROM_LOAD( "tn01", 0x0000, 0x0800, ... )
ROM_LOAD( "tn02", 0x0800, 0x0800, ... )
ROM_LOAD( "tn03", 0x1000, 0x0800, ... )
ROM_LOAD( "tn04", 0x1800, 0x0800, ... )
ROM_LOAD( "tn05-1", 0x4000, 0x0800, ... )

/* color maps player 1/player 2 */
ROM_REGION( 0x0800, REGION_PROMS, 0 )
ROM_LOAD( "tn06", 0x0000, 0x0400, ... )
ROM_LOAD( "tn07", 0x0400, 0x0400, ... )
ROM_END
For this quick example we're interested in the CPU region, It lists the files and their starting memory locations and lengths.

In Factor this game can be emulated by calling the (run) word from Space Invaders. It takes the title of the window, a sequence describing the ROM files and a CPU object as parameters on the stack.

For the CPU object we just use the <space-invaders> CPU since the hardware is pretty close to the Space Invaders machine. The sequence contains 2 element arrays, each containing the ROM file name and the location to load it. So to run Balloon Bomber, this is all that's needed:
"apps/space-invaders" require
USE: space-invaders
"Balloon Bomber" <space-invaders> {
{ HEX: 0000 "ballbomb/tn01" }
{ HEX: 0800 "ballbomb/tn02" }
{ HEX: 1000 "ballbomb/tn03" }
{ HEX: 1800 "ballbomb/tn04" }
{ HEX: 4000 "ballbomb/tn05-1" }
} (run)
You'll need the ROM files in the 'ballbomb' subdirectory off the 'rom-root'.

I've added 'Balloon Bomber' to my repository as an example in 'apps/balloon-bomber'.

For some games you need to adjust the controls and graphics displays, etc. I'll do a later post on how to do this but it basically involves specialising various <space-invader> generic words.

Categories:

New Job

A couple of weeks ago I wrote about moving to Auckland. Things have settled down a bit and the Econ Lodge is turning out to be a reasonably comfortable stay.

The reason for moving here is to take up a new job. I'm now a contractor working for the Mozilla Corporation. So far it has been really interesting working on Firefox and I'm quite excited about what's coming up. Most of my prior web based work has been as a web application developer. Working on the other side, the web browser, gives me a whole new perspective on things.

Previously I worked for Core Technology in the R&D area developing a web application building system called Aviarc.

Aviarc was a very interesting system to work on and I helped build the core engine. I wrote it as a continuation based web server written in Scheme, but hosted in a J2EE container. This was made easy by using a Java based Scheme called SISC.

The original idea of Aviarc was to make it easy for non-experienced programmers to develop web applications quickly and easily. It has drag and drop screen builders, customizable widgets, plug-in security methods, a workflow language, and is very scriptable both on the client side and server side. All the GUI builder tools were developed using Javascript, HTML and 'Ajax' and are themselves Aviarc applications. It's now in production use in a number of companies in Australia and New Zealand.

I'd been working on it for about 3-4 years and decided near the end of last year I needed a break. I left Core and spent some time being unemployed for a bit.

While I was deciding what to do I was contacted by Robert O'Callahan to see if I was interested in contracting to the Mozilla Corporation. It sounded like interesting work so I've moved to Auckland to work as a contractor to Mozilla with Robert and hopefully some other developers soon.

So new year, new place to live and new job. We'll see what the rest of the year holds in store.

Categories:

Saturday, February 03, 2007

Lunar Rescue Emulator

The Space Invaders emulator I wrote is actually a generic 8080 emulator. Quite a few arcade games used similar hardware to the old Space Invaders machines.

One of those is Lunar Rescue. I added a Lunar Rescue emulator by using the Space Invaders routines but with the Lunar Rescue ROM code loaded. This works fine. The sounds are probably slightly different and the colours are not right but the game plays fine. I'll work on these issues to get it as correct as possible.

To implement the Lunar Rescue game I create a TUPLE specific for the game and delegated all functionality to the Space Invaders TUPLE. To implement the correct colours and sounds I'll add methods specific to the Lunar Rescue TUPLE. Factor does OO easily.

I did some refactoring of Space Invaders and now running the 'apps/space-invaders' module brings up a window with buttons for the supported games. Clicking a button runs Space Invaders or Lunar Rescue.

The ROM files have moved too. They now live in subdirectories off 'apps/space-invaders/resources'. You'll need to create 'invaders' and 'lrescue' subdirectories, each containing the require ROM files. These are specifically:
  • invaders/invaders.e
  • invaders/invaders.f
  • invaders/invaders.g
  • invaders/invaders.h
  • lrescue/lrescue.1
  • lrescue/lrescue.2
  • lrescue/lrescue.3
  • lrescue/lrescue.4
  • lrescue/lrescue.5
  • lrescue/lrescue.6
You'll notice I've gone towards using the separate ROM files for Space Invaders rather than the complete 'invaders.rom'. This is to make it easier so you don't have to manually concatenate the files.

Categories:

Space Invaders gets Sound

Following up on my previous post, I've added sound to my Space Invaders Emulator written in Factor.

I used the .wav files obtained from the Space Invaders Didactic Emulator and also used the hardware information from that site to work out how the Space Invaders sound system worked.

If you have OpenAL and ALUT installed you should be able to run it with:
"apps/space-invaders" run-module
You'll need the Space Invaders ROM file, which you'll have to obtain, and place it in the 'apps/space-invaders/resources' directory.

So far it has only been tested on Windows but the sound support does work on Linux so it should be fine there. There is an issue with Mac OS X due to it having an older version of OpenAL. That issue is being investigated.

Categories:

OpenAL library wrapper for Factor

I've written a wrapper for the OpenAL sound library for Factor.

It's a thin alien wrapper around the C interface and was pretty easy to write given Factor's great C FFI support (called 'alien'). It has been tested under Windows and Linux and should be easy to get going for the Mac.

You'll need to install OpenAL and ALUT. Binaries for these are available from the OpenAL download page. With Ubuntu Linux you can install these libraries with:
apt-get install libopenal-dev libalut-dev
Note that you need the 'dev' versions for Factor to find the shared libraries.

Under Windows make sure you put the alut.dll file somewhere in your path. To test it from within Factor:
"libs/openal" require
USE: openal
play-hello
This should play the default 'Hello World' example. I want to use this to add sound to my Space Invaders emulator.

Categories: