File : s-bbcppr-sparc.adb


   1 ------------------------------------------------------------------------------
   2 --                                                                          --
   3 --                  GNAT RUN-TIME LIBRARY (GNARL) COMPONENTS                --
   4 --                                                                          --
   5 --               S Y S T E M . B B . C P U _ P R I M I T I V E S            --
   6 --                                                                          --
   7 --                                  B o d y                                 --
   8 --                                                                          --
   9 --        Copyright (C) 1999-2002 Universidad Politecnica de Madrid         --
  10 --             Copyright (C) 2003-2005 The European Space Agency            --
  11 --                     Copyright (C) 2003-2016, AdaCore                     --
  12 --                                                                          --
  13 -- GNARL is free software; you can  redistribute it  and/or modify it under --
  14 -- terms of the  GNU General Public License as published  by the Free Soft- --
  15 -- ware  Foundation;  either version 3,  or (at your option) any later ver- --
  16 -- sion. GNARL is distributed in the hope that it will be useful, but WITH- --
  17 -- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
  18 -- or FITNESS FOR A PARTICULAR PURPOSE.                                     --
  19 --                                                                          --
  20 --                                                                          --
  21 --                                                                          --
  22 --                                                                          --
  23 --                                                                          --
  24 -- You should have received a copy of the GNU General Public License and    --
  25 -- a copy of the GCC Runtime Library Exception along with this program;     --
  26 -- see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see    --
  27 -- <http://www.gnu.org/licenses/>.                                          --
  28 --                                                                          --
  29 ------------------------------------------------------------------------------
  30 
  31 pragma Restrictions (No_Elaboration_Code);
  32 
  33 with System.Storage_Elements;
  34 with System.Multiprocessors;
  35 with System.BB.Threads;
  36 with System.BB.CPU_Primitives.Multiprocessors;
  37 with System.BB.Threads.Queues;
  38 
  39 package body System.BB.CPU_Primitives is
  40    use BB.Parameters;
  41    use System.BB.Threads;
  42    use System.BB.CPU_Primitives.Multiprocessors;
  43 
  44    package SSE renames System.Storage_Elements;
  45    use type SSE.Integer_Address;
  46    use type SSE.Storage_Offset;
  47 
  48    ----------------
  49    -- Local data --
  50    ----------------
  51 
  52    SP       : constant Context_Id :=  6;
  53    PC       : constant Context_Id :=  7;
  54    PSR      : constant Context_Id :=  8;
  55    WIM      : constant Context_Id := 17;
  56    WIN      : constant Context_Id := 18;
  57    O0       : constant Context_Id :=  0;
  58    INT      : constant Context_Id := 52;
  59    --  These are the registers that are initialized: Program Counter, Stack
  60    --  Pointer, Window Invalid Mask, and Processor State Register. Moreover,
  61    --  the first input argument, the number of register windows to be restored,
  62    --  and the interrupt nesting level are also initialized.
  63 
  64    Base_CCR : constant Context_Id := Base_CCR_Context_Index;
  65    CCR      : constant Context_Id := CCR_Context_Index;
  66    pragma Assert (Base_CCR_Context_Index = 53 and then CCR_Context_Index = 54);
  67    --  For LEON we allocate two slots for the cache control register at the
  68    --  end of the buffer.
  69 
  70    FP : constant SSE.Storage_Offset := 56;
  71    --  The frame pointer needs also to be initialized; however, it is not kept
  72    --  in the thread descriptor but in the stack, and this value represents the
  73    --  offset from the stack pointer (expressed in bytes).
  74 
  75    ----------------------
  76    -- Trap definitions --
  77    ----------------------
  78 
  79    Instruction_Access_Exception : constant Vector_Id := 16#01#;
  80    Illegal_Instruction          : constant Vector_Id := 16#02#;
  81    Address_Not_Aligned          : constant Vector_Id := 16#07#;
  82    FP_Exception                 : constant Vector_Id := 16#08#;
  83    Data_Access_Exception        : constant Vector_Id := 16#09#;
  84    Instruction_Access_Error     : constant Vector_Id := 16#21#;
  85    Data_Access_Error            : constant Vector_Id := 16#29#;
  86    Division_By_Zero_Hw          : constant Vector_Id := 16#2A#;
  87    Data_Store_Error             : constant Vector_Id := 16#2B#;
  88    Division_By_Zero_Sw          : constant Vector_Id := 16#82#;
  89 
  90    type Trap_Entry is
  91       record
  92          First_Instr  : SSE.Integer_Address;
  93          Second_Instr : SSE.Integer_Address;
  94          Third_Instr  : SSE.Integer_Address;
  95          Fourth_Instr : SSE.Integer_Address;
  96       end record;
  97    --  Each entry in the trap table contains the four first instructions that
  98    --  will be executed as part of the handler. A trap is a vectored transfer
  99    --  of control to the supervisor through a special trap table that contains
 100    --  the first four instructions of each trap handler. The base address of
 101    --  the table is established by supervisor and the displacement, within the
 102    --  table, is determined by the trap type.
 103 
 104    type Trap_Entries_Table is array (Vector_Id) of Trap_Entry;
 105    Trap_Table : Trap_Entries_Table;
 106    pragma Import (Asm, Trap_Table, "trap_table");
 107    --  This is the trap table, that is defined in the crt0 file. This table
 108    --  contains the trap entry for all the traps (synchronous and asynchronous)
 109    --  defined by the SPARC architecture.
 110 
 111    Common_Handler : Address;
 112    pragma Import (Asm, Common_Handler, "common_handler");
 113    --  There is a common part that is executed for every trap. This common
 114    --  handler executes some prologue, then jumps to the user code, and after
 115    --  that executes an epilogue.
 116 
 117    type Vector_Table is array (Vector_Id) of System.Address;
 118    User_Vector_Table : Vector_Table;
 119    pragma Export (Asm, User_Vector_Table, "user_vector_table");
 120    --  In addition to the trap table there is another table that contains the
 121    --  addresses for the trap handlers defined by the user. This is used by
 122    --  the common wrapper to invoke the correct user-defined handler.
 123 
 124    function Get_CCR return System.Address;
 125    pragma Import (Asm, Get_CCR, "get_ccr");
 126    pragma Weak_External (Get_CCR);
 127    --  Get the value from the hardware Cache Control Register.
 128 
 129    procedure GNAT_Error_Handler (Trap : Vector_Id);
 130    --  Trap handler converting synchronous traps to exceptions
 131 
 132    ----------------------------
 133    -- Floating point context --
 134    ----------------------------
 135 
 136    type Thread_Table is array (System.Multiprocessors.CPU) of Thread_Id;
 137    pragma Volatile_Components (Thread_Table);
 138    Float_Latest_User_Table : Thread_Table := (others => Null_Thread_Id);
 139    pragma Export (Asm, Float_Latest_User_Table, "float_latest_user_table");
 140    --  This variable contains the last thread that used the floating point unit
 141    --  for each CPU. Hence, it points to the place where the floating point
 142    --  state must be stored.
 143 
 144    --------------------
 145    -- Context_Switch --
 146    --------------------
 147 
 148    procedure Context_Switch is
 149       procedure Asm_Context_Switch;
 150       pragma Import (Asm, Asm_Context_Switch, "context_switch");
 151    begin
 152       Asm_Context_Switch;
 153    end Context_Switch;
 154 
 155    ------------------------
 156    -- Disable_Interrupts --
 157    ------------------------
 158 
 159    procedure Disable_Interrupts is
 160       procedure Asm_Disable_Interrupts;
 161       pragma Import (Asm, Asm_Disable_Interrupts, "disable_interrupts");
 162    begin
 163       Asm_Disable_Interrupts; -- Replace by inline Asm ???
 164    end Disable_Interrupts;
 165 
 166    -----------------------
 167    -- Enable_Interrupts --
 168    -----------------------
 169 
 170    procedure Enable_Interrupts (Level : Integer) is
 171       procedure Asm_Enable_Interrupts (Level : Natural);
 172       pragma Import (Asm, Asm_Enable_Interrupts, "enable_interrupts");
 173    begin
 174       if Level in Interrupt_Priority then
 175          Asm_Enable_Interrupts (Level - Interrupt_Priority'First + 1);
 176       else
 177          Asm_Enable_Interrupts (0);
 178       end if;
 179    end Enable_Interrupts;
 180 
 181    -----------------
 182    -- Get_Context --
 183    -----------------
 184 
 185    function Get_Context
 186      (Context : Context_Buffer;
 187       Index   : Context_Id) return Word
 188    is
 189    begin
 190       return Word (Context (Index));
 191    end Get_Context;
 192 
 193    ------------------------
 194    -- GNAT_Error_Handler --
 195    ------------------------
 196 
 197    procedure GNAT_Error_Handler (Trap : Vector_Id) is
 198    begin
 199       case Trap is
 200          when Instruction_Access_Exception =>
 201             raise Storage_Error with "instruction access exception";
 202          when Illegal_Instruction =>
 203             raise Constraint_Error with "illegal instruction";
 204          when Address_Not_Aligned =>
 205             raise Constraint_Error with "address not aligned";
 206          when FP_Exception =>
 207             raise Constraint_Error with "floating point exception";
 208          when Data_Access_Exception =>
 209             raise Constraint_Error with "data access exception";
 210          when Instruction_Access_Error =>
 211             raise Constraint_Error with "instruction access exception";
 212          when Data_Access_Error =>
 213             raise Constraint_Error with "data access error";
 214          when Division_By_Zero_Hw | Division_By_Zero_Sw =>
 215             raise Constraint_Error with "division by zero";
 216          when Data_Store_Error =>
 217             raise Constraint_Error with "data store error";
 218          when others =>
 219             raise Program_Error with "unhandled trap";
 220       end case;
 221    end GNAT_Error_Handler;
 222 
 223    ------------------------
 224    -- Initialize_Context --
 225    ------------------------
 226 
 227    procedure Initialize_Context
 228      (Buffer          : not null access Context_Buffer;
 229       Program_Counter : System.Address;
 230       Argument        : System.Address;
 231       Stack_Pointer   : System.Address)
 232    is
 233    begin
 234       --  The stack must be aligned to 16. 96 bytes are needed for storing
 235       --  a whole register window (96 bytes).
 236 
 237       Buffer (SP) :=
 238         SSE.To_Address ((SSE.To_Integer (Stack_Pointer) / 16) * 16 - 96);
 239 
 240       --  Initialize PSR with the state expected by the context switch routine.
 241       --  Floating point unit is disabled. Traps are enabled, although
 242       --  interrupts are disabled (after the context switch only interrupts
 243       --  with a lower priority than the task will be masked). The supervisor
 244       --  and previous supervisor are set to 1 (the system always operates in
 245       --  supervisor mode).
 246 
 247       --  CWP = 0, ET = 1, PS = 1, S = 1, and PIL = 15
 248 
 249       Buffer (PSR) := SSE.To_Address (16#0FE0#);
 250 
 251       --  The WIM is initialized to 2 (corresponding to CWP = 1)
 252 
 253       Buffer (WIM) := SSE.To_Address (2);
 254 
 255       --  The number of windows that must be flushed is initially set to 0
 256       --  (only the current window).
 257 
 258       Buffer (WIN) := SSE.To_Address (0);
 259 
 260       --  Initialize PC with the starting address of the task. Substract 8
 261       --  to compensate the adjustment made in the context switch routine.
 262 
 263       Buffer (PC) := SSE.To_Address (SSE.To_Integer (Program_Counter) - 8);
 264 
 265       --  The argument to be used by the task wrapper function must be
 266       --  passed through the o0 register.
 267 
 268       Buffer (O0) := Argument;
 269 
 270       --  The frame pointer is initialized to be the top of the stack
 271 
 272       declare
 273          FP_In_Stack : System.Address;
 274          for FP_In_Stack'Address use (Buffer (SP) + FP);
 275 
 276       begin
 277          --  Mark the deepest stack frame by setting the frame pointer to zero
 278 
 279          FP_In_Stack := SSE.To_Address (0);
 280       end;
 281 
 282       --  The interrupt nesting level is initialized to 0
 283 
 284       Buffer (INT) := SSE.To_Address (0);
 285 
 286       --  For LEON we initialize the cache control register to its value at
 287       --  initialization time.
 288 
 289       Buffer (CCR) :=
 290         (if Get_CCR'Address = Null_Address then Null_Address else Get_CCR);
 291       Buffer (Base_CCR) := Buffer (CCR);
 292 
 293       --  The rest of registers do not need to be initialized
 294 
 295    end Initialize_Context;
 296 
 297    --------------------
 298    -- Initialize_CPU --
 299    --------------------
 300 
 301    procedure Initialize_CPU is
 302       procedure Asm_Initialize_Floating_Point;
 303       pragma Import (Asm, Asm_Initialize_Floating_Point,
 304                      "initialize_floating_point");
 305    begin
 306       Asm_Initialize_Floating_Point; --  Do in Ada???
 307    end Initialize_CPU;
 308 
 309    ----------------------------
 310    -- Install_Error_Handlers --
 311    ----------------------------
 312 
 313    procedure Install_Error_Handlers is
 314       --  Set up trap handler to map synchronous signals to appropriate
 315       --  exceptions. Make sure that the handler isn't interrupted by
 316       --  another signal that might cause a scheduling event.
 317 
 318    begin
 319       --  The division by zero trap may be either a hardware trap (trap type
 320       --  16#2A#) when the integer division istruction is used (on SPARC V8 and
 321       --  later) or a software trap (trap type 16#82#) caused by the software
 322       --  division implementation in libgcc.
 323 
 324       for J in Vector_Id'Range loop
 325          if J in Instruction_Access_Exception
 326              | Illegal_Instruction | Address_Not_Aligned | FP_Exception
 327              | Data_Access_Exception | Instruction_Access_Error
 328              | Data_Access_Error | Division_By_Zero_Hw | Division_By_Zero_Sw
 329              | Data_Store_Error
 330          then
 331             Install_Trap_Handler (GNAT_Error_Handler'Address, J);
 332          end if;
 333       end loop;
 334    end Install_Error_Handlers;
 335 
 336    --------------------------
 337    -- Install_Trap_Handler --
 338    --------------------------
 339 
 340    procedure Install_Trap_Handler
 341      (Service_Routine : Address;
 342       Vector          : Vector_Id;
 343       Synchronous     : Boolean := False) is separate;
 344 
 345    -----------------
 346    -- Set_Context --
 347    -----------------
 348 
 349    procedure Set_Context
 350      (Context : in out Context_Buffer;
 351       Index   : Context_Id;
 352       Value   : Word)
 353    is
 354    begin
 355       Context (Index) := Address (Value);
 356    end Set_Context;
 357 
 358 end System.BB.CPU_Primitives;