--
--  Author: Brent Seidel
--  Date: 31-Jul-2024
--
--  This file is part of SimCPU.
--  SimCPU 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.
--
--  SimCPU 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 SimCPU. If not, see <https://www.gnu.org/licenses/>.--
--
--  Contains I/O devices for various kinds of disk
--
with Ada.Direct_IO;
generic
  sector_size : Natural;
  max_drives  : Natural;
package BBS.Sim_CPU.disk is
   --
   --  The floppy disk device object for an 8 bit system.  This simulates an
   --  8 inch floppy with 128 byte sectors, but can be modified for others.
   --
   type disk_ctrl is new io_device with private;
   --
   --  Port useage (base +)
   --    0 - Control port
   --    1 - Sector number
   --    2 - Track number
   --    3 - DMA address LSB
   --    4 - DMA address MSB
   --    5 - Count (number of sectors to read)
   --    6 - Head number (not yet implemented)
   --
   --  Control port bits are:
   --  (write)
   --    7-6 - Action (0 - none, 1 - read, 2 - write, 3 - select disk)
   --    5-4 - Not used
   --    3-0 - Disk number (0-15)
   --  (read)
   --    7 - Offline (set true if drive unavailable or no file attached)
   --    6 - Out of range (track, sector, or head is out of range)
   --    5 - Other error
   --    4 - Unused
   --    3-0 - Disk number (0-15)
   --
   --  Controller configuration constants.  These may eventually move to
   --  be parameters for a generic.
   --
   subtype drive_num is Natural range 0 .. max_drives - 1;
   --
   --  Disk drive geometry
   --
   type geometry is record
      tracks  : byte;     --  Number of tracks on disk
      sectors : byte;     --  Number of sectors per track
      heads   : byte;     --  Number of heads per drive (currently unused)
   end record;
   --
   --  Geometry for 8 inch floppy disk for CP/M.
   --
   floppy8_geom : geometry := (77, 26, 0);
   --
   --  I/O device actions
   --
   --  Write to a port address
   --
   overriding
   procedure write(self : in out disk_ctrl; addr : addr_bus; data : data_bus);
   --
   --  Read from a port address
   --
   overriding
   function read(self : in out disk_ctrl; addr : addr_bus) return data_bus;
   --
   --  How many addresses are used by the port
   --
   overriding
   function getSize(self : in out disk_ctrl) return addr_bus is (6);
   --
   --  Get the base address
   --
   overriding
   function getBase(self : in out disk_ctrl) return addr_bus;
   --
   --  Set the base address
   --
   overriding
   procedure setBase(self : in out disk_ctrl; base : addr_bus);
   --
   --  Set the owner (used mainly for DMA)
   --
   overriding
   procedure setOwner(self : in out disk_ctrl; owner : sim_access);
   --
   --  Get device name/description
   --
   overriding
   function name(self : in out disk_ctrl) return string is ("8 Bit Floppy Disk Controller");
   --
   --  Set which exception to use
   --
   overriding
   procedure setException(self : in out disk_ctrl; except : long) is null;
   --
   --  Open the attached file
   --
   procedure open(self : in out disk_ctrl; drive : drive_num;
     geom : geometry; name : String);
   --
   --  Close the attached file
   --
   procedure close(self : in out disk_ctrl; drive : drive_num);
   --
   --  Read from the selected drive
   --
   procedure read(self : in out disk_ctrl);
   --
   --  write to the selected drive
   --
   procedure write(self : in out disk_ctrl);
   -- -------------------------------------------------------------------------
   --
   --  Definitions for a hard disk controller with 32 bit addressing.
   --  The geomentry of this device is simplified into a simple linear
   --  sequence of blocks.
   --
   --  Port usage (base +)
   --  0 - Command
   --  1 - Status
   --  2 - Value MSB
   --  3 - Value
   --  4 - Value
   --  5 - Value LSB
   --
   --  Commands are:
   --  0 - Do nothing
   --  1 - Set drive
   --  2 - Set starting block
   --  3 - Set block count
   --  4 - Set DMA address
   --  5 - Read data
   --  6 - Write data
   --  7 - Read max drive number
   --  8 - Read max block number
   --  Status bits are
   --  7 - Unused
   --  6 - Unused
   --  5 - Unused
   --  4 - Bad command
   --  3 - Drive out of range
   --  2 - Count out of range
   --  1 - Starting block out of range
   --  0 - Drive out of range
   --
   --  In operation, write the value first and then issue the set command to
   --  set a value.  To read a value, issue a read command, then read the value.
   --
   type hd_ctrl is new io_device with private;
   --
   --
   --  I/O device actions
   --
   --  Write to a port address
   --
   overriding
   procedure write(self : in out hd_ctrl; addr : addr_bus; data : data_bus);
   --
   --  Read from a port address
   --
   overriding
   function read(self : in out hd_ctrl; addr : addr_bus) return data_bus;
   --
   --  How many addresses are used by the port
   --
   overriding
   function getSize(self : in out hd_ctrl) return addr_bus is (6);
   --
   --  Get the base address
   --
   overriding
   function getBase(self : in out hd_ctrl) return addr_bus;
   --
   --  Set the base address
   --
   overriding
   procedure setBase(self : in out hd_ctrl; base : addr_bus);
   --
   --  Set the owner (used mainly for DMA)
   --
   overriding
   procedure setOwner(self : in out hd_ctrl; owner : sim_access);
   --
   --  Get device name/description
   --
   overriding
   function name(self : in out hd_ctrl) return string is ("Mass Storage Controller");
   --
   --  Set which exception to use
   --
   overriding
   procedure setException(self : in out hd_ctrl; except : long);
   --
   --  Open the attached file
   --
   procedure open(self : in out hd_ctrl; drive : drive_num;
     size : Natural; name : String);
   --
   --  Close the attached file
   --
   procedure close(self : in out hd_ctrl; drive : drive_num);
   --
   --  Read from the selected drive
   --
   procedure read(self : in out hd_ctrl) is null;
   --
   --  write to the selected drive
   --
   procedure write(self : in out hd_ctrl) is null;
   -- =========================================================================
private
   --
   --  Types for mass storage device access
   --
   type disk_sector is array (0 .. sector_size - 1) of byte;
   package disk_io is new Ada.Direct_IO(disk_sector);
   -- -------------------------------------------------------------------------
   --
   --  Record for information specific to each disk drive.
   --
   type disk_info is record
      present : Boolean := False;
      geom  : geometry;
      image : disk_io.File_Type;
   end record;
   type info_array is array (drive_num) of disk_info;
   --
   --  Definition of the 8 bit floppy disk controller
   --
   type disk_ctrl is new io_device with record
      selected_drive : drive_num := 0;
      drive_info : info_array;
      sector : byte;
      track  : byte;
      count  : byte := 1;
      dma    : addr_bus;
      host   : BBS.Sim_CPU.sim_access;
   end record;
   -- -------------------------------------------------------------------------
   --
   --  Info for each mass storage device
   --
   type hd_info is record
      present : Boolean := False;
      size  : Natural;
      image : disk_io.File_Type;
   end record;
   --
   --  Array for HD info
   --
   type hd_array is array (drive_num) of hd_info;
   --
   --  Definition for a hard disk controller with 32 bit addressing.
   --
   type hd_ctrl is new io_device with record
      int_code : long;    --  Code to send for interrupts
      t0     : byte;      --  Temp value 0
      t1     : byte;      --  Temp value 1
      t2     : byte;      --  Temp value 2
      t3     : byte;      --  Temp value 3
      status : byte;      --  Status code
--      target : byte;      --  Indicates which value to read/write
      drive  : byte := 0; --  Which disk drive to access
      block  : addr_bus;  --  Which block to read/write
      count  : addr_bus;  --  How many blocks to read/write
      dma    : addr_bus;  --  Memory address to read/write to
      host   : BBS.Sim_CPU.sim_access;
      drive_info : hd_array;
   end record;
end;
