LESSON 2: BUILDING OUR FIRST EXAMPLE PROJECTTABLE OF CONTENTS-WHAT DOES IT MEAN TO COMPILE A DREAMCAST PROJECT? WHAT DOES IT MEAN TO BUILD A DREAMCAST PROJECT?
-STEP 1: CREATING DIRECTORIES AND FILES FOR THE PROJECT
-EXPLAINING THE KOS FILESYSTEM
-STEP 2: CONFIGURING OUR MAKEFILE
-STEP 3: BUILDING THE PROJECT
-STEP 4: RUNNING OUR PROGRAM
WHAT DOES IT MEAN TO COMPILE A DREAMCAST PROJECT? WHAT DOES IT MEAN TO BUILD A DREAMCAST PROJECT?So, now that our toolchain is all set up, let's try building a project and running it, both in an emulator and on a real Dreamcast. Before we begin, let's first talk about what compiling actually is. Colloquially, compiling has become a catch all term for "Turn source code into executables." More specifically, the compiler we are using, gcc, does two things - first it
converts files into object code (called
objects, denoted as *.o files), and then it
links objects together into a single binary that is executable. Since Windows is the dominant operating system, most people assume an executable is an .exe file, but a more common executable format outside of windows is
.elf (
Executable and
Linkable
Format).
When we compile our Dreamcast projects, we will output an elf file that is capable of being executed by the Dreamcast. There are multiple ways to deploy an elf file on a Dreamcast - for example, there are windows-like shells you can run on the Dreamcast, like Dreamshell, that will let you mount an SD card and execute elf files by clicking and opening them, and emulators like NullDC are capable of loading an elf file like a rom. But, ultimately, we are interested in running our program on a real, stock Dreamcast, which means we will have to burn our program into a bootable CD-ROM. To understand how we build a bootable CD-ROM, we must first understand what a CD-ROM is. From the perspective of our computers, a CD-ROM is a continuous stream of binary - 1's and 0's, which are further arranged into sectors, which are further arranged into tracks (owing to the format's roots in audio). There is no inherent file system when talking about data stored at this level (yes yes, ignore sector segmenting for a moment); rather data is stored sequentially, meaning if I had 3 files each 1 byte big, they would be stored as 24 bits back to back with no discernible distinction between the files. File systems, interfacing, and data formats make sense of this data at a higher level, but on the disk the best we can do is tell which specific bits we are reading in a stream of them. We identify what area we are currently examining via a seek offset. The Dreamcast boot sequence is tuned to look for two files at two specific regions of the CD in order to boot -
IP.bin and
1st_read.bin.
IP.bin is the bootstrap loaded from a reserved sector area on the last track of a CD, and contains a checksum (which, funnily enough, is not checked), a Sega license screen graphic (which is required to boot - an old trick console makers used to do for legal reasons to allow them to classify non-licensed software as trademark violations), an area that defines the region of the disk - Japan, US, or Euro. More importantly, IP.bin also contains meta information defining 1st_read.bin. IP.bin's bootstrap will execute code to display the Sega License Screen graphic (and check that it's not modified), then move to a second bootstrap that sets up some hardware registers. Many homebrew applications will use this second bootstrap to load a second graphic under the Sega License Screen graphic explaining that the licensing terms from the Sega graphic should be ignored, like so:
After which, the bootstrap transfers control over to 1st_read.bin. 1st_read.bin is actually our ELF, stripped of all the headers it gains when compiling, and converted into binary. It is placed at offset 0x8C010000 which IP.bin branches to in execution. The Dreamcast reacts differently from here on out depending on whether it is reading a GD-ROM or a CD-ROM. If the disc is a GD-Rom, the Dreamcast will read 1st_read.bin linearly into memory, as would be expected. To prevent people from running programs from CD-ROMs (as one of their anti-piracy measures), if one is detected the Dreamcast will instead read 1st_read.bin using a pseudo-random scattered pattern generated from a specific arbitrary seed, scrambling the binary out of order and destroying it in the process. We can defeat this process by reverse-scrambling our elf when converting it to 1st_read.bin by using the opposite of this pseudo-random scatter. This way, the scatter cancels out and our ELF is preserved when it enters memory for execution.
Many assume the Dreamcast had poor anti-piracy measures, but the reality is that the Dreamcast was broken wide open early on by a pretty heinous and serious breech of security. The only reason Dreamcast piracy and homebrew were ever possible is because a Katana SDK - the official Sega SDK for the Dreamcast, was stolen by the warezgroup Utopia sometime around late 1999. The Katana SDK contained a scrambling program that would automatically reverse scramble your binary for you, intended to let developers burn non-game related tools on CD-ROM instead of GD-ROM. Access to the Katana SDK did not mean piracy groups could freely author software, as it still took a few years of research to reverse engineer the pseudo-random scatter algorithm (which they did by examining pre-scattered code against post-scattered code), but rather it allowed them to create one single program which could load other programs, which they dubbed the utopia boot CD. Had that Katana SDK never been stolen, the entire Dreamcast piracy and homebrew scenes would likely never have materialized.
Anyways, because these files (IP.bin and 1st_read.bin) need to be in precise locations on the CD, we cannot simply burn our elf like a PC data disk and expect the program to execute. Rather, we need to pack both files into a binary CD image, so we can place them at precise offsets, and then burn that image. Luckily, KOS provides utilities to do that manually (mkisofs), and there are also easier gui utilities to do that automatically (bootdreams). Additionally, both of those utilities will also let us add other external files to our CD-ROM image beyond our executable binary into the other unused sectors of the CD-ROM, like music, graphics, data, and so forth. From there, we can finally burn our disc and boot our program on a real Dreamcast.
to sum up, the entire process looks like this:
All that looks gnarly, but in practice, it comes down to just a few commands after setting up our Makefile. It's not a painful process once you do it a few times, and shouldn't be a problem to build in rapid succession multiple times during development. Additionally, we can use emulators at times to cut out the steps involving actually burning the CD. For the sake of clarity, going forward, use of the term
"Compile" will refer to the process of creating the ELF, while use of the term
"Build" will refer to the entire process of creating the elf and converting it to a CD-ROM image along with external files. I.e.
"Compile the project" = "create an elf file"; "build the project" = "create a booting CD that includes our program and external files."STEP 1: CREATING DIRECTORIES AND FILES FOR THE PROJECTWith all that said, let's first do some house keeping to keep our directory lists nice and organized. I prefer to keep all my active projects in a folder located within the KOS folder in our tool chain. To do this, in cygwin, navigate to:
The tilde '~' represents a path to our home directory in cygwin. Now that we are in the KOS folder, make a folder called 'Projects':
To make sure our tool chain ws set up correctly and KOS is installed, we will try compiling the example project called "png." I prefer to leave the projects untouched in their original folder and copy them into my projects folder so I can have an original copy if I need to revert. The example project we want is located at ~/dc/kos/examples/Dreamcast/png. First, make a directory in our Projects folder called png
then copy the contents of ~/dc/kos/examples/Dreamcast/png into this the folder we created:
Code: Select all
cp -r ~/dc/kos/examples/Dreamcast/png/* ~/dc/kos/Projects/png/
the "-r" flag we used in the
co
py command means we are copying all the files (indicated by *) and folders in ~/dc/kos/examples/Dreamcast/png/ recursively, which is a long way of saying we will copy folders as well as files.
Before we continue, I like to set my terminal to automatically open to the Projects folder when I open them. I also like to clear the screen of any verbose info. To do this, open your ~/bashrc file or ~/bash_profile file in the text editor, and add the following command to the bottom of the file:
Now that we have our project copied, navigate over to the png folder in our Projects folder:
If we have a look around in this directory like so:
we see we have a few files:
Code: Select all
example.c
Makefile
wfont.bin
romdisk_boot
First, we have our source code file, example.c When we program for the Dreamcast, we can use either C++, which are .cpp files, or we can use C, which are .c files. Next, we have our Makefile, which is where we do the actual compiling of our projects. Makefiles are scripts that we feed to a GNU program called Make to automate the process. Within our Makefiles we can set up compiler options and do more, such as calling external tools we may need during the compiling process. Finally, we have a binary file called wfont.bin that holds the graphics data for a font we will use to render text in this example. In a later lesson we'll dive further into data formats and reading binary.
We also see we have a folder, called romdisk_boot, and if we navigate into that folder:
and look in the directory
we see we have two files:
The first file is a 512x512 picture encoded in png format (you can open it on your PC like any other png), and a
gzip compressed file. If we open the gzip file on our PC (using a tool like winzip or winrar), we see inside that is another file called text (without any extension). If we open that file in notepad, we see it is a plain text file containing the following text:
Lincoln's Gettysburg Address, given November 19, 1863
on the battlefield near Gettysburg, Pennsylvania, USA
Four score and seven years ago, our fathers brought forth
upon this continent a new nation: conceived in liberty, and
dedicated to the proposition that all men are created equal.
Now we are engaged in a great civil war. . .testing whether
that nation, or any nation so conceived and so dedicated. . .
can long endure. We are met on a great battlefield of that war.
We have come to dedicate a portion of that field as a final resting place
for those who here gave their lives that this nation might live.
It is altogether fitting and proper that we should do this.
But, in a larger sense, we cannot dedicate. . .we cannot consecrate. . .
we cannot hallow this ground. The brave men, living and dead,
who struggled here have consecrated it, far above our poor power
to add or detract. The world will little note, nor long remember,
what we say here, but it can never forget what they did here.
It is for us the living, rather, to be dedicated here to the unfinished
work which they who fought here have thus far so nobly advanced.
It is rather for us to be here dedicated to the great task remaining
cd-rombefore us. . .that from these honored dead we take increased devotion
to that cause for which they gave the last full measure of devotion. . .
that we here highly resolve that these dead shall not have died in vain. . .
that this nation, under God, shall have a new birth of freedom. . .
and that government of the people. . .by the people. . .for the people. . .
shall not perish from this earth.
This lesson isn't going to dive into the source code for this example, as we'll eventually cover everything it does in future lessons. It's not important to understand exactly how it does everything, but for the curious, this program will use a library called zlib to decompress the text file above into plain text in memory, then load a font graphic into memory along with a png file that is loaded as a texture. It then draws the png file in the background of the program and renders our decompressed text file using our font on the screen in scrolling text - a pretty basic and classic style demo.
EXPLAINING THE KOS FILESYSTEMLet's take a minute to talk about how the Dreamcast and KOS file system works. KOS is more than just a set of tools we use when building our programs, KOS is actually a full blown operating system for the Dreamcast, like Windows or Linux. KOS can do many things, like interacting with the Dreamcast hardware, executing program threads, manage memory, etc. It even utilizes a virtual file system with mount points. Our program's working directory is the
Root of this virtual file system, "/". When we build a Dreamcast project using the KOS SDK, KOS sets up and mounts multiple directories that our programs can access. One directory maps to the VMU devices in the controllers, "/vmu/". There is also the
CD-ROM drive, which is mounted as "/cd/". Files in here are located on the CD itself and must be loaded into memory by our program to be used. For example, if we were to open a text file on the CD using something like this:
Code: Select all
FILE* f;
f = fopen("/cd/example.txt", "r");
then KOS would allocate some memory for us in the Dreamcast's 16MB main memory, and then tell the GD-ROM drive to read data off the CD into that memory so we can access it locally. This has a few downsides - first, this is slow, as it takes time for the GD-ROM to be read and moved into memory. Secondly, this has the obvious downside of needing to actually load files to use them in the first place. That might not sound like something that we need to worry about, but it can be problematic. For example, when you run a program on a real Dreamcast, we have no console to output text to. If we output text to the screen on a real Dreamcast console, that means we are rendering text itself, which means we need to have a font graphic loaded in memory. But, say our command to open the font graphic from the CD was bugged - we couldn't actually output whatever error we had in the first place. For this reason, it becomes necessary to have data that is bundled with our program itself, as part of the program binary, so that, as soon as we load the program, this data is loaded with it.
This particular example we are compiling is good because it demonstrates two different ways to do this - one that applies no only to Dreamcast development but general programming, and one that is specific to the KOS SDK. The font itself is a binary graphics file called wfont.bin. We first use a utility bundled with KOS called
bin2o to turn the binary graphics file into an object that can be linked into our executable. By linking the file as an object in our executable, we can access it in our program source with a global declaration like so:
extern, for those unfamiliar, is a reserved word indicating that the variable is defined elsewhere in the program. You usually see this in programs that share a variable across files (i.e. source1.c and source2.c both share a variable), but in this case rather than pointing to a later declared variable, we're pointing to an actual block of data in our binary. So long as our label matches the file name, our compiler will figure it out for us. This way, if we needed to use a font to output console information to the screen, it would already be available in memory as our program loads. This method of packing data into your executable isn't limited to KOS or the Dreamcast, and can be used in normal PC development, btw. The downside to this is that, should you want to unload that file to free memory, you're going to have to manually deallocate your memory. Further, you're going to have to essentially manually refernce every file you want packed into your binary in your source code. If you're packing multiple objects into your binary, this could get very long.
Luckily, KOS provides an automated way to manage data packed into your binary. We do this by creating a
romdisk directory on our development PC. When we compile our program using our Makefile, we will first use a utility bundled with KOS called
genromfs to turn our romdisk directory (in this example, ~/dc/kos/Projects/png/romdisk_boot/) into a binary image file that we can be bundled into our program executable. With a single command, KOS will automatically mount a portion of a program's executable that maps to this romdisk directory as
"/rd/". If we wanted to later free up memory, we can unmount the "/rd/" folder through KOS. The only thing we need to do is make sure KOS can point to the romdisk folder correctly, which we do in this example with the following code in our source:
Code: Select all
extern uint8 romdisk_boot[];
KOS_INIT_ROMDISK(romdisk_boot);
Just make sure the label matches the file name for our romdisk object that we generated with genromfs. You can actually use romdisks to load multiple chunks of files by creating multiple romdisk objects packed into your executable. This can make for an easy way to load in and out data in your program; i.e.
packing all of "level 1" assets into "level_one_romdisk", all of "level 2" into "level_two_romdisk", etc.We can also mount an SD Card adapter through KOS, although it's more involved and not automatic. We will cover mounting an SD Card in a later lesson. SD Cards are read through a homebrew adapter that connects to the serial port of the Dreamcast. We can launch an ELF from the SD Card as though it were launching from the GD-Rom Drive, but in doing so we lose the ability to write to the SD Card adapter. However, if we boot from a CD-ROM, we can access the SD Card in much the same way you'd access as USB drive - both with the ability to read
and write. This can be helpful for logging or swapping out assets without rebuilding your entire program.
STEP 2: CONFIGURING OUR MAKEFILEOpen the Makefile in our png folder (~/dc/kos/Projects/png/) with our text editor. You'll note that Makefiles don't have a file extension, but they are still plain text files. Makefiles will vary from project to project, but the Makefile in this example is pretty general and can be used as template going forward. Makefiles are scripts that control the way our make commands work.
The first line of the Makefile is
This is basically the default action when running make. You can actually make individual parts of the Makefile, but this opening part labeled “all” is what gets run if you run make by itself. In this case, it runs a macro called “rm-elf” then another macro called “example.elf”
Code: Select all
include $(KOS_BASE)/Makefile.rules
This line tells our Makefile to include a general set of rules. You'll note we use a symbol, $(KOS_BASE). This is a label we declared when we ran our environ.sh script. If you go into environ.sh, see exactly what $(KOS_BASE) maps to, in this case, the location of our KOS folder (~/dc/kos).
This line declares a variable string called OBJS that we can use when sending commands. Anytime we use OBJS in our commands, it will be replaced with the text to the right of the equals sign. To use this variable in a command, we use a dollar sign then call the name of our variable in parenthesis, like this: $(OBJ).
Code: Select all
KOS_LOCAL_CFLAGS = -I$(KOS_BASE)/addons/zlib
This is another variable string. This one is for flags we want to use later on. It uses the $(KOS_BASE) symbol, then goes to the /addons/zlib/ folder in KOS.
Code: Select all
clean:
-rm -f example.elf $(OBJS)
-rm -f romdisk_boot.*
This is another macro defined in the Makefile, called “clean:”. To call this macro, when we launch make from our terminal, we add the label as a flag, like so:
This macro sends two commands to the console. The first
re
moves (deletes) files, namely example.elf, and whatever we have defined in $(OBJS). The “-f” flag after rm is for “force,” it deletes the files without complaining, whether they exist or not. It also deletes any files named “romdisk_boot” regardless of extension. “*” is a wild card symbol, it means “all” or “any.” You can use “*” on both sides of the file name – before the period and after. “*.o” would mean “any object file,” “object.*” would mean “any file named “object” of any type, and “*.*” would mean “any file, period.”
This means that the clean command is deleting any files we might generate during a compile. In this case, the following files are deleted: example.elf, example.o, wfont.o, and any files named romdisk_boot. That is the general purpose of any clean command, and it's generally a good idea to have one that deletes all files you produce in compile.
Code: Select all
dist:
-rm -f $(OBJS)
-rm -f romdisk_boot.*
$(KOS_STRIP) example.elf
This is a macro to prep a built project for distribution. You see it deletes the object files we produce during compile (example.o and wfont.o), and it deletes any files named “romdisk_boot” regardless of extension.
This command then calls $(KOS_STRIP). KOS_STRIP is defined in environ_base.sh, which is called in environ.sh. It is a link to a program in Cygwin's bin folder called sh-elf-strip, which is located in opt/toolchains/dc/sh-elf/bin/ sh-elf-strip is a program that removes symbols from files, which we do to our elf when we want to distribute it.
Code: Select all
rm-elf:
-rm -f example.elf
-rm -f romdisk_boot.*
this is a macro to manually remove the elf file we generate from compile, along with all our romdisk_boot files regardless of extension.
Code: Select all
example.elf: $(OBJS) romdisk_boot.o
$(KOS_CC) $(KOS_CFLAGS) $(KOS_LDFLAGS) -o $@ $(KOS_START) $^ -lpng -lz -lm $(KOS_LIBS)
This is a macro to create example.elf. To the right of the macro name, we have two per-requisites that make will check. First, all the objects we defined as $(OBJ) must exist, and also a file named romdisk_boot.o must exist.
This is our Linker function. The actual command begins with $(KOS_CC). KOC_CC is defined in environ.sh, it is a link to our compiler, at “/opt/toolchains/dc/sh-elf/bin/sh-elf-gcc”. Sh-elf-gcc is a special variant of gcc that generates elfs for the sh family of processor by linking object files. The Dreamcast uses an sh4 processor.
Before this macro will run, the prerequisite files must exist. If the files do not exist, they will check our environ.sh, environ_base.sh, and any files “included” with the Makefile, along with the rest of the Makefile itself for instructions on how to create them. Let's examine our prerequisites and see how they are generated before examining how our linker works.
The first prerequisite is $(OBJS). That is a string meaning example.o and wfont.o. So when we call $(OBJS) it equates to two separate prerequisites. Example.o, as you might recall, is the compiled object file. Since the name of the source is Example.c, it makes sense to call it's compiled object output Example.o. Example.o doesn't exist yet, and the rest of the Makefile doesn't define how to create it. Neither does environ.sh or environ_base.sh. But we included $(KOS_BASE)/Makefile.rules, and in there we define how to create a .o file:
Code: Select all
%.o: %.c
kos-cc $(CFLAGS) -c $< -o $@
“%” in this case is a wild card input, kind of like “*”. In this case, there is no specific instruction for “Example.o” but there is a general rule for any object file. You see this macro has a prerequisite itself, %.c has to exist, in this case “Example.c”. In this case, that file does exist in our folder, so we pass the prerequisite.
It calls kos-cc from our KOS_BASE folder (because that's where Makefile.rules is), which is our KOS C compiler. We feed our C Compiler $(CFLAGS) which is set automatically depending on our version of KOS. The -c flag tells the compiler to take in a source file. The -c flag takes in a parameter, which pass as $<. $< is a symbol that refers to our prerequisites themselves. $< means the first prerequisite on the list, which is “%.c” which is also “Example.c”.
The -o flag tells the compiler we want to output a file. The -o flag takes in a parameter which we pass as $@. $@ is a symbol that refers to the name of the macro itself. Since our macro is called “%.o” this means we pass the compiler an output of “%.o” which, in this case, means “example.o”. In short, we are telling the compiler to take in Example.c and output Example.o.
Going back to our Linker, the second prerequisite from $(OBJS) is wfont.o. Again, this file doesn't exist, but the next defined macro in our Makefile tells us how to make wfont.o:
Code: Select all
wfont.o: wfont.bin
$(KOS_BASE)/utils/bin2o/bin2o $< wfont $@
In this case, wfont.bin needs to exist first. You may remember that we said wfont.bin was the graphic for our font in binary form. In this case, rather than calling our KOS-CC compiler, we call a program in ~/dc/kos/utils/bin2o called bin2o. This program rather obviously converts a binary file into an object file suitable for linking. Again, we feed the first prerequisite as an input, recognized as the symbol $<. Object files contain a label, which we set by passing the “wfont” flag. This labels our object file as “wfont.” The output file is passed as the macro name recognized by the symbol $@. In short, this runs bin2o and takes in wfont.bin and outputs a object labeled “wfont” as wfont.o.
Back at our Linker, the final prerequisite is romdisk_boot.o, which also does not exist. But later in the Makefile, we define it as:
Code: Select all
romdisk_boot.o: romdisk_boot.img
$(KOS_BASE)/utils/bin2o/bin2o $< romdisk_boot $@
You see that we first need romdisk_boot.img to exist. We create that in the Makefile here:
Code: Select all
romdisk_boot.img:
$(KOS_GENROMFS) -f $@ -d romdisk_boot -v
$(KOS_GENROMFS) is a link to a program called genromfs located at “~/dc/kos/utils/genromfs/”. By passing -f to genromfs we force it to generate the file without complaining, even if it already exists. We use the macro name, romdisk_boot.img as our output recognized by $@, then tell genromfs we are passing a directory by passing “-d”. “-d” takes a parameter which we pass as the string “romdisk_boot”. The -v flag tells it to be verbose, so we can see the generation of the folder. What this does is take our romdisk_boot folder and turns it into a binary image of the folder, called romdisk.img.
With romdisk_boot.img created, we can continue creating romdisk_boot.o. This time it continues just like we did with wfont. We take romdisk.img as the input ($<), label it romdisk_boot, then name the output file romdisk.o ($@)
With Example.o, wfont.o, and romdisk_boot.o all created, we can finally continue with our Linker call. Recall that our linker called a program named sh-elf-gcc. When calling sh-elf-gcc, we use $(KOS_CFLAGS), which is defined in environ.sh. These are general settings we want to use for gcc. According to environ_base.sh, $(KOS_LDFLAGS) actually isn't set. Whether or not it's set depends on which version of the kos-cross compiler we are using. we don't really need to worry about it. It disables stdlib when set, which we don't necessarily want.
The next part of the command, “-o” tells gcc that we want to output a file. The -o flag takes a name as a parameter, which we pass $@. Our macro is example.elf, so the name we passed -o is “example.elf”
$(KOS_START) is a macro to call a startup script. Whether or not it's set depends on which version of the kos-cross compiler we are using. we don't really need to worry about it.
$^ refers to our prerequisites, which we are feeding to gcc to generate our output file. Though we don't use it in this example, $< would refer to the first prerequisite we listed, $(OBJ), while $> would refer to the last, romdisk_boot.o. $^ refers to all the prerequisites, so we wind up passing gcc $(OBJ) and romdisk_boot.o, which equates to example.o, wfont.o, and romdisk_boot.o.
Finally, we pass our Linker library files that we need. When compiling in unix, library files usually begin with -l, for example the png library is -lpng. In windows, typically library files are .lib files, for example png.lib may exist. Because we are using Cygwin in windows, we adhere to UNIX style rules. In this case, we pass 4 libraries: -lpng, -lz, and -lm, and $(KOS_LIBS). $(KOS_LIBS) are all the libraries we need to compile KOS projects.
Thus, in all, our Linker calls sh-elf-gcc and links example.o, wfont.o, romdisk_boot.o, and uses libraries -lpng, -lz, and -lw, to output example.elf.
The final line in the Makefile is a macro called run. This should compile our project then attempt to run it through a special serial cable you can build for your Dreamcast. We won't be using this style of running programs in our tutorial, but this is a valid avenue for deploying ELFs. To use this, we would call
STEP 3: BUILDING THE PROJECTNow that we understand our Makefile, it's finally time to build our project. Open a terminal and go to the png folder. From within this folder, type:
This will call make using the Makefile. Before we called make, we should have had the following files in the directory:
Code: Select all
example.c
Makefile
romdisk_boot (folder)
wfont.bin
After running make, we should have the following:
Code: Select all
example.c
example.elf
example.o
Makefile
romdisk_boot (folder)
romdisk_boot.img
romdisk_boot.o
wfont.bin
wfont.o
If we were to run:
we would go back to our first file list. Make creates those files, and make clean deletes them. Now that we have generated our elf file, let's turn it into a binary:
Code: Select all
sh-elf-objcopy -R .stack -O binary example.elf output.bin
this calls a program called sh-elf-objcopy. Objcopy is a program available on many platforms that lets you copy objects into a binary. In this case, we are turning our elf into a binary called output.bin. After we have our output.bin, we need to scramble it. If you are on Linux, use the following command:
Code: Select all
../../utils/scramble/scramble output.bin 1st_read.bin
or, if you are windows, you run this command:
This will produce a binary file called 1st_read.bin. Now, we need to grab an appropriate IP.bin. I have included one in the file pack in the OP, and likewise you can grab it individually right here: [IP.bin link]
From here, if you are running windows, you can use a program called Bootdreams. I have included Bootdreams in the filepack in the opening post, and also individually here: [Bootdreams link]
Boot dreams makes it easy to turn your 1st_read.bin and IP.bin into a bootable Dreamcast disk with a graphical interface. Open it in windows:
Click on Browse to open a file browser. Navigate to your png folder in Cygwin:
This folder we select will be turned into the “/cd/” folder from the perspective of our program. Bootdreams will find 1st_read.bin and IP.bin in this folder and assign them to the appropriate spot on the cd accordingly. Make sure you have diskjuggler selected at the top of bootdreams and give your program a label in the label section. Keep your disk format as Audio/disk, then click process. It will ask you if you want to create a diskjuggler image, click yes. If, for some reason, it cannot find 1st_read.bin, it will ask you what binary file you want to associate with that region of the disk. Also, if it doesn't find IP.bin, it was ask if you want it to create it. With all that said and done, save your file as “example.cdi” file.
Next, burn your .cdi file with the special version of IMGBurn you installed on your PC prior. To do this, open IMG Burn:
Click “write image file to disc” and next to “Please select a file” click the folder button. Navigate to your example.cdi file, insert a blank CD-ROM into your CD burner, then click the burn button. Sit back and wait for it to burn.
If you aren't on windows, or don't want to use these GUI programs, you can burn your disc using the following commands instead.
Code: Select all
mkisofs -G IP.bin -o session1.iso ~/dc/kos/Projects/png/
This uses mkisofs to pack IP.bin and an entire folder, “~/dc/kos/Projects/png/” into an output file called session1.iso. After we create session1.iso, use the following commands to burn the disc:
Code: Select all
dd if=session1.iso bs=1024 count=36 > session2.iso
cdrecord dev=1,0,0 speed=8 -multi -xa1 session1.iso
cdrecord dev=1,0,0 speed=8 -eject -xa1 session2.iso
This creates a second iso that will pad our CD, then burns our session1.iso on session 1, then burns session2.iso on the second session.
STEP 4: RUNNING OUR PROGRAMWith this burned disc, we can place it in our Dreamcast and it will boot:
Otherwise, we can load either the cdi image we create with boot dreams, or the sesssion1.iso we created otherwise in NullDC. To do this, open NullDC and click “File → Normal Boot” then select your CDI image and click ok. Assuming your emulator is set up correctly, you will boot the program as intended.