In the past, I've been doing the same for a x86 toy OS called Lovelace OS.
The spec:
-- Lovelace Operating System - An Unix Like Ada'Based Operating system
-- Copyright (C) 2013-2014 Xavier GRAVE, Frederic BOYER
-- This program is free software: you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
-- You should have received a copy of the GNU General Public License
-- along with this program. If not, see <
http://www.gnu.org/licenses/>.
pragma Suppress (All_Checks);
with System;
with System.Storage_Elements;
procedure Oasys.Memset (Destination : in System.Address;
Value : in System.Storage_Elements.Storage_Element;
Count : in System.Storage_Elements.Storage_Count);
pragma Pure (Memset);
pragma Export (C, Memset, "memset");
Then the body for the x86-32 part
-- Lovelace Operating System - An Unix Like Ada'Based Operating system
-- Copyright (C) 2013-2014 Xavier GRAVE, Frederic BOYER
-- This program is free software: you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
-- You should have received a copy of the GNU General Public License
-- along with this program. If not, see <
http://www.gnu.org/licenses/>.
with System.Storage_Elements; use System.Storage_Elements;
with Oasys.Debug;
procedure Oasys.Memset (Destination : in System.Address;
Value : in Storage_Element;
Count : in Storage_Count) is
pragma Suppress (All_Checks);
-- Storage_unit zones
Byte_Zone_Destination : Storage_Array (1 .. Count);
for Byte_Zone_Destination'Address use Destination;
Offset : Storage_Offset := 0;
Number_Of_Bytes_To_Write : Storage_Count := Count;
-- CPU width (ie 32 or 64 bits) in bytes
Full_Width : constant := System.Word_Size / System.Storage_Unit;
begin
-- see
http://www.noxeos.com/2013/08/06/code-optimisations/
-- Algo
-- offset = 0
-- while destination + offset is not aligned,
-- set the byte to value and add 1 to offset
-- decrease count of elements to set
while ((Destination + Offset) mod Full_Width /= 0) loop
-- Warning ! We use offset + 1 for indexing the array
-- because offset starts at 0 and arrays to 1
Byte_Zone_Destination (Offset + 1) := Value;
Offset := Offset + 1;
Number_Of_Bytes_To_Write := Number_Of_Bytes_To_Write - 1;
end loop;
declare
-- Number of word zones
Number_Of_Zones : constant Natural := Natural (Number_Of_Bytes_To_Write) / Full_Width;
type Word is mod 2**System.Word_Size;
-- word long zones
type Long_Word_Zone_Array is array (1 .. Number_Of_Zones) of Word;
Zone_Destination : Long_Word_Zone_Array;
for Zone_Destination'Address use (Destination + Offset);
Remaining_Bytes : constant Natural := Natural (Number_Of_Bytes_To_Write) rem Full_Width;
Long_Value : Word := 0;
Power : Natural := 0;
begin
-- Creating the long value
while Power < System.Word_Size loop
Oasys.Debug.Put_String ("Long value " & Word'Image (Long_Value));
Oasys.Debug.New_Line;
Oasys.Debug.Put_String ("Power = " & Natural'Image (Power));
Oasys.Debug.New_Line;
Oasys.Debug.Put_String ("Value shifted = " & Word'Image (Word (Value) * 2**Power));
Oasys.Debug.New_Line;
Long_Value := Long_Value + Word (Value) * 2**Power;
Power := Power + System.Storage_Unit;
end loop;
Oasys.Debug.Put_String ("Long value " & Word'Image (Long_Value));
Oasys.Debug.New_Line;
-- As we are aligned,
-- find how many aligned word we have
-- build an array from (destination + last_offset) to last aligned count
-- This way, we use the full width of the CPU
for Index in Zone_Destination'Range loop
Zone_Destination (Index) := Long_Value;
Offset := Offset + Full_Width;
end loop;
-- If there are still small bytes to change
if (Remaining_Bytes /= 0) then
-- For the same reason as above, we add one to Offset
for Index in Offset - 1 .. Byte_Zone_Destination'Last loop
Byte_Zone_Destination (Index) := Value;
end loop;
end if;
end;
end Oasys.Memset;
For what it's worth ;)