212 lines
6.3 KiB
Plaintext
212 lines
6.3 KiB
Plaintext
|
--
|
|||
|
-- MEMORY.ADA
|
|||
|
--
|
|||
|
-- Memory management package for Artek Ada
|
|||
|
--
|
|||
|
-- Copyright (C) 1986 Artek Corporation
|
|||
|
-- Author: V. Thorsteinsson
|
|||
|
--
|
|||
|
-- This generic package enables users of Artek Ada to access all
|
|||
|
-- 640 Kb of available memory under DOS.
|
|||
|
--
|
|||
|
-- It is implemented as a set of five operations:
|
|||
|
-- ALLOCATE, DEALLOCATE, MODIFY_ALLOCATION, READ, and WRITE.
|
|||
|
-- The allocated memory is modeled as an array (indexed from 0)
|
|||
|
-- of the generic type DATA. Elements of the array may be written
|
|||
|
-- or read using the READ and WRITE operations. The size
|
|||
|
-- of the array may be set using ALLOCATE and the memory used
|
|||
|
-- by the array can be freed with DEALLOCATE. If the user
|
|||
|
-- wishes to modify the size of an already allocated array,
|
|||
|
-- he should use the MODIFY_ALLOCATION procedure. This will
|
|||
|
-- preserve the memory contents up to the latest original element
|
|||
|
-- or the latest new element, whichever is lower in memory.
|
|||
|
-- Any error in usage causes a MEMORY_ERROR exception to be
|
|||
|
-- raised.
|
|||
|
--
|
|||
|
-- Example of usage:
|
|||
|
--
|
|||
|
-- with TEXT_IO; use TEXT_IO;
|
|||
|
-- procedure MEMORY_DEMO is
|
|||
|
--
|
|||
|
-- type SYMBOL is record
|
|||
|
-- IDENTIFIER : STRING (1..32);
|
|||
|
-- SYMTYPE : (OBJECT, PROGRAM, LABEL);
|
|||
|
-- CONTENTS : INTEGER;
|
|||
|
-- end record;
|
|||
|
--
|
|||
|
-- package SYMTABLE is new MEMORY (SYMBOL);
|
|||
|
--
|
|||
|
-- S : SYMBOL;
|
|||
|
--
|
|||
|
-- begin
|
|||
|
-- SYMTABLE.ALLOCATE (2000); -- This allocates about 70K of data
|
|||
|
-- S . IDENTIFIER := "IDENTIFIER ";
|
|||
|
-- S . SYMTYPE := PROGRAM;
|
|||
|
-- for I in 0..1999 loop -- NOTE: not 1 to 2000!
|
|||
|
-- S . CONTENTS := I;
|
|||
|
-- SYMTABLE.WRITE (I, S); -- Write S into array element I
|
|||
|
-- end loop;
|
|||
|
-- SYMTABLE.READ (1555, S); -- Read S from array element 1555
|
|||
|
-- SYMTABLE.DEALLOCATE;
|
|||
|
-- PUT_LINE (INTEGER'IMAGE (S . CONTENTS)); -- Should write 1555
|
|||
|
-- exception
|
|||
|
-- when MEMORY_ERROR =>
|
|||
|
-- PUT_LINE ("Error while working with MEMORY package");
|
|||
|
-- end MEMORY_DEMO;
|
|||
|
--
|
|||
|
|
|||
|
with SYSTEM; use SYSTEM;
|
|||
|
|
|||
|
generic
|
|||
|
type DATA is private;
|
|||
|
package MEMORY is
|
|||
|
procedure ALLOCATE (NUMBER_OF_ELEMENTS : in POSITIVE);
|
|||
|
procedure DEALLOCATE;
|
|||
|
procedure MODIFY_ALLOCATION (NUMBER_OF_ELEMENTS : in POSITIVE);
|
|||
|
procedure READ (NUMBER_OF_ELEMENT : in NATURAL; ELEMENT : out DATA);
|
|||
|
procedure WRITE (NUMBER_OF_ELEMENT : in NATURAL; ELEMENT : in DATA);
|
|||
|
MEMORY_ERROR : exception;
|
|||
|
end MEMORY;
|
|||
|
|
|||
|
with DOS_INTERFACE; use DOS_INTERFACE;
|
|||
|
with LONG_OPERATIONS; use LONG_OPERATIONS;
|
|||
|
with SYSTEM;
|
|||
|
|
|||
|
package body MEMORY is
|
|||
|
|
|||
|
use SYSTEM;
|
|||
|
|
|||
|
type LONG_PTR is record
|
|||
|
OFF : WORD;
|
|||
|
SEG : WORD;
|
|||
|
end record;
|
|||
|
|
|||
|
subtype SEGMENT is WORD;
|
|||
|
|
|||
|
NIL : constant SEGMENT := 0;
|
|||
|
ELEMENT_SIZE : constant INTEGER := DATA'SIZE / STORAGE_UNIT;
|
|||
|
|
|||
|
BASE : SEGMENT := NIL;
|
|||
|
POOLSIZE : NATURAL := 0;
|
|||
|
|
|||
|
R : REG_8086;
|
|||
|
|
|||
|
function DOS_ALLOCATE (SIZE : INTEGER) return SEGMENT is
|
|||
|
begin
|
|||
|
R . AX := 16#4800#;
|
|||
|
R . BX := WORD (SIZE);
|
|||
|
CALL_DOS (R);
|
|||
|
if R . FLAGS mod 2 = 1 then -- Carry set
|
|||
|
raise MEMORY_ERROR;
|
|||
|
end if;
|
|||
|
return R . AX;
|
|||
|
end;
|
|||
|
|
|||
|
procedure DOS_DEALLOCATE (S : SEGMENT) is
|
|||
|
begin
|
|||
|
R . AX := 16#4900#;
|
|||
|
R . ES := S;
|
|||
|
CALL_DOS (R);
|
|||
|
if R . FLAGS mod 2 = 1 then
|
|||
|
raise MEMORY_ERROR;
|
|||
|
end if;
|
|||
|
end;
|
|||
|
|
|||
|
procedure DOS_MODIFY_ALLOCATION (S : SEGMENT; SIZE : INTEGER) is
|
|||
|
begin
|
|||
|
R . AX := 16#4A00#;
|
|||
|
R . ES := S;
|
|||
|
R . BX := WORD (SIZE);
|
|||
|
CALL_DOS (R);
|
|||
|
if R . FLAGS mod 2 = 1 then
|
|||
|
raise MEMORY_ERROR;
|
|||
|
end if;
|
|||
|
end;
|
|||
|
|
|||
|
procedure ALLOCATE (NUMBER_OF_ELEMENTS : in POSITIVE) is
|
|||
|
|
|||
|
SIZE : LONG_INTEGER;
|
|||
|
|
|||
|
begin
|
|||
|
if BASE /= NIL then
|
|||
|
raise MEMORY_ERROR;
|
|||
|
end if;
|
|||
|
SIZE := SHR (NUMBER_OF_ELEMENTS * ELEMENT_SIZE, 4);
|
|||
|
BASE := DOS_ALLOCATE (SIZE . LOW + 1);
|
|||
|
POOLSIZE := NUMBER_OF_ELEMENTS;
|
|||
|
end ALLOCATE;
|
|||
|
|
|||
|
procedure DEALLOCATE is
|
|||
|
begin
|
|||
|
if BASE = NIL then
|
|||
|
raise MEMORY_ERROR;
|
|||
|
end if;
|
|||
|
DOS_DEALLOCATE (BASE);
|
|||
|
POOLSIZE := 0;
|
|||
|
end DEALLOCATE;
|
|||
|
|
|||
|
procedure MODIFY_ALLOCATION (NUMBER_OF_ELEMENTS : in POSITIVE) is
|
|||
|
|
|||
|
SIZE : LONG_INTEGER;
|
|||
|
|
|||
|
begin
|
|||
|
if BASE = NIL then
|
|||
|
raise MEMORY_ERROR;
|
|||
|
end if;
|
|||
|
SIZE := SHR (NUMBER_OF_ELEMENTS * ELEMENT_SIZE, 4);
|
|||
|
DOS_MODIFY_ALLOCATION (BASE, SIZE . LOW + 1);
|
|||
|
POOLSIZE := NUMBER_OF_ELEMENTS;
|
|||
|
end MODIFY_ALLOCATION;
|
|||
|
|
|||
|
procedure MOVE_SHORT_LONG (FROM : in INTEGER; TO : in LONG_INTEGER; SIZE : in INTEGER) is
|
|||
|
begin
|
|||
|
pragma NATIVE (
|
|||
|
16#55#, 16#06#, 16#8B#, 16#EE#, 16#8B#, 16#76#, 16#00#, 16#8B#,
|
|||
|
16#56#, 16#02#, 16#8B#, 16#FA#, 16#81#, 16#E7#, 16#0F#, 16#00#,
|
|||
|
16#81#, 16#E2#, 16#F0#, 16#FF#, 16#B1#, 16#04#, 16#D3#, 16#EA#,
|
|||
|
16#8B#, 16#46#, 16#04#, 16#B1#, 16#0C#, 16#D3#, 16#E0#, 16#0B#,
|
|||
|
16#C2#, 16#8B#, 16#4E#, 16#06#, 16#8E#, 16#C0#, 16#FC#, 16#F3#,
|
|||
|
16#A4#, 16#07#, 16#5D#);
|
|||
|
null;
|
|||
|
end MOVE_SHORT_LONG;
|
|||
|
|
|||
|
procedure MOVE_LONG_SHORT (FROM : in LONG_INTEGER; TO : in INTEGER; SIZE : in INTEGER) is
|
|||
|
begin
|
|||
|
pragma NATIVE (
|
|||
|
16#1E#, 16#55#, 16#8B#, 16#EE#, 16#8B#, 16#7E#, 16#04#, 16#8B#,
|
|||
|
16#56#, 16#00#, 16#8B#, 16#F2#, 16#81#, 16#E6#, 16#0F#, 16#00#,
|
|||
|
16#81#, 16#E2#, 16#F0#, 16#FF#, 16#B1#, 16#04#, 16#D3#, 16#EA#,
|
|||
|
16#8B#, 16#46#, 16#02#, 16#B1#, 16#0C#, 16#D3#, 16#E0#, 16#0B#,
|
|||
|
16#C2#, 16#8B#, 16#4E#, 16#06#, 16#8E#, 16#D8#, 16#FC#, 16#F3#,
|
|||
|
16#A4#, 16#5D#, 16#1F#);
|
|||
|
null;
|
|||
|
end MOVE_LONG_SHORT;
|
|||
|
|
|||
|
procedure READ (NUMBER_OF_ELEMENT : in NATURAL; ELEMENT : out DATA) is
|
|||
|
|
|||
|
ADDRESS : LONG_INTEGER;
|
|||
|
|
|||
|
begin
|
|||
|
if BASE = NIL or NUMBER_OF_ELEMENT >= POOLSIZE then
|
|||
|
raise MEMORY_ERROR;
|
|||
|
end if;
|
|||
|
ADDRESS := INTEGER (BASE) * 16;
|
|||
|
ADDRESS := NUMBER_OF_ELEMENT * ELEMENT_SIZE + ADDRESS;
|
|||
|
MOVE_LONG_SHORT (ADDRESS, ELEMENT'ADDRESS, ELEMENT_SIZE);
|
|||
|
end READ;
|
|||
|
|
|||
|
procedure WRITE (NUMBER_OF_ELEMENT : in NATURAL; ELEMENT : in DATA) is
|
|||
|
|
|||
|
ADDRESS : LONG_INTEGER;
|
|||
|
|
|||
|
begin
|
|||
|
if BASE = NIL or NUMBER_OF_ELEMENT >= POOLSIZE then
|
|||
|
raise MEMORY_ERROR;
|
|||
|
end if;
|
|||
|
ADDRESS := INTEGER (BASE) * 16;
|
|||
|
ADDRESS := NUMBER_OF_ELEMENT * ELEMENT_SIZE + ADDRESS;
|
|||
|
MOVE_SHORT_LONG (ELEMENT'ADDRESS, ADDRESS, ELEMENT_SIZE);
|
|||
|
end WRITE;
|
|||
|
|
|||
|
end MEMORY;
|
|||
|
|