
/*
** VMEM.H - header file for VMEM
**
** Version 0.1 ©1990 by Edward Hutchins
** Based in part on the SetCPU program by Dave Haynie
** Authors:
**
**      Edward Hutchins: eah1@cec1.wustl.edu
**      Loren Rittle: l-rittle@uiuc.edu
**
** Revisions:
** 12/19/91 code released as freeware under the GNU general public license - Ed.
**
**    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 1, 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, write to the Free Software
**    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <exec/types.h>
#include <exec/exec.h>
#include <exec/execbase.h>
#include <exec/tasks.h>
#include <exec/memory.h>
#include <libraries/dos.h>
#include <devices/timer.h>
#include <graphics/gfx.h>
#include <graphics/rastport.h>
#include <intuition/intuition.h>
#include <proto/all.h>

/*
** external declarations for the assembly routines
*/

IMPORT VOID SetCRP (ULONG *);
IMPORT VOID GetCRP (ULONG *);
IMPORT VOID SetTC (ULONG);
IMPORT ULONG GetTC (VOID);
IMPORT VOID SetCACR (ULONG);
IMPORT ULONG GetCACR (VOID);
IMPORT ULONG GetCPUType (VOID);
IMPORT ULONG GetMMUType (VOID);
IMPORT ULONG GetFPUType (VOID);
IMPORT VOID InsertFaultHandler (VOID);

/*
** Define all bit components used for manipulation of the Cache Control
** Register.
*/

#define CACR_INST (1L<<0)
#define CACR_DATA (1L<<8)

#define CACR_WALLOC     5
#define CACR_BURST      4
#define CACR_CLEAR      3
#define CACR_ENTRY      2
#define CACR_FREEZE     1
#define CACR_ENABLE     0

/*
** Define important bits used in various MMU registers.
*/

/*
** Here are the CRP definitions.  The CRP register is 64 bits long, but
** only the first 32 bits are control bits, the next 32 bits provide the
** base address of the table.
*/

#define CRP_UPPER       (1L << 31)                      /*  Upper / lower limit mode    */
#define CRP_LIMIT(x)    ((ULONG) ((x) & 0x7fff) << 16)  /*  Upper / lower limit value   */
#define CRP_SG          (1L << 9)                       /*  Indicates shared space      */
#define CRP_DT_INVALID  0x00                            /*  Invalid root descriptor     */
#define CRP_DT_PAGE     0x01                            /*  Fixed offset, auto-genned   */
#define CRP_DT_V4BYTE   0x02                            /*  Short root descriptor       */
#define CRP_DT_V8BYTE   0x03                            /*  Long root descriptor        */
#define CRP_DT_MASK     0x03

/*
** Here are the TC definitions.  The TC register is 32 bits long.
*/

#define TC_ENB          (1L << 31)                      /*  Enable the MMU              */
#define TC_SRE          (1L << 25)                      /*  For separate Supervisor     */
#define TC_FCL          (1L << 24)                      /*  Use function codes?         */
#define TC_PS(x)        ((ULONG) ((x) & 0x0f) << 20)    /*  Page Size                   */
#define TC_IS(x)        ((ULONG) ((x) & 0x0f) << 16)    /*  Initial Shift               */
#define TC_TIA(x)       ((ULONG) ((x) & 0x0f) << 12)    /*  Table level A index         */
#define TC_TIB(x)       ((ULONG) ((x) & 0x0f) << 8)     /*  Table level B index         */
#define TC_TIC(x)       ((ULONG) ((x) & 0x0f) << 4)     /*  Table level C index         */
#define TC_TID(x)       ((ULONG) ((x) & 0x0f) << 0)     /*  Table level D index         */

/*
** Here are the page descriptor definitions, for short descriptors only,
** since that's all I'm using at this point.
*/

#define PD_ADDR(x)      ((ULONG) (x) & ~0x0F)           /*  Translated Address          */
#define PD_ADDR_MASK    (0xFFFFFFF0)                    /*  Address bits                */
#define PD_WP           (1 << 2)                        /*  Write protect it !          */
#define PD_USED         (1 << 3)                        /*  Page referenced             */
#define PD_MOD          (1 << 4)                        /*  Page "dirty"                */
#define PD_CI           (1 << 6)                        /*  Cache inhibit               */
#define PD_DT_INVALID   0x00                            /*  Invalid root descriptor     */
#define PD_DT_PAGE      0x01                            /*  Fixed offset, auto-gen      */
#define PD_DT_V4BYTE    0x02                            /*  Short root descriptor       */
#define PD_DT_V8BYTE    0x03                            /*  Long root descriptor        */
#define PD_DT_MASK      0x03                            /*  DT Mask                     */

/* short page descriptor format */

typedef ULONG PD_SHORT;
typedef PD_SHORT *PPD_SHORT;

/* long page descriptor format */

typedef struct
{
    UWORD Limit;
    UWORD Status;
    ULONG Address;
} PD_LONG;

typedef PD_LONG *PPD_LONG;

/* page frame descriptor stuff (for the ageing table) */

typedef struct
{
    UWORD Age;          /*  Page age in daemon ticks    */
    UWORD PageIndex;    /*  Index into PageTable        */
} FRAME_DESC;

typedef FRAME_DESC *PFRAME_DESC;

/* maximum age allowed by law */

#define AGE_MAX 0xFFFF

/* weighted average age, since dirty pages cost twice what clean ones do */

#define WAGE(p) (((PageTable [(p)->PageIndex]) & PD_MOD) ? ((p)->Age / 2) : ((p)->Age))

/*
** Here's the FASTROM support stuff.
*/

#define ROMBASE         0x00FC0000
#define ROMSIZE         0x00040000

/*
** Bus Error exception stack frames
*/

/* fault format numbers are in VectorOffset */

#define SF_FORMAT_MASK  0xF000
#define SSF_SIZE        0x20
#define SSF_FORMAT      0xA000
#define LSF_SIZE        0x5C
#define LSF_FORMAT      0xB000

/* short bus cycle fault (16 words) - format $a */

typedef struct
{
    UWORD StatusReg;
    CPTR  PC;
    UWORD VectorOffset;   /* bits 12-15 are the frame ID (1010) */
    UWORD InternReg1;
    UWORD SpecialStatusReg;
    UWORD InstPipeC;
    UWORD InstPipeB;
    CPTR  DataCycleFaultAddr;
    UWORD InternReg2 [2];
    ULONG DataOutputBuffer;
    UWORD InternReg3 [2];
} ShortBusFault;

typedef ShortBusFault *PShortBusFault;

/* long bus cycle fault (46 words) - format $b */

typedef struct
{
    UWORD StatusReg;
    CPTR  PC;
    UWORD VectorOffset;         /*  Bits 12-15 are the frame ID (1010) */
    UWORD InternReg1;
    UWORD SpecialStatusReg;
    UWORD InstPipeC;
    UWORD InstPipeB;
    CPTR  DataCycleFaultAddr;
    UWORD InternReg2 [2];
    ULONG DataOutputBuffer;     /*  Same as short frame to here */
    UWORD InternReg3 [4];
    CPTR  StageBAddress;
    UWORD InternReg4 [2];
    ULONG DataInputBuffer;
    UWORD InternReg5 [3];
    UWORD InternalInformation;  /*  Version # in bits 12-15 */
    UWORD InternReg6 [18];
} LongBusFault;

typedef LongBusFault *PLongBusFault;

/* special status bits */

#define SSTAT_FC        0x8000  /*  Fault on stage C of the instruction pipe    */
#define SSTAT_FB        0x4000  /*  Fault on stage B                            */
#define SSTAT_RC        0x2000  /*  Stage C re-run                              */
#define SSTAT_RB        0x1000  /*  Stage B re-run                              */
#define SSTAT_DF        0x0100  /*  Data fault                                  */
#define SSTAT_RM        0x0080  /*  Read-modify-write cycle                     */
#define SSTAT_RW        0x0040  /*  Read/write indicator                        */
#define SSTAT_SIZE_MASK 0x0030  /*  Size of data transfer                       */

/* the exception could be either one of these */

typedef union
{
    ShortBusFault S;
    LongBusFault L;
} BusFault;

typedef BusFault *PBusFault;

/*
** FaultNode - a recorded page fault
*/

typedef struct
{
    struct MinNode Next;        /*  Page fault list             */
    ULONG OldRegs   [15];       /*  D0-D7/A0-A6                 */
    ULONG OldUSP;               /*  Previous USP                */
    struct Task *FaultedTask;   /*  The task with the fault     */
    UBYTE RestartSigNum;        /*  Signal bit number           */
    UBYTE Pad   [3];            /*  Longword padding            */
    BusFault Fault;             /*  Copied fault                */
} FaultNode;

typedef FaultNode *PFaultNode;

/*
** This is what a fault node contains:
**
**           low memory
** |----------------------------|       start of FaultNode
** |FaultNode                   |       real fault frame copied from system stack
** |----------------------------|       end of fake user stack
** |////////////////////////////|       padding (hopefully)
** |/// Task Context saved by //|
** |///// Signal() or Wait() ///|
** |----------------------------|       this is where the fake USP is left pointing
** |///// return address ///////|       fake return address pointing to RestartHandler
** |----------------------------|       top of fake user stack
**         high memory
*/

/* allocate this much space for the FaultNode and the fake user stack */

#define FAULTNODE_SIZE 0x400

/*
** Ageing timer stuff
*/

typedef struct timerequest TIMER_REQ;
typedef TIMER_REQ *PTIMER_REQ;

/*
** function prototypes
*/

extern struct Window *OpenScrn (WORD w, WORD h, WORD d, ULONG IDCMP, ULONG Flags);
extern void CloseScrn (struct Window * window);

