aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorClyne Sullivan <clyne@bitgloo.com>2025-01-12 15:50:21 -0500
committerClyne Sullivan <clyne@bitgloo.com>2025-01-12 15:50:21 -0500
commit3465042dc2a80f4090d6cf6b65ddc33ee4e48b55 (patch)
tree6635abbabe7418b84355d0ae7cb355ab6e84e6e8
parent2eecfdaeca7daedd7e4ae3baaa94113b43cb8b68 (diff)
initial schip implementation; add command line arguments
-rw-r--r--src/ada_chip.adb132
-rw-r--r--src/cpu.ads19
-rw-r--r--src/isa.ads11
-rw-r--r--src/video.adb41
-rw-r--r--src/video.ads26
5 files changed, 188 insertions, 41 deletions
diff --git a/src/ada_chip.adb b/src/ada_chip.adb
index da48b7b..b6a7611 100644
--- a/src/ada_chip.adb
+++ b/src/ada_chip.adb
@@ -17,9 +17,13 @@ procedure Ada_Chip is
State : CPU.Instance;
Delay_Timer : Natural := 0;
Sound_Timer : Natural := 0;
+ Model : Video.Model := Video.Chip_8;
+ Steps_Per_Frame : Natural := 8;
procedure Draw_Sprite (VX, VY : ISA.Register_Index; N : ISA.Byte) is
use ISA;
+ use Sf;
+ use Video;
X : constant Byte := State.Registers (VX);
Y : constant Byte := State.Registers (VY);
@@ -27,22 +31,54 @@ procedure Ada_Chip is
Row_Pixels : Pixel with Address => Row'Address;
VF : Byte := 0;
begin
- for I in 0 .. N - 1 loop
- Row := State.Memory (State.Address_Register + Address (I));
-
- for J in 0 .. 7 loop
- if Row_Pixels (7 - J) then
- if Video.Toggle_Pixel
- (Sf.sfUint32 ((X + Byte (J)) mod Video.Width),
- Sf.sfUint32 ((Y + I) mod Video.Height))
- then
- VF := 1;
+ if Model = Super_Chip_10 and then N = 0 then
+ for I in 0 .. Byte (15) loop
+ Row := State.Memory (State.Address_Register + Address (I * 2));
+
+ for J in 0 .. 7 loop
+ if Row_Pixels (7 - J) then
+ if Video.Toggle_Pixel
+ (sfUint32 (X + Byte (J)) mod Video.Width,
+ sfUint32 (Y + I) mod Video.Height)
+ then
+ VF := 1;
+ end if;
end if;
- end if;
+ end loop;
+
+ Row := State.Memory (State.Address_Register + Address (I * 2 + 1));
+
+ for J in 0 .. 7 loop
+ if Row_Pixels (7 - J) then
+ if Video.Toggle_Pixel
+ (sfUint32 (8 + X + Byte (J)) mod Video.Width,
+ sfUint32 (Y + I) mod Video.Height)
+ then
+ VF := 1;
+ end if;
+ end if;
+ end loop;
+ end loop;
+
+ State.Registers (15) := VF;
+ else
+ for I in 0 .. N - 1 loop
+ Row := State.Memory (State.Address_Register + Address (I));
+
+ for J in 0 .. 7 loop
+ if Row_Pixels (7 - J) then
+ if Video.Toggle_Pixel
+ (sfUint32 (X + Byte (J)) mod Video.Width,
+ sfUint32 (Y + I) mod Video.Height)
+ then
+ VF := 1;
+ end if;
+ end if;
+ end loop;
end loop;
- end loop;
- State.Registers (15) := VF;
+ State.Registers (15) := VF;
+ end if;
end Draw_Sprite;
procedure Run_Flow (ins : ISA.Opcode) is
@@ -50,6 +86,8 @@ procedure Ada_Chip is
case ins.Value is
when ISA.Clear_Screen => Video.Clear_Screen;
when ISA.Ret => CPU.Ret (State);
+ when ISA.Low_Res => Video.Low_Res;
+ when ISA.High_Res => Video.High_Res;
when others =>
Ada.Text_IO.Put_Line ("Machine code calls are unsupported!");
delay 1.0;
@@ -85,10 +123,35 @@ procedure Ada_Chip is
when Set_Sound => Sound_Timer := Natural (State.Registers (X));
when Reg_Store => CPU.Reg_Store (State, X);
when Reg_Load => CPU.Reg_Load (State, X);
+ when Reg_Store_X => declare
+ I : constant Address := State.Address_Register;
+ begin
+ State.Address_Register := CPU.RPL_Stash;
+ CPU.Reg_Store (State, X);
+ State.Address_Register := I;
+ end;
+ when Reg_Load_X => declare
+ I : constant Address := State.Address_Register;
+ begin
+ State.Address_Register := CPU.RPL_Stash;
+ CPU.Reg_Load (State, X);
+ State.Address_Register := I;
+ end;
when Add_Address => State.Address_Register :=
State.Address_Register + Address (State.Registers (X));
- when Get_Font =>
- State.Address_Register := Address (State.Registers (X) mod 16) * 5;
+ when Get_Font => declare
+ use Video;
+ VX : constant Byte := State.Registers (X);
+ begin
+ if Model = Video.Super_Chip_10 and then VX > 15 then
+ State.Address_Register := Address (VX mod 16) * 10 + 80;
+ else
+ State.Address_Register := Address (VX mod 16) * 5;
+ end if;
+ end;
+ when Get_Font_10 =>
+ State.Address_Register := Address (State.Registers (X) mod 16)
+ * 10 + 80;
when Get_BCD =>
State.Memory (State.Address_Register) :=
State.Registers (X) / 100;
@@ -143,17 +206,46 @@ procedure Ada_Chip is
end case;
end Run_Step;
- Steps_Per_Frame : constant := 8;
Beep_Sound : constant Sf.Audio.sfSound_Ptr := Sf.Audio.Sound.create;
Beep_Sound_Buffer : constant Sf.Audio.sfSoundBuffer_Ptr :=
Sf.Audio.SoundBuffer.createFromFile ("beep.ogg");
+
+ File_Loaded : Boolean := False;
begin
- if Ada.Command_Line.Argument_Count /= 1 then
- Ada.Text_IO.Put_Line ("usage: adachip <.c8 file>");
+ for I in 1 .. Ada.Command_Line.Argument_Count loop
+ declare
+ Arg : constant String := Ada.Command_Line.Argument (I);
+ begin
+ if Arg = "--schip" then
+ Ada.Text_IO.Put_Line ("Super-CHIP model selected.");
+ Model := Video.Super_Chip_10;
+ else
+ if Arg'Length > 6
+ and then Arg (1 .. 6) = "--spf="
+ then
+ Steps_Per_Frame := Natural'Value (Arg (7 .. Arg'Length));
+ else
+ if File_Loaded then
+ Ada.Text_IO.Put_Line ("More than one ROM specified!");
+ File_Loaded := False;
+ exit;
+ else
+ Ada.Text_IO.Put_Line ("Loading ROM: " &
+ Ada.Command_Line.Argument (I));
+ CPU.Load_File (State, Ada.Command_Line.Argument (I));
+ File_Loaded := True;
+ end if;
+ end if;
+ end if;
+ end;
+ end loop;
+
+ if not File_Loaded then
+ Ada.Text_IO.Put_Line ("usage: adachip [flags] <.c8 file>");
else
- Video.Initialize;
+ Video.Initialize (Model);
+ Video.Low_Res;
Random_Byte.Reset (Random_Generator);
- CPU.Load_File (State, Ada.Command_Line.Argument (1));
Sf.Audio.Sound.setBuffer (Beep_Sound, Beep_Sound_Buffer);
while Video.Is_Running loop
diff --git a/src/cpu.ads b/src/cpu.ads
index 340375b..5401698 100644
--- a/src/cpu.ads
+++ b/src/cpu.ads
@@ -25,6 +25,23 @@ package CPU is
16#E0#, 16#90#, 16#90#, 16#90#, 16#E0#, -- D
16#F0#, 16#80#, 16#F0#, 16#80#, 16#F0#, -- E
16#F0#, 16#80#, 16#F0#, 16#80#, 16#80#, -- F
+
+ 16#F0#, 0, 16#90#, 0, 16#90#, 0, 16#90#, 0, 16#F0#, 0, -- 0
+ 16#20#, 0, 16#60#, 0, 16#20#, 0, 16#20#, 0, 16#70#, 0, -- 1
+ 16#F0#, 0, 16#10#, 0, 16#F0#, 0, 16#80#, 0, 16#F0#, 0, -- 2
+ 16#F0#, 0, 16#10#, 0, 16#F0#, 0, 16#10#, 0, 16#F0#, 0, -- 3
+ 16#90#, 0, 16#90#, 0, 16#F0#, 0, 16#10#, 0, 16#10#, 0, -- 4
+ 16#F0#, 0, 16#80#, 0, 16#F0#, 0, 16#10#, 0, 16#F0#, 0, -- 5
+ 16#F0#, 0, 16#80#, 0, 16#F0#, 0, 16#90#, 0, 16#F0#, 0, -- 6
+ 16#F0#, 0, 16#10#, 0, 16#20#, 0, 16#40#, 0, 16#40#, 0, -- 7
+ 16#F0#, 0, 16#90#, 0, 16#F0#, 0, 16#90#, 0, 16#F0#, 0, -- 8
+ 16#F0#, 0, 16#90#, 0, 16#F0#, 0, 16#10#, 0, 16#F0#, 0, -- 9
+ 16#F0#, 0, 16#90#, 0, 16#F0#, 0, 16#90#, 0, 16#90#, 0, -- A
+ 16#E0#, 0, 16#90#, 0, 16#E0#, 0, 16#90#, 0, 16#E0#, 0, -- B
+ 16#F0#, 0, 16#80#, 0, 16#80#, 0, 16#80#, 0, 16#F0#, 0, -- C
+ 16#E0#, 0, 16#90#, 0, 16#90#, 0, 16#90#, 0, 16#E0#, 0, -- D
+ 16#F0#, 0, 16#80#, 0, 16#F0#, 0, 16#80#, 0, 16#F0#, 0, -- E
+ 16#F0#, 0, 16#80#, 0, 16#F0#, 0, 16#80#, 0, 16#80#, 0, -- F
others => 0
);
Registers : Register_Bank;
@@ -33,6 +50,8 @@ package CPU is
Stack : Address_Stack.Vector;
end record;
+ RPL_Stash : constant Address := 240;
+
procedure Load_File (Inst : in out Instance; File_Name : String);
function Get_Opcode (Inst : in out Instance) return Opcode;
diff --git a/src/isa.ads b/src/isa.ads
index ffc0593..e5310d3 100644
--- a/src/isa.ads
+++ b/src/isa.ads
@@ -45,6 +45,8 @@ package ISA is
Clear_Screen : constant Opcode_Value := 16#E0#;
Ret : constant Opcode_Value := 16#EE#;
+ Low_Res : constant Opcode_Value := 16#FE#;
+ High_Res : constant Opcode_Value := 16#FF#;
type Math_Class is (
Assign, Bit_Or, Bit_And, Bit_Xor, Add, Sub_Y, Shift_Right, Sub_X,
@@ -71,8 +73,8 @@ package ISA is
);
type Misc_Class is (
- Get_Delay, Get_Key, Set_Delay, Set_Sound, Add_Address, Get_Font, Get_BCD,
- Reg_Store, Reg_Load
+ Get_Delay, Get_Key, Set_Delay, Set_Sound, Add_Address, Get_Font,
+ Get_Font_10, Get_BCD, Reg_Store, Reg_Load, Reg_Store_X, Reg_Load_X
);
for Misc_Class use (
@@ -82,9 +84,12 @@ package ISA is
Set_Sound => Opcode_Value (16#18#),
Add_Address => Opcode_Value (16#1E#),
Get_Font => Opcode_Value (16#29#),
+ Get_Font_10 => Opcode_Value (16#30#),
Get_BCD => Opcode_Value (16#33#),
Reg_Store => Opcode_Value (16#55#),
- Reg_Load => Opcode_Value (16#65#)
+ Reg_Load => Opcode_Value (16#65#),
+ Reg_Store_X => Opcode_Value (16#75#),
+ Reg_Load_X => Opcode_Value (16#85#)
);
Start_Address : constant Address := 16#200#;
diff --git a/src/video.adb b/src/video.adb
index aebf23d..f4ddb6b 100644
--- a/src/video.adb
+++ b/src/video.adb
@@ -2,22 +2,55 @@ with Sf.Window;
with Sf.Window.Event;
with Sf.Window.Keyboard;
with Sf.Graphics.Color;
+with Sf.Graphics.Image;
+with Sf.Graphics.RenderWindow;
+with Sf.Graphics.Texture;
package body Video is
procedure Clear_Screen is
begin
- for X in 0 .. sfUint32 (Width) - 1 loop
- for Y in 0 .. sfUint32 (Height) - 1 loop
+ for X in 0 .. Width - 1 loop
+ for Y in 0 .. Height - 1 loop
Image.setPixel (Pixels, X, Y, Color.sfBlack);
end loop;
end loop;
end Clear_Screen;
- procedure Initialize is
+ procedure Low_Res is
begin
+ Video.Width := 64;
+ Video.Height := 32;
+ Video.Scale := 10;
+ Sprite.setScale (Pixels_Sprite, (Float (Scale), Float (Scale)));
+ end Low_Res;
+
+ procedure High_Res is
+ begin
+ Video.Width := 128;
+ Video.Height := 64;
+ Video.Scale := 5;
+ Sprite.setScale (Pixels_Sprite, (Float (Scale), Float (Scale)));
+ end High_Res;
+
+ procedure Initialize (M : Model) is
+ begin
+ case M is
+ when Chip_8 =>
+ Width := 64;
+ Height := 32;
+ Scale := 10;
+ when Super_Chip_10 =>
+ Width := 128;
+ Height := 64;
+ Scale := 5;
+ end case;
+
+ app := RenderWindow.create ((Width * Scale, Height * Scale, 32), Title);
+ Pixels := Image.create (Width, Height);
+ Pixels_Texture := Texture.createFromImage (Pixels);
+
Sprite.setTexture (Pixels_Sprite, Pixels_Texture);
Sprite.setPosition (Pixels_Sprite, (Float (0), Float (0)));
- Sprite.setScale (Pixels_Sprite, (Float (Scale), Float (Scale)));
RenderWindow.setFramerateLimit (app, 60);
end Initialize;
diff --git a/src/video.ads b/src/video.ads
index 32f7683..ec9b212 100644
--- a/src/video.ads
+++ b/src/video.ads
@@ -1,24 +1,25 @@
with Sf;
with Sf.Graphics;
-with Sf.Graphics.Image;
-with Sf.Graphics.RenderWindow;
with Sf.Graphics.Sprite;
-with Sf.Graphics.Texture;
package Video is
use Sf;
use Sf.Graphics;
+ type Model is (Chip_8, Super_Chip_10);
type Key is range 0 .. 15;
type Key_Map is array (Key'Range) of Boolean;
- Width : constant := 64;
- Height : constant := 32;
- Scale : constant := 10;
Title : constant String := "Ada-Chip";
+ Width : sfUint32;
+ Height : sfUint32;
+ Scale : sfUint32;
+
procedure Clear_Screen;
- procedure Initialize;
+ procedure Low_Res;
+ procedure High_Res;
+ procedure Initialize (M : Model);
procedure Display;
procedure Finish;
procedure Poll_Events;
@@ -31,11 +32,8 @@ package Video is
private
Keys : Key_Map;
- Pixels : constant sfImage_Ptr := Image.create (Width, Height);
- Pixels_Sprite : constant sfSprite_Ptr := Sprite.create;
- Pixels_Texture : constant sfTexture_Ptr :=
- Texture.createFromImage (Pixels);
-
- app : constant sfRenderWindow_Ptr := RenderWindow.create
- ((Width * Scale, Height * Scale, 32), Title);
+ app : sfRenderWindow_Ptr;
+ Pixels : sfImage_Ptr;
+ Pixels_Texture : sfTexture_Ptr;
+ Pixels_Sprite : constant sfSprite_Ptr := Sprite.create;
end Video;