aboutsummaryrefslogtreecommitdiffstats
path: root/src/cpu.adb
blob: 809e03999fe2c66e9565c0cdd7d97f8b236a459c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
with Ada.Sequential_IO;
with Ada.Text_IO;
with Bit_Ops;

package body CPU is
   function Get_Opcode (Inst : in out Instance) return Opcode is
      Op : aliased Opcode_Raw;
      Op_Record : Opcode with Address => Op'Address;
   begin
      Op := Opcode_Raw (Inst.Memory (Inst.Program_Counter)) * 2 ** 8;
      Op := Op + Opcode_Raw (Inst.Memory (Inst.Program_Counter + 1));
      Inst.Program_Counter := Inst.Program_Counter + 2;
      return Op_Record;
   end Get_Opcode;

   procedure Reg_Store (Inst : in out Instance; VX : Register_Index) is
   begin
      for I in 0 .. VX loop
         Inst.Memory (Inst.Address_Register + Address (I)) :=
            Inst.Registers (I);
      end loop;
   end Reg_Store;

   procedure Reg_Load (Inst : in out Instance; VX : Register_Index) is
   begin
      for I in 0 .. VX loop
         Inst.Registers (I) := Inst.Memory
            (Inst.Address_Register + Address (I));
      end loop;
   end Reg_Load;

   procedure Ret (Inst : in out Instance) is
   begin
      Jump (Inst, Inst.Stack.Last_Element);
      Inst.Stack.Delete_Last;
   end Ret;

   procedure Call (Inst : in out Instance; A : Address) is
   begin
      Inst.Stack.Append (Inst.Program_Counter);
      Jump (Inst, A);
   end Call;

   procedure Jump (Inst : in out Instance; A : Address) is
   begin
      Inst.Program_Counter := A;
   end Jump;

   procedure Skip (Inst : in out Instance) is
   begin
      Inst.Program_Counter := Inst.Program_Counter + 2;
   end Skip;

   procedure Math (Inst : in out Instance; VX, VY : Register_Index; N : Byte)
   is begin
      case N is
         when 0 =>
            Inst.Registers (VX) := Inst.Registers (VY);
         when 1 =>
            Inst.Registers (VX) := Bit_Ops.Bitwise_Or
               (Inst.Registers (VX), Inst.Registers (VY));
         when 2 =>
            Inst.Registers (VX) := Bit_Ops.Bitwise_And
               (Inst.Registers (VX), Inst.Registers (VY));
         when 3 =>
            Inst.Registers (VX) := Bit_Ops.Bitwise_Xor
               (Inst.Registers (VX), Inst.Registers (VY));
         when 4 =>
            declare
               X : constant Byte := Inst.Registers (VX);
               Y : constant Byte := Inst.Registers (VY);
            begin
               Inst.Registers (VX) := X + Y;
               Inst.Registers (15) :=
                  (if Integer (X) + Integer (Y) > Integer (X + Y)
                     then 1 else 0);
            end;
         when 5 =>
            declare
               X : constant Byte := Inst.Registers (VX);
               Y : constant Byte := Inst.Registers (VY);
            begin
               Inst.Registers (VX) := X - Y;
               Inst.Registers (15) := (if X >= Y then 1 else 0);
            end;
         when 6 =>
            Inst.Registers (15) := Inst.Registers (VX) mod 2;
            Inst.Registers (VX) := Inst.Registers (VX) / 2;
         when 14 =>
            Inst.Registers (15) := Inst.Registers (VX) / (2 ** 7);
            Inst.Registers (VX) := Inst.Registers (VX) * 2;
         when others => begin
            Ada.Text_IO.Put_Line ("Uh oh!");
            Ada.Text_IO.Put_Line (Byte'Image (N));
         end;
      end case;
   end Math;

   procedure Load_File (Inst : in out Instance; File_Name : String) is
      package Byte_IO is new Ada.Sequential_IO (Byte);

      I : Address := Start_Address;
      File_Handle : Byte_IO.File_Type;
   begin
      Byte_IO.Open (File_Handle, Byte_IO.In_File, File_Name);

      while not Byte_IO.End_Of_File (File_Handle) loop
         Byte_IO.Read (File_Handle, Inst.Memory (I));
         I := I + 1;
      end loop;

      Byte_IO.Close (File_Handle);
   end Load_File;
end CPU;