Viewing File: <root>/src/emu/cpu/t11/t11.c

    1  /*** t11: Portable DEC T-11 emulator ******************************************
    2  
    3      Copyright Aaron Giles
    4  
    5      System dependencies:    long must be at least 32 bits
    6                              word must be 16 bit unsigned int
    7                              byte must be 8 bit unsigned int
    8                              long must be more than 16 bits
    9                              arrays up to 65536 bytes must be supported
   10                              machine must be twos complement
   11  
   12  *****************************************************************************/
   13  
   14  #include "emu.h"
   15  #include "debugger.h"
   16  #include "t11.h"
   17  
   18  
   19  /*************************************
   20   *
   21   *  Internal state representation
   22   *
   23   *************************************/
   24  
   25  struct t11_state
   26  {
   27      PAIR                ppc;    /* previous program counter */
   28      PAIR                reg[8];
   29      PAIR                psw;
   30      UINT16              initial_pc;
   31      UINT8               wait_state;
   32      UINT8               irq_state;
   33      int                 icount;
   34      device_irq_acknowledge_callback irq_callback;
   35      legacy_cpu_device *     device;
   36      address_space *program;
   37      direct_read_data *direct;
   38  };
   39  
   40  
   41  INLINE t11_state *get_safe_token(device_t *device)
   42  {
   43      assert(device != NULL);
   44      assert(device->type() == T11);
   45      return (t11_state *)downcast<legacy_cpu_device *>(device)->token();
   46  }
   47  
   48  
   49  
   50  /*************************************
   51   *
   52   *  Macro shortcuts
   53   *
   54   *************************************/
   55  
   56  /* registers of various sizes */
   57  #define REGD(x) reg[x].d
   58  #define REGW(x) reg[x].w.l
   59  #define REGB(x) reg[x].b.l
   60  
   61  /* PC, SP, and PSW definitions */
   62  #define SP      REGW(6)
   63  #define PC      REGW(7)
   64  #define SPD     REGD(6)
   65  #define PCD     REGD(7)
   66  #define PSW     psw.b.l
   67  
   68  
   69  /*************************************
   70   *
   71   *  Low-level memory operations
   72   *
   73   *************************************/
   74  
   75  INLINE int ROPCODE(t11_state *cpustate)
   76  {
   77      cpustate->PC &= 0xfffe;
   78      int val = cpustate->direct->read_decrypted_word(cpustate->PC);
   79      cpustate->PC += 2;
   80      return val;
   81  }
   82  
   83  
   84  INLINE int RBYTE(t11_state *cpustate, int addr)
   85  {
   86      return cpustate->program->read_byte(addr);
   87  }
   88  
   89  
   90  INLINE void WBYTE(t11_state *cpustate, int addr, int data)
   91  {
   92      cpustate->program->write_byte(addr, data);
   93  }
   94  
   95  
   96  INLINE int RWORD(t11_state *cpustate, int addr)
   97  {
   98      return cpustate->program->read_word(addr & 0xfffe);
   99  }
  100  
  101  
  102  INLINE void WWORD(t11_state *cpustate, int addr, int data)
  103  {
  104      cpustate->program->write_word(addr & 0xfffe, data);
  105  }
  106  
  107  
  108  
  109  /*************************************
  110   *
  111   *  Low-level stack operations
  112   *
  113   *************************************/
  114  
  115  INLINE void PUSH(t11_state *cpustate, int val)
  116  {
  117      cpustate->SP -= 2;
  118      WWORD(cpustate, cpustate->SPD, val);
  119  }
  120  
  121  
  122  INLINE int POP(t11_state *cpustate)
  123  {
  124      int result = RWORD(cpustate, cpustate->SPD);
  125      cpustate->SP += 2;
  126      return result;
  127  }
  128  
  129  
  130  
  131  /*************************************
  132   *
  133   *  Flag definitions and operations
  134   *
  135   *************************************/
  136  
  137  /* flag definitions */
  138  #define CFLAG 1
  139  #define VFLAG 2
  140  #define ZFLAG 4
  141  #define NFLAG 8
  142  
  143  /* extracts flags */
  144  #define GET_C (cpustate->PSW & CFLAG)
  145  #define GET_V (cpustate->PSW & VFLAG)
  146  #define GET_Z (cpustate->PSW & ZFLAG)
  147  #define GET_N (cpustate->PSW & NFLAG)
  148  
  149  /* clears flags */
  150  #define CLR_C (cpustate->PSW &= ~CFLAG)
  151  #define CLR_V (cpustate->PSW &= ~VFLAG)
  152  #define CLR_Z (cpustate->PSW &= ~ZFLAG)
  153  #define CLR_N (cpustate->PSW &= ~NFLAG)
  154  
  155  /* sets flags */
  156  #define SET_C (cpustate->PSW |= CFLAG)
  157  #define SET_V (cpustate->PSW |= VFLAG)
  158  #define SET_Z (cpustate->PSW |= ZFLAG)
  159  #define SET_N (cpustate->PSW |= NFLAG)
  160  
  161  
  162  
  163  /*************************************
  164   *
  165   *  Interrupt handling
  166   *
  167   *************************************/
  168  
  169  struct irq_table_entry
  170  {
  171      UINT8   priority;
  172      UINT8   vector;
  173  };
  174  
  175  static const struct irq_table_entry irq_table[] =
  176  {
  177      { 0<<5, 0x00 },
  178      { 4<<5, 0x38 },
  179      { 4<<5, 0x34 },
  180      { 4<<5, 0x30 },
  181      { 5<<5, 0x5c },
  182      { 5<<5, 0x58 },
  183      { 5<<5, 0x54 },
  184      { 5<<5, 0x50 },
  185      { 6<<5, 0x4c },
  186      { 6<<5, 0x48 },
  187      { 6<<5, 0x44 },
  188      { 6<<5, 0x40 },
  189      { 7<<5, 0x6c },
  190      { 7<<5, 0x68 },
  191      { 7<<5, 0x64 },
  192      { 7<<5, 0x60 }
  193  };
  194  
  195  static void t11_check_irqs(t11_state *cpustate)
  196  {
  197      const struct irq_table_entry *irq = &irq_table[cpustate->irq_state & 15];
  198      int priority = cpustate->PSW & 0xe0;
  199  
  200      /* compare the priority of the interrupt to the PSW */
  201      if (irq->priority > priority)
  202      {
  203          int vector = irq->vector;
  204          int new_pc, new_psw;
  205  
  206          /* call the callback; if we don't get -1 back, use the return value as our vector */
  207          if (cpustate->irq_callback != NULL)
  208          {
  209              int new_vector = (*cpustate->irq_callback)(cpustate->device, cpustate->irq_state & 15);
  210              if (new_vector != -1)
  211                  vector = new_vector;
  212          }
  213  
  214          /* fetch the new PC and PSW from that vector */
  215          assert((vector & 3) == 0);
  216          new_pc = RWORD(cpustate, vector);
  217          new_psw = RWORD(cpustate, vector + 2);
  218  
  219          /* push the old state, set the new one */
  220          PUSH(cpustate, cpustate->PSW);
  221          PUSH(cpustate, cpustate->PC);
  222          cpustate->PCD = new_pc;
  223          cpustate->PSW = new_psw;
  224          t11_check_irqs(cpustate);
  225  
  226          /* count cycles and clear the WAIT flag */
  227          cpustate->icount -= 114;
  228          cpustate->wait_state = 0;
  229      }
  230  }
  231  
  232  
  233  
  234  /*************************************
  235   *
  236   *  Core opcodes
  237   *
  238   *************************************/
  239  
  240  /* includes the static function prototypes and the master opcode table */
  241  #include "t11table.c"
  242  
  243  /* includes the actual opcode implementations */
  244  #include "t11ops.c"
  245  
  246  
  247  
  248  /*************************************
  249   *
  250   *  Low-level initialization/cleanup
  251   *
  252   *************************************/
  253  
  254  static CPU_INIT( t11 )
  255  {
  256      static const UINT16 initial_pc[] =
  257      {
  258          0xc000, 0x8000, 0x4000, 0x2000,
  259          0x1000, 0x0000, 0xf600, 0xf400
  260      };
  261      const struct t11_setup *setup = (const struct t11_setup *)device->static_config();
  262      t11_state *cpustate = get_safe_token(device);
  263  
  264      cpustate->initial_pc = initial_pc[setup->mode >> 13];
  265      cpustate->irq_callback = irqcallback;
  266      cpustate->device = device;
  267      cpustate->program = &device->space(AS_PROGRAM);
  268      cpustate->direct = &cpustate->program->direct();
  269  
  270      device->save_item(NAME(cpustate->ppc.w.l));
  271      device->save_item(NAME(cpustate->reg[0].w.l));
  272      device->save_item(NAME(cpustate->reg[1].w.l));
  273      device->save_item(NAME(cpustate->reg[2].w.l));
  274      device->save_item(NAME(cpustate->reg[3].w.l));
  275      device->save_item(NAME(cpustate->reg[4].w.l));
  276      device->save_item(NAME(cpustate->reg[5].w.l));
  277      device->save_item(NAME(cpustate->reg[6].w.l));
  278      device->save_item(NAME(cpustate->reg[7].w.l));
  279      device->save_item(NAME(cpustate->psw.w.l));
  280      device->save_item(NAME(cpustate->initial_pc));
  281      device->save_item(NAME(cpustate->wait_state));
  282      device->save_item(NAME(cpustate->irq_state));
  283  }
  284  
  285  
  286  
  287  /*************************************
  288   *
  289   *  CPU reset
  290   *
  291   *************************************/
  292  
  293  static CPU_RESET( t11 )
  294  {
  295      t11_state *cpustate = get_safe_token(device);
  296  
  297      /* initial SP is 376 octal, or 0xfe */
  298      cpustate->SP = 0x00fe;
  299  
  300      /* initial PC comes from the setup word */
  301      cpustate->PC = cpustate->initial_pc;
  302  
  303      /* PSW starts off at highest priority */
  304      cpustate->PSW = 0xe0;
  305  
  306      /* initialize the IRQ state */
  307      cpustate->irq_state = 0;
  308  
  309      /* reset the remaining state */
  310      cpustate->REGD(0) = 0;
  311      cpustate->REGD(1) = 0;
  312      cpustate->REGD(2) = 0;
  313      cpustate->REGD(3) = 0;
  314      cpustate->REGD(4) = 0;
  315      cpustate->REGD(5) = 0;
  316      cpustate->ppc.d = 0;
  317      cpustate->wait_state = 0;
  318  }
  319  
  320  
  321  
  322  /*************************************
  323   *
  324   *  Interrupt handling
  325   *
  326   *************************************/
  327  
  328  static void set_irq_line(t11_state *cpustate, int irqline, int state)
  329  {
  330      /* set the appropriate bit */
  331      if (state == CLEAR_LINE)
  332          cpustate->irq_state &= ~(1 << irqline);
  333      else
  334          cpustate->irq_state |= 1 << irqline;
  335  }
  336  
  337  
  338  
  339  /*************************************
  340   *
  341   *  Core execution
  342   *
  343   *************************************/
  344  
  345  static CPU_EXECUTE( t11 )
  346  {
  347      t11_state *cpustate = get_safe_token(device);
  348  
  349      t11_check_irqs(cpustate);
  350  
  351      if (cpustate->wait_state)
  352      {
  353          cpustate->icount = 0;
  354          goto getout;
  355      }
  356  
  357      do
  358      {
  359          UINT16 op;
  360  
  361          cpustate->ppc = cpustate->reg[7];   /* copy PC to previous PC */
  362  
  363          debugger_instruction_hook(device, cpustate->PCD);
  364  
  365          op = ROPCODE(cpustate);
  366          (*opcode_table[op >> 3])(cpustate, op);
  367  
  368      } while (cpustate->icount > 0);
  369  
  370  getout:
  371      ;
  372  }
  373  
  374  
  375  
  376  /**************************************************************************
  377   * Generic set_info
  378   **************************************************************************/
  379  
  380  static CPU_SET_INFO( t11 )
  381  {
  382      t11_state *cpustate = get_safe_token(device);
  383  
  384      switch (state)
  385      {
  386          /* --- the following bits of info are set as 64-bit signed integers --- */
  387          case CPUINFO_INT_INPUT_STATE + T11_IRQ0:        set_irq_line(cpustate, T11_IRQ0, info->i);      break;
  388          case CPUINFO_INT_INPUT_STATE + T11_IRQ1:        set_irq_line(cpustate, T11_IRQ1, info->i);      break;
  389          case CPUINFO_INT_INPUT_STATE + T11_IRQ2:        set_irq_line(cpustate, T11_IRQ2, info->i);      break;
  390          case CPUINFO_INT_INPUT_STATE + T11_IRQ3:        set_irq_line(cpustate, T11_IRQ3, info->i);      break;
  391  
  392          case CPUINFO_INT_PC:
  393          case CPUINFO_INT_REGISTER + T11_PC:             cpustate->PC = info->i;                         break;
  394          case CPUINFO_INT_SP:
  395          case CPUINFO_INT_REGISTER + T11_SP:             cpustate->SP = info->i;                         break;
  396          case CPUINFO_INT_REGISTER + T11_PSW:            cpustate->PSW = info->i;                        break;
  397          case CPUINFO_INT_REGISTER + T11_R0:             cpustate->REGW(0) = info->i;                    break;
  398          case CPUINFO_INT_REGISTER + T11_R1:             cpustate->REGW(1) = info->i;                    break;
  399          case CPUINFO_INT_REGISTER + T11_R2:             cpustate->REGW(2) = info->i;                    break;
  400          case CPUINFO_INT_REGISTER + T11_R3:             cpustate->REGW(3) = info->i;                    break;
  401          case CPUINFO_INT_REGISTER + T11_R4:             cpustate->REGW(4) = info->i;                    break;
  402          case CPUINFO_INT_REGISTER + T11_R5:             cpustate->REGW(5) = info->i;                    break;
  403      }
  404  }
  405  
  406  
  407  
  408  /**************************************************************************
  409   * Generic get_info
  410   **************************************************************************/
  411  
  412  CPU_GET_INFO( t11 )
  413  {
  414      t11_state *cpustate = (device != NULL && device->token() != NULL) ? get_safe_token(device) : NULL;
  415  
  416      switch (state)
  417      {
  418          /* --- the following bits of info are returned as 64-bit signed integers --- */
  419          case CPUINFO_INT_CONTEXT_SIZE:                  info->i = sizeof(t11_state);            break;
  420          case CPUINFO_INT_INPUT_LINES:                   info->i = 4;                            break;
  421          case CPUINFO_INT_DEFAULT_IRQ_VECTOR:            info->i = -1;                           break;
  422          case CPUINFO_INT_ENDIANNESS:                    info->i = ENDIANNESS_LITTLE;                    break;
  423          case CPUINFO_INT_CLOCK_MULTIPLIER:              info->i = 1;                            break;
  424          case CPUINFO_INT_CLOCK_DIVIDER:                 info->i = 1;                            break;
  425          case CPUINFO_INT_MIN_INSTRUCTION_BYTES:         info->i = 2;                            break;
  426          case CPUINFO_INT_MAX_INSTRUCTION_BYTES:         info->i = 6;                            break;
  427          case CPUINFO_INT_MIN_CYCLES:                    info->i = 12;                           break;
  428          case CPUINFO_INT_MAX_CYCLES:                    info->i = 110;                          break;
  429  
  430          case CPUINFO_INT_DATABUS_WIDTH + AS_PROGRAM:    info->i = 16;                   break;
  431          case CPUINFO_INT_ADDRBUS_WIDTH + AS_PROGRAM: info->i = 16;                  break;
  432          case CPUINFO_INT_ADDRBUS_SHIFT + AS_PROGRAM: info->i = 0;                   break;
  433          case CPUINFO_INT_DATABUS_WIDTH + AS_DATA:   info->i = 0;                    break;
  434          case CPUINFO_INT_ADDRBUS_WIDTH + AS_DATA:   info->i = 0;                    break;
  435          case CPUINFO_INT_ADDRBUS_SHIFT + AS_DATA:   info->i = 0;                    break;
  436          case CPUINFO_INT_DATABUS_WIDTH + AS_IO:     info->i = 0;                    break;
  437          case CPUINFO_INT_ADDRBUS_WIDTH + AS_IO:     info->i = 0;                    break;
  438          case CPUINFO_INT_ADDRBUS_SHIFT + AS_IO:     info->i = 0;                    break;
  439  
  440          case CPUINFO_INT_INPUT_STATE + T11_IRQ0:        info->i = (cpustate->irq_state & 1) ? ASSERT_LINE : CLEAR_LINE; break;
  441          case CPUINFO_INT_INPUT_STATE + T11_IRQ1:        info->i = (cpustate->irq_state & 2) ? ASSERT_LINE : CLEAR_LINE; break;
  442          case CPUINFO_INT_INPUT_STATE + T11_IRQ2:        info->i = (cpustate->irq_state & 4) ? ASSERT_LINE : CLEAR_LINE; break;
  443          case CPUINFO_INT_INPUT_STATE + T11_IRQ3:        info->i = (cpustate->irq_state & 8) ? ASSERT_LINE : CLEAR_LINE; break;
  444  
  445          case CPUINFO_INT_PREVIOUSPC:                    info->i = cpustate->ppc.w.l;            break;
  446  
  447          case CPUINFO_INT_PC:
  448          case CPUINFO_INT_REGISTER + T11_PC:             info->i = cpustate->PCD;                break;
  449          case CPUINFO_INT_SP:
  450          case CPUINFO_INT_REGISTER + T11_SP:             info->i = cpustate->SPD;                break;
  451          case CPUINFO_INT_REGISTER + T11_PSW:            info->i = cpustate->PSW;                break;
  452          case CPUINFO_INT_REGISTER + T11_R0:             info->i = cpustate->REGD(0);            break;
  453          case CPUINFO_INT_REGISTER + T11_R1:             info->i = cpustate->REGD(1);            break;
  454          case CPUINFO_INT_REGISTER + T11_R2:             info->i = cpustate->REGD(2);            break;
  455          case CPUINFO_INT_REGISTER + T11_R3:             info->i = cpustate->REGD(3);            break;
  456          case CPUINFO_INT_REGISTER + T11_R4:             info->i = cpustate->REGD(4);            break;
  457          case CPUINFO_INT_REGISTER + T11_R5:             info->i = cpustate->REGD(5);            break;
  458  
  459          /* --- the following bits of info are returned as pointers to data or functions --- */
  460          case CPUINFO_FCT_SET_INFO:                      info->setinfo = CPU_SET_INFO_NAME(t11);         break;
  461          case CPUINFO_FCT_INIT:                          info->init = CPU_INIT_NAME(t11);                break;
  462          case CPUINFO_FCT_RESET:                         info->reset = CPU_RESET_NAME(t11);              break;
  463          case CPUINFO_FCT_EXECUTE:                       info->execute = CPU_EXECUTE_NAME(t11);          break;
  464          case CPUINFO_FCT_DISASSEMBLE:                   info->disassemble = CPU_DISASSEMBLE_NAME(t11);  break;
  465          case CPUINFO_PTR_INSTRUCTION_COUNTER:           info->icount = &cpustate->icount;               break;
  466  
  467          /* --- the following bits of info are returned as NULL-terminated strings --- */
  468          case CPUINFO_STR_NAME:                          strcpy(info->s, "T11");                 break;
  469          case CPUINFO_STR_FAMILY:                    strcpy(info->s, "DEC T-11");            break;
  470          case CPUINFO_STR_VERSION:                   strcpy(info->s, "1.0");                 break;
  471          case CPUINFO_STR_SOURCE_FILE:                       strcpy(info->s, __FILE__);              break;
  472          case CPUINFO_STR_CREDITS:                   strcpy(info->s, "Copyright Aaron Giles"); break;
  473  
  474          case CPUINFO_STR_FLAGS:
  475              sprintf(info->s, "%c%c%c%c%c%c%c%c",
  476                  cpustate->psw.b.l & 0x80 ? '?':'.',
  477                  cpustate->psw.b.l & 0x40 ? 'I':'.',
  478                  cpustate->psw.b.l & 0x20 ? 'I':'.',
  479                  cpustate->psw.b.l & 0x10 ? 'T':'.',
  480                  cpustate->psw.b.l & 0x08 ? 'N':'.',
  481                  cpustate->psw.b.l & 0x04 ? 'Z':'.',
  482                  cpustate->psw.b.l & 0x02 ? 'V':'.',
  483                  cpustate->psw.b.l & 0x01 ? 'C':'.');
  484              break;
  485  
  486          case CPUINFO_STR_REGISTER + T11_PC:             sprintf(info->s, "PC:%04X", cpustate->reg[7].w.l); break;
  487          case CPUINFO_STR_REGISTER + T11_SP:             sprintf(info->s, "SP:%04X", cpustate->reg[6].w.l); break;
  488          case CPUINFO_STR_REGISTER + T11_PSW:            sprintf(info->s, "PSW:%02X", cpustate->psw.b.l);   break;
  489          case CPUINFO_STR_REGISTER + T11_R0:             sprintf(info->s, "R0:%04X", cpustate->reg[0].w.l); break;
  490          case CPUINFO_STR_REGISTER + T11_R1:             sprintf(info->s, "R1:%04X", cpustate->reg[1].w.l); break;
  491          case CPUINFO_STR_REGISTER + T11_R2:             sprintf(info->s, "R2:%04X", cpustate->reg[2].w.l); break;
  492          case CPUINFO_STR_REGISTER + T11_R3:             sprintf(info->s, "R3:%04X", cpustate->reg[3].w.l); break;
  493          case CPUINFO_STR_REGISTER + T11_R4:             sprintf(info->s, "R4:%04X", cpustate->reg[4].w.l); break;
  494          case CPUINFO_STR_REGISTER + T11_R5:             sprintf(info->s, "R5:%04X", cpustate->reg[5].w.l); break;
  495  
  496          case CPUINFO_IS_OCTAL:                          info->i = true;                         break;
  497      }
  498  }
  499  
  500  DEFINE_LEGACY_CPU_DEVICE(T11, t11);