diff options
Diffstat (limited to 'src/ada_chip.adb')
-rw-r--r-- | src/ada_chip.adb | 146 |
1 files changed, 146 insertions, 0 deletions
diff --git a/src/ada_chip.adb b/src/ada_chip.adb new file mode 100644 index 0000000..b79db1c --- /dev/null +++ b/src/ada_chip.adb @@ -0,0 +1,146 @@ +with Ada.Command_Line; +with Ada.Numerics.Discrete_Random; +with Ada.Text_IO; +with Sf; + +with ISA; use ISA; +with CPU; +with Video; + +procedure Ada_Chip is + package Random_Byte is new Ada.Numerics.Discrete_Random (Byte); + + Steps_Per_Frame : constant := 16; + + State : CPU.Instance; + Random_Generator : Random_Byte.Generator; + + procedure Draw_Sprite (VX, VY : Register_Index; N : Byte) is + use Sf; + + X, Y : sfUint32; + Row : aliased Byte; + Row_Pixels : Pixel with Address => Row'Address; + VF : Boolean := False; + begin + X := sfUint32 (State.Registers (VX)); + Y := sfUint32 (State.Registers (VY)); + + 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 (X + sfUint32 (J), Y + sfUint32 (I)) then + VF := True; + end if; + end if; + end loop; + end loop; + + State.Registers (15) := (if VF then 1 else 0); + end Draw_Sprite; + + procedure Run_Step is + ins : Opcode; + begin + ins := CPU.Get_Opcode (State); + case ins.Class is + when Flow => + case ins.Value is + when 16#E0# => Video.Clear_Screen; + when 16#EE# => CPU.Ret (State); + when others => begin + Ada.Text_IO.Put_Line ("Unknown flow instruction!"); + Ada.Text_IO.Put_Line (Opcode_Value'Image (ins.Value)); + delay 1.0; + Video.Finish; + end; + end case; + when Jump => CPU.Jump (State, Address (ins.Value)); + when Call => CPU.Call (State, Address (ins.Value)); + when Equal => + if State.Registers (X_Register (ins)) = To_Byte (ins) then + CPU.Skip (State); + end if; + when Not_Equal => + if State.Registers (X_Register (ins)) /= To_Byte (ins) then + CPU.Skip (State); + end if; + when Compare => + if State.Registers (X_Register (ins)) = + State.Registers (Y_Register (ins)) + then + CPU.Skip (State); + end if; + when Set_Register => + State.Registers (X_Register (ins)) := To_Byte (ins); + when Add => + State.Registers (X_Register (ins)) := + State.Registers (X_Register (ins)) + To_Byte (ins); + when Math => + CPU.Math (State, X_Register (ins), Y_Register (ins), + To_Byte (ins) mod 16); + when Not_Compare => + if State.Registers (X_Register (ins)) /= + State.Registers (Y_Register (ins)) + then + CPU.Skip (State); + end if; + when Set_Address => + State.Address_Register := Address (ins.Value); + when Random => + State.Registers (X_Register (ins)) := + Random_Byte.Random (Random_Generator) mod To_Byte (ins); + when Draw_Sprite => + Draw_Sprite (X_Register (ins), Y_Register (ins), + To_Byte (ins) mod 16); + when Misc => + case To_Byte (ins) is + when 16#07# => + State.Registers (X_Register (ins)) := State.Delay_Timer; + when 16#15# => + State.Delay_Timer := State.Registers (X_Register (ins)); + when 16#1E# => + State.Address_Register := State.Address_Register + + Address (State.Registers (X_Register (ins))); + when 16#55# => + CPU.Reg_Store (State, X_Register (ins)); + when 16#65# => + CPU.Reg_Load (State, X_Register (ins)); + when others => begin + Ada.Text_IO.Put_Line ("Unknown misc instruction!"); + Ada.Text_IO.Put_Line (Opcode_Value'Image (ins.Value)); + delay 1.0; + Video.Finish; + end; + end case; + when others => begin + Ada.Text_IO.Put_Line ("Unknown instruction class!"); + Ada.Text_IO.Put_Line (Opcode_Class'Image (ins.Class)); + delay 1.0; + Video.Finish; + end; + end case; + end Run_Step; +begin + if Ada.Command_Line.Argument_Count /= 1 then + Ada.Text_IO.Put_Line ("usage: adachip <.c8 file>"); + else + Video.Initialize; + Random_Byte.Reset (Random_Generator); + CPU.Load_File (State, Ada.Command_Line.Argument (1)); + + while Video.Is_Running loop + Video.Display; + + if State.Delay_Timer > 0 then + State.Delay_Timer := State.Delay_Timer - 1; + end if; + + for I in 0 .. Steps_Per_Frame loop + Run_Step; + end loop; + end loop; + end if; +end Ada_Chip; |