Subversion Repositories mlite
Compare Revisions
- This comparison shows the changes necessary to convert path
/
- from Rev 1 to Rev 2
- ↔ Reverse comparison
Rev 1 → Rev 2
/*------------------------------------------------------------------- |
-- TITLE: MIPS CPU test code |
-- AUTHOR: Steve Rhoads (rhoadss@yahoo.com) |
-- DATE CREATED: 4/21/01 |
-- FILENAME: test.c |
-- PROJECT: MIPS CPU core |
-- COPYRIGHT: Software placed into the public domain by the author. |
-- Software 'as is' without warranty. Author liable for nothing. |
-- DESCRIPTION: |
-- The executable image of this file is used as input to the VHDL. |
-- |
-- This file must not contain any global or static data since |
-- there isn't a loader to relocate the .data segment and since |
-- having static data causes the opcodes to begin at a different |
-- location in the resulting executable file. |
-- |
-- After being compiled with the Microsoft MIPS compiler, the program |
-- convert will pull out the MIPS opcodes, and switch the executable |
-- to Big Endian, and convert absolute jumps into relative jumps, |
-- and save the opcodes in "code.txt". |
--------------------------------------------------------------------*/ |
#ifdef SIMULATE |
#undef putchar |
// The MIPS CPU VHDL supports a virtual UART. All character writes |
// to address 0xffff will be stored in the file "output.txt". |
#define putchar(C) *(volatile unsigned char*)0xffff=(unsigned char)(C) |
#endif |
|
//The main entry point must be the first function |
//The program convert will change the first opcode to setting |
//the stack pointer. |
int main() |
{ |
int main2(); |
main2(); |
} |
|
char *strcpy2(char *s, const char *t) |
{ |
char *tmp=s; |
while((int)(*s++=*t++)); |
return(tmp); |
} |
|
static void itoa2(long n, char *s, int base, long *digits) |
{ |
long i,j,sign; |
unsigned long n2; |
char number[20]; |
for(i=0;i<15;++i) number[i]=' '; |
number[15]=0; |
if(n>=0||base!=10) sign=1; |
else sign=-1; |
n2=n*sign; |
for(j=14;j>=0;--j) { |
i=n2%base; |
n2/=base; |
number[j]=i<10?'0'+i:'a'+i-10; |
if(n2==0&&15-j>=*digits) break; |
} |
if(sign==-1) { |
number[--j]='-'; |
} |
if(*digits==0||*digits<15-j) { |
strcpy2(s,&number[j]); |
*digits=15-j; |
} else { |
strcpy2(s,&number[15-*digits]); |
} |
} |
|
void print(long num,long base,long digits) |
{ |
volatile unsigned char *uart_base = (unsigned char *)0xffff; |
char *ptr,buffer[128]; |
itoa2(num,buffer,base,&digits); |
ptr=buffer; |
while(*ptr) { |
putchar(*ptr++); /* Put the character out */ |
if(ptr[-1]=='\n') *--ptr='\r'; |
} |
} |
|
void print_hex(unsigned long num) |
{ |
long i; |
unsigned long j; |
for(i=28;i>=0;i-=4) { |
j=((num>>i)&0xf); |
if(j<10) putchar('0'+j); |
else putchar('a'-10+j); |
} |
} |
|
int prime() |
{ |
int i,j,k; |
//show all prime numbers less than 1000 |
for(i=3;i<1000;i+=2) { |
for(j=3;j<i;j+=2) { |
if(i%j==0) { |
j=0; |
break; |
} |
} |
if(j) { |
print(i,10,0); |
putchar(' '); |
} |
} |
putchar('\n'); |
return 0; |
} |
|
int main2() |
{ |
long i,j,k; |
unsigned long m; |
char char_buf[16]; |
short short_buf[16]; |
long long_buf[16]; |
|
//test shift |
j=0x12345678; |
for(i=0;i<32;++i) { |
print_hex(j>>i); |
putchar(' '); |
} |
putchar('\n'); |
j=0x92345678; |
for(i=0;i<32;++i) { |
print_hex(j>>i); |
putchar(' '); |
} |
putchar('\n'); |
j=0x12345678; |
for(i=0;i<32;++i) { |
print_hex(j<<i); |
putchar(' '); |
} |
putchar('\n'); |
putchar('\n'); |
|
//test multiply and divide |
j=7; |
for(i=0;i<=10;++i) { |
print(j*i,10,0); |
putchar(' '); |
} |
putchar('\n'); |
j=0x321; |
for(i=0;i<=5;++i) { |
print_hex(j*(i+0x12345)); |
putchar(' '); |
} |
putchar('\n'); |
j=0x54321; |
for(i=0;i<=5;++i) { |
print_hex(j*(i+0x123)); |
putchar(' '); |
} |
putchar('\n'); |
j=0x12345; |
for(i=1;i<10;++i) { |
print_hex(j/i); |
putchar(' '); |
} |
putchar('\n'); |
for(i=1;i<10;++i) { |
print_hex(j%i); |
putchar(' '); |
} |
putchar('\n'); |
putchar('\n'); |
|
//test addition and subtraction |
j=0x1234; |
for(i=0;i<10;++i) { |
print_hex(j+i); |
putchar(' '); |
} |
putchar('\n'); |
for(i=0;i<10;++i) { |
print_hex(j-i); |
putchar(' '); |
} |
putchar('\n'); |
putchar('\n'); |
|
//test bit operations |
i=0x1234; |
j=0x4321; |
print_hex(i&j); |
putchar(' '); |
print_hex(i|j); |
putchar(' '); |
print_hex(i^j); |
putchar(' '); |
print_hex(~i); |
putchar(' '); |
print_hex(i+0x12); |
putchar(' '); |
print_hex(i-0x12); |
putchar('\n'); |
putchar('\n'); |
|
//test memory access |
for(i=0;i<10;++i) { |
char_buf[i]=i; |
short_buf[i]=i; |
long_buf[i]=i; |
} |
for(i=0;i<10;++i) { |
j=char_buf[i]; |
print(j,10,0); |
putchar(' '); |
j=short_buf[i]; |
print(j,10,0); |
putchar(' '); |
j=long_buf[i]; |
print(j,10,0); |
putchar('\n'); |
} |
putchar('\n'); |
|
prime(); |
|
putchar('d'); putchar('o'); putchar('n'); putchar('e'); putchar('\n'); |
|
} |
|
//convert.c by Steve Rhoads 4/26/01 |
//This program takes a little-endian MIPS executable and |
//converts it to a big-endian executable and changes |
//absolute jumps to branches. |
#include <stdio.h> |
#include <stdlib.h> |
|
#define BUF_SIZE (1024*1024) |
#define CODE_OFFSET 0x200 |
|
int main(int argc,char *argv[]) |
{ |
FILE *infile,*outfile; |
unsigned char *buf; |
long size,i,j; |
unsigned long d; |
infile=fopen("test.exe","rb"); |
if(infile==NULL) { |
printf("Can't open test.exe"); |
return 0; |
} |
buf=(unsigned char*)malloc(BUF_SIZE); |
size=fread(buf,1,BUF_SIZE,infile); |
fclose(infile); |
outfile=fopen("code.txt","w"); |
infile=fopen("test2.exe","wb"); |
for(i=CODE_OFFSET;i<size;i+=4) { |
d=(buf[i+3]<<24)|(buf[i+2]<<16)|(buf[i+1]<<8)|buf[i]; |
if((d>>24)==0x0c) { //JAL |
j=(d&0xfffff)-0x400-((i-CODE_OFFSET)>>2)-1; //BGEZAL |
d=0x04110000+(j&0xffff); |
} |
if(i==CODE_OFFSET) { |
d=0x341d8000; //ori $29,0,0x8000 |
} |
fprintf(outfile,"%8.8x\n",d); |
fwrite(&d,4,1,infile); |
} |
fclose(outfile); |
fclose(infile); |
free(buf); |
return 0; |
} |
|
/*------------------------------------------------------------------- |
-- TITLE: MIPS CPU simulator |
-- AUTHOR: Steve Rhoads (rhoadss@yahoo.com) |
-- DATE CREATED: 1/31/01 |
-- FILENAME: mips.c |
-- PROJECT: MIPS CPU core |
-- COPYRIGHT: Software placed into the public domain by the author. |
-- Software 'as is' without warranty. Author liable for nothing. |
-- DESCRIPTION: |
-- MIPS CPU simulator in C code. |
-- This file served as the starting point for the VHDL code. |
--------------------------------------------------------------------*/ |
#include <stdio.h> |
#include <stdlib.h> |
#include <ctype.h> |
|
#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) |
|
int getch(void); |
|
typedef struct { |
long r[32]; |
long pc,pc_next; |
long hi; |
long lo; |
long skip; |
char *mem; |
long wakeup; |
long big_endian; |
} 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 long big_endian=0; |
|
static long mem_read(State *s,long size,unsigned long address) |
{ |
long value=0; |
address%=MEM_SIZE; |
address+=(long)s->mem; |
switch(size) { |
case 4: value=*(long*)address; |
if(big_endian) value=ntohl(value); |
break; |
case 2: if(big_endian) address^=2; |
value=*(unsigned short*)address; |
if(big_endian) value=ntohs((unsigned short)value); |
break; |
case 1: if(big_endian) address^=3; |
value=*(unsigned char*)address; |
break; |
default: printf("ERROR"); |
} |
return(value); |
} |
|
static void mem_write(State *s,long size,long unsigned address,long value) |
{ |
static char_count=0; |
if(address==0xffff) { //UART write register at 0xffff |
if(isprint(value)) { |
printf("%c",value); |
if(++char_count>=72) { |
printf("\n"); |
char_count=0; |
} |
} else if(value=='\n') { |
printf("\n"); |
char_count=0; |
} else { |
printf("."); |
} |
} |
address%=MEM_SIZE; |
address+=(long)s->mem; |
switch(size) { |
case 4: if(big_endian) value=htonl(value); |
*(long*)address=value; |
break; |
case 2: |
if(big_endian) { |
address^=2; |
value=htons((unsigned short)value); |
} |
*(short*)address=(short)value; |
break; |
case 1: if(big_endian) address^=3; |
*(char*)address=(char)value; |
break; |
default: printf("ERROR"); |
} |
} |
|
//execute one cycle of a MIPS CPU |
void cycle(State *s,int show_mode) |
{ |
volatile unsigned long opcode; |
volatile unsigned long op,rs,rt,rd,re,func,imm,target; |
volatile long imm_shift,branch=0,lbranch=2; |
volatile long *r=s->r; |
volatile unsigned long *u=(unsigned long*)s->r; |
volatile unsigned long ptr; |
opcode=mem_read(s,4,s->pc); |
op=(opcode>>26)&0x3f; |
rs=(opcode>>21)&0x1f; |
rt=(opcode>>16)&0x1f; |
rd=(opcode>>11)&0x1f; |
re=(opcode>>6)&0x1f; |
func=opcode&0x3f; |
imm=opcode&0xffff; |
imm_shift=(((long)(short)imm)<<2)-4; |
target=(opcode<<6)>>4; |
ptr=(short)imm+r[rs]; |
r[0]=0; |
if(show_mode) { |
printf("%8.8lx %8.8lx ",s->pc,opcode); |
if(op==0) printf("%8s ",special_string[func]); |
else if(op==1) printf("%8s ",regimm_string[rt]); |
else printf("%8s ",opcode_string[op]); |
printf("$%2.2ld $%2.2ld $%2.2ld $%2.2ld ",rs,rt,rd,re); |
printf("%4.4lx\n",imm); |
} |
if(show_mode>5) return; |
s->pc=s->pc_next; |
s->pc_next=s->pc_next+4; |
if(s->skip) { |
s->skip=0; |
return; |
} |
switch(op) { |
case 0x00:/*SPECIAL*/ |
switch(func) { |
case 0x00:/*SLL*/ r[rd]=r[rt]<<re; break; |
case 0x02:/*SRL*/ r[rd]=u[rt]>>re; break; |
case 0x03:/*SRA*/ r[rd]=r[rt]>>re; break; |
case 0x04:/*SLLV*/ r[rd]=r[rt]<<r[rs]; break; |
case 0x06:/*SRLV*/ r[rd]=u[rt]>>r[rs]; break; |
case 0x07:/*SRAV*/ r[rd]=r[rt]>>r[rs]; break; |
case 0x08:/*JR*/ s->pc_next=r[rs]; break; |
case 0x09:/*JALR*/ r[rd]=s->pc_next; s->pc_next=r[rs]; break; |
case 0x0a:/*MOVZ*/ if(!r[rt]) r[rd]=r[rs]; break; /*IV*/ |
case 0x0b:/*MOVN*/ if(r[rt]) r[rd]=r[rs]; break; /*IV*/ |
case 0x0c:/*SYSCALL*/ break; |
case 0x0d:/*BREAK*/ s->wakeup=1; break; |
case 0x0f:/*SYNC*/ s->wakeup=1; break; |
case 0x10:/*MFHI*/ r[rd]=s->hi; break; |
case 0x11:/*FTHI*/ s->hi=r[rs]; break; |
case 0x12:/*MFLO*/ r[rd]=s->lo; break; |
case 0x13:/*MTLO*/ s->lo=r[rs]; break; |
case 0x18:/*MULT*/ s->lo=r[rs]*r[rt]; s->hi=0; break; |
case 0x19:/*MULTU*/ s->lo=r[rs]*r[rt]; s->hi=0; break; |
case 0x1a:/*DIV*/ s->lo=r[rs]/r[rt]; s->hi=r[rs]%r[rt]; break; |
case 0x1b:/*DIVU*/ s->lo=r[rs]/r[rt]; s->hi=r[rs]%r[rt]; break; |
case 0x20:/*ADD*/ r[rd]=r[rs]+r[rt]; break; |
case 0x21:/*ADDU*/ r[rd]=r[rs]+r[rt]; break; |
case 0x22:/*SUB*/ r[rd]=r[rs]-r[rt]; break; |
case 0x23:/*SUBU*/ r[rd]=r[rs]-r[rt]; break; |
case 0x24:/*AND*/ r[rd]=r[rs]&r[rt]; break; |
case 0x25:/*OR*/ r[rd]=r[rs]|r[rt]; break; |
case 0x26:/*XOR*/ r[rd]=r[rs]^r[rt]; break; |
case 0x27:/*NOR*/ r[rd]=~(r[rs]|r[rt]); break; |
case 0x2a:/*SLT*/ r[rd]=r[rs]<r[rt]; break; |
case 0x2b:/*SLTU*/ r[rd]=u[rs]<u[rt]; break; |
case 0x2d:/*DADDU*/r[rd]=r[rs]+u[rt]; break; |
case 0x31:/*TGEU*/ break; |
case 0x32:/*TLT*/ break; |
case 0x33:/*TLTU*/ break; |
case 0x34:/*TEQ*/ break; |
case 0x36:/*TNE*/ break; |
default: printf("ERROR0(*0x%x~0x%x)\n",s->pc,opcode); |
s->wakeup=1; |
} |
break; |
case 0x01:/*REGIMM*/ |
switch(rt) { |
case 0x10:/*BLTZAL*/ r[31]=s->pc_next; |
case 0x00:/*BLTZ*/ branch=r[rs]<0; break; |
case 0x11:/*BGEZAL*/ r[31]=s->pc_next; |
case 0x01:/*BGEZ*/ branch=r[rs]>=0; break; |
case 0x12:/*BLTZALL*/r[31]=s->pc_next; |
case 0x02:/*BLTZL*/ lbranch=r[rs]<0; break; |
case 0x13:/*BGEZALL*/r[31]=s->pc_next; |
case 0x03:/*BGEZL*/ lbranch=r[rs]>=0; break; |
default: printf("ERROR1\n"); s->wakeup=1; |
} |
break; |
case 0x03:/*JAL*/ r[31]=s->pc_next; |
case 0x02:/*J*/ s->pc_next=(s->pc&0xf0000000)|target; break; |
case 0x04:/*BEQ*/ branch=r[rs]==r[rt]; break; |
case 0x05:/*BNE*/ branch=r[rs]!=r[rt]; break; |
case 0x06:/*BLEZ*/ branch=r[rs]<=0; break; |
case 0x07:/*BGTZ*/ branch=r[rs]>0; break; |
case 0x08:/*ADDI*/ r[rt]=r[rs]+(short)imm; break; |
case 0x09:/*ADDIU*/ u[rt]=u[rs]+(short)imm; break; |
case 0x0a:/*SLTI*/ r[rt]=r[rs]<(short)imm; break; |
case 0x0b:/*SLTIU*/ u[rt]=u[rs]<(unsigned long)(short)imm; break; |
case 0x0c:/*ANDI*/ r[rt]=r[rs]&imm; break; |
case 0x0d:/*ORI*/ r[rt]=r[rs]|imm; break; |
case 0x0e:/*XORI*/ r[rt]=r[rs]^imm; break; |
case 0x0f:/*LUI*/ r[rt]=(imm<<16); break; |
case 0x10:/*COP0*/ break; |
// case 0x11:/*COP1*/ break; |
// case 0x12:/*COP2*/ break; |
// case 0x13:/*COP3*/ break; |
case 0x14:/*BEQL*/ lbranch=r[rs]==r[rt]; break; |
case 0x15:/*BNEL*/ lbranch=r[rs]!=r[rt]; break; |
case 0x16:/*BLEZL*/ lbranch=r[rs]<=0; break; |
case 0x17:/*BGTZL*/ lbranch=r[rs]>0; break; |
// case 0x1c:/*MAD*/ break; /*IV*/ |
// case 0x20:/*LB*/ r[rt]=*(signed char*)ptr; break; |
case 0x20:/*LB*/ r[rt]=(signed char)mem_read(s,1,ptr); break; |
// case 0x21:/*LH*/ r[rt]=*(signed short*)ptr; break; |
case 0x21:/*LH*/ r[rt]=(signed short)mem_read(s,2,ptr); break; |
case 0x22:/*LWL*/ break; //fixme |
// case 0x23:/*LW*/ r[rt]=*(long*)ptr; break; |
case 0x23:/*LW*/ r[rt]=mem_read(s,4,ptr); break; |
// case 0x24:/*LBU*/ r[rt]=*(unsigned char*)ptr; break; |
case 0x24:/*LBU*/ r[rt]=(unsigned char)mem_read(s,2,ptr); break; |
// case 0x25:/*LHU*/ r[rt]=*(unsigned short*)ptr; break; |
case 0x25:/*LHU*/ r[rt]=(unsigned short)mem_read(s,2,ptr); break; |
case 0x26:/*LWR*/ break; //fixme |
// case 0x28:/*SB*/ *(char*)ptr=(char)r[rt]; break; |
case 0x28:/*SB*/ mem_write(s,1,ptr,r[rt]); break; |
// case 0x29:/*SH*/ *(short*)ptr=(short)r[rt]; break; |
case 0x29:/*SH*/ mem_write(s,2,ptr,r[rt]); break; |
case 0x2a:/*SWL*/ break; //fixme |
// case 0x2b:/*SW*/ *(long*)ptr=r[rt]; break; |
case 0x2b:/*SW*/ mem_write(s,4,ptr,r[rt]); break; |
case 0x2e:/*SWR*/ break; //fixme |
case 0x2f:/*CACHE*/break; |
// case 0x30:/*LL*/ r[rt]=*(long*)ptr; break; |
case 0x30:/*LL*/ r[rt]=mem_read(s,4,ptr); break; |
// case 0x31:/*LWC1*/ break; |
// case 0x32:/*LWC2*/ break; |
// case 0x33:/*LWC3*/ break; |
// case 0x35:/*LDC1*/ break; |
// case 0x36:/*LDC2*/ break; |
// case 0x37:/*LDC3*/ break; |
// case 0x38:/*SC*/ *(long*)ptr=r[rt]; r[rt]=1; break; |
case 0x38:/*SC*/ mem_write(s,4,ptr,r[rt]); r[rt]=1; break; |
// case 0x39:/*SWC1*/ break; |
// case 0x3a:/*SWC2*/ break; |
// case 0x3b:/*SWC3*/ break; |
// case 0x3d:/*SDC1*/ break; |
// case 0x3e:/*SDC2*/ break; |
// case 0x3f:/*SDC3*/ break; |
default: printf("ERROR2\n"); s->wakeup=1; |
} |
s->pc_next+=branch|(lbranch==1)?imm_shift:0; |
s->skip=(lbranch==0); |
} |
|
void show_state(State *s) |
{ |
long i,j; |
for(i=0;i<4;++i) { |
printf("%2.2ld ",i*8); |
for(j=0;j<8;++j) { |
printf("%8.8lx ",s->r[i*8+j]); |
} |
printf("\n"); |
} |
printf("%8.8lx %8.8lx %8.8lx %8.8lx\n",s->pc,s->pc_next,s->hi,s->lo); |
j=s->pc; |
for(i=-4;i<=8;++i) { |
printf("%c",i==0?'*':' '); |
s->pc=j+i*4; |
cycle(s,10); |
} |
s->pc=j; |
} |
|
void do_debug(State *s) |
{ |
int ch; |
long i,j=0,watch=0,addr; |
s->pc_next=s->pc+4; |
s->skip=0; |
s->wakeup=0; |
show_state(s); |
for(;;) { |
if(watch) printf("0x%8.8lx=0x%8.8lx\n",watch,mem_read(s,4,watch)); |
printf("1=Debug 2=Trace 3=Step 4=BreakPt 5=Go 6=Memory "); |
printf("7=Watch 8=Jump 9=Quit> "); |
ch=getch(); |
printf("\n"); |
switch(ch) { |
case '1': case 'd': case ' ': cycle(s,0); show_state(s); break; |
case '2': case 't': cycle(s,0); printf("*"); cycle(s,10); break; |
case '3': case 's': |
printf("Count> "); |
scanf("%ld",&j); |
for(i=0;i<j;++i) cycle(s,0); |
show_state(s); |
break; |
case '4': case 'b': |
printf("Line> "); |
scanf("%lx",&j); |
break; |
case '5': case 'g': |
s->wakeup=0; |
while(s->wakeup==0) { |
if(s->pc==j) break; |
cycle(s,0); |
} |
show_state(s); |
break; |
case '6': case 'm': |
printf("Memory> "); |
scanf("%lx",&j); |
for(i=0;i<8;++i) { |
printf("%8.8lx ",mem_read(s,4,j+i*4)); |
} |
printf("\n"); |
break; |
case '7': case 'w': |
printf("Watch> "); |
scanf("%lx",&watch); |
break; |
case '8': case 'j': |
printf("Jump> "); |
scanf("%lx",&addr); |
s->pc=addr; |
s->pc_next=addr+4; |
show_state(s); |
break; |
case '9': case 'q': return; |
} |
} |
} |
/************************************************************/ |
|
int main(int argc,char *argv[]) |
{ |
State state,*s=&state; |
FILE *in; |
long i,k; |
printf("MIPS emulator\n"); |
memset(s,0,sizeof(State)); |
s->big_endian=0; |
s->mem=malloc(MEM_SIZE); |
if(argc<=1) { |
printf(" Usage: mips file.exe\n"); |
printf(" mips file.exe B {for big_endian}\n"); |
printf(" mips file.exe DD {disassemble}\n"); |
printf(" mips file.exe BD {disassemble big_endian}\n"); |
return 0; |
} |
in=fopen(argv[1],"rb"); |
if(in==NULL) { printf("Can't open file %s!\n",argv[1]); getch(); return(0); } |
i=fread(s->mem,1,MEM_SIZE,in); |
fclose(in); |
printf("Read %ld bytes.\n",i); |
if(argc==3&&argv[2][0]=='B') { |
printf("Big Endian\n"); |
s->big_endian=1; |
big_endian=1; |
} |
if(argc==3&&argv[2][0]=='S') { /*make big endian*/ |
printf("Big Endian\n"); |
for(k=0;k<i+3;k+=4) { |
*(long*)&s->mem[k]=htonl(*(long*)&s->mem[k]); |
} |
in=fopen("big.exe","wb"); |
fwrite(s->mem,i,1,in); |
fclose(in); |
return(0); |
} |
if(argc==3&&argv[2][1]=='D') { /*dump image*/ |
for(k=0;k<i;k+=4) { |
s->pc=k; |
cycle(s,10); |
} |
free(s->mem); |
return(0); |
} |
s->pc=0x0; |
do_debug(s); |
free(s->mem); |
return(0); |
} |
|
+Description +
+MIPS-lite is a "clean room" VHDL implementation of a MIPS CPU. +It supports a simplified MIPS III+ instruction set with a two-stage pipeline. +Only User Mode instructions are supported. + +
+Block Diagram +
+
+Example Instruction +
+As an example, an ADD instruction would take the following steps: +
-
+
- The "pc_next" entity would pass the program + counter (PC) to the "mem_ctrl" entity. [First Stage of Pipeline] +
- "Mem_ctrl" passes the opcode to the "control" entity. +
- "Control" converts the 32-bit opcode to a 60-bit VLWI opcode + and sends control signals to the other entities. +
- Based on the rs_index and rt_index control signals, "reg_bank" + sends the 32-bit reg_source and reg_target to "bus_mux". +
- Based on the a_source and b_source control signals, "bus_mux" + multiplexes reg_source onto a_bus and reg_target onto b_bus. +
- Based on the alu_func control signals, "alu" adds the values + from a_bus and b_bus and places the result on c_bus. +
- Based on the c_source control signals, "bus_bux" multiplexes + c_bus onto reg_dest. +
- Based on the rd_index control signal, "reg_bank" saves + reg_dest into the correct register. +
+The CPU is implemented as a two-stage pipeline with step #1 in the
+first stage and steps #2-8 occurring the second stage.
+Each instruction takes one clock cycle, except memory accesses,
+which take two clock cycles, and multiplication and division, which
+can be accessed in 32 clock cycles.
+
+
+There are several control lines not shown in the diagram.
+A pause (wait-state) line will cause the pipeline to pause
+if the multiplication results are accessed before the
+multiplication is complete.
+
+
+Supporting Documentation +
+The implementation is based on information found in: +
-
+
- "MIPS RISC Architecture" by Gerry Kane and Joe Heinrich and +
- "The Designer's Guide to VHDL" by Peter J. Ashenden +
+The tools used include VHDL Synopsys, ModelTech, and the Microsoft +MIPS C compiler. + +
+Registers +
+All of the registers are clocked by the single master clock. +The registers used in the design are grouped by entity and listed below: +
+ mem_ctrl + =========================================== + | Register Name | Type | Width | + =========================================== + | next_opcode_reg_reg | Flip-flop | 32 | + | opcode_reg_reg | Flip-flop | 32 | + | setup_done_reg | Flip-flop | 1 | + =========================================== + + mult + =========================================== + | Register Name | Type | Width | + =========================================== + | answer_reg_reg | Flip-flop | 32 | + | count_reg_reg | Flip-flop | 6 | + | do_div_reg_reg | Flip-flop | 1 | + | do_signed_reg_reg | Flip-flop | 1 | + | reg_a_reg | Flip-flop | 32 | + | reg_b_reg | Flip-flop | 64 | + =========================================== + + pc_next + =========================================== + | Register Name | Type | Width | + =========================================== + | pc_reg_reg | Flip-flop | 30 | + =========================================== + + reg_bank + =========================================== + | Register Name | Type | Width | + =========================================== + | reg01_reg | Flip-flop | 32 | + | reg02_reg | Flip-flop | 32 | + | reg03_reg | Flip-flop | 32 | + | reg04_reg | Flip-flop | 32 | + | reg05_reg | Flip-flop | 32 | + | reg06_reg | Flip-flop | 32 | + | reg07_reg | Flip-flop | 32 | + | reg08_reg | Flip-flop | 32 | + | reg09_reg | Flip-flop | 32 | + | reg10_reg | Flip-flop | 32 | + | reg11_reg | Flip-flop | 32 | + | reg12_reg | Flip-flop | 32 | + | reg13_reg | Flip-flop | 32 | + | reg14_reg | Flip-flop | 32 | + | reg15_reg | Flip-flop | 32 | + | reg16_reg | Flip-flop | 32 | + | reg17_reg | Flip-flop | 32 | + | reg18_reg | Flip-flop | 32 | + | reg19_reg | Flip-flop | 32 | + | reg20_reg | Flip-flop | 32 | + | reg21_reg | Flip-flop | 32 | + | reg22_reg | Flip-flop | 32 | + | reg23_reg | Flip-flop | 32 | + | reg24_reg | Flip-flop | 32 | + | reg25_reg | Flip-flop | 32 | + | reg26_reg | Flip-flop | 32 | + | reg27_reg | Flip-flop | 32 | + | reg28_reg | Flip-flop | 32 | + | reg29_reg | Flip-flop | 32 | + | reg30_reg | Flip-flop | 32 | + | reg31_reg | Flip-flop | 32 | + | reg_epc_reg | Flip-flop | 32 | + | reg_status_reg | Flip-flop | 1 | + =========================================== ++ +Preliminary Synthesis +
+The CPU core was synthesized for 0.13 um line widths with a predicted
+area less than 0.2 millimeters squared. The predicted maximum
+latency was less than 6 ns for a maximum clock speed of 150 MHz.
+
+
+A preliminary synthesis yields the following cells and die area.
+I think that optimization caused the mips_cpu entity
+to be smaller than the sum of its
+components.
+If one assumes that a standard cell is composed of three gates,
+then this is approximately a 20K gate design. [Is this correct??]
+It is interesting to note that the register bank requires over 60% of the area.
+
+ Block ports nets cells cell_area ~% delay(ns) + ------ ----- ---- ----- --------- --- --------- + alu 101 919 850 7503 12 1.11 + bus_mux 283 672 486 4906 8 0.35 + control 93 296 263 2250 4 0.29 + mem_ctrl 271 455 318 3299 5 0.95 + mult 101 1111 1043 9342 15 0.72 ?? + pc_next 94 277 215 1756 3 0.15 + reg_bank 116 2650 2599 39477 62 1.02 + shifter 71 423 384 3026 5 1.51 + mips_cpu 201 555 45 63888 100 5.61 + + total 1331 7358 6203 ++ +List of Files +
+
-
+
FILE | +PURPOSE | +
makefile | +Makefile for the HP workstation for Synopsys | +
code.txt | +Input opcodes for the test bench -- test.exe "converted" | +
alu.vhd | +Arithmetic Logic Unit | +
bus_mux.vhd | +BUS Multiplex Unit | +
control.vhd | +Opcode Decoder | +
mem_ctrl.vhd | +Memory Controller | +
mips_cpu.vhd | +Top Level VHDL for MIPS CPU | +
mips_pack.vhd | +Constants and Functions Package | +
mult.vhd | +Multiplication and Division Unit | +
pc_next.vhd | +Program Counter Unit | +
ram.vhd | +RAM for the Test Bench | +
reg_bank.vhd | +Register Bank for 32, 32-bit Registers | +
shifter.vhd | +Shifter Unit | +
tbench.vhd | +Test Bench that uses mips_vpu.vhd and ram.vhd | +
makefile | +Makefile for the PC for creating "code.txt" | +
convert.c | +Converts test.exe to code.txt | +
mips.c | +Simulates a MIPS CPU in software | +
test.c | +Test program (opcodes) for the MIPS CPU | +
output.txt | +Output from the test bench | +
index.shtml | +This help file | +
cpu.gif | +Block Diagram | +
+ZIP File +
+CVS is the only way to download the latest files. However +for a quick look at an old version you can download +MIPSlite.zip. + +
+Convert +
+The program "convert" changes the file "test.exe" into the HEX file "code.txt". +The opcodes in "test.exe" are changed to Big Endian. +All absolute jumps are changed to relative jumps. +The first opcode is also changed to set up the stack pointer. + +
+Big/Little Endian +
+The MIPS CPU operates in Big Endian mode by default. To operate in +Little Endian mode, change "little_endian" from "00" to "11" in +the file mem_ctrl.vhd. + +
+Legal Notice +
+
+MIPS is a registered trademark of MIPS Technologies, Inc.
+If you use this core you are responsible for all legal issues.
+This "clean room" implementation of a MIPS CPU does not negate
+MIPS Technologies, Inc. of their trademark, copyrights, or patents....
+
+Free for commercial and non-commercial use as long as the author and
+warning notices are maintained.
+
+
+This software is provided by Steve Rhoads "as is" and
+any express or implied warranties, including, but not limited to, the
+implied warranties of merchantability and fitness for a particular purpose
+are disclaimed. In no event shall the author or contributors be liable
+for any direct, indirect, incidental, special, exemplary, or consequential
+damages (including, but not limited to, procurement of substitute goods
+or services; loss of use, data, or profits; or business interruption)
+however caused and on any theory of liability, whether in contract, strict
+liability, or tort (including negligence or otherwise) arising in any way
+out of the use of this software, even if advised of the possibility of
+such damage.
+
+
Bus Interface
++
+ port(clk : in std_logic; + reset_in : in std_logic; + intr_in : in std_logic; --interrupt line + + --memory access buses + mem_address : out std_logic_vector(31 downto 0); + mem_data_w : out std_logic_vector(31 downto 0); --avoided tri-state + mem_data_r : in std_logic_vector(31 downto 0); + mem_sel : out std_logic_vector(3 downto 0); --byte lines + mem_write : out std_logic; + mem_pause : in std_logic + ); ++ +
+Current Status +
-
+
- The test bench needs to be strengthened. +
- Need feedback on the design. +
- Need feedback on the tools. +
- Need to add simulation of a cache. +
+Maintainer +
- Steve Rhoads,
+rhoads@opencores.org_NOSPAM
+
- *** I am not an experienced VHDL designer ***
+Please let me know of any incorrect statements in this document.
+Mailing-list +
+
+ Index: trunk/tools/output.txt =================================================================== --- trunk/tools/output.txt (nonexistent) +++ trunk/tools/output.txt (revision 2) @@ -0,0 +1,43 @@ +12345678 091a2b3c 048d159e 02468acf 01234567 0091a2b3 0048d159 002468ac +00123456 00091a2b 00048d15 0002468a 00012345 000091a2 000048d1 00002468 +00001234 0000091a 0000048d 00000246 00000123 00000091 00000048 00000024 +00000012 00000009 00000004 00000002 00000001 00000000 00000000 00000000 + +92345678 c91a2b3c e48d159e f2468acf f9234567 fc91a2b3 fe48d159 ff2468ac +ff923456 ffc91a2b ffe48d15 fff2468a fff92345 fffc91a2 fffe48d1 ffff2468 +ffff9234 ffffc91a ffffe48d fffff246 fffff923 fffffc91 fffffe48 ffffff24 +ffffff92 ffffffc9 ffffffe4 fffffff2 fffffff9 fffffffc fffffffe ffffffff + +12345678 2468acf0 48d159e0 91a2b3c0 23456780 468acf00 8d159e00 1a2b3c00 +34567800 68acf000 d159e000 a2b3c000 45678000 8acf0000 159e0000 2b3c0000 +56780000 acf00000 59e00000 b3c00000 67800000 cf000000 9e000000 3c000000 +78000000 f0000000 e0000000 c0000000 80000000 00000000 00000000 00000000 + + +0 7 14 21 28 35 42 49 56 63 70 +038f5ae5 038f5e06 038f6127 038f6448 038f6769 038f6a8a +05fb4e83 060091a4 0605d4c5 060b17e6 06105b07 06159e28 +00012345 000091a2 00006117 000048d1 00003a41 0000308b 0000299c 00002468 +0000205d +00000000 00000001 00000000 00000001 00000000 00000003 00000001 00000005 +00000000 + +00001234 00001235 00001236 00001237 00001238 00001239 0000123a 0000123b +0000123c 0000123d +00001234 00001233 00001232 00001231 00001230 0000122f 0000122e 0000122d +0000122c 0000122b + +00000220 00005335 00005115 ffffedcb 00001246 00001222 + +0 0 0 +1 1 1 +2 2 2 +3 3 3 +4 4 4 +5 5 5 +6 6 6 +7 7 7 +8 8 8 +9 9 9 + +3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 101 Index: trunk/vhdl/mips_cpu.vhd =================================================================== --- trunk/vhdl/mips_cpu.vhd (nonexistent) +++ trunk/vhdl/mips_cpu.vhd (revision 2) @@ -0,0 +1,302 @@ +--------------------------------------------------------------------- +-- TITLE: MIPS CPU core +-- AUTHOR: Steve Rhoads (rhoadss@yahoo.com) +-- DATE CREATED: 2/15/01 +-- FILENAME: mips_cpu.vhd +-- PROJECT: MIPS CPU core +-- COPYRIGHT: Software placed into the public domain by the author. +-- Software 'as is' without warranty. Author liable for nothing. +-- DESCRIPTION: +-- Top level VHDL document that ties the eight other entities together. +-- Implements a MIPS CPU. Based on information found in: +-- "MIPS RISC Architecture" by Gerry Kane and Joe Heinrich +-- and "The Designer's Guide to VHDL" by Peter J. Ashenden +-- An add instruction would take the following steps (see cpu.gif): +-- 1. The "pc_next" entity would have previously passed the program +-- counter (PC) to the "mem_ctrl" entity. +-- 2. "Mem_ctrl" passes the opcode to the "control" entity. +-- 3. "Control" converts the 32-bit opcode to a 60-bit VLWI opcode +-- and sends control signals to the other entities. +-- 4. Based on the rs_index and rt_index control signals, "reg_bank" +-- sends the 32-bit reg_source and reg_target to "bus_mux". +-- 5. Based on the a_source and b_source control signals, "bus_mux" +-- multiplexes reg_source onto a_bus and reg_target onto b_bus. +-- 6. Based on the alu_func control signals, "alu" adds the values +-- from a_bus and b_bus and places the result on c_bus. +-- 7. Based on the c_source control signals, "bus_bux" multiplexes +-- c_bus onto reg_dest. +-- 8. Based on the rd_index control signal, "reg_bank" saves +-- reg_dest into the correct register. +-- The CPU is implemented as a two stage pipeline with step #1 in the +-- first stage and steps #2-8 occuring the second stage. +-- +-- The CPU core was synthesized for 0.13 um line widths with an area +-- of 0.2 millimeters squared. The maximum latency was less than 6 ns +-- for a maximum clock speed of 150 MHz. +--------------------------------------------------------------------- +library ieee; +use ieee.std_logic_1164.all; +use work.mips_pack.all; + +entity mips_cpu is + port(clk : in std_logic; + reset_in : in std_logic; + intr_in : in std_logic; + + mem_address : out std_logic_vector(31 downto 0); + mem_data_w : out std_logic_vector(31 downto 0); + mem_data_r : in std_logic_vector(31 downto 0); + mem_sel : out std_logic_vector(3 downto 0); + mem_write : out std_logic; + mem_pause : in std_logic; + + t_pc : out std_logic_vector(31 downto 0); + t_opcode : out std_logic_vector(31 downto 0); + t_r_dest : out std_logic_vector(31 downto 0) + ); +end; --entity mips_cpu + +architecture logic of mips_cpu is + +component pc_next + port(clk : in std_logic; + reset_in : in std_logic; + pc_new : in std_logic_vector(31 downto 2); + take_branch : in std_logic; + pause_in : in std_logic; + opcode25_0 : in std_logic_vector(25 downto 0); + pc_source : in pc_source_type; + pc_out : out std_logic_vector(31 downto 0)); +end component; + +component mem_ctrl + port(clk : in std_logic; + reset_in : in std_logic; + pause_in : in std_logic; + nullify_op : in std_logic; + address_pc : in std_logic_vector(31 downto 0); + opcode_out : out std_logic_vector(31 downto 0); + + address_data : in std_logic_vector(31 downto 0); + mem_source : in mem_source_type; + data_write : in std_logic_vector(31 downto 0); + data_read : out std_logic_vector(31 downto 0); + pause_out : out std_logic; + + mem_address : out std_logic_vector(31 downto 0); + mem_data_w : out std_logic_vector(31 downto 0); + mem_data_r : in std_logic_vector(31 downto 0); + mem_byte_sel : out std_logic_vector(3 downto 0); + mem_write : out std_logic; + mem_pause : in std_logic); +end component; + +component control + port(opcode : in std_logic_vector(31 downto 0); + intr_signal : in std_logic; + rs_index : out std_logic_vector(5 downto 0); + rt_index : out std_logic_vector(5 downto 0); + rd_index : out std_logic_vector(5 downto 0); + imm_out : out std_logic_vector(15 downto 0); + alu_func : out alu_function_type; + shift_func : out shift_function_type; + mult_func : out mult_function_type; + branch_func : out branch_function_type; + a_source_out : out a_source_type; + b_source_out : out b_source_type; + c_source_out : out c_source_type; + pc_source_out: out pc_source_type; + mem_source_out:out mem_source_type); +end component; + +component reg_bank + port(clk : in std_logic; + rs_index : in std_logic_vector(5 downto 0); + rt_index : in std_logic_vector(5 downto 0); + rd_index : in std_logic_vector(5 downto 0); + reg_source_out : out std_logic_vector(31 downto 0); + reg_target_out : out std_logic_vector(31 downto 0); + reg_dest_new : in std_logic_vector(31 downto 0); + intr_enable : out std_logic); +end component; + +component bus_mux + port(imm_in : in std_logic_vector(15 downto 0); + reg_source : in std_logic_vector(31 downto 0); + a_mux : in a_source_type; + a_out : out std_logic_vector(31 downto 0); + + reg_target : in std_logic_vector(31 downto 0); + b_mux : in b_source_type; + b_out : out std_logic_vector(31 downto 0); + + c_bus : in std_logic_vector(31 downto 0); + c_memory : in std_logic_vector(31 downto 0); + c_pc : in std_logic_vector(31 downto 0); + c_mux : in c_source_type; + reg_dest_out : out std_logic_vector(31 downto 0); + + branch_func : in branch_function_type; + take_branch : out std_logic); +end component; + +component alu + port(a_in : in std_logic_vector(31 downto 0); + b_in : in std_logic_vector(31 downto 0); + alu_function : in alu_function_type; + c_alu : out std_logic_vector(31 downto 0)); +end component; + +component shifter + port(value : in std_logic_vector(31 downto 0); + shift_amount : in std_logic_vector(4 downto 0); + shift_func : in shift_function_type; + c_shift : out std_logic_vector(31 downto 0)); +end component; + +component mult + port(clk : in std_logic; + a, b : in std_logic_vector(31 downto 0); + mult_func : in mult_function_type; + c_mult : out std_logic_vector(31 downto 0); + pause_out : out std_logic); +end component; + + signal opcode : std_logic_vector(31 downto 0); + signal rs_index, rt_index, rd_index : std_logic_vector(5 downto 0); + signal reg_source, reg_target, reg_dest : std_logic_vector(31 downto 0); + signal a_bus, b_bus, c_bus : std_logic_vector(31 downto 0); + signal c_alu, c_shift, c_mult, c_memory + : std_logic_vector(31 downto 0); + signal imm : std_logic_vector(15 downto 0); + signal pc : std_logic_vector(31 downto 0); + signal alu_function : alu_function_type; + signal shift_function : shift_function_type; + signal mult_function : mult_function_type; + signal branch_function: branch_function_type; + signal take_branch : std_logic; + signal a_source : a_source_type; + signal b_source : b_source_type; + signal c_source : c_source_type; + signal pc_source : pc_source_type; + signal mem_source : mem_source_type; + signal pause_mult : std_logic; + signal pause_memory : std_logic; + signal pause : std_logic; + signal nullify_op : std_logic; + signal intr_enable : std_logic; + signal intr_signal : std_logic; +-- signal mem_byte_sel : std_logic_vector(3 downto 0); +-- signal mem_write : std_logic; +begin --architecture + + pause <= pause_mult or pause_memory; + --nulify_op = pc_source==from_lbranch && take_branch=='0' + nullify_op <= pc_source(1) and pc_source(0) and not take_branch; + c_bus <= c_alu or c_shift or c_mult; + intr_signal <= (intr_in and intr_enable) and + (not pc_source(0) and not pc_source(1)); --from_inc4 + + u1: pc_next PORT MAP ( + clk => clk, + reset_in => reset_in, + take_branch => take_branch, + pause_in => pause, + pc_new => c_alu(31 downto 2), + opcode25_0 => opcode(25 downto 0), + pc_source => pc_source, + pc_out => pc); + + u2: mem_ctrl PORT MAP ( + clk => clk, + reset_in => reset_in, + pause_in => pause, + nullify_op => nullify_op, + address_pc => pc, + opcode_out => opcode, + + address_data => c_alu, + mem_source => mem_source, + data_write => reg_target, + data_read => c_memory, + pause_out => pause_memory, + + mem_address => mem_address, + mem_data_w => mem_data_w, + mem_data_r => mem_data_r, + mem_byte_sel => mem_sel, + mem_write => mem_write, + mem_pause => mem_pause); + + u3: control PORT MAP ( + opcode => opcode, + intr_signal => intr_signal, + rs_index => rs_index, + rt_index => rt_index, + rd_index => rd_index, + imm_out => imm, + alu_func => alu_function, + shift_func => shift_function, + mult_func => mult_function, + branch_func => branch_function, + a_source_out => a_source, + b_source_out => b_source, + c_source_out => c_source, + pc_source_out=> pc_source, + mem_source_out=> mem_source); + + u4: reg_bank port map ( + clk => clk, + rs_index => rs_index, + rt_index => rt_index, + rd_index => rd_index, + reg_source_out => reg_source, + reg_target_out => reg_target, + reg_dest_new => reg_dest, + intr_enable => intr_enable); + + u5: bus_mux port map ( + imm_in => imm, + reg_source => reg_source, + a_mux => a_source, + a_out => a_bus, + + reg_target => reg_target, + b_mux => b_source, + b_out => b_bus, + + c_bus => c_bus, + c_memory => c_memory, + c_pc => pc, + c_mux => c_source, + reg_dest_out => reg_dest, + + branch_func => branch_function, + take_branch => take_branch); + + u6: alu port map ( + a_in => a_bus, + b_in => b_bus, + alu_function => alu_function, + c_alu => c_alu); + + u7: shifter port map ( + value => b_bus, + shift_amount => a_bus(4 downto 0), + shift_func => shift_function, + c_shift => c_shift); + + u8: mult port map ( + clk => clk, + a => a_bus, + b => b_bus, + mult_func => mult_function, + c_mult => c_mult, + pause_out => pause_mult); + + t_pc <= pc; + t_opcode <= opcode; + t_r_dest <= reg_dest; + +end; --architecture logic + Index: trunk/vhdl/ram.vhd =================================================================== --- trunk/vhdl/ram.vhd (nonexistent) +++ trunk/vhdl/ram.vhd (revision 2) @@ -0,0 +1,113 @@ +--------------------------------------------------------------------- +-- TITLE: Random Access Memory +-- AUTHOR: Steve Rhoads (rhoadss@yahoo.com) +-- DATE CREATED: 4/21/01 +-- FILENAME: ram.vhd +-- PROJECT: MIPS CPU core +-- COPYRIGHT: Software placed into the public domain by the author. +-- Software 'as is' without warranty. Author liable for nothing. +-- DESCRIPTION: +-- Implements the RAM, reads the executable from "code.txt", +-- and saves a character to "output.txt" upon a write to 0xffff. +-- Modified from "The Designer's Guide to VHDL" by Peter J. Ashenden +--------------------------------------------------------------------- +library ieee; +use ieee.std_logic_1164.all; +use ieee.std_logic_misc.all; +use ieee.std_logic_arith.all; +use ieee.std_logic_textio.all; +use std.textio.all; + +use ieee.std_logic_unsigned.all; +use work.mips_pack.all; + +entity ram is + generic(load_file_name : string); + port(clk : in std_logic; + mem_byte_sel : in std_logic_vector(3 downto 0); + mem_write : in std_logic; + mem_address : in std_logic_vector; + mem_data_w : in std_logic_vector(31 downto 0); + mem_data_r : out std_logic_vector(31 downto 0)); +end; --entity ram + +architecture logic of ram is +begin + +ram_proc: process + variable data : std_logic_vector(31 downto 0); + variable d : std_logic_vector(31 downto 0); + variable datab : std_logic_vector(31 downto 0); + variable value : natural; + subtype word is std_logic_vector(mem_data_w'length-1 downto 0); + type storage_array is + array(natural range 0 to 2**mem_address'length-1) of word; + variable storage : storage_array; + variable index : natural; + file load_file : text is in load_file_name; + file store_file : text is out "output.txt"; + variable hex_file_line : line; + variable c : character; + variable line_length : natural := 0; +begin + --load in the ram executable image + index := 0; + while not endfile(load_file) loop + readline(load_file, hex_file_line); + hread(hex_file_line, data); + storage(index) := data; + index := index + 1; + end loop; + assert false report "done reading code" severity note; + + wait on clk; --wait for line noise to go away + + loop + wait on clk, mem_address, mem_write; + + --support putchar() when writing to address 0xffff + if rising_edge(clk) then + if mem_write = '1' and mem_address = ONES(15 downto 0) then + index := conv_integer(mem_data_w(6 downto 0)); + if index /= 10 then + c := character'val(index); + write(hex_file_line, c); + line_length := line_length + 1; + end if; + if index = 10 or line_length >= 72 then + writeline(store_file, hex_file_line); + line_length := 0; + end if; + end if; + end if; + + index := conv_integer(mem_address(mem_address'length-1 downto 2)); + data := storage(index); + + if mem_write = '0' then + mem_data_r <= data; + end if; + if mem_byte_sel(0) = '1' then + data(7 downto 0) := mem_data_w(7 downto 0); + end if; + if mem_byte_sel(1) = '1' then + data(15 downto 8) := mem_data_w(15 downto 8); + end if; + if mem_byte_sel(2) = '1' then + data(23 downto 16) := mem_data_w(23 downto 16); + end if; + if mem_byte_sel(3) = '1' then + data(31 downto 24) := mem_data_w(31 downto 24); + end if; + + if rising_edge(clk) then + if mem_write = '1' then + storage(index) := data; + end if; + end if; + end loop; +end process; + +end; --architecture logic + + Index: trunk/vhdl/control.vhd =================================================================== --- trunk/vhdl/control.vhd (nonexistent) +++ trunk/vhdl/control.vhd (revision 2) @@ -0,0 +1,440 @@ +--------------------------------------------------------------------- +-- TITLE: Controller / Opcode Decoder +-- AUTHOR: Steve Rhoads (rhoadss@yahoo.com) +-- DATE CREATED: 2/8/01 +-- FILENAME: control.vhd +-- PROJECT: MIPS CPU core +-- COPYRIGHT: Software placed into the public domain by the author. +-- Software 'as is' without warranty. Author liable for nothing. +-- DESCRIPTION: +-- Controls the CPU by decoding the opcode and generating control +-- signals to the rest of the CPU. +-- This entity decodes the MIPS opcode into a Very-Long-Word-Instruction. +-- The 32-bit opcode is converted to a +-- 6+6+6+16+5+2+3+3+2+2+3+2+4 = 60 bit VLWI opcode. +-- Based on information found in: +-- "MIPS RISC Architecture" by Gerry Kane and Joe Heinrich +-- and "The Designer's Guide to VHDL" by Peter J. Ashenden +--------------------------------------------------------------------- +library ieee; +use ieee.std_logic_1164.all; +use work.mips_pack.all; + +entity control is + port(opcode : in std_logic_vector(31 downto 0); + intr_signal : in std_logic; + rs_index : out std_logic_vector(5 downto 0); + rt_index : out std_logic_vector(5 downto 0); + rd_index : out std_logic_vector(5 downto 0); + imm_out : out std_logic_vector(15 downto 0); + alu_func : out alu_function_type; + shift_func : out shift_function_type; + mult_func : out mult_function_type; + branch_func : out branch_function_type; + a_source_out : out a_source_type; + b_source_out : out b_source_type; + c_source_out : out c_source_type; + pc_source_out: out pc_source_type; + mem_source_out:out mem_source_type); +end; --entity control + +architecture logic of control is +-- type alu_function_type is (alu_nothing, alu_add, alu_subtract, +-- alu_less_than, alu_less_than_signed, alu_equal, alu_not_equal, +-- alu_ltz, alu_lez, alu_eqz, alu_nez, alu_gez, alu_gtz, +-- alu_or, alu_and, alu_xor, alu_nor); +-- type shift_function_type is ( +-- shift_nothing, shift_left_unsigned, +-- shift_right_signed, shift_right_unsigned); +-- type mult_function_type is ( +-- mult_nothing, mult_read_lo, mult_read_hi, mult_write_lo, +-- mult_write_hi, mult_mult, mult_divide, mult_signed_divide); +-- type a_source_type is (from_reg_source, from_imm10_6); +-- type b_source_type is (from_reg_target, from_imm, from_signed_imm); +-- type c_source_type is (from_null, from_alu, from_shift, +-- from_mult, from_memory, from_pc, from_imm_shift16, +-- from_reg_source_nez, from_reg_source_eqz); +-- type pc_source_type is (from_inc4, from_inc8, from_reg_source, +-- from_opcode25_0, from_branch, from_lbranch); +begin + +control_proc: process(opcode, intr_signal) + variable op, func : std_logic_vector(5 downto 0); + variable rs, rt, rd : std_logic_vector(5 downto 0); + variable re, rtx : std_logic_vector(4 downto 0); + variable imm : std_logic_vector(15 downto 0); + variable alu_function : alu_function_type; + variable shift_function : shift_function_type; + variable mult_function : mult_function_type; + variable a_source : a_source_type; + variable b_source : b_source_type; + variable c_source : c_source_type; + variable pc_source : pc_source_type; + variable branch_function: branch_function_type; + variable mem_source : mem_source_type; +begin + alu_function := alu_nothing; + shift_function := shift_nothing; + mult_function := mult_nothing; + a_source := a_from_reg_source; + b_source := b_from_reg_target; + c_source := c_from_null; + pc_source := from_inc4; + branch_function := branch_eq; + mem_source := mem_none; + op := opcode(31 downto 26); + rs := '0' & opcode(25 downto 21); + rt := '0' & opcode(20 downto 16); + rtx := opcode(20 downto 16); + rd := '0' & opcode(15 downto 11); + re := opcode(10 downto 6); + func := opcode(5 downto 0); + imm := opcode(15 downto 0); + + case op is + when "000000" => --00 SPECIAL + case func is + when "000000" => --00 SLL r[rd]=r[rt]<