Skip to content
This repository has been archived by the owner on May 29, 2018. It is now read-only.

Getting Started

dylanwinn edited this page Apr 14, 2012 · 2 revisions

Until a filesystem can be implemented, all AtlasOS programs must be assembled into the kernel. Below is a short tutorial on how to do so.

Application Structure

All applications are stored between the :apps and :apps_end labels, immediately after the :kernel_end label. Each app exists between as least two labels :appname and :appname_end. Let's take the simplest possible application as an example:

:helloworld
	SET A, helloworld_string
	JSR text_out ; text_out prints the contents of the A register. More on APIs later.
	JSR proc_kill_me ; allow the kernel to terminate the process.
:helloworld_string dat "Hello World!", 0xA0, 0 ; all data is stored in labels. 0xA0 is a carriage return.
:helloworld_end

Now, add a new label at the bottom of the list between :application_table and :application_table_end like so:

:app6 dat "helloworld", 0, helloworld, helloworld_end

Note that the first parameter, "name_of_app" can be completely arbitrary. Assemble the kernel, run it, and type "load helloworld" to see the result:

$> load helloworld
Hello World!
$> 

Multitasking

Due to the lack of interrupts or an MMU on the DCPU, multitasking on AtlasOS is entirely cooperative. The example above actually doesn't cooperate, and the kernel can do nothing about it. A cooperative app yields to other processes by calling a special subroutine within the kernel. If our app is going to run for longer, chances are it will be built in a big loop, so it follows that we would yield at the end of each iteration:

:helloworld
	SET I, hello_loop_end
	SUB I, hello_loop ; define memory boundries of the loop to follow.
	SET J, 4 ; defines the number of iterations for the loop to follow.
:helloworld_loop ; here we have added a loop.
	SET A, helloworld_string
	JSR text_out
        SUB J, 1 ; subtract 1 from the counter after each iteration.
	IFE J, 0
		JSR proc_kill_me ; when the counter hits zero, kill the process.
	JSR proc_suspend ; otherwise, yield to the kernel.
	SUB PC, I ; the kernel will call us back here, so we jump back to the top of the loop.
:helloworld_loop_end
:helloworld_string dat "Hello World!", 0xA0, 0
:helloworld_end  

Assemble, run, and load as before to see the result:

$> load helloworld
Hello World!
Hello World!
$> Hello World!
Hello World!

Uh-oh, that wasn't quite the result we were hoping for, was it? The loop printed "Hello World!" four times like we expected, but something else seems to have gone wrong. It's actually quite simple: the shell thought our app was done running, and started printing to the screen before we were done! The biggest pitfall of multitasking is having to deal with other apps consuming resources and doing unpredictable things. Not to worry, though, there is a simple way to work around the shell. If we kill the shell, the kernel will wait until our app has finished executing to revive it:

:helloworld
        SET A,2 ; the shell should always be number 2 on the process list, after the kernel.
        JSR proc_kill ; proc_kill kills the process in the A register. More on APIs later.
	SET I, hello_loop_end
	SUB I, hello_loop
	SET J, 4
:helloworld_loop
	SET A, helloworld_string
	JSR text_out
        SUB J, 1
	IFE J, 0
		JSR proc_kill_me
	JSR proc_suspend
	SUB PC, I
:helloworld_loop_end
:helloworld_string dat "Hello World!", 0xA0, 0
:helloworld_end

Assemble, run, and load as before to see the result:

$> load helloworld
Hello World!
Hello World!
Hello World!
Hello World!
Atlas-Shell v0.3.2
$>

As you can see, the shell has started fresh complete with the version splash, and it did so seamlessly. It is also possible to restart the shell without the version splash, to clear the command history from the screen, and much more. More on that later, in the next section on:

API

// TODO

Clone this wiki locally