comp.lang.ada
 help / color / mirror / Atom feed
* DOS interrupts with GNAT 3.04
@ 1996-12-21  0:00 Rich Maggio
  1996-12-23  0:00 ` Gautier
  0 siblings, 1 reply; 8+ messages in thread
From: Rich Maggio @ 1996-12-21  0:00 UTC (permalink / raw)



I am wondering if there are any provisions (aside from interfacing to another 
programming language) in this Ada compiler to access the software interrupts
in DOS.  The reason is this: by doing this, it would be very simple to put 
together a package to perform nice screen output - cursor positioning, 
character attributes, etc.  As a C programmer, I made it a habit not to rely
on libraries provided by the compiler for this since this leads to non protable
code.  I would like to do the same with my Ada code.  I know that you can interface
Ada with code written in other programming languages, but that would seem to 
me to be a last resort.  If I am primarily (hypothetical) an Ada programmer,
why should I have to resort to C?  

The reason that I ask this is that I was poking around some of the ADS files 
and found that there are provisions to create interrupts handlers.  Since
there is support for this, I thought that there must be support for 
the reverse - generating interrupts (software or otherwise).

One creative idea that I saw (in Michael Feldman's Ada 95 book) was to make
use of "escape sequences" that would be caught by ANSI.SYS and perform
screen positioning and such.  This is good for screen I/O stuff, but there are
many other services in DOS that can be accessed through the software interrupt
mechanism.

On the same note, is it possible to create the equivalent of a FAR pointer
to interface directly to regions in memory - for example video RAM?

Any input would be welcomed.  I realize that these questions are not specific
the the Ada language itself, but these are real world situations that many
Ada programmers (novice and experienced) must face.  I am just trying to get a 
feel for what the capabilities of GNAT are and what the "Ada way" is for certain
situations. 

Thanks in advance for your help.

Rich Maggio





^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: DOS interrupts with GNAT 3.04
  1996-12-21  0:00 DOS interrupts with GNAT 3.04 Rich Maggio
@ 1996-12-23  0:00 ` Gautier
  1996-12-24  0:00   ` Robert Dewar
  1996-12-24  0:00   ` Michael F Brenner
  0 siblings, 2 replies; 8+ messages in thread
From: Gautier @ 1996-12-23  0:00 UTC (permalink / raw)



In article <E2qt4t.KAx@nonexistent.com>, 
Rich Maggio <maggior@world2u.com> writes:
> I am wondering if there are any provisions (aside from interfacing to another 
> programming language) in this Ada compiler to access the software interrupts
> in DOS.  The reason is this: by doing this, it would be very simple to put 
> together a package to perform nice screen output - cursor positioning, 
> character attributes, etc.
>...
> 
> Thanks in advance for your help.
> 
> Rich Maggio
>
The interface with DOS interruptions is done in a package (DJGPP_Library if I
remember well) of the vga-pack (EZ2LOAD). I've played with it some time ago
for mouse and screen interruptions. Browse the archives PAQS and TESTS at

    http://www.unine.ch/math/Personnel/Assistants/Gautier/Gaut_FTP.htm
                         
Gautier
 




^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: DOS interrupts with GNAT 3.04
  1996-12-23  0:00 ` Gautier
@ 1996-12-24  0:00   ` Robert Dewar
  1996-12-25  0:00     ` Jerry van Dijk
  1996-12-24  0:00   ` Michael F Brenner
  1 sibling, 1 reply; 8+ messages in thread
From: Robert Dewar @ 1996-12-24  0:00 UTC (permalink / raw)



"Rich Maggio <maggior@world2u.com> writes:
> I am wondering if there are any provisions (aside from interfacing to another
> programming language) in this Ada compiler to access the software interrupts
> in DOS.  The reason is this: by doing this, it would be very simple to put
> together a package to perform nice screen output - cursor positioning,
> character attributes, etc."


The best way to put together a package like that would be to generate
the necessary int sequences directly using package Machine_Code. Of course
this is only done once in the body of the package.





^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: DOS interrupts with GNAT 3.04
  1996-12-23  0:00 ` Gautier
  1996-12-24  0:00   ` Robert Dewar
@ 1996-12-24  0:00   ` Michael F Brenner
  1996-12-25  0:00     ` Jerry van Dijk
  1 sibling, 1 reply; 8+ messages in thread
From: Michael F Brenner @ 1996-12-24  0:00 UTC (permalink / raw)



Dos interrupts are done a little differently on several different compilers.
On Janus and Meridian they are provided. On Alsys only the interrupts which
did not pass an address were provided, otherwise you need access to assembly
code. On gnat the following code seems to work, and is subject to the Ada
modification to the Gnu GPPL which permits commercial companies to use it
but not change its free stataus:


with unsign;
package memory is
  use unsign;

  -- Memory:
  --
  -- Purpose:
  --    Provide physical memory access
  --
  -- Architecture:
  --   ADO (Abstract Data Object)
  --   SDS (Semantically Dependent Specification)
  --
  -- History
  --   1986-09-17 added pragma inline (put) which cut the drawing time for
  --   1986-09-17   the SV PCX 2%, from 36 down to 35 seconds.
  --   1986-02-25 created

  type addresses is new unsigned_32;
  type byte_arrays is array (addresses range <>) of unsigned_8;

  procedure put (address: addresses; data: in unsigned_8);
  procedure put (address: addresses; data: in unsigned_16);
  procedure put (address: addresses; data: in unsigned_32);
  procedure put (address: addresses; data: in byte_arrays);
  procedure put (address: addresses; data: in string);

  procedure get (address: addresses; data: out unsigned_8);
  procedure get (address: addresses; data: out unsigned_16);
  procedure get (address: addresses; data: out unsigned_32);
  procedure get (address: addresses; length: addresses; data: out byte_arrays);

  function  get (address: addresses) return unsigned_8;
  function  get (address: addresses) return unsigned_16;
  function  get (address: addresses) return unsigned_32;
  function  get (address: addresses; length: addresses)
    return byte_arrays;
  function  get (address: addresses; length: addresses)
    return string;
  pragma inline (put);
end memory;
with unsign;
package dos16bit is

  -- These objects and methods are common to all 16-bit and and 32-bit DOSs.
  -- They comprise all DOS calls that do not pass addresses or 32-bit lengths.
  -- DOS16bit is complemented by dos_utils which differs for each compiler.
  --
  -- Warning: DOS and Unix are not thread-safe for memory allocation, I/O, etc.
  -- Warning: DOS blocks on all I/O, Unix blocks on most I/O.
  -- Warning: DOS is not even re-entrant, as some Unixen are


  procedure init; -- not to be used by Alsys to avoid random reboots


  -- DOS SYSTEM CALLS

  DOS_interrupt: constant := 16#21#;

  type interrupts is range 0..255;
  for interrupts'size use 8;

  subtype register_data is unsign.unsigned_16;
  type registers_16 is record

    -- Half of the 16-bit and 32-bit DOS calls (those that do not pass
    -- addresses  or 32-bit lengths) can use the simplified registers
    -- (registers_16) to do their work. These DOS calls are identical
    -- across 16- and 32-bit systems.

    ax, bx, cx, dx, flags: register_data := 0;
  end record;

  procedure interrupt_16 (interrupt: interrupts; 
                          register: in out registers_16);

        -- flags is used in many DOS calls as an error indicator:
        -- flags bit 0: carry
        -- flags bit 2: parity
        -- flags bit 6: zero
        -- flags bit 7: sign

  type dos_error_numbers is range -2**15..2**15-1;

  function  command_line           return string; -- not to be used by Alsys
  function  error                  return dos_error_numbers;
  function  error_interpretation   return string;

end dos16bit;

with dos_utils;
with memory;
package body dos16bit is
  -- compiler_this_package_is_dependent_on: constant string := "any DOS";



  -- GLOBAL VARIABLES

  cmd_line:            string (1..255);
  cmd_line_length:     integer := 0;
  initialized:         boolean:=False;
  x:                   constant string (1..2):=ascii.nul & '$';
  interrupt_62_failed: exception;
  why_are_you_calling_dos16bit_Instead_Of_os_command_Line: exception;


  function odd (number: register_data) return boolean is
    use unsign;
  begin
    return (number and 1) = 1;
  end odd;

  -- INTERRUPTS

  procedure get_original_command_line is

    -- WARNING: not to be called by Alsys
    -- WARNING: not to be called twice

    use memory;
    use unsign;
    DOS_get_psp:      constant := 16#6200#;
    sixteen:          constant := 16#10#;
    offset_to_length: constant := 16#80#;
    reg:    dos16bit.registers_16;
    psp:    memory.addresses;
    length: unsigned_8;
    byte:   unsigned_8;
    char:   character;
    j:      natural := 1;
  begin
    if initialized then
      raise interrupt_62_failed;
    end if;
    reg.ax      := DOS_get_PSP;
    dos16bit.interrupt_16 (16#21#, reg);
    if (reg.flags and 1)=1 then
      raise interrupt_62_failed;
    end if;
    psp         := addresses (reg.bx) * sixteen;
    length      := memory.get (psp + offset_to_length);
    cmd_line_length := natural(length);
    for i in 1 .. cmd_line_length loop
      byte := memory.get (psp+offset_to_length+addresses(i));
      char := character'val (byte);
      cmd_line (i) := char;
    end loop;
    loop
      exit when j > cmd_line_length;
      exit when cmd_line(j) /= ' ';
      j:=j+1;
    end loop;
    if j>1 then
      for i in j..cmd_line_length loop
        cmd_line (i+1-j) := cmd_line (i);
      end loop;
      cmd_line_length := cmd_line_length+1-j;
    end if;
  end get_original_command_line;

  function command_line return string is
  begin
    if not initialized then
      raise why_are_you_calling_dos16bit_Instead_Of_os_command_Line;
    end if;
    return cmd_line (1..cmd_line_length);
  end command_line;

  function error return dos_error_numbers is
    reg: registers_16;
    dos_get_error: constant := 16#5900#;
  begin
    reg.ax := dos_get_error;
    reg.bx := 0;
    interrupt_16 (interrupt => DOS_interrupt, register => reg);
    return dos_error_numbers (reg.ax);
  end error;

  function error_interpretation return string is

    bh, bl, ch: register_data;
    reg: registers_16;

    type classes is (non_recognized_error,
                     non_available_resource,  busy_network,
                     wrong_password,          dos_failure,
                     hardware_failure,        bad_dos_system_file,
                     programmer_inserted_bug, missing_object,
                     wrong_control_block,     locked_item,
                     bad_spot_on_media,       duplicate_file,
                     surprize);

    type locuses is (plenum,
                     computer_somewhere,      block_device_driver,
                     network,                 character_device_driver,
                     memory,                  new_dos_feature);

    type errors  is (no_error,
                     bad_function,      file_not_found,     path_not_found,
                     file_too_many,     denied_access,      bad_handle,
                     memory_overwrite,  lack_of_memory,     bad_address,
                     bad_environment,   bad_format,         datum_bad,
                     bad_drive,         delete_current_dir, dissimilar_device,
                     file_no_more,      write_protect,      unit_unknown,
                     drive_not_ready,   command_unknown,    data_CRC_error,
                     bad_length,        seek_error,         medium_unknown,
                     sector_not_found,  printer_outa_paper, write_fault,
                     read_fault,        general_failure,    sharing_violation,
                     lock_violation,    sudden_disk_change,
                     hard_to_describe_file_error);

    type actions is (take_no_action,
                     retry_now,               retry_after_a_delay,
                     fix_the_incorrect_name,  terminate_after_cleanup,
                     abort_without_cleanup,   ignore_and_investigate_later,
                     make_it_available_now,   call_a_hacker);

    dos_get_error: constant := 16#5900#;
  begin
    reg.ax := dos_get_error;
    reg.bx := 0;
    interrupt_16 (interrupt => DOS_interrupt, register => reg);

    if natural (reg.ax)=0 then
      return ""; --No error to interpret
    end if;
    if natural (reg.ax) > errors'pos(errors'last) then
      reg.ax := errors'pos(errors'last);
    end if;

    bh := register_data (natural (reg.bx) / 256);
    if natural (bh) > natural (classes'pos(classes'last)) then
      bh := classes'pos(classes'last);
    end if;
    bl := register_data (natural (reg.bx) mod 256);
    if natural (bl) > actions'pos(actions'last) then
      bl := actions'pos(actions'last);
    end if;

    ch := register_data (natural (reg.cx) / 256);
    if natural (ch)>locuses'pos(locuses'last) then
      ch := locuses'pos(locuses'last);
    end if;

    return ascii.cr & ascii.lf                &
           "Error "                           &
           register_data'image(reg.ax)        &
           " occurred because a "             &
           classes'image(classes'val(bh))     &
           " in the "                         &
           locuses'image (locuses'val (ch))   &
           ascii.cr & ascii.lf                &
           " had a "                          &
           errors'image (errors'val (reg.ax)) &
           ". Your best hope is to "          &
           actions'image (actions'val (bl))   &
           ascii.cr & ascii.lf;
  end error_interpretation;

  procedure interrupt_16 (interrupt: interrupts;
                          register: in out registers_16) is
  begin
    dos_utils.interrupt_16 (interrupt, register);
  end interrupt_16;



  -- SYSTEM CALLS

  procedure init is
  begin
    if not initialized then
      get_original_command_line;
    end if;
    initialized:=True;
  end init;



end dos16bit;
with dos16bit;
with system;
package DOS_utils is

  --  DOS_utils: Gnat Version
  --
  --  Purpose:
  --     Provide interface to 80x86 software interrupts
  --
  --  Architecture:
  --    ADO (Abstract Data Object)
  --    SIS (Semantically Dependent Specification)

  subtype interrupts is dos16bit.interrupts;

  procedure interrupt_16 (interrupt: interrupts;
                          register:  in out dos16bit.registers_16);

  type register_data is mod 2**32;
  type short_register_data is mod 2**16;
  type flag_data is mod 2**8;
  type registers is record
    di, si, bp, cflag, bx, dx, cx, ax: register_data := 0;
    flags: flag_data := 0;
  end record; -- This register order is for gnat3.05 (djgpp 2.0)

  procedure interrupt (interrupt: interrupts; register: in out registers);
end DOS_utils;
with System.Storage_Elements;
package body DOS_utils is

  -- compiler_this_package_is_dependent_on: constant string := "gnat3";

  procedure os_interrupt (interrupt: interrupts;
                          register:  system.address;
                          results:   system.address);
  pragma Import (C, os_interrupt, "int86");

  procedure interrupt_16 (interrupt: interrupts;
                          register:  in out dos16bit.registers_16) is
    reg: registers;
  begin
    reg.ax := register_data (register.ax);
    reg.bx := register_data (register.bx);
    reg.cx := register_data (register.cx);
    reg.dx := register_data (register.dx);
    os_interrupt (interrupt, reg'address, reg'address);
    register.ax    := dos16bit.register_data (reg.ax);
    register.bx    := dos16bit.register_data (reg.bx);
    register.cx    := dos16bit.register_data (reg.cx);
    register.dx    := dos16bit.register_data (reg.dx);
    register.flags := dos16bit.register_data (reg.flags);
  end interrupt_16;

  procedure interrupt (interrupt: interrupts; register: in out registers) is
  begin
    os_interrupt (interrupt, register'address, register'address);
  end interrupt;

end DOS_utils;




^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: DOS interrupts with GNAT 3.04
  1996-12-24  0:00   ` Robert Dewar
@ 1996-12-25  0:00     ` Jerry van Dijk
  1996-12-25  0:00       ` Robert Dewar
  1996-12-25  0:00       ` Robert Dewar
  0 siblings, 2 replies; 8+ messages in thread
From: Jerry van Dijk @ 1996-12-25  0:00 UTC (permalink / raw)



Robert Dewar <dewar@merv.cs.nyu.edu> wrote in article
<dewar.851440688@merv>...

> > I am wondering if there are any provisions (aside from interfacing to
another
> > programming language) in this Ada compiler to access the software
interrupts
> > in DOS.

> The best way to put together a package like that would be to generate
> the necessary int sequences directly using package Machine_Code. Of
course
> this is only done once in the body of the package.

Hmmmm, I didn't know 3.04 for DOS supported Machine_Code...

But even the I wouldn't recommend doing it this way. On a 16-bit real-mode 
compiler, this would be easy.. On a 32-bit protected mode compile (&
runtime)
your code would also have to handle the mode switches (RM<->PM), transfer,
callbacks, etc.

Better use the existing DJGPP code.

As far as fast character I/O under DOS is concerned, If someone has some
server
space left, I have some usefull packages...

Merry Christmas!
Jerry.





^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: DOS interrupts with GNAT 3.04
  1996-12-24  0:00   ` Michael F Brenner
@ 1996-12-25  0:00     ` Jerry van Dijk
  0 siblings, 0 replies; 8+ messages in thread
From: Jerry van Dijk @ 1996-12-25  0:00 UTC (permalink / raw)




>   procedure interrupt_16 (interrupt: interrupts;
>                           register:  in out dos16bit.registers_16) is
>     reg: registers;

As DJ  and other warned several times:

1) This 16-bit Borland interface supports only a limited number of DOS
calls, which
    ones is not documented.
2) BIOS and other interrupt calls are not possible
3) These functions are *unsupported* and will disappear in the next DJGPP
    distribution.

Here's an example that shows some reliable techniques to access DOS from
the
GNAT/DJGPP enviroment:

-- Demonstrates how to call a dos interrupt with GNAT 3.05

with Interfaces;   use Interfaces;
with Interfaces.C; use Interfaces.C;

procedure Demo is

   -- Raised if the conventional memory transfer buffer is too small
   Transfer_Buffer_Too_Small : exception;

   -- Defines the DPMI available processor registers.
   -- Note: one of several possible definitions
   type Dpmi_Regs is
      record
         Di     : Unsigned_16;
         Di_Hi  : Unsigned_16;
         Si     : Unsigned_16;
         Si_Hi  : Unsigned_16;
         Bp     : Unsigned_16;
         Bp_Hi  : Unsigned_16;
         Res    : Unsigned_16;
         Res_Hi : Unsigned_16;
         Bx     : Unsigned_16;
         Bx_Hi  : Unsigned_16;
         Dx     : Unsigned_16;
         Dx_Hi  : Unsigned_16;
         Cx     : Unsigned_16;
         Cx_Hi  : Unsigned_16;
         Ax     : Unsigned_16;
         Ax_Hi  : Unsigned_16;
         Flags  : Unsigned_16;
         Es     : Unsigned_16;
         Ds     : Unsigned_16;
         Fs     : Unsigned_16;
         Gs     : Unsigned_16;
         Ip     : Unsigned_16;
         Cs     : Unsigned_16;
         Sp     : Unsigned_16;
         Ss     : Unsigned_16;
      end record;
   pragma Convention (C, Dpmi_Regs);

   -- Make DPMI issue a real mode interrupt
   procedure Dpmi_Int (Vector : in Unsigned_16; Regs : in out Dpmi_Regs);
   pragma Import (C, Dpmi_Int, "__dpmi_int");

   -- Defines the dos extender info block
   type Go32_Info_Block is
      record
         Size_Of_This_Structure_In_Bytes        : Unsigned_32;
         Linear_Address_Of_Primary_Screen       : Unsigned_32;
         Linear_Address_Of_Secondary_Screen     : Unsigned_32;
         Linear_Address_Of_Transfer_Buffer      : Unsigned_32;
         Size_Of_Transfer_Buffer                : Unsigned_32;
         Pid                                    : Unsigned_32;
         Master_Interrupt_Controller_Base       : Unsigned_8;
         Slave_Interrupt_Controller_Base        : Unsigned_8;
         Selector_For_Linear_Memory             : Unsigned_16;
         Linear_Address_Of_Stub_Info_Structure  : Unsigned_32;
         Linear_Address_Of_Original_Psp         : Unsigned_32;
         Run_Mode                               : Unsigned_16;
         Run_Mode_Info                          : Unsigned_16;
      end record;
   pragma Convention (C, Go32_Info_Block);

   -- Make the current extender info available within Ada
   Current_Info : Go32_Info_Block;
   pragma Import (C, Current_Info, "_go32_info_block");

   -- Procedure to copy data to conventional memory
   procedure Dosmemput (Buffer  : in char_array;
                        Length  : in Unsigned_32;
                        Fysical : in Unsigned_32);
   pragma Import (C, Dosmemput, "dosmemput");

   procedure DOS_Print(Str : in String) is

      -- The DOS formatted string (note the zero)
      DOS_String : char_array(0..Str'Length);

      -- The processor registers
      Regs : Dpmi_Regs;

   begin

      -- Translate the string to a DOS string by appending
      -- the '$' that DOS uses to mark the end of the string
      for I in Str'Range loop
         DOS_String (size_t (I-1)) := To_C ( Str (I));
      end loop;
      DOS_String (size_t (Str'Length)) := To_C ('$');

      -- Check that the djgpp conventional memory transfer buffer is
      -- large enough to hold our string. If not, raise an exception.
      -- Normally we would either enlarge the transfer buffer or allocate
      -- our own. Here we leave this as an exercise for the reader :-)
      if Current_Info.Linear_Address_Of_Transfer_Buffer < Str'Length + 1
then
         raise Transfer_Buffer_Too_Small;
      end if;

      -- Next, copy our string to the transfer buffer
      Dosmemput (DOS_String, Str'Length + 1,
        Current_Info.Linear_Address_Of_Transfer_Buffer);

      -- Now, tell dos to print the contents of the transfer buffer
      Regs.Ax := 16#0900#;

      -- Make Ds point to the segment part of the physical address
      Regs.Ds := Unsigned_16( Shift_Right(
        Current_Info.Linear_Address_Of_Transfer_Buffer, 4)) and 16#FFFF#;

      -- Make Dx point to the offset part of the physical address
      Regs.Dx := Unsigned_16(
        Current_Info.Linear_Address_Of_Transfer_Buffer) and 16#0F#;

      -- Issue the interrupt
      Dpmi_Int (16#21#, Regs);

   end DOS_Print;

begin
   DOS_Print("Hello, world!");
end Demo;

Jerry.





^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: DOS interrupts with GNAT 3.04
  1996-12-25  0:00     ` Jerry van Dijk
@ 1996-12-25  0:00       ` Robert Dewar
  1996-12-25  0:00       ` Robert Dewar
  1 sibling, 0 replies; 8+ messages in thread
From: Robert Dewar @ 1996-12-25  0:00 UTC (permalink / raw)



Jerry said

"Hmmmm, I didn't know 3.04 for DOS supported Machine_Code...

But even the I wouldn't recommend doing it this way. On a 16-bit real-mode
compiler, this would be easy.. On a 32-bit protected mode compile (&
runtime)
your code would also have to handle the mode switches (RM<->PM), transfer,
callbacks, etc.

Better use the existing DJGPP code."


Machine_Code is not supported till version 3.07 (the current public release
of the DOS version is 3.05, we hope to see a 3.07 in the near future, we
are working on it right now).





^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: DOS interrupts with GNAT 3.04
  1996-12-25  0:00     ` Jerry van Dijk
  1996-12-25  0:00       ` Robert Dewar
@ 1996-12-25  0:00       ` Robert Dewar
  1 sibling, 0 replies; 8+ messages in thread
From: Robert Dewar @ 1996-12-25  0:00 UTC (permalink / raw)



iJerry said

"But even the I wouldn't recommend doing it this way. On a 16-bit real-mode
compiler, this would be easy.. On a 32-bit protected mode compile (&
runtime)
your code would also have to handle the mode switches (RM<->PM), transfer,
callbacks, etc.

Better use the existing DJGPP code."


I agree, much better to use the existing routines. What would be nice
is a complete Ada 95 interface to the useful DJGPP routines.





^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~1996-12-25  0:00 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
1996-12-21  0:00 DOS interrupts with GNAT 3.04 Rich Maggio
1996-12-23  0:00 ` Gautier
1996-12-24  0:00   ` Robert Dewar
1996-12-25  0:00     ` Jerry van Dijk
1996-12-25  0:00       ` Robert Dewar
1996-12-25  0:00       ` Robert Dewar
1996-12-24  0:00   ` Michael F Brenner
1996-12-25  0:00     ` Jerry van Dijk

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox