/*

  P-Code interpreter (to run the apple pascal system)
  Copyright (C) 2000 Mario Klebsch

  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 2 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, write to the Free Software
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

  $Log: Memory.c,v $
  Revision 1.5  2001/06/06 23:26:44  mario
  Amiga-Patch von "Stefan A. Haubenthal" <polluks@web.de>

  Revision 1.4  2001/05/26 15:13:29  mario
  Diverse kleine Fehler behoben, fehlende #includes, Labels ohne Statement
  dahinter, ...

  Revision 1.3  2001/05/21 20:47:06  mario
  Die einzelnen Bits der Speicherflags können jetzt einzeln abbestellt
  werden.

  Revision 1.2  2001/05/20 13:12:02  mario
  CVS-Idents und Logs eingefügt


*/

#ident "$Id: Memory.c,v 1.5 2001/06/06 23:26:44 mario Exp $";

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

#include "psystem.h"
#include "pcode.h"
#include "Memory.h"

#ifdef XXX
#define MEM_VALID	1
#define MEM_RD_ONLY	2
#define MEM_WARN	4
#endif

int SwapBytes=0;

typedef struct Memory_St
{
#ifdef WORD_MEMORY
  word		Value;
#else
  byte		Value;
#endif
  byte		Flags;
} Memory_t;

#ifdef __SASC
__far
#endif
Memory_t	Mem[0x10000];

#ifdef WORD_MEMORY
word MemRd(word Addr)
{
  PointerCheck(Addr);
#ifdef MEM_VALID
  if (!(Mem[Addr].Flags&MEM_VALID))
    warning("MemRdByte: Reading uninitialized Memory 0x%04x",Addr);
#endif
#ifdef MEM_WARN
  if (Mem[Addr].Flags&MEM_WARN)
    warning("MemRdByte: Access to 0x%04x", Addr);
#endif
  return(Mem[Addr].Value);
}

void MemWr(word Addr, word Value)
{
  PointerCheck(Addr);
#ifdef MEM_RD_ONLY
  if (Mem[Addr].Flags&MEM_RD_ONLY)
    {
      warning("MemWrByte: 0x%04x is read only", Addr);
      XeqError(XBADMEM);
    }
#endif
#ifdef MEM_WARN
  if (Mem[Addr].Flags&MEM_WARN)
    warning("MemWrByte: Access to 0x%04x", Addr);
#endif
  Mem[Addr].Value=Value;
#ifdef MEM_VALID
  Mem[Addr].Flags|=MEM_VALID;
#endif
}

byte MemRdByte(word Addr, Integer Offset)
{
  PointerCheck(Addr);
  Addr   += (Offset&~1)/2;
  Offset &= 1;
  if (Offset)
    return(MemRd(Addr)>>8);
  else
    return(MemRd(Addr)&0xff);
}

void MemWrByte(word Addr, Integer Offset, byte Value)
{
  word	w;
  PointerCheck(Addr);
  Addr   += (Offset&~1)/2;
  Offset &= 1;
  w=MemRd(Addr);
  if (Offset)
    w=(w&0x00ff)|(Value<<8);
  else
    w=(w&0xff00)|(Value&0xff);
  MemWr(Addr, w);
}

#else

byte MemRdByte(word Addr, Integer Offset)
{
  PointerCheck(Addr);
  Addr += Offset;
#ifdef MEM_VALID
  if (!(Mem[Addr].Flags&MEM_VALID))
    warning("MemRdByte: Reading uninitialized Memory 0x%04x",Addr);
#endif
#ifdef MEM_WARN
  if (Mem[Addr].Flags&MEM_WARN)
    warning("MemRdByte: Access to 0x%04x", Addr);
#endif
  return(Mem[Addr].Value);
}

void MemWrByte(word Addr, Integer Offset, byte Value)
{
  PointerCheck(Addr);
  Addr += Offset;
#ifdef MEM_RD_ONLY
  if (Mem[Addr].Flags&MEM_RD_ONLY)
    {
      warning("MemWrByte: 0x%04x is read only", Addr);
      XeqError(XBADMEM);
    }
#endif
#ifdef MEM_WARN
  if (Mem[Addr].Flags&MEM_WARN)
    warning("MemWrByte: Access to 0x%04x", Addr);
#endif
  Mem[Addr].Value=Value;
#ifdef MEM_VALID
  Mem[Addr].Flags|=MEM_VALID;
#endif
}

word MemRd(word Addr)
{
  PointerCheck(Addr);
  return ( MemRdByte(Addr, 0+SwapBytes) +
	   (MemRdByte(Addr, 1-SwapBytes)<<8) );	
}

void MemWr(word Addr, word Value)
{
  PointerCheck(Addr);
  MemWrByte(Addr, 0+SwapBytes, Value & 0xff);
  MemWrByte(Addr, 1+SwapBytes, Value >> 8);
}
#endif

void MemReadOnly(word from, word to, int RO)
{
#ifdef MEM_RD_ONLY
  while (from<=to)
    {
      if (RO)
	Mem[from].Flags|=MEM_RD_ONLY;
      else
	Mem[from].Flags&=~MEM_RD_ONLY;
      from++;
    }
#endif
}

void MemDump(FILE *f, word Start, word End)
{
  int	w;
  int	i;
  int	Count=0;
#ifdef WORD_MEMORY
  word	Value;
  char	b[6];
  byte	ch1;
#else
  byte	Value;
  char	b[4];
#endif
  byte	ch;
  char	Buffer[80];
  char	OldBuffer[80];
  OldBuffer[0]='\0';
  for (w=Start; w<=End;)
    {
#ifdef WORD_MEMORY
      w=w&0xfff8;
#else
      w=w&0xfff0;
#endif
      sprintf(Buffer,"%04x: %48s %16s\n",w,"","");
#ifdef WORD_MEMORY
      for (i=0;i< 8;i++)
#else
      for (i=0;i<16;i++)
#endif
	{
#ifdef MEM_VALID
	  if (Mem[w].Flags&MEM_VALID)
	    {
#endif /* MEM_VALID */
	      Value=Mem[w].Value;
#ifdef WORD_MEMORY
	      sprintf(b,"%04x",Value);
#else
	      sprintf(b,"%02x",Value);
#endif
	      ch=Value&0xff;
	      if (!isprint(ch))
		ch='.';
#ifdef WORD_MEMORY
	      ch1=Value>>8;
	      if (!isprint(ch1))
		ch1='.';
#endif
#ifdef MEM_VALID
	    }
	  else
	    {
#ifdef WORD_MEMORY
	      strcpy(b,"....");
	      ch1=' ';
#else
	      strcpy(b,"..");
#endif
	      ch=' ';
	    }
#endif /* MEM_VALID */
#ifdef WORD_MEMORY
	  Buffer[6+5*i   ]=b[0];
	  Buffer[6+5*i+1 ]=b[1];
	  Buffer[6+5*i+2 ]=b[2];
	  Buffer[6+5*i+3 ]=b[3];
	  Buffer[6+5*8+2*i  ]=ch;
	  Buffer[6+5*8+2*i+1]=ch1;
#else
	  Buffer[6+3*i   ]=b[0];
	  Buffer[6+3*i+1 ]=b[1];
	  Buffer[6+3*16+i]=ch;
#endif
	  w++;
	}
      if (strcmp(Buffer+4, OldBuffer+4)!=0)
	{
	  if (Count>1)
	    fprintf(f, ".... %d line%s omitted\n",Count-1, Count==2?"":"s");
	  if (Count>0)
	    fputs(OldBuffer, f);
	  Count=0;
	  fputs(Buffer, f);
	}
      else
	Count++;
      strcpy(OldBuffer,Buffer);
    }
}

void MemInit(void)
{
  memset(Mem, 0, sizeof(Mem));
}

