⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mlite.c

📁 Plasma IP Core 你可以利用这个组件在FPGA中设计MIPS结构的CPU
💻 C
📖 第 1 页 / 共 2 页
字号:
/*--------------------------------------------------------------------- TITLE: Plasma CPU in software.  Executes MIPS(tm) opcodes.-- AUTHOR: Steve Rhoads (rhoadss@yahoo.com)-- DATE CREATED: 1/31/01-- FILENAME: mlite.c-- PROJECT: Plasma CPU core-- COPYRIGHT: Software placed into the public domain by the author.--    Software 'as is' without warranty.  Author liable for nothing.-- DESCRIPTION:--   Plasma CPU simulator in C code.  --   This file served as the starting point for the VHDL code.--   Assumes running on a little endian PC.--------------------------------------------------------------------*/#include <stdio.h>#include <stdlib.h>#include <string.h>#include <ctype.h>#include <assert.h>//#define ENABLE_CACHE#define MEM_SIZE (1024*1024*2)#define ntohs(A) ( ((A)>>8) | (((A)&0xff)<<8) )#define htons(A) ntohs(A)#define ntohl(A) ( ((A)>>24) | (((A)&0xff0000)>>8) | (((A)&0xff00)<<8) | ((A)<<24) )#define htonl(A) ntohl(A)#ifndef WIN32#define getch getcharvoid Sleep(unsigned long value){    volatile unsigned long count = value*1000000;   while(--count > 0) ;}#else#include <conio.h>extern void __stdcall Sleep(unsigned long value);#endif#define UART_WRITE        0x20000000#define UART_READ         0x20000000#define IRQ_MASK          0x20000010#define IRQ_STATUS        0x20000020#define CONFIG_REG        0x20000070#define MMU_PROCESS_ID    0x20000080#define MMU_FAULT_ADDR    0x20000090#define MMU_TLB           0x200000a0#define IRQ_UART_READ_AVAILABLE  0x001#define IRQ_UART_WRITE_AVAILABLE 0x002#define IRQ_COUNTER18_NOT        0x004#define IRQ_COUNTER18            0x008#define IRQ_MMU                  0x200#define MMU_ENTRIES 4#define MMU_MASK (1024*4-1)typedef struct{   unsigned long virtualAddress;   unsigned long physicalAddress;} MmuEntry;typedef struct {   long r[32];   long pc, pc_next, epc;   unsigned long hi;   unsigned long lo;   long status;   long userMode;   long processId;   long exceptionId;   long faultAddr;   long irqStatus;   long skip;   unsigned char *mem;   long wakeup;   long big_endian;   MmuEntry mmuEntry[MMU_ENTRIES];} State;static char *opcode_string[]={   "SPECIAL","REGIMM","J","JAL","BEQ","BNE","BLEZ","BGTZ",   "ADDI","ADDIU","SLTI","SLTIU","ANDI","ORI","XORI","LUI",   "COP0","COP1","COP2","COP3","BEQL","BNEL","BLEZL","BGTZL",   "?","?","?","?","?","?","?","?",   "LB","LH","LWL","LW","LBU","LHU","LWR","?",   "SB","SH","SWL","SW","?","?","SWR","CACHE",   "LL","LWC1","LWC2","LWC3","?","LDC1","LDC2","LDC3"   "SC","SWC1","SWC2","SWC3","?","SDC1","SDC2","SDC3"};static char *special_string[]={   "SLL","?","SRL","SRA","SLLV","?","SRLV","SRAV",   "JR","JALR","MOVZ","MOVN","SYSCALL","BREAK","?","SYNC",   "MFHI","MTHI","MFLO","MTLO","?","?","?","?",   "MULT","MULTU","DIV","DIVU","?","?","?","?",   "ADD","ADDU","SUB","SUBU","AND","OR","XOR","NOR",   "?","?","SLT","SLTU","?","DADDU","?","?",   "TGE","TGEU","TLT","TLTU","TEQ","?","TNE","?",   "?","?","?","?","?","?","?","?"};static char *regimm_string[]={   "BLTZ","BGEZ","BLTZL","BGEZL","?","?","?","?",   "TGEI","TGEIU","TLTI","TLTIU","TEQI","?","TNEI","?",   "BLTZAL","BEQZAL","BLTZALL","BGEZALL","?","?","?","?",   "?","?","?","?","?","?","?","?"};static unsigned long HWMemory[8];static long mem_read(State *s, long size, unsigned long address){   unsigned long value=0, ptr;   s->irqStatus |= IRQ_UART_WRITE_AVAILABLE;   switch(address)   {      case UART_READ:          if(kbhit())            HWMemory[0] = getch();         s->irqStatus &= ~IRQ_UART_READ_AVAILABLE; //clear bit         return HWMemory[0];      case IRQ_MASK:          return HWMemory[1];      case IRQ_MASK + 4:         Sleep(10);         return 0;      case IRQ_STATUS:          if(kbhit())            s->irqStatus |= IRQ_UART_READ_AVAILABLE;         return s->irqStatus;      case MMU_PROCESS_ID:         return s->processId;      case MMU_FAULT_ADDR:         return s->faultAddr;   }   ptr = (unsigned long)s->mem + (address % MEM_SIZE);   if(0x10000000 <= address && address < 0x10000000 + 1024*1024)      ptr = (unsigned long)s->mem + address - 0x10000000;   else if(address < 1024*8)      ptr += 1024*1024;   switch(size)    {      case 4:          if(address & 3)            printf("Unaligned access PC=0x%x address=0x%x\n", s->pc, address);         assert((address & 3) == 0);         value = *(long*)ptr;         if(s->big_endian)             value = ntohl(value);         break;      case 2:         assert((address & 1) == 0);         value = *(unsigned short*)ptr;         if(s->big_endian)             value = ntohs((unsigned short)value);         break;      case 1:         value = *(unsigned char*)ptr;         break;      default:          printf("ERROR");   }   return(value);}static void mem_write(State *s, long size, long unsigned address, unsigned long value){   static char_count=0;   unsigned long ptr;   switch(address)   {      case UART_WRITE:          putch(value);          return;      case IRQ_MASK:            HWMemory[1] = value;          return;      case IRQ_STATUS:          s->irqStatus = value;          return;      case CONFIG_REG:         return;      case MMU_PROCESS_ID:         //printf("processId=%d\n", value);         s->processId = value;         return;   }   if(MMU_TLB <= address && address <= MMU_TLB+MMU_ENTRIES * 8)   {      //printf("TLB 0x%x 0x%x\n", address - MMU_TLB, value);      ptr = (unsigned long)s->mmuEntry + address - MMU_TLB;      *(int*)ptr = value;      s->irqStatus &= ~IRQ_MMU;      return;   }   ptr = (unsigned long)s->mem + (address % MEM_SIZE);   if(0x10000000 <= address && address < 0x10000000 + 1024*1024)      ptr = (unsigned long)s->mem + address - 0x10000000;   else if(address < 1024*8)      ptr += 1024*1024;   switch(size)    {      case 4:          assert((address & 3) == 0);         if(s->big_endian)             value = htonl(value);         *(long*)ptr = value;         break;      case 2:         assert((address & 1) == 0);         if(s->big_endian)             value = htons((unsigned short)value);         *(short*)ptr = (unsigned short)value;          break;      case 1:         *(char*)ptr = (unsigned char)value;          break;      default:          printf("ERROR");   }}#ifdef ENABLE_CACHE/************* Optional MMU and cache implementation *************//* TAG = VirtualAddress | ProcessId | WriteableBit */unsigned long mmu_lookup(State *s, unsigned long processId,                          unsigned long address, int write){   int i;   unsigned long compare, tag;   if(processId == 0 || s->userMode == 0)      return address;   //if(address < 0x30000000)   //   return address;   compare = (address & ~MMU_MASK) | (processId << 1);   for(i = 0; i < MMU_ENTRIES; ++i)   {      tag = s->mmuEntry[i].virtualAddress;      if((tag & ~1) == compare && (write == 0 || (tag & 1)))         return s->mmuEntry[i].physicalAddress | (address & MMU_MASK);   }   //printf("\nMMUTlbMiss 0x%x PC=0x%x w=%d pid=%d user=%d\n",    //   address, s->pc, write, processId, s->userMode);   //printf("m");   s->exceptionId = 1;   s->faultAddr = address & ~MMU_MASK;   s->irqStatus |= IRQ_MMU;   return address;}#define CACHE_SET_ASSOC_LN2   0#define CACHE_SET_ASSOC       (1 << CACHE_SET_ASSOC_LN2)#define CACHE_SIZE_LN2        (13 - CACHE_SET_ASSOC_LN2)  //8 KB#define CACHE_SIZE            (1 << CACHE_SIZE_LN2)#define CACHE_LINE_SIZE_LN2   5                           //32 bytes#define CACHE_LINE_SIZE       (1 << CACHE_LINE_SIZE_LN2)static long cacheData[CACHE_SET_ASSOC][CACHE_SIZE/sizeof(long)];static long cacheAddr[CACHE_SET_ASSOC][CACHE_SIZE/CACHE_LINE_SIZE];static long cacheSetNext;static long cacheMiss, cacheWriteBack, cacheCount;static void cache_init(void){   int set, i;   for(set = 0; set < CACHE_SET_ASSOC; ++set)   {      for(i = 0; i < CACHE_SIZE/CACHE_LINE_SIZE; ++i)         cacheAddr[set][i] = 0xffff0000;   }}/* Write-back cache memory tagged by virtual address and processId *//* TAG = virtualAddress | processId | dirtyBit */static int cache_load(State *s, unsigned long address, int write){   int set, i, pid, miss, offsetAddr, offsetData, offsetMem;   unsigned long addrTagMatch, addrPrevMatch=0;   unsigned long addrPrev;   unsigned long addressPhysical, tag;   ++cacheCount;   addrTagMatch = address & ~(CACHE_SIZE-1);   offsetAddr = (address & (CACHE_SIZE-1)) >> CACHE_LINE_SIZE_LN2;   /* Find match */   miss = 1;   for(set = 0; set < CACHE_SET_ASSOC; ++set)   {      addrPrevMatch = cacheAddr[set][offsetAddr] & ~(CACHE_SIZE-1);      if(addrPrevMatch == addrTagMatch)      {         miss = 0;         break;      }   }   /* Cache miss? */   if(miss)   {      ++cacheMiss;      set = cacheSetNext;      cacheSetNext = (cacheSetNext + 1) & (CACHE_SET_ASSOC-1);   }   else if(write || (address >> 28) != 0x1)   {      tag = cacheAddr[set][offsetAddr];      pid = (tag & (CACHE_SIZE-1)) >> 1;       if(pid != s->processId)         miss = 1;   }   if(miss)   {      offsetData = address & (CACHE_SIZE-1) & ~(CACHE_LINE_SIZE-1);      /* Cache line dirty? */      if(cacheAddr[set][offsetAddr] & 1)      {         /* Write back cache line */         tag = cacheAddr[set][offsetAddr];         addrPrev = tag & ~(CACHE_SIZE-1);         addrPrev |= address & (CACHE_SIZE-1);         pid = (tag & (CACHE_SIZE-1)) >> 1;          addressPhysical = mmu_lookup(s, pid, addrPrev, 1);   //virtual->physical         if(s->exceptionId)            return 0;         offsetMem = addressPhysical & ~(CACHE_LINE_SIZE-1);         for(i = 0; i < CACHE_LINE_SIZE; i += 4)            mem_write(s, 4, offsetMem + i, cacheData[set][(offsetData + i) >> 2]);         ++cacheWriteBack;      }      /* Read cache line */      addressPhysical = mmu_lookup(s, s->processId, address, write); //virtual->physical      if(s->exceptionId)         return 0;      offsetMem = addressPhysical & ~(CACHE_LINE_SIZE-1);      cacheAddr[set][offsetAddr] = addrTagMatch;      for(i = 0; i < CACHE_LINE_SIZE; i += 4)         cacheData[set][(offsetData + i) >> 2] = mem_read(s, 4, offsetMem + i);   }   cacheAddr[set][offsetAddr] |= write;   return set;}static long cache_read(State *s, long size, unsigned long address){   int set, offset;   long value;   if((address >> 28) == 0x2) // && (s->processId == 0 || s->userMode == 0))      return mem_read(s, size, address);   set = cache_load(s, address, 0);   if(s->exceptionId)      return 0;   offset = (address & (CACHE_SIZE-1)) >> 2;   value = cacheData[set][offset];   if(s->big_endian)      address ^= 3;   switch(size)    {      case 2:          value = (value >> ((address & 2) << 3)) & 0xffff;         break;      case 1:         value = (value >> ((address & 3) << 3)) & 0xff;         break;   }   return value;}static void cache_write(State *s, long size, long unsigned address, unsigned long value){   int set, offset;   unsigned long mask;   if((address >> 28) == 0x2) // && (s->processId == 0 || s->userMode == 0))   {      mem_write(s, size, address, value);      return;   }   set = cache_load(s, address, 1);   if(s->exceptionId)      return;   offset = (address & (CACHE_SIZE-1)) >> 2;   if(s->big_endian)      address ^= 3;   switch(size)    {      case 2:         value &= 0xffff;         value |= value << 16;         mask = 0xffff << ((address & 2) << 3);         break;      case 1:         value &= 0xff;         value |= (value << 8) | (value << 16) | (value << 24);         mask = 0xff << ((address & 3) << 3);         break;      case 4:      default:         mask = 0xffffffff;         break;   }   cacheData[set][offset] = (value & mask) | (cacheData[set][offset] & ~mask);}#define mem_read cache_read#define mem_write cache_write/************* End optional cache implementation *************/#elsestatic void cache_init(void) {}#endifvoid mult_big(unsigned long a,               unsigned long b,              unsigned long *hi,               unsigned long *lo){   unsigned long ahi, alo, bhi, blo;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -