File:  [Generator SEGA Genesis emulator] / generator / src / cpu68k.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs
Wed Mar 4 04:46:33 2020 UTC (6 years, 4 months ago) by root
Branches: MAIN, JamesPonder
CVS tags: v0_31, HEAD
0.31

/* Generator is (c) James Ponder, 1997-2001 http://www.squish.net/generator/ */

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

#include "generator.h"
#include "mem68k.h"
#include "cpu68k.h"
#include "vdp.h"
#include "ui.h"
#include "out/def68k-iibs.h"
#include "out/def68k-proto.h"
#include "out/def68k-funcs.h"

/*** externed variables ***/

uint8 *cpu68k_rom = NULL;
unsigned int cpu68k_romlen = 0;
uint8 *cpu68k_ram = NULL;
t_iib *cpu68k_iibtable[65536];
void (*cpu68k_functable[65536*2])(t_ipc *ipc);
int cpu68k_totalinstr;
int cpu68k_totalfuncs;
unsigned int cpu68k_clocks;
unsigned int cpu68k_frames;
t_regs regs;
uint8 movem_bit[256];
t_ipclist *ipclist[LEN_IPCLISTTABLE];

/*** global variables ***/

/*** forward references ***/

void cpu68k_reset(void);

int cpu68k_init(void)
{
  t_iib *iib;
  uint16 bitmap;
  int i, j, sbit, dbit, sbits, dbits;

  memset(cpu68k_iibtable, 0, sizeof(cpu68k_iibtable));
  memset(cpu68k_functable, 0, sizeof(cpu68k_functable));
  memset(&regs, 0, sizeof(regs));

  cpu68k_totalinstr = 0;

  for (i = 0; i < iibs_num; i++) {
    iib = &iibs[i];

    bitmap = iib->mask;
    sbits = 0;
    dbits = 0;

    for (j = 0; j < 2; j++) {
      switch(j ? iib->stype : iib->dtype) {
      case dt_Dreg:
      case dt_Areg:
      case dt_Aind:
      case dt_Ainc:
      case dt_Adec:
      case dt_Adis:
      case dt_Aidx:
	if (j) {
	  bitmap ^= 7<<iib->sbitpos;
	  sbits = 3;
	} else {
	  bitmap ^= 7<<iib->dbitpos;
	  dbits = 3;
	}
	break;
      case dt_AbsW:
      case dt_AbsL:
      case dt_Pdis:
      case dt_Pidx:
	break;
      case dt_ImmB:
      case dt_ImmW:
      case dt_ImmL:
      case dt_ImmS:
	break;
      case dt_Imm3:
	if (j) {
	  bitmap ^= 7<<iib->sbitpos;
	  sbits = 3;
	} else {
	  bitmap ^= 7<<iib->dbitpos;
	  dbits = 3;
	}
	break;
      case dt_Imm4:
	if (j) {
	  bitmap ^= 15<<iib->sbitpos;
	  sbits = 4;
	} else {
	  bitmap ^= 15<<iib->dbitpos;
	  dbits = 4;
	}
	break;
      case dt_Imm8:
      case dt_Imm8s:
	if (j) {
	  bitmap ^= 255<<iib->sbitpos;
	  sbits = 8;
	} else {
	  bitmap ^= 255<<iib->dbitpos;
	  dbits = 8;
	}
	break;
      case dt_ImmV:
	sbits = 12;
	bitmap ^= 0x0FFF;
	break;
      case dt_Ill:
	/* no src/dst parameter */
	break;
      default:
	LOG_CRITICAL(("CPU definition #%d incorrect", i));
	return 1;
      }
    }
    if (bitmap != 0xFFFF) {
      LOG_CRITICAL(("CPU definition #%d incorrect (0x%x)", i, bitmap));
      return 1;
    }
    for (sbit = 0; sbit < (1<<sbits); sbit++) {
      for (dbit = 0; dbit < (1<<dbits); dbit++) {
	bitmap = iib->bits | (sbit<<iib->sbitpos) | (dbit<<iib->dbitpos);
	if (iib->stype == dt_Imm3 || iib->stype == dt_Imm4 ||
	    iib->stype == dt_Imm8) {
	  if (sbit == 0 && iib->flags.imm_notzero) {
	    continue;
	  }
	}
	if (cpu68k_iibtable[bitmap] != NULL) {
	  LOG_CRITICAL(("CPU definition #%d conflicts (0x%x)", i, bitmap));
	  return 1;
	}
	cpu68k_iibtable[bitmap] = iib;
	/* set both flag and non-flag versions */
	cpu68k_functable[bitmap*2]    = cpu68k_funcindex[i*2];
	cpu68k_functable[bitmap*2+1]  = cpu68k_funcindex[i*2+1];
	cpu68k_totalinstr++;
      }
    }
  }

  j = 0;

  for (i = 0; i < 65536; i++) {
    if (cpu68k_iibtable[i]) {
      j++;
    }
  }
  if (j != cpu68k_totalinstr) {
    LOG_CRITICAL(("Instruction count not verified (%d/%d)\n",
		  cpu68k_totalinstr, i));
    return 1;
  }

  cpu68k_totalfuncs = iibs_num;

  for (i = 0; i < 256; i++) {
    for (j = 0; j < 8; j++) {
      if (i & 1<<j)
	break;
    }
    movem_bit[i] = j;
  }

  LOG_VERBOSE(("CPU: %d instructions supported by %d routines",
	       cpu68k_totalinstr, cpu68k_totalfuncs));

  return 0;
}

/* fill in ipc */

void cpu68k_ipc(uint32 addr68k, uint8 *addr, t_iib *iib, t_ipc *ipc)
{
  t_type type;
  uint32 *p;

  ipc->opcode = LOCENDIAN16(*(uint16 *)addr);
  ipc->wordlen = 1;
  if (!iib) {
    /* illegal instruction, no further details (wordlen must be set to 1) */
    return;
  }

  ipc->used = iib->flags.used;
  ipc->set = iib->flags.set;

  if ((iib->mnemonic == i_Bcc) || (iib->mnemonic == i_BSR)) {
    /* special case - we can calculate the offset now */
    /* low 8 bits of current instruction are addr+1 */
    ipc->src = (sint32)(*(sint8 *)(addr+1));
    if (ipc->src == 0) {
      ipc->src = (sint32)(sint16)LOCENDIAN16(*(uint16 *)(addr+2));
      ipc->wordlen++;
    }
    ipc->src+= addr68k+2; /* add PC of next instruction */
    return;
  }
  if (iib->mnemonic == i_DBcc || iib->mnemonic == i_DBRA) {
    /* special case - we can calculate the offset now */
    ipc->src = (sint32)(sint16)LOCENDIAN16(*(uint16 *)(addr+2));
    ipc->src+= addr68k+2; /* add PC of next instruction */
    ipc->wordlen++;
    return;
  }

  addr+= 2;
  addr68k+= 2;

  for (type = 0; type < 2; type++) {

    if (type == tp_src)
      p = &(ipc->src);
    else
      p = &(ipc->dst);

    switch(type == tp_src ? iib->stype : iib->dtype) {
    case dt_Adis:
      *p = (sint32)(sint16)LOCENDIAN16(*(uint16 *)addr);
      ipc->wordlen++;
      addr+= 2;
      addr68k+= 2;
      break;
    case dt_Aidx:
      *p = (sint32)(sint8)addr[1];
      *p = (*p & 0xFFFFFF) | (*addr)<<24;
      ipc->wordlen++;
      addr+= 2;
      addr68k+= 2;
      break;
    case dt_AbsW:
      *p = (sint32)(sint16)LOCENDIAN16(*(uint16 *)addr);
      ipc->wordlen++;
      addr+= 2;
      addr68k+= 2;
      break;
    case dt_AbsL:
      *p = (uint32)( (LOCENDIAN16(*(uint16 *)addr)<<16) +
		     LOCENDIAN16(*(uint16 *)(addr+2)) );
      ipc->wordlen+= 2;
      addr+= 4;
      addr68k+= 4;
      break;
    case dt_Pdis:
      *p = (sint32)(sint16)LOCENDIAN16(*(uint16 *)addr);
      *p+= addr68k; /* add PC of extension word (this word) */
      ipc->wordlen++;
      addr+= 2;
      addr68k+= 2;
      break;
    case dt_Pidx:
      *p = ((sint32)(sint8)addr[1]) + addr68k;
      *p = (*p & 0xFFFFFF) | (*addr)<<24;
      ipc->wordlen++;
      addr+= 2;
      addr68k+= 2;
      break;
    case dt_ImmB:
      /* low 8 bits of next 16 bit word is addr+1 */
      *p = (uint32)(*(uint8 *)(addr+1));
      ipc->wordlen++;
      addr+= 2;
      addr68k+= 2;
      break;
    case dt_ImmW:
      *p = (uint32)LOCENDIAN16(*(uint16 *)addr);
      ipc->wordlen++;
      addr+= 2;
      addr68k+= 2;
      break;
    case dt_ImmL:
      *p = (uint32)( (LOCENDIAN16(*(uint16 *)addr)<<16) +
		     LOCENDIAN16(*(uint16 *)(addr+2)) );
      ipc->wordlen+= 2;
      addr+= 4;
      addr68k+= 4;
      break;
    case dt_Imm3:
      if (type == tp_src)
	*p = (ipc->opcode >> iib->sbitpos) & 7;
      else
	*p = (ipc->opcode >> iib->dbitpos) & 7;
      break;
    case dt_Imm4:
      if (type == tp_src)
	*p = (ipc->opcode >> iib->sbitpos) & 15;
      else
	*p = (ipc->opcode >> iib->dbitpos) & 15;
      break;
    case dt_Imm8:
      if (type == tp_src)
	*p = (ipc->opcode >> iib->sbitpos) & 255;
      else
	*p = (ipc->opcode >> iib->dbitpos) & 255;
      break;
    case dt_Imm8s:
      if (type == tp_src)
	*p = (sint32)(sint8)((ipc->opcode >> iib->sbitpos) & 255);
      else
	*p = (sint32)(sint8)((ipc->opcode >> iib->dbitpos) & 255);
      break;
    default:
      break;
    }
  }
}

t_ipclist *cpu68k_makeipclist(uint32 pc)
{
  int size = 16;
  t_ipclist *list = malloc(sizeof(t_ipclist) + 16*sizeof(t_ipc) + 8);
  t_ipc *ipc = (t_ipc *)(list+1);
  t_iib *iib;
  int instrs = 0;
  uint16 required;
  int i;

  if (list == NULL)
    ui_err("Out of memory");

  pc&= 0xffffff;
  list->pc = pc;
  list->clocks = 0;
  list->norepeat = 0;
  do {
    instrs++;
    if (instrs > size) {
      if (size > 10000)
        ui_err("Something has gone seriously wrong @ %08X", pc);
      size+= 16;
      list = realloc(list, sizeof(t_ipclist) + size*sizeof(t_ipc) + 8);
      if (list == NULL)
        ui_err("Out of memory whilst making ipc list @ %08X", pc);
      ipc = ((t_ipc *)(list+1))+instrs-1;
    }
    if (!(iib = cpu68k_iibtable[fetchword(pc)])) {
      ui_err("Invalid instruction @ %08X", pc);
    }
    cpu68k_ipc(pc, mem68k_memptr[pc>>12](pc), iib, ipc);
    list->clocks+= iib->clocks;
    pc+= (iib->wordlen)<<1;
    ipc++;
  } while (!iib->flags.endblk);
  *(int *)ipc = 0;

  if (instrs == 2) {
    ipc--;
    if (iib->mnemonic == i_Bcc && ipc->src == list->pc) {
      /* we have a 2-instruction block ending in a branch to start */
      ipc = (t_ipc *)(list+1);
      iib = cpu68k_iibtable[ipc->opcode];
      if (iib->mnemonic == i_TST || iib->mnemonic == i_CMP) {
	/* it's a tst/cmp and then a Bcc */
	if (!(iib->stype == dt_Ainc || iib->stype == dt_Adec)) {
	  /* no change could happen during the block */
	  list->norepeat = 1;
	}
      }
    }
  }

  ipc = ((t_ipc *)(list+1))+instrs-1;
  required = 0x1F;               /* all 5 flags need to be correct at end */
  for (i = 0; i < instrs; i++) {
    ipc->set&= required;
    required&= ~ipc->set;
    required|= ipc->used;
    if (ipc->set) {
      ipc->function = cpu68k_functable[(ipc->opcode<<1)+1];
    } else {
      ipc->function = cpu68k_functable[ipc->opcode<<1];
    }
    ipc--;
  }
  /* fprintf("Cached %08X to %08X\n", list->pc, pc-((iib->wordlen)<<1)); */
  return list;
}

void cpu68k_reset(void)
{
  int i;

  if (!cpu68k_ram) {
    if ((cpu68k_ram = malloc(0x10000)) == NULL)
      ui_err("Out of memory");
  }
  memset(cpu68k_ram, 0, 0x10000);

  regs.pc = fetchlong(4);
  regs.regs[15] = fetchlong(0);
  regs.sr.sr_int = 0;
  regs.sr.sr_struct.s = 1; /* Supervisor mode*/
  regs.stop = 0;
  cpu68k_clocks = 0; 
  cpu68k_frames = 0; /* Number of frames */

  for (i = 0; i < LEN_IPCLISTTABLE; i++) {
    if (ipclist[i]) {
      free(ipclist[i]);
      ipclist[i] = NULL;
    }
  }
}

void cpu68k_endfield(void)
{
  cpu68k_clocks = 0;
}

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.