OpenCores
URL https://opencores.org/ocsvn/tisc/tisc/trunk

Subversion Repositories tisc

[/] [tisc/] [web_uploads/] [tisc_sim.c] - Rev 6

Compare with Previous | Blame | View Log

/* Vins Tisc CPU Core, 7th Nov 2001 */
 
/* implemented in C for starters, transferred to VHDL later... */
/* My first attempt at processor design, thanks to :- */
/* Tim Boscke - CPU8BIT2, Rokwell - 6502, Microchip - Pic */
/* Jien Chung Lo - EL405 , Steve Scott - Tisc, */
/* Giovanni Moretti - Intro to Asm */
/* Uses 12 bit program word, and 8 bit data memory */
/* but its not a pic (honest guv) */
 
/* 2 reg machine,accumulator based, with akku and index regs */
/* Harvard architecture, uses return x so as to eliminate need of pmem */
/* indirect instructions like 8051. */
/* pc is 10 bits, akku and idx are 8 bit. */
/* Zero flag checked and pc always incremented */
/* at end of each instruction. */
 
/* Has carry and zero flags, */
/* three addressing modes:- immediate, indirect and reg. */
/* seperate program and data memory for pipelining later... */
 
/* Instructions coded as thus:- */
 
/*
   ; Long instructions first - program jump.
   ; Both store return address for subroutine calls, 1 deep stack.
   00 xxxxxxxxxx jc pmem10 ; if c==1, stack = pc, pc <- pmem10, fi
   01 xxxxxxxxxx jz pmem10 ; if z==1, stack = pc, pc <- pmem10, fi
 
   ; Immediate ops
   ; bits 9 and 8 select what to do
   10 00 xxxxxxxx ld a,#imm8 ; a= imm8, c=0,
   10 01 xxxxxxxx adc a,#imm8 ; add with carry imm8, cy and z set
   10 10 xxxxxxxx adx ix,#imm8 ; add imm8 to idx reg, z=(a==0)
 
   ; Special op is method of reading pmem space/lookup table and sub return
   ; kind of load immediate - not sure how many states this will need
   10 11 xxxxxxxx ret a,#imm8 ; a= imm8, pc = stack
 
   ; Indirect and alu ops
   ; bit 9 selects indirect or alu ops
 
   ; Indirect - bits 7 and 8 select what to do
   11 0 0 0 xxxxxxx ld a,[ix] ; load a indirect data mem
   11 0 0 1 xxxxxxx st [ix],a ; store a indirect data mem
 
   ; register register
   11 0 1 0 xxxxxxx tax ; x = a,
   11 0 1 1 xxxxxxx txa ; a = x
 
   ; Arithmetic ops use indirect addressing
   ; all alu ops indirect, bits 7 and 8 select alu op.
   11 1 00 xxxxxxx add a,[ix] ; add with carry
   11 1 01 xxxxxxx sub a,[ix] ; sub with carry as borrow
   11 1 10 xxxxxxx and a,[ix] ; and mem contents into a
   11 1 11 xxxxxxx nor a,[ix] ; nor
 
 */
 
/* Further work:- since some indirect, register and alu ops */
/* dont use all of the word, we could do the following:-
 
   1) Implement dual instructions in a single 12 bit instruction word.
   2) Extend indirect addressing to use offset.
   3) Increase oip code functionality.
 
   Do this later - get it working first using small nostates.
 */
#include <stdlib.h>
#include <stdio.h>
/* Non Ansi - used for keypress */
#include <conio.h>
 
/* Vins handy defines */
 
#define bit(x) (1 << (x))
#define getbit(x, y) ((x & bit(y)) >> y)
#define setbit(x, y) ((x) & bit(y))
#define clrbit(x, y) ((x) & ~bit(y))
 
/* Mem bit widths */
#define DMEMWIDTH (8)
#define PMEMWIDTH (10)
 
/* Make a few macros for carry access */
/* not needed in hdl */
#define CY getbit(akku, 8)
 
/* VHDL take offs */
#define NINETO0 (0x3FF)
#define SEVENTO0 (0xFF)
 
/* Define instructions */
/* jcc is b00 xx xxxx xxxx */
#define JC (0x000)
/* ldx is b01 xx xxxx xxxx */
#define JZ (0x400)
/* Immediate instructions - b10 xx xxxx xxxx */
#define IMM (0x800)
/* indirect and alu ops - b11 xx xxxx xxxx */
#define IND (0xC00)
/* Reg - Reg */
#define REG IND
 
/* Subset instructions */
/* Immediate subtypes */
#define LDA (0x000)
#define ADC (0x100)
#define ADX (0x200)
#define RET (0x300)
 
/* ALU indirect ops */
/* add - b 00 xxxxxxx */
#define ADD (0x000)
/* sub - b 01 xxxxxxx */
#define SUB (0x080)
/* and - b 10 xxxxxxx */
#define AND (0x100)
/* nor - b 11 xxxxxxx */
#define NOR (0x180)
 
/* Reg to Reg */
/* transfer a to x - b1101 0000 0000*/
#define TAX (0xD00)
/* transfer x to a - b1101 1000 0000*/
#define TXA (0xD80)
 
/* Indirect Ops ld/st */
/* ld a,[ix] - b1100 0xxx xxxx ld */
#define LDAX (0xC00)
/* st [ix],a - b1100 1xxx xxxx st */
#define STAX (0xC80)
 
/* create special data type */
typedef unsigned short UNSIGNED10;
typedef unsigned short AKKU9;
typedef unsigned char BYTE;
typedef unsigned char BIT;
 
/* data memory */
BYTE dmem[2 ^ DMEMWIDTH]; /* program memory */
UNSIGNED10 pmem[2 ^ PMEMWIDTH];
 
/* main program start */
void main(int argc, char **argv)
{
  UNSIGNED10 PC; /* Program counter is 10 bit */
  UNSIGNED10 stack; /* stack is also 10 bit */
  UNSIGNED10 instr; /* working data bus */
 
  BIT Z; /* Flags */
 
/* 9 bit accumulator */
/* bit 9 is cy */
  AKKU9 akku;
 
/* State, temp and index registers */
  BYTE state, temp, ix;
 
/* reset - only reset PC & States in real CPU?*/
  PC = 0; akku = 0;
  state = 0; ix = 0; Z = 0;
 
  printf("\nPress 'q' to quit.\n");
 
/* Load a simple program - just an opcode test*/
  pmem[0] = IMM | LDA | 0x55;
  pmem[1] = REG | TAX;
  pmem[2] = IMM | LDA | 0xAA;
  pmem[3] = IND | STAX; /* Store A (0xaa) at 0x55 */
  pmem[4] = IND | NOR; /* Zero A */
  pmem[5] = IMM | LDA | 0xff;
  pmem[6] = IMM | ADC | 0x01; /* Set carry */
  pmem[7] = JC | 0x10 - 1; /* start again of overflow - remember 1 less*/
  pmem[0x10] = IMM | LDA | 0x00; /* clear A and zero flag */
  pmem[0x11] = JZ | 0x20 - 1; /* jump to 0x21 - remember 1 less */
/* should now return here with val in A */
  pmem[0x12] = IND | STAX; /* Store A (0xaa) at 0x55 */
  pmem[0x13] = IMM | LDA | 0x00; /* clear A and zero flag */
  pmem[0x14] = JZ | 0x21 - 1; /* jump to 0x21 - remember 1 less */
/* should now return here with val in A */
  pmem[0x15] = IND | STAX; /* Store A at 0x55 */
  pmem[0x16] = IMM | LDA | 0x00; /* clear A and zero flag */
  pmem[0x17] = JZ | 0x00; /* Start again, 1 less remember */
 
/* Lookup table */
  pmem[0x20] = IMM | RET | 0x99;
  pmem[0x21] = IMM | RET | 0x81;
 
/* Main fetch-decode-execute-store cycle */
  while (1) /* main state machine loop */
 
    { /* fetch */
      instr = pmem[PC];
 
/* now single step through program */
      printf("mem\top\takku\tix\tStack\ttemp\tState\tC Z\n");
 
      printf("%03X\t%03X\t%02X\t%02X\t%03X\t%02X\t%02X\t%c %c\n",
             PC, instr, akku & 0xff, ix, stack, temp, state, CY ? '1' : '0', Z ? '1' : '0');
 
/* Non Ansi but you know what I mean... */
      while (!_kbhit()) ;
      if (tolower(_getch()) == 'q') return; /* Quit if 'q' pressed */
 
/* Initial decode */
      switch (instr & (bit(11) | bit(10)))
        {
        case JC: /* jump if cary set */
          if (CY)
            {
/* save return address */
              stack = PC;
 
/* Set PC to new value */
/* remember it also increments */
              PC = instr & NINETO0;
            }
 
          break;
 
        case JZ:
          if (Z)
            {
/* Save return address */
              stack = PC;
 
/* Set PC to new value */
/* remember it also increments */
 
              PC = instr & NINETO0;
            }
 
          break;
 
        case IMM:
/* decode immediate instruction */
          switch (instr & (bit(8) | bit(9)))
            {
            case LDA:
              akku = (instr & SEVENTO0);
              break;
 
            case ADC:
              akku += (instr & SEVENTO0);
/* CY set on overflow */
              break;
 
            case ADX:
              ix += (instr & SEVENTO0);
              break;
 
            case RET:
              akku = (instr & SEVENTO0);
/* return stack */
              PC = stack;
              break;
 
            default: /* shoudl never get here */
              ;
            } /* end of imm subtype decode */
 
          break;
 
        case IND: /* All these are indirect */
/* Decode either alu or load/store instr */
          if (instr & bit(9)) /* ALU add, sub, and, or*/
 
            { /* get temp value of mem location */
/* might include disp7 here, ignore for min */
              temp = dmem[ix];
 
/* decode indirect alu instruction */
              switch (instr & (bit(8) | bit(7)))
                {
                case ADD:
                  akku += temp;
                  break;
 
                case SUB:
/* CY acts as borrow if underflow */
                  akku -= temp;
                  break;
 
                case AND:
                  akku &= temp;
                  break;
 
                case NOR:
                  akku = ~(akku | temp) & SEVENTO0;
                  break;
 
                default: /* shoudl never get here */
                  ;
                } /* end of imm subtye decode */
            }
          else                            /* ld/store indirect & reg - reg*/
            {
              if (instr & bit(8)) /* reg - reg */
                {
                  if (bit(7)) /* tax */
                    {
                      ix = akku & SEVENTO0;
                    }
                  else /* txa */
                    {
                      akku = ix;
                    }
                }
              else /* ld/store */
                {
                  if (bit(7)) /* store */
                    { /* not sure how to do this */
                      dmem[ix] = akku & SEVENTO0;
                    }
                  else /* load */
                    {
                      akku = dmem[ix];
                    }
                } /* reg - reg if */
            } /* alu or indirect if */
 
          break; /* alu/ind load/store switch */
 
        default:
          ; /* shouldnt get here */
        }
 
/* PC always incremented */
      PC += 1;
/* set zero flag */
      Z = (akku == 0);
    } /* main while loop */
} /* end of prog */

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.