Microprocessor Simlation Source Code

 
/************************************************************************/
/******           Title      : Microprocessor Simulation           ******/
/******                                                            ******/
/******           Author     : Stephen Griffin                     ******/
/************************************************************************/
 
/************************************************************************/
/****** Pre-Processor Directives                                   ******/
/************************************************************************/
 
#include <stdio.h>
 
#define LDA 0
#define STA 1
#define BRK 2
#define JMP 3
#define BRA 4
#define ADD 5
#define SUB 6
#define MUL 7
#define DIV 8
#define CLA 9
#define CLC 10
#define DMP 11
 
//Extra Instructions
#define AND 12
#define DEC 13
#define BRO 14
#define BRU 15
 
#define MEMSIZE 16
 
/************************************************************************/
/****** Function Prototypes                                        ******/
/************************************************************************/
 
char Load_Memory_Data(void);		//Load memory image from file.
void Dump_Memory_Data(void);	//Save mem and regs to file.
void Initialise_CPU(void);		//Set registers to 0.
void Fetch(void);
void Decode(unsigned char *, unsigned char *);
void Execute(unsigned char, unsigned char, unsigned char *);
void Display_Registers(unsigned char);
 
/************************************************************************/
/****** Global Variables                                           ******/
/************************************************************************/
 
struct
{
	unsigned char MEM[MEMSIZE];
		
		struct
		{
		unsigned char ir;
		unsigned char acc;
		unsigned char pc;
		unsigned char mar;
		unsigned char mdr;
		unsigned char unf;
		unsigned char ovf;
		unsigned char crf;
		}reg;
}cpu;
 
/************************************************************************/
/****** Main Function                                              ******/
/************************************************************************/
 
void main(void)
{
	unsigned char opcode=0, operand=0, fdeloop=1;	//Local variables
 
	if(Load_Memory_Data())	/* only continue if memory data loaded */
	{
		Initialise_CPU();	/* set all regs to zero */
 
		Display_Registers(1); //display register names
 
		/* Loop - Fetch, Decode, Execute */
 
		while((fdeloop)&&(cpu.reg.pc<MEMSIZE))
		{
			Fetch();
			Decode(&opcode, &operand);	
			Execute(opcode, operand, &fdeloop);
			
			Display_Registers(0);	//display register values
		}
	}
}
 
/************************************************************************/
/****** Load Memory data                                           ******/
/************************************************************************/
 
char Load_Memory_Data(void)
{
	FILE *fp;				/* define file pointer */
	unsigned char c, addr=0;
	char filename[40];
 
	printf("\nEnter memory image file name: ");
	gets(filename);					/* get filename */
 
	printf("\nLoad Memory Data");
 
	if((fp=fopen(filename,"rb"))!=NULL)	//Open file, initialise fp 
	{
		while((addr<MEMSIZE)&&((c=fgetc(fp))!=EOF))
		{
			cpu.MEM[addr]=c;
			if(addr%4==0) printf("\n");
			printf("\tMEM[%d]=%d", addr, cpu.MEM[addr]);
			addr++;
		}
		fclose(fp);				//Close file
		return(1);				//tell main to continue
	}
	else
	/* Display messege and return zero if fopen returns NULL. */
	{
		printf("\nCould not open file \"%s\".\n\n", filename);
		return(0);				//tell main to stop
	}
}
 
/************************************************************************/
/****** Dump Memory Data                                           ******/
/************************************************************************/
 
void Dump_Memory_Data()
{
	FILE *fp;
	unsigned char addr;
 
	/* Create file to store memory and register data. */
	if((fp=fopen("CPU_DUMP.txt", "wt"))!=NULL)
	{
		/* Write memory data to file */
 
		fprintf(fp, "Memory Data\n");
 
		/* loop for each memory location
				and write memory data to the file */
		for(addr=0;addr<MEMSIZE;addr++)
			fprintf(fp, "MEM[%d]=%d\n", addr, cpu.MEM[addr]);
 
		/* Write register data to file */
 
		fprintf(fp, "\nCPU Registers\n");
		fprintf(fp, "ir=%d\n", cpu.reg.ir);
		fprintf(fp, "acc=%d\n", cpu.reg.acc);
		fprintf(fp, "pc=%d\n", cpu.reg.pc);
		fprintf(fp, "mar=%d\n", cpu.reg.mar);
		fprintf(fp, "mdr=%d\n", cpu.reg.mdr);
 
		/* write status register flags to file */
 
		fprintf(fp, "\nStatus Register\n");
		fprintf(fp, "unf=%d\n", cpu.reg.unf);	
		fprintf(fp, "ovf=%d\n", cpu.reg.ovf);	
		fprintf(fp, "crf=%d", cpu.reg.crf);	
 
		fclose(fp);			//close file
	}
	else	/* If fopen failed */
	{
		printf("Cannot create file \"CPU_Data.txt\".\n\n");
	}
}
 
/************************************************************************/
/****** Initialise CPU                                             ******/
/************************************************************************/
 
void Initialise_CPU(void)
{
	/* Set registers to zero and display result. */
 
	printf("\n\nInitialise CPU:");
 
	cpu.reg.acc = 0;
	printf("\tACC=%d, ", cpu.reg.acc);
 
	cpu.reg.pc  = 0;
	printf("\tPC=%d, ", cpu.reg.pc);
 
	cpu.reg.unf = 0;
	printf("\tUNF=%d, ", cpu.reg.unf);
 
	cpu.reg.ovf = 0;
	printf("\tOVF=%d, ", cpu.reg.ovf);
 
	cpu.reg.crf = 0;
	printf("\tCRF=%d.\n", cpu.reg.crf);
}
 
/************************************************************************/
/****** Fetch                                                      ******/
/************************************************************************/
 
void Fetch(void)
{
	/* copy pc to mar, then increment pc */
	cpu.reg.mar = cpu.reg.pc;
	cpu.reg.pc++;
 
	/* copy memory data to MDR, then from MDR to IR */
	cpu.reg.mdr = cpu.MEM[cpu.reg.mar];
	cpu.reg.ir = cpu.reg.mdr;
}
 
/************************************************************************/
/****** Decode                                                     ******/
/************************************************************************/
 
void Decode(unsigned char *opcode, unsigned char *operand)
{
	/* shift right 4 bits bits e.g. 10011101->00001001 */
	*opcode  = cpu.reg.ir>>4;
 
	/* mask first 4 bits e.g. 10011101->00001101 */
	*operand = cpu.reg.ir&15;
}
 
/************************************************************************/
/****** Execute                                                    ******/
/************************************************************************/
 
void Execute(unsigned char instruction, unsigned char address, unsigned char *fdeloop)
{
	cpu.reg.ir = instruction;	/* copy instruction to instruction register */
	cpu.reg.mar = address;		/* copy address to memory address register */
 
	switch(instruction)
	{
		case LDA:	/* copy MEM->mdr->acc */
					cpu.reg.mdr=cpu.MEM[cpu.reg.mar];
					cpu.reg.acc=cpu.reg.mdr;
 
					/* Reset flags */
					cpu.reg.unf=0;
					cpu.reg.ovf=0;
					cpu.reg.crf=0;
 
					printf("LDA %d", address);
					break;
	
		case STA:	/* copy acc->mdr->MEM */
					cpu.reg.mdr=cpu.reg.acc;
					cpu.MEM[cpu.reg.mar]=cpu.reg.mdr;
 
					/* reset flags */
					cpu.reg.unf=0;
					cpu.reg.ovf=0;
					cpu.reg.crf=0;
 
					printf("STA %d", address);
					break;
 
		case BRK:	/* stop fdeloop in main */
					*fdeloop=0;
 
					printf("BRK");
					break;
 
		case JMP:	/* copy mar->pc */
					cpu.reg.pc=cpu.reg.mar;
 
					printf("JMP %d", address);
					break;
 
		case BRA:	/* if carry flag is set,
						copy memory address to program counter */
					if(cpu.reg.crf)
						cpu.reg.pc=cpu.reg.mar;
 
					printf("BRA %d", address);
					break;
 
		case ADD:	/* copy mem->mdr */
					cpu.reg.mdr=cpu.MEM[cpu.reg.mar];
 
					/* test result for overflow */
					if(cpu.reg.acc+cpu.reg.mdr>255)
						cpu.reg.ovf=1;
					
					/* add mdr to acc */
					cpu.reg.acc+=cpu.reg.mdr;
 
					/* reset flags */
					cpu.reg.unf=0;
					cpu.reg.crf=0;
 
					printf("ADD %d", address);
					break;
 
		case SUB:	/* copy mem->mdr */
					cpu.reg.mdr=cpu.MEM[cpu.reg.mar];
					if(cpu.reg.acc-cpu.reg.mdr<0)
						cpu.reg.unf=1;
					cpu.reg.acc-=cpu.reg.mdr;
 
					/* reset flags */
					cpu.reg.ovf=0;
					cpu.reg.crf=0;
 
					printf("SUB %d", address);
					break;
 
		case MUL:	/* copy mem->mdr */
					cpu.reg.mdr=cpu.MEM[cpu.reg.mar];
 
					/* set overflow if result>255 */
					if(cpu.reg.acc*cpu.reg.mdr>255)
						cpu.reg.ovf=1;
 
					/* multiply acc by mdr */
					cpu.reg.acc*=cpu.reg.mdr;
 
					/* reset flags */
					cpu.reg.unf=0;
					cpu.reg.crf=0;
 
					printf("MUL %d", address);
					break;
 
		case DIV:	/* copy mem->mdr */
					cpu.reg.mdr=cpu.MEM[cpu.reg.mar];
 
					/* set carry if result has remainder */
					if(cpu.reg.acc%cpu.reg.mdr!=0)
						cpu.reg.crf=1;
 
					/* divide acc by mrd */
					cpu.reg.acc/=cpu.reg.mdr;
 
					/* reset flags */
					cpu.reg.unf=0;
					cpu.reg.ovf=0;
 
					printf("DIV %d", address);
					break;
 
		case CLA:	/* clear accumulator */
					cpu.reg.acc=0;
 
					/* reset flags */
					cpu.reg.unf=0;
					cpu.reg.ovf=0;
					cpu.reg.crf=0;
 
					printf("CLA");
					break;
 
		case CLC:	/* clear carry flag */
					cpu.reg.crf=0;
 
					printf("CLC");
					break;
 
 
		case DMP:	/* stop fdeloop in main */
					*fdeloop=0;
					
					Dump_Memory_Data();
 
					printf("DMP");
					break;
 
		case AND:	/* copy mem->mdr */
					cpu.reg.mdr=cpu.MEM[cpu.reg.mar];
 
					/* AND acc with mdr */
					cpu.reg.acc=cpu.reg.acc&cpu.reg.mdr;
 
					/* reset flags */
					cpu.reg.unf=0;
					cpu.reg.ovf=0;
					cpu.reg.crf=0;
 
					printf("AND %d", address);
					break;
 
		case DEC:	/* set unf if result<0 */
					if(cpu.reg.acc-1<0) cpu.reg.unf=1;
 
					/* perform decrement acc*/
					cpu.reg.acc--;
 
					/* reset flags */
					cpu.reg.ovf=0;
					cpu.reg.crf=0;
 
					printf("DEC");
					break;
 
		case BRO:	/* copy mar->pc, if ovf is set */
					if(cpu.reg.ovf) cpu.reg.pc=cpu.reg.mar;
 
					printf("BRO %d", address);
					break;
 
		case BRU:	/* copy mar->pc, if unf is set */
					if(cpu.reg.unf) cpu.reg.pc=cpu.reg.mar;
 
					printf("BRU %d", address);
					break;
 
		default:	printf("Invalid instruction!");	//in case of error
	}
}
 
/************************************************************************/
/****** Display Registers                                          ******/
/************************************************************************/
 
void Display_Registers(unsigned char start)
{
	if(start)
	printf("\n\t|  IR\tACC\tPC\tMAR\tMDR\tUNF\tOVF\tCRF\n");
 
	else
	{
		printf("\t|  %d",cpu.reg.ir);
		printf("\t%d",cpu.reg.acc);
		printf("\t%d",cpu.reg.pc);
		printf("\t%d",cpu.reg.mar);
		printf("\t%d",cpu.reg.mdr);
		printf("\t%d",cpu.reg.unf);
		printf("\t%d",cpu.reg.ovf);
		printf("\t%d\n",cpu.reg.crf);
	}
}