Ada Bare Bones: Difference between revisions

no edit summary
[unchecked revision][unchecked revision]
No edit summary
Line 60:
<source lang="ada">
pragma Discard_Names;
pragma Restrictions (No_Enumeration_Maps);
pragma Normalize_Scalars;
pragma Restrictions (No_Exception_PropagationNo_Exception_Handlers);
pragma Restrictions (No_Finalization);
-- Use pragma Restrictions (No_Tasking) instead?;
pragma Restrictions (Max_Tasks => 0);
pragma Restrictions (No_Protected_Types);
pragma Restrictions (No_Delay);
-- pragma Restrictions (No_Floating_Point);
pragma Restrictions (No_Recursion);
pragma Restrictions (No_Allocators);
Line 155 ⟶ 154:
===Compiling the runtime===
 
Create a file called gnat.gpr in the root directory and copy the following into it:
 
<pre>
Line 208 ⟶ 207:
 
===startup.s===
 
This is PC specific so place this in the src/pc directory.
 
====GAS====
Line 255 ⟶ 256:
===Console===
 
The following 2 files give you access to the VGA console at 80x25 characters. As they are PC specific, they go into the src/pc directory.
 
====console.ads====
 
<source lang="ada">
with System;
-- TODO
 
package Console is
pragma Preelaborate (Console);
 
type Background_Colour is
(Black,
Blue,
Green,
Cyan,
Red,
Magenta,
Brown,
Light_Grey);
 
for Background_Colour use
(Black => 16#0#,
Blue => 16#1#,
Green => 16#2#,
Cyan => 16#3#,
Red => 16#4#,
Magenta => 16#5#,
Brown => 16#6#,
Light_Grey => 16#7#);
 
for Background_Colour'Size use 4;
 
type Foreground_Colour is
(Black,
Blue,
Green,
Cyan,
Red,
Magenta,
Brown,
Light_Grey,
Dark_Grey,
Light_Blue,
Light_Green,
Light_Cyan,
Light_Red,
Light_Magenta,
Yellow,
White);
 
for Foreground_Colour use
(Black => 16#0#,
Blue => 16#1#,
Green => 16#2#,
Cyan => 16#3#,
Red => 16#4#,
Magenta => 16#5#,
Brown => 16#6#,
Light_Grey => 16#7#,
Dark_Grey => 16#8#,
Light_Blue => 16#9#,
Light_Green => 16#A#,
Light_Cyan => 16#B#,
Light_Red => 16#C#,
Light_Magenta => 16#D#,
Yellow => 16#E#,
White => 16#F#);
 
for Foreground_Colour'Size use 4;
 
type Cell_Colour is
record
Foreground : Foreground_Colour;
Background : Background_Colour;
end record;
 
for Cell_Colour use
record
Foreground at 0 range 0 .. 3;
Background at 0 range 4 .. 7;
end record;
 
for Cell_Colour'Size use 8;
 
type Cell is
record
Char : Character;
Colour : Cell_Colour;
end record;
 
for Cell'Size use 16;
 
Screen_Width : constant Natural := 80;
Screen_Height : constant Natural := 25;
 
subtype Screen_Width_Range is Natural range 1 .. Screen_Width;
subtype Screen_Height_Range is Natural range 1 .. Screen_Height;
 
type Row is array (Screen_Width_Range) of Cell;
type Screen is array (Screen_Height_Range) of Row;
 
Video_Memory : Screen;
 
for Video_Memory'Address use System'To_Address (16#000B_8000#);
 
pragma Import (Ada, Video_Memory);
 
procedure Put
(Char : in Character;
X : in Screen_Width_Range;
Y : in Screen_Height_Range;
Foreground : in Foreground_Colour := White;
Background : in Background_Colour := Black);
 
procedure Put
(Str : in String;
X : in Screen_Width_Range;
Y : in Screen_Height_Range;
Foreground : in Foreground_Colour := White;
Background : in Background_Colour := Black);
 
procedure Clear (Background : in Background_Colour := Black);
end Console;
</source>
 
Line 266 ⟶ 384:
 
<source lang="ada">
package body Console is
-- TODO
procedure Put
(Char : in Character;
X : in Screen_Width_Range;
Y : in Screen_Height_Range;
Foreground : in Foreground_Colour := White;
Background : in Background_Colour := Black) is
begin
Video_Memory (Y)(X).Char := Char;
Video_Memory (Y)(X).Colour.Foreground := Foreground;
Video_Memory (Y)(X).Colour.Background := Background;
end Put;
 
procedure Put
(Str : in String;
X : in Screen_Width_Range;
Y : in Screen_Height_Range;
Foreground : in Foreground_Colour := White;
Background : in Background_Colour := Black) is
begin
for Index in Str'First .. Str'Last loop
Put (Str (Index),
X + Screen_Width_Range (Index) - 1,
Y,
Foreground,
Background);
end loop;
end Put;
 
procedure Clear (Background : in Background_Colour := Black) is
begin
for X in Screen_Width_Range'First .. Screen_Width_Range'Last loop
for Y in Screen_Height_Range'First .. Screen_Height_Range'Last loop
Put (' ', X, Y, Background => Background);
end loop;
end loop;
end Clear;
end Console;
</source>
 
===kernelbare_bones.adb===
 
This is platform independent and therefore goes into the src directory.
 
<source lang="ada">
with Console; use Console;
-- TODO
 
procedure Bare_Bones is
begin
Clear;
 
Put ("Hello, bare bones in Ada.",
Screen_Width_Range'First,
Screen_Height_Range'First);
end Bare_Bones;
pragma No_Return (Bare_Bones);
</source>
 
===linker.ld===
 
This is a PC specific script so goes into the src/pc directory.
 
<pre>
OUTPUT_FORMAT(elf32-i386)
STARTUP(startup.o)
ENTRY (startup)
 
Line 283 ⟶ 455:
. = 0x00100000;
 
.text ALIGN (0x1000) :{
code = .; _code = .; __code = .;
{
*(.text)
*(.rodata)
}
 
.rodata ALIGN (0x1000) : {
{ *(.rodata)
*(.rodata*)
}
 
.data ALIGN (0x1000) : {
data = .; _data = .; __data = .;
{
*(.data)
}
 
.bss : {
{
sbss = .;
bss = .; _bss = .; __bss = .;
*(COMMON)
*(.bss)
ebss = .;
}
end = .; _end = .; __end = .;
}
</pre>
 
===makefile===
 
Place this file in the root directory.
 
<pre>
ARCH = i386
RTS_DIR = `pwd`/rts/boards/$(ARCH)
 
ifeq ($(ARCH),i386)
GNATMAKE = gnatmake
AS = as
ASFLAGS = --32 -march=i386
 
OBJS = obj/startup.o obj/multiboot.o obj/console.o
BOARD = pc
 
.PHONY: obj/multiboot.o obj/console.o
 
endif
 
all: bare_bones
 
bare_bones: $(OBJS) src/bare_bones.adb
$(GNATMAKE) --RTS=$(RTS_DIR) -XBoard=$(BOARD) -Pbare_bones.gpr
 
obj/startup.o: src/$(BOARD)/startup.s
$(AS) $(ASFLAGS) src/$(BOARD)/startup.s -o obj/startup.o
 
.PHONY: clean
 
clean:
-rm obj/* *~ bare_bones
</pre>
 
===bare_bones.gpr===
 
Place this file in the root directory.
 
<pre>
project Bare_Bones is
type Arch_Name is ("i386", "arm");
type Board_Name is ("pc", "rpi");
 
Arch : Arch_Name := "i386";
Board : Board_Name := external ("Board");
 
-- TODO: Add in a case statement that adds an arch dir to source.
 
case Board is
when "pc" =>
for Source_Dirs use ("src", "src/pc");
when "rpi" =>
for Source_Dirs use ("src", "src/rpi");
end case;
 
for Object_Dir use "obj";
for Exec_Dir use ".";
for Main use ("bare_bones.adb");
 
package Builder is
Basic_Switches := ("-gnat2005", "-g", "-x", "-a", "-gnatg",
"-gnatec=../gnat.adc", "-gnaty-I", "-gnaty+d");
 
case Board is
when "pc" =>
for Default_Switches ("Ada") use Basic_Switches &
("-m32", "-march=i386");
when "rpi" =>
for Default_Switches ("Ada") use Basic_Switches &
("-march=armv6zk", "-mfpu=vfp", "-mfloat-abi=hard", "-marm",
"-mcpu=arm1176jzf-s", "-mtune=arm1176jzf-s");
end case;
end Builder;
 
package Compiler is
case Board is
when "pc" =>
for Default_Switches ("Ada") use
("-O0", "-g", "-ggdb", "-ffunction-sections", "-fdata-sections");
when "rpi" =>
for Default_Switches ("Ada") use
("-O0", "-g", "-ggdb", "-ffunction-sections", "-fdata-sections");
 
end case;
end Compiler;
 
-- To reduce size of final binary.
package Linker is
for Default_Switches ("Ada") use
("-Wl,--gc-sections", "-static", "-nostartfiles", "-nodefaultlibs",
"-T../src/" & Board & "/linker.ld", "-v");
end Linker;
end Bare_Bones;
</pre>
 
==Testing==
 
Make sure you have built the RTS above before this next stage otherwise you won'g have a kernel.
 
<source lang="bash">
make
 
qemu -kernel bare_bones
</source>
 
On the QEMU window, it should clear the screen, the the cursor won't move so it will be in the middle of the screen, in the top-left corner will be the message "Hello, bare bones in Ada."
 
[[Category:Bare bones tutorials]]
Anonymous user