📄 mlite.c
字号:
/*--------------------------------------------------------------------- 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 + -